summaryrefslogtreecommitdiff
path: root/makima/cloudflare-agent
diff options
context:
space:
mode:
Diffstat (limited to 'makima/cloudflare-agent')
-rw-r--r--makima/cloudflare-agent/.gitignore4
-rw-r--r--makima/cloudflare-agent/README.md237
-rw-r--r--makima/cloudflare-agent/package-lock.json2802
-rw-r--r--makima/cloudflare-agent/package.json22
-rwxr-xr-xmakima/cloudflare-agent/setup.sh331
-rw-r--r--makima/cloudflare-agent/src/agent.ts773
-rw-r--r--makima/cloudflare-agent/src/index.ts47
-rw-r--r--makima/cloudflare-agent/src/types.ts148
-rw-r--r--makima/cloudflare-agent/tsconfig.json18
-rw-r--r--makima/cloudflare-agent/wrangler.toml20
10 files changed, 4402 insertions, 0 deletions
diff --git a/makima/cloudflare-agent/.gitignore b/makima/cloudflare-agent/.gitignore
new file mode 100644
index 0000000..d833692
--- /dev/null
+++ b/makima/cloudflare-agent/.gitignore
@@ -0,0 +1,4 @@
+node_modules/
+.wrangler/
+.dev.vars
+dist/
diff --git a/makima/cloudflare-agent/README.md b/makima/cloudflare-agent/README.md
new file mode 100644
index 0000000..b33842a
--- /dev/null
+++ b/makima/cloudflare-agent/README.md
@@ -0,0 +1,237 @@
+# Makima Cloudflare Agent
+
+Edge relay agent for [Makima](https://github.com/soryu-co/makima) — distributed task orchestration for AI coding agents.
+
+This Cloudflare Worker acts as a **WebSocket relay** between the Makima server and native daemon instances. It runs on Cloudflare's edge network using Durable Objects for persistent state and connections.
+
+## Why an Edge Relay?
+
+The full Makima daemon requires native capabilities (process spawning, git operations, filesystem access) that aren't available on Cloudflare Workers. Instead, this agent serves as:
+
+1. **WebSocket Relay** — Bridges the Makima server with remote daemon instances via persistent WebSocket connections
+2. **Task Queue Manager** — Receives tasks from the server and dispatches them to the least-loaded downstream daemon
+3. **Status Aggregator** — Tracks daemon health and task history across edge locations
+4. **API Proxy** — Provides HTTP endpoints for monitoring and management from the edge
+
+## Architecture
+
+```
+ Cloudflare Edge
+ ┌─────────────────────────┐
+ │ │
+ Makima Server ◄──►│ MakimaAgent │◄──► Native Daemon 1
+ (wss://...) │ (Durable Object) │◄──► Native Daemon 2
+ │ │◄──► Native Daemon N
+ │ ┌───────────────────┐ │
+ │ │ SQLite State │ │
+ │ │ - Task history │ │
+ │ │ - Connection logs │ │
+ │ └───────────────────┘ │
+ │ │
+ └─────────────────────────┘
+```
+
+**Message flow:**
+
+1. The agent maintains a persistent WebSocket to the Makima server (upstream)
+2. Native daemons connect to the agent via WebSocket at `/ws/daemon` (downstream)
+3. When the server sends a `SpawnTask` command, the agent selects the least-loaded downstream daemon and forwards the task
+4. Task output, progress, and completion messages from daemons are relayed back to the server
+5. The agent sends periodic heartbeats and tracks all task dispatches in SQLite
+
+## Prerequisites
+
+- **Cloudflare Account** with Workers and Durable Objects enabled
+- **Node.js 18+** and npm
+- **Makima Server** running and accessible (default: `wss://api.makima.jp`)
+- **API Key** from your Makima server dashboard
+
+## Quick Setup
+
+```bash
+# Clone and navigate to the cloudflare-agent directory
+cd makima/cloudflare-agent
+
+# Run the interactive setup script
+chmod +x setup.sh
+./setup.sh
+```
+
+The setup script will:
+
+1. Check prerequisites (Node.js 18+, npm, npx)
+2. Prompt for your Makima server URL and API key
+3. Install npm dependencies
+4. Create `.dev.vars` with your secrets
+5. Check Cloudflare authentication (offer to log in)
+6. Optionally set production secrets
+7. Offer to deploy immediately or start a dev server
+
+## Manual Setup
+
+If you prefer manual configuration:
+
+```bash
+# 1. Install dependencies
+npm install
+
+# 2. Create local secrets file
+cat > .dev.vars <<EOF
+MAKIMA_SERVER_URL=wss://api.makima.jp
+MAKIMA_API_KEY=your-api-key-here
+MAKIMA_AGENT_NAME=my-edge-agent
+EOF
+
+# 3. Log in to Cloudflare
+npx wrangler login
+
+# 4. Set production secrets
+echo "wss://api.makima.jp" | npx wrangler secret put MAKIMA_SERVER_URL
+echo "your-api-key-here" | npx wrangler secret put MAKIMA_API_KEY
+echo "my-edge-agent" | npx wrangler secret put MAKIMA_AGENT_NAME
+
+# 5. Deploy
+npx wrangler deploy
+```
+
+## Development
+
+```bash
+# Start local dev server with hot reload
+npm run dev
+
+# Stream production logs
+npm run tail
+
+# Deploy to Cloudflare
+npm run deploy
+```
+
+## API Endpoints
+
+After deployment, the agent exposes these HTTP endpoints:
+
+| Method | Path | Description |
+|--------|---------------|------------------------------------------|
+| GET | `/` | Agent status (same as `/status`) |
+| GET | `/status` | Connection status and daemon overview |
+| GET | `/health` | Simple health check |
+| GET | `/tasks` | Task dispatch history (paginated) |
+| GET | `/logs` | Connection event logs |
+| POST | `/reconnect` | Force reconnection to upstream server |
+| WS | `/ws/daemon` | WebSocket endpoint for downstream daemons|
+
+### Query Parameters
+
+- **`/tasks`**: `?limit=50&offset=0` — Paginate task history
+- **`/logs`**: `?limit=50` — Limit log entries returned
+
+### Example Responses
+
+**GET /status**
+```json
+{
+ "status": "ok",
+ "agentName": "makima-edge",
+ "upstreamConnected": true,
+ "daemonId": "550e8400-e29b-41d4-a716-446655440000",
+ "lastHeartbeat": "2024-12-15T10:30:00.000Z",
+ "connectedDaemons": 2,
+ "activeTasks": 3,
+ "totalTasksProcessed": 142
+}
+```
+
+**GET /health**
+```json
+{
+ "healthy": true,
+ "upstreamConnected": true
+}
+```
+
+## Environment Variables
+
+| Variable | Required | Description | Default |
+|-----------------------|----------|------------------------------------------------|-----------------------|
+| `MAKIMA_SERVER_URL` | Yes | WebSocket URL of the Makima server | — |
+| `MAKIMA_API_KEY` | Yes | API key for server authentication | — |
+| `MAKIMA_AGENT_NAME` | No | Human-readable name for this agent | `makima-edge-{id}` |
+
+Set these as Cloudflare Workers secrets for production:
+```bash
+echo "value" | npx wrangler secret put VARIABLE_NAME
+```
+
+For local development, put them in `.dev.vars` (gitignored automatically).
+
+## How It Works
+
+### Upstream Connection (to Makima Server)
+
+1. On startup, the agent opens a WebSocket to `MAKIMA_SERVER_URL/ws/daemon`
+2. It authenticates using the `MAKIMA_API_KEY` with `maxConcurrentTasks: 0` (relay-only mode)
+3. Sends heartbeats every 30 seconds
+4. On disconnect, reconnects with exponential backoff (1s → 60s, max 20 attempts)
+
+### Downstream Connections (from Native Daemons)
+
+1. Native Makima daemons connect via WebSocket to `/ws/daemon`
+2. Daemons authenticate with their hostname and max concurrent task count
+3. The agent tracks each daemon's active tasks and health
+
+### Task Dispatch
+
+When the server sends a `SpawnTask` command:
+1. The agent records the task in SQLite
+2. Selects the downstream daemon with the fewest active tasks (that still has capacity)
+3. Forwards the full `SpawnTask` command
+4. If no daemons are available, the task remains pending
+
+### Persistence
+
+The agent uses Cloudflare Durable Objects with SQLite for:
+- **Task history** — All received, dispatched, completed, and failed tasks
+- **Connection logs** — Connect/disconnect/error events (last 200 entries)
+- **Agent state** — Connection status, daemon ID, active tasks
+
+The Durable Object auto-hibernates when idle and resumes on the next request, preserving all state.
+
+## Connecting Native Daemons
+
+Native Makima daemons can connect to this edge relay instead of directly to the server. Configure the daemon to point at your deployed Worker URL:
+
+```toml
+# makima-daemon.toml
+[server]
+url = "wss://makima-agent.your-account.workers.dev/ws/daemon"
+api_key = "your-api-key"
+```
+
+Or via environment variable:
+```bash
+MAKIMA_DAEMON_SERVER__URL=wss://makima-agent.your-account.workers.dev/ws/daemon \
+MAKIMA_DAEMON_SERVER__API_KEY=your-api-key \
+makima daemon
+```
+
+## Troubleshooting
+
+### Agent shows "disconnected" status
+- Verify `MAKIMA_SERVER_URL` is correct and the server is reachable
+- Check that `MAKIMA_API_KEY` is valid
+- Review connection logs at `GET /logs`
+
+### Tasks stuck in "pending"
+- No downstream daemons are connected
+- Ensure native daemons are pointing to this agent's `/ws/daemon` endpoint
+- Check `GET /status` for `connectedDaemons` count
+
+### Deployment fails
+- Ensure you're logged in: `npx wrangler whoami`
+- Ensure your account has Durable Objects enabled
+- Check `wrangler.toml` configuration
+
+## License
+
+Part of the [Makima](https://github.com/soryu-co/makima) project.
diff --git a/makima/cloudflare-agent/package-lock.json b/makima/cloudflare-agent/package-lock.json
new file mode 100644
index 0000000..256a708
--- /dev/null
+++ b/makima/cloudflare-agent/package-lock.json
@@ -0,0 +1,2802 @@
+{
+ "name": "makima-agent",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "makima-agent",
+ "version": "0.1.0",
+ "dependencies": {
+ "agents": "^0.0.67"
+ },
+ "devDependencies": {
+ "@cloudflare/workers-types": "^4.20241230.0",
+ "typescript": "^5.7.0",
+ "wrangler": "^3.99.0"
+ }
+ },
+ "node_modules/@ai-sdk/provider": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz",
+ "integrity": "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==",
+ "dependencies": {
+ "json-schema": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@ai-sdk/provider-utils": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz",
+ "integrity": "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==",
+ "dependencies": {
+ "@ai-sdk/provider": "1.1.3",
+ "nanoid": "^3.3.8",
+ "secure-json-parse": "^2.7.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "zod": "^3.23.8"
+ }
+ },
+ "node_modules/@ai-sdk/provider-utils/node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/@ai-sdk/react": {
+ "version": "1.2.12",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-1.2.12.tgz",
+ "integrity": "sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g==",
+ "dependencies": {
+ "@ai-sdk/provider-utils": "2.2.8",
+ "@ai-sdk/ui-utils": "1.2.11",
+ "swr": "^2.2.5",
+ "throttleit": "2.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "react": "^18 || ^19 || ^19.0.0-rc",
+ "zod": "^3.23.8"
+ },
+ "peerDependenciesMeta": {
+ "zod": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@ai-sdk/ui-utils": {
+ "version": "1.2.11",
+ "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-1.2.11.tgz",
+ "integrity": "sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==",
+ "dependencies": {
+ "@ai-sdk/provider": "1.1.3",
+ "@ai-sdk/provider-utils": "2.2.8",
+ "zod-to-json-schema": "^3.24.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "zod": "^3.23.8"
+ }
+ },
+ "node_modules/@cloudflare/kv-asset-handler": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz",
+ "integrity": "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==",
+ "dev": true,
+ "dependencies": {
+ "mime": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=16.13"
+ }
+ },
+ "node_modules/@cloudflare/unenv-preset": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.0.2.tgz",
+ "integrity": "sha512-nyzYnlZjjV5xT3LizahG1Iu6mnrCaxglJ04rZLpDwlDVDZ7v46lNsfxhV3A/xtfgQuSHmLnc6SVI+KwBpc3Lwg==",
+ "dev": true,
+ "peerDependencies": {
+ "unenv": "2.0.0-rc.14",
+ "workerd": "^1.20250124.0"
+ },
+ "peerDependenciesMeta": {
+ "workerd": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@cloudflare/workerd-darwin-64": {
+ "version": "1.20250718.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20250718.0.tgz",
+ "integrity": "sha512-FHf4t7zbVN8yyXgQ/r/GqLPaYZSGUVzeR7RnL28Mwj2djyw2ZergvytVc7fdGcczl6PQh+VKGfZCfUqpJlbi9g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cloudflare/workerd-darwin-arm64": {
+ "version": "1.20250718.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20250718.0.tgz",
+ "integrity": "sha512-fUiyUJYyqqp4NqJ0YgGtp4WJh/II/YZsUnEb6vVy5Oeas8lUOxnN+ZOJ8N/6/5LQCVAtYCChRiIrBbfhTn5Z8Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cloudflare/workerd-linux-64": {
+ "version": "1.20250718.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20250718.0.tgz",
+ "integrity": "sha512-5+eb3rtJMiEwp08Kryqzzu8d1rUcK+gdE442auo5eniMpT170Dz0QxBrqkg2Z48SFUPYbj+6uknuA5tzdRSUSg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cloudflare/workerd-linux-arm64": {
+ "version": "1.20250718.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20250718.0.tgz",
+ "integrity": "sha512-Aa2M/DVBEBQDdATMbn217zCSFKE+ud/teS+fFS+OQqKABLn0azO2qq6ANAHYOIE6Q3Sq4CxDIQr8lGdaJHwUog==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cloudflare/workerd-windows-64": {
+ "version": "1.20250718.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20250718.0.tgz",
+ "integrity": "sha512-dY16RXKffmugnc67LTbyjdDHZn5NoTF1yHEf2fN4+OaOnoGSp3N1x77QubTDwqZ9zECWxgQfDLjddcH8dWeFhg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cloudflare/workers-types": {
+ "version": "4.20260228.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260228.0.tgz",
+ "integrity": "sha512-9LfRg93ncQq6Oc4MFpqGSs+PmPhqWvg8TspXwbiYNR201IhXB4WqHR/aTSudPI0ujsf/NLc8E9fF3C+aA2g8KQ=="
+ },
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz",
+ "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@esbuild-plugins/node-globals-polyfill": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz",
+ "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==",
+ "dev": true,
+ "peerDependencies": {
+ "esbuild": "*"
+ }
+ },
+ "node_modules/@esbuild-plugins/node-modules-polyfill": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz",
+ "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^4.0.0",
+ "rollup-plugin-node-polyfills": "^0.2.1"
+ },
+ "peerDependencies": {
+ "esbuild": "*"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
+ "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
+ "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
+ "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
+ "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
+ "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
+ "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
+ "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
+ "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
+ "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
+ "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
+ "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
+ "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
+ "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
+ "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
+ "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
+ "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
+ "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
+ "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
+ "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
+ "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
+ "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
+ "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@fastify/busboy": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
+ "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
+ "dev": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@hono/node-server": {
+ "version": "1.19.9",
+ "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz",
+ "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==",
+ "engines": {
+ "node": ">=18.14.1"
+ },
+ "peerDependencies": {
+ "hono": "^4"
+ }
+ },
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
+ "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
+ "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
+ "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
+ "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
+ "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
+ "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz",
+ "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
+ "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz",
+ "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz",
+ "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
+ "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.0.5"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
+ "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz",
+ "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
+ "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz",
+ "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz",
+ "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz",
+ "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.2.0"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz",
+ "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
+ "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
+ "node_modules/@modelcontextprotocol/sdk": {
+ "version": "1.26.0",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz",
+ "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==",
+ "dependencies": {
+ "@hono/node-server": "^1.19.9",
+ "ajv": "^8.17.1",
+ "ajv-formats": "^3.0.1",
+ "content-type": "^1.0.5",
+ "cors": "^2.8.5",
+ "cross-spawn": "^7.0.5",
+ "eventsource": "^3.0.2",
+ "eventsource-parser": "^3.0.0",
+ "express": "^5.2.1",
+ "express-rate-limit": "^8.2.1",
+ "hono": "^4.11.4",
+ "jose": "^6.1.3",
+ "json-schema-typed": "^8.0.2",
+ "pkce-challenge": "^5.0.0",
+ "raw-body": "^3.0.0",
+ "zod": "^3.25 || ^4.0",
+ "zod-to-json-schema": "^3.25.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@cfworker/json-schema": "^4.1.1",
+ "zod": "^3.25 || ^4.0"
+ },
+ "peerDependenciesMeta": {
+ "@cfworker/json-schema": {
+ "optional": true
+ },
+ "zod": {
+ "optional": false
+ }
+ }
+ },
+ "node_modules/@opentelemetry/api": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
+ "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/@types/diff-match-patch": {
+ "version": "1.0.36",
+ "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz",
+ "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg=="
+ },
+ "node_modules/accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "dependencies": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.14.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
+ "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
+ "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/agents": {
+ "version": "0.0.67",
+ "resolved": "https://registry.npmjs.org/agents/-/agents-0.0.67.tgz",
+ "integrity": "sha512-Bjn8w9230xcgeP/UKvWbZVvQvPuCpA1S0f8X6859xSvkviAcKWgHidnyRBUMUCniljNTzbU1ZgR8YWveJ4xbqg==",
+ "dependencies": {
+ "@modelcontextprotocol/sdk": "^1.10.2",
+ "ai": "^4.3.9",
+ "cron-schedule": "^5.0.4",
+ "nanoid": "^5.1.5",
+ "partyserver": "^0.0.67",
+ "partysocket": "1.1.3",
+ "zod": "^3.24.3"
+ },
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
+ "node_modules/ai": {
+ "version": "4.3.19",
+ "resolved": "https://registry.npmjs.org/ai/-/ai-4.3.19.tgz",
+ "integrity": "sha512-dIE2bfNpqHN3r6IINp9znguYdhIOheKW2LDigAMrgt/upT3B8eBGPSCblENvaZGoq+hxaN9fSMzjWpbqloP+7Q==",
+ "dependencies": {
+ "@ai-sdk/provider": "1.1.3",
+ "@ai-sdk/provider-utils": "2.2.8",
+ "@ai-sdk/react": "1.2.12",
+ "@ai-sdk/ui-utils": "1.2.11",
+ "@opentelemetry/api": "1.9.0",
+ "jsondiffpatch": "0.6.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "react": "^18 || ^19 || ^19.0.0-rc",
+ "zod": "^3.23.8"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ajv": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
+ "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-formats": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
+ "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
+ "dependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/as-table": {
+ "version": "1.0.55",
+ "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz",
+ "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==",
+ "dev": true,
+ "dependencies": {
+ "printable-characters": "^1.0.42"
+ }
+ },
+ "node_modules/blake3-wasm": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz",
+ "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==",
+ "dev": true
+ },
+ "node_modules/body-parser": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz",
+ "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==",
+ "dependencies": {
+ "bytes": "^3.1.2",
+ "content-type": "^1.0.5",
+ "debug": "^4.4.3",
+ "http-errors": "^2.0.0",
+ "iconv-lite": "^0.7.0",
+ "on-finished": "^2.4.1",
+ "qs": "^6.14.1",
+ "raw-body": "^3.0.1",
+ "type-is": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
+ "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "optional": true
+ },
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
+ "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+ "engines": {
+ "node": ">=6.6.0"
+ }
+ },
+ "node_modules/cors": {
+ "version": "2.8.6",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
+ "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/cron-schedule": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/cron-schedule/-/cron-schedule-5.0.4.tgz",
+ "integrity": "sha512-nH0a49E/kSVk6BeFgKZy4uUsy6D2A16p120h5bYD9ILBhQu7o2sJFH+WI4R731TSBQ0dB1Ik7inB/dRAB4C8QQ==",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/data-uri-to-buffer": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz",
+ "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==",
+ "dev": true
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/defu": {
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
+ "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
+ "dev": true
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/dequal": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/diff-match-patch": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
+ "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw=="
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
+ "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.17.19",
+ "@esbuild/android-arm64": "0.17.19",
+ "@esbuild/android-x64": "0.17.19",
+ "@esbuild/darwin-arm64": "0.17.19",
+ "@esbuild/darwin-x64": "0.17.19",
+ "@esbuild/freebsd-arm64": "0.17.19",
+ "@esbuild/freebsd-x64": "0.17.19",
+ "@esbuild/linux-arm": "0.17.19",
+ "@esbuild/linux-arm64": "0.17.19",
+ "@esbuild/linux-ia32": "0.17.19",
+ "@esbuild/linux-loong64": "0.17.19",
+ "@esbuild/linux-mips64el": "0.17.19",
+ "@esbuild/linux-ppc64": "0.17.19",
+ "@esbuild/linux-riscv64": "0.17.19",
+ "@esbuild/linux-s390x": "0.17.19",
+ "@esbuild/linux-x64": "0.17.19",
+ "@esbuild/netbsd-x64": "0.17.19",
+ "@esbuild/openbsd-x64": "0.17.19",
+ "@esbuild/sunos-x64": "0.17.19",
+ "@esbuild/win32-arm64": "0.17.19",
+ "@esbuild/win32-ia32": "0.17.19",
+ "@esbuild/win32-x64": "0.17.19"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
+ "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
+ "dev": true
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/event-target-polyfill": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/event-target-polyfill/-/event-target-polyfill-0.0.4.tgz",
+ "integrity": "sha512-Gs6RLjzlLRdT8X9ZipJdIZI/Y6/HhRLyq9RdDlCsnpxr/+Nn6bU2EFGuC94GjxqhM+Nmij2Vcq98yoHrU8uNFQ=="
+ },
+ "node_modules/eventsource": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz",
+ "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==",
+ "dependencies": {
+ "eventsource-parser": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/eventsource-parser": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz",
+ "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==",
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/exit-hook": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz",
+ "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/express": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
+ "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
+ "dependencies": {
+ "accepts": "^2.0.0",
+ "body-parser": "^2.2.1",
+ "content-disposition": "^1.0.0",
+ "content-type": "^1.0.5",
+ "cookie": "^0.7.1",
+ "cookie-signature": "^1.2.1",
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "finalhandler": "^2.1.0",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "merge-descriptors": "^2.0.0",
+ "mime-types": "^3.0.0",
+ "on-finished": "^2.4.1",
+ "once": "^1.4.0",
+ "parseurl": "^1.3.3",
+ "proxy-addr": "^2.0.7",
+ "qs": "^6.14.0",
+ "range-parser": "^1.2.1",
+ "router": "^2.2.0",
+ "send": "^1.1.0",
+ "serve-static": "^2.2.0",
+ "statuses": "^2.0.1",
+ "type-is": "^2.0.1",
+ "vary": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/express-rate-limit": {
+ "version": "8.2.1",
+ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz",
+ "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==",
+ "dependencies": {
+ "ip-address": "10.0.1"
+ },
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/express-rate-limit"
+ },
+ "peerDependencies": {
+ "express": ">= 4.11"
+ }
+ },
+ "node_modules/exsolve": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz",
+ "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==",
+ "dev": true
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ },
+ "node_modules/fast-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
+ "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ]
+ },
+ "node_modules/finalhandler": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
+ "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "on-finished": "^2.4.1",
+ "parseurl": "^1.3.3",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/get-source": {
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz",
+ "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==",
+ "dev": true,
+ "dependencies": {
+ "data-uri-to-buffer": "^2.0.0",
+ "source-map": "^0.6.1"
+ }
+ },
+ "node_modules/glob-to-regexp": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+ "dev": true
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/hono": {
+ "version": "4.12.1",
+ "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.1.tgz",
+ "integrity": "sha512-hi9afu8g0lfJVLolxElAZGANCTTl6bewIdsRNhaywfP9K8BPf++F2z6OLrYGIinUwpRKzbZHMhPwvc0ZEpAwGw==",
+ "engines": {
+ "node": ">=16.9.0"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+ "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+ "dependencies": {
+ "depd": "~2.0.0",
+ "inherits": "~2.0.4",
+ "setprototypeof": "~1.2.0",
+ "statuses": "~2.0.2",
+ "toidentifier": "~1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
+ "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/ip-address": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz",
+ "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
+ "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
+ "dev": true,
+ "optional": true
+ },
+ "node_modules/is-promise": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
+ },
+ "node_modules/jose": {
+ "version": "6.1.3",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz",
+ "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
+ "node_modules/json-schema": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
+ },
+ "node_modules/json-schema-typed": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz",
+ "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="
+ },
+ "node_modules/jsondiffpatch": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.6.0.tgz",
+ "integrity": "sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==",
+ "dependencies": {
+ "@types/diff-match-patch": "^1.0.36",
+ "chalk": "^5.3.0",
+ "diff-match-patch": "^1.0.5"
+ },
+ "bin": {
+ "jsondiffpatch": "bin/jsondiffpatch.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz",
+ "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
+ "dev": true,
+ "dependencies": {
+ "sourcemap-codec": "^1.4.8"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/mime": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
+ "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
+ "dev": true,
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
+ "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/miniflare": {
+ "version": "3.20250718.3",
+ "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20250718.3.tgz",
+ "integrity": "sha512-JuPrDJhwLrNLEJiNLWO7ZzJrv/Vv9kZuwMYCfv0LskQDM6Eonw4OvywO3CH/wCGjgHzha/qyjUh8JQ068TjDgQ==",
+ "dev": true,
+ "dependencies": {
+ "@cspotcode/source-map-support": "0.8.1",
+ "acorn": "8.14.0",
+ "acorn-walk": "8.3.2",
+ "exit-hook": "2.2.1",
+ "glob-to-regexp": "0.4.1",
+ "stoppable": "1.1.0",
+ "undici": "^5.28.5",
+ "workerd": "1.20250718.0",
+ "ws": "8.18.0",
+ "youch": "3.3.4",
+ "zod": "3.22.3"
+ },
+ "bin": {
+ "miniflare": "bootstrap.js"
+ },
+ "engines": {
+ "node": ">=16.13"
+ }
+ },
+ "node_modules/miniflare/node_modules/zod": {
+ "version": "3.22.3",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz",
+ "integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/mustache": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
+ "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
+ "dev": true,
+ "bin": {
+ "mustache": "bin/mustache"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz",
+ "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.js"
+ },
+ "engines": {
+ "node": "^18 || >=20"
+ }
+ },
+ "node_modules/negotiator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/ohash": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz",
+ "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
+ "dev": true
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/partyserver": {
+ "version": "0.0.67",
+ "resolved": "https://registry.npmjs.org/partyserver/-/partyserver-0.0.67.tgz",
+ "integrity": "sha512-GQ0fjJ7n5r5LrsFHFUkGR3Bd50YdBZaDNjvRTi8PowZgI5fvCFliT/XdDpRVuwfDDk0jb9es2cXcaAh1z5GsLA==",
+ "dependencies": {
+ "nanoid": "^5.1.5"
+ },
+ "peerDependencies": {
+ "@cloudflare/workers-types": "^4.20240729.0"
+ }
+ },
+ "node_modules/partysocket": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/partysocket/-/partysocket-1.1.3.tgz",
+ "integrity": "sha512-87Jd/nqPoWnVfzHE6Z12WLWTJ+TAgxs0b7i2S163HfQSrVDUK5tW/FC64T5N8L5ss+gqF+EV0BwjZMWggMY3UA==",
+ "dependencies": {
+ "event-target-polyfill": "^0.0.4"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
+ "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "dev": true
+ },
+ "node_modules/pkce-challenge": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz",
+ "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==",
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/printable-characters": {
+ "version": "1.0.42",
+ "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz",
+ "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==",
+ "dev": true
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz",
+ "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
+ "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
+ "dependencies": {
+ "bytes": "~3.1.2",
+ "http-errors": "~2.0.1",
+ "iconv-lite": "~0.7.0",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/react": {
+ "version": "19.2.4",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
+ "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-inject": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz",
+ "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==",
+ "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.",
+ "dev": true,
+ "dependencies": {
+ "estree-walker": "^0.6.1",
+ "magic-string": "^0.25.3",
+ "rollup-pluginutils": "^2.8.1"
+ }
+ },
+ "node_modules/rollup-plugin-node-polyfills": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz",
+ "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==",
+ "dev": true,
+ "dependencies": {
+ "rollup-plugin-inject": "^3.0.0"
+ }
+ },
+ "node_modules/rollup-pluginutils": {
+ "version": "2.8.2",
+ "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
+ "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
+ "dev": true,
+ "dependencies": {
+ "estree-walker": "^0.6.1"
+ }
+ },
+ "node_modules/router": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "is-promise": "^4.0.0",
+ "parseurl": "^1.3.3",
+ "path-to-regexp": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/secure-json-parse": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
+ "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="
+ },
+ "node_modules/semver": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+ "dev": true,
+ "optional": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/send": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
+ "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
+ "dependencies": {
+ "debug": "^4.4.3",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.1",
+ "mime-types": "^3.0.2",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/serve-static": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
+ "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
+ "dependencies": {
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "parseurl": "^1.3.3",
+ "send": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "node_modules/sharp": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz",
+ "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "dependencies": {
+ "color": "^4.2.3",
+ "detect-libc": "^2.0.3",
+ "semver": "^7.6.3"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.33.5",
+ "@img/sharp-darwin-x64": "0.33.5",
+ "@img/sharp-libvips-darwin-arm64": "1.0.4",
+ "@img/sharp-libvips-darwin-x64": "1.0.4",
+ "@img/sharp-libvips-linux-arm": "1.0.5",
+ "@img/sharp-libvips-linux-arm64": "1.0.4",
+ "@img/sharp-libvips-linux-s390x": "1.0.4",
+ "@img/sharp-libvips-linux-x64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.4",
+ "@img/sharp-linux-arm": "0.33.5",
+ "@img/sharp-linux-arm64": "0.33.5",
+ "@img/sharp-linux-s390x": "0.33.5",
+ "@img/sharp-linux-x64": "0.33.5",
+ "@img/sharp-linuxmusl-arm64": "0.33.5",
+ "@img/sharp-linuxmusl-x64": "0.33.5",
+ "@img/sharp-wasm32": "0.33.5",
+ "@img/sharp-win32-ia32": "0.33.5",
+ "@img/sharp-win32-x64": "0.33.5"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/simple-swizzle": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
+ "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sourcemap-codec": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+ "deprecated": "Please use @jridgewell/sourcemap-codec instead",
+ "dev": true
+ },
+ "node_modules/stacktracey": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz",
+ "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==",
+ "dev": true,
+ "dependencies": {
+ "as-table": "^1.0.36",
+ "get-source": "^2.0.12"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/stoppable": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz",
+ "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4",
+ "npm": ">=6"
+ }
+ },
+ "node_modules/swr": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/swr/-/swr-2.4.0.tgz",
+ "integrity": "sha512-sUlC20T8EOt1pHmDiqueUWMmRRX03W7w5YxovWX7VR2KHEPCTMly85x05vpkP5i6Bu4h44ePSMD9Tc+G2MItFw==",
+ "dependencies": {
+ "dequal": "^2.0.3",
+ "use-sync-external-store": "^1.6.0"
+ },
+ "peerDependencies": {
+ "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/throttleit": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz",
+ "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
+ "optional": true
+ },
+ "node_modules/type-is": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
+ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
+ "dependencies": {
+ "content-type": "^1.0.5",
+ "media-typer": "^1.1.0",
+ "mime-types": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/ufo": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz",
+ "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==",
+ "dev": true
+ },
+ "node_modules/undici": {
+ "version": "5.29.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
+ "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
+ "dev": true,
+ "dependencies": {
+ "@fastify/busboy": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=14.0"
+ }
+ },
+ "node_modules/unenv": {
+ "version": "2.0.0-rc.14",
+ "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.14.tgz",
+ "integrity": "sha512-od496pShMen7nOy5VmVJCnq8rptd45vh6Nx/r2iPbrba6pa6p+tS2ywuIHRZ/OBvSbQZB0kWvpO9XBNVFXHD3Q==",
+ "dev": true,
+ "dependencies": {
+ "defu": "^6.1.4",
+ "exsolve": "^1.0.1",
+ "ohash": "^2.0.10",
+ "pathe": "^2.0.3",
+ "ufo": "^1.5.4"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/use-sync-external-store": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+ "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/workerd": {
+ "version": "1.20250718.0",
+ "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20250718.0.tgz",
+ "integrity": "sha512-kqkIJP/eOfDlUyBzU7joBg+tl8aB25gEAGqDap+nFWb+WHhnooxjGHgxPBy3ipw2hnShPFNOQt5lFRxbwALirg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "bin": {
+ "workerd": "bin/workerd"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "optionalDependencies": {
+ "@cloudflare/workerd-darwin-64": "1.20250718.0",
+ "@cloudflare/workerd-darwin-arm64": "1.20250718.0",
+ "@cloudflare/workerd-linux-64": "1.20250718.0",
+ "@cloudflare/workerd-linux-arm64": "1.20250718.0",
+ "@cloudflare/workerd-windows-64": "1.20250718.0"
+ }
+ },
+ "node_modules/wrangler": {
+ "version": "3.114.17",
+ "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.114.17.tgz",
+ "integrity": "sha512-tAvf7ly+tB+zwwrmjsCyJ2pJnnc7SZhbnNwXbH+OIdVas3zTSmjcZOjmLKcGGptssAA3RyTKhcF9BvKZzMUycA==",
+ "dev": true,
+ "dependencies": {
+ "@cloudflare/kv-asset-handler": "0.3.4",
+ "@cloudflare/unenv-preset": "2.0.2",
+ "@esbuild-plugins/node-globals-polyfill": "0.2.3",
+ "@esbuild-plugins/node-modules-polyfill": "0.2.2",
+ "blake3-wasm": "2.1.5",
+ "esbuild": "0.17.19",
+ "miniflare": "3.20250718.3",
+ "path-to-regexp": "6.3.0",
+ "unenv": "2.0.0-rc.14",
+ "workerd": "1.20250718.0"
+ },
+ "bin": {
+ "wrangler": "bin/wrangler.js",
+ "wrangler2": "bin/wrangler.js"
+ },
+ "engines": {
+ "node": ">=16.17.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2",
+ "sharp": "^0.33.5"
+ },
+ "peerDependencies": {
+ "@cloudflare/workers-types": "^4.20250408.0"
+ },
+ "peerDependenciesMeta": {
+ "@cloudflare/workers-types": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/wrangler/node_modules/path-to-regexp": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
+ "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
+ "dev": true
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+ },
+ "node_modules/ws": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+ "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/youch": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.4.tgz",
+ "integrity": "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==",
+ "dev": true,
+ "dependencies": {
+ "cookie": "^0.7.1",
+ "mustache": "^4.2.0",
+ "stacktracey": "^2.1.8"
+ }
+ },
+ "node_modules/zod": {
+ "version": "3.25.76",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
+ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-to-json-schema": {
+ "version": "3.25.1",
+ "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz",
+ "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==",
+ "peerDependencies": {
+ "zod": "^3.25 || ^4"
+ }
+ }
+ }
+}
diff --git a/makima/cloudflare-agent/package.json b/makima/cloudflare-agent/package.json
new file mode 100644
index 0000000..5b6a01e
--- /dev/null
+++ b/makima/cloudflare-agent/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "makima-agent",
+ "version": "0.1.0",
+ "description": "Makima edge relay agent for Cloudflare Workers - bridges the Makima server with remote daemon instances",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "wrangler dev",
+ "deploy": "wrangler deploy",
+ "setup": "bash setup.sh",
+ "tail": "wrangler tail",
+ "types": "wrangler types"
+ },
+ "dependencies": {
+ "agents": "^0.0.67"
+ },
+ "devDependencies": {
+ "@cloudflare/workers-types": "^4.20241230.0",
+ "typescript": "^5.7.0",
+ "wrangler": "^3.99.0"
+ }
+}
diff --git a/makima/cloudflare-agent/setup.sh b/makima/cloudflare-agent/setup.sh
new file mode 100755
index 0000000..acf9cd9
--- /dev/null
+++ b/makima/cloudflare-agent/setup.sh
@@ -0,0 +1,331 @@
+#!/usr/bin/env bash
+# ============================================================================
+# Makima Cloudflare Agent — Interactive Setup Script
+#
+# Sets up the Cloudflare Workers project for deploying a Makima edge relay
+# agent. This agent acts as a WebSocket bridge between the Makima server
+# and native daemon instances running on your infrastructure.
+#
+# Usage:
+# chmod +x setup.sh && ./setup.sh
+# ============================================================================
+
+set -euo pipefail
+
+# Colors
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+BLUE='\033[0;34m'
+CYAN='\033[0;36m'
+BOLD='\033[1m'
+NC='\033[0m' # No Color
+
+# ---------------------------------------------------------------------------
+# Helpers
+# ---------------------------------------------------------------------------
+
+info() { echo -e "${BLUE}ℹ${NC} $*"; }
+success() { echo -e "${GREEN}✔${NC} $*"; }
+warn() { echo -e "${YELLOW}⚠${NC} $*"; }
+error() { echo -e "${RED}✖${NC} $*"; }
+
+prompt() {
+ local var_name="$1"
+ local prompt_text="$2"
+ local default_value="${3:-}"
+ local value
+
+ if [ -n "$default_value" ]; then
+ echo -ne "${CYAN}?${NC} ${prompt_text} ${BOLD}[${default_value}]${NC}: "
+ else
+ echo -ne "${CYAN}?${NC} ${prompt_text}: "
+ fi
+
+ read -r value
+ value="${value:-$default_value}"
+ eval "$var_name=\"$value\""
+}
+
+confirm() {
+ local prompt_text="$1"
+ local default="${2:-y}"
+ local yn
+
+ if [ "$default" = "y" ]; then
+ echo -ne "${CYAN}?${NC} ${prompt_text} ${BOLD}[Y/n]${NC}: "
+ else
+ echo -ne "${CYAN}?${NC} ${prompt_text} ${BOLD}[y/N]${NC}: "
+ fi
+
+ read -r yn
+ yn="${yn:-$default}"
+
+ case "$yn" in
+ [Yy]*) return 0 ;;
+ *) return 1 ;;
+ esac
+}
+
+separator() {
+ echo ""
+ echo -e "${BLUE}──────────────────────────────────────────────────────${NC}"
+ echo ""
+}
+
+# ---------------------------------------------------------------------------
+# Header
+# ---------------------------------------------------------------------------
+
+clear 2>/dev/null || true
+echo ""
+echo -e "${BOLD}${CYAN}"
+echo " ╔══════════════════════════════════════════════════╗"
+echo " ║ Makima Cloudflare Agent Setup ║"
+echo " ║ ║"
+echo " ║ Edge relay for distributed task orchestration ║"
+echo " ╚══════════════════════════════════════════════════╝"
+echo -e "${NC}"
+echo ""
+
+# ---------------------------------------------------------------------------
+# 1. Check Prerequisites
+# ---------------------------------------------------------------------------
+
+info "Checking prerequisites..."
+echo ""
+
+missing=0
+
+# Node.js
+if command -v node &>/dev/null; then
+ node_version=$(node --version)
+ # Check if version is 18+
+ major_version=$(echo "$node_version" | sed 's/v//' | cut -d. -f1)
+ if [ "$major_version" -ge 18 ]; then
+ success "Node.js ${node_version}"
+ else
+ error "Node.js ${node_version} (requires v18+)"
+ missing=1
+ fi
+else
+ error "Node.js not found (requires v18+)"
+ missing=1
+fi
+
+# npm
+if command -v npm &>/dev/null; then
+ success "npm $(npm --version)"
+else
+ error "npm not found"
+ missing=1
+fi
+
+# npx
+if command -v npx &>/dev/null; then
+ success "npx available"
+else
+ error "npx not found"
+ missing=1
+fi
+
+if [ "$missing" -eq 1 ]; then
+ echo ""
+ error "Missing prerequisites. Please install the missing tools and try again."
+ echo ""
+ info "Install Node.js 18+: https://nodejs.org/"
+ exit 1
+fi
+
+separator
+
+# ---------------------------------------------------------------------------
+# 2. Gather Configuration
+# ---------------------------------------------------------------------------
+
+info "Let's configure your Makima edge agent."
+echo ""
+
+prompt MAKIMA_SERVER_URL "Makima server WebSocket URL" "wss://api.makima.jp"
+echo ""
+
+prompt MAKIMA_API_KEY "Makima API key (from your server dashboard)" ""
+if [ -z "$MAKIMA_API_KEY" ]; then
+ error "API key is required."
+ exit 1
+fi
+echo ""
+
+prompt MAKIMA_AGENT_NAME "Agent display name (optional)" "makima-edge"
+echo ""
+
+separator
+
+# ---------------------------------------------------------------------------
+# 3. Install Dependencies
+# ---------------------------------------------------------------------------
+
+info "Installing dependencies..."
+echo ""
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+cd "$SCRIPT_DIR"
+
+npm install 2>&1 | while IFS= read -r line; do
+ echo " $line"
+done
+
+echo ""
+success "Dependencies installed."
+
+separator
+
+# ---------------------------------------------------------------------------
+# 4. Create .dev.vars (local secrets for development)
+# ---------------------------------------------------------------------------
+
+info "Creating .dev.vars for local development secrets..."
+
+cat > .dev.vars <<EOF
+# Makima Cloudflare Agent — Local Development Secrets
+# These are used by 'wrangler dev' and should NOT be committed to git.
+
+MAKIMA_SERVER_URL=${MAKIMA_SERVER_URL}
+MAKIMA_API_KEY=${MAKIMA_API_KEY}
+MAKIMA_AGENT_NAME=${MAKIMA_AGENT_NAME}
+EOF
+
+success "Created .dev.vars"
+echo ""
+
+# Ensure .dev.vars is gitignored
+if [ -f .gitignore ]; then
+ if ! grep -q ".dev.vars" .gitignore 2>/dev/null; then
+ echo ".dev.vars" >> .gitignore
+ success "Added .dev.vars to .gitignore"
+ fi
+else
+ echo ".dev.vars" > .gitignore
+ echo "node_modules/" >> .gitignore
+ echo ".wrangler/" >> .gitignore
+ success "Created .gitignore"
+fi
+
+separator
+
+# ---------------------------------------------------------------------------
+# 5. Wrangler Login Check
+# ---------------------------------------------------------------------------
+
+info "Checking Cloudflare authentication..."
+echo ""
+
+if npx wrangler whoami 2>/dev/null | grep -q "You are logged in"; then
+ success "Already logged in to Cloudflare."
+else
+ warn "Not logged in to Cloudflare."
+ if confirm "Would you like to log in now?"; then
+ npx wrangler login
+ success "Logged in to Cloudflare."
+ else
+ warn "Skipping login. You'll need to run 'npx wrangler login' before deploying."
+ fi
+fi
+
+separator
+
+# ---------------------------------------------------------------------------
+# 6. Set Production Secrets
+# ---------------------------------------------------------------------------
+
+if confirm "Would you like to set production secrets now? (Required before first deploy)"; then
+ echo ""
+ info "Setting secrets via Wrangler..."
+ echo ""
+
+ echo "$MAKIMA_SERVER_URL" | npx wrangler secret put MAKIMA_SERVER_URL 2>&1 | while IFS= read -r line; do
+ echo " $line"
+ done
+ success "Set MAKIMA_SERVER_URL"
+
+ echo "$MAKIMA_API_KEY" | npx wrangler secret put MAKIMA_API_KEY 2>&1 | while IFS= read -r line; do
+ echo " $line"
+ done
+ success "Set MAKIMA_API_KEY"
+
+ if [ -n "$MAKIMA_AGENT_NAME" ]; then
+ echo "$MAKIMA_AGENT_NAME" | npx wrangler secret put MAKIMA_AGENT_NAME 2>&1 | while IFS= read -r line; do
+ echo " $line"
+ done
+ success "Set MAKIMA_AGENT_NAME"
+ fi
+fi
+
+separator
+
+# ---------------------------------------------------------------------------
+# 7. Deploy or Dev
+# ---------------------------------------------------------------------------
+
+echo -e "${BOLD}Setup complete!${NC} What would you like to do next?"
+echo ""
+echo " 1) Deploy to Cloudflare Workers (production)"
+echo " 2) Start local development server"
+echo " 3) Exit (deploy later)"
+echo ""
+
+prompt NEXT_ACTION "Choose an option" "3"
+
+case "$NEXT_ACTION" in
+ 1)
+ echo ""
+ info "Deploying to Cloudflare Workers..."
+ echo ""
+ npx wrangler deploy 2>&1 | while IFS= read -r line; do
+ echo " $line"
+ done
+ echo ""
+ success "Deployed! Your Makima edge agent is live."
+ ;;
+ 2)
+ echo ""
+ info "Starting local development server..."
+ echo ""
+ info "Press Ctrl+C to stop."
+ echo ""
+ npx wrangler dev
+ ;;
+ 3|*)
+ ;;
+esac
+
+# ---------------------------------------------------------------------------
+# 8. Next Steps
+# ---------------------------------------------------------------------------
+
+separator
+
+echo -e "${BOLD}${GREEN}🎉 Makima Cloudflare Agent is ready!${NC}"
+echo ""
+echo -e " ${BOLD}Useful commands:${NC}"
+echo ""
+echo -e " ${CYAN}npm run dev${NC} Start local development server"
+echo -e " ${CYAN}npm run deploy${NC} Deploy to Cloudflare Workers"
+echo -e " ${CYAN}npm run tail${NC} Stream production logs"
+echo ""
+echo -e " ${BOLD}API Endpoints (after deploy):${NC}"
+echo ""
+echo -e " ${CYAN}GET /status${NC} Agent connection status"
+echo -e " ${CYAN}GET /health${NC} Health check"
+echo -e " ${CYAN}GET /tasks${NC} Task dispatch history"
+echo -e " ${CYAN}GET /logs${NC} Connection event logs"
+echo -e " ${CYAN}POST /reconnect${NC} Force upstream reconnection"
+echo -e " ${CYAN}WS /ws/daemon${NC} Downstream daemon WebSocket"
+echo ""
+echo -e " ${BOLD}Architecture:${NC}"
+echo ""
+echo -e " Makima Server ←WebSocket→ ${CYAN}Edge Agent${NC} ←WebSocket→ Native Daemons"
+echo ""
+echo -e " ${BOLD}Documentation:${NC}"
+echo -e " See ${CYAN}README.md${NC} for full setup and architecture details."
+echo ""
diff --git a/makima/cloudflare-agent/src/agent.ts b/makima/cloudflare-agent/src/agent.ts
new file mode 100644
index 0000000..a5a7823
--- /dev/null
+++ b/makima/cloudflare-agent/src/agent.ts
@@ -0,0 +1,773 @@
+/**
+ * MakimaAgent — Cloudflare Durable Object Agent
+ *
+ * Acts as an edge relay between the Makima server and downstream daemon
+ * instances. It does NOT execute tasks itself (that requires native process
+ * spawning, git, filesystem access). Instead it:
+ *
+ * 1. Maintains a persistent WebSocket to the Makima server (upstream).
+ * 2. Accepts WebSocket connections from native daemons (downstream).
+ * 3. Relays messages bidirectionally between upstream and downstream.
+ * 4. Tracks task dispatch history and daemon health in SQLite.
+ * 5. Exposes an HTTP API for status and management.
+ */
+
+import { Agent } from "agents";
+import type { Connection, ConnectionContext, WSMessage } from "agents";
+import type {
+ Env,
+ AgentState,
+ DaemonMessage,
+ DaemonCommand,
+ TaskRecord,
+ DownstreamDaemon,
+ StatusResponse,
+ TaskHistoryResponse,
+} from "./types";
+
+// ---------------------------------------------------------------------------
+// Constants
+// ---------------------------------------------------------------------------
+
+const HEARTBEAT_INTERVAL_MS = 30_000; // 30s
+const RECONNECT_BASE_MS = 1_000; // 1s initial backoff
+const RECONNECT_MAX_MS = 60_000; // 60s max backoff
+const MAX_RECONNECT_ATTEMPTS = 20;
+const TASK_HISTORY_MAX = 500;
+
+// ---------------------------------------------------------------------------
+// MakimaAgent Durable Object
+// ---------------------------------------------------------------------------
+
+export class MakimaAgent extends Agent<Env, AgentState> {
+ // -- Upstream (Makima server) connection --
+ private upstreamWs: WebSocket | null = null;
+ private heartbeatInterval: ReturnType<typeof setInterval> | null = null;
+ private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;
+
+ // -- Downstream (native daemon) connections --
+ private downstreamDaemons: Map<string, DownstreamDaemon> = new Map();
+
+ // -- Bookkeeping --
+ private totalTasksProcessed = 0;
+
+ // -- Default state for new agent instances --
+ initialState: AgentState = {
+ connected: false,
+ lastConnectedAt: null,
+ lastHeartbeatAt: null,
+ reconnectAttempts: 0,
+ daemonId: null,
+ activeTasks: [],
+ };
+
+ // =========================================================================
+ // Lifecycle
+ // =========================================================================
+
+ /**
+ * Called once when the Durable Object is first instantiated.
+ * Sets up the SQLite schema and establishes the upstream connection.
+ */
+ async onStart(): Promise<void> {
+ this.initDatabase();
+ this.loadStats();
+
+ // Attempt upstream connection
+ await this.connectUpstream();
+ }
+
+ // =========================================================================
+ // SQLite Schema
+ // =========================================================================
+
+ private initDatabase(): void {
+ // Use the raw storage sql for DDL since tagged template doesn't support multi-statement
+ this.ctx.storage.sql.exec(`
+ CREATE TABLE IF NOT EXISTS task_history (
+ task_id TEXT PRIMARY KEY,
+ task_name TEXT NOT NULL,
+ status TEXT NOT NULL DEFAULT 'pending',
+ dispatched_to TEXT,
+ received_at TEXT NOT NULL,
+ dispatched_at TEXT,
+ completed_at TEXT,
+ error TEXT
+ )
+ `);
+ this.ctx.storage.sql.exec(`
+ CREATE TABLE IF NOT EXISTS connection_log (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ event TEXT NOT NULL,
+ timestamp TEXT NOT NULL,
+ details TEXT
+ )
+ `);
+ this.ctx.storage.sql.exec(`
+ CREATE INDEX IF NOT EXISTS idx_task_history_status
+ ON task_history(status)
+ `);
+ this.ctx.storage.sql.exec(`
+ CREATE INDEX IF NOT EXISTS idx_task_history_received
+ ON task_history(received_at DESC)
+ `);
+ }
+
+ private loadStats(): void {
+ const rows = this.sql<{ cnt: number }>`SELECT COUNT(*) as cnt FROM task_history`;
+ this.totalTasksProcessed = rows[0]?.cnt ?? 0;
+ }
+
+ // =========================================================================
+ // Upstream (Makima Server) Connection
+ // =========================================================================
+
+ private async connectUpstream(): Promise<void> {
+ const serverUrl = this.env.MAKIMA_SERVER_URL;
+ const apiKey = this.env.MAKIMA_API_KEY;
+
+ if (!serverUrl || !apiKey) {
+ this.logConnection(
+ "error",
+ "Missing MAKIMA_SERVER_URL or MAKIMA_API_KEY"
+ );
+ return;
+ }
+
+ // Normalize URL: ensure it ends with /ws/daemon
+ let wsUrl = serverUrl;
+ if (!wsUrl.endsWith("/ws/daemon")) {
+ wsUrl = wsUrl.replace(/\/$/, "") + "/ws/daemon";
+ }
+
+ try {
+ // Cloudflare Workers use the standard WebSocket API via fetch upgrade
+ const resp = await fetch(wsUrl, {
+ headers: {
+ Upgrade: "websocket",
+ },
+ });
+
+ const ws = resp.webSocket;
+ if (!ws) {
+ throw new Error(`WebSocket upgrade failed (status ${resp.status})`);
+ }
+
+ ws.accept();
+ this.upstreamWs = ws;
+
+ // Authenticate immediately
+ const authMsg: DaemonMessage = {
+ type: "authenticate",
+ apiKey,
+ machineId: `cf-agent-${this.name}`,
+ hostname: `cloudflare-edge-${this.name}`,
+ maxConcurrentTasks: 0, // Relay only — does not execute tasks directly
+ };
+ ws.send(JSON.stringify(authMsg));
+
+ // Wire up event handlers
+ ws.addEventListener("message", (event) => {
+ this.handleUpstreamMessage(event);
+ });
+
+ ws.addEventListener("close", (event) => {
+ this.handleUpstreamClose(event.code, event.reason);
+ });
+
+ ws.addEventListener("error", () => {
+ this.logConnection("error", "Upstream WebSocket error");
+ this.handleUpstreamClose(1006, "WebSocket error");
+ });
+
+ // Start heartbeat
+ this.startHeartbeat();
+
+ this.logConnection("connected", `Connected to ${wsUrl}`);
+ } catch (err) {
+ const msg = err instanceof Error ? err.message : String(err);
+ this.logConnection("error", `Failed to connect: ${msg}`);
+ this.scheduleReconnect();
+ }
+ }
+
+ private handleUpstreamMessage(event: MessageEvent): void {
+ let command: DaemonCommand;
+ try {
+ command = JSON.parse(
+ typeof event.data === "string" ? event.data : ""
+ ) as DaemonCommand;
+ } catch {
+ this.logConnection("error", "Failed to parse upstream message");
+ return;
+ }
+
+ switch (command.type) {
+ case "authenticated":
+ this.onUpstreamAuthenticated(command.daemonId);
+ break;
+
+ case "spawnTask":
+ this.onSpawnTask(command);
+ break;
+
+ case "pauseTask":
+ case "resumeTask":
+ case "interruptTask":
+ case "sendMessage":
+ // Forward task control commands to the appropriate downstream daemon
+ this.forwardToDownstream(command);
+ break;
+
+ default:
+ // Forward any unrecognized commands to all downstream daemons
+ this.broadcastToDownstream(JSON.stringify(command));
+ break;
+ }
+ }
+
+ private onUpstreamAuthenticated(daemonId: string): void {
+ this.setState({
+ ...this.state,
+ connected: true,
+ lastConnectedAt: new Date().toISOString(),
+ reconnectAttempts: 0,
+ daemonId,
+ });
+
+ this.logConnection(
+ "authenticated",
+ `Authenticated as daemon ${daemonId}`
+ );
+ }
+
+ private onSpawnTask(command: Extract<DaemonCommand, { type: "spawnTask" }>): void {
+ // Record in task history
+ const now = new Date().toISOString();
+ const taskId = command.taskId;
+ const taskName = command.taskName;
+ this.sql`INSERT OR REPLACE INTO task_history (task_id, task_name, status, received_at)
+ VALUES (${taskId}, ${taskName}, 'pending', ${now})`;
+ this.totalTasksProcessed++;
+
+ // Find the best downstream daemon to dispatch to
+ const daemon = this.selectDownstreamDaemon();
+ if (daemon) {
+ this.dispatchTaskToDownstream(daemon, command);
+ } else {
+ // No downstream daemons connected — store as pending
+ this.logConnection(
+ "warning",
+ `No downstream daemons available for task ${command.taskId}`
+ );
+ // Notify upstream that we can't handle this task right now
+ this.sendUpstream({
+ type: "taskStatusChange",
+ taskId: command.taskId,
+ oldStatus: "pending",
+ newStatus: "pending",
+ });
+ }
+ }
+
+ private dispatchTaskToDownstream(
+ daemon: DownstreamDaemon,
+ command: Extract<DaemonCommand, { type: "spawnTask" }>
+ ): void {
+ try {
+ daemon.ws.send(JSON.stringify(command));
+ daemon.activeTasks.add(command.taskId);
+
+ const now = new Date().toISOString();
+ const did = daemon.id;
+ const tid = command.taskId;
+ this.sql`UPDATE task_history
+ SET status = 'dispatched', dispatched_to = ${did}, dispatched_at = ${now}
+ WHERE task_id = ${tid}`;
+
+ this.setState({
+ ...this.state,
+ activeTasks: [...this.state.activeTasks, command.taskId],
+ });
+
+ this.logConnection(
+ "dispatch",
+ `Task ${command.taskId} dispatched to daemon ${daemon.hostname}`
+ );
+ } catch (err) {
+ this.logConnection(
+ "error",
+ `Failed to dispatch task ${command.taskId}: ${err}`
+ );
+ }
+ }
+
+ private selectDownstreamDaemon(): DownstreamDaemon | null {
+ let best: DownstreamDaemon | null = null;
+ let leastTasks = Infinity;
+
+ for (const daemon of this.downstreamDaemons.values()) {
+ if (daemon.activeTasks.size < daemon.maxConcurrentTasks) {
+ if (daemon.activeTasks.size < leastTasks) {
+ leastTasks = daemon.activeTasks.size;
+ best = daemon;
+ }
+ }
+ }
+ return best;
+ }
+
+ private forwardToDownstream(command: DaemonCommand): void {
+ // Find which downstream daemon has this task
+ const taskId = "taskId" in command ? (command as { taskId: string }).taskId : null;
+ if (!taskId) return;
+
+ for (const daemon of this.downstreamDaemons.values()) {
+ if (daemon.activeTasks.has(taskId)) {
+ daemon.ws.send(JSON.stringify(command));
+ return;
+ }
+ }
+
+ this.logConnection(
+ "warning",
+ `No downstream daemon found for task ${taskId}`
+ );
+ }
+
+ private broadcastToDownstream(message: string): void {
+ for (const daemon of this.downstreamDaemons.values()) {
+ try {
+ daemon.ws.send(message);
+ } catch {
+ // Ignore send failures on individual daemons
+ }
+ }
+ }
+
+ // =========================================================================
+ // Downstream (Native Daemon) WebSocket Handling
+ // =========================================================================
+
+ /**
+ * Called by the Agents SDK when a client connects via WebSocket.
+ * In our architecture, "clients" are native Makima daemons that connect
+ * to this edge relay to receive task dispatches.
+ */
+ onConnect(connection: Connection, ctx: ConnectionContext): void {
+ const daemonId = crypto.randomUUID();
+ const daemon: DownstreamDaemon = {
+ id: daemonId,
+ ws: connection as unknown as WebSocket,
+ hostname: "unknown",
+ maxConcurrentTasks: 10,
+ activeTasks: new Set(),
+ lastHeartbeat: new Date().toISOString(),
+ };
+ this.downstreamDaemons.set(daemonId, daemon);
+
+ this.logConnection(
+ "downstream_connect",
+ `Downstream daemon connected: ${daemonId}`
+ );
+ }
+
+ /**
+ * Called when a downstream daemon sends a message.
+ */
+ onMessage(connection: Connection, message: WSMessage): void {
+ const data =
+ typeof message === "string"
+ ? message
+ : message instanceof ArrayBuffer
+ ? new TextDecoder().decode(message)
+ : "";
+ let parsed: DaemonMessage;
+ try {
+ parsed = JSON.parse(data) as DaemonMessage;
+ } catch {
+ return;
+ }
+
+ // Find which downstream daemon sent this
+ const daemon = this.findDaemonByConnection(connection);
+
+ // Handle authenticate from downstream daemons
+ if (parsed.type === "authenticate" && daemon) {
+ daemon.hostname = (parsed as Extract<DaemonMessage, { type: "authenticate" }>).hostname;
+ daemon.maxConcurrentTasks = (parsed as Extract<DaemonMessage, { type: "authenticate" }>).maxConcurrentTasks;
+ // Send back a synthetic authentication confirmation
+ connection.send(
+ JSON.stringify({
+ type: "authenticated",
+ daemonId: daemon.id,
+ })
+ );
+ return;
+ }
+
+ // Handle heartbeats from downstream
+ if (parsed.type === "heartbeat" && daemon) {
+ daemon.lastHeartbeat = new Date().toISOString();
+ return;
+ }
+
+ // Handle task completion from downstream
+ if (parsed.type === "taskComplete" && daemon) {
+ const tc = parsed as Extract<DaemonMessage, { type: "taskComplete" }>;
+ daemon.activeTasks.delete(tc.taskId);
+
+ const status = tc.success ? "completed" : "failed";
+ const now = new Date().toISOString();
+ const errMsg = tc.error ?? null;
+ const tid = tc.taskId;
+ this.sql`UPDATE task_history
+ SET status = ${status}, completed_at = ${now}, error = ${errMsg}
+ WHERE task_id = ${tid}`;
+
+ this.setState({
+ ...this.state,
+ activeTasks: this.state.activeTasks.filter((id) => id !== tc.taskId),
+ });
+ }
+
+ // Forward all daemon messages to the upstream server
+ this.sendUpstream(parsed);
+ }
+
+ /**
+ * Called when a downstream daemon disconnects.
+ */
+ onClose(connection: Connection, code: number, reason: string, wasClean: boolean): void {
+ const daemon = this.findDaemonByConnection(connection);
+ if (daemon) {
+ this.logConnection(
+ "downstream_disconnect",
+ `Downstream daemon ${daemon.hostname} disconnected: code=${code} reason=${reason} clean=${wasClean}`
+ );
+ this.downstreamDaemons.delete(daemon.id);
+ }
+ }
+
+ onError(connectionOrError: Connection | unknown, error?: unknown): void {
+ // Handle the overloaded signature: (connection, error) or (error)
+ if (error !== undefined) {
+ const connection = connectionOrError as Connection;
+ const daemon = this.findDaemonByConnection(connection);
+ if (daemon) {
+ this.logConnection(
+ "error",
+ `Downstream daemon ${daemon.hostname} error: ${error}`
+ );
+ }
+ } else {
+ this.logConnection("error", `Agent error: ${connectionOrError}`);
+ }
+ }
+
+ private findDaemonByConnection(connection: Connection): DownstreamDaemon | undefined {
+ for (const daemon of this.downstreamDaemons.values()) {
+ if (daemon.ws === (connection as unknown as WebSocket)) {
+ return daemon;
+ }
+ }
+ return undefined;
+ }
+
+ // =========================================================================
+ // Heartbeat
+ // =========================================================================
+
+ private startHeartbeat(): void {
+ this.stopHeartbeat();
+ this.heartbeatInterval = setInterval(() => {
+ this.sendHeartbeat();
+ }, HEARTBEAT_INTERVAL_MS);
+ }
+
+ private stopHeartbeat(): void {
+ if (this.heartbeatInterval) {
+ clearInterval(this.heartbeatInterval);
+ this.heartbeatInterval = null;
+ }
+ }
+
+ private sendHeartbeat(): void {
+ const activeTasks = this.state.activeTasks;
+ this.sendUpstream({
+ type: "heartbeat",
+ activeTasks,
+ });
+ this.setState({
+ ...this.state,
+ lastHeartbeatAt: new Date().toISOString(),
+ });
+ }
+
+ // =========================================================================
+ // Upstream Reconnection
+ // =========================================================================
+
+ private handleUpstreamClose(code: number, reason: string): void {
+ this.upstreamWs = null;
+ this.stopHeartbeat();
+
+ this.setState({
+ ...this.state,
+ connected: false,
+ });
+
+ this.logConnection(
+ "disconnected",
+ `Upstream disconnected: code=${code} reason=${reason}`
+ );
+
+ this.scheduleReconnect();
+ }
+
+ private scheduleReconnect(): void {
+ if (this.reconnectTimeout) {
+ clearTimeout(this.reconnectTimeout);
+ }
+
+ const attempts = this.state.reconnectAttempts;
+ if (attempts >= MAX_RECONNECT_ATTEMPTS) {
+ this.logConnection(
+ "error",
+ `Max reconnect attempts (${MAX_RECONNECT_ATTEMPTS}) reached — giving up`
+ );
+ return;
+ }
+
+ // Exponential backoff with jitter
+ const delay = Math.min(
+ RECONNECT_BASE_MS * Math.pow(2, attempts) +
+ Math.random() * RECONNECT_BASE_MS,
+ RECONNECT_MAX_MS
+ );
+
+ this.setState({
+ ...this.state,
+ reconnectAttempts: attempts + 1,
+ });
+
+ this.logConnection(
+ "reconnecting",
+ `Scheduling reconnect in ${Math.round(delay)}ms (attempt ${attempts + 1})`
+ );
+
+ this.reconnectTimeout = setTimeout(() => {
+ this.connectUpstream();
+ }, delay);
+ }
+
+ // =========================================================================
+ // Upstream Send Helper
+ // =========================================================================
+
+ private sendUpstream(message: DaemonMessage): void {
+ if (!this.upstreamWs) return;
+ try {
+ this.upstreamWs.send(JSON.stringify(message));
+ } catch {
+ this.logConnection("error", "Failed to send upstream message");
+ }
+ }
+
+ // =========================================================================
+ // Connection Logging
+ // =========================================================================
+
+ private logConnection(event: string, details: string): void {
+ try {
+ const now = new Date().toISOString();
+ this.sql`INSERT INTO connection_log (event, timestamp, details)
+ VALUES (${event}, ${now}, ${details})`;
+
+ // Prune old logs (keep last 200)
+ this.ctx.storage.sql.exec(`
+ DELETE FROM connection_log
+ WHERE id NOT IN (
+ SELECT id FROM connection_log ORDER BY id DESC LIMIT 200
+ )
+ `);
+ } catch {
+ // Swallow — logging should never break the agent
+ }
+ }
+
+ // =========================================================================
+ // RPC Methods (callable from Agent SDK clients)
+ // =========================================================================
+
+ /** Returns the current status of the edge relay agent. */
+ getStatus(): StatusResponse {
+ const agentName = this.env.MAKIMA_AGENT_NAME ?? `makima-edge-${this.name}`;
+
+ return {
+ status: this.state.connected
+ ? this.downstreamDaemons.size > 0
+ ? "ok"
+ : "degraded"
+ : "disconnected",
+ agentName,
+ upstreamConnected: this.state.connected,
+ daemonId: this.state.daemonId,
+ lastHeartbeat: this.state.lastHeartbeatAt,
+ connectedDaemons: this.downstreamDaemons.size,
+ activeTasks: this.state.activeTasks.length,
+ totalTasksProcessed: this.totalTasksProcessed,
+ };
+ }
+
+ /** Returns paginated task history from the SQLite store. */
+ getTaskHistory(limit = 50, offset = 0): TaskHistoryResponse {
+ const clampedLimit = Math.min(Math.max(1, limit), TASK_HISTORY_MAX);
+
+ const rows = this.sql<TaskRecord>`
+ SELECT task_id as taskId, task_name as taskName, status,
+ dispatched_to as dispatchedTo, received_at as receivedAt,
+ dispatched_at as dispatchedAt, completed_at as completedAt, error
+ FROM task_history
+ ORDER BY received_at DESC
+ LIMIT ${clampedLimit} OFFSET ${offset}
+ `;
+
+ const totalRows = this.sql<{ cnt: number }>`SELECT COUNT(*) as cnt FROM task_history`;
+
+ return {
+ tasks: rows,
+ total: totalRows[0]?.cnt ?? 0,
+ limit: clampedLimit,
+ offset,
+ };
+ }
+
+ /** Force a reconnection to the upstream Makima server. */
+ reconnect(): { success: boolean; message: string } {
+ // Close existing connection if any
+ if (this.upstreamWs) {
+ try {
+ this.upstreamWs.close(1000, "Manual reconnect requested");
+ } catch {
+ // Ignore
+ }
+ this.upstreamWs = null;
+ }
+
+ this.stopHeartbeat();
+
+ // Reset reconnect counter
+ this.setState({
+ ...this.state,
+ reconnectAttempts: 0,
+ connected: false,
+ });
+
+ // Start fresh connection
+ this.connectUpstream();
+
+ return {
+ success: true,
+ message: "Reconnection initiated",
+ };
+ }
+
+ // =========================================================================
+ // HTTP Request Handler
+ // =========================================================================
+
+ /**
+ * Handles HTTP requests routed to this Durable Object.
+ * Provides a REST API for management and status.
+ */
+ async onRequest(request: Request): Promise<Response> {
+ const url = new URL(request.url);
+ const path = url.pathname;
+
+ // CORS headers for browser-based clients
+ const corsHeaders: Record<string, string> = {
+ "Access-Control-Allow-Origin": "*",
+ "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
+ };
+
+ if (request.method === "OPTIONS") {
+ return new Response(null, { status: 204, headers: corsHeaders });
+ }
+
+ const jsonHeaders: Record<string, string> = {
+ "Content-Type": "application/json",
+ ...corsHeaders,
+ };
+
+ try {
+ // GET /status — Agent status
+ if (path === "/status" || path === "/") {
+ return new Response(JSON.stringify(this.getStatus()), {
+ headers: jsonHeaders,
+ });
+ }
+
+ // GET /tasks — Task history
+ if (path === "/tasks" && request.method === "GET") {
+ const limit = parseInt(url.searchParams.get("limit") ?? "50", 10);
+ const offset = parseInt(url.searchParams.get("offset") ?? "0", 10);
+ return new Response(
+ JSON.stringify(this.getTaskHistory(limit, offset)),
+ { headers: jsonHeaders }
+ );
+ }
+
+ // POST /reconnect — Force reconnection
+ if (path === "/reconnect" && request.method === "POST") {
+ return new Response(JSON.stringify(this.reconnect()), {
+ headers: jsonHeaders,
+ });
+ }
+
+ // GET /logs — Connection logs
+ if (path === "/logs" && request.method === "GET") {
+ const logLimit = Math.min(
+ parseInt(url.searchParams.get("limit") ?? "50", 10),
+ 200
+ );
+ const rows = this.sql<{
+ id: number;
+ event: string;
+ timestamp: string;
+ details: string | null;
+ }>`SELECT id, event, timestamp, details
+ FROM connection_log
+ ORDER BY id DESC
+ LIMIT ${logLimit}`;
+ return new Response(JSON.stringify({ logs: rows }), {
+ headers: jsonHeaders,
+ });
+ }
+
+ // GET /health — Simple health check
+ if (path === "/health") {
+ return new Response(
+ JSON.stringify({
+ healthy: true,
+ upstreamConnected: this.state.connected,
+ }),
+ { headers: jsonHeaders }
+ );
+ }
+
+ return new Response(JSON.stringify({ error: "Not found" }), {
+ status: 404,
+ headers: jsonHeaders,
+ });
+ } catch (err) {
+ return new Response(
+ JSON.stringify({
+ error: err instanceof Error ? err.message : "Internal error",
+ }),
+ { status: 500, headers: jsonHeaders }
+ );
+ }
+ }
+}
diff --git a/makima/cloudflare-agent/src/index.ts b/makima/cloudflare-agent/src/index.ts
new file mode 100644
index 0000000..0b64af4
--- /dev/null
+++ b/makima/cloudflare-agent/src/index.ts
@@ -0,0 +1,47 @@
+/**
+ * Makima Cloudflare Agent — Worker Entry Point
+ *
+ * Routes incoming requests to the MakimaAgent Durable Object which manages
+ * the upstream WebSocket connection to the Makima server and relays tasks
+ * to downstream native daemon instances.
+ *
+ * Routes:
+ * GET / → Agent status (JSON)
+ * GET /status → Agent status (JSON)
+ * GET /health → Health check
+ * GET /tasks → Task history (paginated)
+ * GET /logs → Connection logs
+ * POST /reconnect → Force upstream reconnection
+ * * /ws → WebSocket upgrade for downstream daemons
+ * * /agent/* → Forwarded to Agent's onRequest handler
+ */
+
+import { MakimaAgent } from "./agent";
+import type { Env } from "./types";
+
+export { MakimaAgent };
+
+export default {
+ async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
+ const url = new URL(request.url);
+
+ // Use a singleton Durable Object — all traffic routes to one agent
+ // instance identified by a fixed name. This ensures a single persistent
+ // upstream WebSocket to the Makima server.
+ const agentId = env.MAKIMA_AGENT.idFromName("makima-relay-primary");
+ const agent = env.MAKIMA_AGENT.get(agentId);
+
+ // WebSocket upgrade path — downstream daemons connect here
+ if (url.pathname === "/ws" || url.pathname === "/ws/daemon") {
+ const upgradeHeader = request.headers.get("Upgrade");
+ if (upgradeHeader !== "websocket") {
+ return new Response("Expected WebSocket upgrade", { status: 426 });
+ }
+ // Forward the WebSocket upgrade to the Durable Object
+ return agent.fetch(request);
+ }
+
+ // All other routes are forwarded to the Durable Object's onRequest handler
+ return agent.fetch(request);
+ },
+};
diff --git a/makima/cloudflare-agent/src/types.ts b/makima/cloudflare-agent/src/types.ts
new file mode 100644
index 0000000..d2ab20a
--- /dev/null
+++ b/makima/cloudflare-agent/src/types.ts
@@ -0,0 +1,148 @@
+/**
+ * Type definitions for the Makima Cloudflare Agent.
+ *
+ * These types mirror the daemon-server WebSocket protocol defined in
+ * makima/src/daemon/ws/protocol.rs. Only the subset relevant to the
+ * edge relay is included here.
+ */
+
+// ---------------------------------------------------------------------------
+// Worker Environment
+// ---------------------------------------------------------------------------
+
+export interface Env {
+ /** Durable Object binding for MakimaAgent instances. */
+ MAKIMA_AGENT: DurableObjectNamespace;
+ /** Makima server WebSocket URL (e.g. wss://api.makima.jp). */
+ MAKIMA_SERVER_URL: string;
+ /** API key for authenticating with the Makima server. */
+ MAKIMA_API_KEY: string;
+ /** Optional: human-readable name for this edge agent. */
+ MAKIMA_AGENT_NAME?: string;
+}
+
+// ---------------------------------------------------------------------------
+// Agent State (persisted in Durable Object SQLite)
+// ---------------------------------------------------------------------------
+
+export interface AgentState {
+ /** Whether the upstream WebSocket is currently connected. */
+ connected: boolean;
+ /** ISO-8601 timestamp of last successful connection. */
+ lastConnectedAt: string | null;
+ /** ISO-8601 timestamp of last heartbeat sent. */
+ lastHeartbeatAt: string | null;
+ /** Number of consecutive reconnect failures. */
+ reconnectAttempts: number;
+ /** Daemon ID assigned by the server after authentication. */
+ daemonId: string | null;
+ /** Active task IDs being tracked through this relay. */
+ activeTasks: string[];
+}
+
+export const DEFAULT_AGENT_STATE: AgentState = {
+ connected: false,
+ lastConnectedAt: null,
+ lastHeartbeatAt: null,
+ reconnectAttempts: 0,
+ daemonId: null,
+ activeTasks: [],
+};
+
+// ---------------------------------------------------------------------------
+// Daemon → Server Messages (subset used by the relay)
+// ---------------------------------------------------------------------------
+
+export type DaemonMessage =
+ | { type: "authenticate"; apiKey: string; machineId: string; hostname: string; maxConcurrentTasks: number }
+ | { type: "heartbeat"; activeTasks: string[] }
+ | { type: "taskOutput"; taskId: string; output: string; isPartial: boolean }
+ | { type: "taskStatusChange"; taskId: string; oldStatus: string; newStatus: string }
+ | { type: "taskProgress"; taskId: string; summary: string }
+ | { type: "taskComplete"; taskId: string; success: boolean; error?: string };
+
+// ---------------------------------------------------------------------------
+// Server → Daemon Commands (subset relevant to the relay)
+// ---------------------------------------------------------------------------
+
+export type DaemonCommand =
+ | { type: "authenticated"; daemonId: string }
+ | { type: "spawnTask"; taskId: string; taskName: string; plan: string; repoUrl?: string; baseBranch?: string; targetBranch?: string; contractId?: string; depth: number; isOrchestrator: boolean }
+ | { type: "pauseTask"; taskId: string }
+ | { type: "resumeTask"; taskId: string }
+ | { type: "interruptTask"; taskId: string; graceful: boolean }
+ | { type: "sendMessage"; taskId: string; message: string };
+
+// ---------------------------------------------------------------------------
+// Task History Record (stored in SQLite)
+// ---------------------------------------------------------------------------
+
+export interface TaskRecord {
+ /** UUID of the task. */
+ taskId: string;
+ /** Human-readable task name. */
+ taskName: string;
+ /** Current status: pending | dispatched | completed | failed. */
+ status: string;
+ /** Which downstream daemon received this task. */
+ dispatchedTo: string | null;
+ /** ISO-8601 timestamp when the task was received. */
+ receivedAt: string;
+ /** ISO-8601 timestamp when the task was dispatched downstream. */
+ dispatchedAt: string | null;
+ /** ISO-8601 timestamp when the task completed. */
+ completedAt: string | null;
+ /** Error message if failed. */
+ error: string | null;
+}
+
+// ---------------------------------------------------------------------------
+// Connected Downstream Daemon
+// ---------------------------------------------------------------------------
+
+export interface DownstreamDaemon {
+ /** Unique ID for this downstream connection. */
+ id: string;
+ /** WebSocket connection to this daemon. */
+ ws: WebSocket;
+ /** Human-readable hostname. */
+ hostname: string;
+ /** Maximum concurrent tasks this daemon supports. */
+ maxConcurrentTasks: number;
+ /** Currently active task IDs on this daemon. */
+ activeTasks: Set<string>;
+ /** ISO-8601 timestamp of last heartbeat received. */
+ lastHeartbeat: string;
+}
+
+// ---------------------------------------------------------------------------
+// HTTP API Response Types
+// ---------------------------------------------------------------------------
+
+export interface StatusResponse {
+ status: "ok" | "degraded" | "disconnected";
+ agentName: string;
+ upstreamConnected: boolean;
+ daemonId: string | null;
+ lastHeartbeat: string | null;
+ connectedDaemons: number;
+ activeTasks: number;
+ totalTasksProcessed: number;
+}
+
+export interface TaskHistoryResponse {
+ tasks: TaskRecord[];
+ total: number;
+ limit: number;
+ offset: number;
+}
+
+// ---------------------------------------------------------------------------
+// RPC method types for the Agent
+// ---------------------------------------------------------------------------
+
+export interface AgentRPC {
+ getStatus: () => StatusResponse;
+ getTaskHistory: (limit?: number, offset?: number) => TaskHistoryResponse;
+ reconnect: () => { success: boolean; message: string };
+}
diff --git a/makima/cloudflare-agent/tsconfig.json b/makima/cloudflare-agent/tsconfig.json
new file mode 100644
index 0000000..ed1dd65
--- /dev/null
+++ b/makima/cloudflare-agent/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ES2022",
+ "moduleResolution": "bundler",
+ "lib": ["ES2022"],
+ "types": ["@cloudflare/workers-types"],
+ "strict": true,
+ "noEmit": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true
+ },
+ "include": ["src/**/*.ts"],
+ "exclude": ["node_modules"]
+}
diff --git a/makima/cloudflare-agent/wrangler.toml b/makima/cloudflare-agent/wrangler.toml
new file mode 100644
index 0000000..11f5c66
--- /dev/null
+++ b/makima/cloudflare-agent/wrangler.toml
@@ -0,0 +1,20 @@
+name = "makima-agent"
+main = "src/index.ts"
+compatibility_date = "2024-12-01"
+compatibility_flags = ["nodejs_compat"]
+
+[observability]
+enabled = true
+
+[vars]
+# Non-secret configuration — override via .dev.vars for local dev
+# MAKIMA_SERVER_URL = "wss://api.makima.jp"
+
+[durable_objects]
+bindings = [
+ { name = "MAKIMA_AGENT", class_name = "MakimaAgent" }
+]
+
+[[migrations]]
+tag = "v1"
+new_sqlite_classes = ["MakimaAgent"]