@frontmcp/sdk 1.8.6 → 1.9.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/adapter/adapter.instance.d.ts +4 -0
- package/adapter/adapter.instance.d.ts.map +1 -1
- package/adapter/adapter.registry.d.ts +2 -0
- package/adapter/adapter.registry.d.ts.map +1 -1
- package/adapter/adapter.utils.d.ts.map +1 -1
- package/agent/agent-call-chain.d.ts +21 -0
- package/agent/agent-call-chain.d.ts.map +1 -0
- package/agent/agent.instance.d.ts +70 -15
- package/agent/agent.instance.d.ts.map +1 -1
- package/agent/agent.registry.d.ts +4 -2
- package/agent/agent.registry.d.ts.map +1 -1
- package/agent/agent.scope.d.ts +18 -1
- package/agent/agent.scope.d.ts.map +1 -1
- package/agent/agent.utils.d.ts +11 -7
- package/agent/agent.utils.d.ts.map +1 -1
- package/agent/flows/call-agent.flow.d.ts +9 -1
- package/agent/flows/call-agent.flow.d.ts.map +1 -1
- package/agent/hooks/agent.hooks.d.ts +4 -4
- package/agent/hooks/agent.hooks.d.ts.map +1 -1
- package/app/instances/app.local.instance.d.ts.map +1 -1
- package/app/instances/app.remote.instance.d.ts +1 -0
- package/app/instances/app.remote.instance.d.ts.map +1 -1
- package/auth/flows/oauth.auth-ui.flow.d.ts +1 -1
- package/auth/flows/oauth.authorize.flow.d.ts +3 -3
- package/auth/flows/oauth.callback.flow.d.ts +2 -2
- package/auth/flows/oauth.connect.flow.d.ts +1 -1
- package/auth/flows/oauth.provider-callback.flow.d.ts +2 -2
- package/auth/flows/oauth.register.flow.d.ts +1 -1
- package/auth/flows/oauth.token.flow.d.ts +1 -1
- package/auth/flows/oauth.userinfo.flow.d.ts +1 -1
- package/auth/flows/well-known.jwks.flow.d.ts +3 -3
- package/auth/flows/well-known.oauth-authorization-server.flow.d.ts +2 -2
- package/auth/flows/well-known.prm.flow.d.ts +1 -1
- package/auth/instances/instance.local-primary-auth.d.ts.map +1 -1
- package/auth/session/session-store.factory.d.ts +1 -1
- package/auth/session/session-store.factory.d.ts.map +1 -1
- package/auth/session/utils/session-id.utils.d.ts +5 -0
- package/auth/session/utils/session-id.utils.d.ts.map +1 -1
- package/browser/index.cjs +72652 -0
- package/browser/index.mjs +72019 -0
- package/channel/channel-notification.service.d.ts +24 -5
- package/channel/channel-notification.service.d.ts.map +1 -1
- package/channel/channel-scope.helper.d.ts +2 -0
- package/channel/channel-scope.helper.d.ts.map +1 -1
- package/channel/channel.instance.d.ts +7 -2
- package/channel/channel.instance.d.ts.map +1 -1
- package/channel/flows/list-channels.flow.d.ts.map +1 -1
- package/channel/flows/send-channel-notification.flow.d.ts +14 -1
- package/channel/flows/send-channel-notification.flow.d.ts.map +1 -1
- package/channel/reply/channel-reply.tool.d.ts.map +1 -1
- package/common/availability/availability.utils.d.ts +4 -3
- package/common/availability/availability.utils.d.ts.map +1 -1
- package/common/dynamic/dynamic.adapter.d.ts +13 -7
- package/common/dynamic/dynamic.adapter.d.ts.map +1 -1
- package/common/dynamic/dynamic.plugin.d.ts +16 -5
- package/common/dynamic/dynamic.plugin.d.ts.map +1 -1
- package/common/dynamic/dynamic.utils.d.ts +16 -1
- package/common/dynamic/dynamic.utils.d.ts.map +1 -1
- package/common/entries/channel.entry.d.ts +1 -1
- package/common/entries/channel.entry.d.ts.map +1 -1
- package/common/entries/scope.entry.d.ts +26 -0
- package/common/entries/scope.entry.d.ts.map +1 -1
- package/common/interfaces/agent.interface.d.ts +19 -3
- package/common/interfaces/agent.interface.d.ts.map +1 -1
- package/common/interfaces/execution-context.interface.d.ts +21 -1
- package/common/interfaces/execution-context.interface.d.ts.map +1 -1
- package/common/interfaces/prompt.interface.d.ts +12 -0
- package/common/interfaces/prompt.interface.d.ts.map +1 -1
- package/common/metadata/agent.metadata.d.ts +36 -19
- package/common/metadata/agent.metadata.d.ts.map +1 -1
- package/common/metadata/app.metadata.d.ts +26 -1
- package/common/metadata/app.metadata.d.ts.map +1 -1
- package/common/metadata/channel.metadata.d.ts +1 -0
- package/common/metadata/channel.metadata.d.ts.map +1 -1
- package/common/metadata/front-mcp.metadata.d.ts +1336 -44
- package/common/metadata/front-mcp.metadata.d.ts.map +1 -1
- package/common/metadata/hook.metadata.d.ts +10 -0
- package/common/metadata/hook.metadata.d.ts.map +1 -1
- package/common/metadata/job.metadata.d.ts +1 -1
- package/common/metadata/prompt.metadata.d.ts +1 -0
- package/common/metadata/prompt.metadata.d.ts.map +1 -1
- package/common/metadata/resource.metadata.d.ts +2 -0
- package/common/metadata/resource.metadata.d.ts.map +1 -1
- package/common/metadata/skill.metadata.d.ts +20 -3
- package/common/metadata/skill.metadata.d.ts.map +1 -1
- package/common/metadata/tool.metadata.d.ts +1 -0
- package/common/metadata/tool.metadata.d.ts.map +1 -1
- package/common/metadata/workflow.metadata.d.ts +2 -2
- package/common/records/agent.record.d.ts +5 -1
- package/common/records/agent.record.d.ts.map +1 -1
- package/common/schemas/http-output.schema.d.ts +28 -28
- package/common/tokens/front-mcp.tokens.d.ts.map +1 -1
- package/common/tokens/server.tokens.d.ts +1 -0
- package/common/tokens/server.tokens.d.ts.map +1 -1
- package/common/types/options/elicitation/schema.d.ts +19 -0
- package/common/types/options/elicitation/schema.d.ts.map +1 -1
- package/common/types/options/http/index.d.ts +1 -1
- package/common/types/options/http/index.d.ts.map +1 -1
- package/common/types/options/http/interfaces.d.ts +36 -1
- package/common/types/options/http/interfaces.d.ts.map +1 -1
- package/common/types/options/http/schema.d.ts +12 -0
- package/common/types/options/http/schema.d.ts.map +1 -1
- package/common/types/options/redis/index.d.ts +3 -3
- package/common/types/options/redis/index.d.ts.map +1 -1
- package/common/types/options/redis/interfaces.d.ts +19 -2
- package/common/types/options/redis/interfaces.d.ts.map +1 -1
- package/common/types/options/redis/schema.d.ts +84 -0
- package/common/types/options/redis/schema.d.ts.map +1 -1
- package/common/types/options/session/interfaces.d.ts +4 -2
- package/common/types/options/session/interfaces.d.ts.map +1 -1
- package/common/types/options/skills-http/schema.d.ts +2 -2
- package/common/types/options/sqlite/interfaces.d.ts +8 -0
- package/common/types/options/sqlite/interfaces.d.ts.map +1 -1
- package/common/types/options/sqlite/resolve.d.ts.map +1 -1
- package/common/types/options/sqlite/schema.d.ts +1 -0
- package/common/types/options/sqlite/schema.d.ts.map +1 -1
- package/common/types/options/transport/interfaces.d.ts +3 -9
- package/common/types/options/transport/interfaces.d.ts.map +1 -1
- package/common/types/options/transport/schema.d.ts +80 -2
- package/common/types/options/transport/schema.d.ts.map +1 -1
- package/common/utils/path.utils.d.ts.map +1 -1
- package/context/call-surface.d.ts +3 -2
- package/context/call-surface.d.ts.map +1 -1
- package/context/frontmcp-context-storage.d.ts +7 -0
- package/context/frontmcp-context-storage.d.ts.map +1 -1
- package/context/frontmcp-context.d.ts +11 -0
- package/context/frontmcp-context.d.ts.map +1 -1
- package/direct/create.d.ts.map +1 -1
- package/direct/direct-server.d.ts +11 -5
- package/direct/direct-server.d.ts.map +1 -1
- package/direct/direct.types.d.ts +100 -14
- package/direct/direct.types.d.ts.map +1 -1
- package/direct/index.d.ts +1 -1
- package/direct/index.d.ts.map +1 -1
- package/direct/runtime-tools.d.ts +16 -0
- package/direct/runtime-tools.d.ts.map +1 -0
- package/elicitation/store/elicitation-store.factory.d.ts.map +1 -1
- package/errors/agent.errors.d.ts +13 -1
- package/errors/agent.errors.d.ts.map +1 -1
- package/errors/error-handler.d.ts.map +1 -1
- package/errors/index.d.ts +3 -3
- package/errors/index.d.ts.map +1 -1
- package/errors/mcp.error.d.ts +3 -0
- package/errors/mcp.error.d.ts.map +1 -1
- package/errors/misconfiguration.d.ts +30 -0
- package/errors/misconfiguration.d.ts.map +1 -0
- package/errors/registry.errors.d.ts +6 -0
- package/errors/registry.errors.d.ts.map +1 -1
- package/errors/transport.errors.d.ts +17 -0
- package/errors/transport.errors.d.ts.map +1 -1
- package/esm/index.mjs +16259 -12889
- package/ext-apps/ext-apps.handler.d.ts +1 -1
- package/ext-apps/ext-apps.handler.d.ts.map +1 -1
- package/flows/flow.instance.d.ts.map +1 -1
- package/front-mcp/front-mcp.d.ts +8 -0
- package/front-mcp/front-mcp.d.ts.map +1 -1
- package/front-mcp/front-mcp.providers.d.ts.map +1 -1
- package/ha/ha-config.d.ts +21 -0
- package/ha/ha-config.d.ts.map +1 -0
- package/ha/ha-headers.d.ts +32 -0
- package/ha/ha-headers.d.ts.map +1 -0
- package/ha/ha-manager.d.ts +24 -2
- package/ha/ha-manager.d.ts.map +1 -1
- package/ha/ha.types.d.ts +2 -0
- package/ha/ha.types.d.ts.map +1 -1
- package/ha/heartbeat.service.d.ts +9 -0
- package/ha/heartbeat.service.d.ts.map +1 -1
- package/ha/index.d.ts +3 -1
- package/ha/index.d.ts.map +1 -1
- package/ha/notification-relay.d.ts +15 -18
- package/ha/notification-relay.d.ts.map +1 -1
- package/ha/relay-messages.d.ts +114 -0
- package/ha/relay-messages.d.ts.map +1 -0
- package/ha/session-takeover.d.ts.map +1 -1
- package/health/health.probes.d.ts +1 -1
- package/health/health.probes.d.ts.map +1 -1
- package/hooks/entry-class-hooks.d.ts +27 -0
- package/hooks/entry-class-hooks.d.ts.map +1 -0
- package/hooks/hook.registry.d.ts +11 -0
- package/hooks/hook.registry.d.ts.map +1 -1
- package/hooks/hooks.utils.d.ts +19 -5
- package/hooks/hooks.utils.d.ts.map +1 -1
- package/index.d.ts +31 -13
- package/index.d.ts.map +1 -1
- package/index.js +16272 -12893
- package/job/execution/job-execution.manager.d.ts.map +1 -1
- package/job/job.instance.d.ts.map +1 -1
- package/job/job.registry.d.ts.map +1 -1
- package/job/store/job-definition-store.factory.d.ts.map +1 -1
- package/job/store/job-state-store.factory.d.ts.map +1 -1
- package/metrics/index.d.ts +1 -1
- package/metrics/index.d.ts.map +1 -1
- package/metrics/metrics.routes.d.ts +23 -0
- package/metrics/metrics.routes.d.ts.map +1 -1
- package/notification/index.d.ts +1 -1
- package/notification/index.d.ts.map +1 -1
- package/notification/notification.service.d.ts +28 -1
- package/notification/notification.service.d.ts.map +1 -1
- package/package.json +16 -10
- package/plugin/plugin.registry.d.ts +5 -1
- package/plugin/plugin.registry.d.ts.map +1 -1
- package/prompt/flows/get-prompt.flow.d.ts +3 -0
- package/prompt/flows/get-prompt.flow.d.ts.map +1 -1
- package/prompt/prompt.instance.d.ts.map +1 -1
- package/prompt/prompt.registry.d.ts +19 -1
- package/prompt/prompt.registry.d.ts.map +1 -1
- package/provider/provider.registry.d.ts +33 -3
- package/provider/provider.registry.d.ts.map +1 -1
- package/remote-mcp/mcp-stateless-client.adapter.d.ts +9 -1
- package/remote-mcp/mcp-stateless-client.adapter.d.ts.map +1 -1
- package/remote-mcp/resilience/health-check.d.ts.map +1 -1
- package/resource/flows/read-resource.flow.d.ts +3 -0
- package/resource/flows/read-resource.flow.d.ts.map +1 -1
- package/resource/resource.instance.d.ts.map +1 -1
- package/resource/resource.registry.d.ts +19 -1
- package/resource/resource.registry.d.ts.map +1 -1
- package/scope/flows/http.request.flow.d.ts +12 -1
- package/scope/flows/http.request.flow.d.ts.map +1 -1
- package/scope/scope.instance.d.ts +20 -1
- package/scope/scope.instance.d.ts.map +1 -1
- package/server/adapters/express.host.adapter.d.ts +6 -1
- package/server/adapters/express.host.adapter.d.ts.map +1 -1
- package/server/middleware/cors-env.d.ts +17 -0
- package/server/middleware/cors-env.d.ts.map +1 -0
- package/server/middleware/csp.middleware.d.ts +12 -1
- package/server/middleware/csp.middleware.d.ts.map +1 -1
- package/server/security/security-audit.d.ts +2 -0
- package/server/security/security-audit.d.ts.map +1 -1
- package/server/server.instance.d.ts.map +1 -1
- package/skill/auth/skill-http-auth.d.ts.map +1 -1
- package/skill/cache/skill-http-cache.factory.d.ts +0 -5
- package/skill/cache/skill-http-cache.factory.d.ts.map +1 -1
- package/skill/errors/skill-validation.error.d.ts +2 -2
- package/skill/errors/skill-validation.error.d.ts.map +1 -1
- package/skill/flows/http/llm-full-txt.flow.d.ts +1 -1
- package/skill/flows/http/llm-txt.flow.d.ts +1 -1
- package/skill/flows/http/skills-api.flow.d.ts +1 -1
- package/skill/providers/memory-skill.provider.d.ts +22 -15
- package/skill/providers/memory-skill.provider.d.ts.map +1 -1
- package/skill/skill.registry.d.ts +8 -6
- package/skill/skill.registry.d.ts.map +1 -1
- package/task/store/index.d.ts +1 -1
- package/task/store/index.d.ts.map +1 -1
- package/task/store/task-store.factory.d.ts +7 -0
- package/task/store/task-store.factory.d.ts.map +1 -1
- package/task/task.types.d.ts +2 -0
- package/task/task.types.d.ts.map +1 -1
- package/tool/flows/call-tool.flow.d.ts +3 -0
- package/tool/flows/call-tool.flow.d.ts.map +1 -1
- package/tool/flows/tools-list.flow.d.ts.map +1 -1
- package/tool/tool.instance.d.ts.map +1 -1
- package/tool/tool.registry.d.ts +10 -1
- package/tool/tool.registry.d.ts.map +1 -1
- package/tool/ui/ui-option-warnings.d.ts +3 -0
- package/tool/ui/ui-option-warnings.d.ts.map +1 -0
- package/tool/ui/ui-resource.handler.d.ts.map +1 -1
- package/tool/ui/ui-shared.d.ts +14 -0
- package/tool/ui/ui-shared.d.ts.map +1 -1
- package/transport/adapters/sse-transport.d.ts +1 -1
- package/transport/adapters/sse-transport.d.ts.map +1 -1
- package/transport/bus/redis-transport-bus.d.ts +28 -21
- package/transport/bus/redis-transport-bus.d.ts.map +1 -1
- package/transport/event-stores/event-store.factory.d.ts.map +1 -1
- package/transport/event-stores/redis.event-store.d.ts.map +1 -1
- package/transport/flow-error-output.d.ts +8 -0
- package/transport/flow-error-output.d.ts.map +1 -0
- package/transport/flows/handle.mcp-20260728.flow.d.ts.map +1 -1
- package/transport/flows/handle.sse.flow.d.ts.map +1 -1
- package/transport/flows/handle.stateless-http.flow.d.ts +2 -1
- package/transport/flows/handle.stateless-http.flow.d.ts.map +1 -1
- package/transport/flows/handle.streamable-http.flow.d.ts +3 -2
- package/transport/flows/handle.streamable-http.flow.d.ts.map +1 -1
- package/transport/in-memory-server.d.ts.map +1 -1
- package/transport/ipc-server.transport.d.ts +26 -0
- package/transport/ipc-server.transport.d.ts.map +1 -0
- package/transport/mcp-20260728/client/mcp-stateless.client.d.ts +2 -0
- package/transport/mcp-20260728/client/mcp-stateless.client.d.ts.map +1 -1
- package/transport/mcp-handlers/initialize-request.handler.d.ts.map +1 -1
- package/transport/relay/index.d.ts +5 -0
- package/transport/relay/index.d.ts.map +1 -0
- package/transport/relay/relay-flow.d.ts +17 -0
- package/transport/relay/relay-flow.d.ts.map +1 -0
- package/transport/relay/relay-http.d.ts +109 -0
- package/transport/relay/relay-http.d.ts.map +1 -0
- package/transport/relay/relay-scope.helper.d.ts +46 -0
- package/transport/relay/relay-scope.helper.d.ts.map +1 -0
- package/transport/relay/session-relay.d.ts +105 -0
- package/transport/relay/session-relay.d.ts.map +1 -0
- package/transport/session-mode.check.d.ts +18 -0
- package/transport/session-mode.check.d.ts.map +1 -0
- package/transport/transport.registry.d.ts +95 -2
- package/transport/transport.registry.d.ts.map +1 -1
- package/transport/transport.remote.d.ts +16 -5
- package/transport/transport.remote.d.ts.map +1 -1
- package/transport/transport.types.d.ts +20 -11
- package/transport/transport.types.d.ts.map +1 -1
- package/transport/web-fetch-handler.d.ts +11 -0
- package/transport/web-fetch-handler.d.ts.map +1 -1
- package/transport/web-standard-mcp.d.ts.map +1 -1
- package/utils/dynamic-import.utils.d.ts +20 -0
- package/utils/dynamic-import.utils.d.ts.map +1 -0
- package/workflow/engine/workflow-step.executor.d.ts.map +1 -1
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request and response objects for an HTTP request relayed between the nodes of a
|
|
3
|
+
* distributed deployment.
|
|
4
|
+
*
|
|
5
|
+
* The node that receives a request for a session another node owns serializes it
|
|
6
|
+
* ({@link serializeRelayRequest}). The owner rebuilds a `ServerRequest` from it
|
|
7
|
+
* ({@link createRelayedServerRequest}) and runs it through its own `http:request`
|
|
8
|
+
* flow with a {@link RelayServerResponse}, whose output is streamed back.
|
|
9
|
+
*
|
|
10
|
+
* Both objects implement the subset of Node's `IncomingMessage` / `ServerResponse`
|
|
11
|
+
* (and Express' `status` / `json` / `send`) that the flows, the transport adapters
|
|
12
|
+
* and the MCP SDK's Streamable HTTP and SSE transports use. They depend on no Node
|
|
13
|
+
* built-in module, so importing them is safe in every runtime.
|
|
14
|
+
*/
|
|
15
|
+
import { type ServerRequest, type ServerResponse } from '../../common';
|
|
16
|
+
import type { RelayedHttpRequest } from '../../ha/relay-messages';
|
|
17
|
+
type Listener = (...args: unknown[]) => void;
|
|
18
|
+
/** Minimal event emitter (no dependency on Node's `events`). */
|
|
19
|
+
declare class RelayEmitter {
|
|
20
|
+
private readonly listeners;
|
|
21
|
+
on(event: string | symbol, listener: Listener): this;
|
|
22
|
+
addListener(event: string | symbol, listener: Listener): this;
|
|
23
|
+
once(event: string | symbol, listener: Listener): this;
|
|
24
|
+
off(event: string | symbol, listener: Listener): this;
|
|
25
|
+
removeListener(event: string | symbol, listener: Listener): this;
|
|
26
|
+
removeAllListeners(event?: string | symbol): this;
|
|
27
|
+
listenerCount(event: string | symbol): number;
|
|
28
|
+
emit(event: string | symbol, ...args: unknown[]): boolean;
|
|
29
|
+
}
|
|
30
|
+
/** Serialize a request this node received so its session owner can serve it. */
|
|
31
|
+
export declare function serializeRelayRequest(request: ServerRequest): RelayedHttpRequest;
|
|
32
|
+
/** The node that relayed this request, when it was relayed. */
|
|
33
|
+
export declare function relayedFrom(request: ServerRequest): string | undefined;
|
|
34
|
+
/** Whether a request was relayed here from another node. */
|
|
35
|
+
export declare function isRelayedRequest(request: ServerRequest): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Rebuild the `ServerRequest` of a relayed request on the session owner.
|
|
38
|
+
* Its socket peer is the client's address on the node that received the request,
|
|
39
|
+
* so client-IP rules see the same client they would have seen there.
|
|
40
|
+
*/
|
|
41
|
+
export declare function createRelayedServerRequest(relayed: RelayedHttpRequest, sourceNodeId: string): ServerRequest;
|
|
42
|
+
/** A body chunk as carried in a relay frame. */
|
|
43
|
+
export interface RelayChunk {
|
|
44
|
+
data: string;
|
|
45
|
+
encoding: 'utf8' | 'base64';
|
|
46
|
+
}
|
|
47
|
+
/** Encode a body chunk for a relay frame. Returns `undefined` for an empty chunk. */
|
|
48
|
+
export declare function encodeRelayChunk(chunk: unknown, encoding?: string): RelayChunk | undefined;
|
|
49
|
+
/** Decode a relay frame body chunk. */
|
|
50
|
+
export declare function decodeRelayChunk(chunk: RelayChunk): Uint8Array | string;
|
|
51
|
+
/** Receives what the owner writes to a relayed response, in order. */
|
|
52
|
+
export interface RelayResponseSink {
|
|
53
|
+
head(status: number, headers: Record<string, string | string[]>): void;
|
|
54
|
+
data(chunk: RelayChunk): void;
|
|
55
|
+
end(): void;
|
|
56
|
+
}
|
|
57
|
+
type OutgoingHeaderValue = number | string | readonly string[];
|
|
58
|
+
type OutgoingHeaders = Record<string, OutgoingHeaderValue | undefined> | readonly string[];
|
|
59
|
+
/**
|
|
60
|
+
* The response of a relayed request on the session owner. Whatever the flow writes
|
|
61
|
+
* is handed to the {@link RelayResponseSink} (and from there published back to the
|
|
62
|
+
* node that relayed the request). `destroy()` — called when that node's client goes
|
|
63
|
+
* away — emits `close` before `finish`, which aborts a streaming MCP response.
|
|
64
|
+
*/
|
|
65
|
+
export declare class RelayServerResponse extends RelayEmitter {
|
|
66
|
+
private readonly sink;
|
|
67
|
+
statusCode: number;
|
|
68
|
+
statusMessage: string;
|
|
69
|
+
headersSent: boolean;
|
|
70
|
+
writableEnded: boolean;
|
|
71
|
+
writableFinished: boolean;
|
|
72
|
+
destroyed: boolean;
|
|
73
|
+
private readonly headerMap;
|
|
74
|
+
constructor(sink: RelayResponseSink);
|
|
75
|
+
get writable(): boolean;
|
|
76
|
+
get finished(): boolean;
|
|
77
|
+
setHeader(name: string, value: OutgoingHeaderValue): this;
|
|
78
|
+
getHeader(name: string): string | string[] | undefined;
|
|
79
|
+
getHeaders(): Record<string, string | string[]>;
|
|
80
|
+
getHeaderNames(): string[];
|
|
81
|
+
hasHeader(name: string): boolean;
|
|
82
|
+
removeHeader(name: string): void;
|
|
83
|
+
writeHead(statusCode: number, reasonOrHeaders?: string | OutgoingHeaders, maybeHeaders?: OutgoingHeaders): this;
|
|
84
|
+
flushHeaders(): void;
|
|
85
|
+
/** Express `res.status()`. */
|
|
86
|
+
status(code: number): this;
|
|
87
|
+
/** Express `res.json()`. */
|
|
88
|
+
json(body: unknown): this;
|
|
89
|
+
/** Express `res.send()`. */
|
|
90
|
+
send(body?: unknown): this;
|
|
91
|
+
/** Express `res.redirect()`. */
|
|
92
|
+
redirect(statusOrUrl: number | string, maybeUrl?: string): this;
|
|
93
|
+
write(chunk: unknown, encodingOrCallback?: unknown, callback?: unknown): boolean;
|
|
94
|
+
end(chunk?: unknown, encodingOrCallback?: unknown, callback?: unknown): this;
|
|
95
|
+
/**
|
|
96
|
+
* Abort the response: nothing more reaches the sink. `close` fires with the response
|
|
97
|
+
* unfinished, which is how the MCP transports learn the client went away.
|
|
98
|
+
*/
|
|
99
|
+
destroy(error?: Error): this;
|
|
100
|
+
/** Node `ServerResponse` no-ops. */
|
|
101
|
+
cork(): void;
|
|
102
|
+
uncork(): void;
|
|
103
|
+
setTimeout(): this;
|
|
104
|
+
/** The response, typed as the `ServerResponse` the flows expect. */
|
|
105
|
+
asServerResponse(): ServerResponse;
|
|
106
|
+
private sendHead;
|
|
107
|
+
}
|
|
108
|
+
export {};
|
|
109
|
+
//# sourceMappingURL=relay-http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay-http.d.ts","sourceRoot":"","sources":["../../../src/transport/relay/relay-http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire a scope's HA relay channel: request relay, remote session destroys and
|
|
3
|
+
* relayed notifications. Kept out of `scope.instance.ts` so the scope stays lean.
|
|
4
|
+
*/
|
|
5
|
+
import type { HaManager } from '../../ha';
|
|
6
|
+
import type { RedisTransportBus } from '../bus/redis-transport-bus';
|
|
7
|
+
import type { TransportService } from '../transport.registry';
|
|
8
|
+
import { type RelayFlowRunner } from './relay-flow';
|
|
9
|
+
import { SessionRelay } from './session-relay';
|
|
10
|
+
interface RelayScopeLogger {
|
|
11
|
+
info(message: string, meta?: Record<string, unknown>): void;
|
|
12
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
13
|
+
verbose?(message: string, meta?: Record<string, unknown>): void;
|
|
14
|
+
}
|
|
15
|
+
export interface WireSessionRelayOptions {
|
|
16
|
+
nodeId: string;
|
|
17
|
+
haManager: HaManager;
|
|
18
|
+
bus: RedisTransportBus;
|
|
19
|
+
transportService: TransportService;
|
|
20
|
+
notifications: {
|
|
21
|
+
deliverRelayedNotification(sessionId: string, method: string, params?: Record<string, unknown>): boolean;
|
|
22
|
+
};
|
|
23
|
+
/** Runs relayed requests through the `http:request` flow (the scope). */
|
|
24
|
+
flows: RelayFlowRunner;
|
|
25
|
+
logger: RelayScopeLogger;
|
|
26
|
+
/** Override the relay's acknowledgement timeout (ms). */
|
|
27
|
+
ackTimeoutMs?: number;
|
|
28
|
+
}
|
|
29
|
+
export interface SessionRelayHandle {
|
|
30
|
+
relay: SessionRelay;
|
|
31
|
+
/** Resolves once this node listens on its relay channel (or the handle was closed). */
|
|
32
|
+
ready: Promise<void>;
|
|
33
|
+
/** Stop relaying and stop retrying the subscription. */
|
|
34
|
+
close(): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Subscribe this node to its relay channel and attach a {@link SessionRelay} to the
|
|
38
|
+
* transport bus. Returns `undefined` when the HA manager has no pub/sub connections.
|
|
39
|
+
*
|
|
40
|
+
* The subscription is retried with backoff (1s doubling to 30s) while Redis is
|
|
41
|
+
* unreachable; until it succeeds the bus cannot relay, and a request for a session
|
|
42
|
+
* another live node owns is answered with a retryable 503.
|
|
43
|
+
*/
|
|
44
|
+
export declare function wireSessionRelay(options: WireSessionRelayOptions): SessionRelayHandle | undefined;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=relay-scope.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay-scope.helper.d.ts","sourceRoot":"","sources":["../../../src/transport/relay/relay-scope.helper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,UAAU,CAAC;AAE1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAA2B,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,UAAU,gBAAgB;IACxB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5D,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACjE;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,GAAG,EAAE,iBAAiB,CAAC;IACvB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,aAAa,EAAE;QACb,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;KAC1G,CAAC;IACF,yEAAyE;IACzE,KAAK,EAAE,eAAe,CAAC;IACvB,MAAM,EAAE,gBAAgB,CAAC;IACzB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,YAAY,CAAC;IACpB,uFAAuF;IACvF,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,wDAAwD;IACxD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAKD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,kBAAkB,GAAG,SAAS,CAoFjG"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Relay — serve a request on the node that owns its MCP session.
|
|
3
|
+
*
|
|
4
|
+
* In a distributed deployment the node that receives a request may not be the one
|
|
5
|
+
* holding the session's transport. That node ({@link SessionRelay.forward}) publishes
|
|
6
|
+
* the request to the owner's relay channel and streams the owner's response back to
|
|
7
|
+
* its client. The owner ({@link SessionRelay.handleMessage} → `relay-request`) runs
|
|
8
|
+
* the request through its own `http:request` flow — auth, quota, routing, the MCP
|
|
9
|
+
* transport and every hook run there, exactly as for a request it received itself —
|
|
10
|
+
* and publishes what it writes, frame by frame, to the relaying node's channel.
|
|
11
|
+
*
|
|
12
|
+
* Redis Pub/Sub delivers the messages one connection publishes in order, so the
|
|
13
|
+
* frames of a response (`ack`, `head`, `data`…, `end`) arrive in the order written.
|
|
14
|
+
*
|
|
15
|
+
* Failure handling on the relaying node:
|
|
16
|
+
* - the owner does not listen on its channel (publish reached no subscriber) or does
|
|
17
|
+
* not acknowledge within `ackTimeoutMs`, its heartbeat expires while it serves, or no
|
|
18
|
+
* frame (a `keepalive` included) arrives for three owner-check intervals: before any
|
|
19
|
+
* byte reached the client the request fails with {@link SessionOwnerUnreachableError}
|
|
20
|
+
* (503, retryable); after, the response is ended;
|
|
21
|
+
* - the client goes away: the owner is told to cancel, which aborts the response there.
|
|
22
|
+
*
|
|
23
|
+
* On the owner, a response frame that cannot be published (Redis error, or the relaying
|
|
24
|
+
* node no longer listens) aborts the response and reports an `error` frame: a response
|
|
25
|
+
* with a lost frame is never completed.
|
|
26
|
+
*/
|
|
27
|
+
import type { ServerRequest, ServerResponse } from '../../common';
|
|
28
|
+
import { SessionOwnerUnreachableError } from '../../errors/transport.errors';
|
|
29
|
+
import type { HaRelayMessage, RelayedHttpRequest } from '../../ha/relay-messages';
|
|
30
|
+
/** Where the relaying node writes the owner's response (a Node / Express `ServerResponse`). */
|
|
31
|
+
export interface RelayResponseTarget {
|
|
32
|
+
readonly headersSent: boolean;
|
|
33
|
+
readonly writableEnded: boolean;
|
|
34
|
+
readonly writableFinished?: boolean;
|
|
35
|
+
writeHead(status: number, headers: Record<string, string | string[]>): unknown;
|
|
36
|
+
flushHeaders?(): void;
|
|
37
|
+
write(chunk: Uint8Array | string): unknown;
|
|
38
|
+
end(): unknown;
|
|
39
|
+
once(event: 'close', listener: () => void): unknown;
|
|
40
|
+
removeListener(event: 'close', listener: () => void): unknown;
|
|
41
|
+
}
|
|
42
|
+
interface RelayLogger {
|
|
43
|
+
info(message: string, meta?: Record<string, unknown>): void;
|
|
44
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
45
|
+
verbose?(message: string, meta?: Record<string, unknown>): void;
|
|
46
|
+
}
|
|
47
|
+
export interface SessionRelayOptions {
|
|
48
|
+
/** This node's machine ID. */
|
|
49
|
+
nodeId: string;
|
|
50
|
+
/** Publish a message to a node's relay channel; resolves to the number of receivers. */
|
|
51
|
+
publish(nodeId: string, message: HaRelayMessage): Promise<number>;
|
|
52
|
+
/** Whether a node's heartbeat is present. */
|
|
53
|
+
isNodeAlive(nodeId: string): Promise<boolean>;
|
|
54
|
+
/** Serve a request relayed to this node (runs it through the `http:request` flow). */
|
|
55
|
+
serve(request: ServerRequest, response: ServerResponse): Promise<void>;
|
|
56
|
+
/** How long the relaying node waits for the owner to acknowledge a request. @default 5000 */
|
|
57
|
+
ackTimeoutMs?: number;
|
|
58
|
+
/**
|
|
59
|
+
* How often the relaying node checks the owner's heartbeat while it serves, and how often
|
|
60
|
+
* the owner sends a `keepalive` frame. @default 10000
|
|
61
|
+
*/
|
|
62
|
+
ownerCheckIntervalMs?: number;
|
|
63
|
+
/** `Retry-After` given to a client whose request could not be relayed. @default 30 */
|
|
64
|
+
retryAfterSeconds?: number;
|
|
65
|
+
logger?: RelayLogger;
|
|
66
|
+
}
|
|
67
|
+
export declare class SessionRelay {
|
|
68
|
+
private readonly options;
|
|
69
|
+
private readonly nodeId;
|
|
70
|
+
private readonly ackTimeoutMs;
|
|
71
|
+
private readonly ownerCheckIntervalMs;
|
|
72
|
+
private readonly retryAfterSeconds;
|
|
73
|
+
private readonly logger?;
|
|
74
|
+
/** Requests this node relayed, awaiting the owner's response frames. */
|
|
75
|
+
private readonly pending;
|
|
76
|
+
/** Requests this node is serving for other nodes. */
|
|
77
|
+
private readonly serving;
|
|
78
|
+
private closed;
|
|
79
|
+
constructor(options: SessionRelayOptions);
|
|
80
|
+
/** Requests relayed from this node that are still in flight. */
|
|
81
|
+
get pendingCount(): number;
|
|
82
|
+
/** Requests this node is serving for other nodes. */
|
|
83
|
+
get servingCount(): number;
|
|
84
|
+
/** The error a request gets when its session owner cannot serve it. */
|
|
85
|
+
unreachable(ownerNodeId: string, reason: string): SessionOwnerUnreachableError;
|
|
86
|
+
/**
|
|
87
|
+
* Relay a request to the node that owns its session and write that node's response
|
|
88
|
+
* to `response`. Resolves once the response is complete (or the client went away).
|
|
89
|
+
*
|
|
90
|
+
* @throws SessionOwnerUnreachableError when the owner could not serve the request and
|
|
91
|
+
* nothing has been written to `response` yet.
|
|
92
|
+
*/
|
|
93
|
+
forward(ownerNodeId: string, sessionId: string, request: RelayedHttpRequest, response: RelayResponseTarget): Promise<void>;
|
|
94
|
+
/** Dispatch a request-relay message that arrived on this node's channel. */
|
|
95
|
+
handleMessage(message: HaRelayMessage): void;
|
|
96
|
+
/**
|
|
97
|
+
* Stop relaying: requests relayed from this node fail (or end), and requests this
|
|
98
|
+
* node serves for others are aborted after telling their node.
|
|
99
|
+
*/
|
|
100
|
+
close(): Promise<void>;
|
|
101
|
+
/** Owner side: serve a request another node relayed here, streaming the response back. */
|
|
102
|
+
private serveRelayed;
|
|
103
|
+
}
|
|
104
|
+
export {};
|
|
105
|
+
//# sourceMappingURL=session-relay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-relay.d.ts","sourceRoot":"","sources":["../../../src/transport/relay/session-relay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Warn at startup when `transport.sessionMode` asks for something the server does not do.
|
|
3
|
+
*
|
|
4
|
+
* Nothing reads `sessionMode` since v1.0: whether the server keeps sessions follows
|
|
5
|
+
* `transport.protocol` (`'stateless-api'` serves without sessions). The option is still accepted, so
|
|
6
|
+
* `sessionMode: 'stateless'` (or a function) used to be silently ignored (#678). `'stateful'`, the
|
|
7
|
+
* default, matches what the session-based protocols do and is left alone.
|
|
8
|
+
*/
|
|
9
|
+
export declare function warnIfSessionModeIgnored(options: {
|
|
10
|
+
logger: {
|
|
11
|
+
warn(message: string): void;
|
|
12
|
+
};
|
|
13
|
+
transport?: {
|
|
14
|
+
sessionMode?: unknown;
|
|
15
|
+
protocol?: unknown;
|
|
16
|
+
};
|
|
17
|
+
}): void;
|
|
18
|
+
//# sourceMappingURL=session-mode.check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-mode.check.d.ts","sourceRoot":"","sources":["../../src/transport/session-mode.check.ts"],"names":[],"mappings":"AAKA;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,MAAM,EAAE;QAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACxC,SAAS,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3D,GAAG,IAAI,CAYP"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { StoredSession } from '@frontmcp/auth';
|
|
2
|
-
import type { ServerResponse, TransportPersistenceConfigInput } from '../common';
|
|
2
|
+
import type { ServerRequest, ServerResponse, TransportPersistenceConfigInput } from '../common';
|
|
3
|
+
import type { ClaimedSessionInfo } from '../ha';
|
|
3
4
|
import type { Scope } from '../scope';
|
|
4
|
-
import { type TransportBus, type Transporter, type TransportType } from './transport.types';
|
|
5
|
+
import { type RemoteLocation, type TransportBus, type Transporter, type TransportType } from './transport.types';
|
|
5
6
|
export declare class TransportService {
|
|
6
7
|
readonly ready: Promise<void>;
|
|
7
8
|
private readonly byType;
|
|
@@ -58,8 +59,44 @@ export declare class TransportService {
|
|
|
58
59
|
* Returns undefined if persistence is disabled or not configured.
|
|
59
60
|
*/
|
|
60
61
|
private getDefaultTtlMs;
|
|
62
|
+
/**
|
|
63
|
+
* TTL resolved from `persistence.defaultTtlMs`, then `persistence.redis.defaultTtlMs`, then 1 hour.
|
|
64
|
+
* Set only when a persistence backend is configured.
|
|
65
|
+
*/
|
|
66
|
+
private resolvedTtlMs;
|
|
67
|
+
/** Store config kept after a successful create so a failed ping can be retried. */
|
|
68
|
+
private storeRetryConfig?;
|
|
69
|
+
private storeRetryTimer;
|
|
70
|
+
private storeRetryAttempt;
|
|
71
|
+
private destroyed;
|
|
72
|
+
/** Last time a request refreshed the stored session's TTL, by session id. */
|
|
73
|
+
private readonly lastTtlRefreshAt;
|
|
74
|
+
/** Last time a request re-advertised a served session on the transport bus, by session id. */
|
|
75
|
+
private readonly lastBusRefreshAt;
|
|
76
|
+
/** Session ids with a transport on this node (any type / token), with their transport count. */
|
|
77
|
+
private readonly localSessionIds;
|
|
78
|
+
/** The HA liveness generation in which this node last confirmed it owns a local session, by session id. */
|
|
79
|
+
private readonly ownershipGeneration;
|
|
80
|
+
/** Sessions whose local transports are being dropped because another node owns them now. */
|
|
81
|
+
private readonly relinquishing;
|
|
82
|
+
/**
|
|
83
|
+
* Redis key prefix under which session records are stored.
|
|
84
|
+
* The session store appends `session:` to the transport key prefix.
|
|
85
|
+
*/
|
|
86
|
+
getSessionKeyPrefix(): string;
|
|
61
87
|
constructor(scope: Scope, persistenceConfig?: false | TransportPersistenceConfigInput, bus?: TransportBus);
|
|
62
88
|
private initialize;
|
|
89
|
+
/**
|
|
90
|
+
* Create the session store and validate the connection.
|
|
91
|
+
* Returns true when the store is usable; on failure the store is left undefined.
|
|
92
|
+
*/
|
|
93
|
+
private connectSessionStore;
|
|
94
|
+
/**
|
|
95
|
+
* Retry the session store with exponential backoff (1s doubling to 30s) so a Redis that
|
|
96
|
+
* was down at startup is picked up when it comes back, and `/readyz` turns healthy.
|
|
97
|
+
*/
|
|
98
|
+
private scheduleSessionStoreRetry;
|
|
99
|
+
private retrySessionStore;
|
|
63
100
|
destroy(): Promise<void>;
|
|
64
101
|
/**
|
|
65
102
|
* Drain the configured session store and clear the reference. Probes
|
|
@@ -88,7 +125,56 @@ export declare class TransportService {
|
|
|
88
125
|
/** The backend kind selected at construction (`undefined` if none). Used by
|
|
89
126
|
* the orphan-sqlite WARN guard in scope.instance.ts and by error telemetry. */
|
|
90
127
|
getBackendKind(): 'redis' | 'vercel-kv' | 'sqlite' | undefined;
|
|
128
|
+
/** The configured backend as an operator reads it in a log line. */
|
|
129
|
+
private sessionStoreLabel;
|
|
130
|
+
/**
|
|
131
|
+
* Slide the stored session's TTL while this instance is serving it. Redis and Vercel KV
|
|
132
|
+
* session stores extend the TTL on read, so a plain `get` is enough. Throttled per session
|
|
133
|
+
* to a quarter of the TTL, fire-and-forget.
|
|
134
|
+
*/
|
|
135
|
+
private refreshStoredSessionTtl;
|
|
91
136
|
getTransporter(type: TransportType, token: string, sessionId: string): Promise<Transporter | undefined>;
|
|
137
|
+
/**
|
|
138
|
+
* Distributed routing: the node a request must be relayed to, because another live node
|
|
139
|
+
* owns the session it presents. `undefined` means "serve it here": the session is local,
|
|
140
|
+
* unknown, owned by this node, or owned by a node that stopped (this node takes it over).
|
|
141
|
+
*
|
|
142
|
+
* Runs before authentication — it only decides where the request is served; the owner
|
|
143
|
+
* authenticates it. Only session ids this deployment minted cost a Redis lookup.
|
|
144
|
+
*/
|
|
145
|
+
findRemoteSessionOwner(request: ServerRequest): Promise<RemoteLocation | undefined>;
|
|
146
|
+
/**
|
|
147
|
+
* The node that owns a session: the transport bus entry, else the persisted session record.
|
|
148
|
+
* `undefined` when neither knows the session.
|
|
149
|
+
*/
|
|
150
|
+
lookupSessionOwner(sessionId: string): Promise<RemoteLocation | undefined>;
|
|
151
|
+
/**
|
|
152
|
+
* Relay a request to the node that owns its session and write that node's response.
|
|
153
|
+
* @throws SessionOwnerUnreachableError when the owner could not serve it (nothing written yet).
|
|
154
|
+
*/
|
|
155
|
+
relayToSessionOwner(location: RemoteLocation, request: ServerRequest, response: ServerResponse): Promise<void>;
|
|
156
|
+
/**
|
|
157
|
+
* The orphan scanner claimed a session of a stopped node for this node: point the
|
|
158
|
+
* transport bus at this node, so every node relays the session's requests here. The
|
|
159
|
+
* transport itself is recreated from the session store by the first request.
|
|
160
|
+
*/
|
|
161
|
+
adoptClaimedSession(sessionId: string, previousNodeId: string, info: ClaimedSessionInfo): Promise<void>;
|
|
162
|
+
/**
|
|
163
|
+
* Destroy this node's transports for a session (asked by another node through the relay).
|
|
164
|
+
* @returns Whether a transport was found.
|
|
165
|
+
*/
|
|
166
|
+
destroyLocalSession(sessionId: string, reason?: string): Promise<boolean>;
|
|
167
|
+
/**
|
|
168
|
+
* Whether this node still owns a session it holds a transport for. After a gap in this node's
|
|
169
|
+
* heartbeat another node may have taken the session over: the persisted record decides, once per
|
|
170
|
+
* liveness generation, and a session that moved is dropped here (its record is left to the new owner).
|
|
171
|
+
* When the record cannot be read the session is served here, and checked again on its next request.
|
|
172
|
+
*/
|
|
173
|
+
private holdsLocalSession;
|
|
174
|
+
/** Whether a node's heartbeat is present (`true` when liveness cannot be determined). */
|
|
175
|
+
private isNodeAlive;
|
|
176
|
+
/** Re-advertise a session this node serves, so its bus entry does not expire under it. */
|
|
177
|
+
private refreshBusAdvertisement;
|
|
92
178
|
/**
|
|
93
179
|
* Get stored session from Redis (without creating a transport).
|
|
94
180
|
* Used by flows to check if session exists and can be recreated.
|
|
@@ -117,6 +203,11 @@ export declare class TransportService {
|
|
|
117
203
|
* @returns The recreated transport
|
|
118
204
|
*/
|
|
119
205
|
recreateTransporter(type: TransportType, token: string, sessionId: string, storedSession: StoredSession, res: ServerResponse): Promise<Transporter>;
|
|
206
|
+
/**
|
|
207
|
+
* A transporter that relays to `ownerNodeId` when that node is alive and the transport bus
|
|
208
|
+
* is available; `undefined` when the owner stopped (its session can be taken over).
|
|
209
|
+
*/
|
|
210
|
+
private remoteOwnerTransporter;
|
|
120
211
|
/**
|
|
121
212
|
* Internal method to actually recreate the transport (called with mutex protection)
|
|
122
213
|
*/
|
|
@@ -126,6 +217,8 @@ export declare class TransportService {
|
|
|
126
217
|
* Internal method to actually create the transport (called with mutex protection)
|
|
127
218
|
*/
|
|
128
219
|
private doCreateTransporter;
|
|
220
|
+
/** A session transport went away: forget it, and its bus entry and stored record unless another node owns them now. */
|
|
221
|
+
private onSessionTransportDisposed;
|
|
129
222
|
destroyTransporter(type: TransportType, token: string, sessionId: string, reason?: string): Promise<void>;
|
|
130
223
|
/**
|
|
131
224
|
* Update the stored session in Redis with client capabilities from the initialize handshake.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.registry.d.ts","sourceRoot":"","sources":["../../src/transport/transport.registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"transport.registry.d.ts","sourceRoot":"","sources":["../../src/transport/transport.registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
import { type ServerResponse } from '../common';
|
|
2
2
|
import { type AuthenticatedServerRequest } from '../server/server.types';
|
|
3
|
-
import { type TransportBus, type Transporter, type TransportKey, type TransportType } from './transport.types';
|
|
3
|
+
import { type RemoteLocation, type TransportBus, type Transporter, type TransportKey, type TransportType } from './transport.types';
|
|
4
|
+
/**
|
|
5
|
+
* Transporter for a session owned by another live node of a distributed deployment.
|
|
6
|
+
*
|
|
7
|
+
* Requests are relayed to the owning node, which serves them on its own transport;
|
|
8
|
+
* its response is streamed back to this node's client. When the owner cannot be
|
|
9
|
+
* reached the client gets a retryable `503` instead.
|
|
10
|
+
*/
|
|
4
11
|
export declare class RemoteTransporter implements Transporter {
|
|
5
12
|
private readonly key;
|
|
6
13
|
private readonly bus;
|
|
14
|
+
private readonly location;
|
|
7
15
|
readonly type: TransportType;
|
|
8
16
|
readonly tokenHash: string;
|
|
9
17
|
readonly sessionId: string;
|
|
10
|
-
constructor(key: TransportKey, bus: TransportBus);
|
|
11
|
-
|
|
18
|
+
constructor(key: TransportKey, bus: TransportBus, location: RemoteLocation);
|
|
19
|
+
/** The node that owns the session. */
|
|
20
|
+
get ownerNodeId(): string;
|
|
21
|
+
ping(_timeoutMs?: number): Promise<boolean>;
|
|
12
22
|
initialize(req: AuthenticatedServerRequest, res: ServerResponse): Promise<void>;
|
|
13
|
-
handleRequest(
|
|
14
|
-
destroy(
|
|
23
|
+
handleRequest(req: AuthenticatedServerRequest, res: ServerResponse): Promise<void>;
|
|
24
|
+
destroy(reason?: string): Promise<void>;
|
|
15
25
|
get isInitialized(): boolean;
|
|
16
26
|
markAsInitialized(): void;
|
|
17
27
|
resetForReinitialization(): void;
|
|
18
28
|
reregisterServer(): void;
|
|
29
|
+
private relay;
|
|
19
30
|
}
|
|
20
31
|
//# sourceMappingURL=transport.remote.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.remote.d.ts","sourceRoot":"","sources":["../../src/transport/transport.remote.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transport.remote.d.ts","sourceRoot":"","sources":["../../src/transport/transport.remote.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EAAE,KAAK,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEzE,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;GAMG;AACH,qBAAa,iBAAkB,YAAW,WAAW;IAMjD,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAP3B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAGR,GAAG,EAAE,YAAY,EACjB,GAAG,EAAE,YAAY,EACjB,QAAQ,EAAE,cAAc;IAO3C,sCAAsC;IACtC,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI3C,UAAU,CAAC,GAAG,EAAE,0BAA0B,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/E,aAAa,CAAC,GAAG,EAAE,0BAA0B,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5E,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,IAAI,aAAa,IAAI,OAAO,CAE3B;IAED,iBAAiB,IAAI,IAAI;IAIzB,wBAAwB,IAAI,IAAI;IAIhC,gBAAgB,IAAI,IAAI;YAIV,KAAK;CAUpB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ServerResponse } from '../common';
|
|
1
|
+
import { type ServerRequest, type ServerResponse } from '../common';
|
|
2
2
|
import { type AuthenticatedServerRequest } from '../server/server.types';
|
|
3
3
|
export type TransportType = 'sse' | 'streamable-http' | 'http' | 'stateless-http' | 'in-memory' | 'stdio';
|
|
4
4
|
/** Session id the stateless HTTP transport gives every request; it identifies no client. */
|
|
@@ -14,21 +14,30 @@ export interface RemoteLocation {
|
|
|
14
14
|
nodeId: string;
|
|
15
15
|
channel: string;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Distributed session registry: which node owns which session, and the relay that
|
|
19
|
+
* serves a request on the owning node.
|
|
20
|
+
*/
|
|
17
21
|
export interface TransportBus {
|
|
18
22
|
nodeId(): string;
|
|
23
|
+
/** Record that this node owns the session. */
|
|
19
24
|
advertise(key: TransportKey): Promise<void>;
|
|
25
|
+
/** Drop this node's ownership record (only when it still owns the session). */
|
|
20
26
|
revoke(key: TransportKey): Promise<void>;
|
|
27
|
+
/** The node owning this exact session (same type and token), unless it is this node. */
|
|
21
28
|
lookup(key: TransportKey): Promise<RemoteLocation | null>;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
/** The node owning a session id, whatever its type or token — this node included. */
|
|
30
|
+
lookupOwner(sessionId: string): Promise<RemoteLocation | null>;
|
|
31
|
+
/** Relay channel of a node. */
|
|
32
|
+
channelOf(nodeId: string): string;
|
|
33
|
+
/** Whether requests can be relayed to another node from here. */
|
|
34
|
+
canRelay(): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Serve a request on the node that owns its session and write that node's response.
|
|
37
|
+
* @throws SessionOwnerUnreachableError when the owner could not serve it (nothing written yet).
|
|
38
|
+
*/
|
|
39
|
+
proxyRequest(location: RemoteLocation, sessionId: string, request: ServerRequest, response: ServerResponse): Promise<void>;
|
|
40
|
+
/** Ask the owning node to destroy its transport for the session. */
|
|
32
41
|
destroyRemote(key: TransportKey, reason?: string): Promise<void>;
|
|
33
42
|
}
|
|
34
43
|
export interface Transporter {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.types.d.ts","sourceRoot":"","sources":["../../src/transport/transport.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"transport.types.d.ts","sourceRoot":"","sources":["../../src/transport/transport.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type MetricsOptionsInterface } from '../common/types/options/metrics';
|
|
2
|
+
import { type MetricsService } from '../metrics/metrics.service';
|
|
1
3
|
import { type Scope } from '../scope/scope.instance';
|
|
2
4
|
import { type WebStandardMcpPair } from './web-standard-mcp';
|
|
3
5
|
/**
|
|
@@ -81,6 +83,15 @@ export interface CreateWebFetchHandlerOptions {
|
|
|
81
83
|
* in the adapter regardless.
|
|
82
84
|
*/
|
|
83
85
|
sessionRouter?: WebFetchSessionRouter;
|
|
86
|
+
/**
|
|
87
|
+
* The `/metrics` endpoint (`@FrontMcp({ metrics: { enabled: true } })`).
|
|
88
|
+
* `createFetchHandler()` passes the server's service here, as the Express
|
|
89
|
+
* host registers it as a route, so both answer the same scrape.
|
|
90
|
+
*/
|
|
91
|
+
metrics?: {
|
|
92
|
+
service: MetricsService;
|
|
93
|
+
config: MetricsOptionsInterface;
|
|
94
|
+
};
|
|
84
95
|
}
|
|
85
96
|
/**
|
|
86
97
|
* Build a Web-standard fetch handler for a Scope.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-fetch-handler.d.ts","sourceRoot":"","sources":["../../src/transport/web-fetch-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"web-fetch-handler.d.ts","sourceRoot":"","sources":["../../src/transport/web-fetch-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-standard-mcp.d.ts","sourceRoot":"","sources":["../../src/transport/web-standard-mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"web-standard-mcp.d.ts","sourceRoot":"","sources":["../../src/transport/web-standard-mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAErD,OAAO,EAA4B,KAAK,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACnG,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAE9E,iFAAiF;AACjF,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE;QAAE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;IACtC,SAAS,EAAE;QACT,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,QAAQ,CAAA;SAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QACtF,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;KACtB,CAAC;IACF,gGAAgG;IAChG,KAAK,CAAC,EAAE,2BAA2B,CAAC;CACrC;AAED,MAAM,WAAW,wBAAwB;IACvC,uFAAuF;IACvF,aAAa,EAAE,mBAAmB,CAAC;IACnC,gGAAgG;IAChG,QAAQ,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7B,0GAA0G;IAC1G,GAAG,EAAE,OAAO,CAAC;IACb,yGAAyG;IACzG,GAAG,CAAC,EAAE;QAAE,SAAS,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;KAAE,CAAC;IACtD;;;;OAIG;IACH,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAkCD;;;;;;GAMG;AACH,wBAAsB,6BAA6B,CACjD,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,2BAA2B,CAAA;CAAE,GAClE,OAAO,CAAC,kBAAkB,CAAC,CAI7B;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,QAAQ,CAAC,CAsCnB"}
|