stitchkit 0.93.0 → 0.94.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +198 -0
- package/README.md +5 -2
- package/dist/agent-runtime/children-control.d.ts +6 -0
- package/dist/agent-runtime/children-control.d.ts.map +1 -0
- package/dist/agent-runtime/children-spawn.d.ts +6 -0
- package/dist/agent-runtime/children-spawn.d.ts.map +1 -0
- package/dist/agent-runtime/children-state.d.ts +46 -0
- package/dist/agent-runtime/children-state.d.ts.map +1 -0
- package/dist/agent-runtime/children-usage.d.ts +8 -0
- package/dist/agent-runtime/children-usage.d.ts.map +1 -0
- package/dist/agent-runtime/children.d.ts +11 -14
- package/dist/agent-runtime/children.d.ts.map +1 -1
- package/dist/agent-runtime/coding-shell-process.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-contract.d.ts +2 -1
- package/dist/agent-runtime/coding-tool-contract.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-listing.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-search-patch.d.ts.map +1 -1
- package/dist/agent-runtime/contained-darwin.d.ts +38 -0
- package/dist/agent-runtime/contained-darwin.d.ts.map +1 -0
- package/dist/agent-runtime/contained-files.d.ts +11 -26
- package/dist/agent-runtime/contained-files.d.ts.map +1 -1
- package/dist/agent-runtime/contained-scan.d.ts +21 -0
- package/dist/agent-runtime/contained-scan.d.ts.map +1 -0
- package/dist/agent-runtime/contained-write.d.ts +9 -0
- package/dist/agent-runtime/contained-write.d.ts.map +1 -0
- package/dist/agent-runtime/deferred-tool-types.d.ts +4 -3
- package/dist/agent-runtime/deferred-tool-types.d.ts.map +1 -1
- package/dist/agent-runtime/events.d.ts +1 -1
- package/dist/agent-runtime/events.d.ts.map +1 -1
- package/dist/agent-runtime/harness-control.d.ts +0 -1
- package/dist/agent-runtime/harness-control.d.ts.map +1 -1
- package/dist/agent-runtime/harness.d.ts +0 -5
- package/dist/agent-runtime/harness.d.ts.map +1 -1
- package/dist/agent-runtime/managed-tools.d.ts +3 -2
- package/dist/agent-runtime/managed-tools.d.ts.map +1 -1
- package/dist/agent-runtime/observability.d.ts +1 -1
- package/dist/agent-runtime/observability.d.ts.map +1 -1
- package/dist/agent-runtime/openrouter.d.ts +29 -0
- package/dist/agent-runtime/openrouter.d.ts.map +1 -0
- package/dist/agent-runtime/projections.d.ts +1 -1
- package/dist/agent-runtime/projections.d.ts.map +1 -1
- package/dist/agent-runtime/run-acquisition.d.ts +17 -0
- package/dist/agent-runtime/run-acquisition.d.ts.map +1 -0
- package/dist/agent-runtime/run-execution-state.d.ts +133 -0
- package/dist/agent-runtime/run-execution-state.d.ts.map +1 -0
- package/dist/agent-runtime/run-execution.d.ts +17 -33
- package/dist/agent-runtime/run-execution.d.ts.map +1 -1
- package/dist/agent-runtime/run-failure.d.ts +18 -0
- package/dist/agent-runtime/run-failure.d.ts.map +1 -0
- package/dist/agent-runtime/run-model-attempts.d.ts +6 -0
- package/dist/agent-runtime/run-model-attempts.d.ts.map +1 -0
- package/dist/agent-runtime/run-prompt-history.d.ts +58 -0
- package/dist/agent-runtime/run-prompt-history.d.ts.map +1 -0
- package/dist/agent-runtime/run-provider-ledger.d.ts +26 -0
- package/dist/agent-runtime/run-provider-ledger.d.ts.map +1 -0
- package/dist/agent-runtime/run-stream-parts.d.ts +17 -0
- package/dist/agent-runtime/run-stream-parts.d.ts.map +1 -0
- package/dist/agent-runtime/run-terminal.d.ts +11 -0
- package/dist/agent-runtime/run-terminal.d.ts.map +1 -0
- package/dist/agent-runtime/run-turn-preparation.d.ts +22 -0
- package/dist/agent-runtime/run-turn-preparation.d.ts.map +1 -0
- package/dist/agent-runtime/runtime-admission-gate.d.ts +29 -0
- package/dist/agent-runtime/runtime-admission-gate.d.ts.map +1 -0
- package/dist/agent-runtime/runtime-control.d.ts +9 -0
- package/dist/agent-runtime/runtime-control.d.ts.map +1 -0
- package/dist/agent-runtime/runtime-recovery.d.ts +10 -0
- package/dist/agent-runtime/runtime-recovery.d.ts.map +1 -0
- package/dist/agent-runtime/runtime-state.d.ts +36 -0
- package/dist/agent-runtime/runtime-state.d.ts.map +1 -0
- package/dist/agent-runtime/runtime-submit.d.ts +5 -0
- package/dist/agent-runtime/runtime-submit.d.ts.map +1 -0
- package/dist/agent-runtime/runtime.d.ts +10 -5
- package/dist/agent-runtime/runtime.d.ts.map +1 -1
- package/dist/agent-runtime/schedule-records.d.ts +34 -0
- package/dist/agent-runtime/schedule-records.d.ts.map +1 -0
- package/dist/agent-runtime/schedules.d.ts +34 -0
- package/dist/agent-runtime/schedules.d.ts.map +1 -1
- package/dist/agent-runtime/sqlite-bun.d.ts +12 -0
- package/dist/agent-runtime/sqlite-bun.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-events.d.ts +5 -0
- package/dist/agent-runtime/sqlite-events.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-history.d.ts +7 -0
- package/dist/agent-runtime/sqlite-history.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-ledger.d.ts +7 -0
- package/dist/agent-runtime/sqlite-ledger.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-node.d.ts +12 -0
- package/dist/agent-runtime/sqlite-node.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-reads.d.ts +14 -0
- package/dist/agent-runtime/sqlite-reads.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-rows.d.ts +178 -0
- package/dist/agent-runtime/sqlite-rows.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-schema.d.ts +7 -0
- package/dist/agent-runtime/sqlite-schema.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-transactions.d.ts +25 -0
- package/dist/agent-runtime/sqlite-transactions.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite.d.ts +10 -6
- package/dist/agent-runtime/sqlite.d.ts.map +1 -1
- package/dist/agent-runtime/store-archive.d.ts +16 -0
- package/dist/agent-runtime/store-archive.d.ts.map +1 -0
- package/dist/agent-runtime/store-conformance-lifecycle.d.ts +434 -0
- package/dist/agent-runtime/store-conformance-lifecycle.d.ts.map +1 -0
- package/dist/agent-runtime/store-conformance-ordering.d.ts +18 -0
- package/dist/agent-runtime/store-conformance-ordering.d.ts.map +1 -0
- package/dist/agent-runtime/store-conformance-support.d.ts +130 -0
- package/dist/agent-runtime/store-conformance-support.d.ts.map +1 -0
- package/dist/agent-runtime/store-conformance-terminal.d.ts +12 -0
- package/dist/agent-runtime/store-conformance-terminal.d.ts.map +1 -0
- package/dist/agent-runtime/store-conformance.d.ts +40 -0
- package/dist/agent-runtime/store-conformance.d.ts.map +1 -0
- package/dist/agent-runtime/store-create.d.ts +11 -0
- package/dist/agent-runtime/store-create.d.ts.map +1 -0
- package/dist/agent-runtime/store-driver-contract.d.ts +814 -0
- package/dist/agent-runtime/store-driver-contract.d.ts.map +1 -0
- package/dist/agent-runtime/store-events.d.ts +7 -89
- package/dist/agent-runtime/store-events.d.ts.map +1 -1
- package/dist/agent-runtime/store-memory.d.ts +4 -0
- package/dist/agent-runtime/store-memory.d.ts.map +1 -0
- package/dist/agent-runtime/store-mutate.d.ts +13 -0
- package/dist/agent-runtime/store-mutate.d.ts.map +1 -0
- package/dist/agent-runtime/store-purge.d.ts +1 -1
- package/dist/agent-runtime/store-purge.d.ts.map +1 -1
- package/dist/agent-runtime/store-reads.d.ts +29 -0
- package/dist/agent-runtime/store-reads.d.ts.map +1 -0
- package/dist/agent-runtime/store-reduce-history.d.ts +10 -0
- package/dist/agent-runtime/store-reduce-history.d.ts.map +1 -0
- package/dist/agent-runtime/store-reduce-run.d.ts +14 -0
- package/dist/agent-runtime/store-reduce-run.d.ts.map +1 -0
- package/dist/agent-runtime/store-reduce-shared.d.ts +76 -0
- package/dist/agent-runtime/store-reduce-shared.d.ts.map +1 -0
- package/dist/agent-runtime/store-reduce-terminal.d.ts +6 -0
- package/dist/agent-runtime/store-reduce-terminal.d.ts.map +1 -0
- package/dist/agent-runtime/store-reducer.d.ts +24 -0
- package/dist/agent-runtime/store-reducer.d.ts.map +1 -0
- package/dist/agent-runtime/store-snapshot.d.ts +19 -0
- package/dist/agent-runtime/store-snapshot.d.ts.map +1 -0
- package/dist/agent-runtime/store.d.ts +1 -1
- package/dist/agent-runtime/store.d.ts.map +1 -1
- package/dist/application/admission-rate.d.ts +21 -0
- package/dist/application/admission-rate.d.ts.map +1 -0
- package/dist/application/admission-run.d.ts +8 -0
- package/dist/application/admission-run.d.ts.map +1 -0
- package/dist/application/admission.d.ts +1 -1
- package/dist/application/admission.d.ts.map +1 -1
- package/dist/application/diagnostic-journal-lock.d.ts +9 -34
- package/dist/application/diagnostic-journal-lock.d.ts.map +1 -1
- package/dist/application/diagnostic-journal-manager.d.ts.map +1 -1
- package/dist/application/diagnostic-journal-storage.d.ts.map +1 -1
- package/dist/application/events.d.ts +1 -1
- package/dist/application/events.d.ts.map +1 -1
- package/dist/application/file-state-store.d.ts +23 -0
- package/dist/application/file-state-store.d.ts.map +1 -0
- package/dist/application/health.d.ts +1 -1
- package/dist/application/health.d.ts.map +1 -1
- package/dist/application/kernel-admission.d.ts +8 -0
- package/dist/application/kernel-admission.d.ts.map +1 -0
- package/dist/application/kernel-contract.d.ts +142 -0
- package/dist/application/kernel-contract.d.ts.map +1 -0
- package/dist/application/kernel-resource-context.d.ts +24 -0
- package/dist/application/kernel-resource-context.d.ts.map +1 -0
- package/dist/application/kernel-restart.d.ts +5 -0
- package/dist/application/kernel-restart.d.ts.map +1 -0
- package/dist/application/kernel-rollback.d.ts +4 -0
- package/dist/application/kernel-rollback.d.ts.map +1 -0
- package/dist/application/kernel-shutdown.d.ts +6 -0
- package/dist/application/kernel-shutdown.d.ts.map +1 -0
- package/dist/application/kernel-start.d.ts +20 -0
- package/dist/application/kernel-start.d.ts.map +1 -0
- package/dist/application/kernel-state.d.ts +116 -0
- package/dist/application/kernel-state.d.ts.map +1 -0
- package/dist/application/kernel.d.ts +9 -140
- package/dist/application/kernel.d.ts.map +1 -1
- package/dist/application/latest-sink.d.ts +1 -1
- package/dist/application/latest-sink.d.ts.map +1 -1
- package/dist/application/notification-outbox.d.ts.map +1 -1
- package/dist/application/opentelemetry.d.ts +1 -1
- package/dist/application/opentelemetry.d.ts.map +1 -1
- package/dist/application/schedule.d.ts +0 -1
- package/dist/application/schedule.d.ts.map +1 -1
- package/dist/application/watch-hub-core.d.ts +122 -0
- package/dist/application/watch-hub-core.d.ts.map +1 -0
- package/dist/application/watch-hub.d.ts +3 -3
- package/dist/application/watch-hub.d.ts.map +1 -1
- package/dist/browser/client-executors.d.ts +14 -0
- package/dist/browser/client-executors.d.ts.map +1 -0
- package/dist/browser/client-multipart.d.ts +1 -1
- package/dist/browser/client-multipart.d.ts.map +1 -1
- package/dist/browser/client-url.d.ts +1 -1
- package/dist/browser/client-url.d.ts.map +1 -1
- package/dist/browser/client.d.ts +3 -2
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/browser/contract-stream.d.ts +1 -1
- package/dist/browser/contract-stream.d.ts.map +1 -1
- package/dist/browser/http-fetch.d.ts +22 -0
- package/dist/browser/http-fetch.d.ts.map +1 -0
- package/dist/browser/http.d.ts +2 -4
- package/dist/browser/http.d.ts.map +1 -1
- package/dist/browser/live-state-core.d.ts +63 -0
- package/dist/browser/live-state-core.d.ts.map +1 -0
- package/dist/browser/live-state.d.ts.map +1 -1
- package/dist/browser/realtime-client.d.ts +26 -0
- package/dist/browser/realtime-client.d.ts.map +1 -0
- package/dist/browser/resumable.d.ts +1 -28
- package/dist/browser/resumable.d.ts.map +1 -1
- package/dist/browser/retained.d.ts.map +1 -0
- package/dist/browser/socket-io-connection.d.ts +82 -0
- package/dist/browser/socket-io-connection.d.ts.map +1 -0
- package/dist/browser/socket-io-peer.d.ts +20 -0
- package/dist/browser/socket-io-peer.d.ts.map +1 -0
- package/dist/browser/socket-io-trace.d.ts +31 -0
- package/dist/browser/socket-io-trace.d.ts.map +1 -0
- package/dist/browser/socket-io.d.ts +24 -18
- package/dist/browser/socket-io.d.ts.map +1 -1
- package/dist/browser/stream.d.ts +14 -2
- package/dist/browser/stream.d.ts.map +1 -1
- package/dist/contract/client-types.d.ts +134 -0
- package/dist/contract/client-types.d.ts.map +1 -0
- package/dist/contract/define-validation.d.ts +30 -0
- package/dist/contract/define-validation.d.ts.map +1 -0
- package/dist/contract/define.d.ts +47 -394
- package/dist/contract/define.d.ts.map +1 -1
- package/dist/contract/normalize.d.ts +56 -0
- package/dist/contract/normalize.d.ts.map +1 -0
- package/dist/contract/runtime-context.d.ts +131 -0
- package/dist/contract/runtime-context.d.ts.map +1 -0
- package/dist/contract/tool-options.d.ts +105 -0
- package/dist/contract/tool-options.d.ts.map +1 -0
- package/dist/contract/tool-view.d.ts +148 -0
- package/dist/contract/tool-view.d.ts.map +1 -0
- package/dist/declaration/declaration.d.ts.map +1 -0
- package/dist/durability/contract.d.ts +259 -0
- package/dist/durability/contract.d.ts.map +1 -0
- package/dist/durability/effect.d.ts +24 -0
- package/dist/durability/effect.d.ts.map +1 -0
- package/dist/durability/engine.d.ts +14 -0
- package/dist/durability/engine.d.ts.map +1 -0
- package/dist/durability/events.d.ts +103 -0
- package/dist/durability/events.d.ts.map +1 -0
- package/dist/durability/json.d.ts +3 -0
- package/dist/durability/json.d.ts.map +1 -0
- package/dist/durability/ledger.d.ts +27 -0
- package/dist/durability/ledger.d.ts.map +1 -0
- package/dist/durability/parks.d.ts +22 -0
- package/dist/durability/parks.d.ts.map +1 -0
- package/dist/durability/scheduler.d.ts +30 -0
- package/dist/durability/scheduler.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/browser.d.ts +5 -0
- package/dist/entrypoints/agent-runtime/browser.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/browser.js +124 -0
- package/dist/entrypoints/agent-runtime/coding-tools.d.ts +2 -0
- package/dist/entrypoints/agent-runtime/coding-tools.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/coding-tools.js +22 -0
- package/dist/entrypoints/agent-runtime/harness.d.ts +2 -0
- package/dist/entrypoints/agent-runtime/harness.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/harness.js +739 -0
- package/dist/entrypoints/agent-runtime/openrouter.d.ts +2 -0
- package/dist/entrypoints/agent-runtime/openrouter.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/openrouter.js +270 -0
- package/dist/entrypoints/agent-runtime/sandbox.d.ts +5 -0
- package/dist/entrypoints/agent-runtime/sandbox.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/sandbox.js +797 -0
- package/dist/entrypoints/agent-runtime/sqlite/bun.d.ts +2 -0
- package/dist/entrypoints/agent-runtime/sqlite/bun.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/sqlite/bun.js +44 -0
- package/dist/entrypoints/agent-runtime/sqlite/node.d.ts +2 -0
- package/dist/entrypoints/agent-runtime/sqlite/node.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/sqlite/node.js +46 -0
- package/dist/entrypoints/agent-runtime/testing.d.ts +4 -0
- package/dist/entrypoints/agent-runtime/testing.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/testing.js +1116 -0
- package/dist/entrypoints/agent-runtime.d.ts +42 -0
- package/dist/entrypoints/agent-runtime.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime.js +2670 -0
- package/dist/entrypoints/application/diagnostic-journal.d.ts +21 -0
- package/dist/entrypoints/application/diagnostic-journal.d.ts.map +1 -0
- package/dist/entrypoints/application/diagnostic-journal.js +492 -0
- package/dist/entrypoints/application/grammy.d.ts +2 -0
- package/dist/entrypoints/application/grammy.d.ts.map +1 -0
- package/dist/entrypoints/application/grammy.js +169 -0
- package/dist/entrypoints/application/opentelemetry.d.ts +2 -0
- package/dist/entrypoints/application/opentelemetry.d.ts.map +1 -0
- package/dist/entrypoints/application/opentelemetry.js +250 -0
- package/dist/entrypoints/application/schemas.d.ts +15 -0
- package/dist/entrypoints/application/schemas.d.ts.map +1 -0
- package/dist/entrypoints/application/schemas.js +27 -0
- package/dist/entrypoints/application.d.ts +23 -0
- package/dist/entrypoints/application.d.ts.map +1 -0
- package/dist/entrypoints/application.js +2016 -0
- package/dist/entrypoints/bin/upgrade-cli.d.ts.map +1 -0
- package/dist/entrypoints/bin/upgrade-cli.js +177 -0
- package/dist/entrypoints/cli.d.ts +44 -0
- package/dist/entrypoints/cli.d.ts.map +1 -0
- package/dist/entrypoints/cli.js +773 -0
- package/dist/entrypoints/contract.d.ts +12 -0
- package/dist/entrypoints/contract.d.ts.map +1 -0
- package/dist/entrypoints/contract.js +64 -0
- package/dist/entrypoints/declaration.d.ts +2 -0
- package/dist/entrypoints/declaration.d.ts.map +1 -0
- package/dist/entrypoints/declaration.js +183 -0
- package/dist/entrypoints/files.d.ts +5 -0
- package/dist/entrypoints/files.d.ts.map +1 -0
- package/dist/entrypoints/files.js +111 -0
- package/dist/entrypoints/geo.d.ts +3 -0
- package/dist/entrypoints/geo.d.ts.map +1 -0
- package/dist/entrypoints/geo.js +245 -0
- package/dist/entrypoints/google.d.ts +2 -0
- package/dist/entrypoints/google.d.ts.map +1 -0
- package/dist/entrypoints/google.js +175 -0
- package/dist/entrypoints/index.d.ts +17 -0
- package/dist/entrypoints/index.d.ts.map +1 -0
- package/dist/entrypoints/index.js +764 -0
- package/dist/entrypoints/live.d.ts +19 -0
- package/dist/entrypoints/live.d.ts.map +1 -0
- package/dist/entrypoints/live.js +302 -0
- package/dist/entrypoints/node.d.ts +19 -0
- package/dist/entrypoints/node.d.ts.map +1 -0
- package/dist/entrypoints/node.js +308 -0
- package/dist/entrypoints/oauth.d.ts +2 -0
- package/dist/entrypoints/oauth.d.ts.map +1 -0
- package/dist/entrypoints/oauth.js +170 -0
- package/dist/entrypoints/observability.d.ts +19 -0
- package/dist/entrypoints/observability.d.ts.map +1 -0
- package/dist/entrypoints/observability.js +567 -0
- package/dist/entrypoints/primitives.d.ts +3 -0
- package/dist/entrypoints/primitives.d.ts.map +1 -0
- package/dist/entrypoints/primitives.js +749 -0
- package/dist/entrypoints/react.d.ts +5 -0
- package/dist/entrypoints/react.d.ts.map +1 -0
- package/dist/entrypoints/react.js +403 -0
- package/dist/entrypoints/release.d.ts +15 -0
- package/dist/entrypoints/release.d.ts.map +1 -0
- package/dist/entrypoints/release.js +196 -0
- package/dist/entrypoints/remote.d.ts +9 -0
- package/dist/entrypoints/remote.d.ts.map +1 -0
- package/dist/entrypoints/remote.js +66 -0
- package/dist/entrypoints/server.d.ts +39 -0
- package/dist/entrypoints/server.d.ts.map +1 -0
- package/dist/entrypoints/server.js +2009 -0
- package/dist/entrypoints/telegram.d.ts +3 -0
- package/dist/entrypoints/telegram.d.ts.map +1 -0
- package/dist/entrypoints/telegram.js +224 -0
- package/dist/entrypoints/testing.d.ts +10 -0
- package/dist/entrypoints/testing.d.ts.map +1 -0
- package/dist/entrypoints/testing.js +1377 -0
- package/dist/entrypoints/tools/connections.d.ts +19 -0
- package/dist/entrypoints/tools/connections.d.ts.map +1 -0
- package/dist/entrypoints/tools/connections.js +1110 -0
- package/dist/entrypoints/tools/contract.d.ts +29 -0
- package/dist/entrypoints/tools/contract.d.ts.map +1 -0
- package/dist/entrypoints/tools/contract.js +24 -0
- package/dist/entrypoints/tools/invoker.d.ts +9 -0
- package/dist/entrypoints/tools/invoker.d.ts.map +1 -0
- package/dist/entrypoints/tools/invoker.js +20 -0
- package/dist/entrypoints/tools.d.ts +54 -0
- package/dist/entrypoints/tools.d.ts.map +1 -0
- package/dist/entrypoints/tools.js +3009 -0
- package/dist/entrypoints/tracking/server.d.ts +15 -0
- package/dist/entrypoints/tracking/server.d.ts.map +1 -0
- package/dist/entrypoints/tracking.d.ts +24 -0
- package/dist/entrypoints/tracking.d.ts.map +1 -0
- package/dist/entrypoints/tracking.js +1140 -0
- package/dist/files/boundary.d.ts.map +1 -1
- package/dist/files/file-io.d.ts +14 -0
- package/dist/files/file-io.d.ts.map +1 -0
- package/dist/google/google.d.ts.map +1 -0
- package/dist/index-0b1ess5e.js +38 -0
- package/dist/index-1j8pm5t0.js +412 -0
- package/dist/index-1zbbzgfh.js +89 -0
- package/dist/index-2bxbyab0.js +47 -0
- package/dist/index-2gxzjvyr.js +266 -0
- package/dist/index-35mh5bhj.js +177 -0
- package/dist/index-48ffdxgk.js +6 -0
- package/dist/index-4gcnakhx.js +82 -0
- package/dist/index-55hkhm67.js +343 -0
- package/dist/index-79z7m7dt.js +675 -0
- package/dist/index-7f68ghdn.js +3618 -0
- package/dist/index-7p1f0vp2.js +154 -0
- package/dist/index-83bdg97s.js +16 -0
- package/dist/index-863ea9jb.js +154 -0
- package/dist/index-8p52kd5p.js +242 -0
- package/dist/index-d9pk3td4.js +326 -0
- package/dist/index-dce5wxcq.js +63 -0
- package/dist/index-e01r054k.js +105 -0
- package/dist/index-ensd0r74.js +595 -0
- package/dist/index-eqqvgdb3.js +46 -0
- package/dist/index-gxrt5h6v.js +341 -0
- package/dist/index-h6eeys1v.js +211 -0
- package/dist/index-ham5sz8m.js +734 -0
- package/dist/index-het2he5g.js +1387 -0
- package/dist/index-hffjpmq9.js +30 -0
- package/dist/index-hmp4800j.js +51 -0
- package/dist/index-k30h66yd.js +317 -0
- package/dist/index-k5hsfc3j.js +31 -0
- package/dist/index-khtgb21r.js +92 -0
- package/dist/index-m9zn6cpq.js +51 -0
- package/dist/index-ndddxtyx.js +324 -0
- package/dist/index-ngfhvfpd.js +30 -0
- package/dist/index-np4m8hd3.js +1205 -0
- package/dist/index-p3vsv1fb.js +3493 -0
- package/dist/index-p5r7qpdd.js +85 -0
- package/dist/index-p9e0w8hs.js +1084 -0
- package/dist/index-p9sh0xx4.js +64 -0
- package/dist/index-paz6sgdp.js +371 -0
- package/dist/index-px2gm2jp.js +448 -0
- package/dist/index-qwhynv6x.js +103 -0
- package/dist/index-s812ycat.js +65 -0
- package/dist/index-sp1tzwnb.js +281 -0
- package/dist/index-t9rhjr9f.js +2306 -0
- package/dist/index-v260df89.js +342 -0
- package/dist/index-w906953s.js +946 -0
- package/dist/index-wdkt63w3.js +214 -0
- package/dist/index-wqgjfstn.js +18 -0
- package/dist/index-wsm5w4ee.js +1023 -0
- package/dist/index-xw3s75nj.js +100 -0
- package/dist/index-yw4fzmdz.js +268 -0
- package/dist/index-zfrhfn82.js +85 -0
- package/dist/index-znfs20ss.js +98 -0
- package/dist/internal/atomic-file.d.ts +23 -2
- package/dist/internal/atomic-file.d.ts.map +1 -1
- package/dist/internal/backoff.d.ts +29 -0
- package/dist/internal/backoff.d.ts.map +1 -0
- package/dist/internal/canonical-json.d.ts +21 -11
- package/dist/internal/canonical-json.d.ts.map +1 -1
- package/dist/internal/channel.d.ts.map +1 -0
- package/dist/internal/exclusive-lock.d.ts +51 -0
- package/dist/internal/exclusive-lock.d.ts.map +1 -0
- package/dist/internal/logger.d.ts.map +1 -0
- package/dist/internal/process-identity.d.ts +47 -0
- package/dist/internal/process-identity.d.ts.map +1 -0
- package/dist/internal/request.d.ts.map +1 -0
- package/dist/internal/stable-digest.d.ts +0 -43
- package/dist/internal/stable-digest.d.ts.map +1 -1
- package/dist/internal/typed.d.ts +0 -8
- package/dist/internal/typed.d.ts.map +1 -1
- package/dist/internal/with-exclusive-lock.d.ts +67 -0
- package/dist/internal/with-exclusive-lock.d.ts.map +1 -0
- package/dist/internal/zod-issues.d.ts +38 -0
- package/dist/internal/zod-issues.d.ts.map +1 -0
- package/dist/json-schema/dialect.d.ts +17 -0
- package/dist/json-schema/dialect.d.ts.map +1 -0
- package/dist/json-schema/json-schema.d.ts.map +1 -0
- package/dist/live/watch-client.d.ts.map +1 -1
- package/dist/live/watch-delta.d.ts.map +1 -1
- package/dist/oauth/authorization-code.d.ts +57 -0
- package/dist/oauth/authorization-code.d.ts.map +1 -0
- package/dist/observability/audit.d.ts +3 -3
- package/dist/observability/audit.d.ts.map +1 -1
- package/dist/observability/bounded-logger.d.ts +1 -1
- package/dist/observability/bounded-logger.d.ts.map +1 -1
- package/dist/observability/bounded-sink.d.ts +81 -0
- package/dist/observability/bounded-sink.d.ts.map +1 -0
- package/dist/observability/context.d.ts +1 -1
- package/dist/observability/context.d.ts.map +1 -1
- package/dist/observability/event.d.ts +2 -1
- package/dist/observability/event.d.ts.map +1 -1
- package/dist/observability/work.d.ts +1 -1
- package/dist/observability/work.d.ts.map +1 -1
- package/dist/primitives/audit.d.ts +1 -1
- package/dist/primitives/audit.d.ts.map +1 -1
- package/dist/primitives/export-operation.d.ts +4 -2
- package/dist/primitives/export-operation.d.ts.map +1 -1
- package/dist/realtime/registry.d.ts +0 -5
- package/dist/realtime/registry.d.ts.map +1 -1
- package/dist/realtime/socket.d.ts +1 -1
- package/dist/realtime/socket.d.ts.map +1 -1
- package/dist/server/bun.d.ts +0 -1
- package/dist/server/bun.d.ts.map +1 -1
- package/dist/server/context-contribution.d.ts +1 -1
- package/dist/server/context-contribution.d.ts.map +1 -1
- package/dist/server/context.d.ts +2 -2
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/contract-method.d.ts +15 -0
- package/dist/server/contract-method.d.ts.map +1 -0
- package/dist/server/contract-stream.d.ts +1 -1
- package/dist/server/contract-stream.d.ts.map +1 -1
- package/dist/server/create.d.ts +8 -0
- package/dist/server/create.d.ts.map +1 -1
- package/dist/server/endpoint-dispatch.d.ts +10 -0
- package/dist/server/endpoint-dispatch.d.ts.map +1 -0
- package/dist/server/endpoint-response.d.ts +19 -0
- package/dist/server/endpoint-response.d.ts.map +1 -0
- package/dist/server/error-dispatch.d.ts +17 -1
- package/dist/server/error-dispatch.d.ts.map +1 -1
- package/dist/server/error-hook.d.ts +2 -2
- package/dist/server/error-hook.d.ts.map +1 -1
- package/dist/server/handler-state.d.ts +44 -0
- package/dist/server/handler-state.d.ts.map +1 -0
- package/dist/server/implement-registry.d.ts +54 -0
- package/dist/server/implement-registry.d.ts.map +1 -0
- package/dist/server/implement.d.ts +9 -55
- package/dist/server/implement.d.ts.map +1 -1
- package/dist/server/middleware/auth.d.ts +1 -31
- package/dist/server/middleware/auth.d.ts.map +1 -1
- package/dist/server/middleware/cors.d.ts +17 -0
- package/dist/server/middleware/cors.d.ts.map +1 -1
- package/dist/server/middleware/jwt.d.ts +31 -0
- package/dist/server/middleware/jwt.d.ts.map +1 -0
- package/dist/server/middleware/trust-fence.d.ts +1 -1
- package/dist/server/middleware/trust-fence.d.ts.map +1 -1
- package/dist/server/multipart-reader.d.ts +22 -0
- package/dist/server/multipart-reader.d.ts.map +1 -0
- package/dist/server/multipart.d.ts +1 -1
- package/dist/server/multipart.d.ts.map +1 -1
- package/dist/server/oauth/cimd.d.ts +88 -0
- package/dist/server/oauth/cimd.d.ts.map +1 -0
- package/dist/server/oauth/endpoints.d.ts +39 -0
- package/dist/server/oauth/endpoints.d.ts.map +1 -0
- package/dist/server/oauth/metadata.d.ts +28 -0
- package/dist/server/oauth/metadata.d.ts.map +1 -0
- package/dist/server/oauth/provider.d.ts +117 -0
- package/dist/server/oauth/provider.d.ts.map +1 -0
- package/dist/server/realtime.d.ts +1 -1
- package/dist/server/realtime.d.ts.map +1 -1
- package/dist/server/request-completion.d.ts +16 -0
- package/dist/server/request-completion.d.ts.map +1 -0
- package/dist/server/response-metadata.d.ts +1 -1
- package/dist/server/response-metadata.d.ts.map +1 -1
- package/dist/server/route-table.d.ts +9 -0
- package/dist/server/route-table.d.ts.map +1 -0
- package/dist/server/stream.d.ts +0 -13
- package/dist/server/stream.d.ts.map +1 -1
- package/dist/server/streaming-pump.d.ts +66 -0
- package/dist/server/streaming-pump.d.ts.map +1 -0
- package/dist/server/streaming-route.d.ts +12 -5
- package/dist/server/streaming-route.d.ts.map +1 -1
- package/dist/server/types.d.ts +10 -4
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/unix-client-bun.d.ts.map +1 -1
- package/dist/server/unix-client-http1.d.ts +76 -0
- package/dist/server/unix-client-http1.d.ts.map +1 -0
- package/dist/server/unix-client.d.ts.map +1 -1
- package/dist/testing/handler-clients.d.ts +32 -0
- package/dist/testing/handler-clients.d.ts.map +1 -0
- package/dist/testing/managed-resource-conformance-scenarios.d.ts.map +1 -1
- package/dist/testing/realtime-probe.d.ts +33 -0
- package/dist/testing/realtime-probe.d.ts.map +1 -0
- package/dist/testing/surface-conformance.d.ts +2 -32
- package/dist/testing/surface-conformance.d.ts.map +1 -1
- package/dist/testing/surface-manifest-digest.d.ts +44 -0
- package/dist/testing/surface-manifest-digest.d.ts.map +1 -0
- package/dist/testing/surface-manifest.d.ts +30 -4
- package/dist/testing/surface-manifest.d.ts.map +1 -1
- package/dist/tools/agent.d.ts +1 -1
- package/dist/tools/agent.d.ts.map +1 -1
- package/dist/tools/cli/args-fields.d.ts +31 -0
- package/dist/tools/cli/args-fields.d.ts.map +1 -0
- package/dist/tools/cli/args-route.d.ts +42 -0
- package/dist/tools/cli/args-route.d.ts.map +1 -0
- package/dist/tools/cli/args-view.d.ts +32 -0
- package/dist/tools/cli/args-view.d.ts.map +1 -0
- package/dist/tools/cli/args.d.ts +80 -0
- package/dist/tools/cli/args.d.ts.map +1 -0
- package/dist/tools/cli/argument-error.d.ts +5 -0
- package/dist/tools/cli/argument-error.d.ts.map +1 -0
- package/dist/tools/cli/checkpoint.d.ts +24 -0
- package/dist/tools/cli/checkpoint.d.ts.map +1 -0
- package/dist/tools/cli/command.d.ts +70 -0
- package/dist/tools/cli/command.d.ts.map +1 -0
- package/dist/tools/cli/config.d.ts +90 -0
- package/dist/tools/cli/config.d.ts.map +1 -0
- package/dist/tools/cli/create-cli.d.ts +36 -0
- package/dist/tools/cli/create-cli.d.ts.map +1 -0
- package/dist/tools/cli/download.d.ts +8 -0
- package/dist/tools/cli/download.d.ts.map +1 -0
- package/dist/tools/cli/format.d.ts +50 -0
- package/dist/tools/cli/format.d.ts.map +1 -0
- package/dist/tools/cli/help.d.ts +24 -0
- package/dist/tools/cli/help.d.ts.map +1 -0
- package/dist/tools/cli/installer.d.ts +34 -0
- package/dist/tools/cli/installer.d.ts.map +1 -0
- package/dist/tools/cli/invoke.d.ts +144 -0
- package/dist/tools/cli/invoke.d.ts.map +1 -0
- package/dist/tools/cli/io.d.ts +10 -0
- package/dist/tools/cli/io.d.ts.map +1 -0
- package/dist/tools/cli/managed-surface.d.ts +30 -0
- package/dist/tools/cli/managed-surface.d.ts.map +1 -0
- package/dist/tools/cli/manifest.d.ts +80 -0
- package/dist/tools/cli/manifest.d.ts.map +1 -0
- package/dist/tools/cli/policy.d.ts +27 -0
- package/dist/tools/cli/policy.d.ts.map +1 -0
- package/dist/tools/cli/prepare.d.ts +14 -0
- package/dist/tools/cli/prepare.d.ts.map +1 -0
- package/dist/tools/cli/profile.d.ts +40 -0
- package/dist/tools/cli/profile.d.ts.map +1 -0
- package/dist/tools/cli/run-managed.d.ts +5 -0
- package/dist/tools/cli/run-managed.d.ts.map +1 -0
- package/dist/tools/cli/run-native.d.ts +9 -0
- package/dist/tools/cli/run-native.d.ts.map +1 -0
- package/dist/tools/cli/session.d.ts +40 -0
- package/dist/tools/cli/session.d.ts.map +1 -0
- package/dist/tools/cli/signature.d.ts +81 -0
- package/dist/tools/cli/signature.d.ts.map +1 -0
- package/dist/tools/cli/stream.d.ts +93 -0
- package/dist/tools/cli/stream.d.ts.map +1 -0
- package/dist/tools/cli/update.d.ts +145 -0
- package/dist/tools/cli/update.d.ts.map +1 -0
- package/dist/tools/cli/view.d.ts +12 -0
- package/dist/tools/cli/view.d.ts.map +1 -0
- package/dist/tools/cli/wait.d.ts +54 -0
- package/dist/tools/cli/wait.d.ts.map +1 -0
- package/dist/tools/connections/runtime.d.ts +1 -1
- package/dist/tools/connections/runtime.d.ts.map +1 -1
- package/dist/tools/connections/types.d.ts +3 -3
- package/dist/tools/connections/types.d.ts.map +1 -1
- package/dist/tools/durability-context.d.ts +1 -1
- package/dist/tools/durability-context.d.ts.map +1 -1
- package/dist/tools/execute-args.d.ts +23 -0
- package/dist/tools/execute-args.d.ts.map +1 -0
- package/dist/tools/execute-hooks.d.ts +146 -0
- package/dist/tools/execute-hooks.d.ts.map +1 -0
- package/dist/tools/execute-result.d.ts +40 -0
- package/dist/tools/execute-result.d.ts.map +1 -0
- package/dist/tools/execute.d.ts +31 -193
- package/dist/tools/execute.d.ts.map +1 -1
- package/dist/tools/internal/surface-projector.d.ts +9 -6
- package/dist/tools/internal/surface-projector.d.ts.map +1 -1
- package/dist/tools/internal/tool-view.d.ts +41 -0
- package/dist/tools/internal/tool-view.d.ts.map +1 -0
- package/dist/tools/invoker.d.ts +13 -4
- package/dist/tools/invoker.d.ts.map +1 -1
- package/dist/tools/lifecycle.d.ts +1 -1
- package/dist/tools/lifecycle.d.ts.map +1 -1
- package/dist/tools/list-names.d.ts +3 -3
- package/dist/tools/list-names.d.ts.map +1 -1
- package/dist/tools/manifest.d.ts +2 -2
- package/dist/tools/manifest.d.ts.map +1 -1
- package/dist/tools/mcp/app.d.ts +62 -0
- package/dist/tools/mcp/app.d.ts.map +1 -0
- package/dist/tools/mcp/catalog.d.ts +68 -0
- package/dist/tools/mcp/catalog.d.ts.map +1 -0
- package/dist/tools/mcp/handler.d.ts +46 -0
- package/dist/tools/mcp/handler.d.ts.map +1 -0
- package/dist/tools/mcp/mount.d.ts +152 -0
- package/dist/tools/mcp/mount.d.ts.map +1 -0
- package/dist/tools/mcp/prepare.d.ts +76 -0
- package/dist/tools/mcp/prepare.d.ts.map +1 -0
- package/dist/tools/mcp/progress.d.ts +46 -0
- package/dist/tools/mcp/progress.d.ts.map +1 -0
- package/dist/tools/mcp/register.d.ts +36 -0
- package/dist/tools/mcp/register.d.ts.map +1 -0
- package/dist/tools/mcp/round-context.d.ts +38 -0
- package/dist/tools/mcp/round-context.d.ts.map +1 -0
- package/dist/tools/mcp/round-policy.d.ts +33 -0
- package/dist/tools/mcp/round-policy.d.ts.map +1 -0
- package/dist/tools/mcp/round.d.ts +53 -0
- package/dist/tools/mcp/round.d.ts.map +1 -0
- package/dist/tools/mcp/runtime-tools.d.ts +25 -0
- package/dist/tools/mcp/runtime-tools.d.ts.map +1 -0
- package/dist/tools/mcp/stdio-signals.d.ts +33 -0
- package/dist/tools/mcp/stdio-signals.d.ts.map +1 -0
- package/dist/tools/mcp/stdio.d.ts +20 -0
- package/dist/tools/mcp/stdio.d.ts.map +1 -0
- package/dist/tools/mcp/trace.d.ts +12 -0
- package/dist/tools/mcp/trace.d.ts.map +1 -0
- package/dist/tools/mount.d.ts +14 -7
- package/dist/tools/mount.d.ts.map +1 -1
- package/dist/tools/native-definition.d.ts +4 -3
- package/dist/tools/native-definition.d.ts.map +1 -1
- package/dist/tools/operations/async-operation-binding-types.d.ts +127 -0
- package/dist/tools/operations/async-operation-binding-types.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-binding.d.ts +28 -0
- package/dist/tools/operations/async-operation-binding.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-canonical-types.d.ts +110 -0
- package/dist/tools/operations/async-operation-canonical-types.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-canonical.d.ts +7 -0
- package/dist/tools/operations/async-operation-canonical.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-contract.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-id.d.ts +23 -0
- package/dist/tools/operations/async-operation-id.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-runtime-tools.d.ts +41 -0
- package/dist/tools/operations/async-operation-runtime-tools.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-runtime-types.d.ts +69 -0
- package/dist/tools/operations/async-operation-runtime-types.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-runtime.d.ts +5 -0
- package/dist/tools/operations/async-operation-runtime.d.ts.map +1 -0
- package/dist/tools/operations/define-wait-tool.d.ts +22 -0
- package/dist/tools/operations/define-wait-tool.d.ts.map +1 -0
- package/dist/tools/operations/mount-wait.d.ts.map +1 -0
- package/dist/tools/operations/wait-core.d.ts.map +1 -0
- package/dist/tools/remote.d.ts +1 -1
- package/dist/tools/remote.d.ts.map +1 -1
- package/dist/tools/runtime-tool.d.ts +13 -4
- package/dist/tools/runtime-tool.d.ts.map +1 -1
- package/dist/tools/schema/coerce.d.ts.map +1 -0
- package/dist/tools/schema/flatten-join.d.ts.map +1 -0
- package/dist/tools/schema/flatten.d.ts.map +1 -0
- package/dist/tools/schema/portable-formats.d.ts.map +1 -0
- package/dist/tools/schema/presentation.d.ts +24 -0
- package/dist/tools/schema/presentation.d.ts.map +1 -0
- package/dist/tools/schema/schema.d.ts.map +1 -0
- package/dist/tools/schema/untyped-properties.d.ts.map +1 -0
- package/dist/tools/surface.d.ts +2 -3
- package/dist/tools/surface.d.ts.map +1 -1
- package/dist/tools/tool-logger.d.ts +1 -1
- package/dist/tools/tool-logger.d.ts.map +1 -1
- package/dist/tools/toolkit.d.ts +4 -4
- package/dist/tools/toolkit.d.ts.map +1 -1
- package/dist/tools/transfer/define-download-tool.d.ts +18 -0
- package/dist/tools/transfer/define-download-tool.d.ts.map +1 -0
- package/dist/tools/transfer/define-upload-tool.d.ts +16 -0
- package/dist/tools/transfer/define-upload-tool.d.ts.map +1 -0
- package/dist/tools/transfer/define-view-file-tool.d.ts +10 -0
- package/dist/tools/transfer/define-view-file-tool.d.ts.map +1 -0
- package/dist/tools/transfer/download-core.d.ts +20 -0
- package/dist/tools/transfer/download-core.d.ts.map +1 -0
- package/dist/tools/transfer/managed-file-error.d.ts +6 -0
- package/dist/tools/transfer/managed-file-error.d.ts.map +1 -0
- package/dist/tools/transfer/mount-download.d.ts +41 -0
- package/dist/tools/transfer/mount-download.d.ts.map +1 -0
- package/dist/tools/transfer/mount-upload.d.ts +21 -0
- package/dist/tools/transfer/mount-upload.d.ts.map +1 -0
- package/dist/tools/transfer/native-result.d.ts.map +1 -0
- package/dist/tools/transfer/upload-core.d.ts +4 -0
- package/dist/tools/transfer/upload-core.d.ts.map +1 -0
- package/dist/tools/transfer/view-file-contract.d.ts.map +1 -0
- package/dist/tools/transfer/view-file.d.ts +62 -0
- package/dist/tools/transfer/view-file.d.ts.map +1 -0
- package/dist/tools/transports.d.ts +1 -1
- package/dist/tools/transports.d.ts.map +1 -1
- package/dist/tracking/client-listeners.d.ts +30 -0
- package/dist/tracking/client-listeners.d.ts.map +1 -0
- package/dist/tracking/client-visit.d.ts +61 -0
- package/dist/tracking/client-visit.d.ts.map +1 -0
- package/dist/tracking/client.d.ts +3 -2
- package/dist/tracking/client.d.ts.map +1 -1
- package/dist/tracking/contract.d.ts +1 -1
- package/dist/tracking/contract.d.ts.map +1 -1
- package/llms/agent-runtime-browser.txt +33 -0
- package/llms/agent-runtime-coding-tools.txt +58 -0
- package/llms/agent-runtime-harness.txt +45 -0
- package/llms/agent-runtime-openrouter.txt +22 -0
- package/llms/agent-runtime-sandbox.txt +159 -0
- package/llms/agent-runtime-sqlite-bun.txt +29 -0
- package/llms/agent-runtime-sqlite-node.txt +26 -0
- package/llms/agent-runtime-testing.txt +30 -0
- package/llms/agent-runtime.2.txt +550 -0
- package/llms/agent-runtime.3.txt +311 -0
- package/llms/agent-runtime.txt +893 -0
- package/llms/application-diagnostic-journal.txt +30 -0
- package/llms/application-grammy.txt +27 -0
- package/llms/application-opentelemetry.txt +27 -0
- package/llms/application-schemas.txt +42 -0
- package/llms/application.2.txt +487 -0
- package/llms/application.txt +886 -0
- package/llms/cli.2.txt +80 -0
- package/llms/cli.txt +948 -0
- package/llms/contract.txt +606 -0
- package/llms/declaration.txt +286 -0
- package/llms/files.txt +33 -0
- package/llms/geo.txt +114 -0
- package/llms/google.txt +27 -0
- package/llms/live.txt +471 -0
- package/llms/node.txt +43 -0
- package/llms/oauth.txt +136 -0
- package/llms/observability.txt +893 -0
- package/llms/primitives.txt +158 -0
- package/llms/react.txt +184 -0
- package/llms/release.txt +176 -0
- package/llms/remote.txt +25 -0
- package/llms/server.2.txt +361 -0
- package/llms/server.3.txt +1031 -0
- package/llms/server.4.txt +905 -0
- package/llms/server.5.txt +250 -0
- package/llms/server.txt +996 -0
- package/llms/stitchkit.2.txt +836 -0
- package/llms/stitchkit.3.txt +147 -0
- package/llms/stitchkit.txt +260 -0
- package/llms/telegram.txt +30 -0
- package/llms/testing.txt +676 -0
- package/llms/tools-connections.txt +45 -0
- package/llms/tools-contract.txt +9 -0
- package/llms/tools-invoker.txt +9 -0
- package/llms/tools.2.txt +647 -0
- package/llms/tools.3.txt +288 -0
- package/llms/tools.txt +966 -0
- package/llms/tracking-server.txt +32 -0
- package/llms/tracking.txt +263 -0
- package/llms/upgrading-0.37.0-0.50.0.txt +947 -0
- package/llms/upgrading-0.53.0-0.67.0.txt +1174 -0
- package/llms/upgrading-0.68.0-0.94.0.txt +1159 -0
- package/llms/upgrading.txt +215 -0
- package/llms-full.txt +312 -77
- package/llms.txt +54 -5
- package/package.json +84 -83
- package/dist/agent-runtime/durability-contract.d.ts +0 -176
- package/dist/agent-runtime/durability-contract.d.ts.map +0 -1
- package/dist/agent-runtime/durability-json.d.ts +0 -3
- package/dist/agent-runtime/durability-json.d.ts.map +0 -1
- package/dist/agent-runtime/durability-ledger.d.ts +0 -16
- package/dist/agent-runtime/durability-ledger.d.ts.map +0 -1
- package/dist/agent-runtime/durability-scheduler.d.ts +0 -29
- package/dist/agent-runtime/durability-scheduler.d.ts.map +0 -1
- package/dist/agent-runtime/durability.d.ts +0 -14
- package/dist/agent-runtime/durability.d.ts.map +0 -1
- package/dist/agent-runtime/store-driver.d.ts +0 -814
- package/dist/agent-runtime/store-driver.d.ts.map +0 -1
- package/dist/agent-runtime-browser.d.ts +0 -5
- package/dist/agent-runtime-browser.d.ts.map +0 -1
- package/dist/agent-runtime-browser.js +0 -124
- package/dist/agent-runtime-coding-tools.d.ts +0 -2
- package/dist/agent-runtime-coding-tools.d.ts.map +0 -1
- package/dist/agent-runtime-coding-tools.js +0 -23
- package/dist/agent-runtime-harness.d.ts +0 -2
- package/dist/agent-runtime-harness.d.ts.map +0 -1
- package/dist/agent-runtime-harness.js +0 -729
- package/dist/agent-runtime-openrouter.d.ts +0 -29
- package/dist/agent-runtime-openrouter.d.ts.map +0 -1
- package/dist/agent-runtime-openrouter.js +0 -270
- package/dist/agent-runtime-sandbox.d.ts +0 -5
- package/dist/agent-runtime-sandbox.d.ts.map +0 -1
- package/dist/agent-runtime-sandbox.js +0 -798
- package/dist/agent-runtime-sqlite-bun.d.ts +0 -11
- package/dist/agent-runtime-sqlite-bun.d.ts.map +0 -1
- package/dist/agent-runtime-sqlite-bun.js +0 -42
- package/dist/agent-runtime-sqlite-node.d.ts +0 -11
- package/dist/agent-runtime-sqlite-node.d.ts.map +0 -1
- package/dist/agent-runtime-sqlite-node.js +0 -44
- package/dist/agent-runtime-testing.d.ts +0 -3
- package/dist/agent-runtime-testing.d.ts.map +0 -1
- package/dist/agent-runtime-testing.js +0 -156
- package/dist/agent-runtime.d.ts +0 -38
- package/dist/agent-runtime.d.ts.map +0 -1
- package/dist/agent-runtime.js +0 -2607
- package/dist/application/channel.d.ts.map +0 -1
- package/dist/application-diagnostic-journal.d.ts +0 -21
- package/dist/application-diagnostic-journal.d.ts.map +0 -1
- package/dist/application-diagnostic-journal.js +0 -632
- package/dist/application-grammy.d.ts +0 -2
- package/dist/application-grammy.d.ts.map +0 -1
- package/dist/application-grammy.js +0 -169
- package/dist/application-opentelemetry.d.ts +0 -2
- package/dist/application-opentelemetry.d.ts.map +0 -1
- package/dist/application-opentelemetry.js +0 -250
- package/dist/application-schemas.d.ts +0 -15
- package/dist/application-schemas.d.ts.map +0 -1
- package/dist/application-schemas.js +0 -27
- package/dist/application.d.ts +0 -22
- package/dist/application.d.ts.map +0 -1
- package/dist/application.js +0 -1977
- package/dist/cli.d.ts +0 -41
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -753
- package/dist/contract/index.d.ts +0 -8
- package/dist/contract/index.d.ts.map +0 -1
- package/dist/contract/index.js +0 -55
- package/dist/declaration.d.ts.map +0 -1
- package/dist/declaration.js +0 -183
- package/dist/files.d.ts +0 -3
- package/dist/files.d.ts.map +0 -1
- package/dist/files.js +0 -15
- package/dist/geo.d.ts +0 -3
- package/dist/geo.d.ts.map +0 -1
- package/dist/geo.js +0 -245
- package/dist/google.d.ts.map +0 -1
- package/dist/google.js +0 -175
- package/dist/index-0a349c33.js +0 -470
- package/dist/index-0j3vcp5m.js +0 -28
- package/dist/index-2c2bjw3s.js +0 -51
- package/dist/index-2na0qrfn.js +0 -214
- package/dist/index-2qzskm8h.js +0 -63
- package/dist/index-3bmnp41g.js +0 -2169
- package/dist/index-3xwxfj4z.js +0 -334
- package/dist/index-4fpa9dy2.js +0 -51
- package/dist/index-6kyksz9y.js +0 -268
- package/dist/index-77fekveh.js +0 -44
- package/dist/index-7gnkny4z.js +0 -326
- package/dist/index-7zbps32p.js +0 -89
- package/dist/index-9f8ztey6.js +0 -588
- package/dist/index-a11g2kry.js +0 -866
- package/dist/index-a916km3r.js +0 -45
- package/dist/index-actkayzn.js +0 -367
- package/dist/index-bn2cjajt.js +0 -524
- package/dist/index-bx75zwt7.js +0 -63
- package/dist/index-cby4ar3v.js +0 -46
- package/dist/index-cnyk6te3.js +0 -77
- package/dist/index-cxqhvq21.js +0 -413
- package/dist/index-e0znv5gn.js +0 -176
- package/dist/index-e42wzzz5.js +0 -154
- package/dist/index-f477k430.js +0 -324
- package/dist/index-f9mb610r.js +0 -177
- package/dist/index-fadnxwna.js +0 -1046
- package/dist/index-fq77yfzc.js +0 -1303
- package/dist/index-h9etkkyk.js +0 -1126
- package/dist/index-hrbajay7.js +0 -1196
- package/dist/index-kw9t5ayn.js +0 -507
- package/dist/index-mzvgxp0n.js +0 -80
- package/dist/index-n0f51dfn.js +0 -3170
- package/dist/index-p13mwz16.js +0 -16
- package/dist/index-s8cnx02s.js +0 -90
- package/dist/index-sr93cwf9.js +0 -325
- package/dist/index-tmwcrptx.js +0 -85
- package/dist/index-v5573g1k.js +0 -142
- package/dist/index-vjpvjqpn.js +0 -86
- package/dist/index-vk3kq9sb.js +0 -3344
- package/dist/index-wc4x00bn.js +0 -103
- package/dist/index-wnfk50r0.js +0 -211
- package/dist/index-yewwh1w4.js +0 -647
- package/dist/index-yn8remb1.js +0 -290
- package/dist/index-ywd0y6m1.js +0 -394
- package/dist/index-zwkgfq1s.js +0 -345
- package/dist/index.d.ts +0 -14
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -632
- package/dist/internal/errors.d.ts +0 -92
- package/dist/internal/errors.d.ts.map +0 -1
- package/dist/internal/observability-sink.d.ts +0 -81
- package/dist/internal/observability-sink.d.ts.map +0 -1
- package/dist/live.d.ts +0 -19
- package/dist/live.d.ts.map +0 -1
- package/dist/live.js +0 -282
- package/dist/logger.d.ts.map +0 -1
- package/dist/node.d.ts +0 -18
- package/dist/node.d.ts.map +0 -1
- package/dist/node.js +0 -303
- package/dist/oauth.d.ts +0 -57
- package/dist/oauth.d.ts.map +0 -1
- package/dist/oauth.js +0 -170
- package/dist/observability/index.d.ts +0 -19
- package/dist/observability/index.d.ts.map +0 -1
- package/dist/observability/index.js +0 -569
- package/dist/primitives.d.ts +0 -3
- package/dist/primitives.d.ts.map +0 -1
- package/dist/primitives.js +0 -754
- package/dist/react.d.ts +0 -5
- package/dist/react.d.ts.map +0 -1
- package/dist/react.js +0 -403
- package/dist/release.d.ts +0 -15
- package/dist/release.d.ts.map +0 -1
- package/dist/release.js +0 -196
- package/dist/remote.d.ts +0 -9
- package/dist/remote.d.ts.map +0 -1
- package/dist/remote.js +0 -88
- package/dist/retained.d.ts.map +0 -1
- package/dist/server/file-state-store.d.ts +0 -23
- package/dist/server/file-state-store.d.ts.map +0 -1
- package/dist/server/index.d.ts +0 -36
- package/dist/server/index.d.ts.map +0 -1
- package/dist/server/index.js +0 -1745
- package/dist/server/request.d.ts.map +0 -1
- package/dist/telegram.d.ts +0 -3
- package/dist/telegram.d.ts.map +0 -1
- package/dist/telegram.js +0 -224
- package/dist/testing/agent-store-conformance.d.ts +0 -40
- package/dist/testing/agent-store-conformance.d.ts.map +0 -1
- package/dist/testing.d.ts +0 -39
- package/dist/testing.d.ts.map +0 -1
- package/dist/testing.js +0 -2209
- package/dist/tool-invoker.d.ts +0 -9
- package/dist/tool-invoker.d.ts.map +0 -1
- package/dist/tool-invoker.js +0 -21
- package/dist/tools/async-operation-contract.d.ts.map +0 -1
- package/dist/tools/async-operation.d.ts +0 -332
- package/dist/tools/async-operation.d.ts.map +0 -1
- package/dist/tools/cli-args.d.ts +0 -143
- package/dist/tools/cli-args.d.ts.map +0 -1
- package/dist/tools/cli-checkpoint.d.ts +0 -24
- package/dist/tools/cli-checkpoint.d.ts.map +0 -1
- package/dist/tools/cli-command.d.ts +0 -70
- package/dist/tools/cli-command.d.ts.map +0 -1
- package/dist/tools/cli-format.d.ts +0 -49
- package/dist/tools/cli-format.d.ts.map +0 -1
- package/dist/tools/cli-installer.d.ts +0 -34
- package/dist/tools/cli-installer.d.ts.map +0 -1
- package/dist/tools/cli-invoke.d.ts +0 -143
- package/dist/tools/cli-invoke.d.ts.map +0 -1
- package/dist/tools/cli-manifest.d.ts +0 -80
- package/dist/tools/cli-manifest.d.ts.map +0 -1
- package/dist/tools/cli-policy.d.ts +0 -27
- package/dist/tools/cli-policy.d.ts.map +0 -1
- package/dist/tools/cli-profile.d.ts +0 -40
- package/dist/tools/cli-profile.d.ts.map +0 -1
- package/dist/tools/cli-signature.d.ts +0 -81
- package/dist/tools/cli-signature.d.ts.map +0 -1
- package/dist/tools/cli-stream.d.ts +0 -93
- package/dist/tools/cli-stream.d.ts.map +0 -1
- package/dist/tools/cli-update.d.ts +0 -126
- package/dist/tools/cli-update.d.ts.map +0 -1
- package/dist/tools/cli-view.d.ts +0 -12
- package/dist/tools/cli-view.d.ts.map +0 -1
- package/dist/tools/cli-wait.d.ts +0 -54
- package/dist/tools/cli-wait.d.ts.map +0 -1
- package/dist/tools/cli.d.ts +0 -94
- package/dist/tools/cli.d.ts.map +0 -1
- package/dist/tools/coerce.d.ts.map +0 -1
- package/dist/tools/connections/index.d.ts +0 -20
- package/dist/tools/connections/index.d.ts.map +0 -1
- package/dist/tools/connections/index.js +0 -1107
- package/dist/tools/define-download-tool.d.ts +0 -18
- package/dist/tools/define-download-tool.d.ts.map +0 -1
- package/dist/tools/define-upload-tool.d.ts +0 -16
- package/dist/tools/define-upload-tool.d.ts.map +0 -1
- package/dist/tools/define-view-file-tool.d.ts +0 -10
- package/dist/tools/define-view-file-tool.d.ts.map +0 -1
- package/dist/tools/define-wait-tool.d.ts +0 -22
- package/dist/tools/define-wait-tool.d.ts.map +0 -1
- package/dist/tools/download-core.d.ts +0 -20
- package/dist/tools/download-core.d.ts.map +0 -1
- package/dist/tools/flatten-join.d.ts.map +0 -1
- package/dist/tools/flatten.d.ts.map +0 -1
- package/dist/tools/json-schema-dialect.d.ts +0 -17
- package/dist/tools/json-schema-dialect.d.ts.map +0 -1
- package/dist/tools/json-schema.d.ts.map +0 -1
- package/dist/tools/managed-file-error.d.ts +0 -6
- package/dist/tools/managed-file-error.d.ts.map +0 -1
- package/dist/tools/mcp-app.d.ts +0 -62
- package/dist/tools/mcp-app.d.ts.map +0 -1
- package/dist/tools/mcp-catalog.d.ts +0 -68
- package/dist/tools/mcp-catalog.d.ts.map +0 -1
- package/dist/tools/mcp-handler.d.ts +0 -46
- package/dist/tools/mcp-handler.d.ts.map +0 -1
- package/dist/tools/mcp-prepare.d.ts +0 -75
- package/dist/tools/mcp-prepare.d.ts.map +0 -1
- package/dist/tools/mcp-progress.d.ts +0 -46
- package/dist/tools/mcp-progress.d.ts.map +0 -1
- package/dist/tools/mcp-round-policy.d.ts +0 -33
- package/dist/tools/mcp-round-policy.d.ts.map +0 -1
- package/dist/tools/mcp-round.d.ts +0 -61
- package/dist/tools/mcp-round.d.ts.map +0 -1
- package/dist/tools/mcp-stdio-signals.d.ts +0 -33
- package/dist/tools/mcp-stdio-signals.d.ts.map +0 -1
- package/dist/tools/mcp-stdio.d.ts +0 -20
- package/dist/tools/mcp-stdio.d.ts.map +0 -1
- package/dist/tools/mcp-trace.d.ts +0 -12
- package/dist/tools/mcp-trace.d.ts.map +0 -1
- package/dist/tools/mcp.d.ts +0 -152
- package/dist/tools/mcp.d.ts.map +0 -1
- package/dist/tools/mount-download.d.ts +0 -41
- package/dist/tools/mount-download.d.ts.map +0 -1
- package/dist/tools/mount-upload.d.ts +0 -21
- package/dist/tools/mount-upload.d.ts.map +0 -1
- package/dist/tools/mount-wait.d.ts.map +0 -1
- package/dist/tools/native-mcp.d.ts +0 -20
- package/dist/tools/native-mcp.d.ts.map +0 -1
- package/dist/tools/native-result.d.ts.map +0 -1
- package/dist/tools/oauth-metadata.d.ts +0 -28
- package/dist/tools/oauth-metadata.d.ts.map +0 -1
- package/dist/tools/oauth-provider.d.ts +0 -184
- package/dist/tools/oauth-provider.d.ts.map +0 -1
- package/dist/tools/portable-formats.d.ts.map +0 -1
- package/dist/tools/presentation.d.ts +0 -22
- package/dist/tools/presentation.d.ts.map +0 -1
- package/dist/tools/schema.d.ts.map +0 -1
- package/dist/tools/untyped-properties.d.ts.map +0 -1
- package/dist/tools/upload-core.d.ts +0 -4
- package/dist/tools/upload-core.d.ts.map +0 -1
- package/dist/tools/view-file-contract.d.ts.map +0 -1
- package/dist/tools/view-file.d.ts +0 -62
- package/dist/tools/view-file.d.ts.map +0 -1
- package/dist/tools/wait-core.d.ts.map +0 -1
- package/dist/tools-contract.d.ts +0 -29
- package/dist/tools-contract.d.ts.map +0 -1
- package/dist/tools-contract.js +0 -24
- package/dist/tools.d.ts +0 -50
- package/dist/tools.d.ts.map +0 -1
- package/dist/tools.js +0 -2930
- package/dist/tracking-server.d.ts +0 -15
- package/dist/tracking-server.d.ts.map +0 -1
- package/dist/tracking.d.ts +0 -24
- package/dist/tracking.d.ts.map +0 -1
- package/dist/tracking.js +0 -1092
- package/dist/upgrade-cli.d.ts.map +0 -1
- package/dist/upgrade-cli.js +0 -177
- /package/dist/{retained.d.ts → browser/retained.d.ts} +0 -0
- /package/dist/{declaration.d.ts → declaration/declaration.d.ts} +0 -0
- /package/dist/{upgrade-cli.d.ts → entrypoints/bin/upgrade-cli.d.ts} +0 -0
- /package/dist/{tracking-server.js → entrypoints/tracking/server.js} +0 -0
- /package/dist/{google.d.ts → google/google.d.ts} +0 -0
- /package/dist/{index-pq95qkbf.js → index-5jm36zv1.js} +0 -0
- /package/dist/{application → internal}/channel.d.ts +0 -0
- /package/dist/{logger.d.ts → internal/logger.d.ts} +0 -0
- /package/dist/{server → internal}/request.d.ts +0 -0
- /package/dist/{tools → json-schema}/json-schema.d.ts +0 -0
- /package/dist/tools/{async-operation-contract.d.ts → operations/async-operation-contract.d.ts} +0 -0
- /package/dist/tools/{mount-wait.d.ts → operations/mount-wait.d.ts} +0 -0
- /package/dist/tools/{wait-core.d.ts → operations/wait-core.d.ts} +0 -0
- /package/dist/tools/{coerce.d.ts → schema/coerce.d.ts} +0 -0
- /package/dist/tools/{flatten-join.d.ts → schema/flatten-join.d.ts} +0 -0
- /package/dist/tools/{flatten.d.ts → schema/flatten.d.ts} +0 -0
- /package/dist/tools/{portable-formats.d.ts → schema/portable-formats.d.ts} +0 -0
- /package/dist/tools/{schema.d.ts → schema/schema.d.ts} +0 -0
- /package/dist/tools/{untyped-properties.d.ts → schema/untyped-properties.d.ts} +0 -0
- /package/dist/tools/{native-result.d.ts → transfer/native-result.d.ts} +0 -0
- /package/dist/tools/{view-file-contract.d.ts → transfer/view-file-contract.d.ts} +0 -0
package/dist/tools.js
DELETED
|
@@ -1,2930 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ManagedFileError
|
|
3
|
-
} from "./index-actkayzn.js";
|
|
4
|
-
import {
|
|
5
|
-
signJwt,
|
|
6
|
-
verifyPkce
|
|
7
|
-
} from "./index-sr93cwf9.js";
|
|
8
|
-
import"./index-hr4tzbwq.js";
|
|
9
|
-
import {
|
|
10
|
-
DEFAULT_CORS_ALLOW_HEADERS,
|
|
11
|
-
DEFAULT_PROCESS_SIGNALS,
|
|
12
|
-
contractOnlyService,
|
|
13
|
-
defaultSignalSource,
|
|
14
|
-
guardSignalCallback,
|
|
15
|
-
mediaTypeEssence,
|
|
16
|
-
reportSignalError
|
|
17
|
-
} from "./index-cxqhvq21.js";
|
|
18
|
-
import {
|
|
19
|
-
redact
|
|
20
|
-
} from "./index-6kyksz9y.js";
|
|
21
|
-
import {
|
|
22
|
-
buildToolManifest,
|
|
23
|
-
describeToolCatalog,
|
|
24
|
-
mountAgent
|
|
25
|
-
} from "./index-e42wzzz5.js";
|
|
26
|
-
import {
|
|
27
|
-
AgentToolError,
|
|
28
|
-
createLocalStepDurability,
|
|
29
|
-
isAgentToolError
|
|
30
|
-
} from "./index-kw9t5ayn.js";
|
|
31
|
-
import {
|
|
32
|
-
AsyncOperationCancelResultSchema,
|
|
33
|
-
McpAnnotationsSchema,
|
|
34
|
-
McpMediaContentSchema,
|
|
35
|
-
ViewFileErrorSchema,
|
|
36
|
-
ViewFileInputSchema,
|
|
37
|
-
ViewFileOutputSchema,
|
|
38
|
-
createAsyncOperationSnapshotSchema
|
|
39
|
-
} from "./index-4fpa9dy2.js";
|
|
40
|
-
import {
|
|
41
|
-
createToolInvoker
|
|
42
|
-
} from "./index-bx75zwt7.js";
|
|
43
|
-
import {
|
|
44
|
-
WaitTimeoutError,
|
|
45
|
-
createCli,
|
|
46
|
-
defineCliCommand,
|
|
47
|
-
fetchGuarded,
|
|
48
|
-
fetchPinnedDocument,
|
|
49
|
-
readCapped,
|
|
50
|
-
runWaitOperation
|
|
51
|
-
} from "./index-3bmnp41g.js";
|
|
52
|
-
import {
|
|
53
|
-
compareCodepoints,
|
|
54
|
-
serializeCanonicalJson
|
|
55
|
-
} from "./index-0j3vcp5m.js";
|
|
56
|
-
import"./index-sbdmyz75.js";
|
|
57
|
-
import {
|
|
58
|
-
collectToolSurface
|
|
59
|
-
} from "./index-2c2bjw3s.js";
|
|
60
|
-
import {
|
|
61
|
-
argumentsDigest
|
|
62
|
-
} from "./index-a916km3r.js";
|
|
63
|
-
import {
|
|
64
|
-
collectTools,
|
|
65
|
-
createToolRunner,
|
|
66
|
-
formatToolError
|
|
67
|
-
} from "./index-mzvgxp0n.js";
|
|
68
|
-
import {
|
|
69
|
-
ToolExecutionControlError,
|
|
70
|
-
executeToolMethod,
|
|
71
|
-
isToolExecutionControlError,
|
|
72
|
-
parseToolCallArguments,
|
|
73
|
-
toolResultFromError
|
|
74
|
-
} from "./index-yn8remb1.js";
|
|
75
|
-
import {
|
|
76
|
-
getRequestContext,
|
|
77
|
-
getTraceId,
|
|
78
|
-
runWithRequestContext
|
|
79
|
-
} from "./index-tmwcrptx.js";
|
|
80
|
-
import"./index-f9mb610r.js";
|
|
81
|
-
import {
|
|
82
|
-
normalizeError
|
|
83
|
-
} from "./index-e0znv5gn.js";
|
|
84
|
-
import {
|
|
85
|
-
defineContract
|
|
86
|
-
} from "./index-0a349c33.js";
|
|
87
|
-
import"./index-rxfy4cq7.js";
|
|
88
|
-
import {
|
|
89
|
-
ManagedFilePathSchema,
|
|
90
|
-
ManagedFileRefSchema
|
|
91
|
-
} from "./index-6k1937bx.js";
|
|
92
|
-
import {
|
|
93
|
-
resolvePropagationContext
|
|
94
|
-
} from "./index-zcgf3gqf.js";
|
|
95
|
-
import {
|
|
96
|
-
coerceJsonArgs
|
|
97
|
-
} from "./index-7zbps32p.js";
|
|
98
|
-
import {
|
|
99
|
-
createRuntimeToolFactory,
|
|
100
|
-
defineRuntimeTool
|
|
101
|
-
} from "./index-vjpvjqpn.js";
|
|
102
|
-
import {
|
|
103
|
-
PORTABLE_JSON_SCHEMA_FORMATS,
|
|
104
|
-
assertToolName,
|
|
105
|
-
assertUniqueToolName,
|
|
106
|
-
findNonPortableFormats,
|
|
107
|
-
findUntypedProperties,
|
|
108
|
-
flattenToolJsonSchema,
|
|
109
|
-
prepareProjectedMcpTools,
|
|
110
|
-
presentationMetadata,
|
|
111
|
-
staticInputRounds,
|
|
112
|
-
validateMcpRoundPolicy,
|
|
113
|
-
validateResolvedInputRounds
|
|
114
|
-
} from "./index-h9etkkyk.js";
|
|
115
|
-
import {
|
|
116
|
-
toJsonSchema
|
|
117
|
-
} from "./index-cby4ar3v.js";
|
|
118
|
-
import {
|
|
119
|
-
AppError,
|
|
120
|
-
STITCH_ERROR_STATUS
|
|
121
|
-
} from "./index-2vtcmrj9.js";
|
|
122
|
-
import"./index-kzfs85xp.js";
|
|
123
|
-
import {
|
|
124
|
-
isRecord
|
|
125
|
-
} from "./index-77fekveh.js";
|
|
126
|
-
// src/tools/async-operation.ts
|
|
127
|
-
import { z } from "zod";
|
|
128
|
-
// src/tools/native-definition.ts
|
|
129
|
-
function managedNativeIdentity(identity, method) {
|
|
130
|
-
return { ...identity, method };
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// src/tools/define-wait-tool.ts
|
|
134
|
-
function defineWaitTool(config) {
|
|
135
|
-
const renderedMcp = config.render ? {
|
|
136
|
-
mcp: (state) => {
|
|
137
|
-
const rendered = config.render?.(state, false);
|
|
138
|
-
return {
|
|
139
|
-
content: [
|
|
140
|
-
{
|
|
141
|
-
type: "text",
|
|
142
|
-
text: rendered?.text ?? JSON.stringify(state, null, 2)
|
|
143
|
-
}
|
|
144
|
-
]
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
} : undefined;
|
|
148
|
-
const present = renderedMcp || config.present ? { ...renderedMcp, ...config.present } : undefined;
|
|
149
|
-
return defineRuntimeTool({
|
|
150
|
-
name: config.name ?? "wait",
|
|
151
|
-
description: config.description,
|
|
152
|
-
identity: managedNativeIdentity(config.identity, "GET"),
|
|
153
|
-
input: config.input,
|
|
154
|
-
output: config.state,
|
|
155
|
-
transports: config.transports,
|
|
156
|
-
annotations: config.annotations,
|
|
157
|
-
present,
|
|
158
|
-
handler: async (context) => {
|
|
159
|
-
let result;
|
|
160
|
-
try {
|
|
161
|
-
result = await runWaitOperation({
|
|
162
|
-
input: context.input,
|
|
163
|
-
poll: async (input, signal) => config.state.parse(await config.poll(input, { ...context, signal })),
|
|
164
|
-
done: config.done,
|
|
165
|
-
backoff: config.backoff,
|
|
166
|
-
timeoutSec: config.timeoutFromInput?.(context.input) ?? config.defaultTimeout,
|
|
167
|
-
signal: context.signal
|
|
168
|
-
});
|
|
169
|
-
} catch (error) {
|
|
170
|
-
if (error instanceof WaitTimeoutError) {
|
|
171
|
-
throw new AppError("WAIT_TIMEOUT", "Wait timed out before the first snapshot", 408);
|
|
172
|
-
}
|
|
173
|
-
throw error;
|
|
174
|
-
}
|
|
175
|
-
const rendered = config.render?.(result.state, result.timedOut);
|
|
176
|
-
if (result.timedOut) {
|
|
177
|
-
throw new AppError("WAIT_TIMEOUT", rendered?.text ?? "Wait timed out before the operation completed", 408);
|
|
178
|
-
}
|
|
179
|
-
if (rendered?.isError) {
|
|
180
|
-
throw new AppError("WAIT_FAILED", rendered.text, 409);
|
|
181
|
-
}
|
|
182
|
-
return result.state;
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// src/tools/async-operation.ts
|
|
188
|
-
function terminal(snapshot) {
|
|
189
|
-
if (typeof snapshot !== "object" || snapshot === null || !("phase" in snapshot)) {
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
|
-
return snapshot.phase === "succeeded" || snapshot.phase === "failed" || snapshot.phase === "cancelled";
|
|
193
|
-
}
|
|
194
|
-
function succeeded(snapshot) {
|
|
195
|
-
return typeof snapshot === "object" && snapshot !== null && "phase" in snapshot && snapshot.phase === "succeeded";
|
|
196
|
-
}
|
|
197
|
-
function defineAsyncOperation(config) {
|
|
198
|
-
const capabilityName = (capability) => config.names?.[capability] ?? `${config.name}_${capability}`;
|
|
199
|
-
const description = (capability) => config.descriptions?.[capability] ?? `${config.description}: ${capability}`;
|
|
200
|
-
const identity = (capability, method) => ({
|
|
201
|
-
serviceName: config.identity.serviceName,
|
|
202
|
-
action: `${config.identity.action}.${capability}`,
|
|
203
|
-
scope: config.scopes?.[capability] ?? config.identity.scope,
|
|
204
|
-
meta: config.identity.meta,
|
|
205
|
-
method
|
|
206
|
-
});
|
|
207
|
-
const common = (capability) => ({
|
|
208
|
-
name: capabilityName(capability),
|
|
209
|
-
description: description(capability),
|
|
210
|
-
transports: config.transports?.[capability],
|
|
211
|
-
annotations: config.annotations?.[capability] ?? (capability === "start" || capability === "cancel" ? { destructiveHint: true } : undefined)
|
|
212
|
-
});
|
|
213
|
-
const inspect = async (capability, context) => {
|
|
214
|
-
await config.authorize(context.input, capability, context);
|
|
215
|
-
const state = config.state.parse(await config.inspect(context.input, context));
|
|
216
|
-
const snapshot = config.snapshot.parse(await config.classify(state, context));
|
|
217
|
-
return { state, snapshot };
|
|
218
|
-
};
|
|
219
|
-
const start = defineRuntimeTool({
|
|
220
|
-
...common("start"),
|
|
221
|
-
identity: identity("start", "POST"),
|
|
222
|
-
input: config.startInput,
|
|
223
|
-
output: config.id,
|
|
224
|
-
handler: (context) => config.start(context.input, context)
|
|
225
|
-
});
|
|
226
|
-
const status = defineRuntimeTool({
|
|
227
|
-
...common("status"),
|
|
228
|
-
identity: identity("status", "GET"),
|
|
229
|
-
input: config.id,
|
|
230
|
-
output: config.snapshot,
|
|
231
|
-
handler: async (context) => (await inspect("status", context)).snapshot
|
|
232
|
-
});
|
|
233
|
-
const wait = defineWaitTool({
|
|
234
|
-
...common("wait"),
|
|
235
|
-
identity: identity("wait", "GET"),
|
|
236
|
-
input: config.id,
|
|
237
|
-
state: config.snapshot,
|
|
238
|
-
poll: async (_id, context) => (await inspect("wait", context)).snapshot,
|
|
239
|
-
done: terminal,
|
|
240
|
-
backoff: config.backoff,
|
|
241
|
-
defaultTimeout: config.defaultTimeout,
|
|
242
|
-
timeoutFromInput: config.timeoutFromId
|
|
243
|
-
});
|
|
244
|
-
const definitions = { start, status, wait };
|
|
245
|
-
const names = new Set;
|
|
246
|
-
if (config.cancel) {
|
|
247
|
-
const capability = config.cancel;
|
|
248
|
-
definitions.cancel = defineRuntimeTool({
|
|
249
|
-
...common("cancel"),
|
|
250
|
-
identity: identity("cancel", "DELETE"),
|
|
251
|
-
input: config.id,
|
|
252
|
-
output: AsyncOperationCancelResultSchema,
|
|
253
|
-
handler: async (context) => {
|
|
254
|
-
const inspected = await inspect("cancel", context);
|
|
255
|
-
return capability.handler(inspected.state, context);
|
|
256
|
-
}
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
if (config.result) {
|
|
260
|
-
const capability = config.result;
|
|
261
|
-
definitions.result = defineRuntimeTool({
|
|
262
|
-
...common("result"),
|
|
263
|
-
identity: identity("result", "GET"),
|
|
264
|
-
input: config.id,
|
|
265
|
-
output: capability.output,
|
|
266
|
-
handler: async (context) => {
|
|
267
|
-
const inspected = await inspect("result", context);
|
|
268
|
-
if (!succeeded(inspected.snapshot)) {
|
|
269
|
-
throw new AppError("OPERATION_NOT_SUCCEEDED", "Operation result is not available", 409);
|
|
270
|
-
}
|
|
271
|
-
return capability.handler(inspected.state, context);
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
if (config.artifacts) {
|
|
276
|
-
const capability = config.artifacts;
|
|
277
|
-
definitions.artifacts = defineRuntimeTool({
|
|
278
|
-
...common("artifacts"),
|
|
279
|
-
identity: identity("artifacts", "GET"),
|
|
280
|
-
input: config.id,
|
|
281
|
-
output: capability.output,
|
|
282
|
-
handler: async (context) => {
|
|
283
|
-
const inspected = await inspect("artifacts", context);
|
|
284
|
-
if (!succeeded(inspected.snapshot)) {
|
|
285
|
-
throw new AppError("OPERATION_NOT_SUCCEEDED", "Operation artifacts are not available", 409);
|
|
286
|
-
}
|
|
287
|
-
return capability.handler(inspected.state, context);
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
for (const definition of Object.values(definitions)) {
|
|
292
|
-
assertUniqueToolName(definition.name, names.has(definition.name), "in-process tool name");
|
|
293
|
-
names.add(definition.name);
|
|
294
|
-
}
|
|
295
|
-
return {
|
|
296
|
-
...definitions,
|
|
297
|
-
runtimeTools: Object.values(definitions),
|
|
298
|
-
schemas: {
|
|
299
|
-
id: config.id,
|
|
300
|
-
snapshot: config.snapshot,
|
|
301
|
-
cancelResult: AsyncOperationCancelResultSchema
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
function adapterResult(capability, target, schema, value) {
|
|
306
|
-
const parsed = schema.safeParse(value);
|
|
307
|
-
if (!parsed.success) {
|
|
308
|
-
throw new Error(`Async operation adapter for capability "${capability}" returned invalid ${target}`, { cause: parsed.error });
|
|
309
|
-
}
|
|
310
|
-
return parsed.data;
|
|
311
|
-
}
|
|
312
|
-
var NON_WIRE_STABLE_ZOD_TYPES = new Set([
|
|
313
|
-
"catch",
|
|
314
|
-
"default",
|
|
315
|
-
"lazy",
|
|
316
|
-
"pipe",
|
|
317
|
-
"prefault",
|
|
318
|
-
"readonly",
|
|
319
|
-
"success",
|
|
320
|
-
"transform"
|
|
321
|
-
]);
|
|
322
|
-
function hasOverwriteCheck(value) {
|
|
323
|
-
return isRecord(value) && isRecord(value._zod) && isRecord(value._zod.def) && value._zod.def.check === "overwrite";
|
|
324
|
-
}
|
|
325
|
-
function assertWireStableIdSchema(schema, boundary) {
|
|
326
|
-
const visited = new Set;
|
|
327
|
-
const pending = [schema];
|
|
328
|
-
while (pending.length > 0) {
|
|
329
|
-
const value = pending.pop();
|
|
330
|
-
if (typeof value !== "object" || value === null || visited.has(value))
|
|
331
|
-
continue;
|
|
332
|
-
visited.add(value);
|
|
333
|
-
if (value instanceof z.ZodType) {
|
|
334
|
-
const definition = value._zod.def;
|
|
335
|
-
if (NON_WIRE_STABLE_ZOD_TYPES.has(definition.type) || "coerce" in definition && definition.coerce === true || "checks" in definition && Array.isArray(definition.checks) && definition.checks.some(hasOverwriteCheck)) {
|
|
336
|
-
throw new Error(`${boundary} must use a wire-stable ID schema without transforms, coercion, defaults or overwrites; use binding: "adapted" with explicit ID adapters`);
|
|
337
|
-
}
|
|
338
|
-
pending.push(...Object.values(definition));
|
|
339
|
-
continue;
|
|
340
|
-
}
|
|
341
|
-
if (Array.isArray(value)) {
|
|
342
|
-
pending.push(...value);
|
|
343
|
-
continue;
|
|
344
|
-
}
|
|
345
|
-
if (isRecord(value))
|
|
346
|
-
pending.push(...Object.values(value));
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
function defineAsyncOperationContract(config) {
|
|
350
|
-
assertWireStableIdSchema(config.id, "Async operation contract");
|
|
351
|
-
const hasStartOutput = config.startOutput !== undefined;
|
|
352
|
-
const hasIdFromStart = config.idFromStart !== undefined;
|
|
353
|
-
if (hasStartOutput !== hasIdFromStart) {
|
|
354
|
-
throw new Error("Async operation contract startOutput and idFromStart must be configured together");
|
|
355
|
-
}
|
|
356
|
-
const description = (capability) => config.descriptions?.[capability] ?? `${config.description}: ${capability}`;
|
|
357
|
-
const endpoint = (capability, method, path, input, output) => {
|
|
358
|
-
const scope = config.scopes?.[capability];
|
|
359
|
-
const expose = config.expose?.[capability];
|
|
360
|
-
return {
|
|
361
|
-
method,
|
|
362
|
-
path,
|
|
363
|
-
desc: description(capability),
|
|
364
|
-
input,
|
|
365
|
-
output,
|
|
366
|
-
...scope !== undefined && { scope },
|
|
367
|
-
...expose !== undefined && { expose }
|
|
368
|
-
};
|
|
369
|
-
};
|
|
370
|
-
const startOutput = config.startOutput ?? config.id;
|
|
371
|
-
const endpoints = {
|
|
372
|
-
start: endpoint("start", "POST", "/", config.startInput, startOutput),
|
|
373
|
-
status: endpoint("status", "POST", "/status", config.id, config.snapshot),
|
|
374
|
-
wait: endpoint("wait", "POST", "/wait", config.id, config.snapshot)
|
|
375
|
-
};
|
|
376
|
-
const capabilities = {
|
|
377
|
-
start: "start",
|
|
378
|
-
status: "status",
|
|
379
|
-
wait: "wait"
|
|
380
|
-
};
|
|
381
|
-
const schemas = {
|
|
382
|
-
startInput: config.startInput,
|
|
383
|
-
startOutput,
|
|
384
|
-
id: config.id,
|
|
385
|
-
snapshot: config.snapshot,
|
|
386
|
-
cancelResult: AsyncOperationCancelResultSchema
|
|
387
|
-
};
|
|
388
|
-
const inputFor = {
|
|
389
|
-
status: (id) => adapterResult("status", "input", config.id, id),
|
|
390
|
-
wait: (id) => adapterResult("wait", "input", config.id, id)
|
|
391
|
-
};
|
|
392
|
-
if (config.cancel) {
|
|
393
|
-
endpoints.cancel = endpoint("cancel", "POST", "/cancel", config.id, AsyncOperationCancelResultSchema);
|
|
394
|
-
capabilities.cancel = "cancel";
|
|
395
|
-
schemas.cancel = AsyncOperationCancelResultSchema;
|
|
396
|
-
inputFor.cancel = (id) => adapterResult("cancel", "input", config.id, id);
|
|
397
|
-
}
|
|
398
|
-
if (config.result) {
|
|
399
|
-
endpoints.result = endpoint("result", "POST", "/result", config.id, config.result);
|
|
400
|
-
capabilities.result = "result";
|
|
401
|
-
schemas.result = config.result;
|
|
402
|
-
inputFor.result = (id) => adapterResult("result", "input", config.id, id);
|
|
403
|
-
}
|
|
404
|
-
if (config.artifacts) {
|
|
405
|
-
endpoints.artifacts = endpoint("artifacts", "POST", "/artifacts", config.id, config.artifacts);
|
|
406
|
-
capabilities.artifacts = "artifacts";
|
|
407
|
-
schemas.artifacts = config.artifacts;
|
|
408
|
-
inputFor.artifacts = (id) => adapterResult("artifacts", "input", config.id, id);
|
|
409
|
-
}
|
|
410
|
-
const contract = config.scope ? defineContract({ prefix: config.prefix, scope: config.scope }, endpoints) : defineContract({ prefix: config.prefix }, endpoints);
|
|
411
|
-
const applicationStartOutput = config.startOutput;
|
|
412
|
-
const applicationIdFromStart = config.idFromStart;
|
|
413
|
-
const idFromStart = applicationStartOutput && applicationIdFromStart ? (output) => adapterResult("start", "id", config.id, applicationIdFromStart(output)) : (output) => adapterResult("start", "id", config.id, output);
|
|
414
|
-
return {
|
|
415
|
-
contract,
|
|
416
|
-
capabilities,
|
|
417
|
-
schemas,
|
|
418
|
-
adapters: { idFromStart, inputFor }
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
function bindContractAsyncOperation(config) {
|
|
422
|
-
const endpoint = (key) => {
|
|
423
|
-
const found = config.contract.endpoints[key];
|
|
424
|
-
if (!found)
|
|
425
|
-
throw new Error(`Contract async operation method "${key}" not found`);
|
|
426
|
-
return found;
|
|
427
|
-
};
|
|
428
|
-
const start = endpoint(config.capabilities.start);
|
|
429
|
-
const status = endpoint(config.capabilities.status);
|
|
430
|
-
const wait = endpoint(config.capabilities.wait);
|
|
431
|
-
if (!start.output || !status.output || !wait.output) {
|
|
432
|
-
throw new Error("Contract async operation requires outputs for start, status and wait");
|
|
433
|
-
}
|
|
434
|
-
const startOutput = start.output;
|
|
435
|
-
const statusOutput = status.output;
|
|
436
|
-
if (wait.output !== statusOutput) {
|
|
437
|
-
throw new Error('Contract async operation capability "wait" output must reuse the same schema instance as the status output');
|
|
438
|
-
}
|
|
439
|
-
const optionalCapabilities = [
|
|
440
|
-
"cancel",
|
|
441
|
-
"result",
|
|
442
|
-
"artifacts"
|
|
443
|
-
];
|
|
444
|
-
if (config.binding !== "adapted") {
|
|
445
|
-
assertWireStableIdSchema(startOutput, "Direct contract async operation");
|
|
446
|
-
if (status.input !== startOutput || wait.input !== startOutput) {
|
|
447
|
-
const capability = status.input !== startOutput ? "status" : "wait";
|
|
448
|
-
throw new Error(`Contract async operation capability "${capability}" input must reuse the same schema instance as the start output`);
|
|
449
|
-
}
|
|
450
|
-
const inputFor2 = {
|
|
451
|
-
status: (id) => adapterResult("status", "input", startOutput, id),
|
|
452
|
-
wait: (id) => adapterResult("wait", "input", startOutput, id)
|
|
453
|
-
};
|
|
454
|
-
for (const capability of optionalCapabilities) {
|
|
455
|
-
const key = config.capabilities[capability];
|
|
456
|
-
if (!key)
|
|
457
|
-
continue;
|
|
458
|
-
if (endpoint(key).input !== startOutput) {
|
|
459
|
-
throw new Error(`Contract async operation capability "${capability}" input must reuse the same schema instance as the start output`);
|
|
460
|
-
}
|
|
461
|
-
inputFor2[capability] = (id) => adapterResult(capability, "input", startOutput, id);
|
|
462
|
-
}
|
|
463
|
-
return {
|
|
464
|
-
contract: config.contract,
|
|
465
|
-
handlers: config.handlers,
|
|
466
|
-
capabilities: config.capabilities,
|
|
467
|
-
schemas: { id: startOutput, snapshot: statusOutput },
|
|
468
|
-
adapters: {
|
|
469
|
-
idFromStart: (output) => adapterResult("start", "id", startOutput, output),
|
|
470
|
-
inputFor: inputFor2
|
|
471
|
-
}
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
const adapters = config.adapters;
|
|
475
|
-
const idSchema = config.id;
|
|
476
|
-
const adaptedInput = (capability, key, builder) => {
|
|
477
|
-
const input = endpoint(key).input;
|
|
478
|
-
if (!input) {
|
|
479
|
-
throw new Error(`Contract async operation capability "${capability}" requires an input schema`);
|
|
480
|
-
}
|
|
481
|
-
return (id) => adapterResult(capability, "input", input, builder(id));
|
|
482
|
-
};
|
|
483
|
-
const inputFor = {
|
|
484
|
-
status: adaptedInput("status", config.capabilities.status, adapters.inputFor.status),
|
|
485
|
-
wait: adaptedInput("wait", config.capabilities.wait, adapters.inputFor.wait)
|
|
486
|
-
};
|
|
487
|
-
const optionalInput = (capability, key, builder) => {
|
|
488
|
-
if (!key)
|
|
489
|
-
return;
|
|
490
|
-
if (!builder) {
|
|
491
|
-
throw new Error(`Contract async operation capability "${capability}" requires an input adapter`);
|
|
492
|
-
}
|
|
493
|
-
inputFor[capability] = adaptedInput(capability, key, builder);
|
|
494
|
-
};
|
|
495
|
-
optionalInput("cancel", config.capabilities.cancel, "cancel" in adapters.inputFor ? adapters.inputFor.cancel : undefined);
|
|
496
|
-
optionalInput("result", config.capabilities.result, "result" in adapters.inputFor ? adapters.inputFor.result : undefined);
|
|
497
|
-
optionalInput("artifacts", config.capabilities.artifacts, "artifacts" in adapters.inputFor ? adapters.inputFor.artifacts : undefined);
|
|
498
|
-
if (!idSchema) {
|
|
499
|
-
throw new Error("Contract adapted async operation requires an id schema");
|
|
500
|
-
}
|
|
501
|
-
return {
|
|
502
|
-
contract: config.contract,
|
|
503
|
-
handlers: config.handlers,
|
|
504
|
-
capabilities: config.capabilities,
|
|
505
|
-
schemas: { id: idSchema, snapshot: statusOutput },
|
|
506
|
-
adapters: {
|
|
507
|
-
idFromStart: (output) => adapterResult("start", "id", idSchema, adapters.idFromStart(output)),
|
|
508
|
-
inputFor
|
|
509
|
-
}
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
// src/tools/download-core.ts
|
|
513
|
-
import { basename, extname } from "node:path";
|
|
514
|
-
var DEFAULT_MAX_BYTES = 100 * 1024 * 1024;
|
|
515
|
-
var MIME_EXT = {
|
|
516
|
-
"image/png": ".png",
|
|
517
|
-
"image/jpeg": ".jpg",
|
|
518
|
-
"image/webp": ".webp",
|
|
519
|
-
"image/gif": ".gif",
|
|
520
|
-
"video/mp4": ".mp4",
|
|
521
|
-
"video/webm": ".webm",
|
|
522
|
-
"audio/mpeg": ".mp3",
|
|
523
|
-
"audio/wav": ".wav",
|
|
524
|
-
"audio/ogg": ".ogg"
|
|
525
|
-
};
|
|
526
|
-
|
|
527
|
-
class DownloadOperationError extends Error {
|
|
528
|
-
code;
|
|
529
|
-
status;
|
|
530
|
-
constructor(code, message, status) {
|
|
531
|
-
super(message);
|
|
532
|
-
this.code = code;
|
|
533
|
-
this.status = status;
|
|
534
|
-
this.name = "DownloadOperationError";
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
function extensionFor(url, mime) {
|
|
538
|
-
if (MIME_EXT[mime])
|
|
539
|
-
return MIME_EXT[mime];
|
|
540
|
-
try {
|
|
541
|
-
const ext = extname(new URL(url).pathname).toLowerCase();
|
|
542
|
-
if (ext)
|
|
543
|
-
return ext;
|
|
544
|
-
} catch {}
|
|
545
|
-
return ".bin";
|
|
546
|
-
}
|
|
547
|
-
function baseNameFor(url) {
|
|
548
|
-
try {
|
|
549
|
-
const path = new URL(url).pathname;
|
|
550
|
-
return (basename(path, extname(path)) || "download").slice(0, 60);
|
|
551
|
-
} catch {
|
|
552
|
-
return "download";
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
async function runDownloadOperation(config) {
|
|
556
|
-
const res = await fetchGuarded(new URL(config.url), config.allowPrivateHosts ?? false, {
|
|
557
|
-
timeoutMs: config.timeoutMs,
|
|
558
|
-
signal: config.signal
|
|
559
|
-
});
|
|
560
|
-
if (!res.ok) {
|
|
561
|
-
throw new DownloadOperationError("DOWNLOAD_HTTP_ERROR", `HTTP ${res.status}`, 502);
|
|
562
|
-
}
|
|
563
|
-
const mimeType = mediaTypeEssence(res.headers.get("content-type")) || "application/octet-stream";
|
|
564
|
-
const max = config.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
565
|
-
const declared = Number(res.headers.get("content-length") ?? 0);
|
|
566
|
-
if (declared > max) {
|
|
567
|
-
await res.body?.cancel();
|
|
568
|
-
throw new DownloadOperationError("DOWNLOAD_TOO_LARGE", `file exceeds the ${max}-byte cap`, 413);
|
|
569
|
-
}
|
|
570
|
-
const path = config.path ?? `${baseNameFor(config.url)}${extensionFor(config.url, mimeType)}`;
|
|
571
|
-
return config.files.write(path, res.body ?? new Uint8Array, {
|
|
572
|
-
maxBytes: max,
|
|
573
|
-
mediaType: mimeType,
|
|
574
|
-
signal: config.signal
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
// src/tools/managed-file-error.ts
|
|
579
|
-
var SAFE_MANAGED_FILE_MESSAGES = {
|
|
580
|
-
FILE_INVALID_PATH: "Invalid managed-file path",
|
|
581
|
-
FILE_OUTSIDE_ROOT: "Managed-file path escapes its boundary",
|
|
582
|
-
FILE_NOT_FOUND: "Managed file not found",
|
|
583
|
-
FILE_NOT_REGULAR: "Managed path is not a regular file",
|
|
584
|
-
FILE_INSPECTION_REJECTED: "Managed file rejected by inspection",
|
|
585
|
-
FILE_TOO_LARGE: "Managed file exceeds the configured size limit",
|
|
586
|
-
FILE_EXISTS: "Managed file already exists"
|
|
587
|
-
};
|
|
588
|
-
function managedFileAppError(error) {
|
|
589
|
-
if (!(error instanceof ManagedFileError))
|
|
590
|
-
return null;
|
|
591
|
-
switch (error.code) {
|
|
592
|
-
case "FILE_INVALID_PATH":
|
|
593
|
-
case "FILE_OUTSIDE_ROOT":
|
|
594
|
-
case "FILE_NOT_FOUND":
|
|
595
|
-
case "FILE_NOT_REGULAR":
|
|
596
|
-
case "FILE_INSPECTION_REJECTED":
|
|
597
|
-
case "FILE_TOO_LARGE":
|
|
598
|
-
case "FILE_EXISTS":
|
|
599
|
-
return new AppError(error.code, SAFE_MANAGED_FILE_MESSAGES[error.code], STITCH_ERROR_STATUS[error.code]);
|
|
600
|
-
case "FILE_IO_ERROR":
|
|
601
|
-
return null;
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
function normalizeFileToolError(error) {
|
|
605
|
-
return managedFileAppError(error) ?? normalizeError(error);
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
// src/tools/define-download-tool.ts
|
|
609
|
-
function defineDownloadTool(config) {
|
|
610
|
-
return defineRuntimeTool({
|
|
611
|
-
name: config.name ?? "download",
|
|
612
|
-
description: config.description,
|
|
613
|
-
identity: managedNativeIdentity(config.identity, "POST"),
|
|
614
|
-
input: config.input,
|
|
615
|
-
output: ManagedFileRefSchema,
|
|
616
|
-
transports: config.transports,
|
|
617
|
-
annotations: config.annotations,
|
|
618
|
-
present: config.present,
|
|
619
|
-
handler: async (context) => {
|
|
620
|
-
const url = await config.resolveUrl(context.input, context);
|
|
621
|
-
if (!url) {
|
|
622
|
-
throw new AppError("DOWNLOAD_NOT_FOUND", "Nothing to download", 404);
|
|
623
|
-
}
|
|
624
|
-
try {
|
|
625
|
-
return await runDownloadOperation({
|
|
626
|
-
url,
|
|
627
|
-
files: config.files,
|
|
628
|
-
path: config.pathFromInput?.(context.input),
|
|
629
|
-
allowPrivateHosts: config.allowPrivateHosts,
|
|
630
|
-
maxBytes: config.maxBytes,
|
|
631
|
-
timeoutMs: config.timeoutMs,
|
|
632
|
-
signal: context.signal
|
|
633
|
-
});
|
|
634
|
-
} catch (error) {
|
|
635
|
-
if (error instanceof DownloadOperationError) {
|
|
636
|
-
throw new AppError(error.code, `Download failed: ${error.message}`, error.status);
|
|
637
|
-
}
|
|
638
|
-
const managedError = managedFileAppError(error);
|
|
639
|
-
if (managedError)
|
|
640
|
-
throw managedError;
|
|
641
|
-
throw error;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
});
|
|
645
|
-
}
|
|
646
|
-
// src/tools/define-upload-tool.ts
|
|
647
|
-
import { z as z2 } from "zod";
|
|
648
|
-
|
|
649
|
-
// src/tools/upload-core.ts
|
|
650
|
-
function runUploadOperation(files, path, upload, signal) {
|
|
651
|
-
signal?.throwIfAborted();
|
|
652
|
-
return files.read(path, { signal }).then((source) => upload(source, signal));
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
// src/tools/define-upload-tool.ts
|
|
656
|
-
var UploadToolInputSchema = z2.object({
|
|
657
|
-
path: ManagedFilePathSchema.describe("Path relative to the configured file boundary")
|
|
658
|
-
});
|
|
659
|
-
function defineUploadTool(config) {
|
|
660
|
-
return defineRuntimeTool({
|
|
661
|
-
name: config.name ?? "upload",
|
|
662
|
-
description: config.description,
|
|
663
|
-
identity: managedNativeIdentity(config.identity, "POST"),
|
|
664
|
-
input: UploadToolInputSchema,
|
|
665
|
-
output: config.output,
|
|
666
|
-
transports: config.transports,
|
|
667
|
-
annotations: config.annotations,
|
|
668
|
-
present: config.present,
|
|
669
|
-
handler: async (context) => {
|
|
670
|
-
try {
|
|
671
|
-
return await runUploadOperation(config.files, context.input.path, (source) => config.upload(source, context), context.signal);
|
|
672
|
-
} catch (error) {
|
|
673
|
-
const managedError = managedFileAppError(error);
|
|
674
|
-
if (managedError)
|
|
675
|
-
throw managedError;
|
|
676
|
-
throw error;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
});
|
|
680
|
-
}
|
|
681
|
-
// src/tools/view-file.ts
|
|
682
|
-
import { extname as extname2 } from "node:path";
|
|
683
|
-
var MAX_INLINE_BYTES = 20 * 1024 * 1024;
|
|
684
|
-
var EXT_MIME = {
|
|
685
|
-
".png": "image/png",
|
|
686
|
-
".jpg": "image/jpeg",
|
|
687
|
-
".jpeg": "image/jpeg",
|
|
688
|
-
".gif": "image/gif",
|
|
689
|
-
".webp": "image/webp",
|
|
690
|
-
".mp3": "audio/mpeg",
|
|
691
|
-
".wav": "audio/wav",
|
|
692
|
-
".ogg": "audio/ogg",
|
|
693
|
-
".m4a": "audio/mp4",
|
|
694
|
-
".mp4": "video/mp4",
|
|
695
|
-
".webm": "video/webm",
|
|
696
|
-
".mov": "video/quicktime"
|
|
697
|
-
};
|
|
698
|
-
async function fetchSource(pathOrUrl, options, maxBytes) {
|
|
699
|
-
const extMime = EXT_MIME[extname2(pathOrUrl).toLowerCase()];
|
|
700
|
-
if (pathOrUrl.startsWith("http://") || pathOrUrl.startsWith("https://")) {
|
|
701
|
-
const url = new URL(pathOrUrl);
|
|
702
|
-
const res = await fetchGuarded(url, options.allowPrivateHosts ?? false, {
|
|
703
|
-
timeoutMs: options.timeoutMs,
|
|
704
|
-
signal: options.signal
|
|
705
|
-
});
|
|
706
|
-
if (!res.ok)
|
|
707
|
-
throw new AppError("VIEW_HTTP_ERROR", `HTTP ${res.status}`, 502);
|
|
708
|
-
const headerMime = mediaTypeEssence(res.headers.get("content-type"));
|
|
709
|
-
const mimeType = headerMime || extMime || "application/octet-stream";
|
|
710
|
-
if (mimeType.startsWith("video/")) {
|
|
711
|
-
await res.body?.cancel();
|
|
712
|
-
return { video: true, mimeType, bytesRead: 0 };
|
|
713
|
-
}
|
|
714
|
-
const declared = Number(res.headers.get("content-length") ?? 0);
|
|
715
|
-
if (declared > maxBytes) {
|
|
716
|
-
await res.body?.cancel();
|
|
717
|
-
return { tooLarge: true, mimeType, bytesRead: 0 };
|
|
718
|
-
}
|
|
719
|
-
const buffer = await readCapped(res, maxBytes);
|
|
720
|
-
return buffer ? { buffer, mimeType, bytesRead: buffer.length } : { tooLarge: true, mimeType, bytesRead: maxBytes };
|
|
721
|
-
}
|
|
722
|
-
if (!options.files) {
|
|
723
|
-
throw new AppError("FILE_INVALID_PATH", "local file paths are disabled — set files to allow them", 400);
|
|
724
|
-
}
|
|
725
|
-
options.signal?.throwIfAborted();
|
|
726
|
-
if (!extMime) {
|
|
727
|
-
throw new AppError("FILE_INSPECTION_REJECTED", "refusing to read a non-media file", 422);
|
|
728
|
-
}
|
|
729
|
-
try {
|
|
730
|
-
const source = await options.files.read(pathOrUrl, {
|
|
731
|
-
maxBytes,
|
|
732
|
-
signal: options.signal
|
|
733
|
-
});
|
|
734
|
-
const buffer = Buffer.from(source.bytes);
|
|
735
|
-
return {
|
|
736
|
-
buffer,
|
|
737
|
-
mimeType: source.ref.mediaType ?? extMime,
|
|
738
|
-
bytesRead: buffer.length
|
|
739
|
-
};
|
|
740
|
-
} catch (error) {
|
|
741
|
-
if (error instanceof ManagedFileError && error.code === "FILE_TOO_LARGE") {
|
|
742
|
-
return { tooLarge: true, mimeType: extMime, bytesRead: maxBytes };
|
|
743
|
-
}
|
|
744
|
-
throw error;
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
async function resolveMediaWithinBudget(pathOrUrl, options, maxBytes) {
|
|
748
|
-
if (maxBytes <= 0) {
|
|
749
|
-
return {
|
|
750
|
-
content: [
|
|
751
|
-
{ type: "text", text: `[media] total inline budget exhausted — ${pathOrUrl}` }
|
|
752
|
-
],
|
|
753
|
-
bytes: 0
|
|
754
|
-
};
|
|
755
|
-
}
|
|
756
|
-
const extMime = EXT_MIME[extname2(pathOrUrl).toLowerCase()];
|
|
757
|
-
if (extMime?.startsWith("video/")) {
|
|
758
|
-
return {
|
|
759
|
-
content: [{ type: "text", text: `[video] ${extMime} — ${pathOrUrl}` }],
|
|
760
|
-
bytes: 0
|
|
761
|
-
};
|
|
762
|
-
}
|
|
763
|
-
const result = await fetchSource(pathOrUrl, options, maxBytes);
|
|
764
|
-
if ("video" in result) {
|
|
765
|
-
return {
|
|
766
|
-
content: [{ type: "text", text: `[video] ${result.mimeType} — ${pathOrUrl}` }],
|
|
767
|
-
bytes: result.bytesRead
|
|
768
|
-
};
|
|
769
|
-
}
|
|
770
|
-
if ("tooLarge" in result) {
|
|
771
|
-
return {
|
|
772
|
-
content: [
|
|
773
|
-
{ type: "text", text: `[${result.mimeType}] too large to inline — ${pathOrUrl}` }
|
|
774
|
-
],
|
|
775
|
-
bytes: result.bytesRead
|
|
776
|
-
};
|
|
777
|
-
}
|
|
778
|
-
const { buffer, mimeType } = result;
|
|
779
|
-
const sizeKb = (buffer.length / 1024).toFixed(0);
|
|
780
|
-
if (mimeType.startsWith("image/")) {
|
|
781
|
-
return {
|
|
782
|
-
content: [
|
|
783
|
-
{
|
|
784
|
-
type: "image",
|
|
785
|
-
data: buffer.toString("base64"),
|
|
786
|
-
mimeType,
|
|
787
|
-
annotations: { audience: ["user", "assistant"], priority: 0.9 }
|
|
788
|
-
},
|
|
789
|
-
{ type: "text", text: `[image] ${mimeType}, ${sizeKb}KB` }
|
|
790
|
-
],
|
|
791
|
-
bytes: buffer.length
|
|
792
|
-
};
|
|
793
|
-
}
|
|
794
|
-
if (mimeType.startsWith("audio/")) {
|
|
795
|
-
return {
|
|
796
|
-
content: [
|
|
797
|
-
{
|
|
798
|
-
type: "audio",
|
|
799
|
-
data: buffer.toString("base64"),
|
|
800
|
-
mimeType,
|
|
801
|
-
annotations: { audience: ["user", "assistant"], priority: 0.9 }
|
|
802
|
-
},
|
|
803
|
-
{ type: "text", text: `[audio] ${mimeType}, ${sizeKb}KB` }
|
|
804
|
-
],
|
|
805
|
-
bytes: buffer.length
|
|
806
|
-
};
|
|
807
|
-
}
|
|
808
|
-
return {
|
|
809
|
-
content: [{ type: "text", text: `[${mimeType}] ${sizeKb}KB — ${pathOrUrl}` }],
|
|
810
|
-
bytes: buffer.length
|
|
811
|
-
};
|
|
812
|
-
}
|
|
813
|
-
async function resolveMedia(pathOrUrl, options = {}) {
|
|
814
|
-
return (await resolveMediaWithinBudget(pathOrUrl, options, MAX_INLINE_BYTES)).content;
|
|
815
|
-
}
|
|
816
|
-
async function runViewFileOperation(paths, options = {}, signal) {
|
|
817
|
-
const list = Array.isArray(paths) ? paths : [paths];
|
|
818
|
-
const content = [];
|
|
819
|
-
const errors = [];
|
|
820
|
-
let remainingBytes = MAX_INLINE_BYTES;
|
|
821
|
-
for (const pathOrUrl of list) {
|
|
822
|
-
signal?.throwIfAborted();
|
|
823
|
-
try {
|
|
824
|
-
const resolved = await resolveMediaWithinBudget(pathOrUrl, { ...options, signal }, remainingBytes);
|
|
825
|
-
remainingBytes -= resolved.bytes;
|
|
826
|
-
content.push(...resolved.content);
|
|
827
|
-
} catch (error) {
|
|
828
|
-
if (signal?.aborted)
|
|
829
|
-
throw signal.reason ?? error;
|
|
830
|
-
const message = normalizeFileToolError(error).message;
|
|
831
|
-
errors.push({ path: pathOrUrl, message });
|
|
832
|
-
content.push({ type: "text", text: `[${pathOrUrl}] Error: ${message}` });
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
return ViewFileOutputSchema.parse({ content, errors });
|
|
836
|
-
}
|
|
837
|
-
function mountViewFile(server, options = {}) {
|
|
838
|
-
server.registerTool("view_file", {
|
|
839
|
-
description: "View media (image, audio, video) by URL or local path — returns it as content you can SEE / HEAR. Pass several paths to view multiple files at once. Use it on a generation `output` url to inspect the result.",
|
|
840
|
-
inputSchema: ViewFileInputSchema.shape,
|
|
841
|
-
annotations: { title: "View Media", readOnlyHint: true, idempotentHint: true }
|
|
842
|
-
}, async (args) => {
|
|
843
|
-
const result = await runViewFileOperation(args.paths, options);
|
|
844
|
-
return { content: result.content };
|
|
845
|
-
});
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
// src/tools/define-view-file-tool.ts
|
|
849
|
-
function defineViewFileTool(config) {
|
|
850
|
-
const defaults = {
|
|
851
|
-
mcp: (output) => ({ content: output.content }),
|
|
852
|
-
agent: (output) => ({
|
|
853
|
-
type: "content",
|
|
854
|
-
value: output.content.map((part) => {
|
|
855
|
-
if (part.type === "text")
|
|
856
|
-
return part;
|
|
857
|
-
return {
|
|
858
|
-
type: "file",
|
|
859
|
-
data: { type: "data", data: part.data },
|
|
860
|
-
mediaType: part.mimeType
|
|
861
|
-
};
|
|
862
|
-
})
|
|
863
|
-
})
|
|
864
|
-
};
|
|
865
|
-
return defineRuntimeTool({
|
|
866
|
-
name: config.name ?? "view_file",
|
|
867
|
-
description: config.description,
|
|
868
|
-
identity: managedNativeIdentity(config.identity, "GET"),
|
|
869
|
-
input: ViewFileInputSchema,
|
|
870
|
-
output: ViewFileOutputSchema,
|
|
871
|
-
transports: config.transports,
|
|
872
|
-
annotations: config.annotations ?? {
|
|
873
|
-
title: "View Media",
|
|
874
|
-
readOnlyHint: true,
|
|
875
|
-
idempotentHint: true
|
|
876
|
-
},
|
|
877
|
-
present: { ...defaults, ...config.present },
|
|
878
|
-
handler: (context) => runViewFileOperation(context.input.paths, {
|
|
879
|
-
files: config.files,
|
|
880
|
-
allowPrivateHosts: config.allowPrivateHosts,
|
|
881
|
-
timeoutMs: config.timeoutMs
|
|
882
|
-
}, context.signal)
|
|
883
|
-
});
|
|
884
|
-
}
|
|
885
|
-
// src/tools/lifecycle.ts
|
|
886
|
-
function composeToolLifecycle(...hooks) {
|
|
887
|
-
return {
|
|
888
|
-
beforeHandle: async (ctx, endpoint) => {
|
|
889
|
-
for (const hook of hooks)
|
|
890
|
-
await hook?.beforeHandle?.(ctx, endpoint);
|
|
891
|
-
},
|
|
892
|
-
afterHandle: async (ctx, result, endpoint) => {
|
|
893
|
-
let current = result;
|
|
894
|
-
for (const hook of hooks) {
|
|
895
|
-
const transformed = await hook?.afterHandle?.(ctx, current, endpoint);
|
|
896
|
-
if (transformed !== undefined)
|
|
897
|
-
current = transformed;
|
|
898
|
-
}
|
|
899
|
-
return current;
|
|
900
|
-
}
|
|
901
|
-
};
|
|
902
|
-
}
|
|
903
|
-
// src/tools/list-names.ts
|
|
904
|
-
var TOOL_TRANSPORTS = ["MCP", "AGENT", "CLI"];
|
|
905
|
-
function listToolNames(surface) {
|
|
906
|
-
const entries = new Map;
|
|
907
|
-
for (const transport of TOOL_TRANSPORTS) {
|
|
908
|
-
for (const entry of collectToolSurface({
|
|
909
|
-
surface,
|
|
910
|
-
transport,
|
|
911
|
-
assertNames: false,
|
|
912
|
-
assertUniqueNames: false
|
|
913
|
-
})) {
|
|
914
|
-
const id = `${entry.kind}\x00${entry.service}\x00${entry.action}`;
|
|
915
|
-
const existing = entries.get(id);
|
|
916
|
-
if (existing) {
|
|
917
|
-
existing.transports.push(transport);
|
|
918
|
-
} else {
|
|
919
|
-
entries.set(id, {
|
|
920
|
-
kind: entry.kind,
|
|
921
|
-
name: entry.mountable.name,
|
|
922
|
-
service: entry.service,
|
|
923
|
-
method: entry.action,
|
|
924
|
-
transports: [transport]
|
|
925
|
-
});
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
return [...entries.values()].sort((a, b) => a.name.localeCompare(b.name) || a.service.localeCompare(b.service));
|
|
930
|
-
}
|
|
931
|
-
function listContractToolNames(contracts) {
|
|
932
|
-
return listToolNames({ services: contracts.map(contractOnlyService) });
|
|
933
|
-
}
|
|
934
|
-
// src/tools/mcp.ts
|
|
935
|
-
import {
|
|
936
|
-
createRequestStateCodec,
|
|
937
|
-
McpServer
|
|
938
|
-
} from "@modelcontextprotocol/server";
|
|
939
|
-
import { z as z5 } from "zod";
|
|
940
|
-
|
|
941
|
-
// src/tools/mcp-app.ts
|
|
942
|
-
import { readFileSync } from "node:fs";
|
|
943
|
-
import { fileURLToPath } from "node:url";
|
|
944
|
-
var RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
|
|
945
|
-
var EXT_APPS_BUNDLE_PLACEHOLDER = "/*__EXT_APPS_BUNDLE__*/";
|
|
946
|
-
function inlineMcpAppBundle(html) {
|
|
947
|
-
if (!html.includes(EXT_APPS_BUNDLE_PLACEHOLDER))
|
|
948
|
-
return html;
|
|
949
|
-
let bundlePath;
|
|
950
|
-
try {
|
|
951
|
-
bundlePath = fileURLToPath(import.meta.resolve("@modelcontextprotocol/ext-apps/app-with-deps"));
|
|
952
|
-
} catch {
|
|
953
|
-
throw new Error("[stitchkit] inlineMcpAppBundle: '@modelcontextprotocol/ext-apps' is not installed. " + "Add it as a dependency to serve MCP App widgets.");
|
|
954
|
-
}
|
|
955
|
-
const bundle = readFileSync(bundlePath, "utf8").replace(/export\{([^}]+)\};?\s*$/, (_match, body) => `globalThis.ExtApps={${body.split(",").map((pair) => {
|
|
956
|
-
const [local, exported] = pair.split(" as ").map((s) => s.trim());
|
|
957
|
-
return `${exported ?? local}:${local}`;
|
|
958
|
-
}).join(",")}};`);
|
|
959
|
-
return html.replace(EXT_APPS_BUNDLE_PLACEHOLDER, () => bundle);
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
// src/tools/mcp-catalog.ts
|
|
963
|
-
import { createHash } from "node:crypto";
|
|
964
|
-
var MCP_CATALOG_META_KEY = "stitchkit/catalog";
|
|
965
|
-
var stampCache = new WeakMap;
|
|
966
|
-
function toolFingerprint(descriptor) {
|
|
967
|
-
const { mountable } = descriptor;
|
|
968
|
-
return {
|
|
969
|
-
name: mountable.name,
|
|
970
|
-
description: mountable.method.desc,
|
|
971
|
-
input: descriptor.inputSchema,
|
|
972
|
-
output: descriptor.outputSchema ? toJsonSchema(descriptor.outputSchema, "output", "any") : null,
|
|
973
|
-
annotations: mountable.method.annotations ?? null
|
|
974
|
-
};
|
|
975
|
-
}
|
|
976
|
-
function mcpCatalogStamp(surface) {
|
|
977
|
-
const cached = stampCache.get(surface);
|
|
978
|
-
if (cached)
|
|
979
|
-
return cached;
|
|
980
|
-
const descriptors = [
|
|
981
|
-
...surface.contractTools,
|
|
982
|
-
...surface.runtimeTools.map((entry) => entry.descriptor)
|
|
983
|
-
].sort((left, right) => compareCodepoints(left.mountable.name, right.mountable.name));
|
|
984
|
-
const bytes = serializeCanonicalJson(descriptors.map(toolFingerprint));
|
|
985
|
-
const stamp = {
|
|
986
|
-
digest: createHash("sha256").update(bytes).digest("hex").slice(0, 16),
|
|
987
|
-
tools: descriptors.length
|
|
988
|
-
};
|
|
989
|
-
stampCache.set(surface, stamp);
|
|
990
|
-
return stamp;
|
|
991
|
-
}
|
|
992
|
-
function mcpCatalogMeta(stamp) {
|
|
993
|
-
return { [MCP_CATALOG_META_KEY]: { ...stamp } };
|
|
994
|
-
}
|
|
995
|
-
function readMcpCatalogStamp(meta) {
|
|
996
|
-
if (!isRecord(meta))
|
|
997
|
-
return null;
|
|
998
|
-
const value = meta[MCP_CATALOG_META_KEY];
|
|
999
|
-
if (!isRecord(value))
|
|
1000
|
-
return null;
|
|
1001
|
-
const { digest, tools } = value;
|
|
1002
|
-
if (typeof digest !== "string" || digest.length === 0)
|
|
1003
|
-
return null;
|
|
1004
|
-
if (typeof tools !== "number" || !Number.isInteger(tools) || tools < 0)
|
|
1005
|
-
return null;
|
|
1006
|
-
return { digest, tools };
|
|
1007
|
-
}
|
|
1008
|
-
function stampToolRegistration(config, stamp) {
|
|
1009
|
-
if (!stamp)
|
|
1010
|
-
return config;
|
|
1011
|
-
return { ...config, _meta: { ...config._meta, ...mcpCatalogMeta(stamp) } };
|
|
1012
|
-
}
|
|
1013
|
-
function stampToolResult(result, stamp) {
|
|
1014
|
-
if (!stamp)
|
|
1015
|
-
return result;
|
|
1016
|
-
return { ...result, _meta: { ...result._meta, ...mcpCatalogMeta(stamp) } };
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
// src/tools/mcp-prepare.ts
|
|
1020
|
-
function textBlock(text) {
|
|
1021
|
-
return [{ type: "text", text }];
|
|
1022
|
-
}
|
|
1023
|
-
function formatMcpResult(result, mode, toolName, errorHint) {
|
|
1024
|
-
if (result.ok) {
|
|
1025
|
-
if (mode === "none")
|
|
1026
|
-
return { content: [] };
|
|
1027
|
-
let serialized;
|
|
1028
|
-
try {
|
|
1029
|
-
serialized = JSON.stringify(result.data, null, 2);
|
|
1030
|
-
} catch {
|
|
1031
|
-
serialized = undefined;
|
|
1032
|
-
}
|
|
1033
|
-
if (serialized === undefined) {
|
|
1034
|
-
const safe = redact(result.data, { sensitiveKeys: /(?!)/ });
|
|
1035
|
-
return { content: textBlock(JSON.stringify(safe, null, 2)), structuredContent: safe };
|
|
1036
|
-
}
|
|
1037
|
-
return { content: textBlock(serialized), structuredContent: result.data };
|
|
1038
|
-
}
|
|
1039
|
-
return {
|
|
1040
|
-
content: textBlock(JSON.stringify(formatToolError(result, toolName, errorHint), null, 2)),
|
|
1041
|
-
isError: true
|
|
1042
|
-
};
|
|
1043
|
-
}
|
|
1044
|
-
function prepareMcpSurface(services, config = {}) {
|
|
1045
|
-
const serviceList = Array.isArray(services) ? services : [services];
|
|
1046
|
-
const tools = serviceList.flatMap((service) => collectTools(service, "MCP", config));
|
|
1047
|
-
return prepareMcpTools(tools, config);
|
|
1048
|
-
}
|
|
1049
|
-
function prepareMcpTools(tools, config = {}) {
|
|
1050
|
-
const prepared = prepareProjectedMcpTools(tools.map((mountable) => ({
|
|
1051
|
-
tool: mountable,
|
|
1052
|
-
name: mountable.name,
|
|
1053
|
-
...mountable.method.paramsSchema !== undefined && {
|
|
1054
|
-
paramsSchema: mountable.method.paramsSchema
|
|
1055
|
-
},
|
|
1056
|
-
...mountable.method.inputSchema !== undefined && {
|
|
1057
|
-
inputSchema: mountable.method.inputSchema
|
|
1058
|
-
},
|
|
1059
|
-
...mountable.method.outputSchema !== undefined && {
|
|
1060
|
-
outputSchema: mountable.method.outputSchema
|
|
1061
|
-
},
|
|
1062
|
-
shouldExtend: mountable.shouldExtend,
|
|
1063
|
-
...mountable.method.mcp !== undefined && { mcp: mountable.method.mcp }
|
|
1064
|
-
})), config).map((entry) => {
|
|
1065
|
-
Object.freeze(entry.tool);
|
|
1066
|
-
return Object.freeze({
|
|
1067
|
-
mountable: entry.tool,
|
|
1068
|
-
inputSchema: entry.inputSchema,
|
|
1069
|
-
...entry.outputSchema !== undefined && { outputSchema: entry.outputSchema },
|
|
1070
|
-
outputMode: entry.outputSchema === undefined ? "none" : "direct"
|
|
1071
|
-
});
|
|
1072
|
-
});
|
|
1073
|
-
return Object.freeze(prepared);
|
|
1074
|
-
}
|
|
1075
|
-
function prepareMcpServerSurface(surface, config = {}) {
|
|
1076
|
-
const contractMountables = [];
|
|
1077
|
-
const definitions = [];
|
|
1078
|
-
const runtimeMountables = [];
|
|
1079
|
-
for (const entry of collectToolSurface({
|
|
1080
|
-
surface,
|
|
1081
|
-
transport: "MCP",
|
|
1082
|
-
extend: config.extend,
|
|
1083
|
-
flattenUnionInput: config.flattenUnionInput
|
|
1084
|
-
})) {
|
|
1085
|
-
if (entry.kind === "contract") {
|
|
1086
|
-
contractMountables.push(entry.mountable);
|
|
1087
|
-
} else {
|
|
1088
|
-
definitions.push(entry.definition);
|
|
1089
|
-
runtimeMountables.push(entry.mountable);
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
const contractTools = prepareMcpTools(contractMountables, config);
|
|
1093
|
-
const runtimeDescriptors = prepareMcpTools(runtimeMountables, {
|
|
1094
|
-
schemaValidation: config.schemaValidation,
|
|
1095
|
-
logger: config.logger,
|
|
1096
|
-
multiRound: config.multiRound
|
|
1097
|
-
});
|
|
1098
|
-
const descriptorsByName = new Map(runtimeDescriptors.map((descriptor) => [descriptor.mountable.name, descriptor]));
|
|
1099
|
-
const runtimeTools = [];
|
|
1100
|
-
for (const definition of definitions) {
|
|
1101
|
-
const descriptor = descriptorsByName.get(definition.name);
|
|
1102
|
-
if (descriptor)
|
|
1103
|
-
runtimeTools.push(Object.freeze({ definition, descriptor }));
|
|
1104
|
-
}
|
|
1105
|
-
return Object.freeze({ contractTools, runtimeTools: Object.freeze(runtimeTools) });
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
// src/tools/mcp-round.ts
|
|
1109
|
-
import {
|
|
1110
|
-
acceptedContent,
|
|
1111
|
-
CLIENT_INFO_META_KEY,
|
|
1112
|
-
inputRequired,
|
|
1113
|
-
inputResponse,
|
|
1114
|
-
PROTOCOL_VERSION_META_KEY
|
|
1115
|
-
} from "@modelcontextprotocol/server";
|
|
1116
|
-
import { z as z3 } from "zod";
|
|
1117
|
-
|
|
1118
|
-
// src/tools/mcp-progress.ts
|
|
1119
|
-
function mcpProgressToken(context) {
|
|
1120
|
-
const token = context.mcpReq._meta?.progressToken;
|
|
1121
|
-
return typeof token === "string" || typeof token === "number" ? token : undefined;
|
|
1122
|
-
}
|
|
1123
|
-
function createMcpProgressReporter(context) {
|
|
1124
|
-
const token = mcpProgressToken(context);
|
|
1125
|
-
if (token === undefined)
|
|
1126
|
-
return async () => {
|
|
1127
|
-
return;
|
|
1128
|
-
};
|
|
1129
|
-
let sent = 0;
|
|
1130
|
-
let highWater = 0;
|
|
1131
|
-
return async (update) => {
|
|
1132
|
-
sent += 1;
|
|
1133
|
-
const value = update.progress ?? Math.max(sent, highWater + 1);
|
|
1134
|
-
highWater = Math.max(highWater, value);
|
|
1135
|
-
try {
|
|
1136
|
-
await context.mcpReq.notify({
|
|
1137
|
-
method: "notifications/progress",
|
|
1138
|
-
params: {
|
|
1139
|
-
progressToken: token,
|
|
1140
|
-
progress: value,
|
|
1141
|
-
...update.total !== undefined && { total: update.total },
|
|
1142
|
-
...update.message !== undefined && { message: update.message }
|
|
1143
|
-
}
|
|
1144
|
-
});
|
|
1145
|
-
} catch {}
|
|
1146
|
-
};
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
|
-
// src/tools/mcp-round.ts
|
|
1150
|
-
function transportContext(context, toolName, outcome, round) {
|
|
1151
|
-
const protocolVersionValue = isRecord(context.mcpReq.envelope) ? Reflect.get(context.mcpReq.envelope, PROTOCOL_VERSION_META_KEY) : undefined;
|
|
1152
|
-
const protocolVersion = typeof protocolVersionValue === "string" ? protocolVersionValue : undefined;
|
|
1153
|
-
const clientInfoValue = isRecord(context.mcpReq.envelope) ? Reflect.get(context.mcpReq.envelope, CLIENT_INFO_META_KEY) : undefined;
|
|
1154
|
-
const clientInfo = isRecord(clientInfoValue) && typeof clientInfoValue.name === "string" && typeof clientInfoValue.version === "string" ? { name: clientInfoValue.name, version: clientInfoValue.version } : undefined;
|
|
1155
|
-
const token = mcpProgressToken(context);
|
|
1156
|
-
return {
|
|
1157
|
-
signal: context.mcpReq.signal,
|
|
1158
|
-
mcp: {
|
|
1159
|
-
era: context.mcpReq.envelope ? "modern" : "legacy",
|
|
1160
|
-
method: context.mcpReq.method,
|
|
1161
|
-
toolName,
|
|
1162
|
-
...protocolVersion !== undefined && { protocolVersion },
|
|
1163
|
-
...clientInfo !== undefined && { clientInfo },
|
|
1164
|
-
...outcome !== undefined && { outcome },
|
|
1165
|
-
...round !== undefined && { round },
|
|
1166
|
-
...token !== undefined && { progressToken: token }
|
|
1167
|
-
},
|
|
1168
|
-
reportProgress: createMcpProgressReporter(context)
|
|
1169
|
-
};
|
|
1170
|
-
}
|
|
1171
|
-
function operationIdentity(tool) {
|
|
1172
|
-
return {
|
|
1173
|
-
toolName: tool.name,
|
|
1174
|
-
serviceName: tool.method.serviceName,
|
|
1175
|
-
action: tool.method.key,
|
|
1176
|
-
method: tool.method.method,
|
|
1177
|
-
...tool.method.scope !== undefined && { scope: tool.method.scope }
|
|
1178
|
-
};
|
|
1179
|
-
}
|
|
1180
|
-
function sameIdentity(left, right) {
|
|
1181
|
-
return left.toolName === right.toolName && left.serviceName === right.serviceName && left.action === right.action && left.method === right.method && left.scope === right.scope;
|
|
1182
|
-
}
|
|
1183
|
-
async function runRoundSuccess(tool, rawArgs, runTool, context) {
|
|
1184
|
-
return runTool({
|
|
1185
|
-
...tool,
|
|
1186
|
-
method: {
|
|
1187
|
-
...tool.method,
|
|
1188
|
-
outputSchema: undefined,
|
|
1189
|
-
handler: () => {
|
|
1190
|
-
return;
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
}, rawArgs, context);
|
|
1194
|
-
}
|
|
1195
|
-
async function runRoundFailure(tool, rawArgs, runTool, context, code, message) {
|
|
1196
|
-
return runTool({
|
|
1197
|
-
...tool,
|
|
1198
|
-
method: {
|
|
1199
|
-
...tool.method,
|
|
1200
|
-
outputSchema: undefined,
|
|
1201
|
-
handler: () => {
|
|
1202
|
-
throw new AppError(code, message, 400);
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
}, rawArgs, context);
|
|
1206
|
-
}
|
|
1207
|
-
async function failedResolution(options) {
|
|
1208
|
-
const result = await runRoundFailure(options.tool, options.rawArgs, options.runTool, options.context, options.code, options.message);
|
|
1209
|
-
return { kind: "response", response: options.formatFailure(result) };
|
|
1210
|
-
}
|
|
1211
|
-
function roundPlanDigest(requests) {
|
|
1212
|
-
return argumentsDigest({
|
|
1213
|
-
plan: requests.map((request) => ({
|
|
1214
|
-
key: request.key,
|
|
1215
|
-
message: request.message,
|
|
1216
|
-
schema: z3.toJSONSchema(request.schema, { io: "input", unrepresentable: "any" })
|
|
1217
|
-
}))
|
|
1218
|
-
});
|
|
1219
|
-
}
|
|
1220
|
-
async function resolveRequests(options, policy) {
|
|
1221
|
-
const declared = staticInputRounds(policy);
|
|
1222
|
-
if (declared)
|
|
1223
|
-
return { requests: declared, guarded: false };
|
|
1224
|
-
const parsed = parseToolCallArguments(options.tool.method, options.rawArgs, options.coerceJsonArgs ?? true);
|
|
1225
|
-
if (!parsed.ok) {
|
|
1226
|
-
return { requests: [], guarded: false };
|
|
1227
|
-
}
|
|
1228
|
-
const resolver = policy.inputRequired;
|
|
1229
|
-
const resolved = await resolver({ params: parsed.params, input: parsed.input });
|
|
1230
|
-
validateResolvedInputRounds(options.tool, resolved, options.runtime?.maxRounds ?? 1);
|
|
1231
|
-
return { requests: resolved, guarded: false };
|
|
1232
|
-
}
|
|
1233
|
-
async function resolveMcpRound(options) {
|
|
1234
|
-
const { policy } = options;
|
|
1235
|
-
if (!policy) {
|
|
1236
|
-
return {
|
|
1237
|
-
kind: "continue",
|
|
1238
|
-
context: transportContext(options.context, options.tool.name)
|
|
1239
|
-
};
|
|
1240
|
-
}
|
|
1241
|
-
if (!options.runtime) {
|
|
1242
|
-
throw new Error(`[stitchkit] MCP tool "${options.tool.name}" declares inputRequired but no multiRound.state key is configured`);
|
|
1243
|
-
}
|
|
1244
|
-
validateMcpRoundPolicy(options.tool, policy, {
|
|
1245
|
-
stateConfigured: true,
|
|
1246
|
-
maxRounds: options.runtime.maxRounds
|
|
1247
|
-
});
|
|
1248
|
-
const state = options.context.mcpReq.requestState();
|
|
1249
|
-
const digest = argumentsDigest(options.rawArgs);
|
|
1250
|
-
if (state) {
|
|
1251
|
-
const mismatched = !sameIdentity(state.identity, operationIdentity(options.tool)) || state.argumentsDigest !== digest || !Number.isInteger(state.round) || state.round < 0 || state.round >= options.runtime.maxRounds || !isRecord(state.accepted);
|
|
1252
|
-
if (mismatched) {
|
|
1253
|
-
return failedResolution({
|
|
1254
|
-
...options,
|
|
1255
|
-
context: transportContext(options.context, options.tool.name, "invalid", Number.isInteger(state.round) ? state.round : 0),
|
|
1256
|
-
code: "INVALID_REQUEST_STATE",
|
|
1257
|
-
message: "Continuation state does not match this operation, arguments or round"
|
|
1258
|
-
});
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
const dynamic = staticInputRounds(policy) === undefined;
|
|
1262
|
-
if (dynamic) {
|
|
1263
|
-
const guarded = await runRoundSuccess(options.tool, options.rawArgs, options.runTool, transportContext(options.context, options.tool.name, "input_required", state?.round ?? 0));
|
|
1264
|
-
if (!guarded.ok)
|
|
1265
|
-
return { kind: "response", response: options.formatFailure(guarded) };
|
|
1266
|
-
}
|
|
1267
|
-
const resolution = await resolveRequests(options, policy);
|
|
1268
|
-
if ("failure" in resolution)
|
|
1269
|
-
return resolution.failure;
|
|
1270
|
-
const requests = resolution.requests;
|
|
1271
|
-
const alreadyGuarded = dynamic;
|
|
1272
|
-
const planDigest = roundPlanDigest(requests);
|
|
1273
|
-
if (requests.length === 0 && !state) {
|
|
1274
|
-
return {
|
|
1275
|
-
kind: "continue",
|
|
1276
|
-
context: transportContext(options.context, options.tool.name)
|
|
1277
|
-
};
|
|
1278
|
-
}
|
|
1279
|
-
if (!state) {
|
|
1280
|
-
if (isRecord(options.context.mcpReq.inputResponses)) {
|
|
1281
|
-
return failedResolution({
|
|
1282
|
-
...options,
|
|
1283
|
-
context: transportContext(options.context, options.tool.name, "invalid", 0),
|
|
1284
|
-
code: "INVALID_REQUEST_STATE",
|
|
1285
|
-
message: "Input responses require a valid continuation state"
|
|
1286
|
-
});
|
|
1287
|
-
}
|
|
1288
|
-
if (!alreadyGuarded) {
|
|
1289
|
-
const guarded = await runRoundSuccess(options.tool, options.rawArgs, options.runTool, transportContext(options.context, options.tool.name, "input_required", 0));
|
|
1290
|
-
if (!guarded.ok) {
|
|
1291
|
-
return { kind: "response", response: options.formatFailure(guarded) };
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
const request2 = requests[0];
|
|
1295
|
-
if (!request2)
|
|
1296
|
-
throw new Error("[stitchkit] validated MRTR policy has no first round");
|
|
1297
|
-
const requestState = await options.runtime.codec.mint({
|
|
1298
|
-
identity: operationIdentity(options.tool),
|
|
1299
|
-
argumentsDigest: digest,
|
|
1300
|
-
round: 0,
|
|
1301
|
-
accepted: {},
|
|
1302
|
-
planDigest
|
|
1303
|
-
}, options.context);
|
|
1304
|
-
return {
|
|
1305
|
-
kind: "response",
|
|
1306
|
-
response: inputRequired({
|
|
1307
|
-
inputRequests: {
|
|
1308
|
-
[request2.key]: inputRequired.elicit({
|
|
1309
|
-
message: request2.message,
|
|
1310
|
-
requestedSchema: request2.schema
|
|
1311
|
-
})
|
|
1312
|
-
},
|
|
1313
|
-
requestState
|
|
1314
|
-
})
|
|
1315
|
-
};
|
|
1316
|
-
}
|
|
1317
|
-
if (state.planDigest !== planDigest || state.round >= requests.length) {
|
|
1318
|
-
return failedResolution({
|
|
1319
|
-
...options,
|
|
1320
|
-
context: transportContext(options.context, options.tool.name, "invalid", state.round),
|
|
1321
|
-
code: "INVALID_REQUEST_STATE",
|
|
1322
|
-
message: state.round >= requests.length ? "Continuation state does not match this operation, arguments or round" : "The questions for this call changed between rounds"
|
|
1323
|
-
});
|
|
1324
|
-
}
|
|
1325
|
-
const request = requests[state.round];
|
|
1326
|
-
if (!request)
|
|
1327
|
-
throw new Error("[stitchkit] validated MRTR state points outside its policy");
|
|
1328
|
-
const view = inputResponse(options.context.mcpReq.inputResponses, request.key);
|
|
1329
|
-
if (view.kind !== "elicit") {
|
|
1330
|
-
return failedResolution({
|
|
1331
|
-
...options,
|
|
1332
|
-
context: transportContext(options.context, options.tool.name, "invalid", state.round),
|
|
1333
|
-
code: "INVALID_INPUT_RESPONSE",
|
|
1334
|
-
message: "Expected an elicitation response for the current round"
|
|
1335
|
-
});
|
|
1336
|
-
}
|
|
1337
|
-
if (view.action !== "accept") {
|
|
1338
|
-
const outcome = view.action === "decline" ? "declined" : "cancelled";
|
|
1339
|
-
return failedResolution({
|
|
1340
|
-
...options,
|
|
1341
|
-
context: transportContext(options.context, options.tool.name, outcome, state.round),
|
|
1342
|
-
code: view.action === "decline" ? "INPUT_DECLINED" : "INPUT_CANCELLED",
|
|
1343
|
-
message: view.action === "decline" ? "Required input was declined" : "Required input was cancelled"
|
|
1344
|
-
});
|
|
1345
|
-
}
|
|
1346
|
-
const content = acceptedContent(options.context.mcpReq.inputResponses, request.key, request.schema);
|
|
1347
|
-
if (!content) {
|
|
1348
|
-
return failedResolution({
|
|
1349
|
-
...options,
|
|
1350
|
-
context: transportContext(options.context, options.tool.name, "invalid", state.round),
|
|
1351
|
-
code: "INVALID_INPUT_RESPONSE",
|
|
1352
|
-
message: "Accepted input failed its declared schema"
|
|
1353
|
-
});
|
|
1354
|
-
}
|
|
1355
|
-
const accepted = { ...state.accepted, [request.key]: content };
|
|
1356
|
-
const nextRound = state.round + 1;
|
|
1357
|
-
const nextRequest = requests[nextRound];
|
|
1358
|
-
if (nextRequest) {
|
|
1359
|
-
if (!alreadyGuarded) {
|
|
1360
|
-
const guarded = await runRoundSuccess(options.tool, options.rawArgs, options.runTool, transportContext(options.context, options.tool.name, "input_required", nextRound));
|
|
1361
|
-
if (!guarded.ok) {
|
|
1362
|
-
return { kind: "response", response: options.formatFailure(guarded) };
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
const requestState = await options.runtime.codec.mint({
|
|
1366
|
-
identity: state.identity,
|
|
1367
|
-
argumentsDigest: state.argumentsDigest,
|
|
1368
|
-
round: nextRound,
|
|
1369
|
-
accepted,
|
|
1370
|
-
planDigest
|
|
1371
|
-
}, options.context);
|
|
1372
|
-
return {
|
|
1373
|
-
kind: "response",
|
|
1374
|
-
response: inputRequired({
|
|
1375
|
-
inputRequests: {
|
|
1376
|
-
[nextRequest.key]: inputRequired.elicit({
|
|
1377
|
-
message: nextRequest.message,
|
|
1378
|
-
requestedSchema: nextRequest.schema
|
|
1379
|
-
})
|
|
1380
|
-
},
|
|
1381
|
-
requestState
|
|
1382
|
-
})
|
|
1383
|
-
};
|
|
1384
|
-
}
|
|
1385
|
-
return {
|
|
1386
|
-
kind: "continue",
|
|
1387
|
-
context: {
|
|
1388
|
-
...transportContext(options.context, options.tool.name, "complete", state.round),
|
|
1389
|
-
mcpInput: accepted
|
|
1390
|
-
}
|
|
1391
|
-
};
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
// src/tools/mcp-trace.ts
|
|
1395
|
-
import {
|
|
1396
|
-
BAGGAGE_META_KEY,
|
|
1397
|
-
TRACEPARENT_META_KEY,
|
|
1398
|
-
TRACESTATE_META_KEY
|
|
1399
|
-
} from "@modelcontextprotocol/server";
|
|
1400
|
-
function runInMcpRequestContext(context, toolName, body) {
|
|
1401
|
-
const ambient = getRequestContext();
|
|
1402
|
-
const metadata = context.mcpReq._meta;
|
|
1403
|
-
const propagation = metadata ? {
|
|
1404
|
-
traceparent: metadata[TRACEPARENT_META_KEY],
|
|
1405
|
-
tracestate: metadata[TRACESTATE_META_KEY],
|
|
1406
|
-
baggage: metadata[BAGGAGE_META_KEY]
|
|
1407
|
-
} : undefined;
|
|
1408
|
-
const request = {
|
|
1409
|
-
...ambient ?? {
|
|
1410
|
-
source: "mcp",
|
|
1411
|
-
method: "MCP",
|
|
1412
|
-
path: `/mcp/${toolName}`,
|
|
1413
|
-
startedAt: process.hrtime.bigint()
|
|
1414
|
-
},
|
|
1415
|
-
trace: resolvePropagationContext(propagation, ambient?.trace),
|
|
1416
|
-
source: "mcp",
|
|
1417
|
-
method: "MCP",
|
|
1418
|
-
path: `/mcp/${toolName}`,
|
|
1419
|
-
startedAt: process.hrtime.bigint(),
|
|
1420
|
-
dimensions: ambient?.dimensions ? { ...ambient.dimensions } : undefined,
|
|
1421
|
-
error: undefined
|
|
1422
|
-
};
|
|
1423
|
-
return runWithRequestContext(request, body);
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
|
-
// src/tools/native-mcp.ts
|
|
1427
|
-
import {
|
|
1428
|
-
isCallToolResult
|
|
1429
|
-
} from "@modelcontextprotocol/server";
|
|
1430
|
-
import { z as z4 } from "zod";
|
|
1431
|
-
function mountPreparedRuntimeMcp(server, tools, config) {
|
|
1432
|
-
for (const { definition, descriptor } of tools) {
|
|
1433
|
-
const { mountable } = descriptor;
|
|
1434
|
-
const toolConfig = {
|
|
1435
|
-
description: definition.description,
|
|
1436
|
-
inputSchema: z4.looseObject({}).meta(presentationMetadata(descriptor.inputSchema))
|
|
1437
|
-
};
|
|
1438
|
-
if (descriptor.outputSchema)
|
|
1439
|
-
toolConfig.outputSchema = descriptor.outputSchema;
|
|
1440
|
-
if (definition.annotations)
|
|
1441
|
-
toolConfig.annotations = definition.annotations;
|
|
1442
|
-
if (definition.ui) {
|
|
1443
|
-
toolConfig._meta = {
|
|
1444
|
-
ui: definition.ui,
|
|
1445
|
-
"ui/resourceUri": definition.ui.resourceUri
|
|
1446
|
-
};
|
|
1447
|
-
}
|
|
1448
|
-
server.registerTool(definition.name, stampToolRegistration(toolConfig, config.catalog), async (rawArgs, mcpContext) => stampToolResult(await runInMcpRequestContext(mcpContext, definition.name, async () => {
|
|
1449
|
-
const args = isRecord(rawArgs) ? rawArgs : {};
|
|
1450
|
-
const runTool = (tool, toolArgs, roundContext) => executeToolMethod(tool.method, definition.name, toolArgs, { ...config.context, ...roundContext, source: "mcp" }, config.hooks, config.lifecycle, config.coerceJsonArgs ?? true, config.onOutputStrip ? (paths) => config.onOutputStrip?.(definition.name, paths) : undefined);
|
|
1451
|
-
const round = await resolveMcpRound({
|
|
1452
|
-
tool: mountable,
|
|
1453
|
-
rawArgs: args,
|
|
1454
|
-
context: mcpContext,
|
|
1455
|
-
policy: mountable.method.mcp,
|
|
1456
|
-
runtime: config.multiRoundRuntime,
|
|
1457
|
-
runTool,
|
|
1458
|
-
formatFailure: (result) => config.formatResult(result, "none", definition.name)
|
|
1459
|
-
});
|
|
1460
|
-
if (round.kind === "response")
|
|
1461
|
-
return round.response;
|
|
1462
|
-
if (!definition.present?.mcp) {
|
|
1463
|
-
const result = await runTool(mountable, args, round.context);
|
|
1464
|
-
return config.formatResult(result, descriptor.outputMode, definition.name);
|
|
1465
|
-
}
|
|
1466
|
-
const presentedResult = await executeToolMethod(mountable.method, definition.name, args, { ...config.context, ...round.context, source: "mcp" }, config.hooks, config.lifecycle, config.coerceJsonArgs ?? true, config.onOutputStrip ? (paths) => config.onOutputStrip?.(definition.name, paths) : undefined, undefined, async (data) => {
|
|
1467
|
-
const presented = await definition.present?.mcp?.(data);
|
|
1468
|
-
if (!presented) {
|
|
1469
|
-
throw new AppError("INTERNAL_SERVER_ERROR", "Runtime MCP presenter did not return a result", 500);
|
|
1470
|
-
}
|
|
1471
|
-
if ("structuredContent" in presented || "isError" in presented) {
|
|
1472
|
-
throw new AppError("INTERNAL_SERVER_ERROR", "Runtime MCP presenter cannot set framework-owned structuredContent or isError", 500);
|
|
1473
|
-
}
|
|
1474
|
-
const structured = config.formatResult({ ok: true, data }, descriptor.outputMode, definition.name).structuredContent;
|
|
1475
|
-
const response = structured === undefined ? presented : { ...presented, structuredContent: structured };
|
|
1476
|
-
if (!isCallToolResult(response)) {
|
|
1477
|
-
throw new AppError("INTERNAL_SERVER_ERROR", "Runtime MCP presenter returned an invalid CallToolResult", 500);
|
|
1478
|
-
}
|
|
1479
|
-
return response;
|
|
1480
|
-
});
|
|
1481
|
-
if (!presentedResult.ok) {
|
|
1482
|
-
return config.formatResult(presentedResult, "none", definition.name);
|
|
1483
|
-
}
|
|
1484
|
-
if (!isCallToolResult(presentedResult.data)) {
|
|
1485
|
-
throw new Error("[stitchkit] Runtime MCP presenter invariant failed");
|
|
1486
|
-
}
|
|
1487
|
-
return presentedResult.data;
|
|
1488
|
-
}), config.catalog));
|
|
1489
|
-
}
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
|
-
// src/tools/mcp.ts
|
|
1493
|
-
function validateMcpSchemas(config) {
|
|
1494
|
-
prepareMcpSurface(config.services, {
|
|
1495
|
-
extend: config.extend,
|
|
1496
|
-
flattenUnionInput: config.flattenUnionInput,
|
|
1497
|
-
schemaValidation: config,
|
|
1498
|
-
logger: config.logger
|
|
1499
|
-
});
|
|
1500
|
-
}
|
|
1501
|
-
function mountMcp(mcpServer, services, config = {}) {
|
|
1502
|
-
const prepared = prepareMcpSurface(services, {
|
|
1503
|
-
extend: config.extend,
|
|
1504
|
-
flattenUnionInput: config.flattenUnionInput,
|
|
1505
|
-
schemaValidation: config.schemaValidation,
|
|
1506
|
-
logger: config.logger
|
|
1507
|
-
});
|
|
1508
|
-
mountPreparedMcp(mcpServer, prepared, {
|
|
1509
|
-
...config,
|
|
1510
|
-
catalog: mcpCatalogStamp({ contractTools: prepared, runtimeTools: [] })
|
|
1511
|
-
});
|
|
1512
|
-
}
|
|
1513
|
-
function mountPreparedMcp(mcpServer, prepared, config = {}) {
|
|
1514
|
-
const runTool = createToolRunner({
|
|
1515
|
-
source: "mcp",
|
|
1516
|
-
extend: config.extend,
|
|
1517
|
-
context: config.context,
|
|
1518
|
-
hooks: config.hooks,
|
|
1519
|
-
lifecycle: config.lifecycle,
|
|
1520
|
-
errorHint: config.errorHint,
|
|
1521
|
-
coerceJsonArgs: config.coerceJsonArgs,
|
|
1522
|
-
onOutputStrip: config.onOutputStrip
|
|
1523
|
-
});
|
|
1524
|
-
for (const descriptor of prepared) {
|
|
1525
|
-
const { mountable } = descriptor;
|
|
1526
|
-
const toolConfig = {
|
|
1527
|
-
description: mountable.method.desc,
|
|
1528
|
-
inputSchema: z5.looseObject({}).meta(presentationMetadata(descriptor.inputSchema))
|
|
1529
|
-
};
|
|
1530
|
-
if (descriptor.outputSchema)
|
|
1531
|
-
toolConfig.outputSchema = descriptor.outputSchema;
|
|
1532
|
-
if (mountable.method.annotations) {
|
|
1533
|
-
toolConfig.annotations = mountable.method.annotations;
|
|
1534
|
-
}
|
|
1535
|
-
if (mountable.method.ui) {
|
|
1536
|
-
toolConfig._meta = {
|
|
1537
|
-
ui: mountable.method.ui,
|
|
1538
|
-
"ui/resourceUri": mountable.method.ui.resourceUri
|
|
1539
|
-
};
|
|
1540
|
-
}
|
|
1541
|
-
mcpServer.registerTool(mountable.name, stampToolRegistration(toolConfig, config.catalog), async (rawArgs, mcpContext) => stampToolResult(await runInMcpRequestContext(mcpContext, mountable.name, async () => {
|
|
1542
|
-
const args = isRecord(rawArgs) ? rawArgs : {};
|
|
1543
|
-
try {
|
|
1544
|
-
const round = await resolveMcpRound({
|
|
1545
|
-
tool: mountable,
|
|
1546
|
-
rawArgs: args,
|
|
1547
|
-
context: mcpContext,
|
|
1548
|
-
policy: mountable.method.mcp,
|
|
1549
|
-
runtime: config.multiRoundRuntime,
|
|
1550
|
-
runTool,
|
|
1551
|
-
formatFailure: (result2) => formatMcpResult(result2, "none", mountable.name, config.errorHint)
|
|
1552
|
-
});
|
|
1553
|
-
if (round.kind === "response")
|
|
1554
|
-
return round.response;
|
|
1555
|
-
const result = await runTool(mountable, args, round.context);
|
|
1556
|
-
return formatMcpResult(result, descriptor.outputMode, mountable.name, config.errorHint);
|
|
1557
|
-
} catch (err) {
|
|
1558
|
-
return formatMcpResult(toolResultFromError(err), "none", mountable.name, config.errorHint);
|
|
1559
|
-
}
|
|
1560
|
-
}), config.catalog));
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
function buildMcpServer(config, auth) {
|
|
1564
|
-
if (!isMcpServerBuildConfig(config)) {
|
|
1565
|
-
throw new TypeError("[stitchkit] buildMcpServer requires a valid config object");
|
|
1566
|
-
}
|
|
1567
|
-
let surface;
|
|
1568
|
-
if (config.surfaces) {
|
|
1569
|
-
const key = config.selectSurface(auth);
|
|
1570
|
-
if (!Object.hasOwn(config.surfaces, key)) {
|
|
1571
|
-
throw new Error(`[stitchkit] Unknown MCP surface "${key}"`);
|
|
1572
|
-
}
|
|
1573
|
-
const selected = config.surfaces[key];
|
|
1574
|
-
if (!selected)
|
|
1575
|
-
throw new Error(`[stitchkit] Unknown MCP surface "${key}"`);
|
|
1576
|
-
surface = selected;
|
|
1577
|
-
} else {
|
|
1578
|
-
const services = typeof config.services === "function" ? config.services(auth) : config.services;
|
|
1579
|
-
const runtimeTools = typeof config.runtimeTools === "function" ? config.runtimeTools(auth) : config.runtimeTools;
|
|
1580
|
-
surface = { services, runtimeTools };
|
|
1581
|
-
}
|
|
1582
|
-
const prepared = prepareMcpServerSurface(surface, {
|
|
1583
|
-
extend: config.extend,
|
|
1584
|
-
flattenUnionInput: config.flattenUnionInput,
|
|
1585
|
-
schemaValidation: config.schemaValidation,
|
|
1586
|
-
logger: config.logger,
|
|
1587
|
-
multiRound: {
|
|
1588
|
-
stateConfigured: config.multiRound !== undefined,
|
|
1589
|
-
maxRounds: config.multiRound?.serving?.maxRounds ?? 10
|
|
1590
|
-
}
|
|
1591
|
-
});
|
|
1592
|
-
return buildMcpServerFromPrepared(config, auth, prepared);
|
|
1593
|
-
}
|
|
1594
|
-
function isMcpServerBuildConfig(value) {
|
|
1595
|
-
return isRecord(value) && isRecord(value.serverInfo);
|
|
1596
|
-
}
|
|
1597
|
-
function buildMcpServerFromPrepared(config, auth, prepared) {
|
|
1598
|
-
let roundCodec;
|
|
1599
|
-
if (config.multiRound) {
|
|
1600
|
-
const principal = config.multiRound.state.principal(auth);
|
|
1601
|
-
roundCodec = createRequestStateCodec({
|
|
1602
|
-
key: config.multiRound.state.key,
|
|
1603
|
-
ttlSeconds: config.multiRound.state.ttlSeconds,
|
|
1604
|
-
bind: (mcpContext) => `${mcpContext.mcpReq.method}\x00${principal}`
|
|
1605
|
-
});
|
|
1606
|
-
}
|
|
1607
|
-
const dynamicSurface = !config.surfaces && (typeof config.services === "function" || typeof config.runtimeTools === "function");
|
|
1608
|
-
const serverOptions = {
|
|
1609
|
-
...config.instructions !== undefined && { instructions: config.instructions },
|
|
1610
|
-
...!dynamicSurface && config.cache?.operations !== undefined && {
|
|
1611
|
-
cacheHints: config.cache.operations
|
|
1612
|
-
},
|
|
1613
|
-
...config.multiRound?.serving !== undefined && {
|
|
1614
|
-
inputRequired: config.multiRound.serving
|
|
1615
|
-
},
|
|
1616
|
-
...roundCodec !== undefined && {
|
|
1617
|
-
requestState: { verify: roundCodec.verify }
|
|
1618
|
-
}
|
|
1619
|
-
};
|
|
1620
|
-
const server = new McpServer(config.serverInfo, serverOptions);
|
|
1621
|
-
const context = config.context?.(auth);
|
|
1622
|
-
const catalog = mcpCatalogStamp(prepared);
|
|
1623
|
-
mountPreparedMcp(server, prepared.contractTools, {
|
|
1624
|
-
catalog,
|
|
1625
|
-
context,
|
|
1626
|
-
hooks: config.hooks,
|
|
1627
|
-
lifecycle: config.lifecycle,
|
|
1628
|
-
extend: config.extend,
|
|
1629
|
-
schemaValidation: config.schemaValidation,
|
|
1630
|
-
logger: config.logger,
|
|
1631
|
-
coerceJsonArgs: config.coerceJsonArgs,
|
|
1632
|
-
flattenUnionInput: config.flattenUnionInput,
|
|
1633
|
-
errorHint: config.errorHint,
|
|
1634
|
-
onOutputStrip: config.onOutputStrip,
|
|
1635
|
-
...roundCodec !== undefined && {
|
|
1636
|
-
multiRoundRuntime: {
|
|
1637
|
-
codec: roundCodec,
|
|
1638
|
-
maxRounds: config.multiRound?.serving?.maxRounds ?? 10
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
});
|
|
1642
|
-
mountPreparedRuntimeMcp(server, prepared.runtimeTools, {
|
|
1643
|
-
catalog,
|
|
1644
|
-
context,
|
|
1645
|
-
hooks: config.hooks,
|
|
1646
|
-
lifecycle: config.lifecycle,
|
|
1647
|
-
coerceJsonArgs: config.coerceJsonArgs,
|
|
1648
|
-
onOutputStrip: config.onOutputStrip,
|
|
1649
|
-
formatResult: (result, mode, toolName) => formatMcpResult(result, mode, toolName, config.errorHint),
|
|
1650
|
-
...roundCodec !== undefined && {
|
|
1651
|
-
multiRoundRuntime: {
|
|
1652
|
-
codec: roundCodec,
|
|
1653
|
-
maxRounds: config.multiRound?.serving?.maxRounds ?? 10
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
});
|
|
1657
|
-
config.rawTools?.(server, auth);
|
|
1658
|
-
for (const resource of config.resources ?? []) {
|
|
1659
|
-
mountMcpResource(server, resource);
|
|
1660
|
-
}
|
|
1661
|
-
return server;
|
|
1662
|
-
}
|
|
1663
|
-
function mountMcpResource(server, resource) {
|
|
1664
|
-
server.registerResource(resource.name, resource.uri, {
|
|
1665
|
-
mimeType: resource.mimeType ?? RESOURCE_MIME_TYPE,
|
|
1666
|
-
...resource.cacheHint !== undefined && { cacheHint: resource.cacheHint }
|
|
1667
|
-
}, async () => ({
|
|
1668
|
-
contents: [
|
|
1669
|
-
{
|
|
1670
|
-
uri: resource.uri,
|
|
1671
|
-
mimeType: resource.mimeType ?? RESOURCE_MIME_TYPE,
|
|
1672
|
-
text: await resource.read(),
|
|
1673
|
-
...resource.ui && { _meta: { ui: resource.ui } }
|
|
1674
|
-
}
|
|
1675
|
-
]
|
|
1676
|
-
}));
|
|
1677
|
-
}
|
|
1678
|
-
// src/tools/mcp-handler.ts
|
|
1679
|
-
import {
|
|
1680
|
-
createMcpHandler as createSdkMcpHandler,
|
|
1681
|
-
hostHeaderValidationResponse,
|
|
1682
|
-
localhostAllowedHostnames,
|
|
1683
|
-
localhostAllowedOrigins,
|
|
1684
|
-
originValidationResponse
|
|
1685
|
-
} from "@modelcontextprotocol/server";
|
|
1686
|
-
|
|
1687
|
-
// src/tools/oauth-metadata.ts
|
|
1688
|
-
var PROTECTED_RESOURCE_PATH = "/.well-known/oauth-protected-resource";
|
|
1689
|
-
function metadataPath(resource) {
|
|
1690
|
-
const { pathname } = new URL(resource);
|
|
1691
|
-
return pathname === "/" ? PROTECTED_RESOURCE_PATH : `${PROTECTED_RESOURCE_PATH}${pathname}`;
|
|
1692
|
-
}
|
|
1693
|
-
function protectedResourceMetadataUrl(resource) {
|
|
1694
|
-
return `${new URL(resource).origin}${metadataPath(resource)}`;
|
|
1695
|
-
}
|
|
1696
|
-
function wwwAuthenticateHeader(resource) {
|
|
1697
|
-
return `Bearer resource_metadata="${protectedResourceMetadataUrl(resource)}"`;
|
|
1698
|
-
}
|
|
1699
|
-
var PUBLIC_CORS = {
|
|
1700
|
-
"Access-Control-Allow-Origin": "*",
|
|
1701
|
-
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
|
1702
|
-
"Access-Control-Allow-Headers": DEFAULT_CORS_ALLOW_HEADERS
|
|
1703
|
-
};
|
|
1704
|
-
function oauthProtectedResourceRoute(config) {
|
|
1705
|
-
const body = JSON.stringify({
|
|
1706
|
-
resource: config.resource,
|
|
1707
|
-
authorization_servers: config.authorizationServers,
|
|
1708
|
-
...config.scopesSupported && { scopes_supported: config.scopesSupported },
|
|
1709
|
-
bearer_methods_supported: ["header"]
|
|
1710
|
-
});
|
|
1711
|
-
return {
|
|
1712
|
-
method: "ALL",
|
|
1713
|
-
path: metadataPath(config.resource),
|
|
1714
|
-
handler: (req) => {
|
|
1715
|
-
if (req.method === "OPTIONS")
|
|
1716
|
-
return new Response(null, { status: 204, headers: PUBLIC_CORS });
|
|
1717
|
-
if (req.method !== "GET")
|
|
1718
|
-
return new Response("Method Not Allowed", { status: 405 });
|
|
1719
|
-
return new Response(body, {
|
|
1720
|
-
status: 200,
|
|
1721
|
-
headers: { "Content-Type": "application/json", ...PUBLIC_CORS }
|
|
1722
|
-
});
|
|
1723
|
-
}
|
|
1724
|
-
};
|
|
1725
|
-
}
|
|
1726
|
-
|
|
1727
|
-
// src/tools/mcp-handler.ts
|
|
1728
|
-
function jsonRpcError(code, message, status, headers) {
|
|
1729
|
-
return Response.json({ jsonrpc: "2.0", error: { code, message }, id: null }, { status, headers });
|
|
1730
|
-
}
|
|
1731
|
-
function hostValidationResponse(request, allowedHosts) {
|
|
1732
|
-
if (request.headers.has("host")) {
|
|
1733
|
-
return hostHeaderValidationResponse(request, [...allowedHosts]);
|
|
1734
|
-
}
|
|
1735
|
-
const hostname = new URL(request.url).hostname;
|
|
1736
|
-
if (allowedHosts.includes(hostname))
|
|
1737
|
-
return;
|
|
1738
|
-
return jsonRpcError(-32000, "Invalid Host header", 403);
|
|
1739
|
-
}
|
|
1740
|
-
function prepareStaticSurface(config) {
|
|
1741
|
-
const preparation = {
|
|
1742
|
-
logger: config.logger,
|
|
1743
|
-
extend: config.extend,
|
|
1744
|
-
flattenUnionInput: config.flattenUnionInput,
|
|
1745
|
-
schemaValidation: config.schemaValidation,
|
|
1746
|
-
multiRound: {
|
|
1747
|
-
stateConfigured: config.multiRound !== undefined,
|
|
1748
|
-
maxRounds: config.multiRound?.serving?.maxRounds ?? 10
|
|
1749
|
-
}
|
|
1750
|
-
};
|
|
1751
|
-
if (config.surfaces && config.selectSurface) {
|
|
1752
|
-
const preparedByKey = new Map;
|
|
1753
|
-
const preparedBySurface = new WeakMap;
|
|
1754
|
-
for (const key in config.surfaces) {
|
|
1755
|
-
if (!Object.hasOwn(config.surfaces, key))
|
|
1756
|
-
continue;
|
|
1757
|
-
const surface = config.surfaces[key];
|
|
1758
|
-
if (!surface)
|
|
1759
|
-
continue;
|
|
1760
|
-
const existing = preparedBySurface.get(surface);
|
|
1761
|
-
const prepared = existing ?? prepareMcpServerSurface(surface, preparation);
|
|
1762
|
-
if (!existing)
|
|
1763
|
-
preparedBySurface.set(surface, prepared);
|
|
1764
|
-
preparedByKey.set(key, prepared);
|
|
1765
|
-
}
|
|
1766
|
-
return (auth) => {
|
|
1767
|
-
const key = config.selectSurface(auth);
|
|
1768
|
-
const prepared = preparedByKey.get(key);
|
|
1769
|
-
if (!prepared)
|
|
1770
|
-
throw new Error(`[stitchkit] Unknown MCP surface "${key}"`);
|
|
1771
|
-
return buildMcpServerFromPrepared(config, auth, prepared);
|
|
1772
|
-
};
|
|
1773
|
-
}
|
|
1774
|
-
if (config.services && typeof config.services !== "function" && typeof config.runtimeTools !== "function") {
|
|
1775
|
-
const prepared = prepareMcpServerSurface({ services: config.services, runtimeTools: config.runtimeTools }, preparation);
|
|
1776
|
-
return (auth) => buildMcpServerFromPrepared(config, auth, prepared);
|
|
1777
|
-
}
|
|
1778
|
-
return null;
|
|
1779
|
-
}
|
|
1780
|
-
function createMcpHandler(config) {
|
|
1781
|
-
const buildPrepared = prepareStaticSurface(config);
|
|
1782
|
-
const authByCarrier = new WeakMap;
|
|
1783
|
-
let closed = false;
|
|
1784
|
-
let resolveClosed;
|
|
1785
|
-
const closedSignal = new Promise((resolve) => {
|
|
1786
|
-
resolveClosed = resolve;
|
|
1787
|
-
});
|
|
1788
|
-
const sdkHandler = createSdkMcpHandler(({ authInfo }) => {
|
|
1789
|
-
const resolved = authInfo ? authByCarrier.get(authInfo) : undefined;
|
|
1790
|
-
if (!resolved) {
|
|
1791
|
-
throw new Error("[stitchkit] MCP request reached the SDK without resolved auth");
|
|
1792
|
-
}
|
|
1793
|
-
const auth = resolved.value;
|
|
1794
|
-
return buildPrepared ? buildPrepared(auth) : buildMcpServer(config, auth);
|
|
1795
|
-
}, {
|
|
1796
|
-
legacy: config.legacy === "reject" ? "reject" : "stateless",
|
|
1797
|
-
maxSubscriptions: 0
|
|
1798
|
-
});
|
|
1799
|
-
const unauthorized = () => {
|
|
1800
|
-
const headers = config.protectedResource ? { "WWW-Authenticate": wwwAuthenticateHeader(config.protectedResource.resource) } : undefined;
|
|
1801
|
-
return jsonRpcError(-32001, "Authorization required", 401, headers);
|
|
1802
|
-
};
|
|
1803
|
-
const observeRejection = (request, response) => {
|
|
1804
|
-
if (response.status < 400 || !config.onTransportRejected)
|
|
1805
|
-
return response;
|
|
1806
|
-
Promise.resolve(config.onTransportRejected({ request, response: response.clone() })).catch(() => {
|
|
1807
|
-
return;
|
|
1808
|
-
});
|
|
1809
|
-
return response;
|
|
1810
|
-
};
|
|
1811
|
-
return {
|
|
1812
|
-
fetch: async (request) => {
|
|
1813
|
-
if (closed) {
|
|
1814
|
-
return observeRejection(request, jsonRpcError(-32000, "MCP handler is closed", 503));
|
|
1815
|
-
}
|
|
1816
|
-
const allowedHosts = config.security?.allowedHosts ?? localhostAllowedHostnames();
|
|
1817
|
-
const hostRejection = hostValidationResponse(request, allowedHosts);
|
|
1818
|
-
if (hostRejection)
|
|
1819
|
-
return observeRejection(request, hostRejection);
|
|
1820
|
-
const allowedOrigins = config.security?.allowedOrigins ?? localhostAllowedOrigins();
|
|
1821
|
-
const originRejection = originValidationResponse(request, [...allowedOrigins]);
|
|
1822
|
-
if (originRejection)
|
|
1823
|
-
return observeRejection(request, originRejection);
|
|
1824
|
-
const auth = await Promise.race([
|
|
1825
|
-
Promise.resolve(config.auth(request)),
|
|
1826
|
-
closedSignal.then(() => null)
|
|
1827
|
-
]);
|
|
1828
|
-
if (closed) {
|
|
1829
|
-
return observeRejection(request, jsonRpcError(-32000, "MCP handler is closed", 503));
|
|
1830
|
-
}
|
|
1831
|
-
if (auth == null)
|
|
1832
|
-
return observeRejection(request, unauthorized());
|
|
1833
|
-
const authCarrier = {
|
|
1834
|
-
token: "",
|
|
1835
|
-
clientId: config.multiRound?.state.principal(auth) ?? "stitchkit",
|
|
1836
|
-
scopes: []
|
|
1837
|
-
};
|
|
1838
|
-
authByCarrier.set(authCarrier, { value: auth });
|
|
1839
|
-
try {
|
|
1840
|
-
return observeRejection(request, await sdkHandler.fetch(request, { authInfo: authCarrier }));
|
|
1841
|
-
} finally {
|
|
1842
|
-
authByCarrier.delete(authCarrier);
|
|
1843
|
-
}
|
|
1844
|
-
},
|
|
1845
|
-
close: async () => {
|
|
1846
|
-
if (closed)
|
|
1847
|
-
return;
|
|
1848
|
-
closed = true;
|
|
1849
|
-
resolveClosed?.();
|
|
1850
|
-
await sdkHandler.close();
|
|
1851
|
-
}
|
|
1852
|
-
};
|
|
1853
|
-
}
|
|
1854
|
-
function createMcpHttpRoute(config) {
|
|
1855
|
-
return {
|
|
1856
|
-
method: "ALL",
|
|
1857
|
-
path: config.path,
|
|
1858
|
-
handler: (request) => config.handler.fetch(request)
|
|
1859
|
-
};
|
|
1860
|
-
}
|
|
1861
|
-
// src/tools/mcp-stdio.ts
|
|
1862
|
-
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
1863
|
-
async function createStdioMcpServer(config) {
|
|
1864
|
-
const auth = await config.auth;
|
|
1865
|
-
return serveStdio(() => buildMcpServer(config, auth), {
|
|
1866
|
-
legacy: config.legacy ?? "serve",
|
|
1867
|
-
maxSubscriptions: 0
|
|
1868
|
-
});
|
|
1869
|
-
}
|
|
1870
|
-
// src/tools/mcp-stdio-signals.ts
|
|
1871
|
-
var bound = new WeakSet;
|
|
1872
|
-
function bindStdioProcessSignals(handle, options = {}) {
|
|
1873
|
-
if (bound.has(handle)) {
|
|
1874
|
-
throw new Error("[stitchkit] bindStdioProcessSignals: this stdio handle is already bound; close the first binding before creating another");
|
|
1875
|
-
}
|
|
1876
|
-
bound.add(handle);
|
|
1877
|
-
const signals = [...new Set(options.signals ?? DEFAULT_PROCESS_SIGNALS)];
|
|
1878
|
-
const source = options.signalSource ?? defaultSignalSource;
|
|
1879
|
-
const handlers = [];
|
|
1880
|
-
let started = false;
|
|
1881
|
-
let sameTurnAsStart = false;
|
|
1882
|
-
let closed = false;
|
|
1883
|
-
let resolveChain = () => {
|
|
1884
|
-
return;
|
|
1885
|
-
};
|
|
1886
|
-
let rejectChain = () => {
|
|
1887
|
-
return;
|
|
1888
|
-
};
|
|
1889
|
-
const promise = new Promise((resolve, reject) => {
|
|
1890
|
-
resolveChain = resolve;
|
|
1891
|
-
rejectChain = reject;
|
|
1892
|
-
});
|
|
1893
|
-
promise.catch(() => {
|
|
1894
|
-
return;
|
|
1895
|
-
});
|
|
1896
|
-
const removeListeners = () => {
|
|
1897
|
-
if (closed)
|
|
1898
|
-
return;
|
|
1899
|
-
closed = true;
|
|
1900
|
-
for (const [signal, handler] of handlers)
|
|
1901
|
-
source.off(signal, handler);
|
|
1902
|
-
if (!started)
|
|
1903
|
-
bound.delete(handle);
|
|
1904
|
-
};
|
|
1905
|
-
const close = () => {
|
|
1906
|
-
const hadStarted = started;
|
|
1907
|
-
removeListeners();
|
|
1908
|
-
if (!hadStarted)
|
|
1909
|
-
resolveChain();
|
|
1910
|
-
};
|
|
1911
|
-
const run = async (signal) => {
|
|
1912
|
-
try {
|
|
1913
|
-
await options.onClose?.(signal);
|
|
1914
|
-
} catch (error) {
|
|
1915
|
-
reportSignalError("prepare", error, options.onError);
|
|
1916
|
-
}
|
|
1917
|
-
try {
|
|
1918
|
-
await handle.close();
|
|
1919
|
-
} catch (error) {
|
|
1920
|
-
rejectChain(error);
|
|
1921
|
-
reportSignalError("close", error, options.onError);
|
|
1922
|
-
removeListeners();
|
|
1923
|
-
return;
|
|
1924
|
-
}
|
|
1925
|
-
resolveChain();
|
|
1926
|
-
try {
|
|
1927
|
-
await options.onComplete?.();
|
|
1928
|
-
} catch (error) {
|
|
1929
|
-
reportSignalError("complete", error, options.onError);
|
|
1930
|
-
} finally {
|
|
1931
|
-
removeListeners();
|
|
1932
|
-
}
|
|
1933
|
-
};
|
|
1934
|
-
const onSignal = (signal) => {
|
|
1935
|
-
if (!started) {
|
|
1936
|
-
started = true;
|
|
1937
|
-
sameTurnAsStart = true;
|
|
1938
|
-
queueMicrotask(() => {
|
|
1939
|
-
sameTurnAsStart = false;
|
|
1940
|
-
});
|
|
1941
|
-
run(signal).catch((error) => reportSignalError("close", error, options.onError));
|
|
1942
|
-
return;
|
|
1943
|
-
}
|
|
1944
|
-
if (sameTurnAsStart)
|
|
1945
|
-
return;
|
|
1946
|
-
removeListeners();
|
|
1947
|
-
guardSignalCallback(() => options.onRepeatedSignal?.(signal), "close", options.onError);
|
|
1948
|
-
let restored = false;
|
|
1949
|
-
try {
|
|
1950
|
-
restored = source.raiseDefault(signal);
|
|
1951
|
-
} catch (error) {
|
|
1952
|
-
reportSignalError("close", error, options.onError);
|
|
1953
|
-
}
|
|
1954
|
-
if (!restored) {
|
|
1955
|
-
guardSignalCallback(() => options.onEscalationBlocked?.(signal), "close", options.onError);
|
|
1956
|
-
}
|
|
1957
|
-
};
|
|
1958
|
-
for (const signal of signals) {
|
|
1959
|
-
const handler = () => onSignal(signal);
|
|
1960
|
-
handlers.push([signal, handler]);
|
|
1961
|
-
source.on(signal, handler);
|
|
1962
|
-
}
|
|
1963
|
-
return { promise, close };
|
|
1964
|
-
}
|
|
1965
|
-
// src/tools/mount-download.ts
|
|
1966
|
-
import { z as z6 } from "zod";
|
|
1967
|
-
|
|
1968
|
-
// src/tools/native-result.ts
|
|
1969
|
-
function textResult(text, isError = false) {
|
|
1970
|
-
const content = [{ type: "text", text }];
|
|
1971
|
-
return isError ? { content, isError: true } : { content };
|
|
1972
|
-
}
|
|
1973
|
-
|
|
1974
|
-
// src/tools/mount-download.ts
|
|
1975
|
-
function mountDownload(server, config) {
|
|
1976
|
-
const name = config.name ?? "download";
|
|
1977
|
-
assertToolName(name, "<native>", "download");
|
|
1978
|
-
server.registerTool(name, { description: config.description, inputSchema: z6.object(config.inputSchema) }, async (rawArgs) => {
|
|
1979
|
-
const args = isRecord(rawArgs) ? rawArgs : {};
|
|
1980
|
-
try {
|
|
1981
|
-
const url = await config.resolveUrl(args);
|
|
1982
|
-
if (!url)
|
|
1983
|
-
return textResult("Nothing to download.", true);
|
|
1984
|
-
const result = await runDownloadOperation({
|
|
1985
|
-
url,
|
|
1986
|
-
files: config.files,
|
|
1987
|
-
path: config.pathFromArgs?.(args),
|
|
1988
|
-
allowPrivateHosts: config.allowPrivateHosts,
|
|
1989
|
-
maxBytes: config.maxBytes,
|
|
1990
|
-
timeoutMs: config.timeoutMs
|
|
1991
|
-
});
|
|
1992
|
-
return textResult(JSON.stringify(result, null, 2));
|
|
1993
|
-
} catch (error) {
|
|
1994
|
-
if (error instanceof DownloadOperationError) {
|
|
1995
|
-
return textResult(`Download failed [${error.code}]: ${error.message}`, true);
|
|
1996
|
-
}
|
|
1997
|
-
const normalized = normalizeFileToolError(error);
|
|
1998
|
-
return textResult(`Download failed [${normalized.code}]: ${normalized.message}`, true);
|
|
1999
|
-
}
|
|
2000
|
-
});
|
|
2001
|
-
}
|
|
2002
|
-
// src/tools/mount-upload.ts
|
|
2003
|
-
function mountUpload(server, config) {
|
|
2004
|
-
const name = config.name ?? "upload";
|
|
2005
|
-
assertToolName(name, "<native>", "upload");
|
|
2006
|
-
server.registerTool(name, {
|
|
2007
|
-
description: config.description,
|
|
2008
|
-
inputSchema: {
|
|
2009
|
-
path: ManagedFilePathSchema.describe("Path relative to the configured file boundary")
|
|
2010
|
-
}
|
|
2011
|
-
}, async (rawArgs) => {
|
|
2012
|
-
const args = isRecord(rawArgs) ? rawArgs : {};
|
|
2013
|
-
const path = typeof args.path === "string" ? args.path : "";
|
|
2014
|
-
if (!path)
|
|
2015
|
-
return textResult("Provide `path`.", true);
|
|
2016
|
-
try {
|
|
2017
|
-
const uploaded = await runUploadOperation(config.files, path, config.upload);
|
|
2018
|
-
return textResult(JSON.stringify(uploaded ?? null, null, 2));
|
|
2019
|
-
} catch (error) {
|
|
2020
|
-
const normalized = normalizeFileToolError(error);
|
|
2021
|
-
return textResult(`Upload failed [${normalized.code}]: ${normalized.message}`, true);
|
|
2022
|
-
}
|
|
2023
|
-
});
|
|
2024
|
-
}
|
|
2025
|
-
// src/tools/mount-wait.ts
|
|
2026
|
-
import { z as z7 } from "zod";
|
|
2027
|
-
function mountWait(server, config) {
|
|
2028
|
-
const name = config.name ?? "wait";
|
|
2029
|
-
assertToolName(name, "<native>", "wait");
|
|
2030
|
-
server.registerTool(name, { description: config.description, inputSchema: z7.object(config.inputSchema) }, async (rawArgs, mcpContext) => {
|
|
2031
|
-
const args = isRecord(rawArgs) ? rawArgs : {};
|
|
2032
|
-
const report = createMcpProgressReporter(mcpContext);
|
|
2033
|
-
let last;
|
|
2034
|
-
try {
|
|
2035
|
-
const { state, timedOut } = await runWaitOperation({
|
|
2036
|
-
input: args,
|
|
2037
|
-
poll: async (input) => {
|
|
2038
|
-
last = await config.poll(input);
|
|
2039
|
-
return last;
|
|
2040
|
-
},
|
|
2041
|
-
done: config.done,
|
|
2042
|
-
backoff: config.backoff,
|
|
2043
|
-
timeoutSec: config.timeoutFromArgs?.(args) ?? config.defaultTimeout,
|
|
2044
|
-
onTick: (attempt, elapsedSec) => {
|
|
2045
|
-
const snapshot = isRecord(last) ? last : undefined;
|
|
2046
|
-
const phase = typeof snapshot?.phase === "string" ? snapshot.phase : undefined;
|
|
2047
|
-
const measured = typeof snapshot?.progress === "number" && Number.isFinite(snapshot.progress) ? snapshot.progress : undefined;
|
|
2048
|
-
report({
|
|
2049
|
-
progress: measured ?? attempt,
|
|
2050
|
-
message: phase ? `${phase} — poll ${attempt}, ${Math.round(elapsedSec)}s elapsed` : `poll ${attempt}, ${Math.round(elapsedSec)}s elapsed`
|
|
2051
|
-
});
|
|
2052
|
-
}
|
|
2053
|
-
});
|
|
2054
|
-
const rendered = config.render ? config.render(state, timedOut) : { text: JSON.stringify(state, null, 2), isError: timedOut };
|
|
2055
|
-
return textResult(rendered.text, rendered.isError);
|
|
2056
|
-
} catch (err) {
|
|
2057
|
-
return textResult(`Wait failed: ${err instanceof Error ? err.message : String(err)}`, true);
|
|
2058
|
-
}
|
|
2059
|
-
});
|
|
2060
|
-
}
|
|
2061
|
-
// src/tools/oauth-provider.ts
|
|
2062
|
-
import { randomUUID } from "node:crypto";
|
|
2063
|
-
import { z as z8 } from "zod";
|
|
2064
|
-
function isPlainDisplayCharacter(character) {
|
|
2065
|
-
const codePoint = character.codePointAt(0);
|
|
2066
|
-
return codePoint !== undefined && codePoint >= 32 && codePoint !== 127 && character !== "<" && character !== ">";
|
|
2067
|
-
}
|
|
2068
|
-
var CimdClientMetadataSchema = z8.object({
|
|
2069
|
-
client_id: z8.url(),
|
|
2070
|
-
redirect_uris: z8.array(z8.url()).min(1),
|
|
2071
|
-
client_name: z8.string().trim().min(1).max(200).refine((value) => Array.from(value).every(isPlainDisplayCharacter), {
|
|
2072
|
-
message: "client_name must be plain display text"
|
|
2073
|
-
}),
|
|
2074
|
-
token_endpoint_auth_method: z8.literal("none"),
|
|
2075
|
-
application_type: z8.enum(["native", "web"]).optional()
|
|
2076
|
-
});
|
|
2077
|
-
function createSecureClientMetadataFetcher(policy = {}) {
|
|
2078
|
-
assertPositiveInteger("cimd.maxBytes", policy.maxBytes ?? DEFAULT_CIMD_MAX_BYTES);
|
|
2079
|
-
assertPositiveNumber("cimd.timeoutMs", policy.timeoutMs ?? DEFAULT_CIMD_TIMEOUT_MS);
|
|
2080
|
-
assertNonNegativeInteger("cimd.maxRedirects", policy.maxRedirects ?? 3);
|
|
2081
|
-
return {
|
|
2082
|
-
fetch: (url, headers) => fetchPinnedDocument(url, {
|
|
2083
|
-
maxBytes: policy.maxBytes ?? DEFAULT_CIMD_MAX_BYTES,
|
|
2084
|
-
timeoutMs: policy.timeoutMs ?? DEFAULT_CIMD_TIMEOUT_MS,
|
|
2085
|
-
maxRedirects: policy.maxRedirects ?? 3,
|
|
2086
|
-
headers,
|
|
2087
|
-
requireHttps: true
|
|
2088
|
-
})
|
|
2089
|
-
};
|
|
2090
|
-
}
|
|
2091
|
-
var PUBLIC_CORS2 = {
|
|
2092
|
-
"Access-Control-Allow-Origin": "*",
|
|
2093
|
-
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
2094
|
-
"Access-Control-Allow-Headers": DEFAULT_CORS_ALLOW_HEADERS
|
|
2095
|
-
};
|
|
2096
|
-
var AS_METADATA_PATH = "/.well-known/oauth-authorization-server";
|
|
2097
|
-
var AUTH_CODE_TTL_MS = 60000;
|
|
2098
|
-
var DEFAULT_CIMD_MAX_BYTES = 64 * 1024;
|
|
2099
|
-
var DEFAULT_CIMD_TIMEOUT_MS = 5000;
|
|
2100
|
-
function assertPositiveInteger(name, value) {
|
|
2101
|
-
if (!Number.isInteger(value) || value < 1)
|
|
2102
|
-
throw new Error(`${name} must be a positive integer`);
|
|
2103
|
-
}
|
|
2104
|
-
function assertNonNegativeInteger(name, value) {
|
|
2105
|
-
if (!Number.isInteger(value) || value < 0) {
|
|
2106
|
-
throw new Error(`${name} must be a non-negative integer`);
|
|
2107
|
-
}
|
|
2108
|
-
}
|
|
2109
|
-
function assertPositiveNumber(name, value) {
|
|
2110
|
-
if (!Number.isFinite(value) || value <= 0)
|
|
2111
|
-
throw new Error(`${name} must be positive`);
|
|
2112
|
-
}
|
|
2113
|
-
function absoluteClientUrl(clientId) {
|
|
2114
|
-
try {
|
|
2115
|
-
return new URL(clientId);
|
|
2116
|
-
} catch {
|
|
2117
|
-
return null;
|
|
2118
|
-
}
|
|
2119
|
-
}
|
|
2120
|
-
function assertCimdClientId(clientId) {
|
|
2121
|
-
const url = new URL(clientId);
|
|
2122
|
-
if (url.protocol !== "https:")
|
|
2123
|
-
throw new Error("CIMD client_id must use https");
|
|
2124
|
-
if (url.username || url.password)
|
|
2125
|
-
throw new Error("CIMD client_id cannot contain credentials");
|
|
2126
|
-
if (url.hash)
|
|
2127
|
-
throw new Error("CIMD client_id cannot contain a fragment");
|
|
2128
|
-
if (url.search)
|
|
2129
|
-
throw new Error("CIMD client_id cannot contain a query");
|
|
2130
|
-
if (url.toString() !== clientId) {
|
|
2131
|
-
throw new Error("CIMD client_id must be an exact canonical URL");
|
|
2132
|
-
}
|
|
2133
|
-
return url;
|
|
2134
|
-
}
|
|
2135
|
-
function parseAgeSeconds(headers) {
|
|
2136
|
-
const raw = headers.get("age");
|
|
2137
|
-
if (raw === null)
|
|
2138
|
-
return 0;
|
|
2139
|
-
const first = raw.split(",")[0]?.trim() ?? "";
|
|
2140
|
-
return /^\d+$/.test(first) ? Number(first) : 0;
|
|
2141
|
-
}
|
|
2142
|
-
function responseFreshness(headers, policy, now) {
|
|
2143
|
-
const maxTtl = policy.maxTtlMs ?? 3600000;
|
|
2144
|
-
const cacheControl = headers.get("cache-control") ?? "";
|
|
2145
|
-
if (/(?:^|,)\s*no-store\s*(?:,|$)/i.test(cacheControl)) {
|
|
2146
|
-
return { freshnessMs: 0, store: false };
|
|
2147
|
-
}
|
|
2148
|
-
if (/(?:^|,)\s*no-cache\s*(?:,|$)/i.test(cacheControl)) {
|
|
2149
|
-
return { freshnessMs: 0, store: true };
|
|
2150
|
-
}
|
|
2151
|
-
const maxAge = cacheControl.match(/(?:^|,)\s*max-age=([^,\s]*)/i)?.[1];
|
|
2152
|
-
if (maxAge !== undefined) {
|
|
2153
|
-
if (!/^\d+$/.test(maxAge))
|
|
2154
|
-
return { freshnessMs: 0, store: true };
|
|
2155
|
-
const age = parseAgeSeconds(headers);
|
|
2156
|
-
return {
|
|
2157
|
-
freshnessMs: Math.max(0, Math.min(maxTtl, (Number(maxAge) - age) * 1000)),
|
|
2158
|
-
store: true
|
|
2159
|
-
};
|
|
2160
|
-
}
|
|
2161
|
-
const expires = headers.get("expires");
|
|
2162
|
-
if (expires !== null) {
|
|
2163
|
-
const expiresAt = Date.parse(expires);
|
|
2164
|
-
if (!Number.isFinite(expiresAt))
|
|
2165
|
-
return { freshnessMs: 0, store: true };
|
|
2166
|
-
const dateAt = Date.parse(headers.get("date") ?? "");
|
|
2167
|
-
const ageMs = parseAgeSeconds(headers) * 1000;
|
|
2168
|
-
const lifetime = Number.isFinite(dateAt) ? expiresAt - dateAt : expiresAt - now;
|
|
2169
|
-
return {
|
|
2170
|
-
freshnessMs: Math.max(0, Math.min(maxTtl, lifetime - ageMs)),
|
|
2171
|
-
store: true
|
|
2172
|
-
};
|
|
2173
|
-
}
|
|
2174
|
-
return { freshnessMs: Math.min(maxTtl, policy.defaultTtlMs ?? 300000), store: true };
|
|
2175
|
-
}
|
|
2176
|
-
function safeClientName(value) {
|
|
2177
|
-
if (value === undefined)
|
|
2178
|
-
return;
|
|
2179
|
-
const safe = Array.from(value).filter(isPlainDisplayCharacter).join("").trim().slice(0, 200);
|
|
2180
|
-
return safe || undefined;
|
|
2181
|
-
}
|
|
2182
|
-
function parseScopes(value) {
|
|
2183
|
-
if (!value)
|
|
2184
|
-
return [];
|
|
2185
|
-
return [...new Set(value.split(/\s+/u).filter(Boolean))];
|
|
2186
|
-
}
|
|
2187
|
-
function toRegisteredClient(metadata) {
|
|
2188
|
-
return {
|
|
2189
|
-
clientId: metadata.client_id,
|
|
2190
|
-
redirectUris: metadata.redirect_uris,
|
|
2191
|
-
...metadata.client_name !== undefined && { clientName: metadata.client_name },
|
|
2192
|
-
...metadata.application_type !== undefined && {
|
|
2193
|
-
applicationType: metadata.application_type
|
|
2194
|
-
}
|
|
2195
|
-
};
|
|
2196
|
-
}
|
|
2197
|
-
function isJsonContentType(value) {
|
|
2198
|
-
const mediaType = value.split(";", 1)[0]?.trim().toLowerCase();
|
|
2199
|
-
return mediaType === "application/json" || mediaType?.endsWith("+json") === true;
|
|
2200
|
-
}
|
|
2201
|
-
function createCimdResolver(options) {
|
|
2202
|
-
const policy = options.cache ?? {};
|
|
2203
|
-
const now = options.now ?? Date.now;
|
|
2204
|
-
const positives = new Map;
|
|
2205
|
-
const negatives = new Map;
|
|
2206
|
-
const inflight = new Map;
|
|
2207
|
-
const maxEntries = policy.maxEntries ?? 256;
|
|
2208
|
-
const maxResolutions = policy.maxResolutions ?? 120;
|
|
2209
|
-
const maxResolutionsPerClient = policy.maxResolutionsPerClient ?? 10;
|
|
2210
|
-
const resolutionWindowMs = policy.resolutionWindowMs ?? 60000;
|
|
2211
|
-
let resolutionWindowStartedAt = now();
|
|
2212
|
-
let resolutionsInWindow = 0;
|
|
2213
|
-
const clientWindows = new Map;
|
|
2214
|
-
const CLIENT_WINDOW_CAP = 4096;
|
|
2215
|
-
assertPositiveInteger("cimd.cache.maxEntries", maxEntries);
|
|
2216
|
-
assertPositiveInteger("cimd.cache.maxResolutions", maxResolutions);
|
|
2217
|
-
assertPositiveInteger("cimd.cache.maxResolutionsPerClient", maxResolutionsPerClient);
|
|
2218
|
-
assertPositiveInteger("cimd.cache.resolutionWindowMs", resolutionWindowMs);
|
|
2219
|
-
assertNonNegativeInteger("cimd.cache.defaultTtlMs", policy.defaultTtlMs ?? 300000);
|
|
2220
|
-
assertNonNegativeInteger("cimd.cache.maxTtlMs", policy.maxTtlMs ?? 3600000);
|
|
2221
|
-
assertNonNegativeInteger("cimd.cache.negativeTtlMs", policy.negativeTtlMs ?? 1e4);
|
|
2222
|
-
const emit = (event) => {
|
|
2223
|
-
try {
|
|
2224
|
-
options.onCacheEvent?.(event);
|
|
2225
|
-
} catch {}
|
|
2226
|
-
};
|
|
2227
|
-
const readCache = (key) => positives.get(key) ?? negatives.get(key);
|
|
2228
|
-
const trimOldest = (pool) => {
|
|
2229
|
-
while (pool.size > maxEntries) {
|
|
2230
|
-
const oldest = pool.keys().next().value;
|
|
2231
|
-
if (oldest === undefined)
|
|
2232
|
-
break;
|
|
2233
|
-
pool.delete(oldest);
|
|
2234
|
-
}
|
|
2235
|
-
};
|
|
2236
|
-
const touch = (key, value) => {
|
|
2237
|
-
if (value.ok) {
|
|
2238
|
-
negatives.delete(key);
|
|
2239
|
-
positives.delete(key);
|
|
2240
|
-
positives.set(key, value);
|
|
2241
|
-
trimOldest(positives);
|
|
2242
|
-
} else {
|
|
2243
|
-
positives.delete(key);
|
|
2244
|
-
negatives.delete(key);
|
|
2245
|
-
negatives.set(key, value);
|
|
2246
|
-
trimOldest(negatives);
|
|
2247
|
-
}
|
|
2248
|
-
};
|
|
2249
|
-
const dropCache = (key) => {
|
|
2250
|
-
positives.delete(key);
|
|
2251
|
-
negatives.delete(key);
|
|
2252
|
-
};
|
|
2253
|
-
const resolveOne = async (clientId) => {
|
|
2254
|
-
const url = assertCimdClientId(clientId);
|
|
2255
|
-
const cached = readCache(clientId);
|
|
2256
|
-
if (cached && cached.expiresAt > now()) {
|
|
2257
|
-
touch(clientId, cached);
|
|
2258
|
-
if (cached.ok) {
|
|
2259
|
-
emit({ clientId, status: "hit", freshnessMs: cached.expiresAt - now() });
|
|
2260
|
-
return cached.client;
|
|
2261
|
-
}
|
|
2262
|
-
emit({ clientId, status: "negative", freshnessMs: cached.expiresAt - now() });
|
|
2263
|
-
throw new Error(cached.message);
|
|
2264
|
-
}
|
|
2265
|
-
emit({ clientId, status: "miss" });
|
|
2266
|
-
const currentTime = now();
|
|
2267
|
-
if (currentTime - resolutionWindowStartedAt >= resolutionWindowMs) {
|
|
2268
|
-
resolutionWindowStartedAt = currentTime;
|
|
2269
|
-
resolutionsInWindow = 0;
|
|
2270
|
-
}
|
|
2271
|
-
let clientWindow = clientWindows.get(clientId);
|
|
2272
|
-
if (!clientWindow || currentTime - clientWindow.startedAt >= resolutionWindowMs) {
|
|
2273
|
-
clientWindow = { startedAt: currentTime, count: 0 };
|
|
2274
|
-
clientWindows.delete(clientId);
|
|
2275
|
-
clientWindows.set(clientId, clientWindow);
|
|
2276
|
-
while (clientWindows.size > CLIENT_WINDOW_CAP) {
|
|
2277
|
-
const oldest = clientWindows.keys().next().value;
|
|
2278
|
-
if (oldest === undefined)
|
|
2279
|
-
break;
|
|
2280
|
-
clientWindows.delete(oldest);
|
|
2281
|
-
}
|
|
2282
|
-
}
|
|
2283
|
-
if (clientWindow.count >= maxResolutionsPerClient) {
|
|
2284
|
-
throw new Error("CIMD metadata resolution rate limit exceeded for this client_id");
|
|
2285
|
-
}
|
|
2286
|
-
if (resolutionsInWindow >= maxResolutions) {
|
|
2287
|
-
throw new Error("CIMD metadata resolution rate limit exceeded");
|
|
2288
|
-
}
|
|
2289
|
-
clientWindow.count += 1;
|
|
2290
|
-
resolutionsInWindow += 1;
|
|
2291
|
-
const conditionalHeaders = {};
|
|
2292
|
-
if (cached?.ok && cached.etag)
|
|
2293
|
-
conditionalHeaders["if-none-match"] = cached.etag;
|
|
2294
|
-
if (cached?.ok && cached.lastModified) {
|
|
2295
|
-
conditionalHeaders["if-modified-since"] = cached.lastModified;
|
|
2296
|
-
}
|
|
2297
|
-
try {
|
|
2298
|
-
const response = await options.fetcher.fetch(url, conditionalHeaders);
|
|
2299
|
-
const freshness = responseFreshness(response.headers, policy, now());
|
|
2300
|
-
if (response.status === 304 && cached?.ok) {
|
|
2301
|
-
const refreshed = {
|
|
2302
|
-
...cached,
|
|
2303
|
-
expiresAt: now() + freshness.freshnessMs
|
|
2304
|
-
};
|
|
2305
|
-
if (freshness.store)
|
|
2306
|
-
touch(clientId, refreshed);
|
|
2307
|
-
else
|
|
2308
|
-
dropCache(clientId);
|
|
2309
|
-
emit({ clientId, status: "revalidated", freshnessMs: freshness.freshnessMs });
|
|
2310
|
-
return refreshed.client;
|
|
2311
|
-
}
|
|
2312
|
-
if (response.status !== 200) {
|
|
2313
|
-
throw new Error(`CIMD endpoint returned HTTP ${response.status}`);
|
|
2314
|
-
}
|
|
2315
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
2316
|
-
if (!isJsonContentType(contentType)) {
|
|
2317
|
-
throw new Error("CIMD endpoint must return a JSON media type");
|
|
2318
|
-
}
|
|
2319
|
-
const decoded = JSON.parse(new TextDecoder().decode(response.body));
|
|
2320
|
-
const metadata = CimdClientMetadataSchema.parse(decoded);
|
|
2321
|
-
if (metadata.client_id !== clientId) {
|
|
2322
|
-
throw new Error("CIMD client_id does not exactly match the requested URL");
|
|
2323
|
-
}
|
|
2324
|
-
if (!metadata.redirect_uris.every((uri) => isRegistrableRedirectUri(uri, metadata.application_type))) {
|
|
2325
|
-
throw new Error("CIMD redirect_uris contains a URI forbidden for the application type");
|
|
2326
|
-
}
|
|
2327
|
-
const client = toRegisteredClient(metadata);
|
|
2328
|
-
if (freshness.store && Number.isFinite(freshness.freshnessMs)) {
|
|
2329
|
-
touch(clientId, {
|
|
2330
|
-
ok: true,
|
|
2331
|
-
client,
|
|
2332
|
-
expiresAt: now() + freshness.freshnessMs,
|
|
2333
|
-
...response.headers.get("etag") !== null && {
|
|
2334
|
-
etag: response.headers.get("etag") ?? undefined
|
|
2335
|
-
},
|
|
2336
|
-
...response.headers.get("last-modified") !== null && {
|
|
2337
|
-
lastModified: response.headers.get("last-modified") ?? undefined
|
|
2338
|
-
}
|
|
2339
|
-
});
|
|
2340
|
-
} else {
|
|
2341
|
-
dropCache(clientId);
|
|
2342
|
-
}
|
|
2343
|
-
return client;
|
|
2344
|
-
} catch (error) {
|
|
2345
|
-
const message = error instanceof Error ? error.message : "CIMD metadata resolution failed";
|
|
2346
|
-
touch(clientId, {
|
|
2347
|
-
ok: false,
|
|
2348
|
-
message,
|
|
2349
|
-
expiresAt: now() + (policy.negativeTtlMs ?? 1e4)
|
|
2350
|
-
});
|
|
2351
|
-
throw error;
|
|
2352
|
-
}
|
|
2353
|
-
};
|
|
2354
|
-
return async (clientId) => {
|
|
2355
|
-
const pending = inflight.get(clientId);
|
|
2356
|
-
if (pending)
|
|
2357
|
-
return pending;
|
|
2358
|
-
const created = resolveOne(clientId).finally(() => inflight.delete(clientId));
|
|
2359
|
-
inflight.set(clientId, created);
|
|
2360
|
-
return created;
|
|
2361
|
-
};
|
|
2362
|
-
}
|
|
2363
|
-
function json(body, status = 200, extraHeaders) {
|
|
2364
|
-
return new Response(JSON.stringify(body), {
|
|
2365
|
-
status,
|
|
2366
|
-
headers: { "Content-Type": "application/json", ...PUBLIC_CORS2, ...extraHeaders }
|
|
2367
|
-
});
|
|
2368
|
-
}
|
|
2369
|
-
function oauthError(error, description, status = 400) {
|
|
2370
|
-
return json({ error, error_description: description }, status);
|
|
2371
|
-
}
|
|
2372
|
-
function isRegistrableRedirectUri(value, applicationType) {
|
|
2373
|
-
try {
|
|
2374
|
-
const url = new URL(value);
|
|
2375
|
-
if (url.username || url.password || url.hash)
|
|
2376
|
-
return false;
|
|
2377
|
-
if (url.protocol === "https:")
|
|
2378
|
-
return true;
|
|
2379
|
-
if (url.protocol !== "http:")
|
|
2380
|
-
return false;
|
|
2381
|
-
if (applicationType === "web")
|
|
2382
|
-
return false;
|
|
2383
|
-
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
2384
|
-
return host === "127.0.0.1" || host === "::1" || host === "localhost";
|
|
2385
|
-
} catch {
|
|
2386
|
-
return false;
|
|
2387
|
-
}
|
|
2388
|
-
}
|
|
2389
|
-
function isLoopbackRedirectUri(value) {
|
|
2390
|
-
try {
|
|
2391
|
-
const url = new URL(value);
|
|
2392
|
-
if (url.protocol !== "http:")
|
|
2393
|
-
return false;
|
|
2394
|
-
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
2395
|
-
return host === "127.0.0.1" || host === "::1" || host === "localhost";
|
|
2396
|
-
} catch {
|
|
2397
|
-
return false;
|
|
2398
|
-
}
|
|
2399
|
-
}
|
|
2400
|
-
function redirectWith(uri, params) {
|
|
2401
|
-
const url = new URL(uri);
|
|
2402
|
-
for (const [key, value] of Object.entries(params))
|
|
2403
|
-
url.searchParams.set(key, value);
|
|
2404
|
-
return new Response(null, { status: 302, headers: { Location: url.toString() } });
|
|
2405
|
-
}
|
|
2406
|
-
async function readForm(req) {
|
|
2407
|
-
const contentType = req.headers.get("content-type") ?? "";
|
|
2408
|
-
if (contentType.includes("application/json")) {
|
|
2409
|
-
const body = await req.json().catch(() => null);
|
|
2410
|
-
const params = new URLSearchParams;
|
|
2411
|
-
if (isRecord(body)) {
|
|
2412
|
-
for (const [key, value] of Object.entries(body)) {
|
|
2413
|
-
if (typeof value === "string")
|
|
2414
|
-
params.set(key, value);
|
|
2415
|
-
}
|
|
2416
|
-
}
|
|
2417
|
-
return params;
|
|
2418
|
-
}
|
|
2419
|
-
return new URLSearchParams(await req.text());
|
|
2420
|
-
}
|
|
2421
|
-
function mountOAuthProvider(config) {
|
|
2422
|
-
const base = config.basePath ?? "/oauth";
|
|
2423
|
-
const ttl = config.accessTokenTtlSec ?? 3600;
|
|
2424
|
-
const registerPath = `${base}/register`;
|
|
2425
|
-
const authorizePath = `${base}/authorize`;
|
|
2426
|
-
const tokenPath = `${base}/token`;
|
|
2427
|
-
const clientRegistration = config.clientRegistration ?? {};
|
|
2428
|
-
const dcrRegistry = clientRegistration.dcr || undefined;
|
|
2429
|
-
const dcrEnabled = dcrRegistry !== undefined;
|
|
2430
|
-
const cimdConfig = clientRegistration.cimd === false ? undefined : clientRegistration.cimd ?? {};
|
|
2431
|
-
const cimdEnabled = cimdConfig !== undefined;
|
|
2432
|
-
const resolveCimd = cimdEnabled ? createCimdResolver({
|
|
2433
|
-
cache: cimdConfig.cache,
|
|
2434
|
-
fetcher: cimdConfig.fetcher ?? createSecureClientMetadataFetcher(),
|
|
2435
|
-
onCacheEvent: cimdConfig.onCacheEvent
|
|
2436
|
-
}) : undefined;
|
|
2437
|
-
const resolveClient = async (clientId) => {
|
|
2438
|
-
const preRegistered = await clientRegistration.preRegistered?.get(clientId);
|
|
2439
|
-
if (preRegistered)
|
|
2440
|
-
return preRegistered.clientId === clientId ? preRegistered : null;
|
|
2441
|
-
const clientUrl = absoluteClientUrl(clientId);
|
|
2442
|
-
if (clientUrl) {
|
|
2443
|
-
if (!resolveCimd || clientUrl.protocol !== "https:")
|
|
2444
|
-
return null;
|
|
2445
|
-
try {
|
|
2446
|
-
return await resolveCimd(clientId);
|
|
2447
|
-
} catch {
|
|
2448
|
-
return null;
|
|
2449
|
-
}
|
|
2450
|
-
}
|
|
2451
|
-
const dcrClient = await dcrRegistry?.get(clientId);
|
|
2452
|
-
return dcrClient?.clientId === clientId ? dcrClient : null;
|
|
2453
|
-
};
|
|
2454
|
-
const redirectToClient = (uri, params) => redirectWith(uri, { ...params, iss: config.issuer });
|
|
2455
|
-
const metadataRoute = {
|
|
2456
|
-
method: "ALL",
|
|
2457
|
-
path: AS_METADATA_PATH,
|
|
2458
|
-
handler: (req) => {
|
|
2459
|
-
if (req.method === "OPTIONS")
|
|
2460
|
-
return new Response(null, { status: 204, headers: PUBLIC_CORS2 });
|
|
2461
|
-
return json({
|
|
2462
|
-
issuer: config.issuer,
|
|
2463
|
-
authorization_endpoint: `${config.issuer}${authorizePath}`,
|
|
2464
|
-
token_endpoint: `${config.issuer}${tokenPath}`,
|
|
2465
|
-
...dcrEnabled && { registration_endpoint: `${config.issuer}${registerPath}` },
|
|
2466
|
-
response_types_supported: ["code"],
|
|
2467
|
-
grant_types_supported: config.refreshTokens ? ["authorization_code", "refresh_token"] : ["authorization_code"],
|
|
2468
|
-
code_challenge_methods_supported: ["S256"],
|
|
2469
|
-
token_endpoint_auth_methods_supported: ["none"],
|
|
2470
|
-
...cimdEnabled && { client_id_metadata_document_supported: true },
|
|
2471
|
-
authorization_response_iss_parameter_supported: true,
|
|
2472
|
-
...config.scopesSupported && { scopes_supported: config.scopesSupported }
|
|
2473
|
-
});
|
|
2474
|
-
}
|
|
2475
|
-
};
|
|
2476
|
-
const registerRoute = {
|
|
2477
|
-
method: "ALL",
|
|
2478
|
-
path: registerPath,
|
|
2479
|
-
handler: async (req) => {
|
|
2480
|
-
if (req.method === "OPTIONS")
|
|
2481
|
-
return new Response(null, { status: 204, headers: PUBLIC_CORS2 });
|
|
2482
|
-
if (req.method !== "POST")
|
|
2483
|
-
return oauthError("invalid_request", "POST required", 405);
|
|
2484
|
-
const meta = await req.json().catch(() => null);
|
|
2485
|
-
if (!isRecord(meta)) {
|
|
2486
|
-
return oauthError("invalid_client_metadata", "Body must be a JSON object");
|
|
2487
|
-
}
|
|
2488
|
-
const rawAppType = meta.application_type;
|
|
2489
|
-
if (rawAppType !== undefined && rawAppType !== "native" && rawAppType !== "web") {
|
|
2490
|
-
return oauthError("invalid_client_metadata", "application_type must be 'native' or 'web'");
|
|
2491
|
-
}
|
|
2492
|
-
const applicationType = rawAppType;
|
|
2493
|
-
const redirectUris = meta.redirect_uris;
|
|
2494
|
-
const tokenEndpointAuthMethod = meta.token_endpoint_auth_method ?? "none";
|
|
2495
|
-
if (tokenEndpointAuthMethod !== "none") {
|
|
2496
|
-
return oauthError("invalid_client_metadata", 'Only public clients with token_endpoint_auth_method "none" are supported');
|
|
2497
|
-
}
|
|
2498
|
-
if (!Array.isArray(redirectUris) || redirectUris.length === 0 || !redirectUris.every((u) => typeof u === "string" && isRegistrableRedirectUri(u, applicationType))) {
|
|
2499
|
-
return oauthError("invalid_redirect_uri", applicationType === "web" ? "redirect_uris must be a non-empty array of absolute https URLs (a web client cannot register an http loopback URI)" : "redirect_uris must be a non-empty array of absolute https URLs (http is allowed only on a loopback host)");
|
|
2500
|
-
}
|
|
2501
|
-
if (!dcrRegistry)
|
|
2502
|
-
throw new Error("DCR route mounted without a DCR registry");
|
|
2503
|
-
const client = await dcrRegistry.register({
|
|
2504
|
-
redirectUris,
|
|
2505
|
-
clientName: typeof meta.client_name === "string" ? meta.client_name : undefined,
|
|
2506
|
-
tokenEndpointAuthMethod,
|
|
2507
|
-
...applicationType && { applicationType }
|
|
2508
|
-
});
|
|
2509
|
-
return json({
|
|
2510
|
-
client_id: client.clientId,
|
|
2511
|
-
redirect_uris: client.redirectUris,
|
|
2512
|
-
token_endpoint_auth_method: "none",
|
|
2513
|
-
grant_types: config.refreshTokens ? ["authorization_code", "refresh_token"] : ["authorization_code"],
|
|
2514
|
-
response_types: ["code"],
|
|
2515
|
-
...client.clientName && { client_name: client.clientName },
|
|
2516
|
-
...client.applicationType && { application_type: client.applicationType }
|
|
2517
|
-
}, 201);
|
|
2518
|
-
}
|
|
2519
|
-
};
|
|
2520
|
-
const authorizeRoute = {
|
|
2521
|
-
method: "ALL",
|
|
2522
|
-
path: authorizePath,
|
|
2523
|
-
handler: async (req) => {
|
|
2524
|
-
if (req.method === "OPTIONS")
|
|
2525
|
-
return new Response(null, { status: 204, headers: PUBLIC_CORS2 });
|
|
2526
|
-
const url = new URL(req.url);
|
|
2527
|
-
const p = url.searchParams;
|
|
2528
|
-
const clientId = p.get("client_id");
|
|
2529
|
-
const redirectUri = p.get("redirect_uri");
|
|
2530
|
-
const responseType = p.get("response_type");
|
|
2531
|
-
const codeChallenge = p.get("code_challenge");
|
|
2532
|
-
const codeChallengeMethod = p.get("code_challenge_method") ?? "S256";
|
|
2533
|
-
const resource = p.get("resource");
|
|
2534
|
-
const scope = p.get("scope") ?? undefined;
|
|
2535
|
-
const state = p.get("state") ?? undefined;
|
|
2536
|
-
if (!clientId || !redirectUri) {
|
|
2537
|
-
return oauthError("invalid_request", "client_id and redirect_uri are required");
|
|
2538
|
-
}
|
|
2539
|
-
const client = await resolveClient(clientId);
|
|
2540
|
-
if (!client)
|
|
2541
|
-
return oauthError("invalid_client", "Unknown client_id", 401);
|
|
2542
|
-
if (!client.redirectUris.includes(redirectUri)) {
|
|
2543
|
-
return oauthError("invalid_request", "redirect_uri does not match a registered URI");
|
|
2544
|
-
}
|
|
2545
|
-
if (responseType !== "code") {
|
|
2546
|
-
return redirectToClient(redirectUri, {
|
|
2547
|
-
error: "unsupported_response_type",
|
|
2548
|
-
...state && { state }
|
|
2549
|
-
});
|
|
2550
|
-
}
|
|
2551
|
-
if (!codeChallenge || codeChallengeMethod !== "S256") {
|
|
2552
|
-
return redirectToClient(redirectUri, {
|
|
2553
|
-
error: "invalid_request",
|
|
2554
|
-
error_description: "PKCE S256 code_challenge is required",
|
|
2555
|
-
...state && { state }
|
|
2556
|
-
});
|
|
2557
|
-
}
|
|
2558
|
-
if (!resource) {
|
|
2559
|
-
return redirectToClient(redirectUri, {
|
|
2560
|
-
error: "invalid_target",
|
|
2561
|
-
error_description: "resource parameter is required",
|
|
2562
|
-
...state && { state }
|
|
2563
|
-
});
|
|
2564
|
-
}
|
|
2565
|
-
if (resource !== config.resource) {
|
|
2566
|
-
return redirectToClient(redirectUri, {
|
|
2567
|
-
error: "invalid_target",
|
|
2568
|
-
error_description: "resource is not served by this authorization server",
|
|
2569
|
-
...state && { state }
|
|
2570
|
-
});
|
|
2571
|
-
}
|
|
2572
|
-
const requestedScopes = parseScopes(scope);
|
|
2573
|
-
const supportedScopes = new Set(config.scopesSupported ?? []);
|
|
2574
|
-
if (config.scopesSupported && requestedScopes.some((requestedScope2) => !supportedScopes.has(requestedScope2))) {
|
|
2575
|
-
return redirectToClient(redirectUri, {
|
|
2576
|
-
error: "invalid_scope",
|
|
2577
|
-
error_description: "One or more requested scopes are not supported",
|
|
2578
|
-
...state && { state }
|
|
2579
|
-
});
|
|
2580
|
-
}
|
|
2581
|
-
const requestedScope = requestedScopes.length > 0 ? requestedScopes.join(" ") : undefined;
|
|
2582
|
-
const authRequest = {
|
|
2583
|
-
clientId,
|
|
2584
|
-
redirectUri,
|
|
2585
|
-
scope: requestedScope,
|
|
2586
|
-
resource,
|
|
2587
|
-
state,
|
|
2588
|
-
isLoopbackRedirect: isLoopbackRedirectUri(redirectUri),
|
|
2589
|
-
...safeClientName(client.clientName) !== undefined && {
|
|
2590
|
-
clientName: safeClientName(client.clientName)
|
|
2591
|
-
},
|
|
2592
|
-
...client.applicationType !== undefined && {
|
|
2593
|
-
applicationType: client.applicationType
|
|
2594
|
-
},
|
|
2595
|
-
...absoluteClientUrl(clientId)?.protocol === "https:" && {
|
|
2596
|
-
clientOrigin: new URL(clientId).origin
|
|
2597
|
-
}
|
|
2598
|
-
};
|
|
2599
|
-
const result = await config.authorizeUser(req, authRequest);
|
|
2600
|
-
if (result instanceof Response)
|
|
2601
|
-
return result;
|
|
2602
|
-
if (!Array.isArray(result.approvedScopes) || !result.approvedScopes.every((scope2) => typeof scope2 === "string")) {
|
|
2603
|
-
throw new Error("authorizeUser must return approvedScopes as an array of strings");
|
|
2604
|
-
}
|
|
2605
|
-
const approvedScopes = [...new Set(result.approvedScopes)];
|
|
2606
|
-
if (approvedScopes.some((approvedScope2) => !requestedScopes.includes(approvedScope2) || config.scopesSupported !== undefined && !supportedScopes.has(approvedScope2))) {
|
|
2607
|
-
throw new Error("authorizeUser approvedScopes must be a subset of requested scopes");
|
|
2608
|
-
}
|
|
2609
|
-
const approvedScope = approvedScopes.length > 0 ? approvedScopes.join(" ") : undefined;
|
|
2610
|
-
const code = randomUUID();
|
|
2611
|
-
await config.codes.save(code, {
|
|
2612
|
-
clientId,
|
|
2613
|
-
redirectUri,
|
|
2614
|
-
codeChallenge,
|
|
2615
|
-
codeChallengeMethod: "S256",
|
|
2616
|
-
resource,
|
|
2617
|
-
scope: approvedScope,
|
|
2618
|
-
userId: result.userId,
|
|
2619
|
-
expiresAt: Date.now() + AUTH_CODE_TTL_MS
|
|
2620
|
-
});
|
|
2621
|
-
return redirectToClient(redirectUri, { code, ...state && { state } });
|
|
2622
|
-
}
|
|
2623
|
-
};
|
|
2624
|
-
const issueAccessToken = (userId, audience, clientId, scope) => signJwt({ scope, client_id: clientId }, config.signingSecret, {
|
|
2625
|
-
issuer: config.issuer,
|
|
2626
|
-
audience,
|
|
2627
|
-
subject: userId,
|
|
2628
|
-
expiresInSec: ttl
|
|
2629
|
-
});
|
|
2630
|
-
const tokenRoute = {
|
|
2631
|
-
method: "ALL",
|
|
2632
|
-
path: tokenPath,
|
|
2633
|
-
handler: async (req) => {
|
|
2634
|
-
if (req.method === "OPTIONS")
|
|
2635
|
-
return new Response(null, { status: 204, headers: PUBLIC_CORS2 });
|
|
2636
|
-
if (req.method !== "POST")
|
|
2637
|
-
return oauthError("invalid_request", "POST required", 405);
|
|
2638
|
-
const form = await readForm(req);
|
|
2639
|
-
const grantType = form.get("grant_type");
|
|
2640
|
-
if (grantType === "authorization_code") {
|
|
2641
|
-
const code = form.get("code");
|
|
2642
|
-
const verifier = form.get("code_verifier");
|
|
2643
|
-
const redirectUri = form.get("redirect_uri");
|
|
2644
|
-
const clientId = form.get("client_id");
|
|
2645
|
-
if (!code || !verifier || !redirectUri || !clientId) {
|
|
2646
|
-
return oauthError("invalid_request", "code, code_verifier, redirect_uri, client_id required");
|
|
2647
|
-
}
|
|
2648
|
-
const data = await config.codes.take(code);
|
|
2649
|
-
if (!data)
|
|
2650
|
-
return oauthError("invalid_grant", "Unknown or used authorization code");
|
|
2651
|
-
if (data.expiresAt < Date.now())
|
|
2652
|
-
return oauthError("invalid_grant", "Authorization code expired");
|
|
2653
|
-
if (data.clientId !== clientId)
|
|
2654
|
-
return oauthError("invalid_grant", "client_id mismatch");
|
|
2655
|
-
if (data.redirectUri !== redirectUri)
|
|
2656
|
-
return oauthError("invalid_grant", "redirect_uri mismatch");
|
|
2657
|
-
if (!await verifyPkce(verifier, data.codeChallenge)) {
|
|
2658
|
-
return oauthError("invalid_grant", "PKCE verification failed");
|
|
2659
|
-
}
|
|
2660
|
-
const accessToken = await issueAccessToken(data.userId, data.resource, data.clientId, data.scope);
|
|
2661
|
-
let refreshToken;
|
|
2662
|
-
if (config.refreshTokens) {
|
|
2663
|
-
refreshToken = randomUUID();
|
|
2664
|
-
await config.refreshTokens.save(refreshToken, {
|
|
2665
|
-
clientId: data.clientId,
|
|
2666
|
-
resource: data.resource,
|
|
2667
|
-
scope: data.scope,
|
|
2668
|
-
userId: data.userId
|
|
2669
|
-
});
|
|
2670
|
-
}
|
|
2671
|
-
return json({
|
|
2672
|
-
access_token: accessToken,
|
|
2673
|
-
token_type: "Bearer",
|
|
2674
|
-
expires_in: ttl,
|
|
2675
|
-
...data.scope && { scope: data.scope },
|
|
2676
|
-
...refreshToken && { refresh_token: refreshToken }
|
|
2677
|
-
});
|
|
2678
|
-
}
|
|
2679
|
-
if (grantType === "refresh_token") {
|
|
2680
|
-
if (!config.refreshTokens) {
|
|
2681
|
-
return oauthError("unsupported_grant_type", "refresh_token grant is not enabled");
|
|
2682
|
-
}
|
|
2683
|
-
const token = form.get("refresh_token");
|
|
2684
|
-
const clientId = form.get("client_id");
|
|
2685
|
-
if (!token || !clientId)
|
|
2686
|
-
return oauthError("invalid_request", "refresh_token and client_id required");
|
|
2687
|
-
const data = await config.refreshTokens.take(token);
|
|
2688
|
-
if (!data)
|
|
2689
|
-
return oauthError("invalid_grant", "Unknown or used refresh token");
|
|
2690
|
-
if (data.clientId !== clientId)
|
|
2691
|
-
return oauthError("invalid_grant", "client_id mismatch");
|
|
2692
|
-
const accessToken = await issueAccessToken(data.userId, data.resource, data.clientId, data.scope);
|
|
2693
|
-
const newRefresh = randomUUID();
|
|
2694
|
-
await config.refreshTokens.save(newRefresh, data);
|
|
2695
|
-
return json({
|
|
2696
|
-
access_token: accessToken,
|
|
2697
|
-
token_type: "Bearer",
|
|
2698
|
-
expires_in: ttl,
|
|
2699
|
-
...data.scope && { scope: data.scope },
|
|
2700
|
-
refresh_token: newRefresh
|
|
2701
|
-
});
|
|
2702
|
-
}
|
|
2703
|
-
return oauthError("unsupported_grant_type", `Unsupported grant_type: ${grantType ?? "none"}`);
|
|
2704
|
-
}
|
|
2705
|
-
};
|
|
2706
|
-
return dcrEnabled ? [metadataRoute, registerRoute, authorizeRoute, tokenRoute] : [metadataRoute, authorizeRoute, tokenRoute];
|
|
2707
|
-
}
|
|
2708
|
-
// src/tools/registry.ts
|
|
2709
|
-
function defineToolRegistry(input) {
|
|
2710
|
-
const defaults = [...input.defaults];
|
|
2711
|
-
const slots = new Set;
|
|
2712
|
-
for (const tool of defaults) {
|
|
2713
|
-
if (!tool.name)
|
|
2714
|
-
throw new Error("A default tool must carry a non-empty name");
|
|
2715
|
-
if (slots.has(tool.name))
|
|
2716
|
-
throw new Error(`Duplicate default tool name: ${tool.name}`);
|
|
2717
|
-
slots.add(tool.name);
|
|
2718
|
-
}
|
|
2719
|
-
const disabled = new Set;
|
|
2720
|
-
const replacements = new Map;
|
|
2721
|
-
const assertKnown = (name, verb) => {
|
|
2722
|
-
if (!slots.has(name)) {
|
|
2723
|
-
throw new Error(`Tool registry ${verb}("${name}") names no default; declared: ${[...slots].sort().join(", ") || "(none)"}`);
|
|
2724
|
-
}
|
|
2725
|
-
};
|
|
2726
|
-
const builder = {
|
|
2727
|
-
replace(name, tool) {
|
|
2728
|
-
assertKnown(name, "replace");
|
|
2729
|
-
if (disabled.has(name)) {
|
|
2730
|
-
throw new Error(`Tool registry cannot replace "${name}": it is disabled`);
|
|
2731
|
-
}
|
|
2732
|
-
if (replacements.has(name)) {
|
|
2733
|
-
throw new Error(`Tool registry already replaced "${name}"`);
|
|
2734
|
-
}
|
|
2735
|
-
if (tool.name !== name) {
|
|
2736
|
-
throw new Error(`A replacement for "${name}" must carry that name, not "${tool.name}"`);
|
|
2737
|
-
}
|
|
2738
|
-
replacements.set(name, tool);
|
|
2739
|
-
return builder;
|
|
2740
|
-
},
|
|
2741
|
-
disable(name) {
|
|
2742
|
-
assertKnown(name, "disable");
|
|
2743
|
-
disabled.add(name);
|
|
2744
|
-
return builder;
|
|
2745
|
-
},
|
|
2746
|
-
build() {
|
|
2747
|
-
const tools = [];
|
|
2748
|
-
const seen = new Set;
|
|
2749
|
-
for (const tool of defaults) {
|
|
2750
|
-
if (disabled.has(tool.name))
|
|
2751
|
-
continue;
|
|
2752
|
-
const effective = replacements.get(tool.name) ?? tool;
|
|
2753
|
-
if (seen.has(effective.name)) {
|
|
2754
|
-
throw new Error(`Duplicate composed tool name: ${effective.name}`);
|
|
2755
|
-
}
|
|
2756
|
-
seen.add(effective.name);
|
|
2757
|
-
tools.push(effective);
|
|
2758
|
-
}
|
|
2759
|
-
return { tools, names: tools.map((tool) => tool.name) };
|
|
2760
|
-
}
|
|
2761
|
-
};
|
|
2762
|
-
return builder;
|
|
2763
|
-
}
|
|
2764
|
-
// src/tools/tool-logger.ts
|
|
2765
|
-
function createToolLogger(config = {}) {
|
|
2766
|
-
const log = config.log ?? ((line) => console.error(line));
|
|
2767
|
-
return {
|
|
2768
|
-
afterToolCall: ({ toolName, result, durationMs, context, endpoint }) => {
|
|
2769
|
-
const record = {
|
|
2770
|
-
tool: toolName,
|
|
2771
|
-
service: endpoint.serviceName,
|
|
2772
|
-
action: endpoint.key,
|
|
2773
|
-
ok: result.ok,
|
|
2774
|
-
code: result.ok ? undefined : result.code,
|
|
2775
|
-
durationMs: Math.round(durationMs),
|
|
2776
|
-
source: String(context.source),
|
|
2777
|
-
traceId: getTraceId()
|
|
2778
|
-
};
|
|
2779
|
-
const codePart = result.ok ? "" : ` ${result.code}`;
|
|
2780
|
-
log(`[tool] ${result.ok ? "ok" : "warn"} ${toolName} (${endpoint.serviceName}.${endpoint.key})${codePart} ${record.durationMs}ms`);
|
|
2781
|
-
config.onRecord?.(record);
|
|
2782
|
-
}
|
|
2783
|
-
};
|
|
2784
|
-
}
|
|
2785
|
-
// src/tools/toolkit.ts
|
|
2786
|
-
function createToolkit() {
|
|
2787
|
-
return {
|
|
2788
|
-
mountMcp: (server, services, config) => mountMcp(server, services, config),
|
|
2789
|
-
mountAgent: (services, config) => mountAgent(services, config),
|
|
2790
|
-
buildMcpServer: (config, auth) => buildMcpServer(config, auth),
|
|
2791
|
-
createMcpHandler: (config) => createMcpHandler(config),
|
|
2792
|
-
createStdioMcpServer: (config) => createStdioMcpServer(config),
|
|
2793
|
-
createCli: (config) => createCli(config)
|
|
2794
|
-
};
|
|
2795
|
-
}
|
|
2796
|
-
// src/tools/transports.ts
|
|
2797
|
-
var ALL_TRANSPORTS = ["HTTP", "MCP", "AGENT", "CLI"];
|
|
2798
|
-
var TOOL_TRANSPORTS2 = ["MCP", "AGENT", "CLI"];
|
|
2799
|
-
function emptyCounts() {
|
|
2800
|
-
return { HTTP: 0, MCP: 0, AGENT: 0, CLI: 0 };
|
|
2801
|
-
}
|
|
2802
|
-
function contractCounts(service) {
|
|
2803
|
-
const counts = emptyCounts();
|
|
2804
|
-
for (const method of Object.values(service.methods)) {
|
|
2805
|
-
if (!method.expose || method.expose.includes("HTTP"))
|
|
2806
|
-
counts.HTTP += 1;
|
|
2807
|
-
}
|
|
2808
|
-
for (const transport of TOOL_TRANSPORTS2) {
|
|
2809
|
-
counts[transport] = collectToolSurface({
|
|
2810
|
-
surface: { services: [service] },
|
|
2811
|
-
transport,
|
|
2812
|
-
assertNames: false,
|
|
2813
|
-
assertUniqueNames: false
|
|
2814
|
-
}).length;
|
|
2815
|
-
}
|
|
2816
|
-
return counts;
|
|
2817
|
-
}
|
|
2818
|
-
function runtimeCounts(runtimeTools) {
|
|
2819
|
-
const counts = emptyCounts();
|
|
2820
|
-
for (const transport of TOOL_TRANSPORTS2) {
|
|
2821
|
-
counts[transport] = collectToolSurface({
|
|
2822
|
-
surface: { runtimeTools },
|
|
2823
|
-
transport,
|
|
2824
|
-
assertNames: false,
|
|
2825
|
-
assertUniqueNames: false
|
|
2826
|
-
}).length;
|
|
2827
|
-
}
|
|
2828
|
-
return counts;
|
|
2829
|
-
}
|
|
2830
|
-
function addCounts(target, source) {
|
|
2831
|
-
for (const transport of ALL_TRANSPORTS)
|
|
2832
|
-
target[transport] += source[transport];
|
|
2833
|
-
}
|
|
2834
|
-
function summarizeTransports(surface) {
|
|
2835
|
-
const totals = emptyCounts();
|
|
2836
|
-
const sources = [];
|
|
2837
|
-
for (const service of surface.services ?? []) {
|
|
2838
|
-
const counts = contractCounts(service);
|
|
2839
|
-
addCounts(totals, counts);
|
|
2840
|
-
sources.push({ kind: "contract", service: service.name, counts });
|
|
2841
|
-
}
|
|
2842
|
-
const runtimeGroups = new Map;
|
|
2843
|
-
for (const definition of surface.runtimeTools ?? []) {
|
|
2844
|
-
const service = definition.identity.serviceName;
|
|
2845
|
-
const group = runtimeGroups.get(service);
|
|
2846
|
-
if (group)
|
|
2847
|
-
group.push(definition);
|
|
2848
|
-
else
|
|
2849
|
-
runtimeGroups.set(service, [definition]);
|
|
2850
|
-
}
|
|
2851
|
-
for (const [service, runtimeTools] of runtimeGroups) {
|
|
2852
|
-
const counts = runtimeCounts(runtimeTools);
|
|
2853
|
-
addCounts(totals, counts);
|
|
2854
|
-
sources.push({ kind: "runtime", service, counts });
|
|
2855
|
-
}
|
|
2856
|
-
return {
|
|
2857
|
-
contractServices: surface.services?.length ?? 0,
|
|
2858
|
-
runtimeTools: surface.runtimeTools?.length ?? 0,
|
|
2859
|
-
totals,
|
|
2860
|
-
sources
|
|
2861
|
-
};
|
|
2862
|
-
}
|
|
2863
|
-
export {
|
|
2864
|
-
wwwAuthenticateHeader,
|
|
2865
|
-
validateMcpSchemas,
|
|
2866
|
-
summarizeTransports,
|
|
2867
|
-
resolveMedia,
|
|
2868
|
-
readMcpCatalogStamp,
|
|
2869
|
-
protectedResourceMetadataUrl,
|
|
2870
|
-
oauthProtectedResourceRoute,
|
|
2871
|
-
mountWait,
|
|
2872
|
-
mountViewFile,
|
|
2873
|
-
mountUpload,
|
|
2874
|
-
mountOAuthProvider,
|
|
2875
|
-
mountMcpResource,
|
|
2876
|
-
mountMcp,
|
|
2877
|
-
mountDownload,
|
|
2878
|
-
mountAgent,
|
|
2879
|
-
mcpCatalogMeta,
|
|
2880
|
-
listToolNames,
|
|
2881
|
-
listContractToolNames,
|
|
2882
|
-
isToolExecutionControlError,
|
|
2883
|
-
isAgentToolError,
|
|
2884
|
-
inlineMcpAppBundle,
|
|
2885
|
-
flattenToolJsonSchema,
|
|
2886
|
-
findUntypedProperties,
|
|
2887
|
-
findNonPortableFormats,
|
|
2888
|
-
describeToolCatalog,
|
|
2889
|
-
defineWaitTool,
|
|
2890
|
-
defineViewFileTool,
|
|
2891
|
-
defineUploadTool,
|
|
2892
|
-
defineToolRegistry,
|
|
2893
|
-
defineRuntimeTool,
|
|
2894
|
-
defineDownloadTool,
|
|
2895
|
-
defineCliCommand,
|
|
2896
|
-
defineAsyncOperationContract,
|
|
2897
|
-
defineAsyncOperation,
|
|
2898
|
-
createToolkit,
|
|
2899
|
-
createToolLogger,
|
|
2900
|
-
createToolInvoker,
|
|
2901
|
-
createStdioMcpServer,
|
|
2902
|
-
createSecureClientMetadataFetcher,
|
|
2903
|
-
createRuntimeToolFactory,
|
|
2904
|
-
createMcpHttpRoute,
|
|
2905
|
-
createMcpHandler,
|
|
2906
|
-
createLocalStepDurability,
|
|
2907
|
-
createCli,
|
|
2908
|
-
createAsyncOperationSnapshotSchema,
|
|
2909
|
-
composeToolLifecycle,
|
|
2910
|
-
collectTools,
|
|
2911
|
-
coerceJsonArgs,
|
|
2912
|
-
buildToolManifest,
|
|
2913
|
-
buildMcpServer,
|
|
2914
|
-
bindStdioProcessSignals,
|
|
2915
|
-
bindContractAsyncOperation,
|
|
2916
|
-
ViewFileOutputSchema,
|
|
2917
|
-
ViewFileInputSchema,
|
|
2918
|
-
ViewFileErrorSchema,
|
|
2919
|
-
UploadToolInputSchema,
|
|
2920
|
-
ToolExecutionControlError,
|
|
2921
|
-
RESOURCE_MIME_TYPE,
|
|
2922
|
-
PROTECTED_RESOURCE_PATH,
|
|
2923
|
-
PORTABLE_JSON_SCHEMA_FORMATS,
|
|
2924
|
-
McpMediaContentSchema,
|
|
2925
|
-
McpAnnotationsSchema,
|
|
2926
|
-
MCP_CATALOG_META_KEY,
|
|
2927
|
-
EXT_APPS_BUNDLE_PLACEHOLDER,
|
|
2928
|
-
AsyncOperationCancelResultSchema,
|
|
2929
|
-
AgentToolError
|
|
2930
|
-
};
|