@prmichaelsen/mcp-auth 7.2.0 → 7.3.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/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +2 -2
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/wrapper/config.d.ts +33 -4
- package/dist/wrapper/config.d.ts.map +1 -1
- package/dist/wrapper/index.d.ts +1 -1
- package/dist/wrapper/index.d.ts.map +1 -1
- package/dist/wrapper/index.js.map +1 -1
- package/dist/wrapper/instance-pool-manager.d.ts +3 -1
- package/dist/wrapper/instance-pool-manager.d.ts.map +1 -1
- package/dist/wrapper/instance-pool-manager.js +5 -4
- package/dist/wrapper/instance-pool-manager.js.map +2 -2
- package/dist/wrapper/server-wrapper.d.ts.map +1 -1
- package/dist/wrapper/server-wrapper.js +10 -8
- package/dist/wrapper/server-wrapper.js.map +2 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @packageDocumentation
|
|
11
11
|
*/
|
|
12
|
-
export { wrapServer, AuthenticatedServerWrapper, type ServerWrapperConfig, type MCPServerFactory, type NormalizedServerWrapperConfig, InstancePoolManager, ProgressManager, type ProgressCallback, type ProgressStreamMetrics } from './wrapper/index.js';
|
|
12
|
+
export { wrapServer, AuthenticatedServerWrapper, type ServerWrapperConfig, type MCPServerFactory, type MCPServerFactoryExtras, type NormalizedServerWrapperConfig, InstancePoolManager, ProgressManager, type ProgressCallback, type ProgressStreamMetrics } from './wrapper/index.js';
|
|
13
13
|
export { AuthenticatedMCPServer, type ServerConfig, type NormalizedServerConfig, withAuth, compose, withLogging, withRateLimit, withTimeout, withRetry, type Tool, AuthenticatedTool, createAuthenticatedTool, type AuthenticatedToolHandler } from './server/index.js';
|
|
14
14
|
export type { TransportType, RequestContext, AuthResult, TransportConfig, RateLimitConfig, LoggingConfig, MiddlewareConfig, InstancePoolConfig, PoolingConfig, Result, AsyncFunction, ToolHandler, Middleware, ProgressNotification, RequestExtra } from './types.js';
|
|
15
15
|
export type { AuthProvider, ResourceTokenResolver, AuthenticatedContext, AuthProviderConfig, TokenResolverConfig } from './auth/types.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,EACL,UAAU,EACV,0BAA0B,EAC1B,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,6BAA6B,EAClC,mBAAmB,EACnB,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAC;AAQ5B,OAAO,EACL,sBAAsB,EACtB,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC3B,QAAQ,EACR,OAAO,EACP,WAAW,EACX,aAAa,EACb,WAAW,EACX,SAAS,EACT,KAAK,IAAI,EACT,iBAAiB,EACjB,uBAAuB,EACvB,KAAK,wBAAwB,EAC9B,MAAM,mBAAmB,CAAC;AAM3B,YAAY,EACV,aAAa,EACb,cAAc,EACd,UAAU,EACV,eAAe,EACf,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,MAAM,EACN,aAAa,EACb,WAAW,EACX,UAAU,EACV,oBAAoB,EACpB,YAAY,EACb,MAAM,YAAY,CAAC;AAMpB,YAAY,EACV,YAAY,EACZ,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAG3D,OAAO,EACL,eAAe,EACf,KAAK,qBAAqB,EAC1B,mBAAmB,EACnB,KAAK,yBAAyB,EAC9B,eAAe,EACf,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EACf,gBAAgB,EAChB,KAAK,sBAAsB,EAC3B,gBAAgB,EAChB,KAAK,sBAAsB,EAC5B,MAAM,2BAA2B,CAAC;AAQnC,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EAEL,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,EAGpB,MAAM,EACN,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,kBAAkB,EAGlB,sBAAsB,EACtB,WAAW,EACX,sBAAsB,EACtB,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,kBAAkB,CAAC;AAG1B,YAAY,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAMlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,EACL,UAAU,EACV,0BAA0B,EAC1B,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,EAClC,mBAAmB,EACnB,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAC;AAQ5B,OAAO,EACL,sBAAsB,EACtB,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC3B,QAAQ,EACR,OAAO,EACP,WAAW,EACX,aAAa,EACb,WAAW,EACX,SAAS,EACT,KAAK,IAAI,EACT,iBAAiB,EACjB,uBAAuB,EACvB,KAAK,wBAAwB,EAC9B,MAAM,mBAAmB,CAAC;AAM3B,YAAY,EACV,aAAa,EACb,cAAc,EACd,UAAU,EACV,eAAe,EACf,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,MAAM,EACN,aAAa,EACb,WAAW,EACX,UAAU,EACV,oBAAoB,EACpB,YAAY,EACb,MAAM,YAAY,CAAC;AAMpB,YAAY,EACV,YAAY,EACZ,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAG3D,OAAO,EACL,eAAe,EACf,KAAK,qBAAqB,EAC1B,mBAAmB,EACnB,KAAK,yBAAyB,EAC9B,eAAe,EACf,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EACf,gBAAgB,EAChB,KAAK,sBAAsB,EAC3B,gBAAgB,EAChB,KAAK,sBAAsB,EAC5B,MAAM,2BAA2B,CAAC;AAQnC,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EAEL,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,EAGpB,MAAM,EACN,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,kBAAkB,EAGlB,sBAAsB,EACtB,WAAW,EACX,sBAAsB,EACtB,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,kBAAkB,CAAC;AAG1B,YAAY,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAMlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG"}
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @prmichaelsen/mcp-auth\n *\n * Authentication and multi-tenancy framework for MCP (Model Context Protocol) servers.\n *\n * Supports two complementary patterns:\n * 1. **Server Wrapping** - Wrap existing MCP servers without modification (MCP-level auth)\n * 2. **Tool-Level Auth** - Build new MCP servers with integrated auth\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// PATTERN 1: SERVER WRAPPING (MCP-Level Auth)\n// ============================================================================\n// Use this to wrap existing MCP servers without modifying them\n// Ideal for multi-tenant services that host multiple MCP servers\n\nexport {\n wrapServer,\n AuthenticatedServerWrapper,\n type ServerWrapperConfig,\n type MCPServerFactory,\n type NormalizedServerWrapperConfig,\n InstancePoolManager,\n ProgressManager,\n type ProgressCallback,\n type ProgressStreamMetrics\n} from './wrapper/index.js';\n\n// ============================================================================\n// PATTERN 2: TOOL-LEVEL AUTH\n// ============================================================================\n// Use this to build new MCP servers with integrated authentication\n// Provides fine-grained control over auth per tool\n\nexport {\n AuthenticatedMCPServer,\n type ServerConfig,\n type NormalizedServerConfig,\n withAuth,\n compose,\n withLogging,\n withRateLimit,\n withTimeout,\n withRetry,\n type Tool,\n AuthenticatedTool,\n createAuthenticatedTool,\n type AuthenticatedToolHandler\n} from './server/index.js';\n\n// ============================================================================\n// SHARED: CORE TYPES\n// ============================================================================\n\nexport type {\n TransportType,\n RequestContext,\n AuthResult,\n TransportConfig,\n RateLimitConfig,\n LoggingConfig,\n MiddlewareConfig,\n InstancePoolConfig,\n PoolingConfig,\n Result,\n AsyncFunction,\n ToolHandler,\n Middleware,\n ProgressNotification,\n RequestExtra\n} from './types.js';\n\n// ============================================================================\n// SHARED: AUTHENTICATION\n// ============================================================================\n\nexport type {\n AuthProvider,\n ResourceTokenResolver,\n AuthenticatedContext,\n AuthProviderConfig,\n TokenResolverConfig\n} from './auth/types.js';\n\nexport { BaseAuthProvider } from './auth/base-provider.js';\n\n// Providers\nexport {\n EnvAuthProvider,\n type EnvAuthProviderConfig,\n SimpleTokenResolver,\n type SimpleTokenResolverConfig,\n JWTAuthProvider,\n type JWTAuthProviderConfig,\n type JWTPayload,\n JWTTokenResolver,\n type JWTTokenResolverConfig,\n APITokenResolver,\n type APITokenResolverConfig\n} from './auth/providers/index.js';\n\n// ============================================================================\n// TENANT MANAGER INTEGRATION\n// ============================================================================\n// Standard interfaces for tenant manager APIs\n// Helps tenant platforms provide consistent APIs for MCP servers\n\nexport {\n type TenantAPIErrorResponse,\n type CredentialsAPIResponse,\n type CredentialsAPIHeaders,\n type TenantManagerAPI,\n TenantAPIStatusCode,\n TenantAPIErrorCode,\n createTenantAPIError,\n TenantAPIErrors\n} from './tenant/index.js';\n\n// ============================================================================\n// SHARED: UTILITIES\n// ============================================================================\n\nexport {\n // Errors\n MCPAuthError,\n AuthenticationError,\n TokenResolutionError,\n InvalidTokenError,\n MissingCredentialsError,\n ConfigurationError,\n RateLimitError,\n ServerPoolError,\n TransportError,\n ValidationError,\n isMCPAuthError,\n isAuthenticationError,\n isTokenResolutionError,\n isRateLimitError,\n formatErrorForClient,\n \n // Logger\n Logger,\n LogLevel,\n defaultLogger,\n createLogger,\n sanitizeForLogging,\n \n // Validation\n validateNonEmptyString,\n validateUrl,\n validatePositiveNumber,\n validatePort,\n validateEnum,\n validateObject,\n validateFunction,\n validateRequiredFields,\n validateTransportConfig,\n validateRateLimitConfig,\n validateLoggingConfig,\n validatePoolingConfig,\n sanitizeString,\n validateUserId,\n validateResourceType,\n validateAccessToken\n} from './utils/index.js';\n\n// Re-export types for convenience\nexport type { LogEntry } from './utils/logger.js';\n\n// ============================================================================\n// USAGE EXAMPLES\n// ============================================================================\n\n/**\n * @example Server Wrapping Pattern (MCP-Level Auth)\n * ```typescript\n * import { wrapServer, JWTAuthProvider, DatabaseTokenResolver } from '@prmichaelsen/mcp-auth';\n * import { createServer as createInstagramServer } from '@prmichaelsen/instagram-mcp';\n *\n * const wrapped = wrapServer({\n * serverFactory: (accessToken, userId) => createInstagramServer(accessToken, userId),\n * authProvider: new JWTAuthProvider({ jwtSecret: process.env.JWT_SECRET }),\n * tokenResolver: new DatabaseTokenResolver({ database: {...} }),\n * resourceType: 'instagram',\n * transport: { type: 'sse', port: 3000 }\n * });\n *\n * await wrapped.start();\n * ```\n *\n * @example Tool-Level Auth Pattern\n * ```typescript\n * import { AuthenticatedMCPServer, withAuth, EnvAuthProvider } from '@prmichaelsen/mcp-auth';\n *\n * const server = new AuthenticatedMCPServer({\n * name: 'my-server',\n * authProvider: new EnvAuthProvider(),\n * tokenResolver: new SimpleTokenResolver({ tokenEnvVar: 'API_TOKEN' }),\n * resourceType: 'myapi',\n * transport: { type: 'stdio' }\n * });\n *\n * server.registerTool('get_data', withAuth(async (args, accessToken, userId) => {\n * const client = new MyAPIClient(accessToken);\n * return client.getData(args);\n * }));\n *\n * await server.start();\n * ```\n */\n"],
|
|
5
|
-
"mappings": "AAkBA;AAAA,EACE;AAAA,EACA;AAAA,
|
|
4
|
+
"sourcesContent": ["/**\n * @prmichaelsen/mcp-auth\n *\n * Authentication and multi-tenancy framework for MCP (Model Context Protocol) servers.\n *\n * Supports two complementary patterns:\n * 1. **Server Wrapping** - Wrap existing MCP servers without modification (MCP-level auth)\n * 2. **Tool-Level Auth** - Build new MCP servers with integrated auth\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// PATTERN 1: SERVER WRAPPING (MCP-Level Auth)\n// ============================================================================\n// Use this to wrap existing MCP servers without modifying them\n// Ideal for multi-tenant services that host multiple MCP servers\n\nexport {\n wrapServer,\n AuthenticatedServerWrapper,\n type ServerWrapperConfig,\n type MCPServerFactory,\n type MCPServerFactoryExtras,\n type NormalizedServerWrapperConfig,\n InstancePoolManager,\n ProgressManager,\n type ProgressCallback,\n type ProgressStreamMetrics\n} from './wrapper/index.js';\n\n// ============================================================================\n// PATTERN 2: TOOL-LEVEL AUTH\n// ============================================================================\n// Use this to build new MCP servers with integrated authentication\n// Provides fine-grained control over auth per tool\n\nexport {\n AuthenticatedMCPServer,\n type ServerConfig,\n type NormalizedServerConfig,\n withAuth,\n compose,\n withLogging,\n withRateLimit,\n withTimeout,\n withRetry,\n type Tool,\n AuthenticatedTool,\n createAuthenticatedTool,\n type AuthenticatedToolHandler\n} from './server/index.js';\n\n// ============================================================================\n// SHARED: CORE TYPES\n// ============================================================================\n\nexport type {\n TransportType,\n RequestContext,\n AuthResult,\n TransportConfig,\n RateLimitConfig,\n LoggingConfig,\n MiddlewareConfig,\n InstancePoolConfig,\n PoolingConfig,\n Result,\n AsyncFunction,\n ToolHandler,\n Middleware,\n ProgressNotification,\n RequestExtra\n} from './types.js';\n\n// ============================================================================\n// SHARED: AUTHENTICATION\n// ============================================================================\n\nexport type {\n AuthProvider,\n ResourceTokenResolver,\n AuthenticatedContext,\n AuthProviderConfig,\n TokenResolverConfig\n} from './auth/types.js';\n\nexport { BaseAuthProvider } from './auth/base-provider.js';\n\n// Providers\nexport {\n EnvAuthProvider,\n type EnvAuthProviderConfig,\n SimpleTokenResolver,\n type SimpleTokenResolverConfig,\n JWTAuthProvider,\n type JWTAuthProviderConfig,\n type JWTPayload,\n JWTTokenResolver,\n type JWTTokenResolverConfig,\n APITokenResolver,\n type APITokenResolverConfig\n} from './auth/providers/index.js';\n\n// ============================================================================\n// TENANT MANAGER INTEGRATION\n// ============================================================================\n// Standard interfaces for tenant manager APIs\n// Helps tenant platforms provide consistent APIs for MCP servers\n\nexport {\n type TenantAPIErrorResponse,\n type CredentialsAPIResponse,\n type CredentialsAPIHeaders,\n type TenantManagerAPI,\n TenantAPIStatusCode,\n TenantAPIErrorCode,\n createTenantAPIError,\n TenantAPIErrors\n} from './tenant/index.js';\n\n// ============================================================================\n// SHARED: UTILITIES\n// ============================================================================\n\nexport {\n // Errors\n MCPAuthError,\n AuthenticationError,\n TokenResolutionError,\n InvalidTokenError,\n MissingCredentialsError,\n ConfigurationError,\n RateLimitError,\n ServerPoolError,\n TransportError,\n ValidationError,\n isMCPAuthError,\n isAuthenticationError,\n isTokenResolutionError,\n isRateLimitError,\n formatErrorForClient,\n \n // Logger\n Logger,\n LogLevel,\n defaultLogger,\n createLogger,\n sanitizeForLogging,\n \n // Validation\n validateNonEmptyString,\n validateUrl,\n validatePositiveNumber,\n validatePort,\n validateEnum,\n validateObject,\n validateFunction,\n validateRequiredFields,\n validateTransportConfig,\n validateRateLimitConfig,\n validateLoggingConfig,\n validatePoolingConfig,\n sanitizeString,\n validateUserId,\n validateResourceType,\n validateAccessToken\n} from './utils/index.js';\n\n// Re-export types for convenience\nexport type { LogEntry } from './utils/logger.js';\n\n// ============================================================================\n// USAGE EXAMPLES\n// ============================================================================\n\n/**\n * @example Server Wrapping Pattern (MCP-Level Auth)\n * ```typescript\n * import { wrapServer, JWTAuthProvider, DatabaseTokenResolver } from '@prmichaelsen/mcp-auth';\n * import { createServer as createInstagramServer } from '@prmichaelsen/instagram-mcp';\n *\n * const wrapped = wrapServer({\n * serverFactory: (accessToken, userId) => createInstagramServer(accessToken, userId),\n * authProvider: new JWTAuthProvider({ jwtSecret: process.env.JWT_SECRET }),\n * tokenResolver: new DatabaseTokenResolver({ database: {...} }),\n * resourceType: 'instagram',\n * transport: { type: 'sse', port: 3000 }\n * });\n *\n * await wrapped.start();\n * ```\n *\n * @example Tool-Level Auth Pattern\n * ```typescript\n * import { AuthenticatedMCPServer, withAuth, EnvAuthProvider } from '@prmichaelsen/mcp-auth';\n *\n * const server = new AuthenticatedMCPServer({\n * name: 'my-server',\n * authProvider: new EnvAuthProvider(),\n * tokenResolver: new SimpleTokenResolver({ tokenEnvVar: 'API_TOKEN' }),\n * resourceType: 'myapi',\n * transport: { type: 'stdio' }\n * });\n *\n * server.registerTool('get_data', withAuth(async (args, accessToken, userId) => {\n * const client = new MyAPIClient(accessToken);\n * return client.getData(args);\n * }));\n *\n * await server.start();\n * ```\n */\n"],
|
|
5
|
+
"mappings": "AAkBA;AAAA,EACE;AAAA,EACA;AAAA,EAKA;AAAA,EACA;AAAA,OAGK;AAQP;AAAA,EACE;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,OAEK;AAoCP,SAAS,wBAAwB;AAGjC;AAAA,EACE;AAAA,EAEA;AAAA,EAEA;AAAA,EAGA;AAAA,EAEA;AAAA,OAEK;AAQP;AAAA,EAKE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAMP;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -71,6 +71,14 @@ export interface RequestContext {
|
|
|
71
71
|
* Optional: Request ID for tracing
|
|
72
72
|
*/
|
|
73
73
|
requestId?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Optional: URL query parameters from the incoming request
|
|
76
|
+
*
|
|
77
|
+
* Populated automatically for HTTP/SSE transports.
|
|
78
|
+
* Allows passing request-level context (e.g., feature flags, mode selectors)
|
|
79
|
+
* through to the server factory via extras.
|
|
80
|
+
*/
|
|
81
|
+
query?: Record<string, string | string[] | undefined>;
|
|
74
82
|
}
|
|
75
83
|
/**
|
|
76
84
|
* Authentication result returned by auth providers
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAErD;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;IAE/B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEhC;;OAEG;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IAExD;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEnC;;OAEG;IACH,SAAS,EAAE,aAAa,CAAC;IAEzB;;OAEG;IACH,SAAS,EAAE,IAAI,CAAC;IAEhB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/wrapper/config.d.ts
CHANGED
|
@@ -6,6 +6,14 @@
|
|
|
6
6
|
import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
7
7
|
import type { AuthProvider, ResourceTokenResolver } from '../auth/types.js';
|
|
8
8
|
import type { TransportConfig, MiddlewareConfig, InstancePoolConfig } from '../types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Extra context passed from the HTTP request to the server factory.
|
|
11
|
+
*
|
|
12
|
+
* Populated from URL query parameters on HTTP/SSE transports.
|
|
13
|
+
* Consumers can use this for any request-level context — ghost mode,
|
|
14
|
+
* feature flags, conversation IDs, etc.
|
|
15
|
+
*/
|
|
16
|
+
export type MCPServerFactoryExtras = Record<string, string | string[] | undefined>;
|
|
9
17
|
/**
|
|
10
18
|
* MCP Server Factory Function
|
|
11
19
|
*
|
|
@@ -15,9 +23,10 @@ import type { TransportConfig, MiddlewareConfig, InstancePoolConfig } from '../t
|
|
|
15
23
|
*
|
|
16
24
|
* @param accessToken - Resource-specific access token (e.g., Instagram, GitHub token)
|
|
17
25
|
* @param userId - Authenticated user identifier
|
|
26
|
+
* @param extras - Optional request-level context from URL query parameters
|
|
18
27
|
* @returns Configured MCP server instance
|
|
19
28
|
*
|
|
20
|
-
* @example
|
|
29
|
+
* @example Basic usage
|
|
21
30
|
* ```typescript
|
|
22
31
|
* export function createServer(accessToken: string, userId?: string): Server {
|
|
23
32
|
* const server = new Server({ name: 'my-server', version: '1.0.0' });
|
|
@@ -26,8 +35,18 @@ import type { TransportConfig, MiddlewareConfig, InstancePoolConfig } from '../t
|
|
|
26
35
|
* return server;
|
|
27
36
|
* }
|
|
28
37
|
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example With extras (e.g., ghost mode)
|
|
40
|
+
* ```typescript
|
|
41
|
+
* serverFactory: (accessToken, userId, extras) => createServer(accessToken, userId, {
|
|
42
|
+
* ghostMode: extras?.ghost_owner ? {
|
|
43
|
+
* owner_user_id: extras.ghost_owner as string,
|
|
44
|
+
* accessor_user_id: userId,
|
|
45
|
+
* } : undefined,
|
|
46
|
+
* })
|
|
47
|
+
* ```
|
|
29
48
|
*/
|
|
30
|
-
export type MCPServerFactory = (accessToken: string, userId: string) => Server | Promise<Server>;
|
|
49
|
+
export type MCPServerFactory = (accessToken: string, userId: string, extras?: MCPServerFactoryExtras) => Server | Promise<Server>;
|
|
31
50
|
/**
|
|
32
51
|
* Server wrapper configuration
|
|
33
52
|
*
|
|
@@ -40,9 +59,19 @@ export interface ServerWrapperConfig {
|
|
|
40
59
|
* This function will be called for each request (ephemeral instances)
|
|
41
60
|
* or reused from pool (if pooling is enabled).
|
|
42
61
|
*
|
|
43
|
-
*
|
|
62
|
+
* The optional third parameter `extras` contains URL query parameters
|
|
63
|
+
* from the incoming HTTP request, enabling request-level context.
|
|
64
|
+
*
|
|
65
|
+
* @example Basic
|
|
66
|
+
* ```typescript
|
|
67
|
+
* serverFactory: (accessToken, userId) => createServer(accessToken, userId)
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* @example With extras
|
|
44
71
|
* ```typescript
|
|
45
|
-
* serverFactory: (accessToken, userId) =>
|
|
72
|
+
* serverFactory: (accessToken, userId, extras) => createServer(accessToken, userId, {
|
|
73
|
+
* ghostMode: extras?.ghost_owner ? { owner_user_id: extras.ghost_owner as string } : undefined,
|
|
74
|
+
* })
|
|
46
75
|
* ```
|
|
47
76
|
*/
|
|
48
77
|
serverFactory: MCPServerFactory;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/wrapper/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEzF
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/wrapper/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEzF;;;;;;GAMG;AACH,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;AAEnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,sBAAsB,KAC5B,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAE9B;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,aAAa,EAAE,gBAAgB,CAAC;IAEhC;;;;;;;;;OASG;IACH,YAAY,EAAE,YAAY,CAAC;IAE3B;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,aAAa,CAAC,EAAE,qBAAqB,CAAC;IAEtC;;;;;;OAMG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,SAAS,EAAE,eAAe,CAAC;IAE3B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAE9B;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IAEtC;;;;;;;;;;;;;;OAcG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAElC;;;;;OAKG;IACH,OAAO,CAAC,EAAE;QACR;;;WAGG;QACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAE3B;;;WAGG;QACH,aAAa,CAAC,EAAE,MAAM,CAAC;QAEvB;;;WAGG;QACH,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IAEF;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,6BAA8B,SAAQ,QAAQ,CAAC,IAAI,CAAC,mBAAmB,EAAE,YAAY,GAAG,SAAS,GAAG,eAAe,GAAG,cAAc,CAAC,CAAC;IACrJ,aAAa,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAC5C,UAAU,EAAE,gBAAgB,CAAC;IAC7B,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACxC,OAAO,EAAE;QACP,iBAAiB,EAAE,MAAM,CAAC;QAC1B,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;CACH"}
|
package/dist/wrapper/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export { wrapServer } from './server-wrapper.js';
|
|
5
5
|
export { AuthenticatedServerWrapper } from './server-wrapper.js';
|
|
6
|
-
export type { ServerWrapperConfig, NormalizedServerWrapperConfig, MCPServerFactory } from './config.js';
|
|
6
|
+
export type { ServerWrapperConfig, NormalizedServerWrapperConfig, MCPServerFactory, MCPServerFactoryExtras } from './config.js';
|
|
7
7
|
/**
|
|
8
8
|
* Instance pool manager exports
|
|
9
9
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/wrapper/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,YAAY,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/wrapper/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,YAAY,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAEhI;;GAEG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE;;GAEG;AACH,OAAO,EAAE,eAAe,EAAE,KAAK,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACpF,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/wrapper/index.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Server wrapper exports\n */\n\nexport { wrapServer } from './server-wrapper.js';\nexport { AuthenticatedServerWrapper } from './server-wrapper.js';\nexport type { ServerWrapperConfig, NormalizedServerWrapperConfig, MCPServerFactory } from './config.js';\n\n/**\n * Instance pool manager exports\n */\nexport { InstancePoolManager } from './instance-pool-manager.js';\n\n/**\n * Progress manager exports\n */\nexport { ProgressManager, type ProgressStreamMetrics } from './progress-manager.js';\nexport type { ProgressCallback } from './progress-manager.js';\n"],
|
|
4
|
+
"sourcesContent": ["/**\n * Server wrapper exports\n */\n\nexport { wrapServer } from './server-wrapper.js';\nexport { AuthenticatedServerWrapper } from './server-wrapper.js';\nexport type { ServerWrapperConfig, NormalizedServerWrapperConfig, MCPServerFactory, MCPServerFactoryExtras } from './config.js';\n\n/**\n * Instance pool manager exports\n */\nexport { InstancePoolManager } from './instance-pool-manager.js';\n\n/**\n * Progress manager exports\n */\nexport { ProgressManager, type ProgressStreamMetrics } from './progress-manager.js';\nexport type { ProgressCallback } from './progress-manager.js';\n"],
|
|
5
5
|
"mappings": "AAIA,SAAS,kBAAkB;AAC3B,SAAS,kCAAkC;AAM3C,SAAS,2BAA2B;AAKpC,SAAS,uBAAmD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
8
8
|
import type { InstancePoolConfig } from '../types.js';
|
|
9
9
|
import type { Logger } from '../utils/logger.js';
|
|
10
|
+
import type { MCPServerFactoryExtras } from './config.js';
|
|
10
11
|
/**
|
|
11
12
|
* Instance Pool Manager
|
|
12
13
|
*
|
|
@@ -47,9 +48,10 @@ export declare class InstancePoolManager {
|
|
|
47
48
|
* @param userId - User identifier
|
|
48
49
|
* @param accessToken - Access token for the user
|
|
49
50
|
* @param factory - Factory function to create new server instances
|
|
51
|
+
* @param extras - Optional request-level context forwarded to the factory
|
|
50
52
|
* @returns Server instance (existing or newly created)
|
|
51
53
|
*/
|
|
52
|
-
getInstance(userId: string, accessToken: string, factory: (accessToken: string, userId: string) => Server | Promise<Server
|
|
54
|
+
getInstance(userId: string, accessToken: string, factory: (accessToken: string, userId: string, extras?: MCPServerFactoryExtras) => Server | Promise<Server>, extras?: MCPServerFactoryExtras): Promise<Server>;
|
|
53
55
|
/**
|
|
54
56
|
* Check if an instance is still valid
|
|
55
57
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instance-pool-manager.d.ts","sourceRoot":"","sources":["../../src/wrapper/instance-pool-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"instance-pool-manager.d.ts","sourceRoot":"","sources":["../../src/wrapper/instance-pool-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAsB1D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAC,CAAiB;gBAE1B,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM;IAatD;;;;;;;;;;;OAWG;IACG,WAAW,CACf,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,sBAAsB,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,EAC3G,MAAM,CAAC,EAAE,sBAAsB,GAC9B,OAAO,CAAC,MAAM,CAAC;IAgDlB;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO;IAsBf;;;;;OAKG;YACW,sBAAsB;IAqBpC;;;;;;;OAOG;YACW,cAAc;IAqB5B;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAYzB;;;;;OAKG;YACW,uBAAuB;IAsBrC;;;;;OAKG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB/B;;;;;;OAMG;IACH,QAAQ;;;;;;;;;;;CAcT"}
|
|
@@ -16,16 +16,17 @@ class InstancePoolManager {
|
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* Get or create a server instance for a user
|
|
19
|
-
*
|
|
19
|
+
*
|
|
20
20
|
* If a valid instance exists for the user, it will be reused.
|
|
21
21
|
* Otherwise, a new instance will be created using the factory function.
|
|
22
|
-
*
|
|
22
|
+
*
|
|
23
23
|
* @param userId - User identifier
|
|
24
24
|
* @param accessToken - Access token for the user
|
|
25
25
|
* @param factory - Factory function to create new server instances
|
|
26
|
+
* @param extras - Optional request-level context forwarded to the factory
|
|
26
27
|
* @returns Server instance (existing or newly created)
|
|
27
28
|
*/
|
|
28
|
-
async getInstance(userId, accessToken, factory) {
|
|
29
|
+
async getInstance(userId, accessToken, factory, extras) {
|
|
29
30
|
const existing = this.instances.get(userId);
|
|
30
31
|
if (existing && this.isValid(existing)) {
|
|
31
32
|
this.logger.debug("Reusing pooled instance", { userId });
|
|
@@ -48,7 +49,7 @@ class InstancePoolManager {
|
|
|
48
49
|
await this.evictLeastRecentlyUsed();
|
|
49
50
|
}
|
|
50
51
|
this.logger.debug("Creating new pooled instance", { userId });
|
|
51
|
-
const server = await factory(accessToken, userId);
|
|
52
|
+
const server = await factory(accessToken, userId, extras);
|
|
52
53
|
this.instances.set(userId, {
|
|
53
54
|
server,
|
|
54
55
|
userId,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/wrapper/instance-pool-manager.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Instance Pool Manager\n * \n * Manages lifecycle of pooled server instances with configurable\n * size limits, idle timeouts, and maximum lifetimes.\n */\n\nimport type { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport type { InstancePoolConfig } from '../types.js';\nimport type { Logger } from '../utils/logger.js';\n\n/**\n * Metadata for a pooled server instance\n */\ninterface InstanceMetadata {\n /** The MCP server instance */\n server: Server;\n \n /** User ID this instance belongs to */\n userId: string;\n \n /** Access token used to create this instance */\n accessToken: string;\n \n /** Timestamp when instance was created */\n createdAt: number;\n \n /** Timestamp when instance was last used */\n lastUsed: number;\n}\n\n/**\n * Instance Pool Manager\n * \n * Manages a pool of server instances with automatic lifecycle management:\n * - Reuses instances for the same user\n * - Enforces maximum pool size with LRU eviction\n * - Automatically closes idle instances\n * - Forces refresh of old instances\n * - Periodic cleanup of expired instances\n * \n * @example\n * ```typescript\n * const poolManager = new InstancePoolManager({\n * maxSize: 10,\n * idleTimeout: 300000,\n * maxLifetime: 3600000\n * }, logger);\n * \n * const server = await poolManager.getInstance(\n * 'user123',\n * 'token456',\n * (token, userId) => createMyServer(token, userId)\n * );\n * ```\n */\nexport class InstancePoolManager {\n private instances: Map<string, InstanceMetadata>;\n private config: InstancePoolConfig;\n private logger: Logger;\n private cleanupTimer?: NodeJS.Timeout;\n \n constructor(config: InstancePoolConfig, logger: Logger) {\n this.instances = new Map();\n this.config = config;\n this.logger = logger;\n this.startCleanupTimer();\n \n this.logger.info('InstancePoolManager initialized', {\n maxSize: config.maxSize,\n idleTimeout: config.idleTimeout,\n maxLifetime: config.maxLifetime\n });\n }\n \n /**\n * Get or create a server instance for a user\n
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/**\n * Instance Pool Manager\n * \n * Manages lifecycle of pooled server instances with configurable\n * size limits, idle timeouts, and maximum lifetimes.\n */\n\nimport type { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport type { InstancePoolConfig } from '../types.js';\nimport type { Logger } from '../utils/logger.js';\nimport type { MCPServerFactoryExtras } from './config.js';\n\n/**\n * Metadata for a pooled server instance\n */\ninterface InstanceMetadata {\n /** The MCP server instance */\n server: Server;\n \n /** User ID this instance belongs to */\n userId: string;\n \n /** Access token used to create this instance */\n accessToken: string;\n \n /** Timestamp when instance was created */\n createdAt: number;\n \n /** Timestamp when instance was last used */\n lastUsed: number;\n}\n\n/**\n * Instance Pool Manager\n * \n * Manages a pool of server instances with automatic lifecycle management:\n * - Reuses instances for the same user\n * - Enforces maximum pool size with LRU eviction\n * - Automatically closes idle instances\n * - Forces refresh of old instances\n * - Periodic cleanup of expired instances\n * \n * @example\n * ```typescript\n * const poolManager = new InstancePoolManager({\n * maxSize: 10,\n * idleTimeout: 300000,\n * maxLifetime: 3600000\n * }, logger);\n * \n * const server = await poolManager.getInstance(\n * 'user123',\n * 'token456',\n * (token, userId) => createMyServer(token, userId)\n * );\n * ```\n */\nexport class InstancePoolManager {\n private instances: Map<string, InstanceMetadata>;\n private config: InstancePoolConfig;\n private logger: Logger;\n private cleanupTimer?: NodeJS.Timeout;\n \n constructor(config: InstancePoolConfig, logger: Logger) {\n this.instances = new Map();\n this.config = config;\n this.logger = logger;\n this.startCleanupTimer();\n \n this.logger.info('InstancePoolManager initialized', {\n maxSize: config.maxSize,\n idleTimeout: config.idleTimeout,\n maxLifetime: config.maxLifetime\n });\n }\n \n /**\n * Get or create a server instance for a user\n *\n * If a valid instance exists for the user, it will be reused.\n * Otherwise, a new instance will be created using the factory function.\n *\n * @param userId - User identifier\n * @param accessToken - Access token for the user\n * @param factory - Factory function to create new server instances\n * @param extras - Optional request-level context forwarded to the factory\n * @returns Server instance (existing or newly created)\n */\n async getInstance(\n userId: string,\n accessToken: string,\n factory: (accessToken: string, userId: string, extras?: MCPServerFactoryExtras) => Server | Promise<Server>,\n extras?: MCPServerFactoryExtras\n ): Promise<Server> {\n // Check if instance exists and is valid\n const existing = this.instances.get(userId);\n if (existing && this.isValid(existing)) {\n this.logger.debug('Reusing pooled instance', { userId });\n existing.lastUsed = Date.now();\n return existing.server;\n }\n \n // Remove invalid instance if exists\n if (existing) {\n this.logger.debug('Removing invalid instance', { \n userId,\n age: Date.now() - existing.createdAt,\n idle: Date.now() - existing.lastUsed\n });\n await this.removeInstance(userId);\n }\n \n // Check pool size limit\n if (this.instances.size >= this.config.maxSize) {\n this.logger.debug('Pool full, evicting LRU instance', { \n size: this.instances.size,\n maxSize: this.config.maxSize\n });\n await this.evictLeastRecentlyUsed();\n }\n \n // Create new instance\n this.logger.debug('Creating new pooled instance', { userId });\n const server = await factory(accessToken, userId, extras);\n \n this.instances.set(userId, {\n server,\n userId,\n accessToken,\n createdAt: Date.now(),\n lastUsed: Date.now()\n });\n \n this.logger.info('Pooled instance created', {\n userId,\n poolSize: this.instances.size\n });\n \n return server;\n }\n \n /**\n * Check if an instance is still valid\n * \n * An instance is valid if:\n * - It hasn't exceeded its maximum lifetime\n * - It hasn't been idle for too long\n * \n * @param instance - Instance metadata to check\n * @returns true if instance is valid, false otherwise\n */\n private isValid(instance: InstanceMetadata): boolean {\n const now = Date.now();\n const age = now - instance.createdAt;\n const idle = now - instance.lastUsed;\n \n const valid = age < this.config.maxLifetime && \n idle < this.config.idleTimeout;\n \n if (!valid) {\n this.logger.debug('Instance invalid', {\n userId: instance.userId,\n age,\n idle,\n maxLifetime: this.config.maxLifetime,\n idleTimeout: this.config.idleTimeout,\n reason: age >= this.config.maxLifetime ? 'max lifetime exceeded' : 'idle timeout exceeded'\n });\n }\n \n return valid;\n }\n \n /**\n * Evict the least recently used instance\n * \n * Finds the instance with the oldest lastUsed timestamp\n * and removes it from the pool.\n */\n private async evictLeastRecentlyUsed(): Promise<void> {\n let oldestUserId: string | null = null;\n let oldestTime = Date.now();\n \n for (const [userId, instance] of this.instances.entries()) {\n if (instance.lastUsed < oldestTime) {\n oldestTime = instance.lastUsed;\n oldestUserId = userId;\n }\n }\n \n if (oldestUserId) {\n this.logger.info('Evicting LRU instance', { \n userId: oldestUserId,\n lastUsed: new Date(oldestTime).toISOString(),\n idleTime: Date.now() - oldestTime\n });\n await this.removeInstance(oldestUserId);\n }\n }\n \n /**\n * Remove an instance from the pool\n * \n * Closes the server instance (if it has a close method)\n * and removes it from the pool.\n * \n * @param userId - User ID of the instance to remove\n */\n private async removeInstance(userId: string): Promise<void> {\n const instance = this.instances.get(userId);\n if (instance) {\n try {\n // Close server if it has a close method\n if ('close' in instance.server && typeof instance.server.close === 'function') {\n await instance.server.close();\n this.logger.debug('Server instance closed', { userId });\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.logger.error(`Error closing instance for user ${userId}: ${errorMessage}`);\n }\n this.instances.delete(userId);\n this.logger.debug('Instance removed from pool', {\n userId,\n poolSize: this.instances.size\n });\n }\n }\n \n /**\n * Start periodic cleanup timer\n * \n * Runs cleanup every minute to remove expired instances.\n */\n private startCleanupTimer(): void {\n // Run cleanup every minute\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredInstances();\n }, 60000);\n \n // Don't keep the process alive just for this timer\n if (this.cleanupTimer.unref) {\n this.cleanupTimer.unref();\n }\n }\n \n /**\n * Clean up expired instances\n * \n * Removes all instances that are no longer valid\n * (exceeded max lifetime or idle timeout).\n */\n private async cleanupExpiredInstances(): Promise<void> {\n const now = Date.now();\n const toRemove: string[] = [];\n \n for (const [userId, instance] of this.instances.entries()) {\n if (!this.isValid(instance)) {\n toRemove.push(userId);\n }\n }\n \n if (toRemove.length > 0) {\n this.logger.info('Cleaning up expired instances', { \n count: toRemove.length,\n userIds: toRemove\n });\n \n for (const userId of toRemove) {\n await this.removeInstance(userId);\n }\n }\n }\n \n /**\n * Close all pooled instances\n * \n * Closes all server instances and clears the pool.\n * Should be called when shutting down the server.\n */\n async closeAll(): Promise<void> {\n this.logger.info('Closing all pooled instances', { \n count: this.instances.size \n });\n \n // Stop cleanup timer\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n \n // Close all instances\n const userIds = Array.from(this.instances.keys());\n for (const userId of userIds) {\n await this.removeInstance(userId);\n }\n \n this.logger.info('All pooled instances closed');\n }\n \n /**\n * Get pool statistics\n * \n * Returns current state of the pool for monitoring and debugging.\n * \n * @returns Pool statistics including size and instance details\n */\n getStats() {\n const now = Date.now();\n return {\n size: this.instances.size,\n maxSize: this.config.maxSize,\n instances: Array.from(this.instances.values()).map(i => ({\n userId: i.userId,\n age: now - i.createdAt,\n idle: now - i.lastUsed,\n createdAt: new Date(i.createdAt).toISOString(),\n lastUsed: new Date(i.lastUsed).toISOString()\n }))\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-wrapper.d.ts","sourceRoot":"","sources":["../../src/wrapper/server-wrapper.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,mBAAmB,
|
|
1
|
+
{"version":3,"file":"server-wrapper.d.ts","sourceRoot":"","sources":["../../src/wrapper/server-wrapper.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,mBAAmB,EAAyD,MAAM,aAAa,CAAC;AA+B9G;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,0BAA0B;IACrC,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,WAAW,CAAC,CAAsB;IAC1C,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,YAAY,CAAC,CAAiB;IACtC,OAAO,CAAC,gBAAgB,CAA2C;IACnE,OAAO,CAAC,eAAe,CAAmB;IAC1C,OAAO,CAAC,eAAe,CAAC,CAAiB;gBAE7B,MAAM,EAAE,mBAAmB;IA2CvC;;OAEG;IACH,OAAO,CAAC,cAAc;IAwDtB;;OAEG;IACH,OAAO,CAAC,eAAe;IAyBvB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkD5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAuD3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAK5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAI1B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAK5B;;;OAGG;YACW,gBAAgB;IAsI9B;;OAEG;YACW,iBAAiB;IAW/B;;OAEG;YACW,uBAAuB;IA2DrC;;OAEG;YACW,mBAAmB;IAuBjC;;OAEG;IACH,OAAO,CAAC,eAAe;IAqCvB;;OAEG;YACW,mBAAmB;IAyBjC;;OAEG;YACW,iBAAiB;IA4N/B;;OAEG;YACW,kBAAkB;IAUhC;;OAEG;IACH,YAAY,IAAI;QACd,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,KAAK,CAAC;YACf,MAAM,EAAE,MAAM,CAAC;YACf,SAAS,EAAE,MAAM,CAAC;YAClB,QAAQ,EAAE,MAAM,CAAC;YACjB,GAAG,EAAE,MAAM,CAAC;YACZ,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC,CAAC;KACJ;IAgBD;;OAEG;IACH,eAAe,IAAI,OAAO;CAG3B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,mBAAmB,GAAG,0BAA0B,CAElF"}
|
|
@@ -281,7 +281,7 @@ class AuthenticatedServerWrapper {
|
|
|
281
281
|
});
|
|
282
282
|
requestLogger.debug("Progress token extracted and stream registered", { userId, progressToken });
|
|
283
283
|
}
|
|
284
|
-
const server = await this.getServerInstance(userId, accessToken);
|
|
284
|
+
const server = await this.getServerInstance(userId, accessToken, context.query);
|
|
285
285
|
if (progressToken) {
|
|
286
286
|
const originalNotification = server.notification?.bind(server);
|
|
287
287
|
if (originalNotification) {
|
|
@@ -333,22 +333,23 @@ class AuthenticatedServerWrapper {
|
|
|
333
333
|
/**
|
|
334
334
|
* Get server instance (ephemeral or from pool)
|
|
335
335
|
*/
|
|
336
|
-
async getServerInstance(userId, accessToken) {
|
|
336
|
+
async getServerInstance(userId, accessToken, extras) {
|
|
337
337
|
if (this.config.instanceMode === "ephemeral") {
|
|
338
338
|
this.logger.debug("Creating ephemeral server instance", { userId });
|
|
339
|
-
return await this.config.serverFactory(accessToken, userId);
|
|
339
|
+
return await this.config.serverFactory(accessToken, userId, extras);
|
|
340
340
|
}
|
|
341
|
-
return await this.getPooledServerInstance(userId, accessToken);
|
|
341
|
+
return await this.getPooledServerInstance(userId, accessToken, extras);
|
|
342
342
|
}
|
|
343
343
|
/**
|
|
344
344
|
* Get or create pooled server instance
|
|
345
345
|
*/
|
|
346
|
-
async getPooledServerInstance(userId, accessToken) {
|
|
346
|
+
async getPooledServerInstance(userId, accessToken, extras) {
|
|
347
347
|
if (this.poolManager) {
|
|
348
348
|
return await this.poolManager.getInstance(
|
|
349
349
|
userId,
|
|
350
350
|
accessToken,
|
|
351
|
-
this.config.serverFactory
|
|
351
|
+
this.config.serverFactory,
|
|
352
|
+
extras
|
|
352
353
|
);
|
|
353
354
|
}
|
|
354
355
|
if (this.serverPool.has(userId)) {
|
|
@@ -371,7 +372,7 @@ class AuthenticatedServerWrapper {
|
|
|
371
372
|
await this.evictOldestInstance();
|
|
372
373
|
}
|
|
373
374
|
this.logger.info("Creating new pooled server instance", { userId });
|
|
374
|
-
const server = await this.config.serverFactory(accessToken, userId);
|
|
375
|
+
const server = await this.config.serverFactory(accessToken, userId, extras);
|
|
375
376
|
this.serverPool.set(userId, {
|
|
376
377
|
server,
|
|
377
378
|
accessToken,
|
|
@@ -520,7 +521,8 @@ class AuthenticatedServerWrapper {
|
|
|
520
521
|
headers: req.headers,
|
|
521
522
|
transport: "sse",
|
|
522
523
|
timestamp: /* @__PURE__ */ new Date(),
|
|
523
|
-
requestId: req.headers["x-request-id"]
|
|
524
|
+
requestId: req.headers["x-request-id"],
|
|
525
|
+
query: req.query
|
|
524
526
|
};
|
|
525
527
|
await this.handleSSERequest(req, res, context);
|
|
526
528
|
} catch (error) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/wrapper/server-wrapper.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Authenticated server wrapper implementation\n *\n * Wraps MCP servers with authentication and multi-tenancy support.\n * Uses ephemeral instances by default for security.\n */\n\nimport type { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport type { ServerWrapperConfig, NormalizedServerWrapperConfig } from './config.js';\nimport type { RequestContext, ProgressNotification } from '../types.js';\nimport {\n AuthenticationError,\n TokenResolutionError,\n ConfigurationError,\n TransportError\n} from '../utils/errors.js';\nimport { createLogger, type Logger } from '../utils/logger.js';\nimport {\n validateRequiredFields,\n validateResourceType,\n validateUserId,\n validateAccessToken,\n validateTransportConfig,\n validatePositiveNumber\n} from '../utils/validation.js';\nimport { ProgressManager } from './progress-manager.js';\nimport { InstancePoolManager } from './instance-pool-manager.js';\n\n/**\n * Server instance metadata (for pooled mode)\n */\ninterface ServerInstance {\n server: Server;\n accessToken: string;\n userId: string;\n createdAt: number;\n lastUsed: number;\n}\n\n/**\n * Authenticated server wrapper\n * \n * Wraps an MCP server with authentication, automatically handling:\n * - Request authentication via AuthProvider\n * - Token resolution via ResourceTokenResolver\n * - Per-user server instance creation (ephemeral or pooled)\n * - Transport management (stdio, SSE, HTTP)\n * \n * @example\n * ```typescript\n * const wrapper = new AuthenticatedServerWrapper({\n * serverFactory: (accessToken, userId) => createInstagramServer(accessToken),\n * authProvider: new JWTAuthProvider({ ... }),\n * tokenResolver: new DatabaseTokenResolver({ ... }),\n * resourceType: 'instagram',\n * transport: { type: 'sse', port: 3000 }\n * });\n * \n * await wrapper.start();\n * ```\n */\nexport class AuthenticatedServerWrapper {\n private config: NormalizedServerWrapperConfig;\n private logger: Logger;\n private serverPool: Map<string, ServerInstance>;\n private poolManager?: InstancePoolManager;\n private isRunning: boolean = false;\n private cleanupTimer?: NodeJS.Timeout;\n private progressContexts: Map<string, string | number> = new Map();\n private progressManager!: ProgressManager;\n private cleanupInterval?: NodeJS.Timeout;\n \n constructor(config: ServerWrapperConfig) {\n // Validate configuration\n this.validateConfig(config);\n \n // Normalize configuration with defaults\n this.config = this.normalizeConfig(config);\n \n // Initialize logger\n this.logger = createLogger(this.config.middleware.logging);\n \n // Initialize server pool (legacy - only used in old pooled mode)\n this.serverPool = new Map();\n \n // Initialize pool manager if pooled mode with instancePool config\n if (this.config.instanceMode === 'pooled' && this.config.instancePool) {\n this.poolManager = new InstancePoolManager(\n this.config.instancePool,\n this.logger\n );\n \n this.logger.info('Instance pool manager initialized', {\n maxSize: this.config.instancePool.maxSize,\n idleTimeout: this.config.instancePool.idleTimeout,\n maxLifetime: this.config.instancePool.maxLifetime\n });\n }\n \n // Initialize progress manager\n this.progressManager = new ProgressManager(this.logger);\n \n // Schedule periodic cleanup of stale streams (every minute)\n this.cleanupInterval = setInterval(() => {\n this.progressManager.cleanupStaleStreams();\n }, 60000);\n \n this.logger.info('AuthenticatedServerWrapper created', {\n name: this.config.name,\n resourceType: this.config.resourceType,\n transport: this.config.transport.type,\n instanceMode: this.config.instanceMode\n });\n }\n \n /**\n * Validate wrapper configuration\n */\n private validateConfig(config: ServerWrapperConfig): void {\n // Validate required fields manually for better type safety\n if (!config.serverFactory) {\n throw new ConfigurationError('serverFactory is required');\n }\n if (!config.authProvider) {\n throw new ConfigurationError('authProvider is required');\n }\n // tokenResolver is now optional for static servers\n if (!config.resourceType) {\n throw new ConfigurationError('resourceType is required');\n }\n if (!config.transport) {\n throw new ConfigurationError('transport is required');\n }\n \n validateResourceType(config.resourceType);\n validateTransportConfig(config.transport);\n \n // Validate instance pool config if pooled mode\n if (config.instanceMode === 'pooled') {\n if (!config.instancePool) {\n throw new ConfigurationError(\n 'instancePool configuration required when instanceMode is \"pooled\"'\n );\n }\n \n validatePositiveNumber(config.instancePool.maxSize, 'instancePool.maxSize');\n validatePositiveNumber(config.instancePool.idleTimeout, 'instancePool.idleTimeout');\n validatePositiveNumber(config.instancePool.maxLifetime, 'instancePool.maxLifetime');\n \n if (config.instancePool.maxSize < 1) {\n throw new ConfigurationError('instancePool.maxSize must be at least 1');\n }\n \n if (config.instancePool.idleTimeout < 1000) {\n throw new ConfigurationError('instancePool.idleTimeout must be at least 1000ms (1 second)');\n }\n \n if (config.instancePool.maxLifetime < config.instancePool.idleTimeout) {\n throw new ConfigurationError('instancePool.maxLifetime must be >= idleTimeout');\n }\n }\n \n // Log mode based on tokenResolver presence\n if (config.tokenResolver) {\n this.logger?.info('Token resolver configured - dynamic mode', {\n resolverType: config.tokenResolver.constructor.name\n });\n } else {\n this.logger?.info('No token resolver - static mode', {\n note: 'Server factory will receive empty string as accessToken'\n });\n }\n }\n \n /**\n * Normalize configuration with defaults\n */\n private normalizeConfig(config: ServerWrapperConfig): NormalizedServerWrapperConfig {\n return {\n serverFactory: config.serverFactory,\n authProvider: config.authProvider,\n tokenResolver: config.tokenResolver ?? null, // Convert undefined to null\n resourceType: config.resourceType,\n transport: config.transport,\n name: config.name ?? 'mcp-auth-wrapped-server',\n version: config.version ?? '1.0.0',\n instanceMode: config.instanceMode ?? 'ephemeral',\n instancePool: config.instancePool ?? null, // Convert undefined to null\n middleware: {\n rateLimit: config.middleware?.rateLimit,\n logging: config.middleware?.logging ?? { enabled: true, level: 'info' }\n },\n pooling: {\n maxServersPerUser: config.pooling?.maxServersPerUser ?? 1,\n idleTimeoutMs: config.pooling?.idleTimeoutMs ?? 300000,\n maxTotalServers: config.pooling?.maxTotalServers ?? 100\n },\n requestTimeoutMs: config.requestTimeoutMs ?? 30000,\n enableTracing: config.enableTracing ?? false\n };\n }\n \n /**\n * Start the wrapped server\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n throw new ConfigurationError('Server is already running');\n }\n \n this.logger.info('Starting authenticated server wrapper', {\n name: this.config.name,\n transport: this.config.transport.type\n });\n \n // Initialize auth provider\n if (this.config.authProvider.initialize) {\n await this.config.authProvider.initialize();\n this.logger.debug('Auth provider initialized');\n }\n \n // Initialize token resolver (if configured)\n if (this.config.tokenResolver) {\n if (this.config.tokenResolver.initialize) {\n await this.config.tokenResolver.initialize();\n this.logger.debug('Token resolver initialized');\n }\n } else {\n this.logger.debug('Static mode - no token resolver to initialize');\n }\n \n // Start appropriate transport\n switch (this.config.transport.type) {\n case 'stdio':\n await this.startStdioTransport();\n break;\n case 'sse':\n await this.startSSETransport();\n break;\n case 'http':\n await this.startHTTPTransport();\n break;\n default:\n throw new TransportError(`Unsupported transport type: ${this.config.transport.type}`);\n }\n \n this.isRunning = true;\n \n this.logger.info('Server wrapper started successfully', {\n name: this.config.name,\n transport: this.config.transport.type,\n port: this.config.transport.port\n });\n }\n \n /**\n * Stop the wrapped server\n */\n async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n \n this.logger.info('Stopping server wrapper');\n \n // Clear cleanup timers\n if (this.cleanupTimer) {\n clearTimeout(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n \n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = undefined;\n }\n \n // Close pool manager if exists\n if (this.poolManager) {\n await this.poolManager.closeAll();\n }\n \n // Close all pooled servers (legacy)\n if (this.config.instanceMode === 'pooled') {\n for (const [userId, instance] of this.serverPool.entries()) {\n try {\n await instance.server.close();\n this.logger.debug('Closed pooled server instance', { userId });\n } catch (error) {\n this.logger.error('Error closing server instance', error as Error, { userId });\n }\n }\n this.serverPool.clear();\n }\n \n // Cleanup auth provider\n if (this.config.authProvider.cleanup) {\n await this.config.authProvider.cleanup();\n this.logger.debug('Auth provider cleaned up');\n }\n \n // Cleanup token resolver (if configured)\n if (this.config.tokenResolver) {\n if (this.config.tokenResolver.cleanup) {\n await this.config.tokenResolver.cleanup();\n this.logger.debug('Token resolver cleaned up');\n }\n }\n \n this.isRunning = false;\n \n this.logger.info('Server wrapper stopped');\n }\n \n /**\n * Store progress context for a user\n */\n private storeProgressContext(userId: string, progressToken: string | number): void {\n this.progressContexts.set(userId, progressToken);\n this.logger.debug('Stored progress context', { userId, progressToken });\n }\n \n /**\n * Get progress context for a user\n */\n private getProgressContext(userId: string): string | number | undefined {\n return this.progressContexts.get(userId);\n }\n \n /**\n * Clear progress context for a user\n */\n private clearProgressContext(userId: string): void {\n this.progressContexts.delete(userId);\n this.logger.debug('Cleared progress context', { userId });\n }\n \n /**\n * Handle SSE request with direct Express req/res access\n * This allows us to use StreamableHTTPServerTransport properly\n */\n private async handleSSERequest(req: any, res: any, context: RequestContext): Promise<void> {\n const requestLogger = this.logger.child({ requestId: context.requestId });\n let userId: string | undefined;\n const progressToken = req.body._meta?.progressToken;\n \n try {\n // 1. Authenticate\n requestLogger.debug('Authenticating request');\n const authResult = await this.config.authProvider.authenticate(context);\n \n if (!authResult.authenticated || !authResult.userId) {\n requestLogger.warn('Authentication failed', { error: authResult.error });\n throw new AuthenticationError(authResult.error || 'Authentication failed');\n }\n \n userId = validateUserId(authResult.userId);\n requestLogger.debug('Authentication successful', { userId });\n \n // 2. Resolve resource token (or use empty string for static mode)\n let accessToken: string;\n \n if (this.config.tokenResolver) {\n // Dynamic mode - resolve token from external source\n const resolvedToken = await this.config.tokenResolver.resolveToken(\n userId,\n this.config.resourceType\n );\n \n if (!resolvedToken) {\n requestLogger.warn('Token resolution failed', { userId, resourceType: this.config.resourceType });\n throw new TokenResolutionError(userId, this.config.resourceType);\n }\n \n validateAccessToken(resolvedToken);\n accessToken = resolvedToken;\n requestLogger.debug('Token resolved', { userId, resourceType: this.config.resourceType });\n } else {\n // Static mode - no external token needed\n accessToken = '';\n requestLogger.debug('Static mode - no token resolution', { userId, mode: 'static' });\n }\n \n // 3. Store progress token and register stream if provided\n if (progressToken) {\n this.storeProgressContext(userId, progressToken);\n \n // Register progress stream with callback to forward notifications\n this.progressManager.registerStream(userId, progressToken, (notification) => {\n // Forward notification to client via response\n // Note: In a real implementation, this would use SSE or WebSocket\n // For now, we log that we would forward it\n requestLogger.debug('Would forward progress notification', {\n userId,\n progressToken: notification.progressToken,\n progress: notification.progress,\n total: notification.total\n });\n });\n \n requestLogger.debug('Progress token extracted and stream registered', { userId, progressToken });\n }\n \n // 4. Get server instance\n const server = await this.getServerInstance(userId, accessToken);\n \n // 5. Intercept server notifications to forward progress\n if (progressToken) {\n const originalNotification = (server as any).notification?.bind(server);\n if (originalNotification) {\n (server as any).notification = (params: any) => {\n // Check if this is a progress notification\n if (params.method === 'notifications/progress') {\n const handled = this.progressManager.forwardNotification(\n params.params as ProgressNotification\n );\n \n if (handled) {\n requestLogger.debug('Progress notification intercepted and forwarded', {\n progressToken: params.params.progressToken\n });\n return; // Don't send through original path\n }\n }\n \n // Forward other notifications normally\n if (originalNotification) {\n originalNotification(params);\n }\n };\n }\n }\n \n // 6. Forward request to server via StreamableHTTPServerTransport\n requestLogger.debug('Forwarding request to MCP server', { userId, hasProgressToken: !!progressToken });\n \n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined // Stateless mode\n });\n \n // Connect server to transport\n await server.connect(transport);\n \n // Forward the request through the transport\n // The transport handles JSON-RPC formatting\n // Tool names are passed through unchanged\n await transport.handleRequest(req, res, req.body);\n \n requestLogger.info('Request handled successfully', {\n userId,\n resourceType: this.config.resourceType,\n hadProgressToken: !!progressToken\n });\n \n // Clean up progress context and stream after request completes\n if (progressToken) {\n this.progressManager.unregisterStream(progressToken);\n this.clearProgressContext(userId);\n }\n \n } catch (error) {\n requestLogger.error('SSE request handling failed', error as Error);\n \n // Clean up progress context and stream on error\n if (progressToken) {\n this.progressManager.unregisterStream(progressToken);\n if (userId) {\n this.clearProgressContext(userId);\n }\n }\n \n throw error;\n }\n }\n \n /**\n * Get server instance (ephemeral or from pool)\n */\n private async getServerInstance(userId: string, accessToken: string): Promise<Server> {\n if (this.config.instanceMode === 'ephemeral') {\n // Create new server instance for each request (recommended)\n this.logger.debug('Creating ephemeral server instance', { userId });\n return await this.config.serverFactory(accessToken, userId);\n }\n \n // Pooled mode\n return await this.getPooledServerInstance(userId, accessToken);\n }\n \n /**\n * Get or create pooled server instance\n */\n private async getPooledServerInstance(userId: string, accessToken: string): Promise<Server> {\n // Use new InstancePoolManager if configured\n if (this.poolManager) {\n return await this.poolManager.getInstance(\n userId,\n accessToken,\n this.config.serverFactory\n );\n }\n \n // Legacy pooling logic (deprecated)\n // Check if we have a cached server instance\n if (this.serverPool.has(userId)) {\n const instance = this.serverPool.get(userId)!;\n \n // Check if token changed (user rotated token)\n if (instance.accessToken !== accessToken) {\n this.logger.info('Token changed, recreating server instance', { userId });\n await instance.server.close();\n this.serverPool.delete(userId);\n } else {\n // Reuse existing instance\n instance.lastUsed = Date.now();\n this.logger.debug('Reusing pooled server instance', { userId });\n return instance.server;\n }\n }\n \n // Check pool size limit\n if (this.serverPool.size >= this.config.pooling.maxTotalServers) {\n this.logger.warn('Server pool limit reached, evicting oldest instance', {\n poolSize: this.serverPool.size,\n maxTotal: this.config.pooling.maxTotalServers\n });\n await this.evictOldestInstance();\n }\n \n // Create new server instance\n this.logger.info('Creating new pooled server instance', { userId });\n const server = await this.config.serverFactory(accessToken, userId);\n \n // Add to pool\n this.serverPool.set(userId, {\n server,\n accessToken,\n userId,\n createdAt: Date.now(),\n lastUsed: Date.now()\n });\n \n // Schedule cleanup if not already scheduled\n if (!this.cleanupTimer) {\n this.scheduleCleanup();\n }\n \n return server;\n }\n \n /**\n * Evict oldest server instance from pool\n */\n private async evictOldestInstance(): Promise<void> {\n let oldestUserId: string | null = null;\n let oldestTime = Infinity;\n \n for (const [userId, instance] of this.serverPool.entries()) {\n if (instance.lastUsed < oldestTime) {\n oldestTime = instance.lastUsed;\n oldestUserId = userId;\n }\n }\n \n if (oldestUserId) {\n const instance = this.serverPool.get(oldestUserId)!;\n await instance.server.close();\n this.serverPool.delete(oldestUserId);\n \n this.logger.debug('Evicted oldest server instance', {\n userId: oldestUserId,\n age: Date.now() - instance.createdAt\n });\n }\n }\n \n /**\n * Schedule cleanup of idle server instances\n */\n private scheduleCleanup(): void {\n const timeout = this.config.pooling.idleTimeoutMs;\n \n this.cleanupTimer = setTimeout(async () => {\n const now = Date.now();\n const toRemove: string[] = [];\n \n for (const [userId, instance] of this.serverPool.entries()) {\n if (now - instance.lastUsed > timeout) {\n toRemove.push(userId);\n }\n }\n \n for (const userId of toRemove) {\n const instance = this.serverPool.get(userId)!;\n try {\n await instance.server.close();\n this.serverPool.delete(userId);\n \n this.logger.debug('Cleaned up idle server instance', {\n userId,\n idleTime: now - instance.lastUsed\n });\n } catch (error) {\n this.logger.error('Error cleaning up server instance', error as Error, { userId });\n }\n }\n \n // Reschedule if pool is not empty\n if (this.serverPool.size > 0) {\n this.scheduleCleanup();\n } else {\n this.cleanupTimer = undefined;\n }\n }, timeout);\n }\n \n /**\n * Start stdio transport (single-user mode)\n */\n private async startStdioTransport(): Promise<void> {\n this.logger.info('Starting stdio transport');\n \n // For stdio, we use environment variable for token\n const envVar = `${this.config.resourceType.toUpperCase()}_ACCESS_TOKEN`;\n const accessToken = process.env[envVar];\n \n if (!accessToken) {\n throw new ConfigurationError(\n `${envVar} environment variable required for stdio mode`\n );\n }\n \n const userId = 'stdio-user';\n \n // Create server instance\n const server = await this.config.serverFactory(accessToken, userId);\n \n // Connect to stdio transport\n const transport = new StdioServerTransport();\n await server.connect(transport);\n \n this.logger.info('Stdio transport started', { userId });\n }\n \n /**\n * Start SSE transport (multi-user mode)\n */\n private async startSSETransport(): Promise<void> {\n this.logger.info('Starting SSE transport', {\n port: this.config.transport.port,\n basePath: this.config.transport.basePath\n });\n \n // Import express dynamically (optional dependency)\n // @ts-ignore - Dynamic import of optional dependency\n const express = await import('express');\n const app = express.default();\n \n // Enable JSON parsing\n app.use(express.json());\n \n // Enable CORS if configured\n if (this.config.transport.cors) {\n // Validate CORS configuration\n if (!this.config.transport.corsOrigin) {\n throw new ConfigurationError(\n 'CORS origin must be explicitly configured when CORS is enabled. ' +\n 'Set transport.corsOrigin to a specific origin (e.g., \"https://app.example.com\") ' +\n 'or an array of allowed origins.'\n );\n }\n \n // Check for wildcard in production\n if (this.config.transport.corsOrigin === '*') {\n const isProduction = process.env.NODE_ENV === 'production';\n \n if (isProduction) {\n throw new ConfigurationError(\n 'CORS wildcard (*) is not allowed in production environments. ' +\n 'Specify explicit origins to prevent CSRF attacks. ' +\n 'Example: corsOrigin: \"https://app.example.com\"'\n );\n }\n \n this.logger.warn(\n 'CORS wildcard (*) detected in development. ' +\n 'This is insecure and should never be used in production.',\n { corsOrigin: this.config.transport.corsOrigin }\n );\n }\n \n // @ts-ignore - Dynamic import of optional dependency\n const cors = await import('cors');\n app.use(cors.default({\n origin: this.config.transport.corsOrigin,\n credentials: true,\n methods: ['GET', 'POST', 'OPTIONS'],\n allowedHeaders: ['Content-Type', 'Authorization', 'X-Request-ID'],\n exposedHeaders: ['X-Request-ID'],\n maxAge: 86400 // 24 hours\n }));\n \n this.logger.info('CORS enabled', {\n origin: this.config.transport.corsOrigin,\n credentials: true\n });\n }\n \n const basePath = this.config.transport.basePath || '/mcp';\n \n // Root endpoint info\n app.get(basePath, (req: any, res: any) => {\n res.json({\n name: this.config.name,\n version: this.config.version,\n resourceType: this.config.resourceType,\n endpoints: {\n message: `POST ${basePath}/message`,\n health: `GET ${basePath}/health`\n },\n documentation: 'https://github.com/prmichaelsen/mcp-auth'\n });\n });\n \n // SSE endpoint for MCP messages\n app.post(`${basePath}/message`, async (req: any, res: any) => {\n try {\n const context: RequestContext = {\n headers: req.headers as Record<string, string>,\n transport: 'sse',\n timestamp: new Date(),\n requestId: req.headers['x-request-id'] as string | undefined\n };\n \n // Handle request and forward to MCP server via transport\n await this.handleSSERequest(req, res, context);\n \n } catch (error) {\n this.logger.error('SSE request failed', error as Error);\n \n if (error instanceof AuthenticationError || error instanceof TokenResolutionError) {\n res.status(error.statusCode).json({\n error: error.message,\n code: error.code\n });\n } else {\n res.status(500).json({\n error: 'Internal server error',\n code: 'INTERNAL_ERROR'\n });\n }\n }\n });\n \n // Progress monitoring endpoint (authenticated)\n app.get(`${basePath}/progress/stats`, async (req: any, res: any) => {\n try {\n // Authenticate request\n const context: RequestContext = {\n headers: req.headers as Record<string, string>,\n transport: 'sse',\n timestamp: new Date(),\n requestId: req.headers['x-request-id'] as string | undefined\n };\n \n const authResult = await this.config.authProvider.authenticate(context);\n \n if (!authResult.authenticated || !authResult.userId) {\n return res.status(401).json({\n error: 'Authentication required',\n code: 'AUTHENTICATION_ERROR'\n });\n }\n \n const userId = authResult.userId;\n \n // Get user-specific metrics\n const userMetrics = this.progressManager.getUserMetrics(userId);\n const globalStats = this.progressManager.getStats();\n \n res.json({\n user: {\n userId,\n ...userMetrics\n },\n global: globalStats,\n timestamp: new Date().toISOString()\n });\n \n } catch (error) {\n this.logger.error('Error fetching progress stats', error as Error);\n res.status(500).json({\n error: 'Internal server error',\n code: 'INTERNAL_ERROR'\n });\n }\n });\n \n // Detailed metrics endpoint (authenticated)\n app.get(`${basePath}/progress/metrics`, async (req: any, res: any) => {\n try {\n // Authenticate request\n const context: RequestContext = {\n headers: req.headers as Record<string, string>,\n transport: 'sse',\n timestamp: new Date(),\n requestId: req.headers['x-request-id'] as string | undefined\n };\n \n const authResult = await this.config.authProvider.authenticate(context);\n \n if (!authResult.authenticated) {\n return res.status(401).json({\n error: 'Authentication required',\n code: 'AUTHENTICATION_ERROR'\n });\n }\n \n // Get all metrics (could add admin check here)\n const allMetrics = this.progressManager.getAllMetrics();\n const health = this.progressManager.checkHealth();\n \n res.json({\n metrics: allMetrics,\n health,\n timestamp: new Date().toISOString()\n });\n \n } catch (error) {\n this.logger.error('Error fetching progress metrics', error as Error);\n res.status(500).json({\n error: 'Internal server error',\n code: 'INTERNAL_ERROR'\n });\n }\n });\n \n // Health check endpoint\n app.get(`${basePath}/health`, (req: any, res: any) => {\n res.json({\n status: 'healthy',\n name: this.config.name,\n version: this.config.version,\n resourceType: this.config.resourceType,\n instanceMode: this.config.instanceMode,\n poolSize: this.serverPool.size\n });\n });\n \n // Start server\n const port = this.config.transport.port || 3000;\n const host = this.config.transport.host || '0.0.0.0';\n \n await new Promise<void>((resolve) => {\n app.listen(port, host, () => {\n this.logger.info('SSE transport listening', {\n host,\n port,\n basePath,\n url: `http://${host}:${port}${basePath}`\n });\n resolve();\n });\n });\n }\n \n /**\n * Start HTTP transport (multi-user mode)\n */\n private async startHTTPTransport(): Promise<void> {\n this.logger.info('Starting HTTP transport', {\n port: this.config.transport.port\n });\n \n // HTTP transport is similar to SSE but with different endpoint structure\n // For now, delegate to SSE implementation\n await this.startSSETransport();\n }\n \n /**\n * Get server pool statistics\n */\n getPoolStats(): {\n size: number;\n instances: Array<{\n userId: string;\n createdAt: number;\n lastUsed: number;\n age: number;\n idleTime: number;\n }>;\n } {\n const now = Date.now();\n const instances = Array.from(this.serverPool.entries()).map(([userId, instance]) => ({\n userId,\n createdAt: instance.createdAt,\n lastUsed: instance.lastUsed,\n age: now - instance.createdAt,\n idleTime: now - instance.lastUsed\n }));\n \n return {\n size: this.serverPool.size,\n instances\n };\n }\n \n /**\n * Check if server is running\n */\n isServerRunning(): boolean {\n return this.isRunning;\n }\n}\n\n/**\n * Convenience function to create and configure an authenticated server wrapper\n *\n * @param config - Server wrapper configuration\n * @returns Configured AuthenticatedServerWrapper instance\n *\n * @example\n * ```typescript\n * const wrapped = wrapServer({\n * serverFactory: (accessToken, userId) => createMyServer(accessToken, userId),\n * authProvider: new JWTAuthProvider({ jwtSecret: process.env.JWT_SECRET }),\n * tokenResolver: new APITokenResolver({ ... }),\n * resourceType: 'myapi',\n * transport: { type: 'sse', port: 3000 }\n * });\n *\n * await wrapped.start();\n * ```\n */\nexport function wrapServer(config: ServerWrapperConfig): AuthenticatedServerWrapper {\n return new AuthenticatedServerWrapper(config);\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Authenticated server wrapper implementation\n *\n * Wraps MCP servers with authentication and multi-tenancy support.\n * Uses ephemeral instances by default for security.\n */\n\nimport type { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport type { ServerWrapperConfig, NormalizedServerWrapperConfig, MCPServerFactoryExtras } from './config.js';\nimport type { RequestContext, ProgressNotification } from '../types.js';\nimport {\n AuthenticationError,\n TokenResolutionError,\n ConfigurationError,\n TransportError\n} from '../utils/errors.js';\nimport { createLogger, type Logger } from '../utils/logger.js';\nimport {\n validateRequiredFields,\n validateResourceType,\n validateUserId,\n validateAccessToken,\n validateTransportConfig,\n validatePositiveNumber\n} from '../utils/validation.js';\nimport { ProgressManager } from './progress-manager.js';\nimport { InstancePoolManager } from './instance-pool-manager.js';\n\n/**\n * Server instance metadata (for pooled mode)\n */\ninterface ServerInstance {\n server: Server;\n accessToken: string;\n userId: string;\n createdAt: number;\n lastUsed: number;\n}\n\n/**\n * Authenticated server wrapper\n * \n * Wraps an MCP server with authentication, automatically handling:\n * - Request authentication via AuthProvider\n * - Token resolution via ResourceTokenResolver\n * - Per-user server instance creation (ephemeral or pooled)\n * - Transport management (stdio, SSE, HTTP)\n * \n * @example\n * ```typescript\n * const wrapper = new AuthenticatedServerWrapper({\n * serverFactory: (accessToken, userId) => createInstagramServer(accessToken),\n * authProvider: new JWTAuthProvider({ ... }),\n * tokenResolver: new DatabaseTokenResolver({ ... }),\n * resourceType: 'instagram',\n * transport: { type: 'sse', port: 3000 }\n * });\n * \n * await wrapper.start();\n * ```\n */\nexport class AuthenticatedServerWrapper {\n private config: NormalizedServerWrapperConfig;\n private logger: Logger;\n private serverPool: Map<string, ServerInstance>;\n private poolManager?: InstancePoolManager;\n private isRunning: boolean = false;\n private cleanupTimer?: NodeJS.Timeout;\n private progressContexts: Map<string, string | number> = new Map();\n private progressManager!: ProgressManager;\n private cleanupInterval?: NodeJS.Timeout;\n \n constructor(config: ServerWrapperConfig) {\n // Validate configuration\n this.validateConfig(config);\n \n // Normalize configuration with defaults\n this.config = this.normalizeConfig(config);\n \n // Initialize logger\n this.logger = createLogger(this.config.middleware.logging);\n \n // Initialize server pool (legacy - only used in old pooled mode)\n this.serverPool = new Map();\n \n // Initialize pool manager if pooled mode with instancePool config\n if (this.config.instanceMode === 'pooled' && this.config.instancePool) {\n this.poolManager = new InstancePoolManager(\n this.config.instancePool,\n this.logger\n );\n \n this.logger.info('Instance pool manager initialized', {\n maxSize: this.config.instancePool.maxSize,\n idleTimeout: this.config.instancePool.idleTimeout,\n maxLifetime: this.config.instancePool.maxLifetime\n });\n }\n \n // Initialize progress manager\n this.progressManager = new ProgressManager(this.logger);\n \n // Schedule periodic cleanup of stale streams (every minute)\n this.cleanupInterval = setInterval(() => {\n this.progressManager.cleanupStaleStreams();\n }, 60000);\n \n this.logger.info('AuthenticatedServerWrapper created', {\n name: this.config.name,\n resourceType: this.config.resourceType,\n transport: this.config.transport.type,\n instanceMode: this.config.instanceMode\n });\n }\n \n /**\n * Validate wrapper configuration\n */\n private validateConfig(config: ServerWrapperConfig): void {\n // Validate required fields manually for better type safety\n if (!config.serverFactory) {\n throw new ConfigurationError('serverFactory is required');\n }\n if (!config.authProvider) {\n throw new ConfigurationError('authProvider is required');\n }\n // tokenResolver is now optional for static servers\n if (!config.resourceType) {\n throw new ConfigurationError('resourceType is required');\n }\n if (!config.transport) {\n throw new ConfigurationError('transport is required');\n }\n \n validateResourceType(config.resourceType);\n validateTransportConfig(config.transport);\n \n // Validate instance pool config if pooled mode\n if (config.instanceMode === 'pooled') {\n if (!config.instancePool) {\n throw new ConfigurationError(\n 'instancePool configuration required when instanceMode is \"pooled\"'\n );\n }\n \n validatePositiveNumber(config.instancePool.maxSize, 'instancePool.maxSize');\n validatePositiveNumber(config.instancePool.idleTimeout, 'instancePool.idleTimeout');\n validatePositiveNumber(config.instancePool.maxLifetime, 'instancePool.maxLifetime');\n \n if (config.instancePool.maxSize < 1) {\n throw new ConfigurationError('instancePool.maxSize must be at least 1');\n }\n \n if (config.instancePool.idleTimeout < 1000) {\n throw new ConfigurationError('instancePool.idleTimeout must be at least 1000ms (1 second)');\n }\n \n if (config.instancePool.maxLifetime < config.instancePool.idleTimeout) {\n throw new ConfigurationError('instancePool.maxLifetime must be >= idleTimeout');\n }\n }\n \n // Log mode based on tokenResolver presence\n if (config.tokenResolver) {\n this.logger?.info('Token resolver configured - dynamic mode', {\n resolverType: config.tokenResolver.constructor.name\n });\n } else {\n this.logger?.info('No token resolver - static mode', {\n note: 'Server factory will receive empty string as accessToken'\n });\n }\n }\n \n /**\n * Normalize configuration with defaults\n */\n private normalizeConfig(config: ServerWrapperConfig): NormalizedServerWrapperConfig {\n return {\n serverFactory: config.serverFactory,\n authProvider: config.authProvider,\n tokenResolver: config.tokenResolver ?? null, // Convert undefined to null\n resourceType: config.resourceType,\n transport: config.transport,\n name: config.name ?? 'mcp-auth-wrapped-server',\n version: config.version ?? '1.0.0',\n instanceMode: config.instanceMode ?? 'ephemeral',\n instancePool: config.instancePool ?? null, // Convert undefined to null\n middleware: {\n rateLimit: config.middleware?.rateLimit,\n logging: config.middleware?.logging ?? { enabled: true, level: 'info' }\n },\n pooling: {\n maxServersPerUser: config.pooling?.maxServersPerUser ?? 1,\n idleTimeoutMs: config.pooling?.idleTimeoutMs ?? 300000,\n maxTotalServers: config.pooling?.maxTotalServers ?? 100\n },\n requestTimeoutMs: config.requestTimeoutMs ?? 30000,\n enableTracing: config.enableTracing ?? false\n };\n }\n \n /**\n * Start the wrapped server\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n throw new ConfigurationError('Server is already running');\n }\n \n this.logger.info('Starting authenticated server wrapper', {\n name: this.config.name,\n transport: this.config.transport.type\n });\n \n // Initialize auth provider\n if (this.config.authProvider.initialize) {\n await this.config.authProvider.initialize();\n this.logger.debug('Auth provider initialized');\n }\n \n // Initialize token resolver (if configured)\n if (this.config.tokenResolver) {\n if (this.config.tokenResolver.initialize) {\n await this.config.tokenResolver.initialize();\n this.logger.debug('Token resolver initialized');\n }\n } else {\n this.logger.debug('Static mode - no token resolver to initialize');\n }\n \n // Start appropriate transport\n switch (this.config.transport.type) {\n case 'stdio':\n await this.startStdioTransport();\n break;\n case 'sse':\n await this.startSSETransport();\n break;\n case 'http':\n await this.startHTTPTransport();\n break;\n default:\n throw new TransportError(`Unsupported transport type: ${this.config.transport.type}`);\n }\n \n this.isRunning = true;\n \n this.logger.info('Server wrapper started successfully', {\n name: this.config.name,\n transport: this.config.transport.type,\n port: this.config.transport.port\n });\n }\n \n /**\n * Stop the wrapped server\n */\n async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n \n this.logger.info('Stopping server wrapper');\n \n // Clear cleanup timers\n if (this.cleanupTimer) {\n clearTimeout(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n \n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = undefined;\n }\n \n // Close pool manager if exists\n if (this.poolManager) {\n await this.poolManager.closeAll();\n }\n \n // Close all pooled servers (legacy)\n if (this.config.instanceMode === 'pooled') {\n for (const [userId, instance] of this.serverPool.entries()) {\n try {\n await instance.server.close();\n this.logger.debug('Closed pooled server instance', { userId });\n } catch (error) {\n this.logger.error('Error closing server instance', error as Error, { userId });\n }\n }\n this.serverPool.clear();\n }\n \n // Cleanup auth provider\n if (this.config.authProvider.cleanup) {\n await this.config.authProvider.cleanup();\n this.logger.debug('Auth provider cleaned up');\n }\n \n // Cleanup token resolver (if configured)\n if (this.config.tokenResolver) {\n if (this.config.tokenResolver.cleanup) {\n await this.config.tokenResolver.cleanup();\n this.logger.debug('Token resolver cleaned up');\n }\n }\n \n this.isRunning = false;\n \n this.logger.info('Server wrapper stopped');\n }\n \n /**\n * Store progress context for a user\n */\n private storeProgressContext(userId: string, progressToken: string | number): void {\n this.progressContexts.set(userId, progressToken);\n this.logger.debug('Stored progress context', { userId, progressToken });\n }\n \n /**\n * Get progress context for a user\n */\n private getProgressContext(userId: string): string | number | undefined {\n return this.progressContexts.get(userId);\n }\n \n /**\n * Clear progress context for a user\n */\n private clearProgressContext(userId: string): void {\n this.progressContexts.delete(userId);\n this.logger.debug('Cleared progress context', { userId });\n }\n \n /**\n * Handle SSE request with direct Express req/res access\n * This allows us to use StreamableHTTPServerTransport properly\n */\n private async handleSSERequest(req: any, res: any, context: RequestContext): Promise<void> {\n const requestLogger = this.logger.child({ requestId: context.requestId });\n let userId: string | undefined;\n const progressToken = req.body._meta?.progressToken;\n \n try {\n // 1. Authenticate\n requestLogger.debug('Authenticating request');\n const authResult = await this.config.authProvider.authenticate(context);\n \n if (!authResult.authenticated || !authResult.userId) {\n requestLogger.warn('Authentication failed', { error: authResult.error });\n throw new AuthenticationError(authResult.error || 'Authentication failed');\n }\n \n userId = validateUserId(authResult.userId);\n requestLogger.debug('Authentication successful', { userId });\n \n // 2. Resolve resource token (or use empty string for static mode)\n let accessToken: string;\n \n if (this.config.tokenResolver) {\n // Dynamic mode - resolve token from external source\n const resolvedToken = await this.config.tokenResolver.resolveToken(\n userId,\n this.config.resourceType\n );\n \n if (!resolvedToken) {\n requestLogger.warn('Token resolution failed', { userId, resourceType: this.config.resourceType });\n throw new TokenResolutionError(userId, this.config.resourceType);\n }\n \n validateAccessToken(resolvedToken);\n accessToken = resolvedToken;\n requestLogger.debug('Token resolved', { userId, resourceType: this.config.resourceType });\n } else {\n // Static mode - no external token needed\n accessToken = '';\n requestLogger.debug('Static mode - no token resolution', { userId, mode: 'static' });\n }\n \n // 3. Store progress token and register stream if provided\n if (progressToken) {\n this.storeProgressContext(userId, progressToken);\n \n // Register progress stream with callback to forward notifications\n this.progressManager.registerStream(userId, progressToken, (notification) => {\n // Forward notification to client via response\n // Note: In a real implementation, this would use SSE or WebSocket\n // For now, we log that we would forward it\n requestLogger.debug('Would forward progress notification', {\n userId,\n progressToken: notification.progressToken,\n progress: notification.progress,\n total: notification.total\n });\n });\n \n requestLogger.debug('Progress token extracted and stream registered', { userId, progressToken });\n }\n \n // 4. Get server instance (pass query params as extras)\n const server = await this.getServerInstance(userId, accessToken, context.query);\n \n // 5. Intercept server notifications to forward progress\n if (progressToken) {\n const originalNotification = (server as any).notification?.bind(server);\n if (originalNotification) {\n (server as any).notification = (params: any) => {\n // Check if this is a progress notification\n if (params.method === 'notifications/progress') {\n const handled = this.progressManager.forwardNotification(\n params.params as ProgressNotification\n );\n \n if (handled) {\n requestLogger.debug('Progress notification intercepted and forwarded', {\n progressToken: params.params.progressToken\n });\n return; // Don't send through original path\n }\n }\n \n // Forward other notifications normally\n if (originalNotification) {\n originalNotification(params);\n }\n };\n }\n }\n \n // 6. Forward request to server via StreamableHTTPServerTransport\n requestLogger.debug('Forwarding request to MCP server', { userId, hasProgressToken: !!progressToken });\n \n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined // Stateless mode\n });\n \n // Connect server to transport\n await server.connect(transport);\n \n // Forward the request through the transport\n // The transport handles JSON-RPC formatting\n // Tool names are passed through unchanged\n await transport.handleRequest(req, res, req.body);\n \n requestLogger.info('Request handled successfully', {\n userId,\n resourceType: this.config.resourceType,\n hadProgressToken: !!progressToken\n });\n \n // Clean up progress context and stream after request completes\n if (progressToken) {\n this.progressManager.unregisterStream(progressToken);\n this.clearProgressContext(userId);\n }\n \n } catch (error) {\n requestLogger.error('SSE request handling failed', error as Error);\n \n // Clean up progress context and stream on error\n if (progressToken) {\n this.progressManager.unregisterStream(progressToken);\n if (userId) {\n this.clearProgressContext(userId);\n }\n }\n \n throw error;\n }\n }\n \n /**\n * Get server instance (ephemeral or from pool)\n */\n private async getServerInstance(userId: string, accessToken: string, extras?: MCPServerFactoryExtras): Promise<Server> {\n if (this.config.instanceMode === 'ephemeral') {\n // Create new server instance for each request (recommended)\n this.logger.debug('Creating ephemeral server instance', { userId });\n return await this.config.serverFactory(accessToken, userId, extras);\n }\n\n // Pooled mode\n return await this.getPooledServerInstance(userId, accessToken, extras);\n }\n \n /**\n * Get or create pooled server instance\n */\n private async getPooledServerInstance(userId: string, accessToken: string, extras?: MCPServerFactoryExtras): Promise<Server> {\n // Use new InstancePoolManager if configured\n if (this.poolManager) {\n return await this.poolManager.getInstance(\n userId,\n accessToken,\n this.config.serverFactory,\n extras\n );\n }\n \n // Legacy pooling logic (deprecated)\n // Check if we have a cached server instance\n if (this.serverPool.has(userId)) {\n const instance = this.serverPool.get(userId)!;\n \n // Check if token changed (user rotated token)\n if (instance.accessToken !== accessToken) {\n this.logger.info('Token changed, recreating server instance', { userId });\n await instance.server.close();\n this.serverPool.delete(userId);\n } else {\n // Reuse existing instance\n instance.lastUsed = Date.now();\n this.logger.debug('Reusing pooled server instance', { userId });\n return instance.server;\n }\n }\n \n // Check pool size limit\n if (this.serverPool.size >= this.config.pooling.maxTotalServers) {\n this.logger.warn('Server pool limit reached, evicting oldest instance', {\n poolSize: this.serverPool.size,\n maxTotal: this.config.pooling.maxTotalServers\n });\n await this.evictOldestInstance();\n }\n \n // Create new server instance\n this.logger.info('Creating new pooled server instance', { userId });\n const server = await this.config.serverFactory(accessToken, userId, extras);\n \n // Add to pool\n this.serverPool.set(userId, {\n server,\n accessToken,\n userId,\n createdAt: Date.now(),\n lastUsed: Date.now()\n });\n \n // Schedule cleanup if not already scheduled\n if (!this.cleanupTimer) {\n this.scheduleCleanup();\n }\n \n return server;\n }\n \n /**\n * Evict oldest server instance from pool\n */\n private async evictOldestInstance(): Promise<void> {\n let oldestUserId: string | null = null;\n let oldestTime = Infinity;\n \n for (const [userId, instance] of this.serverPool.entries()) {\n if (instance.lastUsed < oldestTime) {\n oldestTime = instance.lastUsed;\n oldestUserId = userId;\n }\n }\n \n if (oldestUserId) {\n const instance = this.serverPool.get(oldestUserId)!;\n await instance.server.close();\n this.serverPool.delete(oldestUserId);\n \n this.logger.debug('Evicted oldest server instance', {\n userId: oldestUserId,\n age: Date.now() - instance.createdAt\n });\n }\n }\n \n /**\n * Schedule cleanup of idle server instances\n */\n private scheduleCleanup(): void {\n const timeout = this.config.pooling.idleTimeoutMs;\n \n this.cleanupTimer = setTimeout(async () => {\n const now = Date.now();\n const toRemove: string[] = [];\n \n for (const [userId, instance] of this.serverPool.entries()) {\n if (now - instance.lastUsed > timeout) {\n toRemove.push(userId);\n }\n }\n \n for (const userId of toRemove) {\n const instance = this.serverPool.get(userId)!;\n try {\n await instance.server.close();\n this.serverPool.delete(userId);\n \n this.logger.debug('Cleaned up idle server instance', {\n userId,\n idleTime: now - instance.lastUsed\n });\n } catch (error) {\n this.logger.error('Error cleaning up server instance', error as Error, { userId });\n }\n }\n \n // Reschedule if pool is not empty\n if (this.serverPool.size > 0) {\n this.scheduleCleanup();\n } else {\n this.cleanupTimer = undefined;\n }\n }, timeout);\n }\n \n /**\n * Start stdio transport (single-user mode)\n */\n private async startStdioTransport(): Promise<void> {\n this.logger.info('Starting stdio transport');\n \n // For stdio, we use environment variable for token\n const envVar = `${this.config.resourceType.toUpperCase()}_ACCESS_TOKEN`;\n const accessToken = process.env[envVar];\n \n if (!accessToken) {\n throw new ConfigurationError(\n `${envVar} environment variable required for stdio mode`\n );\n }\n \n const userId = 'stdio-user';\n \n // Create server instance\n const server = await this.config.serverFactory(accessToken, userId);\n \n // Connect to stdio transport\n const transport = new StdioServerTransport();\n await server.connect(transport);\n \n this.logger.info('Stdio transport started', { userId });\n }\n \n /**\n * Start SSE transport (multi-user mode)\n */\n private async startSSETransport(): Promise<void> {\n this.logger.info('Starting SSE transport', {\n port: this.config.transport.port,\n basePath: this.config.transport.basePath\n });\n \n // Import express dynamically (optional dependency)\n // @ts-ignore - Dynamic import of optional dependency\n const express = await import('express');\n const app = express.default();\n \n // Enable JSON parsing\n app.use(express.json());\n \n // Enable CORS if configured\n if (this.config.transport.cors) {\n // Validate CORS configuration\n if (!this.config.transport.corsOrigin) {\n throw new ConfigurationError(\n 'CORS origin must be explicitly configured when CORS is enabled. ' +\n 'Set transport.corsOrigin to a specific origin (e.g., \"https://app.example.com\") ' +\n 'or an array of allowed origins.'\n );\n }\n \n // Check for wildcard in production\n if (this.config.transport.corsOrigin === '*') {\n const isProduction = process.env.NODE_ENV === 'production';\n \n if (isProduction) {\n throw new ConfigurationError(\n 'CORS wildcard (*) is not allowed in production environments. ' +\n 'Specify explicit origins to prevent CSRF attacks. ' +\n 'Example: corsOrigin: \"https://app.example.com\"'\n );\n }\n \n this.logger.warn(\n 'CORS wildcard (*) detected in development. ' +\n 'This is insecure and should never be used in production.',\n { corsOrigin: this.config.transport.corsOrigin }\n );\n }\n \n // @ts-ignore - Dynamic import of optional dependency\n const cors = await import('cors');\n app.use(cors.default({\n origin: this.config.transport.corsOrigin,\n credentials: true,\n methods: ['GET', 'POST', 'OPTIONS'],\n allowedHeaders: ['Content-Type', 'Authorization', 'X-Request-ID'],\n exposedHeaders: ['X-Request-ID'],\n maxAge: 86400 // 24 hours\n }));\n \n this.logger.info('CORS enabled', {\n origin: this.config.transport.corsOrigin,\n credentials: true\n });\n }\n \n const basePath = this.config.transport.basePath || '/mcp';\n \n // Root endpoint info\n app.get(basePath, (req: any, res: any) => {\n res.json({\n name: this.config.name,\n version: this.config.version,\n resourceType: this.config.resourceType,\n endpoints: {\n message: `POST ${basePath}/message`,\n health: `GET ${basePath}/health`\n },\n documentation: 'https://github.com/prmichaelsen/mcp-auth'\n });\n });\n \n // SSE endpoint for MCP messages\n app.post(`${basePath}/message`, async (req: any, res: any) => {\n try {\n const context: RequestContext = {\n headers: req.headers as Record<string, string>,\n transport: 'sse',\n timestamp: new Date(),\n requestId: req.headers['x-request-id'] as string | undefined,\n query: req.query as Record<string, string | string[] | undefined>\n };\n\n // Handle request and forward to MCP server via transport\n await this.handleSSERequest(req, res, context);\n \n } catch (error) {\n this.logger.error('SSE request failed', error as Error);\n \n if (error instanceof AuthenticationError || error instanceof TokenResolutionError) {\n res.status(error.statusCode).json({\n error: error.message,\n code: error.code\n });\n } else {\n res.status(500).json({\n error: 'Internal server error',\n code: 'INTERNAL_ERROR'\n });\n }\n }\n });\n \n // Progress monitoring endpoint (authenticated)\n app.get(`${basePath}/progress/stats`, async (req: any, res: any) => {\n try {\n // Authenticate request\n const context: RequestContext = {\n headers: req.headers as Record<string, string>,\n transport: 'sse',\n timestamp: new Date(),\n requestId: req.headers['x-request-id'] as string | undefined\n };\n \n const authResult = await this.config.authProvider.authenticate(context);\n \n if (!authResult.authenticated || !authResult.userId) {\n return res.status(401).json({\n error: 'Authentication required',\n code: 'AUTHENTICATION_ERROR'\n });\n }\n \n const userId = authResult.userId;\n \n // Get user-specific metrics\n const userMetrics = this.progressManager.getUserMetrics(userId);\n const globalStats = this.progressManager.getStats();\n \n res.json({\n user: {\n userId,\n ...userMetrics\n },\n global: globalStats,\n timestamp: new Date().toISOString()\n });\n \n } catch (error) {\n this.logger.error('Error fetching progress stats', error as Error);\n res.status(500).json({\n error: 'Internal server error',\n code: 'INTERNAL_ERROR'\n });\n }\n });\n \n // Detailed metrics endpoint (authenticated)\n app.get(`${basePath}/progress/metrics`, async (req: any, res: any) => {\n try {\n // Authenticate request\n const context: RequestContext = {\n headers: req.headers as Record<string, string>,\n transport: 'sse',\n timestamp: new Date(),\n requestId: req.headers['x-request-id'] as string | undefined\n };\n \n const authResult = await this.config.authProvider.authenticate(context);\n \n if (!authResult.authenticated) {\n return res.status(401).json({\n error: 'Authentication required',\n code: 'AUTHENTICATION_ERROR'\n });\n }\n \n // Get all metrics (could add admin check here)\n const allMetrics = this.progressManager.getAllMetrics();\n const health = this.progressManager.checkHealth();\n \n res.json({\n metrics: allMetrics,\n health,\n timestamp: new Date().toISOString()\n });\n \n } catch (error) {\n this.logger.error('Error fetching progress metrics', error as Error);\n res.status(500).json({\n error: 'Internal server error',\n code: 'INTERNAL_ERROR'\n });\n }\n });\n \n // Health check endpoint\n app.get(`${basePath}/health`, (req: any, res: any) => {\n res.json({\n status: 'healthy',\n name: this.config.name,\n version: this.config.version,\n resourceType: this.config.resourceType,\n instanceMode: this.config.instanceMode,\n poolSize: this.serverPool.size\n });\n });\n \n // Start server\n const port = this.config.transport.port || 3000;\n const host = this.config.transport.host || '0.0.0.0';\n \n await new Promise<void>((resolve) => {\n app.listen(port, host, () => {\n this.logger.info('SSE transport listening', {\n host,\n port,\n basePath,\n url: `http://${host}:${port}${basePath}`\n });\n resolve();\n });\n });\n }\n \n /**\n * Start HTTP transport (multi-user mode)\n */\n private async startHTTPTransport(): Promise<void> {\n this.logger.info('Starting HTTP transport', {\n port: this.config.transport.port\n });\n \n // HTTP transport is similar to SSE but with different endpoint structure\n // For now, delegate to SSE implementation\n await this.startSSETransport();\n }\n \n /**\n * Get server pool statistics\n */\n getPoolStats(): {\n size: number;\n instances: Array<{\n userId: string;\n createdAt: number;\n lastUsed: number;\n age: number;\n idleTime: number;\n }>;\n } {\n const now = Date.now();\n const instances = Array.from(this.serverPool.entries()).map(([userId, instance]) => ({\n userId,\n createdAt: instance.createdAt,\n lastUsed: instance.lastUsed,\n age: now - instance.createdAt,\n idleTime: now - instance.lastUsed\n }));\n \n return {\n size: this.serverPool.size,\n instances\n };\n }\n \n /**\n * Check if server is running\n */\n isServerRunning(): boolean {\n return this.isRunning;\n }\n}\n\n/**\n * Convenience function to create and configure an authenticated server wrapper\n *\n * @param config - Server wrapper configuration\n * @returns Configured AuthenticatedServerWrapper instance\n *\n * @example\n * ```typescript\n * const wrapped = wrapServer({\n * serverFactory: (accessToken, userId) => createMyServer(accessToken, userId),\n * authProvider: new JWTAuthProvider({ jwtSecret: process.env.JWT_SECRET }),\n * tokenResolver: new APITokenResolver({ ... }),\n * resourceType: 'myapi',\n * transport: { type: 'sse', port: 3000 }\n * });\n *\n * await wrapped.start();\n * ```\n */\nexport function wrapServer(config: ServerWrapperConfig): AuthenticatedServerWrapper {\n return new AuthenticatedServerWrapper(config);\n}\n"],
|
|
5
|
+
"mappings": "AAQA,SAAS,4BAA4B;AACrC,SAAS,qCAAqC;AAG9C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAiC;AAC1C;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,uBAAuB;AAChC,SAAS,2BAA2B;AAmC7B,MAAM,2BAA2B;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAqB;AAAA,EACrB;AAAA,EACA,mBAAiD,oBAAI,IAAI;AAAA,EACzD;AAAA,EACA;AAAA,EAER,YAAY,QAA6B;AAEvC,SAAK,eAAe,MAAM;AAG1B,SAAK,SAAS,KAAK,gBAAgB,MAAM;AAGzC,SAAK,SAAS,aAAa,KAAK,OAAO,WAAW,OAAO;AAGzD,SAAK,aAAa,oBAAI,IAAI;AAG1B,QAAI,KAAK,OAAO,iBAAiB,YAAY,KAAK,OAAO,cAAc;AACrE,WAAK,cAAc,IAAI;AAAA,QACrB,KAAK,OAAO;AAAA,QACZ,KAAK;AAAA,MACP;AAEA,WAAK,OAAO,KAAK,qCAAqC;AAAA,QACpD,SAAS,KAAK,OAAO,aAAa;AAAA,QAClC,aAAa,KAAK,OAAO,aAAa;AAAA,QACtC,aAAa,KAAK,OAAO,aAAa;AAAA,MACxC,CAAC;AAAA,IACH;AAGA,SAAK,kBAAkB,IAAI,gBAAgB,KAAK,MAAM;AAGtD,SAAK,kBAAkB,YAAY,MAAM;AACvC,WAAK,gBAAgB,oBAAoB;AAAA,IAC3C,GAAG,GAAK;AAER,SAAK,OAAO,KAAK,sCAAsC;AAAA,MACrD,MAAM,KAAK,OAAO;AAAA,MAClB,cAAc,KAAK,OAAO;AAAA,MAC1B,WAAW,KAAK,OAAO,UAAU;AAAA,MACjC,cAAc,KAAK,OAAO;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,QAAmC;AAExD,QAAI,CAAC,OAAO,eAAe;AACzB,YAAM,IAAI,mBAAmB,2BAA2B;AAAA,IAC1D;AACA,QAAI,CAAC,OAAO,cAAc;AACxB,YAAM,IAAI,mBAAmB,0BAA0B;AAAA,IACzD;AAEA,QAAI,CAAC,OAAO,cAAc;AACxB,YAAM,IAAI,mBAAmB,0BAA0B;AAAA,IACzD;AACA,QAAI,CAAC,OAAO,WAAW;AACrB,YAAM,IAAI,mBAAmB,uBAAuB;AAAA,IACtD;AAEA,yBAAqB,OAAO,YAAY;AACxC,4BAAwB,OAAO,SAAS;AAGxC,QAAI,OAAO,iBAAiB,UAAU;AACpC,UAAI,CAAC,OAAO,cAAc;AACxB,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAEA,6BAAuB,OAAO,aAAa,SAAS,sBAAsB;AAC1E,6BAAuB,OAAO,aAAa,aAAa,0BAA0B;AAClF,6BAAuB,OAAO,aAAa,aAAa,0BAA0B;AAElF,UAAI,OAAO,aAAa,UAAU,GAAG;AACnC,cAAM,IAAI,mBAAmB,yCAAyC;AAAA,MACxE;AAEA,UAAI,OAAO,aAAa,cAAc,KAAM;AAC1C,cAAM,IAAI,mBAAmB,6DAA6D;AAAA,MAC5F;AAEA,UAAI,OAAO,aAAa,cAAc,OAAO,aAAa,aAAa;AACrE,cAAM,IAAI,mBAAmB,iDAAiD;AAAA,MAChF;AAAA,IACF;AAGA,QAAI,OAAO,eAAe;AACxB,WAAK,QAAQ,KAAK,4CAA4C;AAAA,QAC5D,cAAc,OAAO,cAAc,YAAY;AAAA,MACjD,CAAC;AAAA,IACH,OAAO;AACL,WAAK,QAAQ,KAAK,mCAAmC;AAAA,QACnD,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,QAA4D;AAClF,WAAO;AAAA,MACL,eAAe,OAAO;AAAA,MACtB,cAAc,OAAO;AAAA,MACrB,eAAe,OAAO,iBAAiB;AAAA;AAAA,MACvC,cAAc,OAAO;AAAA,MACrB,WAAW,OAAO;AAAA,MAClB,MAAM,OAAO,QAAQ;AAAA,MACrB,SAAS,OAAO,WAAW;AAAA,MAC3B,cAAc,OAAO,gBAAgB;AAAA,MACrC,cAAc,OAAO,gBAAgB;AAAA;AAAA,MACrC,YAAY;AAAA,QACV,WAAW,OAAO,YAAY;AAAA,QAC9B,SAAS,OAAO,YAAY,WAAW,EAAE,SAAS,MAAM,OAAO,OAAO;AAAA,MACxE;AAAA,MACA,SAAS;AAAA,QACP,mBAAmB,OAAO,SAAS,qBAAqB;AAAA,QACxD,eAAe,OAAO,SAAS,iBAAiB;AAAA,QAChD,iBAAiB,OAAO,SAAS,mBAAmB;AAAA,MACtD;AAAA,MACA,kBAAkB,OAAO,oBAAoB;AAAA,MAC7C,eAAe,OAAO,iBAAiB;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAuB;AAC3B,QAAI,KAAK,WAAW;AAClB,YAAM,IAAI,mBAAmB,2BAA2B;AAAA,IAC1D;AAEA,SAAK,OAAO,KAAK,yCAAyC;AAAA,MACxD,MAAM,KAAK,OAAO;AAAA,MAClB,WAAW,KAAK,OAAO,UAAU;AAAA,IACnC,CAAC;AAGD,QAAI,KAAK,OAAO,aAAa,YAAY;AACvC,YAAM,KAAK,OAAO,aAAa,WAAW;AAC1C,WAAK,OAAO,MAAM,2BAA2B;AAAA,IAC/C;AAGA,QAAI,KAAK,OAAO,eAAe;AAC7B,UAAI,KAAK,OAAO,cAAc,YAAY;AACxC,cAAM,KAAK,OAAO,cAAc,WAAW;AAC3C,aAAK,OAAO,MAAM,4BAA4B;AAAA,MAChD;AAAA,IACF,OAAO;AACL,WAAK,OAAO,MAAM,+CAA+C;AAAA,IACnE;AAGA,YAAQ,KAAK,OAAO,UAAU,MAAM;AAAA,MAClC,KAAK;AACH,cAAM,KAAK,oBAAoB;AAC/B;AAAA,MACF,KAAK;AACH,cAAM,KAAK,kBAAkB;AAC7B;AAAA,MACF,KAAK;AACH,cAAM,KAAK,mBAAmB;AAC9B;AAAA,MACF;AACE,cAAM,IAAI,eAAe,+BAA+B,KAAK,OAAO,UAAU,IAAI,EAAE;AAAA,IACxF;AAEA,SAAK,YAAY;AAEjB,SAAK,OAAO,KAAK,uCAAuC;AAAA,MACtD,MAAM,KAAK,OAAO;AAAA,MAClB,WAAW,KAAK,OAAO,UAAU;AAAA,MACjC,MAAM,KAAK,OAAO,UAAU;AAAA,IAC9B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAsB;AAC1B,QAAI,CAAC,KAAK,WAAW;AACnB;AAAA,IACF;AAEA,SAAK,OAAO,KAAK,yBAAyB;AAG1C,QAAI,KAAK,cAAc;AACrB,mBAAa,KAAK,YAAY;AAC9B,WAAK,eAAe;AAAA,IACtB;AAEA,QAAI,KAAK,iBAAiB;AACxB,oBAAc,KAAK,eAAe;AAClC,WAAK,kBAAkB;AAAA,IACzB;AAGA,QAAI,KAAK,aAAa;AACpB,YAAM,KAAK,YAAY,SAAS;AAAA,IAClC;AAGA,QAAI,KAAK,OAAO,iBAAiB,UAAU;AACzC,iBAAW,CAAC,QAAQ,QAAQ,KAAK,KAAK,WAAW,QAAQ,GAAG;AAC1D,YAAI;AACF,gBAAM,SAAS,OAAO,MAAM;AAC5B,eAAK,OAAO,MAAM,iCAAiC,EAAE,OAAO,CAAC;AAAA,QAC/D,SAAS,OAAO;AACd,eAAK,OAAO,MAAM,iCAAiC,OAAgB,EAAE,OAAO,CAAC;AAAA,QAC/E;AAAA,MACF;AACA,WAAK,WAAW,MAAM;AAAA,IACxB;AAGA,QAAI,KAAK,OAAO,aAAa,SAAS;AACpC,YAAM,KAAK,OAAO,aAAa,QAAQ;AACvC,WAAK,OAAO,MAAM,0BAA0B;AAAA,IAC9C;AAGA,QAAI,KAAK,OAAO,eAAe;AAC7B,UAAI,KAAK,OAAO,cAAc,SAAS;AACrC,cAAM,KAAK,OAAO,cAAc,QAAQ;AACxC,aAAK,OAAO,MAAM,2BAA2B;AAAA,MAC/C;AAAA,IACF;AAEA,SAAK,YAAY;AAEjB,SAAK,OAAO,KAAK,wBAAwB;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,QAAgB,eAAsC;AACjF,SAAK,iBAAiB,IAAI,QAAQ,aAAa;AAC/C,SAAK,OAAO,MAAM,2BAA2B,EAAE,QAAQ,cAAc,CAAC;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAmB,QAA6C;AACtE,WAAO,KAAK,iBAAiB,IAAI,MAAM;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,QAAsB;AACjD,SAAK,iBAAiB,OAAO,MAAM;AACnC,SAAK,OAAO,MAAM,4BAA4B,EAAE,OAAO,CAAC;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,iBAAiB,KAAU,KAAU,SAAwC;AACzF,UAAM,gBAAgB,KAAK,OAAO,MAAM,EAAE,WAAW,QAAQ,UAAU,CAAC;AACxE,QAAI;AACJ,UAAM,gBAAgB,IAAI,KAAK,OAAO;AAEtC,QAAI;AAEF,oBAAc,MAAM,wBAAwB;AAC5C,YAAM,aAAa,MAAM,KAAK,OAAO,aAAa,aAAa,OAAO;AAEtE,UAAI,CAAC,WAAW,iBAAiB,CAAC,WAAW,QAAQ;AACnD,sBAAc,KAAK,yBAAyB,EAAE,OAAO,WAAW,MAAM,CAAC;AACvE,cAAM,IAAI,oBAAoB,WAAW,SAAS,uBAAuB;AAAA,MAC3E;AAEA,eAAS,eAAe,WAAW,MAAM;AACzC,oBAAc,MAAM,6BAA6B,EAAE,OAAO,CAAC;AAG3D,UAAI;AAEJ,UAAI,KAAK,OAAO,eAAe;AAE7B,cAAM,gBAAgB,MAAM,KAAK,OAAO,cAAc;AAAA,UACpD;AAAA,UACA,KAAK,OAAO;AAAA,QACd;AAEA,YAAI,CAAC,eAAe;AAClB,wBAAc,KAAK,2BAA2B,EAAE,QAAQ,cAAc,KAAK,OAAO,aAAa,CAAC;AAChG,gBAAM,IAAI,qBAAqB,QAAQ,KAAK,OAAO,YAAY;AAAA,QACjE;AAEA,4BAAoB,aAAa;AACjC,sBAAc;AACd,sBAAc,MAAM,kBAAkB,EAAE,QAAQ,cAAc,KAAK,OAAO,aAAa,CAAC;AAAA,MAC1F,OAAO;AAEL,sBAAc;AACd,sBAAc,MAAM,qCAAqC,EAAE,QAAQ,MAAM,SAAS,CAAC;AAAA,MACrF;AAGA,UAAI,eAAe;AACjB,aAAK,qBAAqB,QAAQ,aAAa;AAG/C,aAAK,gBAAgB,eAAe,QAAQ,eAAe,CAAC,iBAAiB;AAI3E,wBAAc,MAAM,uCAAuC;AAAA,YACzD;AAAA,YACA,eAAe,aAAa;AAAA,YAC5B,UAAU,aAAa;AAAA,YACvB,OAAO,aAAa;AAAA,UACtB,CAAC;AAAA,QACH,CAAC;AAED,sBAAc,MAAM,kDAAkD,EAAE,QAAQ,cAAc,CAAC;AAAA,MACjG;AAGA,YAAM,SAAS,MAAM,KAAK,kBAAkB,QAAQ,aAAa,QAAQ,KAAK;AAG9E,UAAI,eAAe;AACjB,cAAM,uBAAwB,OAAe,cAAc,KAAK,MAAM;AACtE,YAAI,sBAAsB;AACxB,UAAC,OAAe,eAAe,CAAC,WAAgB;AAE9C,gBAAI,OAAO,WAAW,0BAA0B;AAC9C,oBAAM,UAAU,KAAK,gBAAgB;AAAA,gBACnC,OAAO;AAAA,cACT;AAEA,kBAAI,SAAS;AACX,8BAAc,MAAM,mDAAmD;AAAA,kBACrE,eAAe,OAAO,OAAO;AAAA,gBAC/B,CAAC;AACD;AAAA,cACF;AAAA,YACF;AAGA,gBAAI,sBAAsB;AACxB,mCAAqB,MAAM;AAAA,YAC7B;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,oBAAc,MAAM,oCAAoC,EAAE,QAAQ,kBAAkB,CAAC,CAAC,cAAc,CAAC;AAErG,YAAM,YAAY,IAAI,8BAA8B;AAAA,QAClD,oBAAoB;AAAA;AAAA,MACtB,CAAC;AAGD,YAAM,OAAO,QAAQ,SAAS;AAK9B,YAAM,UAAU,cAAc,KAAK,KAAK,IAAI,IAAI;AAEhD,oBAAc,KAAK,gCAAgC;AAAA,QACjD;AAAA,QACA,cAAc,KAAK,OAAO;AAAA,QAC1B,kBAAkB,CAAC,CAAC;AAAA,MACtB,CAAC;AAGD,UAAI,eAAe;AACjB,aAAK,gBAAgB,iBAAiB,aAAa;AACnD,aAAK,qBAAqB,MAAM;AAAA,MAClC;AAAA,IAEF,SAAS,OAAO;AACd,oBAAc,MAAM,+BAA+B,KAAc;AAGjE,UAAI,eAAe;AACjB,aAAK,gBAAgB,iBAAiB,aAAa;AACnD,YAAI,QAAQ;AACV,eAAK,qBAAqB,MAAM;AAAA,QAClC;AAAA,MACF;AAEA,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,kBAAkB,QAAgB,aAAqB,QAAkD;AACrH,QAAI,KAAK,OAAO,iBAAiB,aAAa;AAE5C,WAAK,OAAO,MAAM,sCAAsC,EAAE,OAAO,CAAC;AAClE,aAAO,MAAM,KAAK,OAAO,cAAc,aAAa,QAAQ,MAAM;AAAA,IACpE;AAGA,WAAO,MAAM,KAAK,wBAAwB,QAAQ,aAAa,MAAM;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,wBAAwB,QAAgB,aAAqB,QAAkD;AAE3H,QAAI,KAAK,aAAa;AACpB,aAAO,MAAM,KAAK,YAAY;AAAA,QAC5B;AAAA,QACA;AAAA,QACA,KAAK,OAAO;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAIA,QAAI,KAAK,WAAW,IAAI,MAAM,GAAG;AAC/B,YAAM,WAAW,KAAK,WAAW,IAAI,MAAM;AAG3C,UAAI,SAAS,gBAAgB,aAAa;AACxC,aAAK,OAAO,KAAK,6CAA6C,EAAE,OAAO,CAAC;AACxE,cAAM,SAAS,OAAO,MAAM;AAC5B,aAAK,WAAW,OAAO,MAAM;AAAA,MAC/B,OAAO;AAEL,iBAAS,WAAW,KAAK,IAAI;AAC7B,aAAK,OAAO,MAAM,kCAAkC,EAAE,OAAO,CAAC;AAC9D,eAAO,SAAS;AAAA,MAClB;AAAA,IACF;AAGA,QAAI,KAAK,WAAW,QAAQ,KAAK,OAAO,QAAQ,iBAAiB;AAC/D,WAAK,OAAO,KAAK,uDAAuD;AAAA,QACtE,UAAU,KAAK,WAAW;AAAA,QAC1B,UAAU,KAAK,OAAO,QAAQ;AAAA,MAChC,CAAC;AACD,YAAM,KAAK,oBAAoB;AAAA,IACjC;AAGA,SAAK,OAAO,KAAK,uCAAuC,EAAE,OAAO,CAAC;AAClE,UAAM,SAAS,MAAM,KAAK,OAAO,cAAc,aAAa,QAAQ,MAAM;AAG1E,SAAK,WAAW,IAAI,QAAQ;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,MACpB,UAAU,KAAK,IAAI;AAAA,IACrB,CAAC;AAGD,QAAI,CAAC,KAAK,cAAc;AACtB,WAAK,gBAAgB;AAAA,IACvB;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,sBAAqC;AACjD,QAAI,eAA8B;AAClC,QAAI,aAAa;AAEjB,eAAW,CAAC,QAAQ,QAAQ,KAAK,KAAK,WAAW,QAAQ,GAAG;AAC1D,UAAI,SAAS,WAAW,YAAY;AAClC,qBAAa,SAAS;AACtB,uBAAe;AAAA,MACjB;AAAA,IACF;AAEA,QAAI,cAAc;AAChB,YAAM,WAAW,KAAK,WAAW,IAAI,YAAY;AACjD,YAAM,SAAS,OAAO,MAAM;AAC5B,WAAK,WAAW,OAAO,YAAY;AAEnC,WAAK,OAAO,MAAM,kCAAkC;AAAA,QAClD,QAAQ;AAAA,QACR,KAAK,KAAK,IAAI,IAAI,SAAS;AAAA,MAC7B,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAwB;AAC9B,UAAM,UAAU,KAAK,OAAO,QAAQ;AAEpC,SAAK,eAAe,WAAW,YAAY;AACzC,YAAM,MAAM,KAAK,IAAI;AACrB,YAAM,WAAqB,CAAC;AAE5B,iBAAW,CAAC,QAAQ,QAAQ,KAAK,KAAK,WAAW,QAAQ,GAAG;AAC1D,YAAI,MAAM,SAAS,WAAW,SAAS;AACrC,mBAAS,KAAK,MAAM;AAAA,QACtB;AAAA,MACF;AAEA,iBAAW,UAAU,UAAU;AAC7B,cAAM,WAAW,KAAK,WAAW,IAAI,MAAM;AAC3C,YAAI;AACF,gBAAM,SAAS,OAAO,MAAM;AAC5B,eAAK,WAAW,OAAO,MAAM;AAE7B,eAAK,OAAO,MAAM,mCAAmC;AAAA,YACnD;AAAA,YACA,UAAU,MAAM,SAAS;AAAA,UAC3B,CAAC;AAAA,QACH,SAAS,OAAO;AACd,eAAK,OAAO,MAAM,qCAAqC,OAAgB,EAAE,OAAO,CAAC;AAAA,QACnF;AAAA,MACF;AAGA,UAAI,KAAK,WAAW,OAAO,GAAG;AAC5B,aAAK,gBAAgB;AAAA,MACvB,OAAO;AACL,aAAK,eAAe;AAAA,MACtB;AAAA,IACF,GAAG,OAAO;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,sBAAqC;AACjD,SAAK,OAAO,KAAK,0BAA0B;AAG3C,UAAM,SAAS,GAAG,KAAK,OAAO,aAAa,YAAY,CAAC;AACxD,UAAM,cAAc,QAAQ,IAAI,MAAM;AAEtC,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI;AAAA,QACR,GAAG,MAAM;AAAA,MACX;AAAA,IACF;AAEA,UAAM,SAAS;AAGf,UAAM,SAAS,MAAM,KAAK,OAAO,cAAc,aAAa,MAAM;AAGlE,UAAM,YAAY,IAAI,qBAAqB;AAC3C,UAAM,OAAO,QAAQ,SAAS;AAE9B,SAAK,OAAO,KAAK,2BAA2B,EAAE,OAAO,CAAC;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,oBAAmC;AAC/C,SAAK,OAAO,KAAK,0BAA0B;AAAA,MACzC,MAAM,KAAK,OAAO,UAAU;AAAA,MAC5B,UAAU,KAAK,OAAO,UAAU;AAAA,IAClC,CAAC;AAID,UAAM,UAAU,MAAM,OAAO,SAAS;AACtC,UAAM,MAAM,QAAQ,QAAQ;AAG5B,QAAI,IAAI,QAAQ,KAAK,CAAC;AAGtB,QAAI,KAAK,OAAO,UAAU,MAAM;AAE9B,UAAI,CAAC,KAAK,OAAO,UAAU,YAAY;AACrC,cAAM,IAAI;AAAA,UACR;AAAA,QAGF;AAAA,MACF;AAGA,UAAI,KAAK,OAAO,UAAU,eAAe,KAAK;AAC5C,cAAM,eAAe,QAAQ,IAAI,aAAa;AAE9C,YAAI,cAAc;AAChB,gBAAM,IAAI;AAAA,YACR;AAAA,UAGF;AAAA,QACF;AAEA,aAAK,OAAO;AAAA,UACV;AAAA,UAEA,EAAE,YAAY,KAAK,OAAO,UAAU,WAAW;AAAA,QACjD;AAAA,MACF;AAGA,YAAM,OAAO,MAAM,OAAO,MAAM;AAChC,UAAI,IAAI,KAAK,QAAQ;AAAA,QACnB,QAAQ,KAAK,OAAO,UAAU;AAAA,QAC9B,aAAa;AAAA,QACb,SAAS,CAAC,OAAO,QAAQ,SAAS;AAAA,QAClC,gBAAgB,CAAC,gBAAgB,iBAAiB,cAAc;AAAA,QAChE,gBAAgB,CAAC,cAAc;AAAA,QAC/B,QAAQ;AAAA;AAAA,MACV,CAAC,CAAC;AAEF,WAAK,OAAO,KAAK,gBAAgB;AAAA,QAC/B,QAAQ,KAAK,OAAO,UAAU;AAAA,QAC9B,aAAa;AAAA,MACf,CAAC;AAAA,IACH;AAEA,UAAM,WAAW,KAAK,OAAO,UAAU,YAAY;AAGnD,QAAI,IAAI,UAAU,CAAC,KAAU,QAAa;AACxC,UAAI,KAAK;AAAA,QACP,MAAM,KAAK,OAAO;AAAA,QAClB,SAAS,KAAK,OAAO;AAAA,QACrB,cAAc,KAAK,OAAO;AAAA,QAC1B,WAAW;AAAA,UACT,SAAS,QAAQ,QAAQ;AAAA,UACzB,QAAQ,OAAO,QAAQ;AAAA,QACzB;AAAA,QACA,eAAe;AAAA,MACjB,CAAC;AAAA,IACH,CAAC;AAGD,QAAI,KAAK,GAAG,QAAQ,YAAY,OAAO,KAAU,QAAa;AAC5D,UAAI;AACF,cAAM,UAA0B;AAAA,UAC9B,SAAS,IAAI;AAAA,UACb,WAAW;AAAA,UACX,WAAW,oBAAI,KAAK;AAAA,UACpB,WAAW,IAAI,QAAQ,cAAc;AAAA,UACrC,OAAO,IAAI;AAAA,QACb;AAGA,cAAM,KAAK,iBAAiB,KAAK,KAAK,OAAO;AAAA,MAE/C,SAAS,OAAO;AACd,aAAK,OAAO,MAAM,sBAAsB,KAAc;AAEtD,YAAI,iBAAiB,uBAAuB,iBAAiB,sBAAsB;AACjF,cAAI,OAAO,MAAM,UAAU,EAAE,KAAK;AAAA,YAChC,OAAO,MAAM;AAAA,YACb,MAAM,MAAM;AAAA,UACd,CAAC;AAAA,QACH,OAAO;AACL,cAAI,OAAO,GAAG,EAAE,KAAK;AAAA,YACnB,OAAO;AAAA,YACP,MAAM;AAAA,UACR,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAC;AAGD,QAAI,IAAI,GAAG,QAAQ,mBAAmB,OAAO,KAAU,QAAa;AAClE,UAAI;AAEF,cAAM,UAA0B;AAAA,UAC9B,SAAS,IAAI;AAAA,UACb,WAAW;AAAA,UACX,WAAW,oBAAI,KAAK;AAAA,UACpB,WAAW,IAAI,QAAQ,cAAc;AAAA,QACvC;AAEA,cAAM,aAAa,MAAM,KAAK,OAAO,aAAa,aAAa,OAAO;AAEtE,YAAI,CAAC,WAAW,iBAAiB,CAAC,WAAW,QAAQ;AACnD,iBAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,YAC1B,OAAO;AAAA,YACP,MAAM;AAAA,UACR,CAAC;AAAA,QACH;AAEA,cAAM,SAAS,WAAW;AAG1B,cAAM,cAAc,KAAK,gBAAgB,eAAe,MAAM;AAC9D,cAAM,cAAc,KAAK,gBAAgB,SAAS;AAElD,YAAI,KAAK;AAAA,UACP,MAAM;AAAA,YACJ;AAAA,YACA,GAAG;AAAA,UACL;AAAA,UACA,QAAQ;AAAA,UACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,CAAC;AAAA,MAEH,SAAS,OAAO;AACd,aAAK,OAAO,MAAM,iCAAiC,KAAc;AACjE,YAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UACnB,OAAO;AAAA,UACP,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAGD,QAAI,IAAI,GAAG,QAAQ,qBAAqB,OAAO,KAAU,QAAa;AACpE,UAAI;AAEF,cAAM,UAA0B;AAAA,UAC9B,SAAS,IAAI;AAAA,UACb,WAAW;AAAA,UACX,WAAW,oBAAI,KAAK;AAAA,UACpB,WAAW,IAAI,QAAQ,cAAc;AAAA,QACvC;AAEA,cAAM,aAAa,MAAM,KAAK,OAAO,aAAa,aAAa,OAAO;AAEtE,YAAI,CAAC,WAAW,eAAe;AAC7B,iBAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,YAC1B,OAAO;AAAA,YACP,MAAM;AAAA,UACR,CAAC;AAAA,QACH;AAGA,cAAM,aAAa,KAAK,gBAAgB,cAAc;AACtD,cAAM,SAAS,KAAK,gBAAgB,YAAY;AAEhD,YAAI,KAAK;AAAA,UACP,SAAS;AAAA,UACT;AAAA,UACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,CAAC;AAAA,MAEH,SAAS,OAAO;AACd,aAAK,OAAO,MAAM,mCAAmC,KAAc;AACnE,YAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UACnB,OAAO;AAAA,UACP,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAGD,QAAI,IAAI,GAAG,QAAQ,WAAW,CAAC,KAAU,QAAa;AACpD,UAAI,KAAK;AAAA,QACP,QAAQ;AAAA,QACR,MAAM,KAAK,OAAO;AAAA,QAClB,SAAS,KAAK,OAAO;AAAA,QACrB,cAAc,KAAK,OAAO;AAAA,QAC1B,cAAc,KAAK,OAAO;AAAA,QAC1B,UAAU,KAAK,WAAW;AAAA,MAC5B,CAAC;AAAA,IACH,CAAC;AAGD,UAAM,OAAO,KAAK,OAAO,UAAU,QAAQ;AAC3C,UAAM,OAAO,KAAK,OAAO,UAAU,QAAQ;AAE3C,UAAM,IAAI,QAAc,CAAC,YAAY;AACnC,UAAI,OAAO,MAAM,MAAM,MAAM;AAC3B,aAAK,OAAO,KAAK,2BAA2B;AAAA,UAC1C;AAAA,UACA;AAAA,UACA;AAAA,UACA,KAAK,UAAU,IAAI,IAAI,IAAI,GAAG,QAAQ;AAAA,QACxC,CAAC;AACD,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,qBAAoC;AAChD,SAAK,OAAO,KAAK,2BAA2B;AAAA,MAC1C,MAAM,KAAK,OAAO,UAAU;AAAA,IAC9B,CAAC;AAID,UAAM,KAAK,kBAAkB;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,eASE;AACA,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,YAAY,MAAM,KAAK,KAAK,WAAW,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,QAAQ,QAAQ,OAAO;AAAA,MACnF;AAAA,MACA,WAAW,SAAS;AAAA,MACpB,UAAU,SAAS;AAAA,MACnB,KAAK,MAAM,SAAS;AAAA,MACpB,UAAU,MAAM,SAAS;AAAA,IAC3B,EAAE;AAEF,WAAO;AAAA,MACL,MAAM,KAAK,WAAW;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,kBAA2B;AACzB,WAAO,KAAK;AAAA,EACd;AACF;AAqBO,SAAS,WAAW,QAAyD;AAClF,SAAO,IAAI,2BAA2B,MAAM;AAC9C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|