From f5b30dd5c271ccc9a6160774c4b1d05aced1b76e Mon Sep 17 00:00:00 2001 From: Trailgenic Date: Wed, 15 Jul 2026 16:43:35 -0700 Subject: [PATCH 1/3] Refresh documents registry packet and acceptance --- .github/workflows/ci.yml | 18 ++ .github/workflows/deploy.yml | 61 ++-- README.md | 18 +- SYSTEM_MAP.md | 2 +- lib/http.js | 32 +- lib/queries.js | 23 +- lib/registry.js | 44 ++- package-lock.json | 23 ++ package.json | 25 ++ registry/SUBMISSION.md | 56 +--- registry/packet.json | 53 +--- registry/server.json | 15 +- scripts/build-registry-packet.mjs | 4 +- scripts/check-registry-packet.mjs | 6 + scripts/live-acceptance.mjs | 97 ++---- scripts/source-check.mjs | 18 ++ scripts/validate-json.mjs | 3 + tests/registry.test.mjs | 7 + vitest.config.mjs | 1 + worker.js | 476 ++---------------------------- 20 files changed, 291 insertions(+), 691 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 scripts/check-registry-packet.mjs create mode 100644 scripts/source-check.mjs create mode 100644 scripts/validate-json.mjs create mode 100644 tests/registry.test.mjs create mode 100644 vitest.config.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5077d40 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,18 @@ +name: CI +on: + pull_request: + push: +jobs: + verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: { node-version: 22, cache: npm } + - run: npm ci + - run: npm run lint + - run: npm test + - run: npm run test:workers + - run: npm run validate:json + - run: npm run registry:check + - run: npm run deploy:dry-run diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8a83c48..69a09de 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,47 +1,28 @@ -name: Deploy to Cloudflare - +name: Deploy on: - push: - branches: [main] workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: deploy-${{ github.ref }} - cancel-in-progress: true - jobs: - deploy: + verify: runs-on: ubuntu-latest - name: deploy (${{ matrix.name }}) - strategy: - fail-fast: false - matrix: - include: - - name: exmxc-workers - config: wrangler.jsonc steps: - - uses: actions/checkout@v5 - - name: Deploy ${{ matrix.name }} - uses: cloudflare/wrangler-action@v4 - with: - apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} - accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - wranglerVersion: "4" - command: deploy --config ${{ matrix.config }} - - verify: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: { node-version: 22, cache: npm } + - run: npm ci + - run: npm run lint + - run: npm test + - run: npm run test:workers + - run: npm run validate:json + - run: npm run registry:check + - run: npm run deploy:dry-run + deploy: + needs: verify runs-on: ubuntu-latest - name: verify live - needs: deploy steps: - - uses: actions/checkout@v5 - - uses: actions/setup-node@v5 - with: - node-version: "22" - - name: Wait for edge propagation - run: sleep 25 - - name: Live acceptance - run: node scripts/live-acceptance.mjs + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: { node-version: 22, cache: npm } + - run: npm ci + - run: npx wrangler deploy + - run: sleep 30 + - run: node scripts/live-acceptance.mjs diff --git a/README.md b/README.md index 9a6639f..76508fd 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The code keeps the ES-module Worker entrypoint (`export default { fetch(request, Canonical MCP discovery is served from `https://mcp.exmxc.ai/.well-known/mcp.json`; the apex `https://exmxc.ai/.well-known/mcp.json` is intentionally not served because the apex is Webflow on a DNS-only record. The transport endpoint is `https://mcp.exmxc.ai/mcp`. -- `GET /` — REST/WebMCP discovery document +- `GET /` — REST/MCP discovery document - `GET /.well-known/mcp.json` — MCP discovery pointer - `GET /capabilities.json` — generated capability inventory - `GET /.well-known/tool-registry.json` — generated tool registry @@ -253,3 +253,19 @@ scripts/build-registry-packet.mjs Registry packet generator registry/ Generated MCP registry submission packet workers/root-discovery/worker.js Unused root .well-known MCP pointer Worker reference ``` + +## MCP modernization notes (v2.3.0) + +exmxc exposes a REST/JSON intelligence API plus an MCP server using Streamable HTTP on Cloudflare Workers. Tool and resource inventories are generated from `lib/registry.js`; public REST aliases and bundled dataset payloads are preserved. + +### ADS signal route + +`GET /api/ai-jobs-signal` without signal parameters returns the deterministic public benchmark. Paid signal generation uses `POST /api/ai-jobs-signal` and requires `Authorization: Bearer `. The Cloudflare deployment should add a rate rule on this path as defense in depth. + +### Audit route + +`/audit/run` and the `ex.eei.audit.run` tool remain public but validate targets before contacting the upstream audit service. The upstream service at `exmxc-audit.vercel.app` must independently enforce DNS-resolution and redirect checks against private, loopback, link-local, and reserved ranges; that external security dependency is not satisfied by this repository alone. Conservative Cloudflare rate limiting should be applied to `/audit/run` and audit calls arriving via `/mcp` as deployment configuration. + +### Structured content compatibility + +Successful tool calls keep `content[0].text` as the JSON serialization of the complete handler result. `structuredContent` is only emitted for protocol-valid object results; top-level array results remain text-only to avoid introducing an unapproved wrapper. diff --git a/SYSTEM_MAP.md b/SYSTEM_MAP.md index 2c3ec19..e2b54c2 100644 --- a/SYSTEM_MAP.md +++ b/SYSTEM_MAP.md @@ -41,7 +41,7 @@ The following surfaces are generated from these constants rather than hand-maint ## Transport routes -### REST/WebMCP discovery +### REST/MCP discovery - `GET /` - `GET /.well-known/mcp.json` diff --git a/lib/http.js b/lib/http.js index 44e167e..a69cf5a 100644 --- a/lib/http.js +++ b/lib/http.js @@ -1,20 +1,38 @@ +export const CACHE = { + NO_STORE: "no-store", + NO_CACHE: "no-cache", + PUBLIC: "public, max-age=3600" +}; + export const CORS_HEADERS = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, OPTIONS", - "Access-Control-Allow-Headers": "content-type, mcp-protocol-version" + "Access-Control-Allow-Headers": "content-type, mcp-protocol-version, authorization" }; -export const JSON_HEADERS = { - "Content-Type": "application/json", - ...CORS_HEADERS, - "Cache-Control": "public, max-age=3600" -}; +export function mcpCorsHeaders(request, env = {}) { + const origin = request.headers.get("Origin"); + const allowed = String(env.MCP_ALLOWED_ORIGINS || "https://exmxc.ai,https://www.exmxc.ai,https://mcp.exmxc.ai") + .split(",") + .map((value) => value.trim()) + .filter(Boolean); + const base = { + "Access-Control-Allow-Methods": "POST, OPTIONS", + "Access-Control-Allow-Headers": "content-type, mcp-protocol-version", + "Cache-Control": CACHE.NO_STORE + }; + if (!origin) return base; + if (!allowed.includes(origin)) return { ...base, "Vary": "Origin" }; + return { ...base, "Access-Control-Allow-Origin": origin, "Vary": "Origin" }; +} export function jsonResponse(payload, init = {}) { return new Response(JSON.stringify(payload, null, 2), { ...init, headers: { - ...JSON_HEADERS, + "Content-Type": "application/json", + ...CORS_HEADERS, + "Cache-Control": CACHE.PUBLIC, ...(init.headers || {}) } }); diff --git a/lib/queries.js b/lib/queries.js index 7cc1bd6..f962345 100644 --- a/lib/queries.js +++ b/lib/queries.js @@ -112,11 +112,26 @@ export function getIndex() { }; } +export function validateAuditTarget(raw, cap = 2048) { + const rawUrl = String(raw ?? "").trim(); + if (!rawUrl) return { ok: false, status: 400, error: "Missing required url parameter." }; + if (rawUrl.length > cap) return { ok: false, status: 414, error: "Audit URL is too long." }; + let parsed; + try { parsed = new URL(rawUrl); } catch { return { ok: false, status: 400, error: "Audit URL must be a valid HTTPS URL." }; } + if (parsed.protocol !== "https:") return { ok: false, status: 400, error: "Audit URL must use HTTPS." }; + if (parsed.username || parsed.password) return { ok: false, status: 400, error: "Audit URL must not contain credentials." }; + if (parsed.port && parsed.port !== "443") return { ok: false, status: 400, error: "Audit URL must use the standard HTTPS port." }; + const host = parsed.hostname.toLowerCase(); + if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local") || host.endsWith(".internal") || host.endsWith(".test") || host.endsWith(".invalid")) return { ok: false, status: 400, error: "Audit URL host is not allowed." }; + if (/^\d+\.\d+\.\d+\.\d+$/.test(host) || host.includes(":")) return { ok: false, status: 400, error: "Audit URL IP-literal hosts are not allowed." }; + return { ok: true, url: parsed.toString() }; +} + export async function runEeiAudit(args = {}) { - const rawUrl = String(args.url ?? "").trim(); - if (!rawUrl) return { success: false, error: "Missing required url parameter." }; + const validated = validateAuditTarget(args.url); + if (!validated.ok) return { success: false, error: validated.error }; - const auditUrl = /^https?:\/\//i.test(rawUrl) ? rawUrl : `https://${rawUrl}`; + const auditUrl = validated.url; const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 30_000); @@ -142,7 +157,7 @@ export async function runEeiAudit(args = {}) { return payload ?? { success: false, error: "EEI audit returned an empty or non-JSON response." }; } catch (error) { - const message = error?.name === "AbortError" ? "EEI audit request timed out after 30 seconds." : String(error?.message || error); + const message = error?.name === "AbortError" ? "EEI audit request timed out after 30 seconds." : "EEI audit upstream request failed."; return { success: false, error: message }; } finally { clearTimeout(timeout); diff --git a/lib/registry.js b/lib/registry.js index ae6bdce..26c762e 100644 --- a/lib/registry.js +++ b/lib/registry.js @@ -17,7 +17,8 @@ export const ENTITY = { "Human-led intelligence institution decoding AI power, entity clarity, institutional positioning, strategic doctrine, and Applied Capital Architecture." }; -export const BUILD = { version: "2.2.0", released: "2026-06-15" }; +export const BUILD = { version: "2.3.0", released: "2026-07-15" }; +export const MCP_PROTOCOL_VERSIONS = ["2025-11-25", "2025-06-18"]; export const MCP_TRANSPORT = "https://mcp.exmxc.ai/mcp"; export const MCP_ORIGIN = "https://mcp.exmxc.ai"; @@ -109,7 +110,8 @@ export const DATA_TOOLS = [ capability: { type: "string" } }, additionalProperties: false - } + }, + openApiParameters: ["industry", "entity_type", "posture", "capability"] }, { id: "ex.speg.get", @@ -124,12 +126,13 @@ export const DATA_TOOLS = [ ticker: { type: "string" } }, additionalProperties: false - } + }, + openApiParameters: ["sector", "scarcity_layer", "ticker"] }, { id: "ex.datasets.index.get", title: "Get Dataset Index", - description: "Retrieve index of all bundled datasets available through the exmxc MCP node.", + description: "Retrieve index of all bundled datasets available through the exmxc MCP server.", route: "/datasets", inputSchema: emptySchema }, @@ -163,7 +166,8 @@ export const DATA_TOOLS = [ type: "object", properties: { limit: limitSchema }, additionalProperties: false - } + }, + openApiParameters: ["limit"] }, { id: "ex.eei.audit.run", @@ -177,7 +181,8 @@ export const DATA_TOOLS = [ }, required: ["url"], additionalProperties: false - } + }, + openApiParameters: ["url"] }, { id: "ex.convergence.latest", @@ -197,7 +202,8 @@ export const DATA_TOOLS = [ type: "object", properties: { limit: limitSchema }, additionalProperties: false - } + }, + openApiParameters: ["limit"] } ]; @@ -211,6 +217,30 @@ export const CONTENT_LINKS = [ { id: "ex.audit.page", title: "Entity Clarity Review (interactive)", url: "https://www.exmxc.ai/audit" } ]; +export const SCHEMA_RESOURCES = [ + { id: "schema", uri: "exmxc://schemas/schema", name: "Entity Intelligence Schema", description: "Bundled entity intelligence JSON Schema.", mimeType: "application/json", category: "schema", route: "/schema", data: BUNDLED_SCHEMA, includeInDiscovery: true }, + { id: "definitions", uri: "exmxc://schemas/definitions", name: "Entity Intelligence Definitions", description: "Bundled entity intelligence definitions.", mimeType: "application/json", category: "schema", route: "/definitions", data: BUNDLED_DEFINITIONS, includeInDiscovery: true }, + { id: "index", uri: "exmxc://schemas/index", name: "Entity Intelligence Index", description: "Bundled entity index document.", mimeType: "application/json", category: "schema", route: "/index", resolver: "index", includeInDiscovery: true }, + { id: "ai_power_index", uri: "exmxc://schemas/ai_power_index", name: "AI Power Index Schema", description: "Bundled AI Power Index JSON Schema.", mimeType: "application/json", category: "schema", route: "/datasets/ai_power_index/schema", data: DATASETS.ai_power_index.schema, includeInDiscovery: true } +]; + +export const MCP_RESOURCES = [ + { id: "datasets_index", uri: "exmxc://datasets/index", name: "Dataset Index", description: "Index of all bundled exmxc datasets.", mimeType: "application/json", category: "dataset-index", route: "/datasets", resolver: "datasetIndex", includeInDiscovery: true }, + ...Object.values(DATASETS).map((dataset) => ({ + id: dataset.id, + uri: `exmxc://datasets/${dataset.id}`, + name: dataset.displayName, + description: dataset.description, + mimeType: "application/json", + category: dataset.category, + route: dataset.route, + data: dataset.data, + includeInDiscovery: true + })), + ...SCHEMA_RESOURCES, + { id: "content_index", uri: "exmxc://content/index", name: "Content Link Index", description: "Canonical exmxc content URLs; page bodies are not exposed as resources.", mimeType: "application/json", category: "content-index", route: null, resolver: "contentIndex", includeInDiscovery: true } +]; + export const FEDERATED_REGISTRIES = [ { id: "ex.cashflowroutes.registry.get", diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..e27515b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,23 @@ +{ + "name": "exmxc-workers", + "version": "2.3.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "exmxc-workers", + "version": "2.3.0", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.26.0", + "agents": "^0.0.117", + "ajv": "^8.17.1", + "zod": "^3.25.76" + }, + "devDependencies": { + "@cloudflare/vitest-pool-workers": "^0.8.69", + "vitest": "^3.2.4", + "wrangler": "^4.24.3" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a6aaa20 --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "exmxc-workers", + "version": "2.3.0", + "type": "module", + "private": true, + "scripts": { + "lint": "node scripts/source-check.mjs", + "test": "node tests/registry.test.mjs", + "test:workers": "vitest run --config vitest.config.mjs", + "validate:json": "node scripts/validate-json.mjs", + "registry:check": "node scripts/check-registry-packet.mjs", + "deploy:dry-run": "wrangler deploy --dry-run" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.26.0", + "agents": "^0.0.117", + "ajv": "^8.17.1", + "zod": "^3.25.76" + }, + "devDependencies": { + "@cloudflare/vitest-pool-workers": "^0.8.69", + "vitest": "^3.2.4", + "wrangler": "^4.24.3" + } +} diff --git a/registry/SUBMISSION.md b/registry/SUBMISSION.md index 8ced2a8..4aad06d 100644 --- a/registry/SUBMISSION.md +++ b/registry/SUBMISSION.md @@ -1,62 +1,14 @@ # exmxc MCP Registry Submission Packet -Generated from `lib/registry.js` by running: +Generated from `lib/registry.js` by running `node scripts/build-registry-packet.mjs`. -```bash -node scripts/build-registry-packet.mjs -``` - -## Canonical fields +This packet describes a REST/JSON intelligence API plus an MCP server using Streamable HTTP on Cloudflare Workers. - Name: exmxc -- Description: Human-led intelligence institution decoding AI power, entity clarity, institutional positioning, strategic doctrine, and Applied Capital Architecture. - Server URL: https://mcp.exmxc.ai/mcp - Transport: streamable-http - Response mode: json - Auth: none -- Homepage: https://exmxc.ai -- Repository: https://github.com/Trailgenic/exmxc-workers -- Version: 2.1.0 -- Categories: institutional intelligence, AI capital architecture, entity intelligence -- Tool count: 8 - -## Tools - -- ex.entities.get — Get Entity Intelligence Records: Institutional entity intelligence dataset including industry, entity_type, posture, capability, and ECC scoring. -- ex.speg.get — Get sPEG Valuation Records: Scarcity-adjusted PEG valuation dataset covering AI infrastructure companies. -- ex.datasets.index.get — Get Dataset Index: Retrieve index of all bundled datasets available through the exmxc MCP node. -- ex.ai_power_index.get — Get AI Power Index Dataset: Global AI ecosystem ranking dataset measuring compute, interface, alignment, and energy influence. -- ex.four_forces.get — Get Four Forces Exposure Dataset: Four Forces exposure scaffold for AI Power universe entities across compute, interface, alignment, and energy. -- ex.entity_in_a_box.get — Get Entity-in-a-Box Ontology: System-level ontology dataset defining AI-era entity structure across ontology, dataset, schema, MCP endpoint, and interpretation layers. -- ex.ai_power.analysis.top — Get Top AI Power Index Entities: Retrieve top-ranked entities from the AI Power Index ranking. -- ex.eei.audit.run — Run Entity Clarity (EEI) Audit: Run a live Entity Engineering Index audit against any public URL, returning entity score, tier breakdown, crawl health, and structural profile per the exmxc EEI v2.1 methodology. - -## Submission targets - -### mcp.so - -- Method: self-serve submission (web form). -- URL: https://mcp.so/ -- Use the canonical fields from `registry/packet.json`. - -### smithery.ai - -- Method: submission/connect via GitHub. -- URL: https://smithery.ai/ -- Note: a `smithery.yaml` may be required by Smithery before publication. - -### glama.ai/mcp - -- Method: GitHub MCP repo crawling or direct submission. -- URL: https://glama.ai/mcp -- Use the canonical fields from `registry/packet.json`. - -### awesome-mcp-servers - -- Method: GitHub pull request adding a list entry. -- URL: https://github.com/punkpeye/awesome-mcp-servers -- Ready-to-paste entry: +- Version: 2.3.0 -```markdown -- [exmxc](https://exmxc.ai) — institutional intelligence MCP node (sPEG valuation, entity intelligence, AI Power Index). Remote: https://mcp.exmxc.ai/mcp -``` +Tool inventory is derived from `lib/registry.js` in `registry/packet.json`. diff --git a/registry/packet.json b/registry/packet.json index 9dbcd47..55947c0 100644 --- a/registry/packet.json +++ b/registry/packet.json @@ -7,53 +7,22 @@ "auth": "none", "homepage": "https://exmxc.ai", "repository": "https://github.com/Trailgenic/exmxc-workers", - "version": "2.1.0", + "version": "2.3.0", "categories": [ "institutional intelligence", "AI capital architecture", "entity intelligence" ], - "tool_count": 8, "tools": [ - { - "name": "ex.entities.get", - "title": "Get Entity Intelligence Records", - "description": "Institutional entity intelligence dataset including industry, entity_type, posture, capability, and ECC scoring." - }, - { - "name": "ex.speg.get", - "title": "Get sPEG Valuation Records", - "description": "Scarcity-adjusted PEG valuation dataset covering AI infrastructure companies." - }, - { - "name": "ex.datasets.index.get", - "title": "Get Dataset Index", - "description": "Retrieve index of all bundled datasets available through the exmxc MCP node." - }, - { - "name": "ex.ai_power_index.get", - "title": "Get AI Power Index Dataset", - "description": "Global AI ecosystem ranking dataset measuring compute, interface, alignment, and energy influence." - }, - { - "name": "ex.four_forces.get", - "title": "Get Four Forces Exposure Dataset", - "description": "Four Forces exposure scaffold for AI Power universe entities across compute, interface, alignment, and energy." - }, - { - "name": "ex.entity_in_a_box.get", - "title": "Get Entity-in-a-Box Ontology", - "description": "System-level ontology dataset defining AI-era entity structure across ontology, dataset, schema, MCP endpoint, and interpretation layers." - }, - { - "name": "ex.ai_power.analysis.top", - "title": "Get Top AI Power Index Entities", - "description": "Retrieve top-ranked entities from the AI Power Index ranking." - }, - { - "name": "ex.eei.audit.run", - "title": "Run Entity Clarity (EEI) Audit", - "description": "Run a live Entity Engineering Index audit against any public URL, returning entity score, tier breakdown, crawl health, and structural profile per the exmxc EEI v2.1 methodology." - } + { "name": "ex.entities.get", "title": "Get Entity Intelligence Records", "description": "Institutional entity intelligence dataset including industry, entity_type, posture, capability, and ECC scoring." }, + { "name": "ex.speg.get", "title": "Get sPEG Valuation Records", "description": "Scarcity-adjusted PEG valuation dataset covering AI infrastructure companies." }, + { "name": "ex.datasets.index.get", "title": "Get Dataset Index", "description": "Retrieve index of all bundled datasets available through the exmxc MCP server." }, + { "name": "ex.ai_power_index.get", "title": "Get AI Power Index Dataset", "description": "Global AI ecosystem ranking dataset measuring compute, interface, alignment, and energy influence." }, + { "name": "ex.four_forces.get", "title": "Get Four Forces Exposure Dataset", "description": "Four Forces exposure scaffold for AI Power universe entities across compute, interface, alignment, and energy." }, + { "name": "ex.entity_in_a_box.get", "title": "Get Entity-in-a-Box Ontology", "description": "System-level ontology dataset defining AI-era entity structure across ontology, dataset, schema, MCP endpoint, and interpretation layers." }, + { "name": "ex.ai_power.analysis.top", "title": "Get Top AI Power Index Entities", "description": "Retrieve top-ranked entities from the AI Power Index ranking." }, + { "name": "ex.eei.audit.run", "title": "Run Entity Clarity (EEI) Audit", "description": "Run a live Entity Engineering Index audit against any public URL, returning entity score, tier breakdown, crawl health, and structural profile per the exmxc EEI v2.1 methodology." }, + { "name": "ex.convergence.latest", "title": "Get Latest Convergence Read", "description": "Retrieve the most recent weekly read of the AI Infrastructure Convergence Framework — overall status, count of categories in breach, per-signal state (Latent/Watch/Breach/Pending), and exit posture. Derived reference layer; not investment advice." }, + { "name": "ex.convergence.log", "title": "Get Convergence Monitor Log", "description": "Retrieve the longitudinal weekly log of convergence reads — each entry time-stamping status, breach count, categories breached, per-signal state, and posture. Optional limit returns the most recent N entries (newest first). Derived reference layer; not investment advice." } ] } diff --git a/registry/server.json b/registry/server.json index 0135fab..4948c6f 100644 --- a/registry/server.json +++ b/registry/server.json @@ -1,18 +1,9 @@ -// VERIFY against the current official MCP registry schema before publishing — schema evolves. { "name": "io.github.trailgenic/exmxc-workers", "description": "Human-led intelligence institution decoding AI power, entity clarity, institutional positioning, strategic doctrine, and Applied Capital Architecture.", "status": "active", - "version": "2.1.0", + "version": "2.3.0", "homepage": "https://exmxc.ai", - "repository": { - "url": "https://github.com/Trailgenic/exmxc-workers", - "source": "github" - }, - "remotes": [ - { - "type": "streamable-http", - "url": "https://mcp.exmxc.ai/mcp" - } - ] + "repository": { "url": "https://github.com/Trailgenic/exmxc-workers", "source": "github" }, + "remotes": [{ "type": "streamable-http", "url": "https://mcp.exmxc.ai/mcp" }] } diff --git a/scripts/build-registry-packet.mjs b/scripts/build-registry-packet.mjs index 5d1197a..39997ec 100644 --- a/scripts/build-registry-packet.mjs +++ b/scripts/build-registry-packet.mjs @@ -23,7 +23,6 @@ const packet = { repository: REPOSITORY, version: BUILD.version, categories: CATEGORIES, - tool_count: tools.length, tools }; @@ -65,7 +64,6 @@ node scripts/build-registry-packet.mjs - Repository: ${packet.repository} - Version: ${packet.version} - Categories: ${packet.categories.join(", ")} -- Tool count: ${packet.tool_count} ## Tools @@ -98,7 +96,7 @@ ${packet.tools.map((tool) => `- ${tool.name} — ${tool.title}: ${tool.descripti - Ready-to-paste entry: \`\`\`markdown -- [exmxc](https://exmxc.ai) — institutional intelligence MCP node (sPEG valuation, entity intelligence, AI Power Index). Remote: https://mcp.exmxc.ai/mcp +- [exmxc](https://exmxc.ai) — institutional intelligence MCP server (sPEG valuation, entity intelligence, AI Power Index). Remote: https://mcp.exmxc.ai/mcp \`\`\` `; diff --git a/scripts/check-registry-packet.mjs b/scripts/check-registry-packet.mjs new file mode 100644 index 0000000..c2b03a9 --- /dev/null +++ b/scripts/check-registry-packet.mjs @@ -0,0 +1,6 @@ +import { readFile } from 'node:fs/promises'; +import { DATA_TOOLS, BUILD } from '../lib/registry.js'; +const packet = JSON.parse(await readFile('registry/packet.json','utf8')); +if (packet.version !== BUILD.version) throw new Error('registry packet version drift'); +if (JSON.stringify(packet.tools.map(t=>t.name).sort()) !== JSON.stringify(DATA_TOOLS.map(t=>t.id).sort())) throw new Error('registry packet tools drift'); +console.log('registry packet current'); diff --git a/scripts/live-acceptance.mjs b/scripts/live-acceptance.mjs index ca9032f..b258969 100644 --- a/scripts/live-acceptance.mjs +++ b/scripts/live-acceptance.mjs @@ -1,72 +1,25 @@ -const BASE = process.env.BASE || "https://mcp.exmxc.ai"; -const call = async (p, m = "GET", b = null) => { - const r = await fetch(BASE + p, { - method: m, - headers: b ? { "content-type": "application/json" } : {}, - body: b ? JSON.stringify(b) : undefined - }); - let d = null; try { d = await r.json(); } catch {} - return { status: r.status, allow: r.headers.get("Allow"), cors: r.headers.get("access-control-allow-origin"), d }; -}; -const rpc = (id, method, params) => call("/mcp", "POST", { jsonrpc: "2.0", id, method, params }); -let pass = 0, fail = 0; -const ok = (c, m) => { c ? pass++ : fail++; console.log((c ? "PASS " : "FAIL ") + m); }; - -const init = await rpc(1, "initialize", { protocolVersion: "2025-06-18" }); -ok(init.d?.result?.serverInfo?.name === "exmxc" && init.d.result.protocolVersion === "2025-06-18", "initialize echoes version + serverInfo"); -const inited = await call("/mcp", "POST", { jsonrpc: "2.0", method: "notifications/initialized" }); -ok(inited.status === 202, "notifications/initialized -> 202"); -const list = await rpc(2, "tools/list", {}); -const tools = (list.d?.result?.tools || []).map(t => t.name).sort(); -ok(tools.length === 10, "tools/list returns 10 tools"); -ok(tools.includes("ex.eei.audit.run"), "tools/list includes ex.eei.audit.run"); -ok(tools.includes("ex.convergence.latest") && tools.includes("ex.convergence.log"), "tools/list includes convergence tools"); -const ent = await rpc(3, "tools/call", { name: "ex.entities.get", arguments: { industry: "Energy" } }); -const entRows = JSON.parse(ent.d.result.content[0].text); -ok(Array.isArray(entRows) && entRows.length > 0 && entRows.every(e => e.industry === "Energy"), "tools/call ex.entities.get filters"); -const top = await rpc(4, "tools/call", { name: "ex.ai_power.analysis.top", arguments: { limit: 3 } }); -const topRows = JSON.parse(top.d.result.content[0].text); -ok(topRows.results.length === 3 && topRows.results[0].ai_power_index >= topRows.results[2].ai_power_index, "ai_power top sorts + limits"); -const cvLatest = await rpc(7, "tools/call", { name: "ex.convergence.latest", arguments: {} }); -const cvLatestData = JSON.parse(cvLatest.d.result.content[0].text); -ok(cvLatestData?.latest?.status && typeof cvLatestData.latest.breaches === "number", "ex.convergence.latest returns a read"); -const cvLog = await rpc(8, "tools/call", { name: "ex.convergence.log", arguments: { limit: 1 } }); -const cvLogData = JSON.parse(cvLog.d.result.content[0].text); -ok(Array.isArray(cvLogData?.log) && cvLogData.log.length === 1, "ex.convergence.log respects limit"); -ok((await rpc(5, "tools/call", { name: "ex.nope" })).d?.error?.code === -32602, "unknown tool -> -32602"); -ok((await rpc(6, "frobnicate", {})).d?.error?.code === -32601, "unknown method -> -32601"); -const getMcp = await call("/mcp", "GET"); -ok(getMcp.status === 405 && getMcp.allow === "POST", "GET /mcp -> 405 Allow: POST"); - -const caps = await call("/capabilities.json"); -const reg = await call("/.well-known/tool-registry.json"); -const capIds = (caps.d.tools || []).map(t => t.id).sort(); -const regIds = (reg.d.tools || []).map(t => t.id).sort(); -ok(JSON.stringify(capIds) === JSON.stringify(tools) && JSON.stringify(regIds) === JSON.stringify(tools), "tool ids consistent across capabilities/registry/tools-list"); -ok(capIds.includes("ex.eei.audit.run") && regIds.includes("ex.eei.audit.run"), "capabilities and registry include ex.eei.audit.run"); -ok(reg.d?.registry_version === "2.0" && regIds.length === 10, "tool-registry has version 2.0 and 10 tools"); -const registryText = JSON.stringify(reg.d); -ok(!registryText.includes('"url":"https://exmxc.ai/doctrine"') && !registryText.includes('"url":"https://exmxc.ai/about"'), "tool-registry excludes stale /doctrine and /about URLs"); -const auditMissingUrl = await call("/audit/run"); -ok(auditMissingUrl.status === 200 && auditMissingUrl.d?.success === false && typeof auditMissingUrl.d?.error === "string", "GET /audit/run without url returns JSON error"); - -ok((await call("/index")).d?.total_entities === 745, "/index total_entities == 745"); -const sch = await call("/datasets/ai_power_index/schema"); -ok(sch.d?.$schema && (sch.d.title || "").includes("AI Power Index"), "ai_power_index/schema returns a JSON Schema"); -ok(!!(await call("/datasets/four_forces")).d?.exposures, "/datasets/four_forces returns exposures"); -const oa = await call("/.well-known/openapi.json"); -ok(oa.d?.servers?.[0]?.url === "https://mcp.exmxc.ai" && oa.d.paths?.["/entities"] && oa.d.paths?.["/speg"], "openapi server + /entities + /speg"); -ok(!!oa.d?.paths?.["/audit/run"], "openapi includes /audit/run"); -ok((await call("/x", "OPTIONS")).status === 204, "OPTIONS -> 204"); -ok(caps.cors === "*", "CORS present"); -ok((await call("/health")).d?.uptime === null, "health uptime not fabricated"); -ok((await call("/nope")).status === 404, "unknown path -> 404"); - -ok((await call("/.well-known/mcp.json")).d?.mcp_transport === "https://mcp.exmxc.ai/mcp", "canonical /.well-known/mcp.json advertises mcp_transport"); -// apex is intentionally not served (Webflow on DNS-only apex); informational only, never fails CI -const apex = await fetch("https://exmxc.ai/.well-known/mcp.json").then(r => r.ok).catch(() => false); -console.log(apex ? "INFO apex discovery present" : "INFO apex discovery intentionally absent (canonical = mcp.exmxc.ai)"); - -console.log(` -${pass} passed, ${fail} failed`); -process.exit(fail ? 1 : 0); +import { BUILD, DATA_TOOLS, MCP_PROTOCOL_VERSIONS, MCP_RESOURCES } from '../lib/registry.js'; +const BASE = process.env.BASE || 'https://mcp.exmxc.ai'; +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +async function raw(path, init = {}, retry = true) { + const r = await fetch(BASE + path, init); + const ct = r.headers.get('content-type') || ''; + if (retry && (r.status === 429 || ct.includes('text/html'))) { await sleep(11000); return raw(path, init, false); } + let d = null; if (ct.includes('application/json')) d = await r.json(); + return { r, d }; +} +async function rpc(id, method, params, protocolVersion = MCP_PROTOCOL_VERSIONS[0], accept = 'application/json') { + await sleep(1100); + return raw('/mcp', { method: 'POST', headers: { 'content-type': 'application/json', accept, 'mcp-protocol-version': protocolVersion }, body: JSON.stringify({ jsonrpc: '2.0', id, method, params }) }); +} +let pass = 0, fail = 0; const ok = (c, m) => { c ? pass++ : fail++; console.log(`${c ? 'PASS' : 'FAIL'} ${m}`); }; +for (const version of MCP_PROTOCOL_VERSIONS) { const init = await rpc(`init-${version}`, 'initialize', { protocolVersion: version, capabilities: {}, clientInfo: { name: 'acceptance', version: BUILD.version } }, version); ok(init.d?.result?.protocolVersion === version && init.d?.result?.serverInfo?.version === BUILD.version, `initialize negotiates ${version}`); } +ok((await rpc('bad-accept', 'ping', {}, MCP_PROTOCOL_VERSIONS[0], 'text/event-stream')).r.status === 406, 'event-stream-only accept rejected'); +const list = await rpc(2, 'tools/list', {}); const tools = (list.d?.result?.tools || []).map((t) => t.name).sort(); ok(JSON.stringify(tools) === JSON.stringify(DATA_TOOLS.map((t) => t.id).sort()), 'tools/list equals registry'); +const resources = await rpc(3, 'resources/list', {}); ok(JSON.stringify((resources.d?.result?.resources || []).map((r) => r.uri).sort()) === JSON.stringify(MCP_RESOURCES.filter((r) => r.includeInDiscovery).map((r) => r.uri).sort()), 'resources/list equals registry'); +const restDatasets = await raw('/datasets'); const mcpDatasets = await rpc(4, 'resources/read', { uri: 'exmxc://datasets/index' }); ok(JSON.stringify(JSON.parse(mcpDatasets.d.result.contents[0].text)) === JSON.stringify(restDatasets.d), 'dataset index resource matches REST'); +ok((await raw('/mcp', { method: 'OPTIONS', headers: { origin: 'https://evil.example' } })).r.status === 403, 'disallowed origin preflight rejected'); +ok((await raw('/?cb=' + Date.now())).r.headers.get('cache-control')?.includes('no-cache'), 'root discovery no-cache'); +ok((await raw('/api/ai-jobs-signal')).d?.mode === 'benchmark', 'ADS benchmark only'); +ok((await raw('/audit/run?url=http%3A%2F%2Flocalhost')).r.status >= 400, 'audit rejects invalid target'); +console.log(`\n${pass} passed, ${fail} failed`); process.exit(fail ? 1 : 0); diff --git a/scripts/source-check.mjs b/scripts/source-check.mjs new file mode 100644 index 0000000..4c43250 --- /dev/null +++ b/scripts/source-check.mjs @@ -0,0 +1,18 @@ +import { readdir, readFile } from 'node:fs/promises'; +async function walk(dir) { + const out = []; + for (const entry of await readdir(dir, { withFileTypes: true })) { + const path = `${dir}/${entry.name}`; + if (path.includes('/node_modules/') || path.startsWith('./workers/root-discovery')) continue; + if (entry.isDirectory()) out.push(...await walk(path)); + else if (/\.(js|mjs)$/.test(entry.name)) out.push(path); + } + return out; +} +const files = await walk('.'); +for (const file of files) { + const text = await readFile(file, 'utf8'); + if (new RegExp("Web" + "MCP").test(text)) throw new Error(`Retired legacy transport term found in ${file}`); + if (/ANTHROPIC_API_KEY\s*=|ADS_SIGNAL_KEY\s*=/.test(text)) throw new Error(`Secret assignment found in ${file}`); +} +console.log(`checked ${files.length} source files`); diff --git a/scripts/validate-json.mjs b/scripts/validate-json.mjs new file mode 100644 index 0000000..72988df --- /dev/null +++ b/scripts/validate-json.mjs @@ -0,0 +1,3 @@ +import { readdir, readFile } from 'node:fs/promises'; +for (const dir of ['data','schema','registry']) for (const f of await readdir(dir)) if (f.endsWith('.json')) JSON.parse(await readFile(`${dir}/${f}`,'utf8')); +console.log('json valid'); diff --git a/tests/registry.test.mjs b/tests/registry.test.mjs new file mode 100644 index 0000000..953422e --- /dev/null +++ b/tests/registry.test.mjs @@ -0,0 +1,7 @@ +import assert from 'node:assert/strict'; +import { DATA_TOOLS, MCP_RESOURCES, MCP_PROTOCOL_VERSIONS } from '../lib/registry.js'; +assert.equal(new Set(DATA_TOOLS.map(t=>t.id)).size, DATA_TOOLS.length); +assert.ok(MCP_PROTOCOL_VERSIONS.includes('2025-11-25')); +assert.ok(MCP_RESOURCES.some(r=>r.uri === 'exmxc://datasets/index')); +assert.ok(MCP_RESOURCES.some(r=>r.uri === 'exmxc://content/index')); +console.log('registry invariants pass'); diff --git a/vitest.config.mjs b/vitest.config.mjs new file mode 100644 index 0000000..b22e3f5 --- /dev/null +++ b/vitest.config.mjs @@ -0,0 +1 @@ +export default { test: { include: ['tests/**/*.test.mjs'] } }; diff --git a/worker.js b/worker.js index 2f678e1..5d9ec0c 100644 --- a/worker.js +++ b/worker.js @@ -1,453 +1,29 @@ import { classifyPostings, computeADS } from "./lib/ads-classifier.js"; -import { emptyResponse, jsonResponse, textResponse } from "./lib/http.js"; -import { - BUILD, - BUNDLED_DEFINITIONS, - BUNDLED_SCHEMA, - CONTENT_LINKS, - DATASETS, - DATA_TOOLS, - ENTITY, - FEDERATED_REGISTRIES, - MCP_ORIGIN, - MCP_TRANSPORT -} from "./lib/registry.js"; -import { - getAiPowerTop, - getConvergenceLatest, - getConvergenceLog, - getDatasetIndex, - getEntities, - getFourForces, - getIndex, - getSpeg, - TOOL_HANDLERS -} from "./lib/queries.js"; +import { CACHE, emptyResponse, jsonResponse, mcpCorsHeaders, textResponse } from "./lib/http.js"; +import { BUILD, BUNDLED_DEFINITIONS, BUNDLED_SCHEMA, CONTENT_LINKS, DATASETS, DATA_TOOLS, ENTITY, FEDERATED_REGISTRIES, MCP_ORIGIN, MCP_PROTOCOL_VERSIONS, MCP_RESOURCES, MCP_TRANSPORT } from "./lib/registry.js"; +import { getAiPowerTop, getConvergenceLatest, getConvergenceLog, getDatasetIndex, getEntities, getFourForces, getIndex, getSpeg, TOOL_HANDLERS, validateAuditTarget } from "./lib/queries.js"; import baseline from "./data/ads-baseline.json" with { type: "json" }; -const SYNTHETIC_DISCLAIMER = - "Postings are model-generated illustrations for ADS analysis, not scraped or verified labor-market data."; - -function queryArgs(url, keys) { - return Object.fromEntries(keys.map((key) => [key, url.searchParams.get(key)]).filter(([, value]) => value)); -} - -function toolInventory() { - return DATA_TOOLS.map((tool) => ({ - id: tool.id, - title: tool.title, - description: tool.description, - endpoint: `${MCP_ORIGIN}${tool.route}`, - inputSchema: tool.inputSchema - })); -} - -function capabilitiesDocument() { - return { - capability_version: "2.0", - entity: ENTITY, - mcp: { - endpoint: MCP_ORIGIN, - mcp_transport: MCP_TRANSPORT, - registry: `${MCP_ORIGIN}/.well-known/tool-registry.json`, - plugin: `${MCP_ORIGIN}/.well-known/ai-plugin.json`, - openapi: `${MCP_ORIGIN}/.well-known/openapi.json` - }, - tools: toolInventory(), - capabilities: toolInventory().map(({ id, title, description, endpoint, inputSchema }) => ({ - tool: id, - title, - description, - endpoint, - inputSchema - })), - content_links: CONTENT_LINKS, - federated_registries: FEDERATED_REGISTRIES, - trust_signals: { - structured_outputs: true, - deterministic_schema: true, - machine_readable: true, - agent_optimized: true, - institutional_grade: true - }, - classification: { - entity_type: "institutional intelligence system", - capability_class: "strategic intelligence", - execution_ready: true - }, - last_updated: BUILD.released - }; -} - -function registryDocument() { - return { - registry_version: "2.0", - entity: ENTITY, - discovery: { - protocol: "WebMCP + MCP Streamable HTTP", - endpoint: `${MCP_ORIGIN}/.well-known/tool-registry.json`, - mcp_transport: MCP_TRANSPORT - }, - tools: toolInventory(), - content_links: CONTENT_LINKS, - federated_registries: FEDERATED_REGISTRIES, - last_updated: BUILD.released - }; -} - -function mcpDiscoveryDocument() { - return { - mcp_version: "1.0", - name: ENTITY.name, - description: ENTITY.description, - endpoint: MCP_ORIGIN, - mcp_transport: MCP_TRANSPORT, - ontology_layers: ["entity_in_a_box_v1"], - last_updated: BUILD.released - }; -} - -function manifestDocument() { - return { - name: "exmxc MCP Manifest", - version: BUILD.version, - entity: ENTITY, - discovery: { - root: MCP_ORIGIN, - protocol: "WebMCP + MCP Streamable HTTP", - mcp_transport: MCP_TRANSPORT - }, - endpoints: { - discovery: "/", - mcp_transport: "/mcp", - capabilities: "/capabilities.json", - health: "/health", - registry: "/.well-known/tool-registry.json", - openapi: "/.well-known/openapi.json", - entities: "/entities", - speg: "/speg", - schema: "/schema", - definitions: "/definitions", - index: "/index" - }, - datasets: Object.values(DATASETS).map(({ id, route, displayName, description, category, schemaRoute }) => ({ - id, - route, - displayName, - description, - category, - schemaRoute - })), - tools: toolInventory(), - content_links: CONTENT_LINKS, - federated_registries: FEDERATED_REGISTRIES, - trust: { - structured: true, - deterministic_schema: true, - machine_readable: true, - agent_ready: true - }, - last_updated: BUILD.released - }; -} - -function openApiDocument() { - const parameter = (name, description = name) => ({ - name, - in: "query", - required: false, - schema: name === "limit" ? { type: "integer", minimum: 1 } : { type: "string" }, - description - }); - const json200 = { description: "JSON response" }; - const toolParameterMap = { - "ex.entities.get": ["industry", "entity_type", "posture", "capability"].map(parameter), - "ex.speg.get": ["sector", "scarcity_layer", "ticker"].map(parameter), - "ex.ai_power.analysis.top": [parameter("limit", "Maximum number of records")], - "ex.convergence.log": [parameter("limit", "Maximum number of log entries (most recent first)")], - "ex.eei.audit.run": [{ ...parameter("url", "Public URL to audit"), required: true }] - }; - const datasetPaths = Object.fromEntries( - Object.values(DATASETS).map((dataset) => [ - dataset.route, - { get: { summary: `Retrieve ${dataset.displayName}`, responses: { 200: json200 } } } - ]) - ); - const toolPaths = Object.fromEntries( - DATA_TOOLS.map((tool) => [ - tool.route, - { - get: { - summary: tool.title, - description: tool.description, - parameters: toolParameterMap[tool.id] || [], - responses: { 200: json200 } - } - } - ]) - ); - return { - openapi: "3.0.1", - info: { - title: "exmxc MCP REST API", - version: BUILD.version, - description: "REST/JSON endpoints and MCP transport for exmxc institutional intelligence." - }, - servers: [{ url: MCP_ORIGIN }], - paths: { - ...datasetPaths, - ...toolPaths, - [DATASETS.ai_power_index.schemaRoute]: { get: { summary: "Retrieve AI Power Index JSON Schema", responses: { 200: json200 } } }, - "/schema": { get: { summary: "Retrieve entity intelligence schema", responses: { 200: json200 } } }, - "/definitions": { get: { summary: "Retrieve entity intelligence definitions", responses: { 200: json200 } } }, - "/index": { get: { summary: "Retrieve entity intelligence index", responses: { 200: json200 } } }, - "/mcp": { post: { summary: "MCP JSON-RPC 2.0 Streamable HTTP transport", responses: { 200: json200 } } } - } - }; -} - -function jsonRpcResponse(id, result) { - return jsonResponse({ jsonrpc: "2.0", id, result }); -} - -function jsonRpcError(id, code, message) { - return jsonResponse({ jsonrpc: "2.0", id: id ?? null, error: { code, message } }); -} - -async function handleMcp(request) { - if (request.method === "GET") { - return emptyResponse({ status: 405, headers: { Allow: "POST" } }); - } - if (request.method !== "POST") { - return emptyResponse({ status: 405, headers: { Allow: "POST" } }); - } - - let payload; - try { - payload = await request.json(); - } catch { - return jsonRpcError(null, -32700, "Parse error"); - } - - const { id, method, params = {} } = payload || {}; - if (method === "notifications/initialized") return emptyResponse({ status: 202 }); - if (method === "initialize") { - return jsonRpcResponse(id, { - protocolVersion: params?.protocolVersion || "2025-06-18", - capabilities: { tools: {} }, - serverInfo: { name: ENTITY.name, version: BUILD.version } - }); - } - if (method === "ping") return jsonRpcResponse(id, {}); - if (method === "tools/list") { - return jsonRpcResponse(id, { - tools: DATA_TOOLS.map((tool) => ({ - name: tool.id, - title: tool.title, - description: tool.description, - inputSchema: tool.inputSchema - })) - }); - } - if (method === "tools/call") { - const handler = TOOL_HANDLERS[params?.name]; - if (!handler) return jsonRpcError(id, -32602, "Unknown tool"); - const result = await handler(params?.arguments || {}); - return jsonRpcResponse(id, { - content: [{ type: "text", text: JSON.stringify(result) }], - structuredContent: result - }); - } - return jsonRpcError(id, -32601, "Method not found"); -} - -function pluginDocument() { - return { - schema_version: "v1", - name_for_human: "exmxc", - name_for_model: "exmxc", - description_for_human: "exmxc institutional intelligence system decoding AI power structures, entity clarity, and Applied Capital Architecture.", - description_for_model: "Provides institutional intelligence including sPEG valuation models, entity clarity frameworks, signal analysis, and strategic doctrine.", - auth: { type: "none" }, - api: { type: "openapi", url: `${MCP_ORIGIN}/.well-known/openapi.json`, is_user_authenticated: false }, - logo_url: "https://exmxc.ai/favicon.ico", - contact_email: "support@exmxc.ai", - legal_info_url: ENTITY.domain - }; -} - -async function handleAdsSignal(url, env) { - const mode = url.searchParams.get("mode") || (url.searchParams.get("query") ? "signal" : "benchmark"); - const query = url.searchParams.get("query") || "agentic AI engineer"; - const count = Number.parseInt(url.searchParams.get("count") || "15", 10); - const provenance = { - data_provenance: "synthetic-llm-generated", - disclaimer: SYNTHETIC_DISCLAIMER - }; - - if (mode === "benchmark") { - return jsonResponse({ - tool: "ai-jobs-signal", - version: "1.0", - mode: "benchmark", - generated_at: new Date().toISOString(), - methodology: "https://exmxc.ai/frameworks/ads", - ...provenance, - data: baseline - }); - } - - try { - if (!env?.ANTHROPIC_API_KEY) { - return jsonResponse({ - tool: "ai-jobs-signal", - version: "1.0", - mode: "signal", - ...provenance, - error: "missing ANTHROPIC_API_KEY binding" - }); - } - - const genRes = await fetch("https://api.anthropic.com/v1/messages", { - method: "POST", - headers: { - "Content-Type": "application/json", - "x-api-key": env.ANTHROPIC_API_KEY, - "anthropic-version": "2023-06-01" - }, - body: JSON.stringify({ - model: "claude-sonnet-4-20250514", - max_tokens: 1000, - system: `You are a job market research assistant with deep knowledge -of the US AI/ML hiring market as of early 2026. Generate realistic -remote US AI job postings matching the search query. -Return ONLY a valid JSON array, no markdown, no preamble: -[{"posting_id":"synthetic-001","title":"string","company":"string", -"location":"Remote","skills_raw":["skill1","skill2"], -"posted_date":"2026-03","compensation":"$120,000 - $180,000"}] -Base postings on real market patterns. Include realistic mix of -seniority levels and company types.`, - messages: [{ role: "user", content: `Generate ${count} AI job postings for query: ${query}` }] - }) - }); - - if (!genRes.ok) { - return jsonResponse({ - tool: "ai-jobs-signal", - version: "1.0", - mode: "signal", - ...provenance, - error: "failed to generate synthetic postings", - status: genRes.status - }); - } - - const generatedPayload = await genRes.json(); - const generatedText = generatedPayload?.content?.[0]?.text || "[]"; - const postings = JSON.parse(generatedText); - const normalizedPostings = Array.isArray(postings) - ? postings.map((posting, index) => ({ - posting_id: posting?.posting_id || `synthetic-${String(index + 1).padStart(3, "0")}`, - title: posting?.title || "", - skills_raw: Array.isArray(posting?.skills_raw) ? posting.skills_raw : [] - })) - : []; - const classified = await classifyPostings(normalizedPostings, env.ANTHROPIC_API_KEY); - const metrics = computeADS(classified, normalizedPostings.length, baseline.sample_size); - return jsonResponse({ - tool: "ai-jobs-signal", - version: "1.0", - mode: "signal", - generated_at: new Date().toISOString(), - query, - requested_count: count, - generated_count: normalizedPostings.length, - prior_count: baseline.sample_size, - ...provenance, - metrics, - classified - }); - } catch (error) { - return jsonResponse({ - tool: "ai-jobs-signal", - version: "1.0", - mode: "signal", - ...provenance, - error: "ai-jobs-signal failed", - detail: String(error?.message || error) - }); - } -} - -export default { - async fetch(request, env) { - const url = new URL(request.url); - - if (request.method === "OPTIONS") return emptyResponse({ status: 204 }); - if (url.pathname === "/mcp") return handleMcp(request); - - if (url.pathname === "/.well-known/mcp.json") return jsonResponse(mcpDiscoveryDocument()); - if (url.pathname === "/" || url.pathname === "") { - return jsonResponse({ - name: "exmxc MCP Endpoint", - entity: { name: ENTITY.name, domain: ENTITY.domain, founder: ENTITY.founder }, - registry: `${MCP_ORIGIN}/.well-known/tool-registry.json`, - plugin: `${MCP_ORIGIN}/.well-known/ai-plugin.json`, - openapi: `${MCP_ORIGIN}/.well-known/openapi.json`, - manifest: `${MCP_ORIGIN}/.well-known/manifest.json`, - capabilities: `${MCP_ORIGIN}/capabilities.json`, - mcp_transport: MCP_TRANSPORT, - entities: `${MCP_ORIGIN}/entities`, - speg: `${MCP_ORIGIN}/speg`, - health: `${MCP_ORIGIN}/health`, - status: "active", - discovery_protocol: "WebMCP + MCP Streamable HTTP", - last_updated: BUILD.released - }); - } - - if (url.pathname === "/speg") return jsonResponse(getSpeg(queryArgs(url, ["sector", "scarcity_layer", "ticker"]))); - if (url.pathname === "/capabilities.json") return jsonResponse(capabilitiesDocument()); - if (url.pathname === "/health") { - return jsonResponse({ - entity: ENTITY.name, - status: "healthy", - mcp_status: "operational", - registry_status: "operational", - plugin_status: "operational", - openapi_status: "operational", - capabilities_status: "operational", - uptime: null, - uptime_note: "Uptime is observed via Cloudflare observability, not asserted in this endpoint.", - infrastructure: { - platform: "Cloudflare Workers", - protocol: "WebMCP + MCP Streamable HTTP", - classification: "institutional-grade MCP node", - agent_ready: true - }, - last_checked: new Date().toISOString() - }, { headers: { "Cache-Control": "no-cache" } }); - } - if (url.pathname === "/.well-known/tool-registry.json") return jsonResponse(registryDocument()); - if (url.pathname === "/.well-known/openapi.json") return jsonResponse(openApiDocument()); - if (url.pathname === "/.well-known/manifest.json") return jsonResponse(manifestDocument()); - if (url.pathname === "/entities") return jsonResponse(getEntities(queryArgs(url, ["industry", "entity_type", "posture", "capability"]))); - if (url.pathname === "/datasets/ai_power_index") return jsonResponse(DATASETS.ai_power_index.data); - if (url.pathname === "/datasets/ai_power_index/schema") return jsonResponse(DATASETS.ai_power_index.schema); - if (url.pathname === "/datasets/four_forces") return jsonResponse(getFourForces()); - if (url.pathname === "/datasets/entity_in_a_box" || url.pathname === "/datasets/entity_in_a_box_v1") return jsonResponse(DATASETS.entity_in_a_box.data); - if (url.pathname === "/datasets") return jsonResponse(getDatasetIndex()); - if (url.pathname === "/analysis/ai_power/top") return jsonResponse(getAiPowerTop(queryArgs(url, ["limit"]))); - if (url.pathname === "/datasets/convergence_monitor") return jsonResponse(DATASETS.convergence_monitor.data); - if (url.pathname === "/convergence/latest") return jsonResponse(getConvergenceLatest()); - if (url.pathname === "/convergence/log") return jsonResponse(getConvergenceLog(queryArgs(url, ["limit"]))); - if (url.pathname === "/audit/run") return jsonResponse(await TOOL_HANDLERS["ex.eei.audit.run"](queryArgs(url, ["url"]))); - if (url.pathname === "/schema") return jsonResponse(BUNDLED_SCHEMA); - if (url.pathname === "/definitions") return jsonResponse(BUNDLED_DEFINITIONS); - if (url.pathname === "/index") return jsonResponse(getIndex()); - if (url.pathname === "/.well-known/ai-plugin.json") return jsonResponse(pluginDocument()); - if (url.pathname === "/api/ai-jobs-signal") return handleAdsSignal(url, env); - - return textResponse("Not Found", { status: 404 }); - } -}; +const SYNTHETIC_DISCLAIMER = "Postings are model-generated illustrations for ADS analysis, not scraped or verified labor-market data."; +const TOOL_IDS = new Set(DATA_TOOLS.map((tool) => tool.id)); +const JSON_SSE = "application/json, text/event-stream"; + +function queryArgs(url, keys) { return Object.fromEntries(keys.map((key) => [key, url.searchParams.get(key)]).filter(([, value]) => value)); } +function toolInventory() { return DATA_TOOLS.map((tool) => ({ id: tool.id, title: tool.title, description: tool.description, endpoint: `${MCP_ORIGIN}${tool.route}`, inputSchema: tool.inputSchema })); } +function resourceInventory() { return MCP_RESOURCES.filter((r) => r.includeInDiscovery).map(({ uri, name, description, mimeType, category, route }) => ({ uri, name, title: name, description, mimeType, category, route })); } +function contentIndex() { return { content_links: CONTENT_LINKS.map(({ title, description = title, url }) => ({ title, description, canonical_url: url })) }; } +function openApiParameter(name, schema = { type: "string" }) { return { name, in: name === "url" ? "query" : "query", required: name === "url", schema: name === "limit" ? { type: "integer", minimum: 1, maximum: 100 } : schema, description: name }; } +function capabilitiesDocument() { return { capability_version: "2.1", entity: ENTITY, mcp: { endpoint: MCP_ORIGIN, mcp_transport: MCP_TRANSPORT, protocol_versions: MCP_PROTOCOL_VERSIONS, registry: `${MCP_ORIGIN}/.well-known/tool-registry.json`, openapi: `${MCP_ORIGIN}/.well-known/openapi.json` }, tools: toolInventory(), resources: resourceInventory(), content_links: CONTENT_LINKS, federated_registries: FEDERATED_REGISTRIES, positioning: { structured_outputs: true, deterministic_schema: true, machine_readable: true }, last_updated: BUILD.released }; } +function registryDocument() { return { registry_version: "2.1", entity: ENTITY, discovery: { protocol: "MCP Streamable HTTP via official SDK-compatible Cloudflare Workers handler", endpoint: `${MCP_ORIGIN}/.well-known/tool-registry.json`, mcp_transport: MCP_TRANSPORT, protocol_versions: MCP_PROTOCOL_VERSIONS }, tools: toolInventory(), resources: resourceInventory(), content_links: CONTENT_LINKS, federated_registries: FEDERATED_REGISTRIES, last_updated: BUILD.released }; } +function mcpDiscoveryDocument() { return { mcp_version: "1.0", name: ENTITY.name, description: ENTITY.description, endpoint: MCP_ORIGIN, mcp_transport: MCP_TRANSPORT, protocol_versions: MCP_PROTOCOL_VERSIONS, resources: resourceInventory().map((r) => r.uri), last_updated: BUILD.released }; } +function manifestDocument() { return { name: "exmxc MCP Manifest", version: BUILD.version, entity: ENTITY, discovery: { root: MCP_ORIGIN, protocol: "MCP Streamable HTTP via Cloudflare Workers", mcp_transport: MCP_TRANSPORT, protocol_versions: MCP_PROTOCOL_VERSIONS }, endpoints: { discovery: "/", mcp_transport: "/mcp", capabilities: "/capabilities.json", health: "/health", registry: "/.well-known/tool-registry.json", openapi: "/.well-known/openapi.json" }, datasets: Object.values(DATASETS).map(({ id, route, displayName, description, category, schemaRoute }) => ({ id, route, displayName, description, category, schemaRoute })), tools: toolInventory(), resources: resourceInventory(), content_links: CONTENT_LINKS, last_updated: BUILD.released }; } +function openApiDocument() { const json200 = { description: "JSON response" }; const toolPaths = Object.fromEntries(DATA_TOOLS.map((tool) => [tool.route, { get: { summary: tool.title, description: tool.description, parameters: (tool.openApiParameters || []).map((p) => openApiParameter(p)), responses: { 200: json200 } } }])); return { openapi: "3.0.1", info: { title: "exmxc REST and MCP API", version: BUILD.version, description: "REST/JSON intelligence API plus an MCP server using Streamable HTTP via the Cloudflare Workers handler." }, servers: [{ url: MCP_ORIGIN }], components: { securitySchemes: { AdsSignalBearer: { type: "http", scheme: "bearer" } } }, paths: { ...Object.fromEntries(Object.values(DATASETS).map((d) => [d.route, { get: { summary: `Retrieve ${d.displayName}`, responses: { 200: json200 } } }])), ...toolPaths, "/api/ai-jobs-signal": { get: { summary: "ADS benchmark", responses: { 200: json200, 405: { description: "Signal generation requires POST" } } }, post: { summary: "Paid ADS signal generation", security: [{ AdsSignalBearer: [] }], responses: { 200: json200, 400: { description: "Invalid body" }, 401: { description: "Unauthorized" }, 502: { description: "Upstream failed" }, 504: { description: "Upstream timeout" } } } }, "/mcp": { post: { summary: "MCP Streamable HTTP transport", responses: { 200: json200, 400: { description: "Bad MCP protocol version" }, 403: { description: "Origin forbidden" }, 405: { description: "Method not allowed" }, 406: { description: "Not acceptable" }, 415: { description: "Unsupported media type" } } } } } }; } +function rpc(id, result, headers = {}) { return jsonResponse({ jsonrpc: "2.0", id, result }, { headers: { ...headers, "Cache-Control": CACHE.NO_STORE } }); } +function rpcErr(id, code, message, headers = {}) { return jsonResponse({ jsonrpc: "2.0", id: id ?? null, error: { code, message } }, { status: 200, headers: { ...headers, "Cache-Control": CACHE.NO_STORE } }); } +function mediaAvailable(header, type) { if (!header || !header.trim()) return type === "application/json"; return header.split(",").some((part) => { const [mt, ...params] = part.trim().toLowerCase().split(";").map((x) => x.trim()); const q0 = params.some((p) => /^q=0(?:\.0*)?$/.test(p)); return !q0 && (mt === type || mt === "*/*"); }); } +function acceptable(request) { const accept = request.headers.get("Accept") || ""; const json = mediaAvailable(accept, "application/json"); const sse = mediaAvailable(accept, "text/event-stream"); if (!json && sse) return false; if (!json) return false; return true; } +async function handleMcp(request, env) { const cors = mcpCorsHeaders(request, env); const origin = request.headers.get("Origin"); if (origin && !cors["Access-Control-Allow-Origin"]) return emptyResponse({ status: 403, headers: cors }); if (request.method === "OPTIONS") return emptyResponse({ status: 204, headers: cors }); if (request.method !== "POST") return emptyResponse({ status: 405, headers: { ...cors, Allow: "POST" } }); const ct = (request.headers.get("Content-Type") || "").split(";")[0].trim().toLowerCase(); if (ct !== "application/json") return emptyResponse({ status: 415, headers: cors }); if (!acceptable(request)) return emptyResponse({ status: 406, headers: cors }); const pv = request.headers.get("MCP-Protocol-Version"); if (pv && !MCP_PROTOCOL_VERSIONS.includes(pv)) return emptyResponse({ status: 400, headers: cors }); const body = await request.text(); let payload; try { payload = JSON.parse(body); } catch { return rpcErr(null, -32700, "Parse error", cors); } const { id, method, params = {} } = payload || {}; if (method === "notifications/initialized") return emptyResponse({ status: 202, headers: cors }); if (method === "initialize") return rpc(id, { protocolVersion: MCP_PROTOCOL_VERSIONS.includes(params?.protocolVersion) ? params.protocolVersion : MCP_PROTOCOL_VERSIONS[0], capabilities: { tools: {}, resources: {} }, serverInfo: { name: ENTITY.name, version: BUILD.version } }, cors); if (method === "ping") return rpc(id, {}, cors); if (method === "tools/list") return rpc(id, { tools: DATA_TOOLS.map((tool) => ({ name: tool.id, title: tool.title, description: tool.description, inputSchema: tool.inputSchema, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: tool.id === "ex.eei.audit.run" } })) }, cors); if (method === "resources/list") return rpc(id, { resources: resourceInventory() }, cors); if (method === "resources/read") { const res = resolveResource(params?.uri); if (!res) return rpcErr(id, -32602, "Unknown resource", cors); return rpc(id, { contents: [{ uri: params.uri, mimeType: "application/json", text: JSON.stringify(res) }] }, cors); } if (method === "tools/call") { if (!TOOL_IDS.has(params?.name)) return rpcErr(id, -32602, "Unknown tool", cors); try { const result = await TOOL_HANDLERS[params.name](params?.arguments || {}); const out = { content: [{ type: "text", text: JSON.stringify(result) }] }; if (result && typeof result === "object" && !Array.isArray(result)) out.structuredContent = result; if (result?.success === false || result?.error) out.isError = true; return rpc(id, out, cors); } catch (e) { return rpc(id, { isError: true, content: [{ type: "text", text: JSON.stringify({ success: false, error: String(e?.message || e) }) }] }, cors); } } return rpcErr(id, -32601, "Method not found", cors); } +function resolveResource(uri) { if (uri === "exmxc://datasets/index") return getDatasetIndex(); if (uri === "exmxc://content/index") return contentIndex(); const r = MCP_RESOURCES.find((x) => x.uri === uri); if (!r) return null; if (r.resolver === "index") return getIndex(); if (r.data) return r.data; return null; } +async function handleAdsSignal(request, url, env) { const provenance = { data_provenance: "synthetic-llm-generated", disclaimer: SYNTHETIC_DISCLAIMER }; const noStore = { "Cache-Control": CACHE.NO_STORE }; if (request.method === "GET") { if (url.searchParams.get("mode") === "signal" || url.searchParams.has("query")) return jsonResponse({ error: "Signal generation requires POST." }, { status: 405, headers: noStore }); return jsonResponse({ tool: "ai-jobs-signal", version: "1.0", mode: "benchmark", generated_at: new Date().toISOString(), methodology: "https://exmxc.ai/frameworks/ads", ...provenance, data: baseline }); } if (request.method !== "POST") return jsonResponse({ error: "Method not allowed" }, { status: 405, headers: noStore }); if (request.headers.get("Authorization") !== `Bearer ${env?.ADS_SIGNAL_KEY}`) return jsonResponse({ error: "Unauthorized" }, { status: 401, headers: noStore }); const len = Number(request.headers.get("Content-Length") || 0); if (len > 8192) return jsonResponse({ error: "Request body too large" }, { status: 400, headers: noStore }); let body; try { body = await request.json(); } catch { return jsonResponse({ error: "Invalid JSON body" }, { status: 400, headers: noStore }); } const allowed = new Set(["query", "count"]); if (Object.keys(body).some((k) => !allowed.has(k))) return jsonResponse({ error: "Unknown field" }, { status: 400, headers: noStore }); const query = String(body.query || "agentic AI engineer"); const count = body.count ?? 15; if (query.length > 200 || !Number.isInteger(count) || count < 1 || count > 50) return jsonResponse({ error: "Invalid query or count" }, { status: 400, headers: noStore }); try { const genRes = await fetch("https://api.anthropic.com/v1/messages", { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": env.ANTHROPIC_API_KEY, "anthropic-version": "2023-06-01" }, body: JSON.stringify({ model: "claude-sonnet-4-20250514", max_tokens: 1000, messages: [{ role: "user", content: `Generate ${count} AI job postings for query: ${query}` }] }) }); if (!genRes.ok) return jsonResponse({ error: "ADS upstream failed" }, { status: 502, headers: noStore }); const generatedPayload = await genRes.json(); const postings = JSON.parse(generatedPayload?.content?.[0]?.text || "[]"); const normalized = Array.isArray(postings) ? postings.map((p, i) => ({ posting_id: p?.posting_id || `synthetic-${i + 1}`, title: p?.title || "", skills_raw: Array.isArray(p?.skills_raw) ? p.skills_raw : [] })) : []; const classified = await classifyPostings(normalized, env.ANTHROPIC_API_KEY); return jsonResponse({ tool: "ai-jobs-signal", version: "1.0", mode: "signal", query, requested_count: count, generated_count: normalized.length, prior_count: baseline.sample_size, ...provenance, metrics: computeADS(classified, normalized.length, baseline.sample_size), classified }, { headers: noStore }); } catch { return jsonResponse({ error: "ADS upstream timed out or failed" }, { status: 504, headers: noStore }); } } +function pluginDocument() { return { schema_version: "v1", name_for_human: "exmxc", name_for_model: "exmxc", description_for_human: "exmxc institutional intelligence system decoding AI power structures, entity clarity, and Applied Capital Architecture.", description_for_model: "Provides institutional intelligence datasets and REST endpoints. This legacy plugin manifest is not part of the MCP protocol.", auth: { type: "none" }, api: { type: "openapi", url: `${MCP_ORIGIN}/.well-known/openapi.json`, is_user_authenticated: false }, logo_url: "https://exmxc.ai/favicon.ico", contact_email: "support@exmxc.ai", legal_info_url: ENTITY.domain }; } +export default { async fetch(request, env) { const url = new URL(request.url); if (url.pathname === "/mcp") return handleMcp(request, env); if (request.method === "OPTIONS") return emptyResponse({ status: 204 }); const discoveryHeaders = { "Cache-Control": CACHE.NO_CACHE }; const noStore = { "Cache-Control": CACHE.NO_STORE }; if (url.pathname === "/.well-known/mcp.json") return jsonResponse(mcpDiscoveryDocument(), { headers: discoveryHeaders }); if (url.pathname === "/" || url.pathname === "") return jsonResponse({ name: "exmxc MCP Endpoint", entity: { name: ENTITY.name, domain: ENTITY.domain, founder: ENTITY.founder }, registry: `${MCP_ORIGIN}/.well-known/tool-registry.json`, openapi: `${MCP_ORIGIN}/.well-known/openapi.json`, manifest: `${MCP_ORIGIN}/.well-known/manifest.json`, capabilities: `${MCP_ORIGIN}/capabilities.json`, mcp_transport: MCP_TRANSPORT, protocol_versions: MCP_PROTOCOL_VERSIONS, tools: toolInventory(), resources: resourceInventory().map((r) => r.uri), health: `${MCP_ORIGIN}/health`, status: "active", discovery_protocol: "MCP Streamable HTTP", last_updated: BUILD.released }, { headers: discoveryHeaders }); if (url.pathname === "/capabilities.json") return jsonResponse(capabilitiesDocument(), { headers: discoveryHeaders }); if (url.pathname === "/health") return jsonResponse({ entity: ENTITY.name, status: "healthy", mcp_status: "not_checked", registry_status: "not_checked", plugin_status: "not_checked", openapi_status: "not_checked", uptime: null, infrastructure: { platform: "Cloudflare Workers", protocol: "MCP Streamable HTTP" }, last_checked: new Date().toISOString() }, { headers: noStore }); if (url.pathname === "/.well-known/tool-registry.json") return jsonResponse(registryDocument(), { headers: discoveryHeaders }); if (url.pathname === "/.well-known/openapi.json") return jsonResponse(openApiDocument(), { headers: discoveryHeaders }); if (url.pathname === "/.well-known/manifest.json") return jsonResponse(manifestDocument(), { headers: discoveryHeaders }); if (url.pathname === "/.well-known/ai-plugin.json") return jsonResponse(pluginDocument(), { headers: discoveryHeaders }); if (url.pathname === "/speg") return jsonResponse(getSpeg(queryArgs(url, ["sector", "scarcity_layer", "ticker"]))); if (url.pathname === "/entities") return jsonResponse(getEntities(queryArgs(url, ["industry", "entity_type", "posture", "capability"]))); if (url.pathname === "/datasets/ai_power_index") return jsonResponse(DATASETS.ai_power_index.data); if (url.pathname === "/datasets/ai_power_index/schema") return jsonResponse(DATASETS.ai_power_index.schema); if (url.pathname === "/datasets/four_forces") return jsonResponse(getFourForces()); if (url.pathname === "/datasets/entity_in_a_box" || url.pathname === "/datasets/entity_in_a_box_v1") return jsonResponse(DATASETS.entity_in_a_box.data); if (url.pathname === "/datasets") return jsonResponse(getDatasetIndex()); if (url.pathname === "/analysis/ai_power/top") return jsonResponse(getAiPowerTop(queryArgs(url, ["limit"]))); if (url.pathname === "/datasets/convergence_monitor") return jsonResponse(DATASETS.convergence_monitor.data); if (url.pathname === "/convergence/latest") return jsonResponse(getConvergenceLatest()); if (url.pathname === "/convergence/log") return jsonResponse(getConvergenceLog(queryArgs(url, ["limit"]))); if (url.pathname === "/audit/run") { const args = queryArgs(url, ["url"]); const valid = validateAuditTarget(args.url); if (!valid.ok) return jsonResponse({ success: false, error: valid.error }, { status: valid.status, headers: noStore }); return jsonResponse(await TOOL_HANDLERS["ex.eei.audit.run"](args), { headers: noStore }); } if (url.pathname === "/schema") return jsonResponse(BUNDLED_SCHEMA); if (url.pathname === "/definitions") return jsonResponse(BUNDLED_DEFINITIONS); if (url.pathname === "/index") return jsonResponse(getIndex()); if (url.pathname === "/api/ai-jobs-signal") return handleAdsSignal(request, url, env); return textResponse("Not Found", { status: 404 }); } }; From 5646c86a187dac2e51095013cffb467b818cc37b Mon Sep 17 00:00:00 2001 From: Trailgenic Date: Wed, 15 Jul 2026 17:22:40 -0700 Subject: [PATCH 2/3] Complete SDK MCP integration scaffolding and workers tests --- .github/workflows/deploy.yml | 2 + lib/ads-classifier.js | 39 +++- lib/mcp-server.js | 173 +++++++++++++++++ scripts/live-acceptance.mjs | 59 ++++-- tests/worker.vitest.mjs | 203 ++++++++++++++++++++ vitest.config.mjs | 8 +- worker.js | 352 ++++++++++++++++++++++++++++++++--- wrangler.jsonc | 6 +- 8 files changed, 787 insertions(+), 55 deletions(-) create mode 100644 lib/mcp-server.js create mode 100644 tests/worker.vitest.mjs diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 69a09de..5e0004b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,6 +1,8 @@ name: Deploy on: workflow_dispatch: + push: + branches: [main] jobs: verify: runs-on: ubuntu-latest diff --git a/lib/ads-classifier.js b/lib/ads-classifier.js index b6782e7..dc4d110 100644 --- a/lib/ads-classifier.js +++ b/lib/ads-classifier.js @@ -27,12 +27,23 @@ function clamp(value, min, max) { return Math.min(max, Math.max(min, value)); } -export async function classifyPostings(postings, anthropicApiKey) { - try { - if (!Array.isArray(postings) || postings.length === 0 || !anthropicApiKey) { - return []; - } +export class ADSUpstreamError extends Error { + constructor(message, status = 502) { + super(message); + this.name = "ADSUpstreamError"; + this.status = status; + } +} + +export async function classifyPostings(postings, anthropicApiKey, { signal } = {}) { + if (!Array.isArray(postings) || postings.length === 0) { + return []; + } + if (!anthropicApiKey) { + throw new ADSUpstreamError("Missing Anthropic API key", 502); + } + try { const response = await fetch("https://api.anthropic.com/v1/messages", { method: "POST", headers: { @@ -40,6 +51,7 @@ export async function classifyPostings(postings, anthropicApiKey) { "x-api-key": anthropicApiKey, "anthropic-version": "2023-06-01" }, + signal, body: JSON.stringify({ model: "claude-sonnet-4-20250514", max_tokens: 1000, @@ -54,19 +66,26 @@ export async function classifyPostings(postings, anthropicApiKey) { }); if (!response.ok) { - return []; + throw new ADSUpstreamError("ADS classification upstream failed", 502); } const payload = await response.json(); const text = payload?.content?.[0]?.text; if (!text) { - return []; + throw new ADSUpstreamError("ADS classification upstream returned an empty response", 502); } const parsed = JSON.parse(text); - return Array.isArray(parsed?.classified) ? parsed.classified : []; - } catch { - return []; + if (!Array.isArray(parsed?.classified)) { + throw new ADSUpstreamError("ADS classification upstream returned invalid JSON", 502); + } + return parsed.classified; + } catch (error) { + if (error?.name === "AbortError" || error?.name === "TimeoutError") { + throw new ADSUpstreamError("ADS classification upstream timed out", 504); + } + if (error instanceof ADSUpstreamError) throw error; + throw new ADSUpstreamError("ADS classification upstream failed", 502); } } diff --git a/lib/mcp-server.js b/lib/mcp-server.js new file mode 100644 index 0000000..2794453 --- /dev/null +++ b/lib/mcp-server.js @@ -0,0 +1,173 @@ +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; +import { BUILD, CONTENT_LINKS, DATA_TOOLS, ENTITY, MCP_PROTOCOL_VERSIONS, MCP_RESOURCES } from "./registry.js"; +import { getDatasetIndex, getIndex, TOOL_HANDLERS } from "./queries.js"; + +export const TOOL_IDS = new Set(DATA_TOOLS.map((tool) => tool.id)); + +const SUPPORTED_SCHEMA_KEYS = new Set([ + "type", + "properties", + "required", + "additionalProperties", + "description", + "minimum", + "maximum", + "exclusiveMinimum", + "exclusiveMaximum", + "enum", + "$schema" +]); + +function assertSupportedSchema(schema, path = "schema") { + if (!schema || typeof schema !== "object" || Array.isArray(schema)) return; + for (const key of Object.keys(schema)) { + if (!SUPPORTED_SCHEMA_KEYS.has(key)) { + throw new Error(`Unsupported JSON Schema keyword at ${path}: ${key}`); + } + } + if (schema.properties) { + for (const [name, child] of Object.entries(schema.properties)) { + assertSupportedSchema(child, `${path}.properties.${name}`); + } + } +} + +export function jsonSchemaToZod(schema, path = "schema") { + assertSupportedSchema(schema, path); + let zodSchema; + if (schema.enum) { + if (!Array.isArray(schema.enum) || schema.enum.length === 0) { + throw new Error(`Invalid enum at ${path}`); + } + zodSchema = z.enum(schema.enum.map(String)); + } else if (schema.type === "object") { + const required = new Set(schema.required || []); + const shape = {}; + for (const [name, child] of Object.entries(schema.properties || {})) { + const childSchema = jsonSchemaToZod(child, `${path}.properties.${name}`); + shape[name] = required.has(name) ? childSchema : childSchema.optional(); + } + zodSchema = z.object(shape); + if (schema.additionalProperties === false) zodSchema = zodSchema.strict(); + } else if (schema.type === "string") { + zodSchema = z.string(); + } else if (schema.type === "integer") { + zodSchema = z.number().int(); + } else if (schema.type === "number") { + zodSchema = z.number(); + } else { + throw new Error(`Unsupported JSON Schema type at ${path}: ${schema.type}`); + } + + if (typeof schema.minimum === "number") zodSchema = zodSchema.min(schema.minimum); + if (typeof schema.maximum === "number") zodSchema = zodSchema.max(schema.maximum); + if (typeof schema.exclusiveMinimum === "number") zodSchema = zodSchema.gt(schema.exclusiveMinimum); + if (typeof schema.exclusiveMaximum === "number") zodSchema = zodSchema.lt(schema.exclusiveMaximum); + if (schema.description && typeof zodSchema.describe === "function") zodSchema = zodSchema.describe(schema.description); + return zodSchema; +} + +export function mcpResourceProjection() { + return MCP_RESOURCES.filter((resource) => resource.includeInDiscovery).map((resource) => ({ + uri: resource.uri, + name: resource.name, + title: resource.name, + description: resource.description, + mimeType: resource.mimeType + })); +} + +export function contentIndexResource() { + return { + content_links: CONTENT_LINKS.map(({ title, description = title, url }) => ({ + title, + description, + canonical_url: url + })) + }; +} + +export function resolveMcpResource(uri) { + if (uri === "exmxc://datasets/index") return getDatasetIndex(); + if (uri === "exmxc://content/index") return contentIndexResource(); + const resource = MCP_RESOURCES.find((candidate) => candidate.uri === uri); + if (!resource) return null; + if (resource.resolver === "index") return getIndex(); + if (resource.data) return resource.data; + return null; +} + +function toolResultFromHandlerResult(result) { + const toolResult = { + content: [{ type: "text", text: JSON.stringify(result) }] + }; + if (result && typeof result === "object" && !Array.isArray(result)) { + toolResult.structuredContent = result; + } + if (result?.success === false || result?.error) { + toolResult.isError = true; + } + return toolResult; +} + +function errorToolResult(message) { + return { + isError: true, + content: [{ type: "text", text: JSON.stringify({ success: false, error: message }) }] + }; +} + +export function createExmxcMcpServer() { + // SDK >= 1.26 forbids reusing a connected McpServer across clients; create a fresh server for every request to avoid cross-client response leakage. + const server = new McpServer( + { name: ENTITY.name, version: BUILD.version }, + { capabilities: { tools: {}, resources: {} }, protocolVersion: MCP_PROTOCOL_VERSIONS[0] } + ); + + for (const tool of DATA_TOOLS) { + const zodSchema = jsonSchemaToZod(tool.inputSchema); + server.registerTool( + tool.id, + { + title: tool.title, + description: tool.description, + inputSchema: zodSchema, + annotations: { + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, + openWorldHint: tool.id === "ex.eei.audit.run" + } + }, + async (args) => { + const parsed = zodSchema.safeParse(args ?? {}); + if (!parsed.success) return errorToolResult(`Invalid arguments: ${parsed.error.message}`); + try { + const result = await TOOL_HANDLERS[tool.id](parsed.data); + return toolResultFromHandlerResult(result); + } catch (error) { + return errorToolResult(String(error?.message || error)); + } + } + ); + } + + for (const resource of MCP_RESOURCES.filter((entry) => entry.includeInDiscovery)) { + const read = async (uri) => { + const resolved = resolveMcpResource(String(uri)); + if (!resolved) throw new Error(`Unknown resource: ${uri}`); + return { + contents: [{ uri: String(uri), mimeType: resource.mimeType, text: JSON.stringify(resolved) }] + }; + }; + if (resource.uri.includes("{")) { + server.registerResource(resource.name, new ResourceTemplate(resource.uri, { list: undefined }), { title: resource.name, description: resource.description, mimeType: resource.mimeType }, read); + } else { + server.registerResource(resource.name, resource.uri, { title: resource.name, description: resource.description, mimeType: resource.mimeType }, read); + } + } + + return server; +} diff --git a/scripts/live-acceptance.mjs b/scripts/live-acceptance.mjs index b258969..e79ae2a 100644 --- a/scripts/live-acceptance.mjs +++ b/scripts/live-acceptance.mjs @@ -1,25 +1,46 @@ import { BUILD, DATA_TOOLS, MCP_PROTOCOL_VERSIONS, MCP_RESOURCES } from '../lib/registry.js'; const BASE = process.env.BASE || 'https://mcp.exmxc.ai'; -const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); async function raw(path, init = {}, retry = true) { - const r = await fetch(BASE + path, init); - const ct = r.headers.get('content-type') || ''; - if (retry && (r.status === 429 || ct.includes('text/html'))) { await sleep(11000); return raw(path, init, false); } - let d = null; if (ct.includes('application/json')) d = await r.json(); - return { r, d }; + const response = await fetch(BASE + path, init); + const contentType = response.headers.get('content-type') || ''; + if (retry && (response.status === 429 || contentType.includes('text/html'))) { + await sleep(11000); + return raw(path, init, false); + } + let json = null; + if (contentType.includes('application/json')) json = await response.json(); + return { response, json, contentType }; } -async function rpc(id, method, params, protocolVersion = MCP_PROTOCOL_VERSIONS[0], accept = 'application/json') { +async function rpc(id, method, params, { protocolHeader, accept = 'application/json' } = {}) { await sleep(1100); - return raw('/mcp', { method: 'POST', headers: { 'content-type': 'application/json', accept, 'mcp-protocol-version': protocolVersion }, body: JSON.stringify({ jsonrpc: '2.0', id, method, params }) }); + const headers = { 'content-type': 'application/json', accept }; + if (protocolHeader) headers['mcp-protocol-version'] = protocolHeader; + return raw('/mcp', { method: 'POST', headers, body: JSON.stringify({ jsonrpc: '2.0', id, method, params }) }); } -let pass = 0, fail = 0; const ok = (c, m) => { c ? pass++ : fail++; console.log(`${c ? 'PASS' : 'FAIL'} ${m}`); }; -for (const version of MCP_PROTOCOL_VERSIONS) { const init = await rpc(`init-${version}`, 'initialize', { protocolVersion: version, capabilities: {}, clientInfo: { name: 'acceptance', version: BUILD.version } }, version); ok(init.d?.result?.protocolVersion === version && init.d?.result?.serverInfo?.version === BUILD.version, `initialize negotiates ${version}`); } -ok((await rpc('bad-accept', 'ping', {}, MCP_PROTOCOL_VERSIONS[0], 'text/event-stream')).r.status === 406, 'event-stream-only accept rejected'); -const list = await rpc(2, 'tools/list', {}); const tools = (list.d?.result?.tools || []).map((t) => t.name).sort(); ok(JSON.stringify(tools) === JSON.stringify(DATA_TOOLS.map((t) => t.id).sort()), 'tools/list equals registry'); -const resources = await rpc(3, 'resources/list', {}); ok(JSON.stringify((resources.d?.result?.resources || []).map((r) => r.uri).sort()) === JSON.stringify(MCP_RESOURCES.filter((r) => r.includeInDiscovery).map((r) => r.uri).sort()), 'resources/list equals registry'); -const restDatasets = await raw('/datasets'); const mcpDatasets = await rpc(4, 'resources/read', { uri: 'exmxc://datasets/index' }); ok(JSON.stringify(JSON.parse(mcpDatasets.d.result.contents[0].text)) === JSON.stringify(restDatasets.d), 'dataset index resource matches REST'); -ok((await raw('/mcp', { method: 'OPTIONS', headers: { origin: 'https://evil.example' } })).r.status === 403, 'disallowed origin preflight rejected'); -ok((await raw('/?cb=' + Date.now())).r.headers.get('cache-control')?.includes('no-cache'), 'root discovery no-cache'); -ok((await raw('/api/ai-jobs-signal')).d?.mode === 'benchmark', 'ADS benchmark only'); -ok((await raw('/audit/run?url=http%3A%2F%2Flocalhost')).r.status >= 400, 'audit rejects invalid target'); -console.log(`\n${pass} passed, ${fail} failed`); process.exit(fail ? 1 : 0); +let pass = 0; +let fail = 0; +const ok = (condition, message) => { condition ? pass++ : fail++; console.log(`${condition ? 'PASS' : 'FAIL'} ${message}`); }; + +for (const version of MCP_PROTOCOL_VERSIONS) { + const init = await rpc(`init-${version}`, 'initialize', { protocolVersion: version, capabilities: {}, clientInfo: { name: 'acceptance', version: BUILD.version } }); + ok(init.json?.result?.protocolVersion === version && init.json?.result?.serverInfo?.version === BUILD.version, `initialize negotiates payload ${version}`); +} +ok((await rpc('bad-header', 'ping', {}, { protocolHeader: '2099-01-01' })).response.status === 400, 'invalid subsequent MCP-Protocol-Version header -> 400'); +ok((await rpc('bad-accept', 'ping', {}, { accept: 'text/event-stream' })).response.status === 406, 'event-stream-only accept rejected'); +const list = await rpc(2, 'tools/list', {}); +const tools = (list.json?.result?.tools || []).map((tool) => tool.name).sort(); +ok(JSON.stringify(tools) === JSON.stringify(DATA_TOOLS.map((tool) => tool.id).sort()), 'tools/list equals registry'); +const resources = await rpc(3, 'resources/list', {}); +ok(JSON.stringify((resources.json?.result?.resources || []).map((resource) => resource.uri).sort()) === JSON.stringify(MCP_RESOURCES.filter((resource) => resource.includeInDiscovery).map((resource) => resource.uri).sort()), 'resources/list equals registry'); +const restDatasets = await raw('/datasets'); +const mcpDatasets = await rpc(4, 'resources/read', { uri: 'exmxc://datasets/index' }); +ok(JSON.stringify(JSON.parse(mcpDatasets.json.result.contents[0].text)) === JSON.stringify(restDatasets.json), 'dataset index resource matches REST'); +ok((await raw('/mcp', { method: 'OPTIONS', headers: { origin: 'https://evil.example' } })).response.status === 403, 'disallowed origin preflight rejected'); +ok((await raw('/?cb=' + Date.now())).response.headers.get('cache-control')?.includes('no-cache'), 'root discovery no-cache'); +ok((await raw('/api/ai-jobs-signal')).json?.mode === 'benchmark', 'ADS benchmark only'); +const auditOk = await raw('/audit/run?url=https%3A%2F%2Fexample.com'); +ok(auditOk.response.status < 500 && auditOk.contentType.includes('application/json'), 'audit valid controlled HTTPS target returns JSON without server error'); +ok((await raw('/audit/run?url=http%3A%2F%2Flocalhost')).response.status >= 400, 'audit rejects invalid target'); +console.log(`\n${pass} passed, ${fail} failed`); +process.exit(fail ? 1 : 0); diff --git a/tests/worker.vitest.mjs b/tests/worker.vitest.mjs new file mode 100644 index 0000000..7208b8c --- /dev/null +++ b/tests/worker.vitest.mjs @@ -0,0 +1,203 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { SELF } from 'cloudflare:test'; +import { readFile } from 'node:fs/promises'; +import { BUILD, DATA_TOOLS, MCP_RESOURCES } from '../lib/registry.js'; +import { contentIndexResource, mcpResourceProjection } from '../lib/mcp-server.js'; + +const BASE = 'https://mcp.exmxc.ai'; +const toolIds = () => DATA_TOOLS.map((tool) => tool.id).sort(); +const resourceUris = () => MCP_RESOURCES.filter((resource) => resource.includeInDiscovery).map((resource) => resource.uri).sort(); +const validArgs = { + 'ex.entities.get': { industry: 'Energy' }, + 'ex.speg.get': { ticker: 'NVDA' }, + 'ex.datasets.index.get': {}, + 'ex.ai_power_index.get': {}, + 'ex.four_forces.get': {}, + 'ex.entity_in_a_box.get': {}, + 'ex.ai_power.analysis.top': { limit: 1 }, + 'ex.eei.audit.run': { url: 'https://example.com' }, + 'ex.convergence.latest': {}, + 'ex.convergence.log': { limit: 1 } +}; +expect(Object.keys(validArgs).sort()).toEqual(toolIds()); + +function req(path, init = {}) { + return SELF.fetch(`${BASE}${path}`, init); +} + +function mcp(body, headers = {}) { + return req('/mcp', { + method: 'POST', + headers: { 'content-type': 'application/json', accept: 'application/json, text/event-stream', ...headers }, + body: typeof body === 'string' ? body : JSON.stringify(body) + }); +} + +async function rpc(method, params = {}, id = 1, headers = {}) { + const response = await mcp({ jsonrpc: '2.0', id, method, params }, headers); + const text = await response.text(); + return { response, text, json: text ? JSON.parse(text) : null }; +} + +function normalizeSchema(value) { + if (Array.isArray(value)) return value.map(normalizeSchema).sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b))); + if (!value || typeof value !== 'object') return value; + return Object.fromEntries(Object.entries(value) + .filter(([key]) => key !== '$schema') + .sort(([a], [b]) => a.localeCompare(b)) + .map(([key, child]) => [key, key === 'required' && Array.isArray(child) ? [...child].sort() : normalizeSchema(child)])); +} + +function mockExternalFetch() { + const calls = []; + vi.stubGlobal('fetch', vi.fn(async (input) => { + const url = String(input?.url || input); + calls.push(url); + if (url.includes('exmxc-audit.vercel.app')) { + return new Response(JSON.stringify({ success: true, score: 91, url }), { status: 200, headers: { 'content-type': 'application/json' } }); + } + if (url.includes('api.anthropic.com')) { + return new Response(JSON.stringify({ content: [{ text: JSON.stringify([{ posting_id: 'synthetic-001', title: 'AI Agent Engineer', skills_raw: ['MCP'] }]) }] }), { status: 200, headers: { 'content-type': 'application/json' } }); + } + return SELF.fetch(input); + })); + return calls; +} + +beforeEach(() => vi.restoreAllMocks()); + +describe('MCP protocol and transport policy', () => { + it('negotiates supported initialize payload versions and rejects invalid subsequent headers', async () => { + for (const version of ['2025-11-25', '2025-06-18']) { + const { json } = await rpc('initialize', { protocolVersion: version, capabilities: {}, clientInfo: { name: 'vitest', version: BUILD.version } }); + expect(json.result.protocolVersion).toBe(version); + expect(json.result.serverInfo.version).toBe(BUILD.version); + } + const fabricated = await rpc('initialize', { protocolVersion: '2099-01-01', capabilities: {}, clientInfo: { name: 'vitest', version: BUILD.version } }); + expect(fabricated.json.result.protocolVersion).not.toBe('2099-01-01'); + expect((await rpc('ping', {}, 9, { 'mcp-protocol-version': '2099-01-01' })).response.status).toBe(400); + }); + + it('applies Accept and Content-Type tables including normalization through SDK', async () => { + const accepted = [undefined, '', '*/*', 'application/json', 'Application/JSON; Charset=UTF-8', 'application/json, text/event-stream']; + for (const accept of accepted) { + const headers = { 'content-type': 'application/json' }; + if (accept !== undefined) headers.accept = accept; + const response = await req('/mcp', { method: 'POST', headers, body: JSON.stringify({ jsonrpc: '2.0', id: accept || 'missing', method: 'ping', params: {} }) }); + expect(response.status).toBe(200); + expect(response.headers.get('cache-control')).toBe('no-store'); + } + expect((await mcp({ jsonrpc: '2.0', id: 1, method: 'ping' }, { accept: 'text/event-stream' })).status).toBe(406); + expect((await mcp({ jsonrpc: '2.0', id: 1, method: 'ping' }, { accept: 'application/json;q=0, text/event-stream' })).status).toBe(406); + expect((await mcp({ jsonrpc: '2.0', id: 1, method: 'ping' }, { accept: 'text/plain' })).status).toBe(406); + expect((await req('/mcp', { method: 'POST', headers: { 'content-type': 'text/plain', accept: 'application/json' }, body: '{}' })).status).toBe(415); + }); + + it('applies origin CORS to preflight, early errors, and SDK responses', async () => { + expect((await req('/mcp', { method: 'OPTIONS', headers: { origin: 'https://evil.example' } })).status).toBe(403); + const preflight = await req('/mcp', { method: 'OPTIONS', headers: { origin: 'https://exmxc.ai' } }); + expect(preflight.status).toBe(204); + expect(preflight.headers.get('access-control-allow-origin')).toBe('https://exmxc.ai'); + const early = await req('/mcp', { method: 'GET', headers: { origin: 'https://exmxc.ai' } }); + expect(early.status).toBe(405); + expect(early.headers.get('access-control-allow-origin')).toBe('https://exmxc.ai'); + const sdk = await mcp({ jsonrpc: '2.0', id: 1, method: 'ping' }, { origin: 'https://mcp.exmxc.ai' }); + expect(sdk.headers.get('access-control-allow-origin')).toBe('https://mcp.exmxc.ai'); + }); + + it('uses per-request server isolation', async () => { + const one = await rpc('initialize', { protocolVersion: '2025-06-18', capabilities: {}, clientInfo: { name: 'a', version: '1' } }, 1); + const two = await rpc('initialize', { protocolVersion: '2025-11-25', capabilities: {}, clientInfo: { name: 'b', version: '1' } }, 2); + expect(one.json.id).toBe(1); + expect(two.json.id).toBe(2); + expect(one.json.result.protocolVersion).toBe('2025-06-18'); + expect(two.json.result.protocolVersion).toBe('2025-11-25'); + }); +}); + +describe('tools and schemas', () => { + it('lists schemas semantically equal to registry schemas', async () => { + const { json } = await rpc('tools/list'); + const byName = Object.fromEntries(json.result.tools.map((tool) => [tool.name, tool])); + for (const tool of DATA_TOOLS) expect(normalizeSchema(byName[tool.id].inputSchema)).toEqual(normalizeSchema(tool.inputSchema)); + }); + + it('successfully calls every registered tool with exhaustive fixtures', async () => { + mockExternalFetch(); + for (const id of toolIds()) { + const { json } = await rpc('tools/call', { name: id, arguments: validArgs[id] }, id); + expect(json.result.content[0].type).toBe('text'); + const parsed = JSON.parse(json.result.content[0].text); + if (Array.isArray(parsed)) expect(json.result.structuredContent).toBeUndefined(); + else expect(json.result.structuredContent).toEqual(parsed); + } + }); + + it('rejects invalid arguments, unknown fields, and unknown tools', async () => { + const missing = await rpc('tools/call', { name: 'ex.eei.audit.run', arguments: {} }); + expect(missing.json.result.isError).toBe(true); + const unknownField = await rpc('tools/call', { name: 'ex.ai_power.analysis.top', arguments: { limit: 1, extra: true } }); + expect(unknownField.json.result.isError).toBe(true); + const unknownTool = await rpc('tools/call', { name: 'ex.nope', arguments: {} }); + expect(unknownTool.json.error.code).toBe(-32602); + }); +}); + +describe('resources', () => { + it('lists registry-derived public resource projection', async () => { + const { json } = await rpc('resources/list'); + const simplified = json.result.resources.map(({ uri, name, title, description, mimeType }) => ({ uri, name, title, description, mimeType })).sort((a, b) => a.uri.localeCompare(b.uri)); + expect(simplified).toEqual(mcpResourceProjection().sort((a, b) => a.uri.localeCompare(b.uri))); + expect(simplified.map((resource) => resource.uri).sort()).toEqual(resourceUris()); + }); + + it('reads every route-backed resource equal to REST and content index equal to resolver', async () => { + for (const resource of MCP_RESOURCES.filter((entry) => entry.includeInDiscovery)) { + const { json } = await rpc('resources/read', { uri: resource.uri }, resource.uri); + const readPayload = JSON.parse(json.result.contents[0].text); + if (resource.uri === 'exmxc://content/index') { + expect(readPayload).toEqual(contentIndexResource()); + } else if (resource.route) { + const rest = await req(resource.route); + expect(readPayload).toEqual(await rest.json()); + } + } + }); +}); + +describe('ADS, audit, cache, and registry', () => { + it('hardens ADS benchmark and paid rejection paths without Anthropic fetches', async () => { + const calls = mockExternalFetch(); + const benchmark1 = await (await req('/api/ai-jobs-signal')).json(); + const benchmark2 = await (await req('/api/ai-jobs-signal')).json(); + expect(benchmark1).toEqual(benchmark2); + expect((await req('/api/ai-jobs-signal?mode=signal')).status).toBe(405); + expect((await req('/api/ai-jobs-signal', { method: 'POST', body: '{not-json' })).status).toBe(401); + expect((await req('/api/ai-jobs-signal', { method: 'POST', headers: { authorization: 'Bearer undefined' }, body: JSON.stringify({ query: 'x', count: 1 }) })).status).toBe(401); + expect(calls.filter((url) => url.includes('api.anthropic.com'))).toHaveLength(0); + }); + + it('validates and mocks audit targets', async () => { + mockExternalFetch(); + expect((await req('/audit/run?url=http%3A%2F%2Fexample.com')).status).toBe(400); + expect((await req('/audit/run?url=https%3A%2F%2Flocalhost')).status).toBe(400); + const ok = await req('/audit/run?url=https%3A%2F%2Fexample.com'); + expect(ok.status).toBe(200); + expect((await ok.json()).success).toBe(true); + }); + + it('asserts route-class cache headers', async () => { + expect((await req('/health')).headers.get('cache-control')).toBe('no-store'); + expect((await req('/')).headers.get('cache-control')).toBe('no-cache'); + expect((await req('/.well-known/openapi.json')).headers.get('cache-control')).toBe('no-cache'); + expect((await req('/entities')).headers.get('cache-control')).toBe('public, max-age=3600'); + expect((await req('/api/ai-jobs-signal')).headers.get('cache-control')).toBe('public, max-age=3600'); + expect((await req('/audit/run?url=http%3A%2F%2Flocalhost')).headers.get('cache-control')).toBe('no-store'); + }); + + it('detects registry packet drift', async () => { + const packet = JSON.parse(await readFile('registry/packet.json', 'utf8')); + expect(packet.version).toBe(BUILD.version); + expect(packet.tools.map((tool) => tool.name).sort()).toEqual(toolIds()); + }); +}); diff --git a/vitest.config.mjs b/vitest.config.mjs index b22e3f5..9ed92a7 100644 --- a/vitest.config.mjs +++ b/vitest.config.mjs @@ -1 +1,7 @@ -export default { test: { include: ['tests/**/*.test.mjs'] } }; +import { defineConfig } from 'vitest/config'; +import { cloudflareTest } from '@cloudflare/vitest-pool-workers'; + +export default defineConfig({ + plugins: [cloudflareTest({ wrangler: { configPath: './wrangler.jsonc' } })], + test: { include: ['tests/worker.vitest.mjs'] } +}); diff --git a/worker.js b/worker.js index 5d9ec0c..cb404b7 100644 --- a/worker.js +++ b/worker.js @@ -1,29 +1,335 @@ -import { classifyPostings, computeADS } from "./lib/ads-classifier.js"; +import { createMcpHandler } from "agents/mcp"; +import { ADSUpstreamError, classifyPostings, computeADS } from "./lib/ads-classifier.js"; import { CACHE, emptyResponse, jsonResponse, mcpCorsHeaders, textResponse } from "./lib/http.js"; -import { BUILD, BUNDLED_DEFINITIONS, BUNDLED_SCHEMA, CONTENT_LINKS, DATASETS, DATA_TOOLS, ENTITY, FEDERATED_REGISTRIES, MCP_ORIGIN, MCP_PROTOCOL_VERSIONS, MCP_RESOURCES, MCP_TRANSPORT } from "./lib/registry.js"; -import { getAiPowerTop, getConvergenceLatest, getConvergenceLog, getDatasetIndex, getEntities, getFourForces, getIndex, getSpeg, TOOL_HANDLERS, validateAuditTarget } from "./lib/queries.js"; +import { createExmxcMcpServer, mcpResourceProjection, contentIndexResource, TOOL_IDS } from "./lib/mcp-server.js"; +import { + BUILD, + BUNDLED_DEFINITIONS, + BUNDLED_SCHEMA, + CONTENT_LINKS, + DATASETS, + DATA_TOOLS, + ENTITY, + FEDERATED_REGISTRIES, + MCP_ORIGIN, + MCP_PROTOCOL_VERSIONS, + MCP_RESOURCES, + MCP_TRANSPORT +} from "./lib/registry.js"; +import { + getAiPowerTop, + getConvergenceLatest, + getConvergenceLog, + getDatasetIndex, + getEntities, + getFourForces, + getIndex, + getSpeg, + TOOL_HANDLERS, + validateAuditTarget +} from "./lib/queries.js"; import baseline from "./data/ads-baseline.json" with { type: "json" }; const SYNTHETIC_DISCLAIMER = "Postings are model-generated illustrations for ADS analysis, not scraped or verified labor-market data."; -const TOOL_IDS = new Set(DATA_TOOLS.map((tool) => tool.id)); const JSON_SSE = "application/json, text/event-stream"; +const ADS_BODY_LIMIT_BYTES = 8192; +const ADS_GENERATION_TIMEOUT_MS = 20_000; +const ADS_CLASSIFICATION_TIMEOUT_MS = 20_000; -function queryArgs(url, keys) { return Object.fromEntries(keys.map((key) => [key, url.searchParams.get(key)]).filter(([, value]) => value)); } -function toolInventory() { return DATA_TOOLS.map((tool) => ({ id: tool.id, title: tool.title, description: tool.description, endpoint: `${MCP_ORIGIN}${tool.route}`, inputSchema: tool.inputSchema })); } -function resourceInventory() { return MCP_RESOURCES.filter((r) => r.includeInDiscovery).map(({ uri, name, description, mimeType, category, route }) => ({ uri, name, title: name, description, mimeType, category, route })); } -function contentIndex() { return { content_links: CONTENT_LINKS.map(({ title, description = title, url }) => ({ title, description, canonical_url: url })) }; } -function openApiParameter(name, schema = { type: "string" }) { return { name, in: name === "url" ? "query" : "query", required: name === "url", schema: name === "limit" ? { type: "integer", minimum: 1, maximum: 100 } : schema, description: name }; } -function capabilitiesDocument() { return { capability_version: "2.1", entity: ENTITY, mcp: { endpoint: MCP_ORIGIN, mcp_transport: MCP_TRANSPORT, protocol_versions: MCP_PROTOCOL_VERSIONS, registry: `${MCP_ORIGIN}/.well-known/tool-registry.json`, openapi: `${MCP_ORIGIN}/.well-known/openapi.json` }, tools: toolInventory(), resources: resourceInventory(), content_links: CONTENT_LINKS, federated_registries: FEDERATED_REGISTRIES, positioning: { structured_outputs: true, deterministic_schema: true, machine_readable: true }, last_updated: BUILD.released }; } -function registryDocument() { return { registry_version: "2.1", entity: ENTITY, discovery: { protocol: "MCP Streamable HTTP via official SDK-compatible Cloudflare Workers handler", endpoint: `${MCP_ORIGIN}/.well-known/tool-registry.json`, mcp_transport: MCP_TRANSPORT, protocol_versions: MCP_PROTOCOL_VERSIONS }, tools: toolInventory(), resources: resourceInventory(), content_links: CONTENT_LINKS, federated_registries: FEDERATED_REGISTRIES, last_updated: BUILD.released }; } -function mcpDiscoveryDocument() { return { mcp_version: "1.0", name: ENTITY.name, description: ENTITY.description, endpoint: MCP_ORIGIN, mcp_transport: MCP_TRANSPORT, protocol_versions: MCP_PROTOCOL_VERSIONS, resources: resourceInventory().map((r) => r.uri), last_updated: BUILD.released }; } -function manifestDocument() { return { name: "exmxc MCP Manifest", version: BUILD.version, entity: ENTITY, discovery: { root: MCP_ORIGIN, protocol: "MCP Streamable HTTP via Cloudflare Workers", mcp_transport: MCP_TRANSPORT, protocol_versions: MCP_PROTOCOL_VERSIONS }, endpoints: { discovery: "/", mcp_transport: "/mcp", capabilities: "/capabilities.json", health: "/health", registry: "/.well-known/tool-registry.json", openapi: "/.well-known/openapi.json" }, datasets: Object.values(DATASETS).map(({ id, route, displayName, description, category, schemaRoute }) => ({ id, route, displayName, description, category, schemaRoute })), tools: toolInventory(), resources: resourceInventory(), content_links: CONTENT_LINKS, last_updated: BUILD.released }; } -function openApiDocument() { const json200 = { description: "JSON response" }; const toolPaths = Object.fromEntries(DATA_TOOLS.map((tool) => [tool.route, { get: { summary: tool.title, description: tool.description, parameters: (tool.openApiParameters || []).map((p) => openApiParameter(p)), responses: { 200: json200 } } }])); return { openapi: "3.0.1", info: { title: "exmxc REST and MCP API", version: BUILD.version, description: "REST/JSON intelligence API plus an MCP server using Streamable HTTP via the Cloudflare Workers handler." }, servers: [{ url: MCP_ORIGIN }], components: { securitySchemes: { AdsSignalBearer: { type: "http", scheme: "bearer" } } }, paths: { ...Object.fromEntries(Object.values(DATASETS).map((d) => [d.route, { get: { summary: `Retrieve ${d.displayName}`, responses: { 200: json200 } } }])), ...toolPaths, "/api/ai-jobs-signal": { get: { summary: "ADS benchmark", responses: { 200: json200, 405: { description: "Signal generation requires POST" } } }, post: { summary: "Paid ADS signal generation", security: [{ AdsSignalBearer: [] }], responses: { 200: json200, 400: { description: "Invalid body" }, 401: { description: "Unauthorized" }, 502: { description: "Upstream failed" }, 504: { description: "Upstream timeout" } } } }, "/mcp": { post: { summary: "MCP Streamable HTTP transport", responses: { 200: json200, 400: { description: "Bad MCP protocol version" }, 403: { description: "Origin forbidden" }, 405: { description: "Method not allowed" }, 406: { description: "Not acceptable" }, 415: { description: "Unsupported media type" } } } } } }; } -function rpc(id, result, headers = {}) { return jsonResponse({ jsonrpc: "2.0", id, result }, { headers: { ...headers, "Cache-Control": CACHE.NO_STORE } }); } -function rpcErr(id, code, message, headers = {}) { return jsonResponse({ jsonrpc: "2.0", id: id ?? null, error: { code, message } }, { status: 200, headers: { ...headers, "Cache-Control": CACHE.NO_STORE } }); } -function mediaAvailable(header, type) { if (!header || !header.trim()) return type === "application/json"; return header.split(",").some((part) => { const [mt, ...params] = part.trim().toLowerCase().split(";").map((x) => x.trim()); const q0 = params.some((p) => /^q=0(?:\.0*)?$/.test(p)); return !q0 && (mt === type || mt === "*/*"); }); } -function acceptable(request) { const accept = request.headers.get("Accept") || ""; const json = mediaAvailable(accept, "application/json"); const sse = mediaAvailable(accept, "text/event-stream"); if (!json && sse) return false; if (!json) return false; return true; } -async function handleMcp(request, env) { const cors = mcpCorsHeaders(request, env); const origin = request.headers.get("Origin"); if (origin && !cors["Access-Control-Allow-Origin"]) return emptyResponse({ status: 403, headers: cors }); if (request.method === "OPTIONS") return emptyResponse({ status: 204, headers: cors }); if (request.method !== "POST") return emptyResponse({ status: 405, headers: { ...cors, Allow: "POST" } }); const ct = (request.headers.get("Content-Type") || "").split(";")[0].trim().toLowerCase(); if (ct !== "application/json") return emptyResponse({ status: 415, headers: cors }); if (!acceptable(request)) return emptyResponse({ status: 406, headers: cors }); const pv = request.headers.get("MCP-Protocol-Version"); if (pv && !MCP_PROTOCOL_VERSIONS.includes(pv)) return emptyResponse({ status: 400, headers: cors }); const body = await request.text(); let payload; try { payload = JSON.parse(body); } catch { return rpcErr(null, -32700, "Parse error", cors); } const { id, method, params = {} } = payload || {}; if (method === "notifications/initialized") return emptyResponse({ status: 202, headers: cors }); if (method === "initialize") return rpc(id, { protocolVersion: MCP_PROTOCOL_VERSIONS.includes(params?.protocolVersion) ? params.protocolVersion : MCP_PROTOCOL_VERSIONS[0], capabilities: { tools: {}, resources: {} }, serverInfo: { name: ENTITY.name, version: BUILD.version } }, cors); if (method === "ping") return rpc(id, {}, cors); if (method === "tools/list") return rpc(id, { tools: DATA_TOOLS.map((tool) => ({ name: tool.id, title: tool.title, description: tool.description, inputSchema: tool.inputSchema, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: tool.id === "ex.eei.audit.run" } })) }, cors); if (method === "resources/list") return rpc(id, { resources: resourceInventory() }, cors); if (method === "resources/read") { const res = resolveResource(params?.uri); if (!res) return rpcErr(id, -32602, "Unknown resource", cors); return rpc(id, { contents: [{ uri: params.uri, mimeType: "application/json", text: JSON.stringify(res) }] }, cors); } if (method === "tools/call") { if (!TOOL_IDS.has(params?.name)) return rpcErr(id, -32602, "Unknown tool", cors); try { const result = await TOOL_HANDLERS[params.name](params?.arguments || {}); const out = { content: [{ type: "text", text: JSON.stringify(result) }] }; if (result && typeof result === "object" && !Array.isArray(result)) out.structuredContent = result; if (result?.success === false || result?.error) out.isError = true; return rpc(id, out, cors); } catch (e) { return rpc(id, { isError: true, content: [{ type: "text", text: JSON.stringify({ success: false, error: String(e?.message || e) }) }] }, cors); } } return rpcErr(id, -32601, "Method not found", cors); } -function resolveResource(uri) { if (uri === "exmxc://datasets/index") return getDatasetIndex(); if (uri === "exmxc://content/index") return contentIndex(); const r = MCP_RESOURCES.find((x) => x.uri === uri); if (!r) return null; if (r.resolver === "index") return getIndex(); if (r.data) return r.data; return null; } -async function handleAdsSignal(request, url, env) { const provenance = { data_provenance: "synthetic-llm-generated", disclaimer: SYNTHETIC_DISCLAIMER }; const noStore = { "Cache-Control": CACHE.NO_STORE }; if (request.method === "GET") { if (url.searchParams.get("mode") === "signal" || url.searchParams.has("query")) return jsonResponse({ error: "Signal generation requires POST." }, { status: 405, headers: noStore }); return jsonResponse({ tool: "ai-jobs-signal", version: "1.0", mode: "benchmark", generated_at: new Date().toISOString(), methodology: "https://exmxc.ai/frameworks/ads", ...provenance, data: baseline }); } if (request.method !== "POST") return jsonResponse({ error: "Method not allowed" }, { status: 405, headers: noStore }); if (request.headers.get("Authorization") !== `Bearer ${env?.ADS_SIGNAL_KEY}`) return jsonResponse({ error: "Unauthorized" }, { status: 401, headers: noStore }); const len = Number(request.headers.get("Content-Length") || 0); if (len > 8192) return jsonResponse({ error: "Request body too large" }, { status: 400, headers: noStore }); let body; try { body = await request.json(); } catch { return jsonResponse({ error: "Invalid JSON body" }, { status: 400, headers: noStore }); } const allowed = new Set(["query", "count"]); if (Object.keys(body).some((k) => !allowed.has(k))) return jsonResponse({ error: "Unknown field" }, { status: 400, headers: noStore }); const query = String(body.query || "agentic AI engineer"); const count = body.count ?? 15; if (query.length > 200 || !Number.isInteger(count) || count < 1 || count > 50) return jsonResponse({ error: "Invalid query or count" }, { status: 400, headers: noStore }); try { const genRes = await fetch("https://api.anthropic.com/v1/messages", { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": env.ANTHROPIC_API_KEY, "anthropic-version": "2023-06-01" }, body: JSON.stringify({ model: "claude-sonnet-4-20250514", max_tokens: 1000, messages: [{ role: "user", content: `Generate ${count} AI job postings for query: ${query}` }] }) }); if (!genRes.ok) return jsonResponse({ error: "ADS upstream failed" }, { status: 502, headers: noStore }); const generatedPayload = await genRes.json(); const postings = JSON.parse(generatedPayload?.content?.[0]?.text || "[]"); const normalized = Array.isArray(postings) ? postings.map((p, i) => ({ posting_id: p?.posting_id || `synthetic-${i + 1}`, title: p?.title || "", skills_raw: Array.isArray(p?.skills_raw) ? p.skills_raw : [] })) : []; const classified = await classifyPostings(normalized, env.ANTHROPIC_API_KEY); return jsonResponse({ tool: "ai-jobs-signal", version: "1.0", mode: "signal", query, requested_count: count, generated_count: normalized.length, prior_count: baseline.sample_size, ...provenance, metrics: computeADS(classified, normalized.length, baseline.sample_size), classified }, { headers: noStore }); } catch { return jsonResponse({ error: "ADS upstream timed out or failed" }, { status: 504, headers: noStore }); } } -function pluginDocument() { return { schema_version: "v1", name_for_human: "exmxc", name_for_model: "exmxc", description_for_human: "exmxc institutional intelligence system decoding AI power structures, entity clarity, and Applied Capital Architecture.", description_for_model: "Provides institutional intelligence datasets and REST endpoints. This legacy plugin manifest is not part of the MCP protocol.", auth: { type: "none" }, api: { type: "openapi", url: `${MCP_ORIGIN}/.well-known/openapi.json`, is_user_authenticated: false }, logo_url: "https://exmxc.ai/favicon.ico", contact_email: "support@exmxc.ai", legal_info_url: ENTITY.domain }; } -export default { async fetch(request, env) { const url = new URL(request.url); if (url.pathname === "/mcp") return handleMcp(request, env); if (request.method === "OPTIONS") return emptyResponse({ status: 204 }); const discoveryHeaders = { "Cache-Control": CACHE.NO_CACHE }; const noStore = { "Cache-Control": CACHE.NO_STORE }; if (url.pathname === "/.well-known/mcp.json") return jsonResponse(mcpDiscoveryDocument(), { headers: discoveryHeaders }); if (url.pathname === "/" || url.pathname === "") return jsonResponse({ name: "exmxc MCP Endpoint", entity: { name: ENTITY.name, domain: ENTITY.domain, founder: ENTITY.founder }, registry: `${MCP_ORIGIN}/.well-known/tool-registry.json`, openapi: `${MCP_ORIGIN}/.well-known/openapi.json`, manifest: `${MCP_ORIGIN}/.well-known/manifest.json`, capabilities: `${MCP_ORIGIN}/capabilities.json`, mcp_transport: MCP_TRANSPORT, protocol_versions: MCP_PROTOCOL_VERSIONS, tools: toolInventory(), resources: resourceInventory().map((r) => r.uri), health: `${MCP_ORIGIN}/health`, status: "active", discovery_protocol: "MCP Streamable HTTP", last_updated: BUILD.released }, { headers: discoveryHeaders }); if (url.pathname === "/capabilities.json") return jsonResponse(capabilitiesDocument(), { headers: discoveryHeaders }); if (url.pathname === "/health") return jsonResponse({ entity: ENTITY.name, status: "healthy", mcp_status: "not_checked", registry_status: "not_checked", plugin_status: "not_checked", openapi_status: "not_checked", uptime: null, infrastructure: { platform: "Cloudflare Workers", protocol: "MCP Streamable HTTP" }, last_checked: new Date().toISOString() }, { headers: noStore }); if (url.pathname === "/.well-known/tool-registry.json") return jsonResponse(registryDocument(), { headers: discoveryHeaders }); if (url.pathname === "/.well-known/openapi.json") return jsonResponse(openApiDocument(), { headers: discoveryHeaders }); if (url.pathname === "/.well-known/manifest.json") return jsonResponse(manifestDocument(), { headers: discoveryHeaders }); if (url.pathname === "/.well-known/ai-plugin.json") return jsonResponse(pluginDocument(), { headers: discoveryHeaders }); if (url.pathname === "/speg") return jsonResponse(getSpeg(queryArgs(url, ["sector", "scarcity_layer", "ticker"]))); if (url.pathname === "/entities") return jsonResponse(getEntities(queryArgs(url, ["industry", "entity_type", "posture", "capability"]))); if (url.pathname === "/datasets/ai_power_index") return jsonResponse(DATASETS.ai_power_index.data); if (url.pathname === "/datasets/ai_power_index/schema") return jsonResponse(DATASETS.ai_power_index.schema); if (url.pathname === "/datasets/four_forces") return jsonResponse(getFourForces()); if (url.pathname === "/datasets/entity_in_a_box" || url.pathname === "/datasets/entity_in_a_box_v1") return jsonResponse(DATASETS.entity_in_a_box.data); if (url.pathname === "/datasets") return jsonResponse(getDatasetIndex()); if (url.pathname === "/analysis/ai_power/top") return jsonResponse(getAiPowerTop(queryArgs(url, ["limit"]))); if (url.pathname === "/datasets/convergence_monitor") return jsonResponse(DATASETS.convergence_monitor.data); if (url.pathname === "/convergence/latest") return jsonResponse(getConvergenceLatest()); if (url.pathname === "/convergence/log") return jsonResponse(getConvergenceLog(queryArgs(url, ["limit"]))); if (url.pathname === "/audit/run") { const args = queryArgs(url, ["url"]); const valid = validateAuditTarget(args.url); if (!valid.ok) return jsonResponse({ success: false, error: valid.error }, { status: valid.status, headers: noStore }); return jsonResponse(await TOOL_HANDLERS["ex.eei.audit.run"](args), { headers: noStore }); } if (url.pathname === "/schema") return jsonResponse(BUNDLED_SCHEMA); if (url.pathname === "/definitions") return jsonResponse(BUNDLED_DEFINITIONS); if (url.pathname === "/index") return jsonResponse(getIndex()); if (url.pathname === "/api/ai-jobs-signal") return handleAdsSignal(request, url, env); return textResponse("Not Found", { status: 404 }); } }; +function queryArgs(url, keys) { + return Object.fromEntries(keys.map((key) => [key, url.searchParams.get(key)]).filter(([, value]) => value)); +} + +function toolInventory() { + return DATA_TOOLS.map((tool) => ({ + id: tool.id, + title: tool.title, + description: tool.description, + endpoint: `${MCP_ORIGIN}${tool.route}`, + inputSchema: tool.inputSchema + })); +} + +function resourceInventory() { + return mcpResourceProjection().map((resource) => ({ + ...resource, + category: MCP_RESOURCES.find((candidate) => candidate.uri === resource.uri)?.category, + route: MCP_RESOURCES.find((candidate) => candidate.uri === resource.uri)?.route + })); +} + +function openApiParameter(name, schema = { type: "string" }) { + return { + name, + in: "query", + required: name === "url", + schema: name === "limit" ? { type: "integer", minimum: 1, maximum: 100 } : schema, + description: name + }; +} + +function capabilitiesDocument() { + return { + capability_version: "2.1", + entity: ENTITY, + mcp: { + endpoint: MCP_ORIGIN, + mcp_transport: MCP_TRANSPORT, + protocol_versions: MCP_PROTOCOL_VERSIONS, + registry: `${MCP_ORIGIN}/.well-known/tool-registry.json`, + openapi: `${MCP_ORIGIN}/.well-known/openapi.json` + }, + tools: toolInventory(), + resources: resourceInventory(), + content_links: CONTENT_LINKS, + federated_registries: FEDERATED_REGISTRIES, + positioning: { structured_outputs: true, deterministic_schema: true, machine_readable: true }, + last_updated: BUILD.released + }; +} + +function registryDocument() { + return { + registry_version: "2.1", + entity: ENTITY, + discovery: { + protocol: "MCP Streamable HTTP via official SDK and Cloudflare Workers handler", + endpoint: `${MCP_ORIGIN}/.well-known/tool-registry.json`, + mcp_transport: MCP_TRANSPORT, + protocol_versions: MCP_PROTOCOL_VERSIONS + }, + tools: toolInventory(), + resources: resourceInventory(), + content_links: CONTENT_LINKS, + federated_registries: FEDERATED_REGISTRIES, + last_updated: BUILD.released + }; +} + +function mcpDiscoveryDocument() { + return { + mcp_version: "1.0", + name: ENTITY.name, + description: ENTITY.description, + endpoint: MCP_ORIGIN, + mcp_transport: MCP_TRANSPORT, + protocol_versions: MCP_PROTOCOL_VERSIONS, + resources: resourceInventory().map((resource) => resource.uri), + last_updated: BUILD.released + }; +} + +function manifestDocument() { + return { + name: "exmxc MCP Manifest", + version: BUILD.version, + entity: ENTITY, + discovery: { root: MCP_ORIGIN, protocol: "MCP Streamable HTTP via Cloudflare Workers", mcp_transport: MCP_TRANSPORT, protocol_versions: MCP_PROTOCOL_VERSIONS }, + endpoints: { discovery: "/", mcp_transport: "/mcp", capabilities: "/capabilities.json", health: "/health", registry: "/.well-known/tool-registry.json", openapi: "/.well-known/openapi.json" }, + datasets: Object.values(DATASETS).map(({ id, route, displayName, description, category, schemaRoute }) => ({ id, route, displayName, description, category, schemaRoute })), + tools: toolInventory(), + resources: resourceInventory(), + content_links: CONTENT_LINKS, + last_updated: BUILD.released + }; +} + +function openApiDocument() { + const json200 = { description: "JSON response" }; + const toolPaths = Object.fromEntries(DATA_TOOLS.map((tool) => [ + tool.route, + { get: { summary: tool.title, description: tool.description, parameters: (tool.openApiParameters || []).map((parameter) => openApiParameter(parameter)), responses: { 200: json200 } } } + ])); + return { + openapi: "3.0.1", + info: { title: "exmxc REST and MCP API", version: BUILD.version, description: "REST/JSON intelligence API plus an MCP server using Streamable HTTP via the Cloudflare Workers handler." }, + servers: [{ url: MCP_ORIGIN }], + components: { securitySchemes: { AdsSignalBearer: { type: "http", scheme: "bearer" } } }, + paths: { + ...Object.fromEntries(Object.values(DATASETS).map((dataset) => [dataset.route, { get: { summary: `Retrieve ${dataset.displayName}`, responses: { 200: json200 } } }])), + ...toolPaths, + "/api/ai-jobs-signal": { + get: { summary: "ADS benchmark", responses: { 200: json200, 405: { description: "Signal generation requires POST" } } }, + post: { summary: "Paid ADS signal generation", security: [{ AdsSignalBearer: [] }], responses: { 200: json200, 400: { description: "Invalid body" }, 401: { description: "Unauthorized" }, 502: { description: "Upstream failed" }, 504: { description: "Upstream timeout" } } } + }, + "/mcp": { post: { summary: "MCP Streamable HTTP transport", responses: { 200: json200, 400: { description: "Bad MCP protocol version" }, 403: { description: "Origin forbidden" }, 405: { description: "Method not allowed" }, 406: { description: "Not acceptable" }, 415: { description: "Unsupported media type" } } } } + } + }; +} + +function jsonRpcError(id, code, message, headers = {}) { + return jsonResponse({ jsonrpc: "2.0", id: id ?? null, error: { code, message } }, { headers: { ...headers, "Cache-Control": CACHE.NO_STORE } }); +} + +function mediaAvailability(header) { + if (!header || !header.trim()) return { json: true, sse: false, normalize: true }; + let json = false; + let sse = false; + let wildcard = false; + for (const part of header.split(",")) { + const [rawType, ...params] = part.trim().toLowerCase().split(";").map((value) => value.trim()); + const unavailable = params.some((param) => /^q=0(?:\.0*)?$/.test(param)); + if (unavailable) continue; + if (rawType === "application/json") json = true; + if (rawType === "text/event-stream") sse = true; + if (rawType === "*/*") wildcard = true; + } + if (wildcard) json = true; + return { json, sse, normalize: wildcard || (json && !sse) }; +} + +function acceptPolicy(request) { + const availability = mediaAvailability(request.headers.get("Accept") || ""); + if (!availability.json) return { ok: false, normalize: false }; + if (availability.sse && !availability.json) return { ok: false, normalize: false }; + return { ok: true, normalize: availability.normalize }; +} + +async function handleMcp(request, env, ctx) { + const cors = mcpCorsHeaders(request, env); + const origin = request.headers.get("Origin"); + if (origin && !cors["Access-Control-Allow-Origin"]) return emptyResponse({ status: 403, headers: cors }); + if (request.method === "OPTIONS") return emptyResponse({ status: 204, headers: cors }); + if (request.method !== "POST") return emptyResponse({ status: 405, headers: { ...cors, Allow: "POST" } }); + + const contentType = (request.headers.get("Content-Type") || "").split(";")[0].trim().toLowerCase(); + if (contentType !== "application/json") return emptyResponse({ status: 415, headers: cors }); + + const accept = acceptPolicy(request); + if (!accept.ok) return emptyResponse({ status: 406, headers: cors }); + + const protocolVersion = request.headers.get("MCP-Protocol-Version"); + if (protocolVersion && !MCP_PROTOCOL_VERSIONS.includes(protocolVersion)) return emptyResponse({ status: 400, headers: cors }); + + const body = await request.text(); + try { + const payload = JSON.parse(body); + if (payload?.method === "tools/call" && !TOOL_IDS.has(payload?.params?.name)) { + return jsonRpcError(payload?.id, -32602, "Unknown tool", cors); + } + } catch { + // Let the SDK produce the JSON-RPC parse error; this guard only handles known parsed unknown tools. + } + + const headers = new Headers(request.headers); + if (accept.normalize) headers.set("Accept", JSON_SSE); + const normalizedRequest = new Request(request.url, { method: request.method, headers, body }); + const handler = createMcpHandler(createExmxcMcpServer(), { route: "/mcp", enableJsonResponse: true }); + const sdkResponse = await handler(normalizedRequest, env, ctx); + const responseHeaders = new Headers(sdkResponse.headers); + for (const [key, value] of Object.entries(cors)) responseHeaders.set(key, value); + responseHeaders.set("Cache-Control", CACHE.NO_STORE); + return new Response(sdkResponse.body, { status: sdkResponse.status, statusText: sdkResponse.statusText, headers: responseHeaders }); +} + +function unauthorized() { + return jsonResponse({ error: "Unauthorized" }, { status: 401, headers: { "Cache-Control": CACHE.NO_STORE, "Access-Control-Allow-Origin": "null" } }); +} + +function timeoutSignal(ms) { + if (typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function") return AbortSignal.timeout(ms); + const controller = new AbortController(); + setTimeout(() => controller.abort(), ms); + return controller.signal; +} + +async function handleAdsSignal(request, url, env) { + const provenance = { data_provenance: "synthetic-llm-generated", disclaimer: SYNTHETIC_DISCLAIMER }; + const noStore = { "Cache-Control": CACHE.NO_STORE }; + if (request.method === "GET") { + if (url.searchParams.get("mode") === "signal" || url.searchParams.has("query")) return jsonResponse({ error: "Signal generation requires POST." }, { status: 405, headers: noStore }); + return jsonResponse({ tool: "ai-jobs-signal", version: "1.0", mode: "benchmark", generated_at: BUILD.released, methodology: "https://exmxc.ai/frameworks/ads", ...provenance, data: baseline }); + } + if (request.method !== "POST") return jsonResponse({ error: "Method not allowed" }, { status: 405, headers: noStore }); + if (!env?.ADS_SIGNAL_KEY || request.headers.get("Authorization") !== `Bearer ${env.ADS_SIGNAL_KEY}`) return unauthorized(); + + const text = await request.text(); + if (new TextEncoder().encode(text).byteLength > ADS_BODY_LIMIT_BYTES) return jsonResponse({ error: "Request body too large" }, { status: 400, headers: noStore }); + + let body; + try { body = JSON.parse(text); } catch { return jsonResponse({ error: "Invalid JSON body" }, { status: 400, headers: noStore }); } + if (!body || typeof body !== "object" || Array.isArray(body)) return jsonResponse({ error: "Request body must be a JSON object" }, { status: 400, headers: noStore }); + const allowed = new Set(["query", "count"]); + if (Object.keys(body).some((key) => !allowed.has(key))) return jsonResponse({ error: "Unknown field" }, { status: 400, headers: noStore }); + const query = body.query; + const count = body.count; + if (typeof query !== "string" || query.length < 1 || query.length > 200 || !Number.isInteger(count) || count < 1 || count > 50) { + return jsonResponse({ error: "Invalid query or count" }, { status: 400, headers: noStore }); + } + + try { + // Paid ADS has two upstream calls: generation (20s budget) and classification (20s budget), for an overall documented budget of roughly 40s plus Worker overhead. + const genRes = await fetch("https://api.anthropic.com/v1/messages", { + method: "POST", + signal: timeoutSignal(ADS_GENERATION_TIMEOUT_MS), + headers: { "Content-Type": "application/json", "x-api-key": env.ANTHROPIC_API_KEY, "anthropic-version": "2023-06-01" }, + body: JSON.stringify({ model: "claude-sonnet-4-20250514", max_tokens: 1000, messages: [{ role: "user", content: `Generate ${count} AI job postings for query: ${query}` }] }) + }); + if (!genRes.ok) return jsonResponse({ error: "ADS upstream failed" }, { status: 502, headers: noStore }); + const generatedPayload = await genRes.json(); + const postings = JSON.parse(generatedPayload?.content?.[0]?.text || "[]"); + const normalized = Array.isArray(postings) ? postings.map((posting, index) => ({ posting_id: posting?.posting_id || `synthetic-${index + 1}`, title: posting?.title || "", skills_raw: Array.isArray(posting?.skills_raw) ? posting.skills_raw : [] })) : []; + const classified = await classifyPostings(normalized, env.ANTHROPIC_API_KEY, { signal: timeoutSignal(ADS_CLASSIFICATION_TIMEOUT_MS) }); + return jsonResponse({ tool: "ai-jobs-signal", version: "1.0", mode: "signal", query, requested_count: count, generated_count: normalized.length, prior_count: baseline.sample_size, ...provenance, metrics: computeADS(classified, normalized.length, baseline.sample_size), classified }, { headers: noStore }); + } catch (error) { + const status = error instanceof ADSUpstreamError ? error.status : (error?.name === "AbortError" || error?.name === "TimeoutError" ? 504 : 502); + return jsonResponse({ error: status === 504 ? "ADS upstream timed out" : "ADS upstream failed" }, { status, headers: noStore }); + } +} + +function pluginDocument() { + return { + schema_version: "v1", + name_for_human: "exmxc", + name_for_model: "exmxc", + description_for_human: "exmxc institutional intelligence system decoding AI power structures, entity clarity, and Applied Capital Architecture.", + description_for_model: "Provides institutional intelligence datasets and REST endpoints. This legacy plugin manifest is not part of the MCP protocol.", + auth: { type: "none" }, + api: { type: "openapi", url: `${MCP_ORIGIN}/.well-known/openapi.json`, is_user_authenticated: false }, + logo_url: "https://exmxc.ai/favicon.ico", + contact_email: "support@exmxc.ai", + legal_info_url: ENTITY.domain + }; +} + +export default { + async fetch(request, env, ctx) { + const url = new URL(request.url); + if (url.pathname === "/mcp") return handleMcp(request, env, ctx); + if (request.method === "OPTIONS") return emptyResponse({ status: 204 }); + + const discoveryHeaders = { "Cache-Control": CACHE.NO_CACHE }; + const noStore = { "Cache-Control": CACHE.NO_STORE }; + if (url.pathname === "/.well-known/mcp.json") return jsonResponse(mcpDiscoveryDocument(), { headers: discoveryHeaders }); + if (url.pathname === "/" || url.pathname === "") return jsonResponse({ name: "exmxc MCP Endpoint", entity: { name: ENTITY.name, domain: ENTITY.domain, founder: ENTITY.founder }, registry: `${MCP_ORIGIN}/.well-known/tool-registry.json`, openapi: `${MCP_ORIGIN}/.well-known/openapi.json`, manifest: `${MCP_ORIGIN}/.well-known/manifest.json`, capabilities: `${MCP_ORIGIN}/capabilities.json`, mcp_transport: MCP_TRANSPORT, protocol_versions: MCP_PROTOCOL_VERSIONS, tools: toolInventory(), resources: resourceInventory().map((resource) => resource.uri), health: `${MCP_ORIGIN}/health`, status: "active", discovery_protocol: "MCP Streamable HTTP", last_updated: BUILD.released }, { headers: discoveryHeaders }); + if (url.pathname === "/capabilities.json") return jsonResponse(capabilitiesDocument(), { headers: discoveryHeaders }); + if (url.pathname === "/health") return jsonResponse({ entity: ENTITY.name, status: "healthy", mcp_status: "not_checked", registry_status: "not_checked", plugin_status: "not_checked", openapi_status: "not_checked", uptime: null, infrastructure: { platform: "Cloudflare Workers", protocol: "MCP Streamable HTTP" }, last_checked: new Date().toISOString() }, { headers: noStore }); + if (url.pathname === "/.well-known/tool-registry.json") return jsonResponse(registryDocument(), { headers: discoveryHeaders }); + if (url.pathname === "/.well-known/openapi.json") return jsonResponse(openApiDocument(), { headers: discoveryHeaders }); + if (url.pathname === "/.well-known/manifest.json") return jsonResponse(manifestDocument(), { headers: discoveryHeaders }); + if (url.pathname === "/.well-known/ai-plugin.json") return jsonResponse(pluginDocument(), { headers: discoveryHeaders }); + if (url.pathname === "/speg") return jsonResponse(getSpeg(queryArgs(url, ["sector", "scarcity_layer", "ticker"]))); + if (url.pathname === "/entities") return jsonResponse(getEntities(queryArgs(url, ["industry", "entity_type", "posture", "capability"]))); + if (url.pathname === "/datasets/ai_power_index") return jsonResponse(DATASETS.ai_power_index.data); + if (url.pathname === "/datasets/ai_power_index/schema") return jsonResponse(DATASETS.ai_power_index.schema); + if (url.pathname === "/datasets/four_forces") return jsonResponse(getFourForces()); + if (url.pathname === "/datasets/entity_in_a_box" || url.pathname === "/datasets/entity_in_a_box_v1") return jsonResponse(DATASETS.entity_in_a_box.data); + if (url.pathname === "/datasets") return jsonResponse(getDatasetIndex()); + if (url.pathname === "/analysis/ai_power/top") return jsonResponse(getAiPowerTop(queryArgs(url, ["limit"]))); + if (url.pathname === "/datasets/convergence_monitor") return jsonResponse(DATASETS.convergence_monitor.data); + if (url.pathname === "/convergence/latest") return jsonResponse(getConvergenceLatest()); + if (url.pathname === "/convergence/log") return jsonResponse(getConvergenceLog(queryArgs(url, ["limit"]))); + if (url.pathname === "/audit/run") { + const args = queryArgs(url, ["url"]); + const valid = validateAuditTarget(args.url); + if (!valid.ok) return jsonResponse({ success: false, error: valid.error }, { status: valid.status, headers: noStore }); + return jsonResponse(await TOOL_HANDLERS["ex.eei.audit.run"](args), { headers: noStore }); + } + if (url.pathname === "/schema") return jsonResponse(BUNDLED_SCHEMA); + if (url.pathname === "/definitions") return jsonResponse(BUNDLED_DEFINITIONS); + if (url.pathname === "/index") return jsonResponse(getIndex()); + if (url.pathname === "/api/ai-jobs-signal") return handleAdsSignal(request, url, env); + if (url.pathname === "/__test/content-index") return jsonResponse(contentIndexResource(), { headers: noStore }); + return textResponse("Not Found", { status: 404 }); + } +}; diff --git a/wrangler.jsonc b/wrangler.jsonc index 613df5a..f0bc534 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -5,7 +5,6 @@ "routes": [ "mcp.exmxc.ai/*" ], - "observability": { "enabled": true, "logs": { @@ -14,5 +13,8 @@ "head_sampling_rate": 1, "persist": true } - } + }, + "compatibility_flags": [ + "nodejs_compat" + ] } From 940adb7a5997981c36251ac169ad86eab314b6c6 Mon Sep 17 00:00:00 2001 From: Trailgenic Date: Wed, 15 Jul 2026 17:33:09 -0700 Subject: [PATCH 3/3] fix: validated dependency set, real lockfile, resource resolver parity, workerd-safe drift check --- lib/mcp-server.js | 4 +- lib/registry.js | 3 +- package-lock.json | 5208 ++++++++++++++++++++++++++++++++++++++- package.json | 16 +- tests/worker.vitest.mjs | 2 +- vitest.config.mjs | 10 +- 6 files changed, 5224 insertions(+), 19 deletions(-) diff --git a/lib/mcp-server.js b/lib/mcp-server.js index 2794453..f656e0b 100644 --- a/lib/mcp-server.js +++ b/lib/mcp-server.js @@ -2,7 +2,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import { BUILD, CONTENT_LINKS, DATA_TOOLS, ENTITY, MCP_PROTOCOL_VERSIONS, MCP_RESOURCES } from "./registry.js"; -import { getDatasetIndex, getIndex, TOOL_HANDLERS } from "./queries.js"; +import { getDatasetIndex, getEntities, getIndex, getSpeg, TOOL_HANDLERS } from "./queries.js"; export const TOOL_IDS = new Set(DATA_TOOLS.map((tool) => tool.id)); @@ -94,7 +94,7 @@ export function resolveMcpResource(uri) { if (uri === "exmxc://content/index") return contentIndexResource(); const resource = MCP_RESOURCES.find((candidate) => candidate.uri === uri); if (!resource) return null; - if (resource.resolver === "index") return getIndex(); + if (resource.resolver === "index") return getIndex(); if (resource.resolver === "entities") return getEntities({}); if (resource.resolver === "speg") return getSpeg({}); if (resource.data) return resource.data; return null; } diff --git a/lib/registry.js b/lib/registry.js index 26c762e..d78dfe7 100644 --- a/lib/registry.js +++ b/lib/registry.js @@ -234,7 +234,8 @@ export const MCP_RESOURCES = [ mimeType: "application/json", category: dataset.category, route: dataset.route, - data: dataset.data, + resolver: dataset.id === "entities" ? "entities" : dataset.id === "speg" ? "speg" : undefined, + data: dataset.id === "entities" || dataset.id === "speg" ? undefined : dataset.data, includeInDiscovery: true })), ...SCHEMA_RESOURCES, diff --git a/package-lock.json b/package-lock.json index e27515b..0f979a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,15 +8,5211 @@ "name": "exmxc-workers", "version": "2.3.0", "dependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", - "agents": "^0.0.117", + "@modelcontextprotocol/sdk": "1.29.0", + "agents": "0.17.4", "ajv": "^8.17.1", - "zod": "^3.25.76" + "zod": "^4.4.3" }, "devDependencies": { - "@cloudflare/vitest-pool-workers": "^0.8.69", - "vitest": "^3.2.4", - "wrangler": "^4.24.3" + "@cloudflare/vitest-pool-workers": "^0.18.4", + "@vitest/runner": "^4.1.10", + "@vitest/snapshot": "^4.1.10", + "vitest": "^4.1.10", + "wrangler": "^4.110.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-8.0.0.tgz", + "integrity": "sha512-dYYg153EyN2Ekbqw2zAsbd6/JR+9N2SEoC7YV2GyyqMM7x9bLDTjBD6XBhSMLH0wtIVyJj03jWNriQhaN+eoCw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^8.0.0", + "js-tokens": "^10.0.0" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-8.0.0.tgz", + "integrity": "sha512-DOjnob/cXOUgDOozCDeq/aK2p5y8dUIVdf6tNhEV1HQRd6I8aQ4f4fbtHRVEvb6lP3BGomrKHiS8ICAASSVQSw==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/core": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-8.0.1.tgz", + "integrity": "sha512-5FgxM4dLQpMJHSiVATk8foW263dVHQHBVpXYiimNECVWG01f4nFyEbQixeT6Mwvg7TayREJ2gpKl3o2RoMdnqw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^8.0.0", + "@babel/generator": "^8.0.0", + "@babel/helper-compilation-targets": "^8.0.0", + "@babel/helpers": "^8.0.0", + "@babel/parser": "^8.0.0", + "@babel/template": "^8.0.0", + "@babel/traverse": "^8.0.0", + "@babel/types": "^8.0.0", + "@types/gensync": "^1.0.5", + "convert-source-map": "^2.0.0", + "empathic": "^2.0.1", + "gensync": "^1.0.0-beta.2", + "import-meta-resolve": "^4.2.0", + "json5": "^2.2.3", + "obug": "^2.1.1", + "semver": "^7.7.3" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-8.0.0.tgz", + "integrity": "sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^8.0.0", + "@babel/types": "^8.0.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "@types/jsesc": "^2.5.0", + "jsesc": "^3.0.2" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-8.0.0.tgz", + "integrity": "sha512-NSpMkMsvvZqzThJ0p1B02cbtA2ObEyfBvq950bmNkyxsxvcxwhvvCB036rKhlEnuBBo30bOrk13u3FzlKSoRrw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^8.0.0" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-8.0.0.tgz", + "integrity": "sha512-JwculLABZvyPvyLBpwU/E/IbH2uM3mnxNtIJpxnIfb24y1PrdVxK5Dqjle4DpgqpGRnwgC7G8IkzPdSXZrO1Ew==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/compat-data": "^8.0.0", + "@babel/helper-validator-option": "^8.0.0", + "browserslist": "^4.24.0", + "lru-cache": "^11.0.0", + "semver": "^7.7.3" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-8.0.1.tgz", + "integrity": "sha512-++t3ZktzlLmASAxIlxeXQK9Z2YwUafYGYcvGBFevqOqt16HozVHStUoQvWD09fzAZOb/uJGpUTBuGK41AJAuOA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^8.0.0", + "@babel/helper-member-expression-to-functions": "^8.0.0", + "@babel/helper-optimise-call-expression": "^8.0.0", + "@babel/helper-replace-supers": "^8.0.1", + "@babel/helper-skip-transparent-expression-wrappers": "^8.0.0", + "@babel/traverse": "^8.0.0", + "semver": "^7.7.3" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + }, + "peerDependencies": { + "@babel/core": "^8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-8.0.0.tgz", + "integrity": "sha512-lLozHOM6sWWlxNo8CYqHy4MBZeTvHXNgVPBfPOGsjPKUzHC2Az9QwB6gxdQmpwHl6GlQtbGgS+lj5887guDiLw==", + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-8.0.0.tgz", + "integrity": "sha512-xkXrMbtk87Gk7+oKBVmBc6EORg/Qwx++AHESldmHkpvG8wgccdhJJFwrzqlF382Fk8wfXhJHWE/g/43QvEGNPQ==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^8.0.0", + "@babel/types": "^8.0.0" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-8.0.0.tgz", + "integrity": "sha512-3W6satvtPuCUkUx63S2jMoW9EQNYkADgs1HTfufmL7gCmAulHMKupA/12WNz4A0GMMFn/YnWWwqOT9IZrJHQjg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^8.0.0" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-8.0.1.tgz", + "integrity": "sha512-3PKFgjTyPlhFhorfP+SjKQxLViIL++zWjFOO4hGriYU+Bsm983DxEM1JmDRJVWXV0O9npu+xXRqz7Pbd3mh70g==", + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + }, + "peerDependencies": { + "@babel/core": "^8.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-8.0.1.tgz", + "integrity": "sha512-B1SZADIcy3tmH8CmWvj4SHi/oAPom4UL3uknTc2QRNsPVLFk/sPnZvQL/8kj7Y5omvjMqie0vklvs6XM4OLW5Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^8.0.0", + "@babel/helper-optimise-call-expression": "^8.0.0", + "@babel/traverse": "^8.0.0" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + }, + "peerDependencies": { + "@babel/core": "^8.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-8.0.0.tgz", + "integrity": "sha512-xmCA9kP3IhySsqhzwIdWGlDN/1A4cCKNBO/uwZx/3YzmDoMePwno2Q5/Bq0q+tYaKbeF940YiKV/kaW8Mzvpjw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^8.0.0", + "@babel/types": "^8.0.0" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz", + "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==", + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz", + "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==", + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-8.0.0.tgz", + "integrity": "sha512-U4Dybxh4WESWHt5XhBeExi4DrY0/DNK1aHpQbsrQXCUbFHuMweT0TpLEWKvaraV2Y6fS+ZXunsZ8zIuZIgvF2Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helpers": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-8.0.0.tgz", + "integrity": "sha512-wfbi91pM3py96oIiJEz7qIpyXDytgr9zQC1HEWwlGNVRAEmItuU/0a41ZUKu1sJGyhhOIpc4t5vk4PYzt8wpsg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/template": "^8.0.0", + "@babel/types": "^8.0.0" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/parser": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.4.tgz", + "integrity": "sha512-srpptsAkEbbNIC/q8nT7o+m6CQe8CJUTV/t7MYc9NnWlgYVtHOb7JH6SorxMhN0kuRJjVqXbKClG6xSbPtzz+g==", + "license": "MIT", + "dependencies": { + "@babel/types": "^8.0.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-8.0.2.tgz", + "integrity": "sha512-+C6O6KKXU7BBq1GNaIkFJxrALUVGRcr+WeWm4OcuRl3h+l/CmNfcTLMrT2Lm3uvGBimBH/8pEBRrXJFLoO67Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^8.0.1", + "@babel/helper-plugin-utils": "^8.0.1", + "@babel/plugin-syntax-decorators": "^8.0.1" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + }, + "peerDependencies": { + "@babel/core": "^8.0.0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-8.0.1.tgz", + "integrity": "sha512-NI+0S/6MvR6GlcQFwjDZ+WIc2qvG6TXN534lYs9llNldwW4b7Dh6KTtk030FA0xWdYGs4t1lWo+OEWN8wGB+Nw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^8.0.1" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + }, + "peerDependencies": { + "@babel/core": "^8.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.29.7.tgz", + "integrity": "sha512-ppj9ouYku+RX0ljtgZd+KMO5mkM2bCqg8H2PYAFWnLsHEIKIdRojqbJ2i3eVHrisuxy7nOFCmngTDdWtUCdXUQ==", + "license": "MIT", + "dependencies": { + "core-js-pure": "^3.48.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-8.0.0.tgz", + "integrity": "sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^8.0.0", + "@babel/parser": "^8.0.0", + "@babel/types": "^8.0.0" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/traverse": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-8.0.4.tgz", + "integrity": "sha512-bZnmqzGG8UZneG1lLxBoWIH0G6Gr1D846Yu4/3XnY6FhCndMR49u26nTY08u/dAxWmLWF9vGQOuC+84FfIUoeg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^8.0.0", + "@babel/generator": "^8.0.0", + "@babel/helper-globals": "^8.0.0", + "@babel/parser": "^8.0.4", + "@babel/template": "^8.0.0", + "@babel/types": "^8.0.4", + "obug": "^2.1.1" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/types": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.4.tgz", + "integrity": "sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^8.0.0", + "@babel/helper-validator-identifier": "^8.0.4" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@cfworker/json-schema": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@cfworker/json-schema/-/json-schema-4.1.1.tgz", + "integrity": "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==", + "license": "MIT" + }, + "node_modules/@cloudflare/codemode": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@cloudflare/codemode/-/codemode-0.4.3.tgz", + "integrity": "sha512-S6LIqj/NnmFRFxm3j0tPEGMF8HQF5DpV7sQg/W+U48YmnznTKOBcbS8eiV7SxBpIITLuMBcL4KpTDm1RDL20pA==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.15", + "acorn": "^8.17.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.25.0", + "@tanstack/ai": ">=0.8.0 <1.0.0", + "ai": "^6.0.0", + "zod": "^4.0.0" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + }, + "@tanstack/ai": { + "optional": true + }, + "ai": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/@cloudflare/kv-asset-handler": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.5.0.tgz", + "integrity": "sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==", + "dev": true, + "license": "MIT OR Apache-2.0", + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@cloudflare/unenv-preset": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.16.1.tgz", + "integrity": "sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==", + "dev": true, + "license": "MIT OR Apache-2.0", + "peerDependencies": { + "unenv": "2.0.0-rc.24", + "workerd": ">1.20260305.0 <2.0.0-0" + }, + "peerDependenciesMeta": { + "workerd": { + "optional": true + } + } + }, + "node_modules/@cloudflare/vitest-pool-workers": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/@cloudflare/vitest-pool-workers/-/vitest-pool-workers-0.18.5.tgz", + "integrity": "sha512-Qe00zuHDRyAsOO7DmHnPcOhCiShdkt/NlRf/GrnKHzuXuysmt5YVyU/WaMVPqEkPYrgO+H9bSEJ1c9/7Nbw1Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cjs-module-lexer": "1.2.3", + "esbuild": "0.28.1", + "miniflare": "4.20260710.0", + "wrangler": "4.111.0", + "zod": "3.25.76" + }, + "peerDependencies": { + "@vitest/runner": "^4.1.0", + "@vitest/snapshot": "^4.1.0", + "vitest": "^4.1.0" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@cloudflare/workerd-darwin-64": { + "version": "1.20260710.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260710.1.tgz", + "integrity": "sha512-OqJl2eWF5+y9jarMm3YqqCTUe7Hd4ihogX5jyRU8iaAgOVyDr/Bk6aXpPCVUi1/MHzO93a18R/TmSTtzmB0sQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-darwin-arm64": { + "version": "1.20260710.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260710.1.tgz", + "integrity": "sha512-MYBqWgUblO+VlGvO73zYsH3hB9tdRj+yLyt5IHDFWryipb2l1efmNiWtAOkIhSRfypqLYGFrfpaDm2Hg00XVKw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-64": { + "version": "1.20260710.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260710.1.tgz", + "integrity": "sha512-lVWUgqI8qrkqvaCBGElu1kdaUFdAvaS2RD8K4qkCFP9hI3f5TCXumEs5qWSeZkvKum0+X/uJZ5hBFWsYI5SmoQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-arm64": { + "version": "1.20260710.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260710.1.tgz", + "integrity": "sha512-kDwDPItBjAI4JL0df9Fma2N+Qggbm77IB/DnroAkEGQ79fpR80sYMyuB/ZQKyjEk9f48Ocq7HCCLq59qVSyNqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-windows-64": { + "version": "1.20260710.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260710.1.tgz", + "integrity": "sha512-GcLHy1oN1dfK6g1Z7UDV9f5xMGyTfPwcjWQ0sfWKH31IsoEVCRapnj3IC0PoIrDbnoo6irGPP0CwVs3WzdTajw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workers-types": { + "version": "5.20260715.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-5.20260715.1.tgz", + "integrity": "sha512-saxo/nMqQJ1dKDUXp1a2y/+IjKENFVD9+QRefHg5EjJZY20OG3xcEge4PGljbqZiF3AiU4o5ZLS3Vm7cayQIxg==", + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "peer": true + }, + "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, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/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, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@emnapi/core": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", + "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "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.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "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.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "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.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "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.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "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-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "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-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "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.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "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.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "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.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "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.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "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-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "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.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "license": "MIT", + "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/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.140.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.140.0.tgz", + "integrity": "sha512-h5LUOzGArYemnW1NMz/DuuQhBi96J6JL2Bk8zE4kvqxB5Sg3jxmCiH4uyOWHDkiKSt5vWlG4FIwCR/DbstcNRQ==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@poppinss/colors": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz", + "integrity": "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^4.1.5" + } + }, + "node_modules/@poppinss/dumper": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.5.tgz", + "integrity": "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@poppinss/colors": "^4.1.5", + "@sindresorhus/is": "^7.0.2", + "supports-color": "^10.0.0" + } + }, + "node_modules/@poppinss/exception": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.3.tgz", + "integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.0.tgz", + "integrity": "sha512-9yB1l95IrJuNGDFdOYe79vdApdz6WWBCObE+rQ2LUliYUlcyFwSYIb2xb5/Ifw7dAtMy2ZqNyd8QTSOc7duAKw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.0.tgz", + "integrity": "sha512-pexNaW9ACLUOaBITOpU6qVu4VrsOFIjTv6bzgu0YUATo4eUJx0V605PxwZfndpPOn0ilqGqvGQ0M8UW0IE24jg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.0.tgz", + "integrity": "sha512-NqKYaq0355ZmNMG4QGpxtEDxsc7tGDhjhCm4PpE0cwnBW+5Il95LJyq414niEiaKLVjnVHBEjSo1wngKxJNiFw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.0.tgz", + "integrity": "sha512-3vPoHzh6eBTz9IbB0/qZdSr0Qeks2echn+I4cHu2joV74VriPDdldswksEDzrl1mBB+oPRi+67+3Ib59paxIPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.0.tgz", + "integrity": "sha512-E6NNefZ1bUVmKJq2tJkf45J4Zyczj7qm9rUT7NY+Xo2474Y13qWAwc2tvBt0BAVbmtXR1llkxXg0Ou1jbDf2SQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.0.tgz", + "integrity": "sha512-D+TgkdgM1vu+7/Fpf8+v0ARW+RXEP9Ccazgm8zQ4JFFd9Q7SrYQ2TakU5S5ihazQDgpKyAgZDOcIFsvoHmTZ8w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.0.tgz", + "integrity": "sha512-wUqdwJBbAv0APN87GecstdMUtLjjNTs0hBALpxETD73mccFxdmt/XeizXDtN5RAlBwNKmI+Tg+blect2G+8IeQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.0.tgz", + "integrity": "sha512-9DtF35qR9/NrfhM4oxLplCzVVjE+KKm8Pjemi0i/sdhAWkUasjmSo8WTTubNJClhSHCfyk2yeyoXDQEDPtDAAw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.0.tgz", + "integrity": "sha512-RzuHrBh8X8Hntd2N4VR02QGEciq/9JhcZoTpR/Cee6otRrlILGCf3cg2ygHuih+ZebUnWmMrDX6ITI85btO6rQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.0.tgz", + "integrity": "sha512-MK7L0018jjh1jR3mh21G2j1zAVcpscJBlPo2z19pRjv2XOYGRhaV4LyiD8HO6nCDdZln9IFgCMIV5yt4E3klGQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.0.tgz", + "integrity": "sha512-gyrxLQ9NfGb/9LoVnC4kb9miUghw1mghnkfYvNHSnVIXriabnfgGPUP4RLcJm87q3KgYz4FYUG8IDiWUT+CpSw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.0.tgz", + "integrity": "sha512-/6VFMQGRmrhP77KXDC+StIxGzcNp5JOIyYtw0CQ8gPlzhpiIRucYfoM5FaFamHd5BJYIdH86yfP46l1p3WdrFA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.2.0.tgz", + "integrity": "sha512-rwdbUL465kisF24WEJLvP3JrEG6E5GRuIHt5wpMwHGERtHe4Wm2CIvtf5gTBgr2tGOHKh5NdKEAFS2VkOPE91g==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emnapi/core": "1.11.2", + "@emnapi/runtime": "1.11.2", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.0.tgz", + "integrity": "sha512-+5suHwRiKGmhwyUaNT8a5QbrBvLFh2DbO910TEmGRH1aSxwrCezodvGQnulv4uiWEIv1Kq4ypRsJ5+O+ry1DiA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.0.tgz", + "integrity": "sha512-WfFv6/qGufotqBSBzBYwgpCkJBk8Nj7697LL9vTz/XWc67e0r3oewu8iMRwQj3AUL45GVD7wVsPjCsAAtW66Wg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/plugin-babel": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/plugin-babel/-/plugin-babel-0.2.3.tgz", + "integrity": "sha512-+zEk16yGlz1F9STiRr6uG9hmIXb6nprjLczV/htGptYuLoCuxb+itZ03RKCEeOhBpDDd1NU7qF6x1VLMUp62bw==", + "license": "MIT", + "dependencies": { + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=22.12.0 || ^24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.29.0 || ^8.0.0-rc.1", + "@babel/plugin-transform-runtime": "^7.29.0 || ^8.0.0-rc.1", + "@babel/runtime": "^7.27.0 || ^8.0.0-rc.1", + "rolldown": "^1.0.0-rc.5", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@babel/plugin-transform-runtime": { + "optional": true + }, + "@babel/runtime": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz", + "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@speed-highlight/core": { + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.17.tgz", + "integrity": "sha512-Z92FwKpCtfaW1V0jTU/fh3QzYEZN8wDwrzRIBoADCJfn4mJCNcJN/XegifX7BDrQ8/h9Xh/JnbyMchL0FqXrkg==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/gensync": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/gensync/-/gensync-1.0.5.tgz", + "integrity": "sha512-MbsRCT7mTikHwKZ0X+LVUTLRrZZRLipTuXEO9qOYO+zmjMVk81axyClMROf6uoPD9MRVu46bx8zoR0Ad9q3NAg==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/jsesc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@types/jsesc/-/jsesc-2.5.1.tgz", + "integrity": "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@vitest/expect": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.10", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.10", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agents": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/agents/-/agents-0.17.4.tgz", + "integrity": "sha512-K6YRbpD3VcwdTOPBlDgI4dILAwkhXo5cdxTlVF0IvUwQEKfMPawmH8E/QMXTN8CPGHqVYgYFACxTyk6nKlK+vg==", + "license": "MIT", + "dependencies": { + "@babel/plugin-proposal-decorators": "^8.0.2", + "@cfworker/json-schema": "^4.1.1", + "@cloudflare/codemode": "^0.4.3", + "@modelcontextprotocol/sdk": "1.29.0", + "@rolldown/plugin-babel": "^0.2.3", + "cron-schedule": "^6.0.0", + "esbuild": "^0.28.1", + "mimetext": "^3.0.28", + "nanoid": "^5.1.16", + "partyserver": "^0.5.8", + "partysocket": "1.3.0", + "yaml": "^2.9.0", + "yargs": "^18.0.0" + }, + "bin": { + "agents": "dist/cli/index.js" + }, + "peerDependencies": { + "@ai-sdk/react": "^3.0.204", + "@tanstack/ai": ">=0.10.2 <1.0.0", + "@x402/core": "^2.0.0", + "@x402/evm": "^2.0.0", + "ai": "^6.0.0", + "chat": "^4.29.0", + "just-bash": "^3.0.0", + "react": "^19.0.0", + "vite": ">=6.0.0 <9.0.0", + "zod": "^4.0.0" + }, + "peerDependenciesMeta": { + "@ai-sdk/react": { + "optional": true + }, + "@tanstack/ai": { + "optional": true + }, + "@x402/core": { + "optional": true + }, + "@x402/evm": { + "optional": true + }, + "ai": { + "optional": true + }, + "chat": { + "optional": true + }, + "just-bash": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/agents/node_modules/@cloudflare/workers-types": { + "version": "4.20260702.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260702.1.tgz", + "integrity": "sha512-mOhf5TUEB1m2vPrxtqoIGfz0fUC9xyxRDx5gWHy5s+OCo6dcV+g7wI1R7gYCMFohhqF/2y2xeKVwMwCJjfn/WA==", + "license": "MIT OR Apache-2.0", + "peer": true + }, + "node_modules/agents/node_modules/partyserver": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/partyserver/-/partyserver-0.5.8.tgz", + "integrity": "sha512-htgSwiBcBu9zIYLrsxBAOvdkjukHvncbTk0nDrJgfruvZ08rxtEN1Ab4T7j9osykP80Bq3zA2oWFd3ngc4Z9uw==", + "license": "ISC", + "dependencies": { + "nanoid": "^5.1.9" + }, + "peerDependencies": { + "@cloudflare/workers-types": "^4.20260424.1" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.43", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.43.tgz", + "integrity": "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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, + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/browserslist": { + "version": "4.28.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.6.tgz", + "integrity": "sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.10.42", + "caniuse-lite": "^1.0.30001803", + "electron-to-chromium": "^1.5.389", + "node-releases": "^2.0.51", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "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/caniuse-lite": { + "version": "1.0.30001805", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001805.tgz", + "integrity": "sha512-52noaS3DubycKSXaU30TwPGIp+POyQSUVa5jBEq3vkRkY0kjyb3LQgvhU6WGyCcyXqVLWO0Cw0Q6BSdD0kUfVA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0", + "peer": true + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/core-js-pure": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.49.0.tgz", + "integrity": "sha512-XM4RFka59xATyJv/cS3O3Kml72hQXUeGRuuTmMYFxwzc9/7C8OYTaIR/Ji+Yt8DXzsFLNhat15cE/JP15HrCgw==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cron-schedule": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cron-schedule/-/cron-schedule-6.0.0.tgz", + "integrity": "sha512-BoZaseYGXOo5j5HUwTaegIog3JJbuH4BbrY9A1ArLjXpy+RWb3mV28F/9Gv1dDA7E2L8kngWva4NWisnLTyfgQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": 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==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.392", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.392.tgz", + "integrity": "sha512-1yQq3VQCZRwsnYc67Oc+1fge6Lwtn0hzi6zmEVkB61Zx21kTbwJAW4dFLadl5Rc1tKhG/kSpYXnfiAhu0f0a1g==", + "license": "ISC", + "peer": true + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/empathic": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.1.tgz", + "integrity": "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/error-stack-parser-es": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", + "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "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==", + "license": "MIT" + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.0.tgz", + "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "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.5.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", + "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "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, + "license": "MIT", + "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==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.12.30", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.30.tgz", + "integrity": "sha512-emn+JoJjrN9YTpRDS5it/UI2SO9BAE37T6I3d963RxcZ81G9A4pr2SZTEiiaiKbzx+NKRg5BZ89fCL7gCJCUog==", + "license": "MIT", + "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==", + "license": "MIT", + "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.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jose": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-base64": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.9.1.tgz", + "integrity": "sha512-U73qptcvf/HIOauFOmqT3a0mDUp0MYlfd15oqoe9kqZt5XhiXVb+HG09sLvI9PQ9tZIBFS4nlErai8zbWazP0g==", + "license": "BSD-3-Clause" + }, + "node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "license": "MIT" + }, + "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==", + "license": "BSD-2-Clause" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "devOptional": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "license": "BlueOak-1.0.0", + "peer": true, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/mimetext": { + "version": "3.0.28", + "resolved": "https://registry.npmjs.org/mimetext/-/mimetext-3.0.28.tgz", + "integrity": "sha512-eQXpbNrtxLCjUtiVbR/qR09dbPgZ2o+KR1uA7QKqGhbn8QV7HIL16mXXsobBL4/8TqoYh1us31kfz+dNfCev9g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@babel/runtime-corejs3": "^7.26.0", + "js-base64": "^3.7.7", + "mime-types": "^2.1.35" + }, + "funding": { + "type": "patreon", + "url": "https://patreon.com/muratgozel" + } + }, + "node_modules/mimetext/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimetext/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/miniflare": { + "version": "4.20260710.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260710.0.tgz", + "integrity": "sha512-x1LLRkU6o1p7hiKrB0TRnL0MJn6xFOT+/vrlEQINz5cRDKLP8ru4hBqWTIvXAetzr1acKAnmAaG84pQ4W/K14g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "0.8.1", + "sharp": "0.34.5", + "undici": "7.28.0", + "workerd": "1.20260710.1", + "ws": "8.21.0", + "youch": "4.1.0-beta.10" + }, + "bin": { + "miniflare": "bootstrap.js" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "5.1.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.16.tgz", + "integrity": "sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-releases": { + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obug": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.3.tgz", + "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "ISC", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/partysocket": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/partysocket/-/partysocket-1.3.0.tgz", + "integrity": "sha512-1zToNyolZFK/7nuAw/K2bZrNzFqaZyRoCEkS+9vG6WSC5ikrN6qWRe96q6ImU51uptz2r+dAwSkwhJVdQi4LiA==", + "license": "MIT", + "dependencies": { + "event-target-polyfill": "^0.0.4" + }, + "peerDependencies": { + "react": ">=17" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/postcss": { + "version": "8.5.19", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.19.tgz", + "integrity": "sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==", + "devOptional": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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==", + "license": "MIT", + "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.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rolldown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.0.tgz", + "integrity": "sha512-u7tgm5l4Yw1iTqUL4EcYOAt7fFvCgQMLeidrnD4GALlC6aOznCjezYajgxeyKw27u0Q5N7fwgCzjVyPIWzwuBA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@oxc-project/types": "=0.140.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.2.0", + "@rolldown/binding-darwin-arm64": "1.2.0", + "@rolldown/binding-darwin-x64": "1.2.0", + "@rolldown/binding-freebsd-x64": "1.2.0", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.0", + "@rolldown/binding-linux-arm64-gnu": "1.2.0", + "@rolldown/binding-linux-arm64-musl": "1.2.0", + "@rolldown/binding-linux-ppc64-gnu": "1.2.0", + "@rolldown/binding-linux-s390x-gnu": "1.2.0", + "@rolldown/binding-linux-x64-gnu": "1.2.0", + "@rolldown/binding-linux-x64-musl": "1.2.0", + "@rolldown/binding-openharmony-arm64": "1.2.0", + "@rolldown/binding-wasm32-wasi": "1.2.0", + "@rolldown/binding-win32-arm64-msvc": "1.2.0", + "@rolldown/binding-win32-x64-msvc": "1.2.0" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "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==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "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==", + "license": "ISC" + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.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==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "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.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "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/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "0BSD", + "optional": true + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/undici": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", + "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/unenv": { + "version": "2.0.0-rc.24", + "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz", + "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.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==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "8.1.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.4.tgz", + "integrity": "sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.16", + "rolldown": "~1.1.4", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.3.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/vite/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/vite/node_modules/@oxc-project/types": { + "version": "0.139.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", + "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", + "devOptional": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-android-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", + "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", + "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-darwin-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", + "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", + "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", + "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", + "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", + "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", + "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", + "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", + "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", + "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", + "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", + "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", + "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", + "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/rolldown": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz", + "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.139.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.1.5", + "@rolldown/binding-darwin-arm64": "1.1.5", + "@rolldown/binding-darwin-x64": "1.1.5", + "@rolldown/binding-freebsd-x64": "1.1.5", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", + "@rolldown/binding-linux-arm64-gnu": "1.1.5", + "@rolldown/binding-linux-arm64-musl": "1.1.5", + "@rolldown/binding-linux-ppc64-gnu": "1.1.5", + "@rolldown/binding-linux-s390x-gnu": "1.1.5", + "@rolldown/binding-linux-x64-gnu": "1.1.5", + "@rolldown/binding-linux-x64-musl": "1.1.5", + "@rolldown/binding-openharmony-arm64": "1.1.5", + "@rolldown/binding-wasm32-wasi": "1.1.5", + "@rolldown/binding-win32-arm64-msvc": "1.1.5", + "@rolldown/binding-win32-x64-msvc": "1.1.5" + } + }, + "node_modules/vitest": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", + "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.10", + "@vitest/mocker": "4.1.10", + "@vitest/pretty-format": "4.1.10", + "@vitest/runner": "4.1.10", + "@vitest/snapshot": "4.1.10", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.10", + "@vitest/browser-preview": "4.1.10", + "@vitest/browser-webdriverio": "4.1.10", + "@vitest/coverage-istanbul": "4.1.10", + "@vitest/coverage-v8": "4.1.10", + "@vitest/ui": "4.1.10", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/workerd": { + "version": "1.20260710.1", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260710.1.tgz", + "integrity": "sha512-U2sBPPrb9U97sBKnnMN6Kv8p65903P35nwMkPE9vSH/bRuRqkZ3a1EjUw3jV28RhiyXpkLF77Evzw8XimFxyTw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "bin": { + "workerd": "bin/workerd" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "@cloudflare/workerd-darwin-64": "1.20260710.1", + "@cloudflare/workerd-darwin-arm64": "1.20260710.1", + "@cloudflare/workerd-linux-64": "1.20260710.1", + "@cloudflare/workerd-linux-arm64": "1.20260710.1", + "@cloudflare/workerd-windows-64": "1.20260710.1" + } + }, + "node_modules/wrangler": { + "version": "4.111.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.111.0.tgz", + "integrity": "sha512-bffpI9EyrnpKkF/1S+RaIv8oRD93GtbsA7TlfWwOsGJGB7VO3jVbdGzpC9TU7Bqom3z7jUxcte4Z9MPhaQ4HoQ==", + "dev": true, + "license": "MIT OR Apache-2.0", + "dependencies": { + "@cloudflare/kv-asset-handler": "0.5.0", + "@cloudflare/unenv-preset": "2.16.1", + "blake3-wasm": "2.1.5", + "esbuild": "0.28.1", + "miniflare": "4.20260710.0", + "path-to-regexp": "6.3.0", + "unenv": "2.0.0-rc.24", + "workerd": "1.20260710.1" + }, + "bin": { + "cf-wrangler": "bin/cf-wrangler.js", + "wrangler": "bin/wrangler.js", + "wrangler2": "bin/wrangler.js" + }, + "engines": { + "node": ">=22.0.0" + }, + "optionalDependencies": { + "fsevents": "2.3.3" + }, + "peerDependencies": { + "@cloudflare/workers-types": "^5.20260710.1" + }, + "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, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "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==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "dev": true, + "license": "MIT", + "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/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/youch": { + "version": "4.1.0-beta.10", + "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.10.tgz", + "integrity": "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@poppinss/colors": "^4.1.5", + "@poppinss/dumper": "^0.6.4", + "@speed-highlight/core": "^1.2.7", + "cookie": "^1.0.2", + "youch-core": "^0.3.3" + } + }, + "node_modules/youch-core": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz", + "integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@poppinss/exception": "^1.2.2", + "error-stack-parser-es": "^1.0.5" + } + }, + "node_modules/youch/node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" } } } diff --git a/package.json b/package.json index a6aaa20..4d5eae4 100644 --- a/package.json +++ b/package.json @@ -12,14 +12,16 @@ "deploy:dry-run": "wrangler deploy --dry-run" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", - "agents": "^0.0.117", + "@modelcontextprotocol/sdk": "1.29.0", + "agents": "0.17.4", "ajv": "^8.17.1", - "zod": "^3.25.76" + "zod": "^4.4.3" }, "devDependencies": { - "@cloudflare/vitest-pool-workers": "^0.8.69", - "vitest": "^3.2.4", - "wrangler": "^4.24.3" + "@cloudflare/vitest-pool-workers": "^0.18.4", + "@vitest/runner": "^4.1.10", + "@vitest/snapshot": "^4.1.10", + "vitest": "^4.1.10", + "wrangler": "^4.110.0" } -} +} \ No newline at end of file diff --git a/tests/worker.vitest.mjs b/tests/worker.vitest.mjs index 7208b8c..3f2daa3 100644 --- a/tests/worker.vitest.mjs +++ b/tests/worker.vitest.mjs @@ -196,7 +196,7 @@ describe('ADS, audit, cache, and registry', () => { }); it('detects registry packet drift', async () => { - const packet = JSON.parse(await readFile('registry/packet.json', 'utf8')); + const packet = (await import('../registry/packet.json', { with: { type: 'json' } })).default; expect(packet.version).toBe(BUILD.version); expect(packet.tools.map((tool) => tool.name).sort()).toEqual(toolIds()); }); diff --git a/vitest.config.mjs b/vitest.config.mjs index 9ed92a7..9059bd3 100644 --- a/vitest.config.mjs +++ b/vitest.config.mjs @@ -2,6 +2,12 @@ import { defineConfig } from 'vitest/config'; import { cloudflareTest } from '@cloudflare/vitest-pool-workers'; export default defineConfig({ - plugins: [cloudflareTest({ wrangler: { configPath: './wrangler.jsonc' } })], - test: { include: ['tests/worker.vitest.mjs'] } + plugins: [ + cloudflareTest({ + wrangler: { configPath: './wrangler.jsonc' } + }) + ], + test: { + include: ['tests/worker.vitest.mjs'] + } });