@frontmcp/sdk 0.5.1 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +12 -16
- package/src/adapter/adapter.instance.js +5 -0
- package/src/adapter/adapter.instance.js.map +1 -1
- package/src/auth/authorization/authorization.class.d.ts +1 -4
- package/src/auth/authorization/authorization.class.js +6 -13
- package/src/auth/authorization/authorization.class.js.map +1 -1
- package/src/auth/flows/session.verify.flow.d.ts +1 -0
- package/src/auth/flows/session.verify.flow.js +11 -1
- package/src/auth/flows/session.verify.flow.js.map +1 -1
- package/src/auth/flows/well-known.jwks.flow.js +2 -2
- package/src/auth/flows/well-known.jwks.flow.js.map +1 -1
- package/src/auth/jwks/dev-key-persistence.d.ts +63 -0
- package/src/auth/jwks/dev-key-persistence.js +219 -0
- package/src/auth/jwks/dev-key-persistence.js.map +1 -0
- package/src/auth/jwks/index.d.ts +1 -0
- package/src/auth/jwks/index.js +1 -0
- package/src/auth/jwks/index.js.map +1 -1
- package/src/auth/jwks/jwks.service.d.ts +7 -4
- package/src/auth/jwks/jwks.service.js +81 -12
- package/src/auth/jwks/jwks.service.js.map +1 -1
- package/src/auth/jwks/jwks.types.d.ts +7 -0
- package/src/auth/jwks/jwks.types.js.map +1 -1
- package/src/auth/machine-id.d.ts +5 -0
- package/src/auth/machine-id.js +32 -0
- package/src/auth/machine-id.js.map +1 -0
- package/src/auth/session/index.d.ts +2 -0
- package/src/auth/session/index.js +5 -1
- package/src/auth/session/index.js.map +1 -1
- package/src/auth/session/record/session.base.js +5 -3
- package/src/auth/session/record/session.base.js.map +1 -1
- package/src/auth/session/record/session.stateless.d.ts +2 -2
- package/src/auth/session/record/session.stateless.js +5 -3
- package/src/auth/session/record/session.stateless.js.map +1 -1
- package/src/auth/session/redis-session.store.d.ts +64 -0
- package/src/auth/session/redis-session.store.js +204 -0
- package/src/auth/session/redis-session.store.js.map +1 -0
- package/src/auth/session/session.service.d.ts +0 -2
- package/src/auth/session/session.service.js +1 -7
- package/src/auth/session/session.service.js.map +1 -1
- package/src/auth/session/transport-session.manager.js +3 -5
- package/src/auth/session/transport-session.manager.js.map +1 -1
- package/src/auth/session/transport-session.types.d.ts +4 -0
- package/src/auth/session/transport-session.types.js +4 -3
- package/src/auth/session/transport-session.types.js.map +1 -1
- package/src/auth/session/utils/session-id.utils.d.ts +12 -1
- package/src/auth/session/utils/session-id.utils.js +48 -9
- package/src/auth/session/utils/session-id.utils.js.map +1 -1
- package/src/auth/session/vercel-kv-session.store.d.ts +96 -0
- package/src/auth/session/vercel-kv-session.store.js +216 -0
- package/src/auth/session/vercel-kv-session.store.js.map +1 -0
- package/src/auth/ui/base-layout.d.ts +0 -8
- package/src/auth/ui/base-layout.js +1 -14
- package/src/auth/ui/base-layout.js.map +1 -1
- package/src/auth/ui/index.d.ts +3 -4
- package/src/auth/ui/index.js +10 -11
- package/src/auth/ui/index.js.map +1 -1
- package/src/auth/ui/{htmx-templates.d.ts → templates.d.ts} +5 -6
- package/src/auth/ui/{htmx-templates.js → templates.js} +8 -15
- package/src/auth/ui/templates.js.map +1 -0
- package/src/common/decorators/decorator-utils.js.map +1 -1
- package/src/common/decorators/front-mcp.decorator.js +26 -3
- package/src/common/decorators/front-mcp.decorator.js.map +1 -1
- package/src/common/index.d.ts +0 -1
- package/src/common/index.js +0 -1
- package/src/common/index.js.map +1 -1
- package/src/common/interfaces/adapter.interface.d.ts +6 -0
- package/src/common/interfaces/adapter.interface.js.map +1 -1
- package/src/common/interfaces/execution-context.interface.d.ts +52 -3
- package/src/common/interfaces/execution-context.interface.js +88 -3
- package/src/common/interfaces/execution-context.interface.js.map +1 -1
- package/src/common/interfaces/flow.interface.d.ts +13 -0
- package/src/common/interfaces/flow.interface.js +24 -0
- package/src/common/interfaces/flow.interface.js.map +1 -1
- package/src/common/interfaces/server.interface.d.ts +9 -0
- package/src/common/interfaces/server.interface.js.map +1 -1
- package/src/common/metadata/app.metadata.d.ts +108 -0
- package/src/common/metadata/front-mcp.metadata.d.ts +1341 -2
- package/src/common/metadata/front-mcp.metadata.js +4 -1
- package/src/common/metadata/front-mcp.metadata.js.map +1 -1
- package/src/common/metadata/prompt.metadata.d.ts +4 -0
- package/src/common/metadata/provider.metadata.d.ts +14 -0
- package/src/common/metadata/provider.metadata.js +18 -2
- package/src/common/metadata/provider.metadata.js.map +1 -1
- package/src/common/metadata/resource.metadata.d.ts +8 -0
- package/src/common/metadata/tool-ui.metadata.d.ts +2 -2
- package/src/common/metadata/tool-ui.metadata.js +1 -1
- package/src/common/metadata/tool-ui.metadata.js.map +1 -1
- package/src/common/metadata/tool.metadata.d.ts +5 -1
- package/src/common/metadata/tool.metadata.js.map +1 -1
- package/src/common/migrate/auth-transport.migrate.d.ts +62 -0
- package/src/common/migrate/auth-transport.migrate.js +140 -0
- package/src/common/migrate/auth-transport.migrate.js.map +1 -0
- package/src/common/migrate/index.d.ts +1 -0
- package/src/common/migrate/index.js +6 -0
- package/src/common/migrate/index.js.map +1 -0
- package/src/common/schemas/http-output.schema.d.ts +24 -6
- package/src/common/schemas/index.d.ts +1 -0
- package/src/common/schemas/index.js +1 -0
- package/src/common/schemas/index.js.map +1 -1
- package/src/common/schemas/session-header.schema.d.ts +16 -0
- package/src/common/schemas/session-header.schema.js +42 -0
- package/src/common/schemas/session-header.schema.js.map +1 -0
- package/src/common/tokens/front-mcp.tokens.js +4 -1
- package/src/common/tokens/front-mcp.tokens.js.map +1 -1
- package/src/common/types/options/auth.options.d.ts +233 -3
- package/src/common/types/options/auth.options.js +29 -40
- package/src/common/types/options/auth.options.js.map +1 -1
- package/src/common/types/options/index.d.ts +2 -0
- package/src/common/types/options/index.js +2 -0
- package/src/common/types/options/index.js.map +1 -1
- package/src/common/types/options/redis.options.d.ts +190 -0
- package/src/common/types/options/redis.options.js +191 -0
- package/src/common/types/options/redis.options.js.map +1 -0
- package/src/common/types/options/server-info.options.d.ts +4 -0
- package/src/common/types/options/transport.options.d.ts +148 -0
- package/src/common/types/options/transport.options.js +121 -0
- package/src/common/types/options/transport.options.js.map +1 -0
- package/src/common/utils/global-config.utils.d.ts +36 -0
- package/src/common/utils/global-config.utils.js +44 -0
- package/src/common/utils/global-config.utils.js.map +1 -0
- package/src/common/utils/index.d.ts +1 -0
- package/src/common/utils/index.js +1 -0
- package/src/common/utils/index.js.map +1 -1
- package/src/completion/flows/complete.flow.d.ts +6 -8
- package/src/context/frontmcp-context-storage.d.ts +94 -0
- package/src/context/frontmcp-context-storage.js +183 -0
- package/src/context/frontmcp-context-storage.js.map +1 -0
- package/src/context/frontmcp-context.d.ts +269 -0
- package/src/context/frontmcp-context.js +360 -0
- package/src/context/frontmcp-context.js.map +1 -0
- package/src/context/frontmcp-context.provider.d.ts +43 -0
- package/src/context/frontmcp-context.provider.js +61 -0
- package/src/context/frontmcp-context.provider.js.map +1 -0
- package/src/context/index.d.ts +34 -0
- package/src/context/index.js +64 -0
- package/src/context/index.js.map +1 -0
- package/src/context/request-context-storage.d.ts +89 -0
- package/src/context/request-context-storage.js +183 -0
- package/src/context/request-context-storage.js.map +1 -0
- package/src/context/request-context.d.ts +184 -0
- package/src/context/request-context.js +209 -0
- package/src/context/request-context.js.map +1 -0
- package/src/context/request-context.provider.d.ts +37 -0
- package/src/context/request-context.provider.js +51 -0
- package/src/context/request-context.provider.js.map +1 -0
- package/src/context/session-key.provider.d.ts +45 -0
- package/src/context/session-key.provider.js +65 -0
- package/src/context/session-key.provider.js.map +1 -0
- package/src/context/trace-context.d.ts +43 -0
- package/src/context/trace-context.js +142 -0
- package/src/context/trace-context.js.map +1 -0
- package/src/errors/index.d.ts +1 -1
- package/src/errors/index.js +4 -1
- package/src/errors/index.js.map +1 -1
- package/src/errors/mcp.error.d.ts +16 -0
- package/src/errors/mcp.error.js +29 -1
- package/src/errors/mcp.error.js.map +1 -1
- package/src/flows/flow.instance.d.ts +16 -0
- package/src/flows/flow.instance.js +166 -80
- package/src/flows/flow.instance.js.map +1 -1
- package/src/flows/flow.registry.d.ts +5 -0
- package/src/flows/flow.registry.js +45 -3
- package/src/flows/flow.registry.js.map +1 -1
- package/src/front-mcp/front-mcp.d.ts +12 -0
- package/src/front-mcp/front-mcp.js +22 -3
- package/src/front-mcp/front-mcp.js.map +1 -1
- package/src/front-mcp/front-mcp.providers.d.ts +474 -1
- package/src/front-mcp/front-mcp.providers.js +2 -1
- package/src/front-mcp/front-mcp.providers.js.map +1 -1
- package/src/front-mcp/index.d.ts +1 -0
- package/src/front-mcp/index.js +3 -0
- package/src/front-mcp/index.js.map +1 -1
- package/src/front-mcp/serverless-handler.d.ts +28 -0
- package/src/front-mcp/serverless-handler.js +61 -0
- package/src/front-mcp/serverless-handler.js.map +1 -0
- package/src/hooks/hooks.utils.d.ts +1 -1
- package/src/hooks/hooks.utils.js +10 -3
- package/src/hooks/hooks.utils.js.map +1 -1
- package/src/index.d.ts +9 -5
- package/src/index.js +21 -1
- package/src/index.js.map +1 -1
- package/src/logger/instances/instance.logger.js +0 -1
- package/src/logger/instances/instance.logger.js.map +1 -1
- package/src/logging/flows/set-level.flow.d.ts +6 -8
- package/src/notification/notification.service.js +5 -1
- package/src/notification/notification.service.js.map +1 -1
- package/src/prompt/flows/get-prompt.flow.d.ts +14 -8
- package/src/prompt/flows/prompts-list.flow.d.ts +8 -7
- package/src/provider/provider.registry.d.ts +97 -5
- package/src/provider/provider.registry.js +306 -9
- package/src/provider/provider.registry.js.map +1 -1
- package/src/provider/provider.types.d.ts +21 -3
- package/src/provider/provider.types.js.map +1 -1
- package/src/resource/flows/read-resource.flow.d.ts +8 -9
- package/src/resource/flows/resource-templates-list.flow.d.ts +8 -7
- package/src/resource/flows/resources-list.flow.d.ts +8 -7
- package/src/resource/flows/subscribe-resource.flow.d.ts +6 -8
- package/src/resource/flows/unsubscribe-resource.flow.d.ts +6 -8
- package/src/scope/flows/http.request.flow.js +43 -7
- package/src/scope/flows/http.request.flow.js.map +1 -1
- package/src/scope/scope.instance.js +12 -5
- package/src/scope/scope.instance.js.map +1 -1
- package/src/server/adapters/base.host.adapter.d.ts +9 -0
- package/src/server/adapters/base.host.adapter.js.map +1 -1
- package/src/server/adapters/express.host.adapter.d.ts +12 -0
- package/src/server/adapters/express.host.adapter.js +21 -1
- package/src/server/adapters/express.host.adapter.js.map +1 -1
- package/src/server/server.instance.d.ts +3 -0
- package/src/server/server.instance.js +14 -7
- package/src/server/server.instance.js.map +1 -1
- package/src/store/adapters/store.vercel-kv.adapter.d.ts +86 -0
- package/src/store/adapters/store.vercel-kv.adapter.js +155 -0
- package/src/store/adapters/store.vercel-kv.adapter.js.map +1 -0
- package/src/store/index.d.ts +2 -0
- package/src/store/index.js +2 -0
- package/src/store/index.js.map +1 -1
- package/src/store/store.factory.d.ts +86 -0
- package/src/store/store.factory.js +194 -0
- package/src/store/store.factory.js.map +1 -0
- package/src/tool/flows/call-tool.flow.d.ts +38 -19
- package/src/tool/flows/call-tool.flow.js +240 -194
- package/src/tool/flows/call-tool.flow.js.map +1 -1
- package/src/tool/flows/tools-list.flow.d.ts +14 -17
- package/src/tool/flows/tools-list.flow.js +84 -33
- package/src/tool/flows/tools-list.flow.js.map +1 -1
- package/src/tool/tool.instance.d.ts +1 -4
- package/src/tool/ui/index.d.ts +4 -4
- package/src/tool/ui/index.js +4 -4
- package/src/tool/ui/index.js.map +1 -1
- package/src/tool/ui/platform-adapters.d.ts +2 -2
- package/src/tool/ui/platform-adapters.js +3 -3
- package/src/tool/ui/platform-adapters.js.map +1 -1
- package/src/tool/ui/template-helpers.d.ts +5 -7
- package/src/tool/ui/template-helpers.js +9 -26
- package/src/tool/ui/template-helpers.js.map +1 -1
- package/src/tool/ui/ui-resource.handler.d.ts +1 -1
- package/src/tool/ui/ui-resource.handler.js +5 -5
- package/src/tool/ui/ui-resource.handler.js.map +1 -1
- package/src/transport/adapters/transport.streamable-http.adapter.js +1 -0
- package/src/transport/adapters/transport.streamable-http.adapter.js.map +1 -1
- package/src/transport/flows/handle.sse.flow.js +9 -2
- package/src/transport/flows/handle.sse.flow.js.map +1 -1
- package/src/transport/flows/handle.streamable-http.flow.js +63 -6
- package/src/transport/flows/handle.streamable-http.flow.js.map +1 -1
- package/src/transport/mcp-handlers/complete-request.handler.d.ts +4 -15
- package/src/transport/mcp-handlers/get-prompt-request.handler.d.ts +5 -15
- package/src/transport/mcp-handlers/index.d.ts +67 -195
- package/src/transport/mcp-handlers/initialize-request.handler.js +12 -2
- package/src/transport/mcp-handlers/initialize-request.handler.js.map +1 -1
- package/src/transport/mcp-handlers/list-prompts-request.handler.d.ts +5 -15
- package/src/transport/mcp-handlers/list-resource-templates-request.handler.d.ts +5 -15
- package/src/transport/mcp-handlers/list-resources-request.handler.d.ts +5 -15
- package/src/transport/mcp-handlers/list-tools-request.handler.d.ts +5 -15
- package/src/transport/mcp-handlers/logging-set-level-request.handler.d.ts +3 -14
- package/src/transport/mcp-handlers/read-resource-request.handler.d.ts +4 -15
- package/src/transport/mcp-handlers/subscribe-request.handler.d.ts +3 -14
- package/src/transport/mcp-handlers/unsubscribe-request.handler.d.ts +3 -14
- package/src/transport/transport.registry.d.ts +72 -4
- package/src/transport/transport.registry.js +342 -11
- package/src/transport/transport.registry.js.map +1 -1
- package/src/auth/ui/htmx-templates.js.map +0 -1
- package/src/common/providers/session.provider.d.ts +0 -13
- package/src/common/providers/session.provider.js +0 -27
- package/src/common/providers/session.provider.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.registry.js","sourceRoot":"","sources":["../../../src/transport/transport.registry.ts"],"names":[],"mappings":"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","sourcesContent":["// server/transport/transport.registry.ts\nimport { createHash } from 'crypto';\nimport {\n TransportBus,\n Transporter,\n TransportKey,\n TransportRegistryBucket,\n TransportTokenBucket,\n TransportType,\n TransportTypeBucket,\n} from './transport.types';\nimport { RemoteTransporter } from './transport.remote';\nimport { LocalTransporter } from './transport.local';\nimport { ServerResponse } from '../common';\nimport { Scope } from '../scope';\nimport HandleStreamableHttpFlow from './flows/handle.streamable-http.flow';\nimport HandleSseFlow from './flows/handle.sse.flow';\nimport HandleStatelessHttpFlow from './flows/handle.stateless-http.flow';\n\nexport class TransportService {\n readonly ready: Promise<void>;\n private readonly byType: TransportRegistryBucket = new Map();\n private readonly distributed: boolean;\n private readonly bus?: TransportBus;\n private readonly scope: Scope;\n\n /**\n * Session history cache for tracking if sessions were ever created.\n * Used to differentiate between \"session never initialized\" (HTTP 400) and\n * \"session expired/terminated\" (HTTP 404) per MCP Spec 2025-11-25.\n *\n * Key: \"type:tokenHash:sessionId\", Value: creation timestamp\n */\n private readonly sessionHistory: Map<string, number> = new Map();\n private readonly MAX_SESSION_HISTORY = 10000;\n\n constructor(scope: Scope) {\n this.scope = scope;\n this.distributed = false; // get from scope metadata\n this.bus = undefined; // get from scope metadata\n if (this.distributed && !this.bus) {\n throw new Error('TransportRegistry: distributed=true requires a TransportBus implementation.');\n }\n\n this.ready = this.initialize();\n }\n\n private async initialize() {\n await this.scope.registryFlows(HandleStreamableHttpFlow, HandleSseFlow, HandleStatelessHttpFlow);\n }\n\n async destroy() {\n /* empty */\n }\n\n async getTransporter(type: TransportType, token: string, sessionId: string): Promise<Transporter | undefined> {\n const key = this.keyOf(type, token, sessionId);\n\n const local = this.lookupLocal(key);\n if (local) return local;\n\n if (this.distributed && this.bus) {\n const location = await this.bus.lookup(key);\n if (location) {\n return new RemoteTransporter(key, this.bus);\n }\n }\n\n return undefined;\n }\n\n async createTransporter(\n type: TransportType,\n token: string,\n sessionId: string,\n res: ServerResponse,\n ): Promise<Transporter> {\n const key = this.keyOf(type, token, sessionId);\n const existing = this.lookupLocal(key);\n if (existing) return existing;\n\n const transporter = new LocalTransporter(this.scope, key, res, () => {\n key.sessionId = sessionId;\n this.evictLocal(key);\n if (this.distributed && this.bus) {\n this.bus.revoke(key).catch(() => void 0);\n }\n });\n\n await transporter.ready();\n\n this.insertLocal(key, transporter);\n\n if (this.distributed && this.bus) {\n await this.bus.advertise(key);\n }\n\n return transporter;\n }\n\n async destroyTransporter(type: TransportType, token: string, sessionId: string, reason?: string): Promise<void> {\n const key = this.keyOf(type, token, sessionId);\n\n const local = this.lookupLocal(key);\n if (local) {\n await local.destroy(reason);\n return;\n }\n\n if (this.distributed && this.bus) {\n const location = await this.bus.lookup(key);\n if (location) {\n await this.bus.destroyRemote(key, reason);\n return;\n }\n }\n\n throw new Error('Invalid session: cannot destroy non-existent transporter.');\n }\n\n /**\n * Get or create a shared singleton transport for anonymous stateless requests.\n * All anonymous requests share the same transport instance.\n */\n async getOrCreateAnonymousStatelessTransport(type: TransportType, res: ServerResponse): Promise<Transporter> {\n const key = this.keyOf(type, '__anonymous__', '__stateless__');\n const existing = this.lookupLocal(key);\n if (existing) return existing;\n\n // Create shared transport for all anonymous requests\n const transporter = new LocalTransporter(this.scope, key, res, () => {\n this.evictLocal(key);\n if (this.distributed && this.bus) {\n this.bus.revoke(key).catch(() => void 0);\n }\n });\n\n await transporter.ready();\n this.insertLocal(key, transporter);\n\n if (this.distributed && this.bus) {\n await this.bus.advertise(key);\n }\n\n return transporter;\n }\n\n /**\n * Get or create a singleton transport for authenticated stateless requests.\n * Each unique token gets its own singleton transport.\n */\n async getOrCreateAuthenticatedStatelessTransport(\n type: TransportType,\n token: string,\n res: ServerResponse,\n ): Promise<Transporter> {\n const key = this.keyOf(type, token, '__stateless__');\n const existing = this.lookupLocal(key);\n if (existing) return existing;\n\n // Create singleton transport for this token\n const transporter = new LocalTransporter(this.scope, key, res, () => {\n this.evictLocal(key);\n if (this.distributed && this.bus) {\n this.bus.revoke(key).catch(() => void 0);\n }\n });\n\n await transporter.ready();\n this.insertLocal(key, transporter);\n\n if (this.distributed && this.bus) {\n await this.bus.advertise(key);\n }\n\n return transporter;\n }\n\n /**\n * Check if a session was ever created (even if it's been terminated/evicted).\n * Used to differentiate between \"session never initialized\" (HTTP 400) and\n * \"session expired/terminated\" (HTTP 404) per MCP Spec 2025-11-25.\n *\n * @param type - Transport type (e.g., 'streamable-http', 'sse')\n * @param token - The authorization token\n * @param sessionId - The session ID to check\n * @returns true if session was ever created, false otherwise\n */\n wasSessionCreated(type: TransportType, token: string, sessionId: string): boolean {\n const tokenHash = this.sha256(token);\n const historyKey = `${type}:${tokenHash}:${sessionId}`;\n return this.sessionHistory.has(historyKey);\n }\n\n /* --------------------------------- internals -------------------------------- */\n\n private sha256(value: string): string {\n return createHash('sha256').update(value, 'utf8').digest('hex');\n }\n\n private keyOf(type: TransportType, token: string, sessionId: string, sessionIdSse?: string): TransportKey {\n return {\n type,\n token,\n tokenHash: this.sha256(token),\n sessionId,\n sessionIdSse,\n };\n }\n\n private ensureTypeBucket(type: TransportType): TransportTypeBucket {\n let bucket = this.byType.get(type);\n if (!bucket) {\n bucket = new Map<string, TransportTokenBucket>();\n this.byType.set(type, bucket);\n }\n return bucket;\n }\n\n private ensureTokenBucket(typeBucket: TransportTypeBucket, tokenHash: string): TransportTokenBucket {\n let bucket = typeBucket.get(tokenHash);\n if (!bucket) {\n bucket = new Map<string, Transporter>();\n typeBucket.set(tokenHash, bucket);\n }\n return bucket;\n }\n\n private lookupLocal(key: TransportKey): Transporter | undefined {\n const typeBucket = this.byType.get(key.type);\n if (!typeBucket) return undefined;\n const tokenBucket = typeBucket.get(key.tokenHash);\n if (!tokenBucket) return undefined;\n return tokenBucket.get(key.sessionId);\n }\n\n private insertLocal(key: TransportKey, t: Transporter): void {\n const typeBucket = this.ensureTypeBucket(key.type);\n const tokenBucket = this.ensureTokenBucket(typeBucket, key.tokenHash);\n tokenBucket.set(key.sessionId, t);\n\n // Record session creation in history for HTTP 404 detection\n const historyKey = `${key.type}:${key.tokenHash}:${key.sessionId}`;\n this.sessionHistory.set(historyKey, Date.now());\n\n // Evict oldest entries if cache exceeds max size (LRU-like eviction)\n if (this.sessionHistory.size > this.MAX_SESSION_HISTORY) {\n const entries = [...this.sessionHistory.entries()].sort((a, b) => a[1] - b[1]);\n // Remove oldest 10% of entries\n const toEvict = Math.ceil(this.MAX_SESSION_HISTORY * 0.1);\n for (let i = 0; i < toEvict && i < entries.length; i++) {\n this.sessionHistory.delete(entries[i][0]);\n }\n }\n }\n\n private evictLocal(key: TransportKey): void {\n const typeBucket = this.byType.get(key.type);\n if (!typeBucket) return;\n const tokenBucket = typeBucket.get(key.tokenHash);\n if (!tokenBucket) return;\n tokenBucket.delete(key.sessionId);\n if (tokenBucket.size === 0) typeBucket.delete(key.tokenHash);\n if (typeBucket.size === 0) this.byType.delete(key.type);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"transport.registry.js","sourceRoot":"","sources":["../../../src/transport/transport.registry.ts"],"names":[],"mappings":";;;;AAAA,yCAAyC;AACzC,mCAAoC;AAUpC,yDAAuD;AACvD,uDAAqD;AAGrD,8GAA2E;AAC3E,sFAAoD;AACpD,4GAAyE;AAGzE,oCAA8C;AAE9C,mFAAyE;AAEzE,MAAa,gBAAgB;IAClB,KAAK,CAAgB;IACb,MAAM,GAA4B,IAAI,GAAG,EAAE,CAAC;IAC5C,WAAW,CAAU;IACrB,GAAG,CAAgB;IACnB,KAAK,CAAQ;IAE9B;;;;;;;OAOG;IACc,cAAc,GAAwB,IAAI,GAAG,EAAE,CAAC;IAChD,mBAAmB,GAAG,KAAK,CAAC;IAE7C;;;OAGG;IACK,YAAY,CAAsF;IAE1G;;OAEG;IACK,iBAAiB,CAAmC;IAE5D;;OAEG;IACK,kBAAkB,CAAgB;IAE1C;;;OAGG;IACc,aAAa,GAAsC,IAAI,GAAG,EAAE,CAAC;IAE9E,YAAY,KAAY,EAAE,iBAAmD;QAC3E,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAC3C,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,CAAC,0BAA0B;QACpD,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC,0BAA0B;QAChD,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;QACjG,CAAC;QAED,0EAA0E;QAC1E,IAAI,iBAAiB,EAAE,OAAO,IAAI,iBAAiB,CAAC,KAAK,EAAE,CAAC;YAC1D,oEAAoE;YACpE,MAAM,WAAW,GAAG,iBAAiB,CAAC,KAAK,CAAC;YAC5C,MAAM,YAAY,GAAG,UAAU,IAAI,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;YAEhF,6EAA6E;YAC7E,wDAAwD;YACxD,IAAI,CAAC,kBAAkB,GAAG;gBACxB,GAAG,WAAW;gBACd,SAAS,EAAE,WAAW,CAAC,SAAS,IAAI,gBAAgB;gBACpD,YAAY,EAAE,iBAAiB,CAAC,YAAY,IAAI,OAAO,EAAE,iBAAiB;aAC3D,CAAC;YAElB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CACpB,sBAAsB,YAAY,8DAA8D,CACjG,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;IACjC,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,mDAAmD;QACnD,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC5B,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,MAAM,IAAA,0BAAkB,EAAC,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;gBACzG,mGAAmG;gBACnG,IAAI,CAAC,YAAY,GAAG,KAA2F,CAAC;gBAChH,IAAI,CAAC,kBAAkB,GAAG,SAAS,CAAC;YACtC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,kFAAkF,EAAE;oBAC1G,KAAK,EAAG,KAAe,CAAC,OAAO;iBAChC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,qDAAqD;QACrD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACnF,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,MAAM,YAAY,GAChB,IAAI,CAAC,iBAAiB,EAAE,KAAK,IAAI,UAAU,IAAI,IAAI,CAAC,iBAAiB,CAAC,KAAK;oBACzE,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,QAAQ;oBACvC,CAAC,CAAC,OAAO,CAAC;gBACd,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CACrB,2CAA2C,YAAY,iCAAiC,CACzF,CAAC;gBACF,+EAA+E;gBAC/E,iFAAiF;gBACjF,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;oBACjC,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC3D,CAAC;gBACD,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC;YAC/F,CAAC;QACH,CAAC;QAED,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,qCAAwB,EAAE,yBAAa,EAAE,oCAAuB,CAAC,CAAC;IACnG,CAAC;IAED,KAAK,CAAC,OAAO;QACX,mDAAmD;QACnD,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;YACtD,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;gBACrC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;YAC1E,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,sDAAsD,EAAE;oBAC7E,KAAK,EAAG,KAAe,CAAC,OAAO;iBAChC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,IAAmB,EAAE,KAAa,EAAE,SAAiB;QACxE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QAE/C,uCAAuC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QAExB,wCAAwC;QACxC,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACjC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC5C,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,IAAI,oCAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;QAED,2EAA2E;QAC3E,2EAA2E;QAC3E,4DAA4D;QAE5D,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,gBAAgB,CAAC,IAAmB,EAAE,KAAa,EAAE,SAAiB;QAC1E,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,KAAK,iBAAiB;YAAE,OAAO,SAAS,CAAC;QAEvE,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAE9B,gCAAgC;QAChC,IAAI,MAAM,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;YACzC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,yDAAyD,EAAE;gBAChF,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;gBACjC,eAAe,EAAE,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;gBACnD,gBAAgB,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;aACxC,CAAC,CAAC;YACH,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,mBAAmB,CACvB,IAAmB,EACnB,KAAa,EACb,SAAiB,EACjB,aAA4B,EAC5B,GAAmB;QAEnB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QAE/C,uCAAuC;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,mEAAmE;QACnE,oGAAoG;QACpG,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;QAC7E,MAAM,eAAe,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzD,IAAI,eAAe,EAAE,CAAC;YACpB,qEAAqE;YACrE,OAAO,eAAe,CAAC;QACzB,CAAC;QAED,+CAA+C;QAC/C,MAAM,iBAAiB,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,CAAC,CAAC;QACzF,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;QAEpD,IAAI,CAAC;YACH,OAAO,MAAM,iBAAiB,CAAC;QACjC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,sCAAsC;YACtC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,qEAAqE,EAAE;gBAC7F,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;gBACjC,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;aAC7F,CAAC,CAAC;YACH,MAAM,KAAK,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,qBAAqB,CACjC,GAAiB,EACjB,SAAiB,EACjB,aAA4B,EAC5B,GAAmB;QAEnB,uEAAuE;QACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,6DAA6D,EAAE;YACpF,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;YACjC,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,QAAQ;YACxC,SAAS,EAAE,aAAa,CAAC,SAAS;SACnC,CAAC,CAAC;QAEH,uCAAuC;QACvC,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAC3E,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;QAE7D,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;QACvC,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,CAAC;QAEjD,uBAAuB;QACvB,MAAM,WAAW,GAAG,IAAI,kCAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;YAClE,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;YAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACrB,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;gBACjC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YAC3C,CAAC;YACD,+BAA+B;YAC/B,IAAI,YAAY,EAAE,CAAC;gBACjB,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YACrD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAEnC,sCAAsC;QACtC,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,cAAc,GAAkB;gBACpC,GAAG,aAAa;gBAChB,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE;aAC3B,CAAC;YACF,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACzF,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,sDAAsD,EAAE;oBAC7E,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;oBACjC,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;iBACxD,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACjC,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,iBAAiB,CACrB,IAAmB,EACnB,KAAa,EACb,SAAiB,EACjB,GAAmB;QAEnB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QAE/C,0BAA0B;QAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,iEAAiE;QACjE,oGAAoG;QACpG,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;QAC7E,MAAM,eAAe,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzD,IAAI,eAAe,EAAE,CAAC;YACpB,mEAAmE;YACnE,OAAO,eAAe,CAAC;QACzB,CAAC;QAED,6CAA6C;QAC7C,MAAM,eAAe,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAC5E,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;QAElD,IAAI,CAAC;YACH,OAAO,MAAM,eAAe,CAAC;QAC/B,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,mBAAmB,CAC/B,GAAiB,EACjB,SAAiB,EACjB,GAAmB,EACnB,IAAmB;QAEnB,uEAAuE;QACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;QACvC,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,CAAC;QAEjD,MAAM,WAAW,GAAG,IAAI,kCAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;YAClE,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;YAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACrB,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;gBACjC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YAC3C,CAAC;YACD,+BAA+B;YAC/B,IAAI,YAAY,EAAE,CAAC;gBACjB,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YACrD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC;QAE1B,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAEnC,0DAA0D;QAC1D,IAAI,YAAY,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAC/C,MAAM,aAAa,GAAkB;gBACnC,OAAO,EAAE;oBACP,EAAE,EAAE,SAAS;oBACb,eAAe,EAAE,GAAG,CAAC,SAAS;oBAC9B,QAAQ,EAAE,iBAAiB;oBAC3B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;oBACrB,MAAM,EAAE,IAAA,kCAAY,GAAE;iBACvB;gBACD,eAAe,EAAE,GAAG,CAAC,SAAS;gBAC9B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;gBACrB,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE;aAC3B,CAAC;YACF,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,aAAa,EAAE,iBAAiB,EAAE,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACxF,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,uDAAuD,EAAE;oBAC9E,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;oBACjC,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;iBACxD,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACjC,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,IAAmB,EAAE,KAAa,EAAE,SAAiB,EAAE,MAAe;QAC7F,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QAE/C,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC5B,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACjC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC5C,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;gBAC1C,OAAO;YACT,CAAC;QACH,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC/E,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,sCAAsC,CAAC,IAAmB,EAAE,GAAmB;QACnF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,eAAe,EAAE,eAAe,CAAC,CAAC;QAC/D,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,qDAAqD;QACrD,MAAM,WAAW,GAAG,IAAI,kCAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;YAClE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACrB,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;gBACjC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAEnC,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACjC,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,0CAA0C,CAC9C,IAAmB,EACnB,KAAa,EACb,GAAmB;QAEnB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,4CAA4C;QAC5C,MAAM,WAAW,GAAG,IAAI,kCAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;YAClE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACrB,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;gBACjC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAEnC,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACjC,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,iBAAiB,CAAC,IAAmB,EAAE,KAAa,EAAE,SAAiB;QACrE,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrC,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QACnE,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,sBAAsB,CAAC,IAAmB,EAAE,KAAa,EAAE,SAAiB;QAChF,wCAAwC;QACxC,IAAI,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;YACnD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,yEAAyE;QACzE,+EAA+E;QAC/E,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;YACpD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;YACnE,OAAO,MAAM,KAAK,SAAS,CAAC;QAC9B,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED,kFAAkF;IAE1E,MAAM,CAAC,KAAa;QAC1B,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAClE,CAAC;IAED;;;OAGG;IACK,cAAc,CAAC,IAAY,EAAE,SAAiB,EAAE,SAAiB;QACvE,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;IACjE,CAAC;IAED;;;OAGG;IACK,eAAe,CAAC,GAAW;QACjC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,OAAO,MAAM,CAAC,CAAC,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,CAAC,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACjG,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;YACtE,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,IAAmB,EAAE,KAAa,EAAE,SAAiB,EAAE,YAAqB;QACxF,OAAO;YACL,IAAI;YACJ,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YAC7B,SAAS;YACT,YAAY;SACb,CAAC;IACJ,CAAC;IAEO,gBAAgB,CAAC,IAAmB;QAC1C,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,GAAG,IAAI,GAAG,EAAgC,CAAC;YACjD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,iBAAiB,CAAC,UAA+B,EAAE,SAAiB;QAC1E,IAAI,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACvC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;YACxC,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACpC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,WAAW,CAAC,GAAiB;QACnC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,UAAU;YAAE,OAAO,SAAS,CAAC;QAClC,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,WAAW;YAAE,OAAO,SAAS,CAAC;QACnC,OAAO,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC;IAEO,WAAW,CAAC,GAAiB,EAAE,CAAc;QACnD,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;QACtE,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAElC,4DAA4D;QAC5D,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/E,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAEhD,iDAAiD;QACjD,qFAAqF;QACrF,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACxD,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/E,0EAA0E;YAC1E,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,GAAG,GAAG,CAAC,CAAC;YAClE,IAAI,OAAO,GAAG,CAAC,CAAC;YAEhB,KAAK,MAAM,CAAC,OAAO,CAAC,IAAI,OAAO,EAAE,CAAC;gBAChC,IAAI,OAAO,IAAI,eAAe;oBAAE,MAAM;gBAEtC,uDAAuD;gBACvD,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;gBAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,qCAAqC;oBACrC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;oBACpC,OAAO,EAAE,CAAC;oBACV,SAAS;gBACX,CAAC;gBAED,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;gBAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAqB,CAAC,CAAC;gBAC1D,MAAM,WAAW,GAAG,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;gBAC/C,MAAM,kBAAkB,GAAG,WAAW,EAAE,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC;gBAEhE,6DAA6D;gBAC7D,IAAI,CAAC,kBAAkB,EAAE,CAAC;oBACxB,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;oBACpC,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;YAED,+EAA+E;YAC/E,IAAI,OAAO,GAAG,eAAe,EAAE,CAAC;gBAC9B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,2EAA2E,EAAE;oBAClG,eAAe;oBACf,eAAe,EAAE,OAAO;oBACxB,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI;oBACrC,OAAO,EAAE,IAAI,CAAC,mBAAmB;iBAClC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAEO,UAAU,CAAC,GAAiB;QAClC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,UAAU;YAAE,OAAO;QACxB,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,WAAW;YAAE,OAAO;QACzB,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAClC,IAAI,WAAW,CAAC,IAAI,KAAK,CAAC;YAAE,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7D,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC;YAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1D,CAAC;CACF;AApnBD,4CAonBC","sourcesContent":["// server/transport/transport.registry.ts\nimport { createHash } from 'crypto';\nimport {\n TransportBus,\n Transporter,\n TransportKey,\n TransportRegistryBucket,\n TransportTokenBucket,\n TransportType,\n TransportTypeBucket,\n} from './transport.types';\nimport { RemoteTransporter } from './transport.remote';\nimport { LocalTransporter } from './transport.local';\nimport { ServerResponse, TransportPersistenceConfigInput } from '../common';\nimport { Scope } from '../scope';\nimport HandleStreamableHttpFlow from './flows/handle.streamable-http.flow';\nimport HandleSseFlow from './flows/handle.sse.flow';\nimport HandleStatelessHttpFlow from './flows/handle.stateless-http.flow';\nimport { StoredSession } from '../auth/session';\nimport type { SessionStore } from '../auth/session/transport-session.types';\nimport { createSessionStore } from '../store';\nimport type { RedisOptions } from '../common/types/options/redis.options';\nimport { getMachineId } from '../auth/authorization/authorization.class';\n\nexport class TransportService {\n readonly ready: Promise<void>;\n private readonly byType: TransportRegistryBucket = new Map();\n private readonly distributed: boolean;\n private readonly bus?: TransportBus;\n private readonly scope: Scope;\n\n /**\n * Session history cache for tracking if sessions were ever created.\n * Used to differentiate between \"session never initialized\" (HTTP 400) and\n * \"session expired/terminated\" (HTTP 404) per MCP Spec 2025-11-25.\n *\n * Key: JSON-encoded {type, tokenHash, sessionId}, Value: creation timestamp\n * Note: We use JSON instead of colon-delimiter because sessionId can contain colons.\n */\n private readonly sessionHistory: Map<string, number> = new Map();\n private readonly MAX_SESSION_HISTORY = 10000;\n\n /**\n * Session store for transport persistence (Redis or Vercel KV)\n * Used to persist session metadata across server restarts\n */\n private sessionStore?: SessionStore & { ping?: () => Promise<boolean>; disconnect?: () => Promise<void> };\n\n /**\n * Transport persistence configuration\n */\n private persistenceConfig?: TransportPersistenceConfigInput;\n\n /**\n * Pending store configuration for async initialization\n */\n private pendingStoreConfig?: RedisOptions;\n\n /**\n * Mutex map for preventing concurrent transport creation for the same key.\n * Key: JSON-encoded {t: type, h: tokenHash, s: sessionId}, Value: Promise that resolves when creation completes\n */\n private readonly creationMutex: Map<string, Promise<Transporter>> = new Map();\n\n constructor(scope: Scope, persistenceConfig?: TransportPersistenceConfigInput) {\n this.scope = scope;\n this.persistenceConfig = persistenceConfig;\n this.distributed = false; // get from scope metadata\n this.bus = undefined; // get from scope metadata\n if (this.distributed && !this.bus) {\n throw new Error('TransportRegistry: distributed=true requires a TransportBus implementation.');\n }\n\n // Initialize session store if persistence is enabled (Redis or Vercel KV)\n if (persistenceConfig?.enabled && persistenceConfig.redis) {\n // Use factory to create appropriate session store based on provider\n const redisConfig = persistenceConfig.redis;\n const providerType = 'provider' in redisConfig ? redisConfig.provider : 'redis';\n\n // Override keyPrefix for transport persistence (separate from auth sessions)\n // Cast to RedisOptions since we're modifying the config\n this.pendingStoreConfig = {\n ...redisConfig,\n keyPrefix: redisConfig.keyPrefix ?? 'mcp:transport:',\n defaultTtlMs: persistenceConfig.defaultTtlMs ?? 3600000, // 1 hour default\n } as RedisOptions;\n\n this.scope.logger.info(\n `[TransportService] ${providerType} session store will be initialized for transport persistence`,\n );\n }\n\n this.ready = this.initialize();\n }\n\n private async initialize() {\n // Create session store if configuration is pending\n if (this.pendingStoreConfig) {\n try {\n const store = await createSessionStore(this.pendingStoreConfig, this.scope.logger.child('SessionStore'));\n // Cast to our extended type (both RedisSessionStore and VercelKvSessionStore have ping/disconnect)\n this.sessionStore = store as SessionStore & { ping?: () => Promise<boolean>; disconnect?: () => Promise<void> };\n this.pendingStoreConfig = undefined;\n } catch (error) {\n this.scope.logger.error('[TransportService] Failed to create session store - session persistence disabled', {\n error: (error as Error).message,\n });\n }\n }\n\n // Validate connection if session store is configured\n if (this.sessionStore) {\n const isConnected = this.sessionStore.ping ? await this.sessionStore.ping() : true;\n if (!isConnected) {\n const providerType =\n this.persistenceConfig?.redis && 'provider' in this.persistenceConfig.redis\n ? this.persistenceConfig.redis.provider\n : 'redis';\n this.scope.logger.error(\n `[TransportService] Failed to connect to ${providerType} - session persistence disabled`,\n );\n // Nullify sessionStore to prevent silent failures on all subsequent operations\n // This ensures clean graceful degradation - sessions will only persist in memory\n if (this.sessionStore.disconnect) {\n await this.sessionStore.disconnect().catch(() => void 0);\n }\n this.sessionStore = undefined;\n } else {\n this.scope.logger.info('[TransportService] Session store connection validated successfully');\n }\n }\n\n await this.scope.registryFlows(HandleStreamableHttpFlow, HandleSseFlow, HandleStatelessHttpFlow);\n }\n\n async destroy() {\n // Close session store connection if it was created\n if (this.sessionStore && this.sessionStore.disconnect) {\n try {\n await this.sessionStore.disconnect();\n this.scope.logger.info('[TransportService] Session store disconnected');\n } catch (error) {\n this.scope.logger.warn('[TransportService] Error disconnecting session store', {\n error: (error as Error).message,\n });\n }\n }\n }\n\n async getTransporter(type: TransportType, token: string, sessionId: string): Promise<Transporter | undefined> {\n const key = this.keyOf(type, token, sessionId);\n\n // 1. Check local in-memory cache first\n const local = this.lookupLocal(key);\n if (local) return local;\n\n // 2. Check distributed bus (if enabled)\n if (this.distributed && this.bus) {\n const location = await this.bus.lookup(key);\n if (location) {\n return new RemoteTransporter(key, this.bus);\n }\n }\n\n // Note: Redis-stored sessions require recreation via recreateTransporter()\n // Flows should use getStoredSession() to check if session exists in Redis,\n // then call recreateTransporter() with the response object.\n\n return undefined;\n }\n\n /**\n * Get stored session from Redis (without creating a transport).\n * Used by flows to check if session exists and can be recreated.\n *\n * @param type - Transport type\n * @param token - Authorization token\n * @param sessionId - Session ID\n * @returns Stored session data if exists and token matches, undefined otherwise\n */\n async getStoredSession(type: TransportType, token: string, sessionId: string): Promise<StoredSession | undefined> {\n if (!this.sessionStore || type !== 'streamable-http') return undefined;\n\n const tokenHash = this.sha256(token);\n const stored = await this.sessionStore.get(sessionId);\n if (!stored) return undefined;\n\n // Verify the token hash matches\n if (stored.authorizationId !== tokenHash) {\n this.scope.logger.warn('[TransportService] Session token mismatch during lookup', {\n sessionId: sessionId.slice(0, 20),\n storedTokenHash: stored.authorizationId.slice(0, 8),\n requestTokenHash: tokenHash.slice(0, 8),\n });\n return undefined;\n }\n\n return stored;\n }\n\n /**\n * Recreate a transport from stored session data.\n * Must be called with a valid response object to create the actual transport.\n *\n * @param type - Transport type\n * @param token - Authorization token\n * @param sessionId - Session ID\n * @param storedSession - Previously stored session data\n * @param res - Server response object for the new transport\n * @returns The recreated transport\n */\n async recreateTransporter(\n type: TransportType,\n token: string,\n sessionId: string,\n storedSession: StoredSession,\n res: ServerResponse,\n ): Promise<Transporter> {\n const key = this.keyOf(type, token, sessionId);\n\n // Check if already recreated in memory\n const existing = this.lookupLocal(key);\n if (existing) return existing;\n\n // Use mutex to prevent concurrent recreation of the same transport\n // Use JSON encoding for mutex key (consistent with history key format, handles colons in sessionId)\n const mutexKey = JSON.stringify({ t: type, h: key.tokenHash, s: sessionId });\n const pendingCreation = this.creationMutex.get(mutexKey);\n if (pendingCreation) {\n // Another request is already recreating this transport - wait for it\n return pendingCreation;\n }\n\n // Recreate the transport with mutex protection\n const recreationPromise = this.doRecreateTransporter(key, sessionId, storedSession, res);\n this.creationMutex.set(mutexKey, recreationPromise);\n\n try {\n return await recreationPromise;\n } catch (error) {\n // Log recreation errors for debugging\n this.scope.logger.error('[TransportService] Failed to recreate transport from stored session', {\n sessionId: sessionId.slice(0, 20),\n error: error instanceof Error ? { name: error.name, message: error.message } : String(error),\n });\n throw error;\n } finally {\n this.creationMutex.delete(mutexKey);\n }\n }\n\n /**\n * Internal method to actually recreate the transport (called with mutex protection)\n */\n private async doRecreateTransporter(\n key: TransportKey,\n sessionId: string,\n storedSession: StoredSession,\n res: ServerResponse,\n ): Promise<Transporter> {\n // Double-check in case another request completed while we were waiting\n const existing = this.lookupLocal(key);\n if (existing) return existing;\n\n this.scope.logger.info('[TransportService] Recreating transport from stored session', {\n sessionId: sessionId.slice(0, 20),\n protocol: storedSession.session.protocol,\n createdAt: storedSession.createdAt,\n });\n\n // Mark session as recreated in history\n const historyKey = this.makeHistoryKey(key.type, key.tokenHash, sessionId);\n this.sessionHistory.set(historyKey, storedSession.createdAt);\n\n const sessionStore = this.sessionStore;\n const persistenceConfig = this.persistenceConfig;\n\n // Create new transport\n const transporter = new LocalTransporter(this.scope, key, res, () => {\n key.sessionId = sessionId;\n this.evictLocal(key);\n if (this.distributed && this.bus) {\n this.bus.revoke(key).catch(() => void 0);\n }\n // Remove from Redis on dispose\n if (sessionStore) {\n sessionStore.delete(sessionId).catch(() => void 0);\n }\n });\n\n await transporter.ready();\n this.insertLocal(key, transporter);\n\n // Update session access time in Redis\n if (sessionStore) {\n const updatedSession: StoredSession = {\n ...storedSession,\n lastAccessedAt: Date.now(),\n };\n sessionStore.set(sessionId, updatedSession, persistenceConfig?.defaultTtlMs).catch((err) => {\n this.scope.logger.warn('[TransportService] Failed to update session in Redis', {\n sessionId: sessionId.slice(0, 20),\n error: err instanceof Error ? err.message : String(err),\n });\n });\n }\n\n if (this.distributed && this.bus) {\n await this.bus.advertise(key);\n }\n\n return transporter;\n }\n\n async createTransporter(\n type: TransportType,\n token: string,\n sessionId: string,\n res: ServerResponse,\n ): Promise<Transporter> {\n const key = this.keyOf(type, token, sessionId);\n\n // Check if already exists\n const existing = this.lookupLocal(key);\n if (existing) return existing;\n\n // Use mutex to prevent concurrent creation of the same transport\n // Use JSON encoding for mutex key (consistent with history key format, handles colons in sessionId)\n const mutexKey = JSON.stringify({ t: type, h: key.tokenHash, s: sessionId });\n const pendingCreation = this.creationMutex.get(mutexKey);\n if (pendingCreation) {\n // Another request is already creating this transport - wait for it\n return pendingCreation;\n }\n\n // Create the transport with mutex protection\n const creationPromise = this.doCreateTransporter(key, sessionId, res, type);\n this.creationMutex.set(mutexKey, creationPromise);\n\n try {\n return await creationPromise;\n } finally {\n this.creationMutex.delete(mutexKey);\n }\n }\n\n /**\n * Internal method to actually create the transport (called with mutex protection)\n */\n private async doCreateTransporter(\n key: TransportKey,\n sessionId: string,\n res: ServerResponse,\n type: TransportType,\n ): Promise<Transporter> {\n // Double-check in case another request completed while we were waiting\n const existing = this.lookupLocal(key);\n if (existing) return existing;\n\n const sessionStore = this.sessionStore;\n const persistenceConfig = this.persistenceConfig;\n\n const transporter = new LocalTransporter(this.scope, key, res, () => {\n key.sessionId = sessionId;\n this.evictLocal(key);\n if (this.distributed && this.bus) {\n this.bus.revoke(key).catch(() => void 0);\n }\n // Remove from Redis on dispose\n if (sessionStore) {\n sessionStore.delete(sessionId).catch(() => void 0);\n }\n });\n\n await transporter.ready();\n\n this.insertLocal(key, transporter);\n\n // Persist session to Redis (streamable-http only for now)\n if (sessionStore && type === 'streamable-http') {\n const storedSession: StoredSession = {\n session: {\n id: sessionId,\n authorizationId: key.tokenHash,\n protocol: 'streamable-http',\n createdAt: Date.now(),\n nodeId: getMachineId(),\n },\n authorizationId: key.tokenHash,\n createdAt: Date.now(),\n lastAccessedAt: Date.now(),\n };\n sessionStore.set(sessionId, storedSession, persistenceConfig?.defaultTtlMs).catch((err) => {\n this.scope.logger.warn('[TransportService] Failed to persist session to Redis', {\n sessionId: sessionId.slice(0, 20),\n error: err instanceof Error ? err.message : String(err),\n });\n });\n }\n\n if (this.distributed && this.bus) {\n await this.bus.advertise(key);\n }\n\n return transporter;\n }\n\n async destroyTransporter(type: TransportType, token: string, sessionId: string, reason?: string): Promise<void> {\n const key = this.keyOf(type, token, sessionId);\n\n const local = this.lookupLocal(key);\n if (local) {\n await local.destroy(reason);\n return;\n }\n\n if (this.distributed && this.bus) {\n const location = await this.bus.lookup(key);\n if (location) {\n await this.bus.destroyRemote(key, reason);\n return;\n }\n }\n\n throw new Error('Invalid session: cannot destroy non-existent transporter.');\n }\n\n /**\n * Get or create a shared singleton transport for anonymous stateless requests.\n * All anonymous requests share the same transport instance.\n */\n async getOrCreateAnonymousStatelessTransport(type: TransportType, res: ServerResponse): Promise<Transporter> {\n const key = this.keyOf(type, '__anonymous__', '__stateless__');\n const existing = this.lookupLocal(key);\n if (existing) return existing;\n\n // Create shared transport for all anonymous requests\n const transporter = new LocalTransporter(this.scope, key, res, () => {\n this.evictLocal(key);\n if (this.distributed && this.bus) {\n this.bus.revoke(key).catch(() => void 0);\n }\n });\n\n await transporter.ready();\n this.insertLocal(key, transporter);\n\n if (this.distributed && this.bus) {\n await this.bus.advertise(key);\n }\n\n return transporter;\n }\n\n /**\n * Get or create a singleton transport for authenticated stateless requests.\n * Each unique token gets its own singleton transport.\n */\n async getOrCreateAuthenticatedStatelessTransport(\n type: TransportType,\n token: string,\n res: ServerResponse,\n ): Promise<Transporter> {\n const key = this.keyOf(type, token, '__stateless__');\n const existing = this.lookupLocal(key);\n if (existing) return existing;\n\n // Create singleton transport for this token\n const transporter = new LocalTransporter(this.scope, key, res, () => {\n this.evictLocal(key);\n if (this.distributed && this.bus) {\n this.bus.revoke(key).catch(() => void 0);\n }\n });\n\n await transporter.ready();\n this.insertLocal(key, transporter);\n\n if (this.distributed && this.bus) {\n await this.bus.advertise(key);\n }\n\n return transporter;\n }\n\n /**\n * Check if a session was ever created (even if it's been terminated/evicted).\n * Used to differentiate between \"session never initialized\" (HTTP 400) and\n * \"session expired/terminated\" (HTTP 404) per MCP Spec 2025-11-25.\n *\n * Note: This is synchronous and only checks local history. For async Redis check,\n * use wasSessionCreatedAsync.\n *\n * @param type - Transport type (e.g., 'streamable-http', 'sse')\n * @param token - The authorization token\n * @param sessionId - The session ID to check\n * @returns true if session was ever created locally, false otherwise\n */\n wasSessionCreated(type: TransportType, token: string, sessionId: string): boolean {\n const tokenHash = this.sha256(token);\n const historyKey = this.makeHistoryKey(type, tokenHash, sessionId);\n return this.sessionHistory.has(historyKey);\n }\n\n /**\n * Async version that also checks Redis for session existence.\n * Used when we need to check if session was ever created across server restarts.\n */\n async wasSessionCreatedAsync(type: TransportType, token: string, sessionId: string): Promise<boolean> {\n // Check local history first (fast path)\n if (this.wasSessionCreated(type, token, sessionId)) {\n return true;\n }\n\n // Check Redis if available - use getStoredSession() to verify token hash\n // (sessionStore.exists() would leak session existence to unauthorized callers)\n if (this.sessionStore && type === 'streamable-http') {\n const stored = await this.getStoredSession(type, token, sessionId);\n return stored !== undefined;\n }\n\n return false;\n }\n\n /* --------------------------------- internals -------------------------------- */\n\n private sha256(value: string): string {\n return createHash('sha256').update(value, 'utf8').digest('hex');\n }\n\n /**\n * Create a history key from components.\n * Uses JSON encoding to handle sessionIds that contain special characters.\n */\n private makeHistoryKey(type: string, tokenHash: string, sessionId: string): string {\n return JSON.stringify({ t: type, h: tokenHash, s: sessionId });\n }\n\n /**\n * Parse a history key back into components.\n * Returns undefined if the key is malformed.\n */\n private parseHistoryKey(key: string): { type: string; tokenHash: string; sessionId: string } | undefined {\n try {\n const parsed = JSON.parse(key);\n if (typeof parsed.t === 'string' && typeof parsed.h === 'string' && typeof parsed.s === 'string') {\n return { type: parsed.t, tokenHash: parsed.h, sessionId: parsed.s };\n }\n return undefined;\n } catch {\n return undefined;\n }\n }\n\n private keyOf(type: TransportType, token: string, sessionId: string, sessionIdSse?: string): TransportKey {\n return {\n type,\n token,\n tokenHash: this.sha256(token),\n sessionId,\n sessionIdSse,\n };\n }\n\n private ensureTypeBucket(type: TransportType): TransportTypeBucket {\n let bucket = this.byType.get(type);\n if (!bucket) {\n bucket = new Map<string, TransportTokenBucket>();\n this.byType.set(type, bucket);\n }\n return bucket;\n }\n\n private ensureTokenBucket(typeBucket: TransportTypeBucket, tokenHash: string): TransportTokenBucket {\n let bucket = typeBucket.get(tokenHash);\n if (!bucket) {\n bucket = new Map<string, Transporter>();\n typeBucket.set(tokenHash, bucket);\n }\n return bucket;\n }\n\n private lookupLocal(key: TransportKey): Transporter | undefined {\n const typeBucket = this.byType.get(key.type);\n if (!typeBucket) return undefined;\n const tokenBucket = typeBucket.get(key.tokenHash);\n if (!tokenBucket) return undefined;\n return tokenBucket.get(key.sessionId);\n }\n\n private insertLocal(key: TransportKey, t: Transporter): void {\n const typeBucket = this.ensureTypeBucket(key.type);\n const tokenBucket = this.ensureTokenBucket(typeBucket, key.tokenHash);\n tokenBucket.set(key.sessionId, t);\n\n // Record session creation in history for HTTP 404 detection\n const historyKey = this.makeHistoryKey(key.type, key.tokenHash, key.sessionId);\n this.sessionHistory.set(historyKey, Date.now());\n\n // Evict oldest entries if cache exceeds max size\n // Only evict entries that don't have active transports (to avoid inconsistent state)\n if (this.sessionHistory.size > this.MAX_SESSION_HISTORY) {\n const entries = [...this.sessionHistory.entries()].sort((a, b) => a[1] - b[1]);\n // Try to remove oldest 10% of entries (skip those with active transports)\n const targetEvictions = Math.ceil(this.MAX_SESSION_HISTORY * 0.1);\n let evicted = 0;\n\n for (const [histKey] of entries) {\n if (evicted >= targetEvictions) break;\n\n // Parse history key to check if transport still exists\n const parsed = this.parseHistoryKey(histKey);\n if (!parsed) {\n // Invalid key format - safe to evict\n this.sessionHistory.delete(histKey);\n evicted++;\n continue;\n }\n\n const { type, tokenHash, sessionId } = parsed;\n const typeBucket = this.byType.get(type as TransportType);\n const tokenBucket = typeBucket?.get(tokenHash);\n const hasActiveTransport = tokenBucket?.has(sessionId) ?? false;\n\n // Only evict if there's no active transport for this session\n if (!hasActiveTransport) {\n this.sessionHistory.delete(histKey);\n evicted++;\n }\n }\n\n // Log warning if we couldn't evict enough entries (all have active transports)\n if (evicted < targetEvictions) {\n this.scope.logger.warn('[TransportService] Session history eviction: unable to free target memory', {\n targetEvictions,\n actualEvictions: evicted,\n currentSize: this.sessionHistory.size,\n maxSize: this.MAX_SESSION_HISTORY,\n });\n }\n }\n }\n\n private evictLocal(key: TransportKey): void {\n const typeBucket = this.byType.get(key.type);\n if (!typeBucket) return;\n const tokenBucket = typeBucket.get(key.tokenHash);\n if (!tokenBucket) return;\n tokenBucket.delete(key.sessionId);\n if (tokenBucket.size === 0) typeBucket.delete(key.tokenHash);\n if (typeBucket.size === 0) this.byType.delete(key.type);\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"htmx-templates.js","sourceRoot":"","sources":["../../../../src/auth/ui/htmx-templates.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * HTMX Template Builders for OAuth UI\n *\n * Server-side HTML rendering with HTMX for interactivity.\n * No build step required - pure runtime rendering with Tailwind CSS CDN.\n *\n * Features:\n * - OAuth consent page with multiple apps\n * - Incremental authorization page for single app\n * - Federated login page for multi-provider selection\n * - All pages use Tailwind CSS from CDN (no build required)\n * - Google Fonts (Inter) for modern typography\n * - HTMX for progressive enhancement (~14KB)\n *\n * Uses base-layout.ts for consistent HTML shell with CDN resources.\n */\n\nimport {\n baseLayout,\n wideLayout,\n extraWideLayout,\n centeredCardLayout,\n escapeHtml as baseEscapeHtml,\n} from './base-layout';\n\n// ============================================\n// Types\n// ============================================\n\n/**\n * App information for authorization cards\n */\nexport interface AppAuthCard {\n /** App identifier */\n appId: string;\n /** Display name */\n appName: string;\n /** App description */\n description?: string;\n /** Icon URL (optional, will use initials fallback) */\n iconUrl?: string;\n /** Scopes required by this app */\n requiredScopes?: string[];\n}\n\n/**\n * Provider information for federated login\n */\nexport interface ProviderCard {\n /** Provider identifier */\n providerId: string;\n /** Display name */\n providerName: string;\n /** Provider URL (for remote providers) */\n providerUrl?: string;\n /** Auth mode */\n mode: string;\n /** App IDs associated with this provider */\n appIds: string[];\n /** Whether this is the parent/primary provider */\n isPrimary?: boolean;\n}\n\n/**\n * Tool information for consent page\n */\nexport interface ToolCard {\n /** Tool identifier */\n toolId: string;\n /** Display name */\n toolName: string;\n /** Tool description */\n description?: string;\n /** Parent app ID */\n appId: string;\n /** Parent app name */\n appName: string;\n}\n\n// ============================================\n// Utility Functions\n// ============================================\n\n/**\n * Escape HTML special characters\n * Re-exported from base-layout for convenience\n */\nexport const escapeHtml = baseEscapeHtml;\n\n// ============================================\n// Template Builders\n// ============================================\n\n/**\n * Build OAuth consent page with HTMX + Tailwind\n * Shows all apps at once with Authorize/Skip buttons\n */\nexport function buildConsentPage(params: {\n apps: AppAuthCard[];\n clientName: string;\n pendingAuthId: string;\n csrfToken: string;\n callbackPath: string;\n}): string {\n const { apps, clientName, pendingAuthId, csrfToken, callbackPath } = params;\n\n const appCards = apps.map((app) => buildAppCardHtml(app, pendingAuthId, csrfToken, callbackPath)).join('\\n');\n\n const content = `\n <h1 class=\"text-3xl font-bold text-gray-900 mb-4\">Authorize ${escapeHtml(clientName)}</h1>\n <p class=\"text-gray-600 mb-8\">\n Select which apps you want to authorize. You can skip apps and authorize them later when needed.\n </p>\n\n <div class=\"space-y-4\" id=\"app-list\">\n ${appCards}\n </div>\n\n <div class=\"mt-6 p-4 bg-blue-50 border border-blue-200 rounded-lg text-sm text-blue-800\">\n Skipped apps can be authorized later when you try to use their tools (progressive authorization).\n </div>`;\n\n return wideLayout(content, { title: `Authorize ${clientName}` });\n}\n\n/**\n * Build single app authorization card HTML\n */\nfunction buildAppCardHtml(app: AppAuthCard, pendingAuthId: string, csrfToken: string, callbackPath: string): string {\n const icon = app.iconUrl\n ? `<img src=\"${escapeHtml(app.iconUrl)}\" alt=\"${escapeHtml(\n app.appName,\n )}\" class=\"w-12 h-12 rounded-lg object-cover\">`\n : `<div class=\"w-12 h-12 rounded-lg bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center text-white font-bold text-lg\">${escapeHtml(\n app.appName.charAt(0).toUpperCase(),\n )}</div>`;\n\n const description = app.description ? `<p class=\"text-sm text-gray-500\">${escapeHtml(app.description)}</p>` : '';\n\n const scopes = app.requiredScopes?.length\n ? `<div class=\"mb-4\">\n <p class=\"text-xs font-medium text-gray-500 uppercase tracking-wide mb-2\">Permissions</p>\n <div class=\"flex flex-wrap gap-2\">\n ${app.requiredScopes\n .map(\n (scope) =>\n `<span class=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800\">${escapeHtml(\n scope,\n )}</span>`,\n )\n .join('')}\n </div>\n </div>`\n : '';\n\n return `<div class=\"bg-white rounded-xl shadow-sm border border-gray-200 p-6 hover:shadow-md transition-shadow\" data-app-id=\"${escapeHtml(\n app.appId,\n )}\">\n <div class=\"flex items-center gap-4 mb-4\">\n ${icon}\n <div class=\"flex-1\">\n <h3 class=\"font-semibold text-gray-900\">${escapeHtml(app.appName)}</h3>\n ${description}\n </div>\n </div>\n\n ${scopes}\n\n <form method=\"POST\" action=\"${escapeHtml(callbackPath)}\" class=\"flex gap-3 pt-4 border-t border-gray-100\">\n <input type=\"hidden\" name=\"csrf\" value=\"${escapeHtml(csrfToken)}\">\n <input type=\"hidden\" name=\"pending_auth_id\" value=\"${escapeHtml(pendingAuthId)}\">\n <input type=\"hidden\" name=\"app\" value=\"${escapeHtml(app.appId)}\">\n <button type=\"submit\" name=\"action\" value=\"authorize\"\n class=\"flex-1 bg-blue-600 hover:bg-blue-700 text-white font-medium py-2.5 px-4 rounded-lg transition-colors\"\n hx-post=\"${escapeHtml(callbackPath)}\"\n hx-swap=\"outerHTML\"\n hx-target=\"closest div[data-app-id]\">\n Authorize\n </button>\n <button type=\"submit\" name=\"action\" value=\"skip\"\n class=\"px-4 py-2.5 text-gray-600 hover:text-gray-900 hover:bg-gray-100 font-medium rounded-lg transition-colors\"\n hx-post=\"${escapeHtml(callbackPath)}\"\n hx-swap=\"outerHTML\"\n hx-target=\"closest div[data-app-id]\">\n Skip\n </button>\n </form>\n </div>`;\n}\n\n/**\n * Build incremental auth page (single app) with HTMX + Tailwind\n * Used when a tool requires authorization for a skipped app\n */\nexport function buildIncrementalAuthPage(params: {\n app: AppAuthCard;\n toolId: string;\n sessionHint: string;\n callbackPath: string;\n}): string {\n const { app, toolId, sessionHint, callbackPath } = params;\n\n const description = app.description ? `<p class=\"text-gray-500 mt-2\">${escapeHtml(app.description)}</p>` : '';\n\n const content = `\n <!-- Warning icon -->\n <div class=\"flex justify-center mb-6\">\n <div class=\"w-16 h-16 rounded-full bg-amber-100 flex items-center justify-center\">\n <svg class=\"w-8 h-8 text-amber-600\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"/>\n </svg>\n </div>\n </div>\n\n <h1 class=\"text-2xl font-bold text-gray-900 text-center mb-2\">Authorization Required</h1>\n <p class=\"text-gray-600 text-center mb-8\">\n To use \"<span class=\"font-mono text-sm bg-gray-100 px-1 rounded\">${escapeHtml(\n toolId,\n )}</span>\", you need to authorize ${escapeHtml(app.appName)}.\n </p>\n\n <!-- App card -->\n <div class=\"bg-white rounded-xl shadow-sm border border-gray-200 p-6 mb-6\">\n <div class=\"flex items-center gap-4 mb-4\">\n <div class=\"w-12 h-12 rounded-lg bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center text-white font-bold text-lg\">\n ${escapeHtml(app.appName.charAt(0).toUpperCase())}\n </div>\n <div class=\"flex-1\">\n <h3 class=\"font-semibold text-gray-900\">${escapeHtml(app.appName)}</h3>\n ${description}\n </div>\n </div>\n\n <form method=\"GET\" action=\"${escapeHtml(callbackPath)}\" class=\"flex gap-3 pt-4 border-t border-gray-100\">\n <input type=\"hidden\" name=\"pending_auth_id\" value=\"${escapeHtml(sessionHint)}\">\n <input type=\"hidden\" name=\"app_id\" value=\"${escapeHtml(app.appId)}\">\n <input type=\"hidden\" name=\"incremental\" value=\"true\">\n <button type=\"button\" onclick=\"window.close()\"\n class=\"flex-1 px-4 py-2.5 text-gray-600 hover:text-gray-900 hover:bg-gray-100 font-medium rounded-lg transition-colors\">\n Cancel\n </button>\n <button type=\"submit\"\n class=\"flex-1 bg-blue-600 hover:bg-blue-700 text-white font-medium py-2.5 px-4 rounded-lg transition-colors\">\n Authorize\n </button>\n </form>\n </div>\n\n <div class=\"p-4 bg-amber-50 border border-amber-200 rounded-lg text-sm text-amber-800 text-center\">\n This is an incremental authorization. Your existing session will be expanded to include ${escapeHtml(\n app.appName,\n )}.\n </div>`;\n\n return centeredCardLayout(content, { title: `Authorize ${app.appName}` });\n}\n\n/**\n * Build federated login page for multi-provider selection\n */\nexport function buildFederatedLoginPage(params: {\n providers: ProviderCard[];\n clientName: string;\n pendingAuthId: string;\n csrfToken: string;\n callbackPath: string;\n}): string {\n const { providers, clientName, pendingAuthId, csrfToken, callbackPath } = params;\n\n const providerCards = providers\n .map((provider) => {\n const isPrimaryBadge = provider.isPrimary\n ? `<span class=\"px-2 py-0.5 text-xs font-medium bg-blue-600 text-white rounded-full\">Primary</span>`\n : '';\n\n const providerUrl = provider.providerUrl\n ? `<p class=\"text-xs text-gray-400 font-mono truncate\">${escapeHtml(provider.providerUrl)}</p>`\n : '';\n\n const appIds =\n provider.appIds.length > 0\n ? `<p class=\"text-xs text-gray-500 mt-1\">Apps: ${provider.appIds.map((id) => escapeHtml(id)).join(', ')}</p>`\n : '';\n\n return `<label class=\"flex items-start gap-4 p-4 bg-white border-2 border-gray-200 rounded-xl cursor-pointer hover:border-blue-300 transition-colors has-[:checked]:border-blue-500 has-[:checked]:bg-blue-50\">\n <input type=\"checkbox\" name=\"providers\" value=\"${escapeHtml(provider.providerId)}\"\n class=\"mt-1 w-5 h-5 rounded border-gray-300\" ${provider.isPrimary ? 'checked' : ''}>\n <div class=\"flex-1\">\n <div class=\"flex items-center gap-2 mb-1\">\n <span class=\"font-semibold text-gray-900\">${escapeHtml(provider.providerName)}</span>\n ${isPrimaryBadge}\n </div>\n <p class=\"text-sm text-gray-500\">Mode: ${escapeHtml(provider.mode)}</p>\n ${providerUrl}\n ${appIds}\n </div>\n </label>`;\n })\n .join('\\n');\n\n const content = `\n <h1 class=\"text-3xl font-bold text-gray-900 mb-4\">Select Authorization Providers</h1>\n <p class=\"text-gray-600 mb-8\">\n ${escapeHtml(clientName)} uses multiple authentication providers. Select which ones you want to authorize.\n </p>\n\n <form method=\"GET\" action=\"${escapeHtml(callbackPath)}\" id=\"federated-form\">\n <input type=\"hidden\" name=\"pending_auth_id\" value=\"${escapeHtml(pendingAuthId)}\">\n <input type=\"hidden\" name=\"federated\" value=\"true\">\n\n <!-- Select all toggle -->\n <label class=\"flex items-center gap-3 mb-6 cursor-pointer\">\n <input type=\"checkbox\" id=\"select-all\" class=\"w-5 h-5 rounded border-gray-300\"\n onchange=\"document.querySelectorAll('input[name=providers]').forEach(cb => cb.checked = this.checked)\">\n <span class=\"text-gray-700\">Select all providers</span>\n </label>\n\n <!-- Provider cards -->\n <div class=\"space-y-4 mb-8\">\n ${providerCards}\n </div>\n\n <!-- Email input -->\n <div class=\"mb-6\">\n <label for=\"email\" class=\"block text-sm font-medium text-gray-700 mb-2\">Email</label>\n <input type=\"email\" id=\"email\" name=\"email\" required placeholder=\"you@example.com\"\n class=\"w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500\">\n </div>\n\n <!-- Buttons -->\n <div class=\"flex gap-4\">\n <button type=\"button\"\n class=\"flex-1 px-6 py-3 text-gray-700 bg-gray-100 hover:bg-gray-200 font-medium rounded-lg transition-colors\"\n onclick=\"document.querySelectorAll('input[name=providers]').forEach(cb => cb.checked = false); document.getElementById('federated-form').submit();\">\n Skip All\n </button>\n <button type=\"submit\"\n class=\"flex-1 px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors\">\n Continue\n </button>\n </div>\n </form>\n\n <div class=\"mt-6 p-4 bg-blue-50 border border-blue-200 rounded-lg text-sm text-blue-800\">\n Skipped providers can be authorized later when you try to use their tools (progressive authorization).\n </div>`;\n\n return wideLayout(content, { title: 'Select Providers' });\n}\n\n/**\n * Build consent page for tool selection\n */\nexport function buildToolConsentPage(params: {\n tools: ToolCard[];\n clientName: string;\n pendingAuthId: string;\n csrfToken: string;\n callbackPath: string;\n userName?: string;\n userEmail?: string;\n}): string {\n const { tools, clientName, pendingAuthId, csrfToken, callbackPath, userName, userEmail } = params;\n\n // Group tools by app\n const toolsByApp: Record<string, { appName: string; tools: ToolCard[] }> = {};\n for (const tool of tools) {\n if (!toolsByApp[tool.appId]) {\n toolsByApp[tool.appId] = { appName: tool.appName, tools: [] };\n }\n toolsByApp[tool.appId].tools.push(tool);\n }\n\n const userInfo =\n userName || userEmail\n ? `<div class=\"p-3 bg-gray-50 rounded-lg mb-6 text-sm\">\n <span class=\"text-gray-500\">Signed in as: </span>\n <span class=\"font-medium text-gray-900\">${escapeHtml(userName || userEmail || '')}</span>\n </div>`\n : '';\n\n const appGroups = Object.entries(toolsByApp)\n .map(([appId, { appName, tools: appTools }]) => {\n const toolItems = appTools\n .map((tool) => {\n const desc = tool.description\n ? `<p class=\"text-sm text-gray-500 mt-0.5\">${escapeHtml(tool.description)}</p>`\n : '';\n return `<label class=\"flex items-start gap-3 p-3 bg-white rounded-lg cursor-pointer hover:bg-gray-50\">\n <input type=\"checkbox\" name=\"tools\" value=\"${escapeHtml(\n tool.toolId,\n )}\" class=\"mt-0.5 w-5 h-5 rounded border-gray-300\" checked>\n <div>\n <span class=\"font-medium text-gray-900\">${escapeHtml(tool.toolName)}</span>\n ${desc}\n </div>\n </label>`;\n })\n .join('\\n');\n\n return `<div class=\"bg-gray-50 rounded-xl overflow-hidden\">\n <div class=\"flex items-center justify-between px-4 py-3 bg-gray-100\">\n <div class=\"flex items-center gap-3\">\n <div class=\"w-8 h-8 rounded-lg bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center text-white font-bold text-sm\">\n ${escapeHtml(appName.charAt(0).toUpperCase())}\n </div>\n <span class=\"font-semibold text-gray-900\">${escapeHtml(appName)}</span>\n </div>\n <button type=\"button\" class=\"text-sm text-blue-600 hover:text-blue-800\"\n onclick=\"const container = this.closest('.bg-gray-50').querySelector('[data-app]'); const cbs = container.querySelectorAll('input[name=tools]'); const allChecked = [...cbs].every(cb => cb.checked); cbs.forEach(cb => cb.checked = !allChecked); updateCount();\">\n Toggle All\n </button>\n </div>\n <div class=\"p-4 space-y-2\" data-app=\"${escapeHtml(appId)}\">\n ${toolItems}\n </div>\n </div>`;\n })\n .join('\\n');\n\n const updateCountScript = `\n <script>\n function updateCount() {\n const all = document.querySelectorAll('input[name=\"tools\"]');\n const checked = document.querySelectorAll('input[name=\"tools\"]:checked');\n document.getElementById('selection-count').textContent = checked.length + ' of ' + all.length + ' selected';\n document.getElementById('select-all').checked = all.length > 0 && all.length === checked.length;\n }\n document.querySelectorAll('input[name=\"tools\"]').forEach(cb => cb.addEventListener('change', updateCount));\n </script>`;\n\n const content = `\n <h1 class=\"text-3xl font-bold text-gray-900 mb-4\">Select Tools to Enable</h1>\n <p class=\"text-gray-600 mb-6\">\n Choose which tools ${escapeHtml(clientName)} can access. You can change this later.\n </p>\n\n ${userInfo}\n\n <form method=\"POST\" action=\"${escapeHtml(callbackPath)}\" id=\"consent-form\">\n <input type=\"hidden\" name=\"csrf\" value=\"${escapeHtml(csrfToken)}\">\n <input type=\"hidden\" name=\"pending_auth_id\" value=\"${escapeHtml(pendingAuthId)}\">\n\n <!-- Select all toggle -->\n <div class=\"flex items-center justify-between mb-6\">\n <label class=\"flex items-center gap-3 cursor-pointer\">\n <input type=\"checkbox\" id=\"select-all\" class=\"w-5 h-5 rounded border-gray-300\" checked\n onchange=\"document.querySelectorAll('input[name=tools]').forEach(cb => cb.checked = this.checked); updateCount();\">\n <span class=\"text-gray-700\">Select all tools</span>\n </label>\n <span id=\"selection-count\" class=\"text-sm text-gray-500\">${tools.length} of ${tools.length} selected</span>\n </div>\n\n <!-- Tool groups by app -->\n <div class=\"space-y-6 mb-8\">\n ${appGroups}\n </div>\n\n <!-- Buttons -->\n <div class=\"flex gap-4\">\n <button type=\"button\" onclick=\"history.back()\"\n class=\"flex-1 px-6 py-3 text-gray-700 bg-gray-100 hover:bg-gray-200 font-medium rounded-lg transition-colors\">\n Cancel\n </button>\n <button type=\"submit\"\n class=\"flex-1 px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors\">\n Confirm Selection\n </button>\n </div>\n </form>\n ${updateCountScript}`;\n\n return extraWideLayout(content, { title: 'Select Tools' });\n}\n\n/**\n * Build simple login page\n */\nexport function buildLoginPage(params: {\n clientName: string;\n scope: string;\n pendingAuthId: string;\n callbackPath: string;\n}): string {\n const { clientName, scope, pendingAuthId, callbackPath } = params;\n\n const scopesHtml = scope\n ? `<div class=\"p-4 bg-gray-50 rounded-lg mb-6\">\n <p class=\"text-xs font-medium text-gray-500 uppercase tracking-wide mb-2\">Requested permissions</p>\n <p class=\"text-gray-700\">${\n scope\n .split(' ')\n .map((s) => escapeHtml(s))\n .join(', ') || 'Default access'\n }</p>\n </div>`\n : '';\n\n const content = `\n <div class=\"bg-white rounded-2xl shadow-xl p-8\">\n <h1 class=\"text-3xl font-bold text-gray-900 mb-2 text-center\">Sign In</h1>\n <p class=\"text-gray-600 mb-8 text-center\">Authorize access to ${escapeHtml(clientName)}</p>\n\n ${scopesHtml}\n\n <form method=\"GET\" action=\"${escapeHtml(callbackPath)}\">\n <input type=\"hidden\" name=\"pending_auth_id\" value=\"${escapeHtml(pendingAuthId)}\">\n\n <!-- Email -->\n <div class=\"mb-4\">\n <label for=\"email\" class=\"block text-sm font-medium text-gray-700 mb-2\">Email</label>\n <input type=\"email\" id=\"email\" name=\"email\" required placeholder=\"you@example.com\"\n class=\"w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500\">\n </div>\n\n <!-- Name (optional) -->\n <div class=\"mb-6\">\n <label for=\"name\" class=\"block text-sm font-medium text-gray-700 mb-2\">Name (optional)</label>\n <input type=\"text\" id=\"name\" name=\"name\" placeholder=\"Your name\"\n class=\"w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500\">\n </div>\n\n <!-- Submit -->\n <button type=\"submit\"\n class=\"w-full px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors\">\n Authorize\n </button>\n </form>\n\n <p class=\"text-center text-sm text-gray-500 mt-6\">Client: ${escapeHtml(clientName)}</p>\n </div>`;\n\n return centeredCardLayout(content, { title: 'Sign In' });\n}\n\n/**\n * Build error page\n */\nexport function buildErrorPage(params: { error: string; description: string }): string {\n const { error, description } = params;\n\n const content = `\n <div class=\"bg-white rounded-2xl shadow-xl p-8 text-center\">\n <!-- Error icon -->\n <div class=\"flex justify-center mb-6\">\n <div class=\"w-16 h-16 rounded-full bg-red-100 flex items-center justify-center\">\n <svg class=\"w-8 h-8 text-red-600\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"/>\n </svg>\n </div>\n </div>\n\n <h1 class=\"text-2xl font-bold text-gray-900 mb-4\">Authorization Error</h1>\n <p class=\"mb-4\">\n <code class=\"px-2 py-1 bg-gray-100 rounded text-red-600 font-mono text-sm\">${escapeHtml(error)}</code>\n </p>\n <p class=\"text-gray-600\">${escapeHtml(description)}</p>\n </div>`;\n\n return centeredCardLayout(content, { title: 'Error' });\n}\n\n// ============================================\n// Legacy Compatibility - renderToHtml wrapper\n// ============================================\n\n/**\n * Simple wrapper for compatibility - just returns the HTML string\n * (HTMX templates are already complete HTML documents)\n */\nexport function renderToHtml(html: string, _options?: { title?: string }): string {\n return html;\n}\n"]}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { SessionIdPayload, UserClaim } from '../types';
|
|
2
|
-
export declare class SessionProvider {
|
|
3
|
-
token: string;
|
|
4
|
-
user: UserClaim;
|
|
5
|
-
session?: {
|
|
6
|
-
id: string;
|
|
7
|
-
payload: SessionIdPayload;
|
|
8
|
-
} | undefined;
|
|
9
|
-
sessionId: string;
|
|
10
|
-
sessionIdPayload: SessionIdPayload;
|
|
11
|
-
requestId: string | number;
|
|
12
|
-
setRequestId(requestId: string | number): void;
|
|
13
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SessionProvider = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const decorators_1 = require("../decorators");
|
|
6
|
-
const metadata_1 = require("../metadata");
|
|
7
|
-
// TODO: REFACTOR/PROVIDERS - move to core and keep SessionInterface and SessionToken for DI
|
|
8
|
-
let SessionProvider = class SessionProvider {
|
|
9
|
-
token;
|
|
10
|
-
user;
|
|
11
|
-
session;
|
|
12
|
-
sessionId;
|
|
13
|
-
sessionIdPayload;
|
|
14
|
-
requestId;
|
|
15
|
-
setRequestId(requestId) {
|
|
16
|
-
this.requestId = requestId;
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
exports.SessionProvider = SessionProvider;
|
|
20
|
-
exports.SessionProvider = SessionProvider = tslib_1.__decorate([
|
|
21
|
-
(0, decorators_1.Provider)({
|
|
22
|
-
name: 'SessionProvider',
|
|
23
|
-
description: 'Used to store session information',
|
|
24
|
-
scope: metadata_1.ProviderScope.SESSION,
|
|
25
|
-
})
|
|
26
|
-
], SessionProvider);
|
|
27
|
-
//# sourceMappingURL=session.provider.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session.provider.js","sourceRoot":"","sources":["../../../../src/common/providers/session.provider.ts"],"names":[],"mappings":";;;;AACA,8CAAyC;AACzC,0CAA4C;AAE5C,4FAA4F;AAOrF,IAAM,eAAe,GAArB,MAAM,eAAe;IAC1B,KAAK,CAAS;IACd,IAAI,CAAY;IAChB,OAAO,CAA0D;IACjE,SAAS,CAAS;IAClB,gBAAgB,CAAmB;IAEnC,SAAS,CAAkB;IAE3B,YAAY,CAAC,SAA0B;QACrC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF,CAAA;AAZY,0CAAe;0BAAf,eAAe;IAL3B,IAAA,qBAAQ,EAAC;QACR,IAAI,EAAE,iBAAiB;QACvB,WAAW,EAAE,mCAAmC;QAChD,KAAK,EAAE,wBAAa,CAAC,OAAO;KAC7B,CAAC;GACW,eAAe,CAY3B","sourcesContent":["import { SessionIdPayload, UserClaim } from '../types';\nimport { Provider } from '../decorators';\nimport { ProviderScope } from '../metadata';\n\n// TODO: REFACTOR/PROVIDERS - move to core and keep SessionInterface and SessionToken for DI\n\n@Provider({\n name: 'SessionProvider',\n description: 'Used to store session information',\n scope: ProviderScope.SESSION,\n})\nexport class SessionProvider {\n token: string;\n user: UserClaim;\n session?: { id: string; payload: SessionIdPayload; } | undefined;\n sessionId: string;\n sessionIdPayload: SessionIdPayload;\n\n requestId: string | number;\n\n setRequestId(requestId: string | number) {\n this.requestId = requestId;\n }\n}\n"]}
|