tracelattice 1.3.2 → 1.3.4
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/README.md +25 -25
- package/dist/ServerConfig.d.ts +16 -23
- package/dist/ServerConfig.d.ts.map +1 -1
- package/dist/ServerConfig.js +12 -1
- package/dist/ServerConfig.js.map +1 -1
- package/dist/__tests__/core/HistoryManager.ownership.test.d.ts +2 -0
- package/dist/__tests__/core/HistoryManager.ownership.test.d.ts.map +1 -0
- package/dist/__tests__/core/SessionLock.test.d.ts +6 -0
- package/dist/__tests__/core/SessionLock.test.d.ts.map +1 -0
- package/dist/__tests__/core/SessionManager.test.d.ts +8 -0
- package/dist/__tests__/core/SessionManager.test.d.ts.map +1 -0
- package/dist/__tests__/core/ThoughtProcessor.toolAllowlist.test.d.ts +2 -0
- package/dist/__tests__/core/ThoughtProcessor.toolAllowlist.test.d.ts.map +1 -0
- package/dist/__tests__/eval/fixtures/scenarios.d.ts.map +1 -1
- package/dist/__tests__/helpers/factories.d.ts +20 -1
- package/dist/__tests__/helpers/factories.d.ts.map +1 -1
- package/dist/__tests__/sanitize.enforceJsonShape.test.d.ts +2 -0
- package/dist/__tests__/sanitize.enforceJsonShape.test.d.ts.map +1 -0
- package/dist/__tests__/transport-owner-context.test.d.ts +8 -0
- package/dist/__tests__/transport-owner-context.test.d.ts.map +1 -0
- package/dist/cache/DiscoveryCache.d.ts +1 -1
- package/dist/cache/DiscoveryCache.d.ts.map +1 -1
- package/dist/cache/DiscoveryCache.js.map +1 -1
- package/dist/cli.js +3602 -8
- package/dist/config/ConfigLoader.d.ts +9 -2
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +12 -5
- package/dist/config/ConfigLoader.js.map +1 -1
- package/dist/context/RequestContext.d.ts +26 -0
- package/dist/context/RequestContext.d.ts.map +1 -1
- package/dist/context/RequestContext.js +7 -1
- package/dist/context/RequestContext.js.map +1 -1
- package/dist/contracts/PersistenceBackend.d.ts.map +1 -0
- package/dist/contracts/features.d.ts +39 -0
- package/dist/contracts/features.d.ts.map +1 -0
- package/dist/contracts/features.js +15 -0
- package/dist/contracts/features.js.map +1 -0
- package/dist/contracts/ids.d.ts +58 -0
- package/dist/contracts/ids.d.ts.map +1 -0
- package/dist/contracts/ids.js +31 -0
- package/dist/contracts/ids.js.map +1 -0
- package/dist/contracts/interfaces.d.ts +48 -3
- package/dist/contracts/interfaces.d.ts.map +1 -1
- package/dist/contracts/strategy.d.ts +2 -2
- package/dist/contracts/strategy.d.ts.map +1 -1
- package/dist/contracts/suspension.d.ts +3 -2
- package/dist/contracts/suspension.d.ts.map +1 -1
- package/dist/contracts/transport.d.ts +25 -0
- package/dist/contracts/transport.d.ts.map +1 -0
- package/dist/core/HistoryManager.d.ts +15 -4
- package/dist/core/HistoryManager.d.ts.map +1 -1
- package/dist/core/HistoryManager.js +25 -14
- package/dist/core/HistoryManager.js.map +1 -1
- package/dist/core/IHistoryManager.d.ts +10 -0
- package/dist/core/IHistoryManager.d.ts.map +1 -1
- package/dist/core/IThoughtFormatter.d.ts +51 -0
- package/dist/core/IThoughtFormatter.d.ts.map +1 -0
- package/dist/core/IThoughtFormatter.js +1 -0
- package/dist/core/InputNormalizer.d.ts.map +1 -1
- package/dist/core/InputNormalizer.js +9 -5
- package/dist/core/InputNormalizer.js.map +1 -1
- package/dist/core/PersistenceBuffer.d.ts +1 -1
- package/dist/core/PersistenceBuffer.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.js.map +1 -1
- package/dist/core/SessionLock.d.ts +56 -0
- package/dist/core/SessionLock.d.ts.map +1 -0
- package/dist/core/SessionLock.js +43 -0
- package/dist/core/SessionLock.js.map +1 -0
- package/dist/core/SessionManager.d.ts +18 -3
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +34 -1
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/ThoughtFormatter.d.ts +2 -1
- package/dist/core/ThoughtFormatter.d.ts.map +1 -1
- package/dist/core/ThoughtFormatter.js +3 -0
- package/dist/core/ThoughtFormatter.js.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts +22 -3
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js +41 -16
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/core/compression/CompressionService.js +3 -3
- package/dist/core/compression/CompressionService.js.map +1 -1
- package/dist/core/compression/Summary.d.ts +4 -3
- package/dist/core/compression/Summary.d.ts.map +1 -1
- package/dist/core/graph/Edge.d.ts +11 -4
- package/dist/core/graph/Edge.d.ts.map +1 -1
- package/dist/core/graph/EdgeEmitter.js +5 -5
- package/dist/core/graph/EdgeEmitter.js.map +1 -1
- package/dist/core/reasoning/strategies/StrategyFactory.d.ts +1 -1
- package/dist/core/reasoning/strategies/StrategyFactory.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/StrategyFactory.js.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js +5 -0
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js.map +1 -1
- package/dist/core/reasoning.d.ts +8 -1
- package/dist/core/reasoning.d.ts.map +1 -1
- package/dist/core/step.d.ts +5 -0
- package/dist/core/step.d.ts.map +1 -1
- package/dist/core/thought.d.ts +4 -3
- package/dist/core/thought.d.ts.map +1 -1
- package/dist/core/tools/InMemorySuspensionStore.d.ts +3 -1
- package/dist/core/tools/InMemorySuspensionStore.d.ts.map +1 -1
- package/dist/core/tools/InMemorySuspensionStore.js +2 -2
- package/dist/core/tools/InMemorySuspensionStore.js.map +1 -1
- package/dist/di/Container.d.ts +6 -3
- package/dist/di/Container.d.ts.map +1 -1
- package/dist/di/Container.js.map +1 -1
- package/dist/di/ServiceRegistry.d.ts +6 -6
- package/dist/di/ServiceRegistry.d.ts.map +1 -1
- package/dist/errors.d.ts +84 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +85 -22
- package/dist/errors.js.map +1 -1
- package/dist/health/HealthChecker.d.ts +1 -1
- package/dist/health/HealthChecker.d.ts.map +1 -1
- package/dist/health/HealthChecker.js.map +1 -1
- package/dist/lib.d.ts +60 -2
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +9 -3
- package/dist/lib.js.map +1 -1
- package/dist/persistence/FilePersistence.d.ts +2 -2
- package/dist/persistence/FilePersistence.d.ts.map +1 -1
- package/dist/persistence/FilePersistence.js.map +1 -1
- package/dist/persistence/MemoryPersistence.d.ts +1 -1
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
- package/dist/persistence/MemoryPersistence.js.map +1 -1
- package/dist/persistence/PersistenceFactory.d.ts +1 -1
- package/dist/persistence/PersistenceFactory.d.ts.map +1 -1
- package/dist/persistence/PersistenceFactory.js.map +1 -1
- package/dist/persistence/SqlitePersistence.d.ts +1 -1
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
- package/dist/persistence/SqlitePersistence.js.map +1 -1
- package/dist/pool/ConnectionPool.d.ts +11 -13
- package/dist/pool/ConnectionPool.d.ts.map +1 -1
- package/dist/pool/ConnectionPool.js.map +1 -1
- package/dist/pool/IConnectionPool.d.ts +100 -0
- package/dist/pool/IConnectionPool.d.ts.map +1 -0
- package/dist/pool/IConnectionPool.js +1 -0
- package/dist/registry/BaseRegistry.d.ts +1 -1
- package/dist/registry/BaseRegistry.d.ts.map +1 -1
- package/dist/registry/BaseRegistry.js.map +1 -1
- package/dist/registry/ToolRegistry.d.ts +1 -0
- package/dist/registry/ToolRegistry.d.ts.map +1 -1
- package/dist/registry/ToolRegistry.js +3 -0
- package/dist/registry/ToolRegistry.js.map +1 -1
- package/dist/sanitize.d.ts +70 -0
- package/dist/sanitize.d.ts.map +1 -1
- package/dist/sanitize.js +77 -1
- package/dist/sanitize.js.map +1 -1
- package/dist/schema.d.ts +35 -35
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +15 -5
- package/dist/schema.js.map +1 -1
- package/dist/transport/BaseTransport.d.ts +3 -2
- package/dist/transport/BaseTransport.d.ts.map +1 -1
- package/dist/transport/BaseTransport.js +1 -1
- package/dist/transport/BaseTransport.js.map +1 -1
- package/dist/transport/HttpTransport.d.ts +4 -2
- package/dist/transport/HttpTransport.d.ts.map +1 -1
- package/dist/transport/HttpTransport.js +13 -4
- package/dist/transport/HttpTransport.js.map +1 -1
- package/dist/transport/SseTransport.d.ts +4 -2
- package/dist/transport/SseTransport.d.ts.map +1 -1
- package/dist/transport/SseTransport.js +13 -3
- package/dist/transport/SseTransport.js.map +1 -1
- package/dist/transport/StreamableHttpTransport.d.ts +4 -2
- package/dist/transport/StreamableHttpTransport.d.ts.map +1 -1
- package/dist/transport/StreamableHttpTransport.js +12 -4
- package/dist/transport/StreamableHttpTransport.js.map +1 -1
- package/dist/types/skill.d.ts +5 -0
- package/dist/types/skill.d.ts.map +1 -1
- package/dist/types/tool.d.ts +6 -1
- package/dist/types/tool.d.ts.map +1 -1
- package/package.json +12 -11
- package/dist/__tests__/helpers/index.d.ts +0 -3
- package/dist/__tests__/helpers/index.d.ts.map +0 -1
- package/dist/contracts/index.d.ts +0 -14
- package/dist/contracts/index.d.ts.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -1
- package/dist/persistence/PersistenceBackend.d.ts.map +0 -1
- /package/dist/{persistence → contracts}/PersistenceBackend.d.ts +0 -0
- /package/dist/{persistence → contracts}/PersistenceBackend.js +0 -0
- /package/dist/contracts/{index.js → transport.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport/StreamableHttpTransport.js","sources":["../../src/transport/StreamableHttpTransport.ts"],"sourcesContent":["/**\n * Streamable HTTP Transport implementation (MCP spec recommended transport).\n *\n * This transport implements the MCP Streamable HTTP specification, which replaces\n * the deprecated SSE transport as the recommended HTTP-based transport since March 2025.\n *\n * Key features:\n * - POST /mcp for JSON-RPC requests (main MCP endpoint)\n * - GET /mcp for optional SSE server-to-client notifications\n * - Session management via Mcp-Session-Id header\n * - Supports both stateful (session-based) and stateless (per-request) modes\n * - Health endpoints (/health, /ready)\n *\n * @example\n * ```typescript\n * const transport = new StreamableHttpTransport({\n * port: 3000,\n * host: 'localhost',\n * stateful: true,\n * });\n * await transport.connect(server);\n * ```\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http';\nimport type { McpServer } from 'tmcp';\nimport { safeParse } from 'valibot';\nimport type { IMetrics } from '../contracts/index.js';\nimport { getErrorMessage } from '../errors.js';\nimport { JsonRpcRequestSchema } from '../schema.js';\nimport { BaseTransport, type TransportOptions } from './BaseTransport.js';\nimport { readRequestBody } from './HttpHelpers.js';\n\n/**\n * MCP Streamable HTTP transport options extending base TransportOptions.\n */\nexport interface StreamableHttpTransportOptions extends TransportOptions {\n\t/**\n\t * Path for the MCP endpoint\n\t * @default '/mcp'\n\t */\n\tpath?: string;\n\n\t/**\n\t * Metrics collector for transport telemetry\n\t */\n\tmetrics?: IMetrics;\n\n\t/**\n\t * Prometheus metrics provider function\n\t */\n\tmetricsProvider?: () => string;\n\n\t/**\n\t * Enable stateful session-based mode.\n\t * When true, sessions are tracked via Mcp-Session-Id header.\n\t * When false, each request is processed independently (stateless).\n\t * @default true\n\t */\n\tstateful?: boolean;\n\n\t/**\n\t * Custom session ID generator function.\n\t * @default () => randomUUID()\n\t */\n\tsessionIdGenerator?: () => string;\n\n\t/**\n\t * Enable request body size limit\n\t * @default true\n\t */\n\tenableBodySizeLimit?: boolean;\n\n\t/**\n\t * Maximum request body size in bytes\n\t * @default 10485760 (10MB)\n\t */\n\tmaxBodySize?: number;\n\n\t/**\n\t * Request timeout in milliseconds\n\t * @default 30000 (30 seconds)\n\t */\n\trequestTimeout?: number;\n}\n\n/**\n * Internal session state for stateful mode.\n */\ninterface SessionState {\n\t/** Unique session identifier */\n\tid: string;\n\t/** Timestamp when the session was created */\n\tcreatedAt: number;\n\t/** Timestamp of the last activity */\n\tlastActivityAt: number;\n\t/** Active SSE notification streams for this session */\n\tnotificationStreams: Set<ServerResponse>;\n}\n\n/**\n * Streamable HTTP Transport for MCP server.\n *\n * This transport implements the MCP Streamable HTTP specification,\n * providing JSON-RPC over HTTP with optional session management\n * and server-to-client SSE notification streams.\n *\n * @remarks\n * **Security Features (inherited from BaseTransport):**\n * - Session ID validation (alphanumeric, max 64 chars)\n * - Query parameter sanitization (whitelist allowed keys)\n * - Rate limiting per IP (configurable, default 100 req/min)\n * - CORS origin validation\n * - Host header validation\n *\n * **MCP Streamable HTTP Spec Compliance:**\n * - POST /mcp — JSON-RPC method calls\n * - GET /mcp — SSE notification stream (server-to-client)\n * - Mcp-Session-Id header for session management\n * - Content-Type: application/json for JSON-RPC responses\n * - Content-Type: text/event-stream for SSE notification streams\n *\n * **HTTP Status Code Mapping:**\n * - 200: Success (JSON-RPC response or SSE stream)\n * - 202: Accepted (JSON-RPC notification, no response body)\n * - 204: CORS Preflight (empty body)\n * - 400: Bad Request (invalid JSON, invalid session ID)\n * - 403: Forbidden (invalid CORS, invalid host)\n * - 404: Not Found\n * - 405: Method Not Allowed\n * - 413: Payload Too Large\n * - 429: Too Many Requests\n * - 500: Internal Server Error\n * - 503: Server Not Ready / Shutting Down\n */\nexport class StreamableHttpTransport extends BaseTransport {\n\tprivate _server: Server | null = null;\n\tprivate _mcpServer: McpServer | null = null;\n\tprivate _path: string;\n\tprivate _stateful: boolean;\n\tprivate _sessionIdGenerator: () => string;\n\tprivate _sessions: Map<string, SessionState> = new Map();\n\tprivate _requestCount: number = 0;\n\tprivate _activeRequests: number = 0;\n\tprivate _bodySizeLimitEnabled: boolean;\n\tprivate _maxBodySize: number;\n\tprivate _requestTimeout: number;\n\tprivate _metrics?: IMetrics;\n\tprivate _metricsProvider: (() => string) | null;\n\n\tconstructor(options: StreamableHttpTransportOptions = {}) {\n\t\tsuper(options);\n\n\t\tthis._path = options.path ?? '/mcp';\n\t\tthis._stateful = options.stateful ?? true;\n\t\tthis._sessionIdGenerator = options.sessionIdGenerator ?? (() => randomUUID());\n\t\tthis._bodySizeLimitEnabled = options.enableBodySizeLimit ?? true;\n\t\tthis._maxBodySize = options.maxBodySize ?? 10 * 1024 * 1024;\n\t\tthis._requestTimeout = options.requestTimeout ?? 30000;\n\t\tthis._metrics = options.metrics;\n\t\tthis._metricsProvider = options.metricsProvider ?? null;\n\t}\n\n\t/**\n\t * Get number of active sessions (stateful) or active requests (stateless).\n\t */\n\tget clientCount(): number {\n\t\treturn this._stateful ? this._sessions.size : this._activeRequests;\n\t}\n\n\t/**\n\t * Get the total number of requests handled.\n\t */\n\tget requestCount(): number {\n\t\treturn this._requestCount;\n\t}\n\n\t/**\n\t * Connects MCP server to this transport and starts listening.\n\t */\n\tasync connect(mcpServer: McpServer): Promise<void> {\n\t\tthis._mcpServer = mcpServer;\n\t\tthis._server = createServer((req, res) => this._handleRequest(req, res));\n\n\t\treturn new Promise((resolve) => {\n\t\t\tthis._server!.listen(this._port, this._host, () => {\n\t\t\t\tthis.log(\n\t\t\t\t\t'info',\n\t\t\t\t\t`Streamable HTTP transport listening on http://${this._host}:${this._port}`\n\t\t\t\t);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Route and handle incoming HTTP requests.\n\t */\n\tprivate async _handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n\t\tconst startTime = Date.now();\n\t\tthis._metrics?.counter('streamable_http_requests_total', 1, {}, 'Total Streamable HTTP transport requests');\n\t\tres.once('finish', () => {\n\t\t\tconst durationSeconds = (Date.now() - startTime) / 1000;\n\t\t\tthis._metrics?.histogram('streamable_http_request_duration_seconds', durationSeconds, {});\n\t\t});\n\n\t\t// Host validation\n\t\tif (!this.validateHostHeader(req)) {\n\t\t\tthis._sendJsonRpcError(res, 403, -32000, 'Forbidden - invalid host header');\n\t\t\treturn;\n\t\t}\n\n\t\t// Shutdown check\n\t\tif (this.isShuttingDown()) {\n\t\t\tthis._sendJsonRpcError(res, 503, -32603, 'Server is shutting down');\n\t\t\treturn;\n\t\t}\n\n\t\t// Rate limiting\n\t\tconst clientIp = this.getClientIp(req);\n\t\tif (this.checkRateLimit(clientIp)) {\n\t\t\tres.setHeader('Retry-After', '60');\n\t\t\tthis._sendJsonRpcError(res, 429, -32000, 'Too many requests');\n\t\t\treturn;\n\t\t}\n\n\t\t// CORS validation\n\t\tif (!this.validateCorsOrigin(req)) {\n\t\t\tthis._sendJsonRpcError(res, 403, -32000, 'Forbidden - invalid origin');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setCorsHeaders(res);\n\n\t\t// CORS preflight\n\t\tif (req.method === 'OPTIONS') {\n\t\t\tres.setHeader('Access-Control-Allow-Headers', 'Content-Type, Mcp-Session-Id');\n\t\t\tres.writeHead(204);\n\t\t\tres.end();\n\t\t\treturn;\n\t\t}\n\n\t\t// Parse URL path\n\t\tconst urlPath = req.url?.split('?')[0] ?? '/';\n\n\t\t// Metrics endpoint\n\t\tif (req.method === 'GET' && urlPath === '/metrics') {\n\t\t\tthis._handleMetrics(res);\n\t\t\treturn;\n\t\t}\n\n\t\t// Health check (liveness)\n\t\tif (req.method === 'GET' && urlPath === '/health') {\n\t\t\tthis._handleHealthCheck(res);\n\t\t\treturn;\n\t\t}\n\n\t\t// Readiness check\n\t\tif (req.method === 'GET' && urlPath === '/ready') {\n\t\t\tawait this._handleReadinessCheck(res);\n\t\t\treturn;\n\t\t}\n\n\t\t// MCP endpoint routing\n\t\tif (urlPath === this._path) {\n\t\t\tif (req.method === 'POST') {\n\t\t\t\tawait this._handleMcpPost(req, res);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (req.method === 'GET') {\n\t\t\t\tthis._handleMcpGet(req, res);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tres.writeHead(405, { 'Content-Type': 'application/json', Allow: 'GET, POST' });\n\t\t\tres.end(JSON.stringify({ jsonrpc: '2.0', id: null, error: { code: -32601, message: 'Method not allowed' } }));\n\t\t\treturn;\n\t\t}\n\n\t\t// 404 for unknown paths\n\t\tthis._sendJsonRpcError(res, 404, -32601, 'Not Found');\n\t}\n\n\t/**\n\t * Send a JSON-RPC error response.\n\t */\n\tprivate _sendJsonRpcError(res: ServerResponse, statusCode: number, code: number, message: string, id: unknown = null, extra?: Record<string, unknown>): void {\n\t\tconst error: Record<string, unknown> = { code, message };\n\t\tif (extra) {\n\t\t\tObject.assign(error, extra);\n\t\t}\n\t\tres.writeHead(statusCode, { 'Content-Type': 'application/json' });\n\t\tres.end(JSON.stringify({ jsonrpc: '2.0', id, error }));\n\t}\n\n\t/**\n\t * Handle POST /mcp — JSON-RPC method calls.\n\t *\n\t * Per the MCP Streamable HTTP spec:\n\t * - Accepts JSON-RPC request bodies\n\t * - Returns Mcp-Session-Id header for new sessions (stateful mode)\n\t * - Validates Mcp-Session-Id for existing sessions (stateful mode)\n\t * - Content-Type: application/json for responses\n\t */\n\tprivate async _handleMcpPost(req: IncomingMessage, res: ServerResponse): Promise<void> {\n\t\tthis._requestCount++;\n\t\tthis._activeRequests++;\n\n\t\tconst timeout = setTimeout(() => {\n\t\t\tthis._activeRequests--;\n\t\t\tthis._sendJsonRpcError(res, 500, -32603, 'Request timeout');\n\t\t}, this._requestTimeout);\n\n\t\ttry {\n\t\t\t// Read request body with size limit\n\t\t\tconst body = await readRequestBody(req, this._bodySizeLimitEnabled ? this._maxBodySize : 0);\n\t\t\tif (body === null) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._sendJsonRpcError(res, 413, -32000, 'Request body too large');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Parse JSON\n\t\t\tlet jsonRpcRequest;\n\t\t\ttry {\n\t\t\t\tjsonRpcRequest = JSON.parse(body);\n\t\t\t} catch {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._sendJsonRpcError(res, 200, -32700, 'Parse error');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Validate JSON-RPC schema\n\t\t\tconst parseResult = safeParse(JsonRpcRequestSchema, jsonRpcRequest);\n\t\t\tif (!parseResult.success) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._sendJsonRpcError(res, 200, -32600, 'Invalid Request', jsonRpcRequest?.id ?? null, { data: parseResult.issues });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Session management (stateful mode)\n\t\t\tlet sessionId: string | undefined;\n\t\t\tif (this._stateful) {\n\t\t\t\tconst sessionResult = this._resolveSession(req, res);\n\t\t\t\tif (sessionResult === false) {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tthis._activeRequests--;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsessionId = sessionResult;\n\t\t\t}\n\n\t\t\t// Check if MCP server is ready\n\t\t\tif (!this._mcpServer) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._sendJsonRpcError(res, 503, -32603, 'Server not ready', jsonRpcRequest?.id ?? null);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Process JSON-RPC request through MCP server\n\t\t\tconst response = await this._mcpServer.receive(jsonRpcRequest, { sessionInfo: {} });\n\t\t\tclearTimeout(timeout);\n\t\t\tthis._activeRequests--;\n\n\t\t\t// Send response with session header if applicable\n\t\t\tconst responseHeaders: Record<string, string> = { 'Content-Type': 'application/json' };\n\t\t\tif (sessionId) responseHeaders['Mcp-Session-Id'] = sessionId;\n\n\t\t\tif (response) {\n\t\t\t\tres.writeHead(200, responseHeaders);\n\t\t\t\tres.end(JSON.stringify(response));\n\t\t\t} else {\n\t\t\t\tif (sessionId) res.setHeader('Mcp-Session-Id', sessionId);\n\t\t\t\tres.writeHead(202);\n\t\t\t\tres.end();\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tclearTimeout(timeout);\n\t\t\tthis._activeRequests--;\n\t\t\tthis._sendJsonRpcError(res, 200, -32603, 'Internal error', null, {\n\t\t\t\tdata: getErrorMessage(error),\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/**\n\t * Handle GET /mcp — Optional SSE notification stream.\n\t *\n\t * Per the MCP Streamable HTTP spec, clients may open a GET request\n\t * to receive server-initiated notifications as SSE events.\n\t * Requires a valid Mcp-Session-Id in stateful mode.\n\t */\n\tprivate _handleMcpGet(req: IncomingMessage, res: ServerResponse): void {\n\t\tif (!this._stateful) {\n\t\t\t// SSE notification streams require stateful mode\n\t\t\tres.writeHead(405, {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\tAllow: 'POST',\n\t\t\t});\n\t\t\tres.end(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\tid: null,\n\t\t\t\t\terror: { code: -32601, message: 'GET not supported in stateless mode' },\n\t\t\t\t})\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Require Mcp-Session-Id for GET requests\n\t\tconst sessionId = this._getSessionIdFromHeader(req);\n\t\tif (!sessionId) {\n\t\t\tres.writeHead(400, { 'Content-Type': 'application/json' });\n\t\t\tres.end(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\tid: null,\n\t\t\t\t\terror: { code: -32600, message: 'Missing Mcp-Session-Id header' },\n\t\t\t\t})\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst session = this._sessions.get(sessionId);\n\t\tif (!session) {\n\t\t\tres.writeHead(404, { 'Content-Type': 'application/json' });\n\t\t\tres.end(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\tid: null,\n\t\t\t\t\terror: { code: -32001, message: 'Session not found' },\n\t\t\t\t})\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Set SSE headers\n\t\tres.writeHead(200, {\n\t\t\t'Content-Type': 'text/event-stream',\n\t\t\t'Cache-Control': 'no-cache',\n\t\t\tConnection: 'keep-alive',\n\t\t\t'Mcp-Session-Id': sessionId,\n\t\t});\n\n\t\t// Send initial connected event\n\t\tthis._sendSseEvent(res, 'connected', {\n\t\t\tsessionId,\n\t\t\ttimestamp: Date.now(),\n\t\t});\n\n\t\t// Track this notification stream\n\t\tsession.notificationStreams.add(res);\n\t\tsession.lastActivityAt = Date.now();\n\t\tthis._updateSessionMetrics();\n\n\t\t// Handle client disconnect\n\t\treq.on('close', () => {\n\t\t\tsession.notificationStreams.delete(res);\n\t\t\tthis._updateSessionMetrics();\n\t\t});\n\t}\n\n\t/**\n\t * Resolve or create a session for a stateful request.\n\t *\n\t * @returns Session ID string on success, or `false` if the response was already sent (error).\n\t */\n\tprivate _resolveSession(req: IncomingMessage, res: ServerResponse): string | false {\n\t\tconst headerSessionId = this._getSessionIdFromHeader(req);\n\n\t\tif (headerSessionId) {\n\t\t\t// Validate format\n\t\t\tif (!this.validateSessionId(headerSessionId)) {\n\t\t\t\tres.writeHead(400, { 'Content-Type': 'application/json' });\n\t\t\t\tres.end(\n\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\t\tid: null,\n\t\t\t\t\t\terror: { code: -32600, message: 'Invalid Mcp-Session-Id format' },\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Check if session exists\n\t\t\tconst session = this._sessions.get(headerSessionId);\n\t\t\tif (session) {\n\t\t\t\tsession.lastActivityAt = Date.now();\n\t\t\t\treturn headerSessionId;\n\t\t\t}\n\n\t\t\t// Unknown session ID — per spec, return 404\n\t\t\tres.writeHead(404, { 'Content-Type': 'application/json' });\n\t\t\tres.end(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\tid: null,\n\t\t\t\t\terror: { code: -32001, message: 'Session not found' },\n\t\t\t\t})\n\t\t\t);\n\t\t\treturn false;\n\t\t}\n\n\t\t// No session header — create new session\n\t\tconst newSessionId = this._sessionIdGenerator();\n\t\tconst sessionState: SessionState = {\n\t\t\tid: newSessionId,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tlastActivityAt: Date.now(),\n\t\t\tnotificationStreams: new Set(),\n\t\t};\n\t\tthis._sessions.set(newSessionId, sessionState);\n\t\tthis.log('info', `New session created: ${newSessionId}`);\n\t\tthis._updateSessionMetrics();\n\n\t\treturn newSessionId;\n\t}\n\n\t/**\n\t * Extract Mcp-Session-Id from request headers.\n\t */\n\tprivate _getSessionIdFromHeader(req: IncomingMessage): string | undefined {\n\t\tconst value = req.headers['mcp-session-id'];\n\t\tif (typeof value === 'string' && value.length > 0) {\n\t\t\treturn value;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\n\t/**\n\t * Send an SSE event to a specific client response stream.\n\t */\n\tprivate _sendSseEvent(res: ServerResponse, event: string, data: unknown): void {\n\t\ttry {\n\t\t\tres.write(`event: ${event}\\n`);\n\t\t\tres.write(`data: ${JSON.stringify(data)}\\n\\n`);\n\t\t} catch {\n\t\t\t// Client disconnected — ignore\n\t\t}\n\t}\n\n\t/**\n\t * Broadcast a notification to all SSE streams in a given session.\n\t *\n\t * @param sessionId - Target session ID\n\t * @param event - SSE event name\n\t * @param data - Event payload\n\t */\n\tbroadcastToSession(sessionId: string, event: string, data: unknown): void {\n\t\tconst session = this._sessions.get(sessionId);\n\t\tif (!session) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const stream of session.notificationStreams) {\n\t\t\tthis._sendSseEvent(stream, event, data);\n\t\t}\n\t}\n\n\t/**\n\t * Handle GET /metrics endpoint.\n\t */\n\tprivate _handleMetrics(res: ServerResponse): void {\n\t\tif (!this._metricsProvider) {\n\t\t\tres.writeHead(404, { 'Content-Type': 'text/plain' });\n\t\t\tres.end('Not Found');\n\t\t\treturn;\n\t\t}\n\n\t\tres.writeHead(200, { 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8' });\n\t\tres.end(this._metricsProvider());\n\t}\n\n\t/**\n\t * Handle GET /health — Liveness check.\n\t */\n\tprivate _handleHealthCheck(res: ServerResponse): void {\n\t\tconst healthData: Record<string, unknown> = {\n\t\t\tstatus: 'healthy',\n\t\t\trequests: this._requestCount,\n\t\t\tsessions: this._sessions.size,\n\t\t\ttransport: 'streamable-http',\n\t\t};\n\t\tif (this._healthChecker) {\n\t\t\tconst liveness = this._healthChecker.checkLiveness();\n\t\t\thealthData.liveness = liveness;\n\t\t}\n\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\tres.end(JSON.stringify(healthData));\n\t}\n\n\t/**\n\t * Handle GET /ready — Readiness check.\n\t */\n\tprivate async _handleReadinessCheck(res: ServerResponse): Promise<void> {\n\t\tif (this._healthChecker) {\n\t\t\tconst readiness = await this._healthChecker.checkReadiness();\n\t\t\tconst statusCode = readiness.status === 'ok' ? 200 : 503;\n\t\t\tres.writeHead(statusCode, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify(readiness));\n\t\t} else {\n\t\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\t\tres.end(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tstatus: 'ok',\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tcomponents: {},\n\t\t\t\t})\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Update session-related metrics.\n\t */\n\tprivate _updateSessionMetrics(): void {\n\t\tthis._metrics?.gauge(\n\t\t\t'streamable_http_active_sessions',\n\t\t\tthis._sessions.size,\n\t\t\t{},\n\t\t\t'Active Streamable HTTP sessions'\n\t\t);\n\n\t\tlet totalStreams = 0;\n\t\tfor (const session of this._sessions.values()) {\n\t\t\ttotalStreams += session.notificationStreams.size;\n\t\t}\n\t\tthis._metrics?.gauge(\n\t\t\t'streamable_http_notification_streams',\n\t\t\ttotalStreams,\n\t\t\t{},\n\t\t\t'Active SSE notification streams'\n\t\t);\n\t}\n\n\t/**\n\t * Stop transport server with graceful shutdown.\n\t *\n\t * @param timeout - Maximum time to wait for in-flight requests (default: 30s)\n\t */\n\tasync stop(timeout?: number): Promise<void> {\n\t\tthis._isShuttingDown = true;\n\t\tthis._stopRateLimitCleanup();\n\n\t\tconst shutdownTimeout = timeout ?? 30000;\n\n\t\t// Close all SSE notification streams\n\t\tfor (const session of this._sessions.values()) {\n\t\t\tfor (const stream of session.notificationStreams) {\n\t\t\t\ttry {\n\t\t\t\t\tstream.end();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore errors\n\t\t\t\t}\n\t\t\t}\n\t\t\tsession.notificationStreams.clear();\n\t\t}\n\t\tthis._sessions.clear();\n\n\t\treturn new Promise((resolve) => {\n\t\t\tif (!this._server) {\n\t\t\t\tthis.log('info', 'Streamable HTTP transport stopped (no server)');\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Force close after timeout\n\t\t\tconst forceClose = setTimeout(() => {\n\t\t\t\tthis.log('warn', 'Streamable HTTP transport force-closing after timeout');\n\t\t\t\tresolve();\n\t\t\t}, shutdownTimeout);\n\n\t\t\tthis._server.close(() => {\n\t\t\t\tclearTimeout(forceClose);\n\t\t\t\tthis.log('info', 'Streamable HTTP transport stopped');\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n}\n\n/**\n * Create a Streamable HTTP transport with given options.\n *\n * @param options - Transport configuration\n * @returns A configured Streamable HTTP transport\n *\n * @example\n * ```typescript\n * const transport = createStreamableHttpTransport({ port: 3000, stateful: true });\n * await transport.connect(server);\n * ```\n */\nexport function createStreamableHttpTransport(\n\toptions: StreamableHttpTransportOptions = {}\n): StreamableHttpTransport {\n\treturn new StreamableHttpTransport(options);\n}\n"],"names":["StreamableHttpTransport","BaseTransport","Map","options","randomUUID","mcpServer","createServer","req","res","Promise","resolve","startTime","Date","durationSeconds","clientIp","urlPath","JSON","statusCode","code","message","id","extra","error","Object","timeout","setTimeout","body","readRequestBody","clearTimeout","jsonRpcRequest","parseResult","safeParse","JsonRpcRequestSchema","sessionId","sessionResult","response","responseHeaders","getErrorMessage","session","headerSessionId","newSessionId","sessionState","Set","value","event","data","stream","healthData","liveness","readiness","totalStreams","shutdownTimeout","forceClose","createStreamableHttpTransport"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transport/StreamableHttpTransport.js","sources":["../../src/transport/StreamableHttpTransport.ts"],"sourcesContent":["/**\n * Streamable HTTP Transport implementation (MCP spec recommended transport).\n *\n * This transport implements the MCP Streamable HTTP specification, which replaces\n * the deprecated SSE transport as the recommended HTTP-based transport since March 2025.\n *\n * Key features:\n * - POST /mcp for JSON-RPC requests (main MCP endpoint)\n * - GET /mcp for optional SSE server-to-client notifications\n * - Session management via Mcp-Session-Id header\n * - Supports both stateful (session-based) and stateless (per-request) modes\n * - Health endpoints (/health, /ready)\n *\n * @example\n * ```typescript\n * const transport = new StreamableHttpTransport({\n * port: 3000,\n * host: 'localhost',\n * stateful: true,\n * });\n * await transport.connect(server);\n * ```\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http';\nimport type { McpServer } from 'tmcp';\nimport { safeParse } from 'valibot';\nimport type { IMetrics } from '../contracts/interfaces.js';\nimport { getErrorMessage } from '../errors.js';\nimport { JsonRpcRequestSchema } from '../schema.js';\nimport { BaseTransport, type TransportOptions } from './BaseTransport.js';\nimport type { ITransport, TransportKind } from '../contracts/transport.js';\nimport { readRequestBody } from './HttpHelpers.js';\nimport { runWithContext } from '../context/RequestContext.js';\n\n/**\n * MCP Streamable HTTP transport options extending base TransportOptions.\n */\nexport interface StreamableHttpTransportOptions extends TransportOptions {\n\t/**\n\t * Path for the MCP endpoint\n\t * @default '/mcp'\n\t */\n\tpath?: string;\n\n\t/**\n\t * Metrics collector for transport telemetry\n\t */\n\tmetrics?: IMetrics;\n\n\t/**\n\t * Prometheus metrics provider function\n\t */\n\tmetricsProvider?: () => string;\n\n\t/**\n\t * Enable stateful session-based mode.\n\t * When true, sessions are tracked via Mcp-Session-Id header.\n\t * When false, each request is processed independently (stateless).\n\t * @default true\n\t */\n\tstateful?: boolean;\n\n\t/**\n\t * Custom session ID generator function.\n\t * @default () => randomUUID()\n\t */\n\tsessionIdGenerator?: () => string;\n\n\t/**\n\t * Enable request body size limit\n\t * @default true\n\t */\n\tenableBodySizeLimit?: boolean;\n\n\t/**\n\t * Maximum request body size in bytes\n\t * @default 10485760 (10MB)\n\t */\n\tmaxBodySize?: number;\n\n\t/**\n\t * Request timeout in milliseconds\n\t * @default 30000 (30 seconds)\n\t */\n\trequestTimeout?: number;\n}\n\n/**\n * Internal session state for stateful mode.\n */\ninterface SessionState {\n\t/** Unique session identifier */\n\tid: string;\n\t/** Timestamp when the session was created */\n\tcreatedAt: number;\n\t/** Timestamp of the last activity */\n\tlastActivityAt: number;\n\t/** Active SSE notification streams for this session */\n\tnotificationStreams: Set<ServerResponse>;\n}\n\n/**\n * Streamable HTTP Transport for MCP server.\n *\n * This transport implements the MCP Streamable HTTP specification,\n * providing JSON-RPC over HTTP with optional session management\n * and server-to-client SSE notification streams.\n *\n * @remarks\n * **Security Features (inherited from BaseTransport):**\n * - Session ID validation (alphanumeric, max 64 chars)\n * - Query parameter sanitization (whitelist allowed keys)\n * - Rate limiting per IP (configurable, default 100 req/min)\n * - CORS origin validation\n * - Host header validation\n *\n * **MCP Streamable HTTP Spec Compliance:**\n * - POST /mcp — JSON-RPC method calls\n * - GET /mcp — SSE notification stream (server-to-client)\n * - Mcp-Session-Id header for session management\n * - Content-Type: application/json for JSON-RPC responses\n * - Content-Type: text/event-stream for SSE notification streams\n *\n * **HTTP Status Code Mapping:**\n * - 200: Success (JSON-RPC response or SSE stream)\n * - 202: Accepted (JSON-RPC notification, no response body)\n * - 204: CORS Preflight (empty body)\n * - 400: Bad Request (invalid JSON, invalid session ID)\n * - 403: Forbidden (invalid CORS, invalid host)\n * - 404: Not Found\n * - 405: Method Not Allowed\n * - 413: Payload Too Large\n * - 429: Too Many Requests\n * - 500: Internal Server Error\n * - 503: Server Not Ready / Shutting Down\n */\nexport class StreamableHttpTransport extends BaseTransport implements ITransport {\n\tget kind(): TransportKind { return 'streamable-http'; }\n\tprivate _server: Server | null = null;\n\tprivate _mcpServer: McpServer | null = null;\n\tprivate _path: string;\n\tprivate _stateful: boolean;\n\tprivate _sessionIdGenerator: () => string;\n\tprivate _sessions: Map<string, SessionState> = new Map();\n\tprivate _requestCount: number = 0;\n\tprivate _activeRequests: number = 0;\n\tprivate _bodySizeLimitEnabled: boolean;\n\tprivate _maxBodySize: number;\n\tprivate _requestTimeout: number;\n\tprivate _metrics?: IMetrics;\n\tprivate _metricsProvider: (() => string) | null;\n\n\tconstructor(options: StreamableHttpTransportOptions = {}) {\n\t\tsuper(options);\n\n\t\tthis._path = options.path ?? '/mcp';\n\t\tthis._stateful = options.stateful ?? true;\n\t\tthis._sessionIdGenerator = options.sessionIdGenerator ?? (() => randomUUID());\n\t\tthis._bodySizeLimitEnabled = options.enableBodySizeLimit ?? true;\n\t\tthis._maxBodySize = options.maxBodySize ?? 10 * 1024 * 1024;\n\t\tthis._requestTimeout = options.requestTimeout ?? 30000;\n\t\tthis._metrics = options.metrics;\n\t\tthis._metricsProvider = options.metricsProvider ?? null;\n\t}\n\n\t/**\n\t * Get number of active sessions (stateful) or active requests (stateless).\n\t */\n\tget clientCount(): number {\n\t\treturn this._stateful ? this._sessions.size : this._activeRequests;\n\t}\n\n\t/**\n\t * Get the total number of requests handled.\n\t */\n\tget requestCount(): number {\n\t\treturn this._requestCount;\n\t}\n\n\t/**\n\t * Connects MCP server to this transport and starts listening.\n\t */\n\tasync connect(mcpServer: McpServer): Promise<void> {\n\t\tthis._mcpServer = mcpServer;\n\t\tthis._server = createServer((req, res) => this._handleRequest(req, res));\n\n\t\treturn new Promise((resolve) => {\n\t\t\tthis._server!.listen(this._port, this._host, () => {\n\t\t\t\tthis.log(\n\t\t\t\t\t'info',\n\t\t\t\t\t`Streamable HTTP transport listening on http://${this._host}:${this._port}`\n\t\t\t\t);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Route and handle incoming HTTP requests.\n\t */\n\tprivate async _handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n\t\tconst startTime = Date.now();\n\t\tthis._metrics?.counter('streamable_http_requests_total', 1, {}, 'Total Streamable HTTP transport requests');\n\t\tres.once('finish', () => {\n\t\t\tconst durationSeconds = (Date.now() - startTime) / 1000;\n\t\t\tthis._metrics?.histogram('streamable_http_request_duration_seconds', durationSeconds, {});\n\t\t});\n\n\t\t// Host validation\n\t\tif (!this.validateHostHeader(req)) {\n\t\t\tthis._sendJsonRpcError(res, 403, -32000, 'Forbidden - invalid host header');\n\t\t\treturn;\n\t\t}\n\n\t\t// Shutdown check\n\t\tif (this.isShuttingDown) {\n\t\t\tthis._sendJsonRpcError(res, 503, -32603, 'Server is shutting down');\n\t\t\treturn;\n\t\t}\n\n\t\t// Rate limiting\n\t\tconst clientIp = this.getClientIp(req);\n\t\tif (this.checkRateLimit(clientIp)) {\n\t\t\tres.setHeader('Retry-After', '60');\n\t\t\tthis._sendJsonRpcError(res, 429, -32000, 'Too many requests');\n\t\t\treturn;\n\t\t}\n\n\t\t// CORS validation\n\t\tif (!this.validateCorsOrigin(req)) {\n\t\t\tthis._sendJsonRpcError(res, 403, -32000, 'Forbidden - invalid origin');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setCorsHeaders(res);\n\n\t\t// CORS preflight\n\t\tif (req.method === 'OPTIONS') {\n\t\t\tres.setHeader('Access-Control-Allow-Headers', 'Content-Type, Mcp-Session-Id');\n\t\t\tres.writeHead(204);\n\t\t\tres.end();\n\t\t\treturn;\n\t\t}\n\n\t\t// Parse URL path\n\t\tconst urlPath = req.url?.split('?')[0] ?? '/';\n\n\t\t// Metrics endpoint\n\t\tif (req.method === 'GET' && urlPath === '/metrics') {\n\t\t\tthis._handleMetrics(res);\n\t\t\treturn;\n\t\t}\n\n\t\t// Health check (liveness)\n\t\tif (req.method === 'GET' && urlPath === '/health') {\n\t\t\tthis._handleHealthCheck(res);\n\t\t\treturn;\n\t\t}\n\n\t\t// Readiness check\n\t\tif (req.method === 'GET' && urlPath === '/ready') {\n\t\t\tawait this._handleReadinessCheck(res);\n\t\t\treturn;\n\t\t}\n\n\t\t// MCP endpoint routing\n\t\tif (urlPath === this._path) {\n\t\t\tif (req.method === 'POST') {\n\t\t\t\tawait this._handleMcpPost(req, res);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (req.method === 'GET') {\n\t\t\t\tthis._handleMcpGet(req, res);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tres.writeHead(405, { 'Content-Type': 'application/json', Allow: 'GET, POST' });\n\t\t\tres.end(JSON.stringify({ jsonrpc: '2.0', id: null, error: { code: -32601, message: 'Method not allowed' } }));\n\t\t\treturn;\n\t\t}\n\n\t\t// 404 for unknown paths\n\t\tthis._sendJsonRpcError(res, 404, -32601, 'Not Found');\n\t}\n\n\t/**\n\t * Send a JSON-RPC error response.\n\t */\n\tprivate _sendJsonRpcError(res: ServerResponse, statusCode: number, code: number, message: string, id: unknown = null, extra?: Record<string, unknown>): void {\n\t\tconst error: Record<string, unknown> = { code, message };\n\t\tif (extra) {\n\t\t\tObject.assign(error, extra);\n\t\t}\n\t\tres.writeHead(statusCode, { 'Content-Type': 'application/json' });\n\t\tres.end(JSON.stringify({ jsonrpc: '2.0', id, error }));\n\t}\n\n\t/**\n\t * Handle POST /mcp — JSON-RPC method calls.\n\t *\n\t * Per the MCP Streamable HTTP spec:\n\t * - Accepts JSON-RPC request bodies\n\t * - Returns Mcp-Session-Id header for new sessions (stateful mode)\n\t * - Validates Mcp-Session-Id for existing sessions (stateful mode)\n\t * - Content-Type: application/json for responses\n\t */\n\tprivate async _handleMcpPost(req: IncomingMessage, res: ServerResponse): Promise<void> {\n\t\tthis._requestCount++;\n\t\tthis._activeRequests++;\n\n\t\tconst timeout = setTimeout(() => {\n\t\t\tthis._activeRequests--;\n\t\t\tthis._sendJsonRpcError(res, 500, -32603, 'Request timeout');\n\t\t}, this._requestTimeout);\n\n\t\ttry {\n\t\t\t// Read request body with size limit\n\t\t\tconst body = await readRequestBody(req, this._bodySizeLimitEnabled ? this._maxBodySize : 0);\n\t\t\tif (body === null) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._sendJsonRpcError(res, 413, -32000, 'Request body too large');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Parse JSON\n\t\t\tlet jsonRpcRequest;\n\t\t\ttry {\n\t\t\t\tjsonRpcRequest = JSON.parse(body);\n\t\t\t} catch {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._sendJsonRpcError(res, 200, -32700, 'Parse error');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Validate JSON-RPC schema\n\t\t\tconst parseResult = safeParse(JsonRpcRequestSchema, jsonRpcRequest);\n\t\t\tif (!parseResult.success) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._sendJsonRpcError(res, 200, -32600, 'Invalid Request', jsonRpcRequest?.id ?? null, { data: parseResult.issues });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Session management (stateful mode)\n\t\t\tlet sessionId: string | undefined;\n\t\t\tif (this._stateful) {\n\t\t\t\tconst sessionResult = this._resolveSession(req, res);\n\t\t\t\tif (sessionResult === false) {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tthis._activeRequests--;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsessionId = sessionResult;\n\t\t\t}\n\n\t\t\t// Check if MCP server is ready\n\t\t\tif (!this._mcpServer) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._sendJsonRpcError(res, 503, -32603, 'Server not ready', jsonRpcRequest?.id ?? null);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Process JSON-RPC request through MCP server\n\t\t\t// Process JSON-RPC request through MCP server with owner context\n\t\t\tconst owner = this._stateful ? (sessionId ?? randomUUID()) : randomUUID();\n\t\t\tconst response = await runWithContext(\n\t\t\t\t{ requestId: randomUUID(), owner },\n\t\t\t\t() => this._mcpServer!.receive(jsonRpcRequest, { sessionInfo: {} })\n\t\t\t);\n\t\t\tclearTimeout(timeout);\n\t\t\tthis._activeRequests--;\n\n\t\t\t// Send response with session header if applicable\n\t\t\tconst responseHeaders: Record<string, string> = { 'Content-Type': 'application/json' };\n\t\t\tif (sessionId) responseHeaders['Mcp-Session-Id'] = sessionId;\n\n\t\t\tif (response) {\n\t\t\t\tres.writeHead(200, responseHeaders);\n\t\t\t\tres.end(JSON.stringify(response));\n\t\t\t} else {\n\t\t\t\tif (sessionId) res.setHeader('Mcp-Session-Id', sessionId);\n\t\t\t\tres.writeHead(202);\n\t\t\t\tres.end();\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tclearTimeout(timeout);\n\t\t\tthis._activeRequests--;\n\t\t\tthis._sendJsonRpcError(res, 200, -32603, 'Internal error', null, {\n\t\t\t\tdata: getErrorMessage(error),\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/**\n\t * Handle GET /mcp — Optional SSE notification stream.\n\t *\n\t * Per the MCP Streamable HTTP spec, clients may open a GET request\n\t * to receive server-initiated notifications as SSE events.\n\t * Requires a valid Mcp-Session-Id in stateful mode.\n\t */\n\tprivate _handleMcpGet(req: IncomingMessage, res: ServerResponse): void {\n\t\tif (!this._stateful) {\n\t\t\t// SSE notification streams require stateful mode\n\t\t\tres.writeHead(405, {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\tAllow: 'POST',\n\t\t\t});\n\t\t\tres.end(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\tid: null,\n\t\t\t\t\terror: { code: -32601, message: 'GET not supported in stateless mode' },\n\t\t\t\t})\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Require Mcp-Session-Id for GET requests\n\t\tconst sessionId = this._getSessionIdFromHeader(req);\n\t\tif (!sessionId) {\n\t\t\tres.writeHead(400, { 'Content-Type': 'application/json' });\n\t\t\tres.end(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\tid: null,\n\t\t\t\t\terror: { code: -32600, message: 'Missing Mcp-Session-Id header' },\n\t\t\t\t})\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst session = this._sessions.get(sessionId);\n\t\tif (!session) {\n\t\t\tres.writeHead(404, { 'Content-Type': 'application/json' });\n\t\t\tres.end(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\tid: null,\n\t\t\t\t\terror: { code: -32001, message: 'Session not found' },\n\t\t\t\t})\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Set SSE headers\n\t\tres.writeHead(200, {\n\t\t\t'Content-Type': 'text/event-stream',\n\t\t\t'Cache-Control': 'no-cache',\n\t\t\tConnection: 'keep-alive',\n\t\t\t'Mcp-Session-Id': sessionId,\n\t\t});\n\n\t\t// Send initial connected event\n\t\tthis._sendSseEvent(res, 'connected', {\n\t\t\tsessionId,\n\t\t\ttimestamp: Date.now(),\n\t\t});\n\n\t\t// Track this notification stream\n\t\tsession.notificationStreams.add(res);\n\t\tsession.lastActivityAt = Date.now();\n\t\tthis._updateSessionMetrics();\n\n\t\t// Handle client disconnect\n\t\treq.on('close', () => {\n\t\t\tsession.notificationStreams.delete(res);\n\t\t\tthis._updateSessionMetrics();\n\t\t});\n\t}\n\n\t/**\n\t * Resolve or create a session for a stateful request.\n\t *\n\t * @returns Session ID string on success, or `false` if the response was already sent (error).\n\t */\n\tprivate _resolveSession(req: IncomingMessage, res: ServerResponse): string | false {\n\t\tconst headerSessionId = this._getSessionIdFromHeader(req);\n\n\t\tif (headerSessionId) {\n\t\t\t// Validate format\n\t\t\tif (!this.validateSessionId(headerSessionId)) {\n\t\t\t\tres.writeHead(400, { 'Content-Type': 'application/json' });\n\t\t\t\tres.end(\n\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\t\tid: null,\n\t\t\t\t\t\terror: { code: -32600, message: 'Invalid Mcp-Session-Id format' },\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Check if session exists\n\t\t\tconst session = this._sessions.get(headerSessionId);\n\t\t\tif (session) {\n\t\t\t\tsession.lastActivityAt = Date.now();\n\t\t\t\treturn headerSessionId;\n\t\t\t}\n\n\t\t\t// Unknown session ID — per spec, return 404\n\t\t\tres.writeHead(404, { 'Content-Type': 'application/json' });\n\t\t\tres.end(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\tid: null,\n\t\t\t\t\terror: { code: -32001, message: 'Session not found' },\n\t\t\t\t})\n\t\t\t);\n\t\t\treturn false;\n\t\t}\n\n\t\t// No session header — create new session\n\t\tconst newSessionId = this._sessionIdGenerator();\n\t\tconst sessionState: SessionState = {\n\t\t\tid: newSessionId,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tlastActivityAt: Date.now(),\n\t\t\tnotificationStreams: new Set(),\n\t\t};\n\t\tthis._sessions.set(newSessionId, sessionState);\n\t\tthis.log('info', `New session created: ${newSessionId}`);\n\t\tthis._updateSessionMetrics();\n\n\t\treturn newSessionId;\n\t}\n\n\t/**\n\t * Extract Mcp-Session-Id from request headers.\n\t */\n\tprivate _getSessionIdFromHeader(req: IncomingMessage): string | undefined {\n\t\tconst value = req.headers['mcp-session-id'];\n\t\tif (typeof value === 'string' && value.length > 0) {\n\t\t\treturn value;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\n\t/**\n\t * Send an SSE event to a specific client response stream.\n\t */\n\tprivate _sendSseEvent(res: ServerResponse, event: string, data: unknown): void {\n\t\ttry {\n\t\t\tres.write(`event: ${event}\\n`);\n\t\t\tres.write(`data: ${JSON.stringify(data)}\\n\\n`);\n\t\t} catch {\n\t\t\t// Client disconnected — ignore\n\t\t}\n\t}\n\n\t/**\n\t * Broadcast a notification to all SSE streams in a given session.\n\t *\n\t * @param sessionId - Target session ID\n\t * @param event - SSE event name\n\t * @param data - Event payload\n\t */\n\tbroadcastToSession(sessionId: string, event: string, data: unknown): void {\n\t\tconst session = this._sessions.get(sessionId);\n\t\tif (!session) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const stream of session.notificationStreams) {\n\t\t\tthis._sendSseEvent(stream, event, data);\n\t\t}\n\t}\n\n\t/**\n\t * Handle GET /metrics endpoint.\n\t */\n\tprivate _handleMetrics(res: ServerResponse): void {\n\t\tif (!this._metricsProvider) {\n\t\t\tres.writeHead(404, { 'Content-Type': 'text/plain' });\n\t\t\tres.end('Not Found');\n\t\t\treturn;\n\t\t}\n\n\t\tres.writeHead(200, { 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8' });\n\t\tres.end(this._metricsProvider());\n\t}\n\n\t/**\n\t * Handle GET /health — Liveness check.\n\t */\n\tprivate _handleHealthCheck(res: ServerResponse): void {\n\t\tconst healthData: Record<string, unknown> = {\n\t\t\tstatus: 'healthy',\n\t\t\trequests: this._requestCount,\n\t\t\tsessions: this._sessions.size,\n\t\t\ttransport: 'streamable-http',\n\t\t};\n\t\tif (this._healthChecker) {\n\t\t\tconst liveness = this._healthChecker.checkLiveness();\n\t\t\thealthData.liveness = liveness;\n\t\t}\n\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\tres.end(JSON.stringify(healthData));\n\t}\n\n\t/**\n\t * Handle GET /ready — Readiness check.\n\t */\n\tprivate async _handleReadinessCheck(res: ServerResponse): Promise<void> {\n\t\tif (this._healthChecker) {\n\t\t\tconst readiness = await this._healthChecker.checkReadiness();\n\t\t\tconst statusCode = readiness.status === 'ok' ? 200 : 503;\n\t\t\tres.writeHead(statusCode, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify(readiness));\n\t\t} else {\n\t\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\t\tres.end(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tstatus: 'ok',\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tcomponents: {},\n\t\t\t\t})\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Update session-related metrics.\n\t */\n\tprivate _updateSessionMetrics(): void {\n\t\tthis._metrics?.gauge(\n\t\t\t'streamable_http_active_sessions',\n\t\t\tthis._sessions.size,\n\t\t\t{},\n\t\t\t'Active Streamable HTTP sessions'\n\t\t);\n\n\t\tlet totalStreams = 0;\n\t\tfor (const session of this._sessions.values()) {\n\t\t\ttotalStreams += session.notificationStreams.size;\n\t\t}\n\t\tthis._metrics?.gauge(\n\t\t\t'streamable_http_notification_streams',\n\t\t\ttotalStreams,\n\t\t\t{},\n\t\t\t'Active SSE notification streams'\n\t\t);\n\t}\n\n\t/**\n\t * Stop transport server with graceful shutdown.\n\t *\n\t * @param timeout - Maximum time to wait for in-flight requests (default: 30s)\n\t */\n\tasync stop(timeout?: number): Promise<void> {\n\t\tthis._isShuttingDown = true;\n\t\tthis._stopRateLimitCleanup();\n\n\t\tconst shutdownTimeout = timeout ?? 30000;\n\n\t\t// Close all SSE notification streams\n\t\tfor (const session of this._sessions.values()) {\n\t\t\tfor (const stream of session.notificationStreams) {\n\t\t\t\ttry {\n\t\t\t\t\tstream.end();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore errors\n\t\t\t\t}\n\t\t\t}\n\t\t\tsession.notificationStreams.clear();\n\t\t}\n\t\tthis._sessions.clear();\n\n\t\treturn new Promise((resolve) => {\n\t\t\tif (!this._server) {\n\t\t\t\tthis.log('info', 'Streamable HTTP transport stopped (no server)');\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Force close after timeout\n\t\t\tconst forceClose = setTimeout(() => {\n\t\t\t\tthis.log('warn', 'Streamable HTTP transport force-closing after timeout');\n\t\t\t\tresolve();\n\t\t\t}, shutdownTimeout);\n\n\t\t\tthis._server.close(() => {\n\t\t\t\tclearTimeout(forceClose);\n\t\t\t\tthis.log('info', 'Streamable HTTP transport stopped');\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n}\n\n/**\n * Create a Streamable HTTP transport with given options.\n *\n * @param options - Transport configuration\n * @returns A configured Streamable HTTP transport\n *\n * @example\n * ```typescript\n * const transport = createStreamableHttpTransport({ port: 3000, stateful: true });\n * await transport.connect(server);\n * ```\n */\nexport function createStreamableHttpTransport(\n\toptions: StreamableHttpTransportOptions = {}\n): StreamableHttpTransport {\n\treturn new StreamableHttpTransport(options);\n}\n"],"names":["StreamableHttpTransport","BaseTransport","Map","options","randomUUID","mcpServer","createServer","req","res","Promise","resolve","startTime","Date","durationSeconds","clientIp","urlPath","JSON","statusCode","code","message","id","extra","error","Object","timeout","setTimeout","body","readRequestBody","clearTimeout","jsonRpcRequest","parseResult","safeParse","JsonRpcRequestSchema","sessionId","sessionResult","owner","response","runWithContext","responseHeaders","getErrorMessage","session","headerSessionId","newSessionId","sessionState","Set","value","event","data","stream","healthData","liveness","readiness","totalStreams","shutdownTimeout","forceClose","createStreamableHttpTransport"],"mappings":"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"}
|
package/dist/types/skill.d.ts
CHANGED
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
* user_invocable: true
|
|
23
23
|
* };
|
|
24
24
|
* ```
|
|
25
|
+
*
|
|
26
|
+
* NOTE: Kept as a hand-written interface (not inferred from `SkillRecommendationSchema`)
|
|
27
|
+
* because `confidence`, `rationale`, and `priority` are REQUIRED here but OPTIONAL in the
|
|
28
|
+
* schema (the schema accepts partial LLM input; the normalizer fills defaults). An inferred
|
|
29
|
+
* type would make these fields optional and break call sites that read them without guards.
|
|
25
30
|
*/
|
|
26
31
|
export interface SkillRecommendation {
|
|
27
32
|
/** The unique name/identifier of the recommended skill. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../../src/types/skill.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH
|
|
1
|
+
{"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../../src/types/skill.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,mBAAmB;IACnC,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IAEnB,+FAA+F;IAC/F,UAAU,EAAE,MAAM,CAAC;IAEnB,0FAA0F;IAC1F,SAAS,EAAE,MAAM,CAAC;IAElB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;IAEjB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB,gFAAgF;IAChF,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,KAAK;IACrB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IAEb,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IAEpB,uEAAuE;IACvE,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,uDAAuD;IACvD,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB"}
|
package/dist/types/tool.d.ts
CHANGED
|
@@ -21,6 +21,11 @@
|
|
|
21
21
|
* alternatives: ['mcp__web_reader__webReader']
|
|
22
22
|
* };
|
|
23
23
|
* ```
|
|
24
|
+
*
|
|
25
|
+
* NOTE: Kept as a hand-written interface (not inferred from `ToolRecommendationSchema`)
|
|
26
|
+
* because `priority` is REQUIRED here but OPTIONAL in the schema (the schema accepts
|
|
27
|
+
* partial input from LLMs; the normalizer fills the default). An inferred type would
|
|
28
|
+
* make `priority` optional and break call sites that read it without a guard.
|
|
24
29
|
*/
|
|
25
30
|
export interface ToolRecommendation {
|
|
26
31
|
/** The unique name/identifier of the recommended tool. */
|
|
@@ -32,7 +37,7 @@ export interface ToolRecommendation {
|
|
|
32
37
|
/** Order in the recommendation sequence (lower numbers = higher priority). */
|
|
33
38
|
priority: number;
|
|
34
39
|
/** Optional suggested parameter values for the tool based on the current context. */
|
|
35
|
-
suggested_inputs?: Record<string,
|
|
40
|
+
suggested_inputs?: Record<string, string | number | boolean | null>;
|
|
36
41
|
/** Alternative tools that could be used if the primary recommendation is not available. */
|
|
37
42
|
alternatives?: string[];
|
|
38
43
|
}
|
package/dist/types/tool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/types/tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/types/tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,kBAAkB;IAClC,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAElB,8FAA8F;IAC9F,UAAU,EAAE,MAAM,CAAC;IAEnB,yFAAyF;IACzF,SAAS,EAAE,MAAM,CAAC;IAElB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;IAEjB,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;IAEpE,2FAA2F;IAC3F,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,IAAI;IACpB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IAEb,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAC;IAEpB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tracelattice",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.4",
|
|
4
4
|
"description": "Semantic Sequential Thinking Layer For Agentic Tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/lib.js",
|
|
7
|
-
"types": "dist/
|
|
7
|
+
"types": "dist/lib.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"types": "./dist/
|
|
11
|
-
"import": "./dist/
|
|
10
|
+
"types": "./dist/lib.d.ts",
|
|
11
|
+
"import": "./dist/lib.js"
|
|
12
12
|
},
|
|
13
13
|
"./package.json": "./package.json"
|
|
14
14
|
},
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
"dependencies": {
|
|
70
70
|
"@tmcp/adapter-valibot": "^0.1.5",
|
|
71
71
|
"@tmcp/transport-stdio": "^0.4.2",
|
|
72
|
+
"@valibot/to-json-schema": "^1.6.0",
|
|
72
73
|
"chalk": "^5.6.2",
|
|
73
74
|
"chokidar": "^5.0.0",
|
|
74
75
|
"tmcp": "^1.19.3",
|
|
@@ -78,18 +79,18 @@
|
|
|
78
79
|
"devDependencies": {
|
|
79
80
|
"@changesets/cli": "^2.31.0",
|
|
80
81
|
"@eslint/js": "^10.0.1",
|
|
81
|
-
"@rsbuild/core": "^
|
|
82
|
-
"@rslib/core": "^0.21.
|
|
82
|
+
"@rsbuild/core": "^2.0.0",
|
|
83
|
+
"@rslib/core": "^0.21.3",
|
|
83
84
|
"@tsconfig/node24": "^24.0.4",
|
|
84
85
|
"@types/node": "^25.6.0",
|
|
85
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
86
|
-
"@typescript-eslint/parser": "^8.
|
|
87
|
-
"@vitest/coverage-v8": "^4.1.
|
|
86
|
+
"@typescript-eslint/eslint-plugin": "^8.59.0",
|
|
87
|
+
"@typescript-eslint/parser": "^8.59.0",
|
|
88
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
88
89
|
"eslint": "^10.2.1",
|
|
89
90
|
"globals": "^17.5.0",
|
|
90
91
|
"prettier": "^3.8.3",
|
|
91
92
|
"typescript": "^6.0.3",
|
|
92
|
-
"typescript-eslint": "^8.
|
|
93
|
-
"vitest": "^4.1.
|
|
93
|
+
"typescript-eslint": "^8.59.0",
|
|
94
|
+
"vitest": "^4.1.5"
|
|
94
95
|
}
|
|
95
96
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Contracts module — shared interface definitions for DI and cross-module dependencies.
|
|
3
|
-
*
|
|
4
|
-
* All modules that need to reference other modules' interfaces should import
|
|
5
|
-
* from here instead of directly from the implementation module.
|
|
6
|
-
*
|
|
7
|
-
* @module contracts
|
|
8
|
-
*/
|
|
9
|
-
export { type DiscoveryCacheOptions, type IDiscoveryCache, type IMetrics, type IOutcomeRecorder, type VerificationOutcome, } from './interfaces.js';
|
|
10
|
-
export type { StrategyContext, StrategyDecision, IReasoningStrategy } from './strategy.js';
|
|
11
|
-
export type { CalibrationMetrics, CalibrationResult, ICalibrator } from './calibrator.js';
|
|
12
|
-
export type { Summary, ISummaryStore } from './summary.js';
|
|
13
|
-
export type { SuspensionRecord, ISuspensionStore } from './suspension.js';
|
|
14
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contracts/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACN,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACxB,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAE3F,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE1F,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE3D,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.d.ts
DELETED
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC"}
|
package/dist/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./lib.js";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PersistenceBackend.d.ts","sourceRoot":"","sources":["../../src/persistence/PersistenceBackend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IAClC;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjD;;;;;OAKG;IACH,WAAW,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAEtC;;;;;OAKG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErE;;;;;OAKG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,GAAG,SAAS,CAAC,CAAC;IAEjE;;;;OAIG;IACH,YAAY,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAElC;;;OAGG;IACH,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAE5B;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;;;OAKG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpE;;;;;;;OAOG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAE9C;;;;OAIG;IACH,gBAAgB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEtC;;;;;OAKG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/E;;;;;;;OAOG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,iBAAiB;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACvC,OAAO,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,eAAe,CAAC,EAAE,OAAO,CAAC;KAC1B,CAAC;CACF"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|