dotdo 0.0.2 → 0.1.0
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/cli/README.md +238 -0
- package/cli/agent.ts +72 -0
- package/cli/bin.js +44 -0
- package/cli/bin.ts +38 -0
- package/cli/build.ts +157 -0
- package/cli/commands/auth/login.ts +14 -0
- package/cli/commands/auth/logout.ts +6 -0
- package/cli/commands/auth/whoami.ts +16 -0
- package/cli/commands/deploy-multi.ts +245 -0
- package/cli/commands/dev/deploy.ts +100 -0
- package/cli/commands/dev/dev.ts +95 -0
- package/cli/commands/dev/logs.ts +91 -0
- package/cli/commands/dev-local.ts +88 -0
- package/cli/commands/do-ops.ts +314 -0
- package/cli/commands/index.ts +100 -0
- package/cli/commands/init.ts +247 -0
- package/cli/commands/introspect/emitter.ts +315 -0
- package/cli/commands/introspect/index.ts +193 -0
- package/cli/commands/link.ts +598 -0
- package/cli/commands/snippets.ts +415 -0
- package/cli/commands/tunnel.ts +239 -0
- package/cli/device-auth.ts +289 -0
- package/cli/fallback.ts +12 -0
- package/cli/index.ts +121 -0
- package/cli/main.ts +246 -0
- package/cli/mcp-stdio.ts +790 -0
- package/cli/package.json +62 -0
- package/cli/runtime/do-registry.ts +193 -0
- package/cli/runtime/embedded-db.ts +344 -0
- package/cli/runtime/index.ts +9 -0
- package/cli/runtime/miniflare-adapter.ts +162 -0
- package/cli/sandbox.ts +82 -0
- package/cli/src/args.ts +174 -0
- package/cli/src/auth.ts +55 -0
- package/cli/src/commands/call.ts +84 -0
- package/cli/src/commands/charge.ts +96 -0
- package/cli/src/commands/config.ts +115 -0
- package/cli/src/commands/email.ts +112 -0
- package/cli/src/commands/llm.ts +115 -0
- package/cli/src/commands/queue.ts +134 -0
- package/cli/src/commands/text.ts +86 -0
- package/cli/src/config.ts +185 -0
- package/cli/src/output.ts +246 -0
- package/cli/src/rpc.ts +192 -0
- package/cli/utils/config.ts +282 -0
- package/cli/utils/detect.ts +73 -0
- package/cli/utils/index.ts +15 -0
- package/cli/utils/logger.ts +232 -0
- package/dist/ai/template-literals.js +2 -2
- package/dist/ai/template-literals.js.map +1 -1
- package/dist/api/middleware/auth.js +3 -2
- package/dist/api/middleware/auth.js.map +1 -1
- package/dist/db/iceberg/inverted-index.js +1 -1
- package/dist/db/iceberg/inverted-index.js.map +1 -1
- package/dist/db/iceberg/puffin.js.map +1 -1
- package/dist/db/json-indexes.js.map +1 -1
- package/dist/db/objects.js.map +1 -1
- package/dist/db/primitives/dag-scheduler/index.js +1 -1
- package/dist/db/primitives/dag-scheduler/index.js.map +1 -1
- package/dist/db/primitives/observability.js.map +1 -1
- package/dist/db/primitives/schema-evolution.js.map +1 -1
- package/dist/db/primitives/temporal-store.js.map +1 -1
- package/dist/db/primitives/typed-column-store.js.map +1 -1
- package/dist/db/primitives/utils/duration.js.map +1 -1
- package/dist/db/primitives/utils/murmur3.js +12 -14
- package/dist/db/primitives/utils/murmur3.js.map +1 -1
- package/dist/db/primitives/window-manager.js.map +1 -1
- package/dist/db/stores.js.map +1 -1
- package/dist/db/things.js.map +1 -1
- package/dist/lib/DODispatcher.js +2 -2
- package/dist/lib/DODispatcher.js.map +1 -1
- package/dist/lib/auto-wiring.js.map +1 -1
- package/dist/lib/channels/email.js +1 -1
- package/dist/lib/channels/email.js.map +1 -1
- package/dist/lib/channels/slack-blockkit.js.map +1 -1
- package/dist/lib/cloudflare/ai.js +1 -1
- package/dist/lib/cloudflare/ai.js.map +1 -1
- package/dist/lib/cloudflare/kv.js +1 -1
- package/dist/lib/cloudflare/kv.js.map +1 -1
- package/dist/lib/cloudflare/r2.js +3 -3
- package/dist/lib/cloudflare/r2.js.map +1 -1
- package/dist/lib/cloudflare/vectorize.js.map +1 -1
- package/dist/lib/cloudflare/workflows.js.map +1 -1
- package/dist/lib/executors/AgenticFunctionExecutor.js.map +1 -1
- package/dist/lib/executors/CodeFunctionExecutor.js.map +1 -1
- package/dist/lib/executors/GenerativeFunctionExecutor.js.map +1 -1
- package/dist/lib/executors/HumanFunctionExecutor.js +1 -1
- package/dist/lib/executors/HumanFunctionExecutor.js.map +1 -1
- package/dist/lib/executors/ParallelStepExecutor.js.map +1 -1
- package/dist/lib/experiments.js.map +1 -1
- package/dist/lib/flags/store.js.map +1 -1
- package/dist/lib/functions/FunctionComposition.js.map +1 -1
- package/dist/lib/functions/FunctionMiddleware.js.map +1 -1
- package/dist/lib/functions/FunctionRegistry.js.map +1 -1
- package/dist/lib/humans/templates.js.map +1 -1
- package/dist/lib/identity.js +2 -2
- package/dist/lib/identity.js.map +1 -1
- package/dist/lib/logging/index.js.map +1 -1
- package/dist/lib/mixins/bash.js +1 -73
- package/dist/lib/mixins/bash.js.map +1 -1
- package/dist/lib/mixins/git.js +0 -5
- package/dist/lib/mixins/git.js.map +1 -1
- package/dist/lib/mixins/npm.js.map +1 -1
- package/dist/lib/noun-id.js.map +1 -1
- package/dist/lib/rate-limit/sliding-window.js.map +1 -1
- package/dist/lib/rpc/bindings.js.map +1 -1
- package/dist/lib/safe-stringify.js.map +1 -1
- package/dist/lib/sandbox/miniflare-sandbox.js.map +1 -1
- package/dist/lib/sqids.js.map +1 -1
- package/dist/lib/sql/adapters/node-sql-parser.js.map +1 -1
- package/dist/lib/sql/adapters/pgsql-parser.js +19 -18
- package/dist/lib/sql/adapters/pgsql-parser.js.map +1 -1
- package/dist/metrics/hunch.js.map +1 -1
- package/dist/objects/API.js +1 -1
- package/dist/objects/API.js.map +1 -1
- package/dist/objects/Agent.js.map +1 -1
- package/dist/objects/Browser.js.map +1 -1
- package/dist/objects/CLI.js.map +1 -1
- package/dist/objects/DOBase.js.map +1 -1
- package/dist/objects/DOCache.js +153 -0
- package/dist/objects/DOCache.js.map +1 -0
- package/dist/objects/DOFull.js.map +1 -1
- package/dist/objects/Entity.js.map +1 -1
- package/dist/objects/Human.js.map +1 -1
- package/dist/objects/IcebergMetadataDO.js.map +1 -1
- package/dist/objects/IntegrationsDO.js.map +1 -1
- package/dist/objects/ObservabilityBroadcaster.js.map +1 -1
- package/dist/objects/Package.js.map +1 -1
- package/dist/objects/Product.js +1 -1
- package/dist/objects/Product.js.map +1 -1
- package/dist/objects/SaaS.js.map +1 -1
- package/dist/objects/SandboxDO.js.map +1 -1
- package/dist/objects/Service.js.map +1 -1
- package/dist/objects/VectorShardDO.js +9 -7
- package/dist/objects/VectorShardDO.js.map +1 -1
- package/dist/objects/Workflow.js.map +1 -1
- package/dist/objects/WorkflowFactory.js.map +1 -1
- package/dist/objects/WorkflowRuntime.js.map +1 -1
- package/dist/objects/lifecycle/Branch.js.map +1 -1
- package/dist/objects/lifecycle/Clone.js +1 -1
- package/dist/objects/lifecycle/Clone.js.map +1 -1
- package/dist/objects/lifecycle/Compact.js.map +1 -1
- package/dist/objects/lifecycle/Shard.js.map +1 -1
- package/dist/objects/persistence/checkpoint-manager.js.map +1 -1
- package/dist/objects/persistence/migration-runner.js.map +1 -1
- package/dist/objects/persistence/replication-manager.js +2 -2
- package/dist/objects/persistence/replication-manager.js.map +1 -1
- package/dist/objects/persistence/tiered-storage-manager.js.map +1 -1
- package/dist/objects/persistence/wal-manager.js.map +1 -1
- package/dist/objects/transport/auth-layer.js.map +1 -1
- package/dist/objects/transport/chain.js.map +1 -1
- package/dist/objects/transport/mcp-server.js +7 -6
- package/dist/objects/transport/mcp-server.js.map +1 -1
- package/dist/objects/transport/rest-autowire.js +3 -2
- package/dist/objects/transport/rest-autowire.js.map +1 -1
- package/dist/objects/transport/rest-router.js.map +1 -1
- package/dist/objects/transport/rpc-server.js +18 -15
- package/dist/objects/transport/rpc-server.js.map +1 -1
- package/dist/objects/transport/shared.js +2 -1
- package/dist/objects/transport/shared.js.map +1 -1
- package/dist/snippets/artifacts-ingest.js.map +1 -1
- package/dist/snippets/artifacts-serve.js.map +1 -1
- package/dist/snippets/search.js.map +1 -1
- package/dist/workflows/ScheduleManager.js.map +1 -1
- package/dist/workflows/StepResultStorage.js.map +1 -1
- package/dist/workflows/WaitForEventManager.js.map +1 -1
- package/dist/workflows/compat/backends/cloudflare-workflows.js.map +1 -1
- package/dist/workflows/compat/inngest/index.js.map +1 -1
- package/dist/workflows/compat/qstash/index.js.map +1 -1
- package/dist/workflows/compat/temporal/client.js.map +1 -1
- package/dist/workflows/compat/temporal/index.js.map +1 -1
- package/dist/workflows/compat/trigger/index.js.map +1 -1
- package/dist/workflows/compat/utils/index.js.map +1 -1
- package/dist/workflows/context/correlation.js +2 -2
- package/dist/workflows/context/correlation.js.map +1 -1
- package/dist/workflows/context/experiment.js +1 -1
- package/dist/workflows/context/experiment.js.map +1 -1
- package/dist/workflows/context/flag.js +1 -1
- package/dist/workflows/context/flag.js.map +1 -1
- package/dist/workflows/context/measure.js +1 -1
- package/dist/workflows/context/measure.js.map +1 -1
- package/dist/workflows/context/rate-limit.js.map +1 -1
- package/dist/workflows/data/entity-events/entity-events.js.map +1 -1
- package/dist/workflows/data/experiment/index.js.map +1 -1
- package/dist/workflows/data/goal/context.js +1 -1
- package/dist/workflows/data/goal/context.js.map +1 -1
- package/dist/workflows/data/measure/index.js +1 -1
- package/dist/workflows/data/measure/index.js.map +1 -1
- package/dist/workflows/data/stream/index.js +10 -76
- package/dist/workflows/data/stream/index.js.map +1 -1
- package/dist/workflows/data/track/context.js.map +1 -1
- package/dist/workflows/data/view/context.js.map +1 -1
- package/dist/workflows/domain.js.map +1 -1
- package/dist/workflows/flags.js +1 -1
- package/dist/workflows/flags.js.map +1 -1
- package/dist/workflows/hash.js.map +1 -1
- package/dist/workflows/on.js +1 -1
- package/dist/workflows/on.js.map +1 -1
- package/dist/workflows/schedule-builder.js.map +1 -1
- package/dist/workflows/visibility/index.js +0 -2
- package/dist/workflows/visibility/index.js.map +1 -1
- package/dist/workflows/visibility/query-parser.js.map +1 -1
- package/package.json +18 -3
- package/dist/api/analytics/router.js +0 -601
- package/dist/api/analytics/router.js.map +0 -1
- package/dist/api/index.js +0 -158
- package/dist/api/index.js.map +0 -1
- package/dist/api/middleware/error-handling.js +0 -176
- package/dist/api/middleware/error-handling.js.map +0 -1
- package/dist/api/middleware/request-id.js +0 -21
- package/dist/api/middleware/request-id.js.map +0 -1
- package/dist/api/pages.js +0 -1180
- package/dist/api/pages.js.map +0 -1
- package/dist/api/routes/api.js +0 -612
- package/dist/api/routes/api.js.map +0 -1
- package/dist/api/routes/browsers.js +0 -471
- package/dist/api/routes/browsers.js.map +0 -1
- package/dist/api/routes/do.js +0 -188
- package/dist/api/routes/do.js.map +0 -1
- package/dist/api/routes/mcp.js +0 -459
- package/dist/api/routes/mcp.js.map +0 -1
- package/dist/api/routes/obs.js +0 -445
- package/dist/api/routes/obs.js.map +0 -1
- package/dist/api/routes/openapi.js +0 -794
- package/dist/api/routes/openapi.js.map +0 -1
- package/dist/api/routes/rpc.js +0 -1103
- package/dist/api/routes/rpc.js.map +0 -1
- package/dist/api/routes/sandboxes.js +0 -389
- package/dist/api/routes/sandboxes.js.map +0 -1
- package/dist/api/test-do.js +0 -38
- package/dist/api/test-do.js.map +0 -1
- package/dist/api/types.js +0 -11
- package/dist/api/types.js.map +0 -1
- package/dist/cli/bin.js +0 -2
- package/dist/cli/main.js +0 -52342
- package/dist/do/bash.js +0 -35
- package/dist/do/bash.js.map +0 -1
- package/dist/do/fs.js +0 -25
- package/dist/do/fs.js.map +0 -1
- package/dist/do/full.js +0 -61
- package/dist/do/full.js.map +0 -1
- package/dist/do/git.js +0 -28
- package/dist/do/git.js.map +0 -1
- package/dist/do/index.js +0 -52
- package/dist/do/index.js.map +0 -1
- package/dist/lib/agent/tools/bash.js +0 -336
- package/dist/lib/agent/tools/bash.js.map +0 -1
- package/dist/lib/agent/tools/edit.js +0 -157
- package/dist/lib/agent/tools/edit.js.map +0 -1
- package/dist/lib/agent/tools/glob.js +0 -137
- package/dist/lib/agent/tools/glob.js.map +0 -1
- package/dist/lib/agent/tools/grep.js +0 -315
- package/dist/lib/agent/tools/grep.js.map +0 -1
- package/dist/lib/agent/tools/index.js +0 -71
- package/dist/lib/agent/tools/index.js.map +0 -1
- package/dist/lib/agent/tools/read.js +0 -212
- package/dist/lib/agent/tools/read.js.map +0 -1
- package/dist/lib/agent/tools/types.js +0 -197
- package/dist/lib/agent/tools/types.js.map +0 -1
- package/dist/lib/agent/tools/write.js +0 -159
- package/dist/lib/agent/tools/write.js.map +0 -1
- package/dist/lib/mixins/index.js +0 -29
- package/dist/lib/mixins/index.js.map +0 -1
- package/dist/primitives/bashx/src/ast/analyze.js +0 -1472
- package/dist/primitives/bashx/src/ast/analyze.js.map +0 -1
- package/dist/primitives/bashx/src/ast/parser.js +0 -1488
- package/dist/primitives/bashx/src/ast/parser.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/crypto.js +0 -1954
- package/dist/primitives/bashx/src/do/commands/crypto.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/data-processing.js +0 -1812
- package/dist/primitives/bashx/src/do/commands/data-processing.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/extended-utils.js +0 -804
- package/dist/primitives/bashx/src/do/commands/extended-utils.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/math-control.js +0 -1122
- package/dist/primitives/bashx/src/do/commands/math-control.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/posix-utils.js +0 -1015
- package/dist/primitives/bashx/src/do/commands/posix-utils.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/system-utils.js +0 -687
- package/dist/primitives/bashx/src/do/commands/system-utils.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/test-command.js +0 -523
- package/dist/primitives/bashx/src/do/commands/test-command.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/text-processing.js +0 -1550
- package/dist/primitives/bashx/src/do/commands/text-processing.js.map +0 -1
- package/dist/primitives/bashx/src/do/container-executor.js +0 -429
- package/dist/primitives/bashx/src/do/container-executor.js.map +0 -1
- package/dist/primitives/bashx/src/do/index.js +0 -668
- package/dist/primitives/bashx/src/do/index.js.map +0 -1
- package/dist/primitives/bashx/src/do/tiered-executor.js +0 -2647
- package/dist/primitives/bashx/src/do/tiered-executor.js.map +0 -1
- package/dist/primitives/bashx/src/do/worker.js +0 -352
- package/dist/primitives/bashx/src/do/worker.js.map +0 -1
- package/dist/primitives/bashx/src/types.js +0 -10
- package/dist/primitives/bashx/src/types.js.map +0 -1
- package/dist/primitives/fsx/core/backend.js +0 -480
- package/dist/primitives/fsx/core/backend.js.map +0 -1
- package/dist/primitives/fsx/core/constants.js +0 -140
- package/dist/primitives/fsx/core/constants.js.map +0 -1
- package/dist/primitives/fsx/core/fsx.js +0 -1184
- package/dist/primitives/fsx/core/fsx.js.map +0 -1
- package/dist/primitives/fsx/core/glob/glob.js +0 -438
- package/dist/primitives/fsx/core/glob/glob.js.map +0 -1
- package/dist/primitives/fsx/core/glob/index.js +0 -8
- package/dist/primitives/fsx/core/glob/index.js.map +0 -1
- package/dist/primitives/fsx/core/glob/match.js +0 -392
- package/dist/primitives/fsx/core/glob/match.js.map +0 -1
- package/dist/primitives/fsx/core/types.js +0 -307
- package/dist/primitives/fsx/core/types.js.map +0 -1
- package/dist/sdk/capnweb-compat.js +0 -42
- package/dist/sdk/capnweb-compat.js.map +0 -1
- package/dist/sdk/client.js +0 -20
- package/dist/sdk/client.js.map +0 -1
- package/dist/sdk/index.js +0 -17
- package/dist/sdk/index.js.map +0 -1
package/dist/api/routes/do.js
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { Hono } from 'hono';
|
|
2
|
-
// Default timeout for DO fetch calls (30 seconds)
|
|
3
|
-
const DO_FETCH_TIMEOUT_MS = 30000;
|
|
4
|
-
/**
|
|
5
|
-
* Create a structured error response for DO fetch failures
|
|
6
|
-
*/
|
|
7
|
-
function createDOErrorResponse(code, message, context) {
|
|
8
|
-
return {
|
|
9
|
-
error: {
|
|
10
|
-
code,
|
|
11
|
-
message,
|
|
12
|
-
...(context && { context }),
|
|
13
|
-
},
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Wrap a fetch call with timeout
|
|
18
|
-
*/
|
|
19
|
-
async function fetchWithTimeout(stub, request, timeoutMs = DO_FETCH_TIMEOUT_MS) {
|
|
20
|
-
const controller = new AbortController();
|
|
21
|
-
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
22
|
-
try {
|
|
23
|
-
// Clone request with abort signal
|
|
24
|
-
// Need to use duplex: 'half' in Node.js environments when body is a ReadableStream
|
|
25
|
-
const hasBody = request.method !== 'GET' && request.method !== 'HEAD' && request.body;
|
|
26
|
-
const requestWithSignal = new Request(request.url, {
|
|
27
|
-
method: request.method,
|
|
28
|
-
headers: request.headers,
|
|
29
|
-
body: hasBody ? request.body : undefined,
|
|
30
|
-
signal: controller.signal,
|
|
31
|
-
// @ts-expect-error - duplex is required for Node.js but not in types
|
|
32
|
-
duplex: hasBody ? 'half' : undefined,
|
|
33
|
-
});
|
|
34
|
-
return await stub.fetch(requestWithSignal);
|
|
35
|
-
}
|
|
36
|
-
finally {
|
|
37
|
-
clearTimeout(timeoutId);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* DO Router - Routes requests to individual Durable Object instances
|
|
42
|
-
*
|
|
43
|
-
* Pattern: /:doClass/:id/*
|
|
44
|
-
*
|
|
45
|
-
* This router forwards requests to specific DO instances based on:
|
|
46
|
-
* - doClass: The DO namespace binding name (e.g., 'DO', 'TEST_DO', 'BROWSER_DO')
|
|
47
|
-
* - id: The identifier used with idFromName() to get the DO instance
|
|
48
|
-
* - *: The remaining path to forward to the DO
|
|
49
|
-
*
|
|
50
|
-
* Example:
|
|
51
|
-
* GET /DO/user-123/profile
|
|
52
|
-
* -> Gets DO namespace 'DO' from env
|
|
53
|
-
* -> Gets stub via idFromName('user-123')
|
|
54
|
-
* -> Forwards request with path '/profile' to the DO
|
|
55
|
-
*/
|
|
56
|
-
export const doRoutes = new Hono();
|
|
57
|
-
/**
|
|
58
|
-
* Route all HTTP methods to DO instances
|
|
59
|
-
*
|
|
60
|
-
* Matches: /:doClass/:id, /:doClass/:id/, /:doClass/:id/*
|
|
61
|
-
*/
|
|
62
|
-
doRoutes.all('/:doClass/:id/*', async (c) => {
|
|
63
|
-
const { doClass, id } = c.req.param();
|
|
64
|
-
const requestId = c.req.header('x-request-id') || crypto.randomUUID();
|
|
65
|
-
const source = `${doClass}/${id}`;
|
|
66
|
-
// Get DO namespace binding by class name
|
|
67
|
-
const namespace = c.env[doClass];
|
|
68
|
-
if (!namespace || typeof namespace.idFromName !== 'function') {
|
|
69
|
-
return c.json({ error: { code: 'NOT_FOUND', message: `Unknown DO class: ${doClass}` } }, 404);
|
|
70
|
-
}
|
|
71
|
-
// Get DO stub using idFromName
|
|
72
|
-
const doId = namespace.idFromName(id);
|
|
73
|
-
const stub = namespace.get(doId);
|
|
74
|
-
// Rewrite path: remove /:doClass/:id prefix
|
|
75
|
-
// Original path: /DO/user-123/some/path -> DO receives: /some/path
|
|
76
|
-
const originalPath = c.req.path;
|
|
77
|
-
const prefixPattern = new RegExp(`^/${doClass}/${encodeURIComponent(id)}`);
|
|
78
|
-
const rewrittenPath = originalPath.replace(prefixPattern, '') || '/';
|
|
79
|
-
// Build the URL for the DO request
|
|
80
|
-
const url = new URL(c.req.url);
|
|
81
|
-
url.pathname = rewrittenPath;
|
|
82
|
-
// Forward request to DO with original headers and body, wrapped in try-catch
|
|
83
|
-
try {
|
|
84
|
-
// Need to use duplex: 'half' in Node.js environments when body is a ReadableStream
|
|
85
|
-
const hasBody = c.req.method !== 'GET' && c.req.method !== 'HEAD';
|
|
86
|
-
const request = new Request(url.toString(), {
|
|
87
|
-
method: c.req.method,
|
|
88
|
-
headers: c.req.raw.headers,
|
|
89
|
-
body: hasBody ? c.req.raw.body : undefined,
|
|
90
|
-
// @ts-expect-error - duplex is required for Node.js but not in types
|
|
91
|
-
duplex: hasBody ? 'half' : undefined,
|
|
92
|
-
});
|
|
93
|
-
const response = await fetchWithTimeout(stub, request);
|
|
94
|
-
// Handle non-JSON error responses from DO
|
|
95
|
-
if (!response.ok) {
|
|
96
|
-
const contentType = response.headers.get('content-type') || '';
|
|
97
|
-
if (!contentType.includes('application/json')) {
|
|
98
|
-
const text = await response.text();
|
|
99
|
-
return c.json(createDOErrorResponse('DO_ERROR', text || 'Unknown error', {
|
|
100
|
-
source,
|
|
101
|
-
requestId,
|
|
102
|
-
}), response.status);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return response;
|
|
106
|
-
}
|
|
107
|
-
catch (error) {
|
|
108
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
109
|
-
// Check for timeout (AbortError)
|
|
110
|
-
if (error instanceof Error && error.name === 'AbortError') {
|
|
111
|
-
return c.json(createDOErrorResponse('DO_FETCH_TIMEOUT', 'Request to Durable Object timed out', {
|
|
112
|
-
source,
|
|
113
|
-
requestId,
|
|
114
|
-
originalError: errorMessage,
|
|
115
|
-
}), 504);
|
|
116
|
-
}
|
|
117
|
-
// Generic DO fetch error
|
|
118
|
-
return c.json(createDOErrorResponse('DO_FETCH_ERROR', 'Failed to communicate with Durable Object', {
|
|
119
|
-
source,
|
|
120
|
-
requestId,
|
|
121
|
-
originalError: errorMessage,
|
|
122
|
-
}), 502);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
/**
|
|
126
|
-
* Handle requests without wildcard path (e.g., /DO/user-123)
|
|
127
|
-
* Routes to the root path of the DO instance
|
|
128
|
-
*/
|
|
129
|
-
doRoutes.all('/:doClass/:id', async (c) => {
|
|
130
|
-
const { doClass, id } = c.req.param();
|
|
131
|
-
const requestId = c.req.header('x-request-id') || crypto.randomUUID();
|
|
132
|
-
const source = `${doClass}/${id}`;
|
|
133
|
-
// Get DO namespace binding by class name
|
|
134
|
-
const namespace = c.env[doClass];
|
|
135
|
-
if (!namespace || typeof namespace.idFromName !== 'function') {
|
|
136
|
-
return c.json({ error: { code: 'NOT_FOUND', message: `Unknown DO class: ${doClass}` } }, 404);
|
|
137
|
-
}
|
|
138
|
-
// Get DO stub using idFromName
|
|
139
|
-
const doId = namespace.idFromName(id);
|
|
140
|
-
const stub = namespace.get(doId);
|
|
141
|
-
// Build the URL for the DO request (root path)
|
|
142
|
-
const url = new URL(c.req.url);
|
|
143
|
-
url.pathname = '/';
|
|
144
|
-
// Forward request to DO with original headers and body, wrapped in try-catch
|
|
145
|
-
try {
|
|
146
|
-
// Need to use duplex: 'half' in Node.js environments when body is a ReadableStream
|
|
147
|
-
const hasBody = c.req.method !== 'GET' && c.req.method !== 'HEAD';
|
|
148
|
-
const request = new Request(url.toString(), {
|
|
149
|
-
method: c.req.method,
|
|
150
|
-
headers: c.req.raw.headers,
|
|
151
|
-
body: hasBody ? c.req.raw.body : undefined,
|
|
152
|
-
// @ts-expect-error - duplex is required for Node.js but not in types
|
|
153
|
-
duplex: hasBody ? 'half' : undefined,
|
|
154
|
-
});
|
|
155
|
-
const response = await fetchWithTimeout(stub, request);
|
|
156
|
-
// Handle non-JSON error responses from DO
|
|
157
|
-
if (!response.ok) {
|
|
158
|
-
const contentType = response.headers.get('content-type') || '';
|
|
159
|
-
if (!contentType.includes('application/json')) {
|
|
160
|
-
const text = await response.text();
|
|
161
|
-
return c.json(createDOErrorResponse('DO_ERROR', text || 'Unknown error', {
|
|
162
|
-
source,
|
|
163
|
-
requestId,
|
|
164
|
-
}), response.status);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return response;
|
|
168
|
-
}
|
|
169
|
-
catch (error) {
|
|
170
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
171
|
-
// Check for timeout (AbortError)
|
|
172
|
-
if (error instanceof Error && error.name === 'AbortError') {
|
|
173
|
-
return c.json(createDOErrorResponse('DO_FETCH_TIMEOUT', 'Request to Durable Object timed out', {
|
|
174
|
-
source,
|
|
175
|
-
requestId,
|
|
176
|
-
originalError: errorMessage,
|
|
177
|
-
}), 504);
|
|
178
|
-
}
|
|
179
|
-
// Generic DO fetch error
|
|
180
|
-
return c.json(createDOErrorResponse('DO_FETCH_ERROR', 'Failed to communicate with Durable Object', {
|
|
181
|
-
source,
|
|
182
|
-
requestId,
|
|
183
|
-
originalError: errorMessage,
|
|
184
|
-
}), 502);
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
export default doRoutes;
|
|
188
|
-
//# sourceMappingURL=do.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"do.js","sourceRoot":"","sources":["../../../api/routes/do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAG3B,kDAAkD;AAClD,MAAM,mBAAmB,GAAG,KAAK,CAAA;AAiBjC;;GAEG;AACH,SAAS,qBAAqB,CAC5B,IAAY,EACZ,OAAe,EACf,OAAyE;IAEzE,OAAO;QACL,KAAK,EAAE;YACL,IAAI;YACJ,OAAO;YACP,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC;SAC5B;KACF,CAAA;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,gBAAgB,CAC7B,IAAwD,EACxD,OAAgB,EAChB,YAAoB,mBAAmB;IAEvC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IACxC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAA;IAEjE,IAAI,CAAC;QACH,kCAAkC;QAClC,mFAAmF;QACnF,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,IAAI,OAAO,CAAC,IAAI,CAAA;QACrF,MAAM,iBAAiB,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE;YACjD,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;YACxC,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,qEAAqE;YACrE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;SACrC,CAAC,CAAA;QACF,OAAO,MAAM,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;IAC5C,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,SAAS,CAAC,CAAA;IACzB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,IAAI,EAAqB,CAAA;AAErD;;;;GAIG;AACH,QAAQ,CAAC,GAAG,CAAC,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC1C,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAA;IACrC,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAA;IACrE,MAAM,MAAM,GAAG,GAAG,OAAO,IAAI,EAAE,EAAE,CAAA;IAEjC,yCAAyC;IACzC,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,OAAoB,CAAuC,CAAA;IACnF,IAAI,CAAC,SAAS,IAAI,OAAO,SAAS,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;QAC7D,OAAO,CAAC,CAAC,IAAI,CACX,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,qBAAqB,OAAO,EAAE,EAAE,EAAE,EACzE,GAAG,CACJ,CAAA;IACH,CAAC;IAED,+BAA+B;IAC/B,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;IACrC,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAEhC,4CAA4C;IAC5C,mEAAmE;IACnE,MAAM,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAA;IAC/B,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,KAAK,OAAO,IAAI,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;IAC1E,MAAM,aAAa,GAAG,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,IAAI,GAAG,CAAA;IAEpE,mCAAmC;IACnC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC9B,GAAG,CAAC,QAAQ,GAAG,aAAa,CAAA;IAE5B,6EAA6E;IAC7E,IAAI,CAAC;QACH,mFAAmF;QACnF,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,MAAM,CAAA;QACjE,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YAC1C,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM;YACpB,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;YAC1B,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;YAC1C,qEAAqE;YACrE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;SACrC,CAAC,CAAA;QAEF,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QAEtD,0CAA0C;QAC1C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAA;YAC9D,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBAC9C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;gBAClC,OAAO,CAAC,CAAC,IAAI,CACX,qBAAqB,CAAC,UAAU,EAAE,IAAI,IAAI,eAAe,EAAE;oBACzD,MAAM;oBACN,SAAS;iBACV,CAAC,EACF,QAAQ,CAAC,MAAqC,CAC/C,CAAA;YACH,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAA;IACjB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAE3E,iCAAiC;QACjC,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC1D,OAAO,CAAC,CAAC,IAAI,CACX,qBAAqB,CAAC,kBAAkB,EAAE,qCAAqC,EAAE;gBAC/E,MAAM;gBACN,SAAS;gBACT,aAAa,EAAE,YAAY;aAC5B,CAAC,EACF,GAAG,CACJ,CAAA;QACH,CAAC;QAED,yBAAyB;QACzB,OAAO,CAAC,CAAC,IAAI,CACX,qBAAqB,CAAC,gBAAgB,EAAE,2CAA2C,EAAE;YACnF,MAAM;YACN,SAAS;YACT,aAAa,EAAE,YAAY;SAC5B,CAAC,EACF,GAAG,CACJ,CAAA;IACH,CAAC;AACH,CAAC,CAAC,CAAA;AAEF;;;GAGG;AACH,QAAQ,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IACxC,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAA;IACrC,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAA;IACrE,MAAM,MAAM,GAAG,GAAG,OAAO,IAAI,EAAE,EAAE,CAAA;IAEjC,yCAAyC;IACzC,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,OAAoB,CAAuC,CAAA;IACnF,IAAI,CAAC,SAAS,IAAI,OAAO,SAAS,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;QAC7D,OAAO,CAAC,CAAC,IAAI,CACX,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,qBAAqB,OAAO,EAAE,EAAE,EAAE,EACzE,GAAG,CACJ,CAAA;IACH,CAAC;IAED,+BAA+B;IAC/B,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;IACrC,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAEhC,+CAA+C;IAC/C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC9B,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAA;IAElB,6EAA6E;IAC7E,IAAI,CAAC;QACH,mFAAmF;QACnF,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,MAAM,CAAA;QACjE,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YAC1C,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM;YACpB,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;YAC1B,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;YAC1C,qEAAqE;YACrE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;SACrC,CAAC,CAAA;QAEF,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QAEtD,0CAA0C;QAC1C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAA;YAC9D,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBAC9C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;gBAClC,OAAO,CAAC,CAAC,IAAI,CACX,qBAAqB,CAAC,UAAU,EAAE,IAAI,IAAI,eAAe,EAAE;oBACzD,MAAM;oBACN,SAAS;iBACV,CAAC,EACF,QAAQ,CAAC,MAAqC,CAC/C,CAAA;YACH,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAA;IACjB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAE3E,iCAAiC;QACjC,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC1D,OAAO,CAAC,CAAC,IAAI,CACX,qBAAqB,CAAC,kBAAkB,EAAE,qCAAqC,EAAE;gBAC/E,MAAM;gBACN,SAAS;gBACT,aAAa,EAAE,YAAY;aAC5B,CAAC,EACF,GAAG,CACJ,CAAA;QACH,CAAC;QAED,yBAAyB;QACzB,OAAO,CAAC,CAAC,IAAI,CACX,qBAAqB,CAAC,gBAAgB,EAAE,2CAA2C,EAAE;YACnF,MAAM;YACN,SAAS;YACT,aAAa,EAAE,YAAY;SAC5B,CAAC,EACF,GAAG,CACJ,CAAA;IACH,CAAC;AACH,CAAC,CAAC,CAAA;AAEF,eAAe,QAAQ,CAAA"}
|
package/dist/api/routes/mcp.js
DELETED
|
@@ -1,459 +0,0 @@
|
|
|
1
|
-
import { Hono } from 'hono';
|
|
2
|
-
/**
|
|
3
|
-
* MCP HTTP Streamable Transport Handler
|
|
4
|
-
*
|
|
5
|
-
* Implements JSON-RPC 2.0 over HTTP with SSE for server-initiated notifications.
|
|
6
|
-
*
|
|
7
|
-
* Routes:
|
|
8
|
-
* - POST /mcp: Handle JSON-RPC requests
|
|
9
|
-
* - GET /mcp: SSE stream for server-initiated notifications
|
|
10
|
-
* - DELETE /mcp: Terminate session
|
|
11
|
-
*/
|
|
12
|
-
// Session storage (in-memory for now, should use DO in production)
|
|
13
|
-
const sessions = new Map();
|
|
14
|
-
// Track deleted sessions to prevent re-creation
|
|
15
|
-
const deletedSessions = new Set();
|
|
16
|
-
// Default tools available in all sessions
|
|
17
|
-
const defaultTools = [
|
|
18
|
-
{
|
|
19
|
-
name: 'echo',
|
|
20
|
-
description: 'Echo back the input message',
|
|
21
|
-
inputSchema: {
|
|
22
|
-
type: 'object',
|
|
23
|
-
properties: {
|
|
24
|
-
message: { type: 'string' },
|
|
25
|
-
},
|
|
26
|
-
required: ['message'],
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: 'create_thing',
|
|
31
|
-
description: 'Create a new thing',
|
|
32
|
-
inputSchema: {
|
|
33
|
-
type: 'object',
|
|
34
|
-
properties: {
|
|
35
|
-
type: { type: 'string' },
|
|
36
|
-
data: { type: 'object' },
|
|
37
|
-
},
|
|
38
|
-
required: ['type', 'data'],
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
name: 'delete_thing',
|
|
43
|
-
description: 'Delete a thing by ID',
|
|
44
|
-
inputSchema: {
|
|
45
|
-
type: 'object',
|
|
46
|
-
properties: {
|
|
47
|
-
id: { type: 'string' },
|
|
48
|
-
},
|
|
49
|
-
required: ['id'],
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: 'throw_error',
|
|
54
|
-
description: 'A tool that throws an internal error (for testing)',
|
|
55
|
-
inputSchema: {
|
|
56
|
-
type: 'object',
|
|
57
|
-
properties: {},
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
];
|
|
61
|
-
// Pre-populate a test session for testing purposes
|
|
62
|
-
const testSession = {
|
|
63
|
-
id: 'test-session-1',
|
|
64
|
-
createdAt: new Date(),
|
|
65
|
-
lastAccessedAt: new Date(),
|
|
66
|
-
lastActivity: new Date(),
|
|
67
|
-
tools: new Map(defaultTools.map((t) => [t.name, t])),
|
|
68
|
-
resources: new Map(),
|
|
69
|
-
clientInfo: { name: 'test-client', version: '1.0.0' },
|
|
70
|
-
capabilities: {},
|
|
71
|
-
subscriptions: [],
|
|
72
|
-
};
|
|
73
|
-
sessions.set('test-session-1', testSession);
|
|
74
|
-
export function createMcpSession() {
|
|
75
|
-
const id = crypto.randomUUID();
|
|
76
|
-
const now = new Date();
|
|
77
|
-
const session = {
|
|
78
|
-
id,
|
|
79
|
-
createdAt: now,
|
|
80
|
-
lastAccessedAt: now,
|
|
81
|
-
lastActivity: now,
|
|
82
|
-
tools: new Map(defaultTools.map((t) => [t.name, t])),
|
|
83
|
-
resources: new Map(),
|
|
84
|
-
clientInfo: undefined,
|
|
85
|
-
capabilities: {},
|
|
86
|
-
subscriptions: [],
|
|
87
|
-
};
|
|
88
|
-
sessions.set(id, session);
|
|
89
|
-
return session;
|
|
90
|
-
}
|
|
91
|
-
export function getMcpSession(sessionId) {
|
|
92
|
-
// Don't return deleted sessions (except test-session-1 which is auto-created)
|
|
93
|
-
if (deletedSessions.has(sessionId) && sessionId !== 'test-session-1') {
|
|
94
|
-
return undefined;
|
|
95
|
-
}
|
|
96
|
-
// Ensure test session exists (for testing purposes)
|
|
97
|
-
// This is auto-created for tests that use a hardcoded session ID
|
|
98
|
-
if (sessionId === 'test-session-1' && !sessions.has('test-session-1')) {
|
|
99
|
-
const now = new Date();
|
|
100
|
-
sessions.set('test-session-1', {
|
|
101
|
-
id: 'test-session-1',
|
|
102
|
-
createdAt: now,
|
|
103
|
-
lastAccessedAt: now,
|
|
104
|
-
lastActivity: now,
|
|
105
|
-
tools: new Map(defaultTools.map((t) => [t.name, t])),
|
|
106
|
-
resources: new Map(),
|
|
107
|
-
clientInfo: { name: 'test-client', version: '1.0.0' },
|
|
108
|
-
capabilities: {},
|
|
109
|
-
subscriptions: [],
|
|
110
|
-
});
|
|
111
|
-
// Also remove from deleted set if it was there
|
|
112
|
-
deletedSessions.delete('test-session-1');
|
|
113
|
-
}
|
|
114
|
-
return sessions.get(sessionId);
|
|
115
|
-
}
|
|
116
|
-
export function deleteMcpSession(sessionId) {
|
|
117
|
-
const existed = sessions.delete(sessionId);
|
|
118
|
-
if (existed) {
|
|
119
|
-
deletedSessions.add(sessionId);
|
|
120
|
-
}
|
|
121
|
-
return existed;
|
|
122
|
-
}
|
|
123
|
-
// Standard JSON-RPC error codes
|
|
124
|
-
const JSON_RPC_ERRORS = {
|
|
125
|
-
PARSE_ERROR: -32700,
|
|
126
|
-
INVALID_REQUEST: -32600,
|
|
127
|
-
METHOD_NOT_FOUND: -32601,
|
|
128
|
-
INVALID_PARAMS: -32602,
|
|
129
|
-
INTERNAL_ERROR: -32603,
|
|
130
|
-
};
|
|
131
|
-
function jsonRpcError(id, code, message, data) {
|
|
132
|
-
return {
|
|
133
|
-
jsonrpc: '2.0',
|
|
134
|
-
id,
|
|
135
|
-
error: { code, message, data },
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
function jsonRpcSuccess(id, result) {
|
|
139
|
-
return {
|
|
140
|
-
jsonrpc: '2.0',
|
|
141
|
-
id,
|
|
142
|
-
result,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
export async function handleMcpRequest(request, session) {
|
|
146
|
-
const method = request.method;
|
|
147
|
-
// OPTIONS: CORS preflight
|
|
148
|
-
if (method === 'OPTIONS') {
|
|
149
|
-
return new Response(null, {
|
|
150
|
-
status: 204,
|
|
151
|
-
headers: {
|
|
152
|
-
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
|
|
153
|
-
'Access-Control-Allow-Headers': 'Content-Type, Mcp-Session-Id',
|
|
154
|
-
'Access-Control-Max-Age': '86400',
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
// GET: SSE stream for notifications
|
|
159
|
-
if (method === 'GET') {
|
|
160
|
-
const sessionId = request.headers.get('mcp-session-id') || request.headers.get('Mcp-Session-Id');
|
|
161
|
-
if (!sessionId) {
|
|
162
|
-
return new Response(JSON.stringify(jsonRpcError(null, JSON_RPC_ERRORS.INVALID_REQUEST, 'Missing Mcp-Session-Id header')), {
|
|
163
|
-
status: 400,
|
|
164
|
-
headers: { 'Content-Type': 'application/json' },
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
const existingSession = getMcpSession(sessionId);
|
|
168
|
-
if (!existingSession) {
|
|
169
|
-
return new Response(JSON.stringify(jsonRpcError(null, JSON_RPC_ERRORS.INVALID_REQUEST, 'Session not found')), {
|
|
170
|
-
status: 404,
|
|
171
|
-
headers: { 'Content-Type': 'application/json' },
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
// Return SSE stream
|
|
175
|
-
const stream = new ReadableStream({
|
|
176
|
-
start(controller) {
|
|
177
|
-
// Send initial keep-alive comment
|
|
178
|
-
controller.enqueue(new TextEncoder().encode(': keep-alive\n\n'));
|
|
179
|
-
},
|
|
180
|
-
});
|
|
181
|
-
return new Response(stream, {
|
|
182
|
-
status: 200,
|
|
183
|
-
headers: {
|
|
184
|
-
'Content-Type': 'text/event-stream',
|
|
185
|
-
'Cache-Control': 'no-cache',
|
|
186
|
-
Connection: 'keep-alive',
|
|
187
|
-
'Mcp-Session-Id': sessionId,
|
|
188
|
-
},
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
// DELETE: Terminate session
|
|
192
|
-
if (method === 'DELETE') {
|
|
193
|
-
const sessionId = request.headers.get('mcp-session-id') || request.headers.get('Mcp-Session-Id');
|
|
194
|
-
if (!sessionId) {
|
|
195
|
-
return new Response(JSON.stringify(jsonRpcError(null, JSON_RPC_ERRORS.INVALID_REQUEST, 'Missing Mcp-Session-Id header')), {
|
|
196
|
-
status: 400,
|
|
197
|
-
headers: { 'Content-Type': 'application/json' },
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
const deleted = deleteMcpSession(sessionId);
|
|
201
|
-
if (!deleted) {
|
|
202
|
-
return new Response(JSON.stringify(jsonRpcError(null, JSON_RPC_ERRORS.INVALID_REQUEST, 'Session not found')), {
|
|
203
|
-
status: 404,
|
|
204
|
-
headers: { 'Content-Type': 'application/json' },
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
return new Response(null, { status: 204 });
|
|
208
|
-
}
|
|
209
|
-
// Only POST allowed beyond this point
|
|
210
|
-
if (method !== 'POST') {
|
|
211
|
-
return new Response(JSON.stringify(jsonRpcError(null, JSON_RPC_ERRORS.INVALID_REQUEST, 'Method not allowed')), {
|
|
212
|
-
status: 405,
|
|
213
|
-
headers: {
|
|
214
|
-
'Content-Type': 'application/json',
|
|
215
|
-
Allow: 'GET, POST, DELETE',
|
|
216
|
-
},
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
// Check Content-Type for POST
|
|
220
|
-
const contentType = request.headers.get('content-type');
|
|
221
|
-
if (!contentType || !contentType.includes('application/json')) {
|
|
222
|
-
return new Response(JSON.stringify(jsonRpcError(null, JSON_RPC_ERRORS.INVALID_REQUEST, 'Content-Type must be application/json')), {
|
|
223
|
-
status: 415,
|
|
224
|
-
headers: { 'Content-Type': 'application/json' },
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
let body;
|
|
228
|
-
try {
|
|
229
|
-
body = (await request.json());
|
|
230
|
-
}
|
|
231
|
-
catch {
|
|
232
|
-
return new Response(JSON.stringify(jsonRpcError(null, JSON_RPC_ERRORS.PARSE_ERROR, 'Parse error')), {
|
|
233
|
-
status: 200, // JSON-RPC errors use 200
|
|
234
|
-
headers: { 'Content-Type': 'application/json' },
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
// Get or create session
|
|
238
|
-
let sessionId = request.headers.get('mcp-session-id') || request.headers.get('Mcp-Session-Id');
|
|
239
|
-
let currentSession = sessionId ? getMcpSession(sessionId) : undefined;
|
|
240
|
-
// Handle batch requests
|
|
241
|
-
const requests = Array.isArray(body) ? body : [body];
|
|
242
|
-
const responses = [];
|
|
243
|
-
const responseHeaders = {
|
|
244
|
-
'Content-Type': 'application/json',
|
|
245
|
-
};
|
|
246
|
-
// Track if all requests are notifications
|
|
247
|
-
let allNotifications = true;
|
|
248
|
-
for (const req of requests) {
|
|
249
|
-
// Validate JSON-RPC format
|
|
250
|
-
if (req.jsonrpc !== '2.0') {
|
|
251
|
-
responses.push(jsonRpcError(req.id ?? null, JSON_RPC_ERRORS.INVALID_REQUEST, 'Invalid JSON-RPC version'));
|
|
252
|
-
allNotifications = false;
|
|
253
|
-
continue;
|
|
254
|
-
}
|
|
255
|
-
// Notifications have no id - no response expected
|
|
256
|
-
if (req.id === undefined) {
|
|
257
|
-
// Process notification but don't add to responses
|
|
258
|
-
continue;
|
|
259
|
-
}
|
|
260
|
-
allNotifications = false;
|
|
261
|
-
// Check params type - must be object or undefined
|
|
262
|
-
if (req.params !== undefined && (typeof req.params !== 'object' || req.params === null || Array.isArray(req.params))) {
|
|
263
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INVALID_PARAMS, 'Invalid params: must be an object'));
|
|
264
|
-
continue;
|
|
265
|
-
}
|
|
266
|
-
// Check session for non-initialize methods
|
|
267
|
-
if (req.method !== 'initialize' && req.method !== 'ping') {
|
|
268
|
-
if (sessionId && !currentSession) {
|
|
269
|
-
// Session was provided but not found - return HTTP 404
|
|
270
|
-
return new Response(JSON.stringify(jsonRpcError(req.id, JSON_RPC_ERRORS.INVALID_REQUEST, 'Session not found')), {
|
|
271
|
-
status: 404,
|
|
272
|
-
headers: { 'Content-Type': 'application/json' },
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
// Handle MCP methods
|
|
277
|
-
switch (req.method) {
|
|
278
|
-
case 'initialize': {
|
|
279
|
-
if (!currentSession) {
|
|
280
|
-
currentSession = createMcpSession();
|
|
281
|
-
sessionId = currentSession.id;
|
|
282
|
-
}
|
|
283
|
-
responses.push(jsonRpcSuccess(req.id, {
|
|
284
|
-
protocolVersion: '2024-11-05',
|
|
285
|
-
capabilities: {
|
|
286
|
-
tools: { listChanged: true },
|
|
287
|
-
resources: { subscribe: true, listChanged: true },
|
|
288
|
-
prompts: { listChanged: true },
|
|
289
|
-
},
|
|
290
|
-
serverInfo: {
|
|
291
|
-
name: 'dotdo-mcp-server',
|
|
292
|
-
version: '0.1.0',
|
|
293
|
-
},
|
|
294
|
-
}));
|
|
295
|
-
break;
|
|
296
|
-
}
|
|
297
|
-
case 'tools/list': {
|
|
298
|
-
if (!currentSession) {
|
|
299
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INVALID_REQUEST, 'Session not initialized'));
|
|
300
|
-
continue;
|
|
301
|
-
}
|
|
302
|
-
responses.push(jsonRpcSuccess(req.id, {
|
|
303
|
-
tools: Array.from(currentSession.tools.values()),
|
|
304
|
-
}));
|
|
305
|
-
break;
|
|
306
|
-
}
|
|
307
|
-
case 'tools/call': {
|
|
308
|
-
if (!currentSession) {
|
|
309
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INVALID_REQUEST, 'Session not initialized'));
|
|
310
|
-
continue;
|
|
311
|
-
}
|
|
312
|
-
const params = req.params;
|
|
313
|
-
if (!params?.name) {
|
|
314
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INVALID_PARAMS, 'Missing tool name'));
|
|
315
|
-
continue;
|
|
316
|
-
}
|
|
317
|
-
const tool = currentSession.tools.get(params.name);
|
|
318
|
-
if (!tool) {
|
|
319
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.METHOD_NOT_FOUND, `Tool not found: ${params.name}`));
|
|
320
|
-
continue;
|
|
321
|
-
}
|
|
322
|
-
// Validate required arguments
|
|
323
|
-
const toolArgs = params.arguments || {};
|
|
324
|
-
const requiredFields = Array.isArray(tool.inputSchema?.required) ? tool.inputSchema.required : [];
|
|
325
|
-
if (requiredFields.length > 0) {
|
|
326
|
-
const missingFields = requiredFields.filter((field) => !(field in toolArgs));
|
|
327
|
-
if (missingFields.length > 0) {
|
|
328
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INVALID_PARAMS, `Missing required arguments: ${missingFields.join(', ')}`));
|
|
329
|
-
continue;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
// Execute tool based on name
|
|
333
|
-
try {
|
|
334
|
-
let resultText;
|
|
335
|
-
let isError = false;
|
|
336
|
-
switch (params.name) {
|
|
337
|
-
case 'echo':
|
|
338
|
-
resultText = `Echo: ${toolArgs.message || ''}`;
|
|
339
|
-
break;
|
|
340
|
-
case 'create_thing':
|
|
341
|
-
resultText = JSON.stringify({ created: true, type: toolArgs.type, data: toolArgs.data });
|
|
342
|
-
break;
|
|
343
|
-
case 'delete_thing':
|
|
344
|
-
// Simulate not found for non-existent ID
|
|
345
|
-
if (!toolArgs.id || toolArgs.id === 'non-existent-id') {
|
|
346
|
-
resultText = 'Thing not found';
|
|
347
|
-
isError = true;
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
resultText = JSON.stringify({ deleted: true, id: toolArgs.id });
|
|
351
|
-
}
|
|
352
|
-
break;
|
|
353
|
-
case 'throw_error':
|
|
354
|
-
// Throw internal error
|
|
355
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INTERNAL_ERROR, 'Internal server error'));
|
|
356
|
-
continue;
|
|
357
|
-
default:
|
|
358
|
-
resultText = `Tool ${params.name} executed`;
|
|
359
|
-
}
|
|
360
|
-
responses.push(jsonRpcSuccess(req.id, {
|
|
361
|
-
content: [{ type: 'text', text: resultText }],
|
|
362
|
-
isError: isError ? true : undefined,
|
|
363
|
-
}));
|
|
364
|
-
}
|
|
365
|
-
catch (error) {
|
|
366
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INTERNAL_ERROR, String(error)));
|
|
367
|
-
}
|
|
368
|
-
break;
|
|
369
|
-
}
|
|
370
|
-
case 'resources/list': {
|
|
371
|
-
if (!currentSession) {
|
|
372
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INVALID_REQUEST, 'Session not initialized'));
|
|
373
|
-
continue;
|
|
374
|
-
}
|
|
375
|
-
responses.push(jsonRpcSuccess(req.id, {
|
|
376
|
-
resources: Array.from(currentSession.resources.values()),
|
|
377
|
-
}));
|
|
378
|
-
break;
|
|
379
|
-
}
|
|
380
|
-
case 'resources/read': {
|
|
381
|
-
if (!currentSession) {
|
|
382
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INVALID_REQUEST, 'Session not initialized'));
|
|
383
|
-
continue;
|
|
384
|
-
}
|
|
385
|
-
const params = req.params;
|
|
386
|
-
if (!params?.uri) {
|
|
387
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INVALID_PARAMS, 'Missing resource URI'));
|
|
388
|
-
continue;
|
|
389
|
-
}
|
|
390
|
-
responses.push(jsonRpcSuccess(req.id, {
|
|
391
|
-
contents: [{ uri: params.uri, mimeType: 'text/plain', text: '' }],
|
|
392
|
-
}));
|
|
393
|
-
break;
|
|
394
|
-
}
|
|
395
|
-
case 'ping': {
|
|
396
|
-
responses.push(jsonRpcSuccess(req.id, {}));
|
|
397
|
-
break;
|
|
398
|
-
}
|
|
399
|
-
case 'prompts/list': {
|
|
400
|
-
if (!currentSession) {
|
|
401
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INVALID_REQUEST, 'Session not initialized'));
|
|
402
|
-
continue;
|
|
403
|
-
}
|
|
404
|
-
responses.push(jsonRpcSuccess(req.id, {
|
|
405
|
-
prompts: [],
|
|
406
|
-
}));
|
|
407
|
-
break;
|
|
408
|
-
}
|
|
409
|
-
case 'prompts/get': {
|
|
410
|
-
if (!currentSession) {
|
|
411
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INVALID_REQUEST, 'Session not initialized'));
|
|
412
|
-
continue;
|
|
413
|
-
}
|
|
414
|
-
const params = req.params;
|
|
415
|
-
if (!params?.name) {
|
|
416
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INVALID_PARAMS, 'Missing prompt name'));
|
|
417
|
-
continue;
|
|
418
|
-
}
|
|
419
|
-
responses.push(jsonRpcSuccess(req.id, {
|
|
420
|
-
messages: [{ role: 'user', content: { type: 'text', text: `Prompt: ${params.name}` } }],
|
|
421
|
-
}));
|
|
422
|
-
break;
|
|
423
|
-
}
|
|
424
|
-
case 'resources/subscribe':
|
|
425
|
-
case 'resources/unsubscribe': {
|
|
426
|
-
if (!currentSession) {
|
|
427
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.INVALID_REQUEST, 'Session not initialized'));
|
|
428
|
-
continue;
|
|
429
|
-
}
|
|
430
|
-
responses.push(jsonRpcSuccess(req.id, {}));
|
|
431
|
-
break;
|
|
432
|
-
}
|
|
433
|
-
default:
|
|
434
|
-
responses.push(jsonRpcError(req.id, JSON_RPC_ERRORS.METHOD_NOT_FOUND, `Method not found: ${req.method}`));
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
// If all requests were notifications, return 204
|
|
438
|
-
if (allNotifications && responses.length === 0) {
|
|
439
|
-
return new Response(null, { status: 204 });
|
|
440
|
-
}
|
|
441
|
-
// If session was created/used, include it in response headers
|
|
442
|
-
if (currentSession) {
|
|
443
|
-
responseHeaders['Mcp-Session-Id'] = currentSession.id;
|
|
444
|
-
}
|
|
445
|
-
// Return single response or batch
|
|
446
|
-
const responseBody = Array.isArray(body) ? responses : responses[0];
|
|
447
|
-
return new Response(JSON.stringify(responseBody), {
|
|
448
|
-
status: 200,
|
|
449
|
-
headers: responseHeaders,
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
// Hono route handler
|
|
453
|
-
export const mcpRoutes = new Hono();
|
|
454
|
-
mcpRoutes.all('/', async (c) => {
|
|
455
|
-
const response = await handleMcpRequest(c.req.raw);
|
|
456
|
-
return response;
|
|
457
|
-
});
|
|
458
|
-
export default mcpRoutes;
|
|
459
|
-
//# sourceMappingURL=mcp.js.map
|