@fragno-dev/mcp-fragment 0.0.0-stage → 0.0.3

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.
Files changed (90) hide show
  1. package/LICENSE.md +16 -0
  2. package/README.md +312 -2
  3. package/bin/run.js +7 -0
  4. package/dist/browser/client/react.d.ts +253 -0
  5. package/dist/browser/client/react.d.ts.map +1 -0
  6. package/dist/browser/client/react.js +194 -0
  7. package/dist/browser/client/react.js.map +1 -0
  8. package/dist/browser/client/solid.d.ts +256 -0
  9. package/dist/browser/client/solid.d.ts.map +1 -0
  10. package/dist/browser/client/solid.js +129 -0
  11. package/dist/browser/client/solid.js.map +1 -0
  12. package/dist/browser/client/svelte.d.ts +256 -0
  13. package/dist/browser/client/svelte.d.ts.map +1 -0
  14. package/dist/browser/client/svelte.js +131 -0
  15. package/dist/browser/client/svelte.js.map +1 -0
  16. package/dist/browser/client/vanilla.d.ts +283 -0
  17. package/dist/browser/client/vanilla.d.ts.map +1 -0
  18. package/dist/browser/client/vanilla.js +159 -0
  19. package/dist/browser/client/vanilla.js.map +1 -0
  20. package/dist/browser/client/vue.d.ts +256 -0
  21. package/dist/browser/client/vue.d.ts.map +1 -0
  22. package/dist/browser/client/vue.js +127 -0
  23. package/dist/browser/client/vue.js.map +1 -0
  24. package/dist/browser/client-BCzNDSlW.d.ts +711 -0
  25. package/dist/browser/client-BCzNDSlW.d.ts.map +1 -0
  26. package/dist/browser/index.d.ts +813 -0
  27. package/dist/browser/index.d.ts.map +1 -0
  28. package/dist/browser/index.js +1 -0
  29. package/dist/browser/src-B6dHZXqB.js +2303 -0
  30. package/dist/browser/src-B6dHZXqB.js.map +1 -0
  31. package/dist/cli/cli.d.ts +6 -0
  32. package/dist/cli/cli.d.ts.map +1 -0
  33. package/dist/cli/cli.js +227 -0
  34. package/dist/cli/cli.js.map +1 -0
  35. package/dist/cli/definition.js +330 -0
  36. package/dist/cli/definition.js.map +1 -0
  37. package/dist/cli/diagnostics.js +93 -0
  38. package/dist/cli/diagnostics.js.map +1 -0
  39. package/dist/cli/index.js +13 -0
  40. package/dist/cli/index.js.map +1 -0
  41. package/dist/cli/mcp-api.js +87 -0
  42. package/dist/cli/mcp-api.js.map +1 -0
  43. package/dist/cli/mcp-types.js +100 -0
  44. package/dist/cli/mcp-types.js.map +1 -0
  45. package/dist/cli/oauth-provider.js +113 -0
  46. package/dist/cli/oauth-provider.js.map +1 -0
  47. package/dist/cli/routes.js +743 -0
  48. package/dist/cli/routes.js.map +1 -0
  49. package/dist/cli/schema.js +13 -0
  50. package/dist/cli/schema.js.map +1 -0
  51. package/dist/cli/services.js +330 -0
  52. package/dist/cli/services.js.map +1 -0
  53. package/dist/node/definition.d.ts +260 -0
  54. package/dist/node/definition.d.ts.map +1 -0
  55. package/dist/node/definition.js +330 -0
  56. package/dist/node/definition.js.map +1 -0
  57. package/dist/node/diagnostics.js +93 -0
  58. package/dist/node/diagnostics.js.map +1 -0
  59. package/dist/node/index.d.ts +694 -0
  60. package/dist/node/index.d.ts.map +1 -0
  61. package/dist/node/index.js +26 -0
  62. package/dist/node/index.js.map +1 -0
  63. package/dist/node/mcp-api.d.ts +2 -0
  64. package/dist/node/mcp-api.js +87 -0
  65. package/dist/node/mcp-api.js.map +1 -0
  66. package/dist/node/mcp-types.d.ts +146 -0
  67. package/dist/node/mcp-types.d.ts.map +1 -0
  68. package/dist/node/mcp-types.js +100 -0
  69. package/dist/node/mcp-types.js.map +1 -0
  70. package/dist/node/oauth-provider.d.ts +24 -0
  71. package/dist/node/oauth-provider.d.ts.map +1 -0
  72. package/dist/node/oauth-provider.js +113 -0
  73. package/dist/node/oauth-provider.js.map +1 -0
  74. package/dist/node/routes.d.ts +466 -0
  75. package/dist/node/routes.d.ts.map +1 -0
  76. package/dist/node/routes.js +743 -0
  77. package/dist/node/routes.js.map +1 -0
  78. package/dist/node/schema.d.ts +9 -0
  79. package/dist/node/schema.d.ts.map +1 -0
  80. package/dist/node/schema.js +13 -0
  81. package/dist/node/schema.js.map +1 -0
  82. package/dist/node/services.d.ts +40 -0
  83. package/dist/node/services.d.ts.map +1 -0
  84. package/dist/node/services.js +330 -0
  85. package/dist/node/services.js.map +1 -0
  86. package/dist/node/testing/mcp-test-server.d.ts +42 -0
  87. package/dist/node/testing/mcp-test-server.d.ts.map +1 -0
  88. package/dist/node/testing/mcp-test-server.js +218 -0
  89. package/dist/node/testing/mcp-test-server.js.map +1 -0
  90. package/package.json +130 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","names":[],"sources":["../../src/routes.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport { defineRoutes } from \"@fragno-dev/core\";\n\nimport { mcpFragmentDefinition, scheduleMcpAuthExpiry } from \"./definition\";\nimport { buildAuthDiagnostics, errorMessage, refreshOutputSchema } from \"./diagnostics\";\nimport {\n assertAllowedEndpoint,\n callMcpTool,\n stringifySecretPayload,\n listMcpTools,\n} from \"./mcp-api\";\nimport {\n createServerInputSchema,\n MCP_OAUTH_REDIRECT_URI_QUERY_PARAMETER,\n mcpAuthStatusSchema,\n mcpOAuthPendingSchema,\n mcpOAuthRedirectUriSchema,\n mcpToolCallResultSchema,\n mcpToolSchema,\n oauthStartInputSchema,\n replaceServerConfigurationInputSchema,\n tokenAuthInputSchema,\n toolCallInputSchema,\n type AuthConfig,\n type McpTool,\n} from \"./mcp-types\";\nimport { mcpSchema } from \"./schema\";\nimport {\n createMcpOperationAuth,\n isMcpAuthReady,\n projectMcpAuthStatus,\n pendingOAuthLink,\n withoutOAuthConsent,\n writeOAuthSecretChanges,\n type AuthPersistenceChanges,\n} from \"./services\";\n\nconst serverConnectionCacheOutputSchema = z.object({\n protocolVersion: z.string().nullable().optional(),\n serverInfo: z.unknown().nullable().optional(),\n capabilities: z.unknown().nullable().optional(),\n tools: z.array(mcpToolSchema).nullable().optional(),\n updatedAt: z.union([z.string(), z.date()]).optional(),\n});\n\nconst serverOutputSchema = z.object({\n slug: z.string(),\n name: z.string().nullable().optional(),\n endpointUrl: z.string(),\n authMode: z.string(),\n cache: serverConnectionCacheOutputSchema.nullable().optional(),\n});\n\nfunction publicServer(\n server: {\n id: { toString(): string } | string;\n name?: string | null;\n endpointUrl: string;\n authMode: string;\n },\n cache?: {\n protocolVersion?: string | null;\n serverInfo?: unknown;\n capabilities?: unknown;\n tools?: unknown;\n updatedAt?: Date;\n } | null,\n) {\n return {\n slug: server.id.toString(),\n name: server.name,\n endpointUrl: server.endpointUrl,\n authMode: server.authMode,\n ...(cache\n ? {\n cache: {\n protocolVersion: cache.protocolVersion ?? null,\n serverInfo: cache.serverInfo ?? null,\n capabilities: cache.capabilities ?? null,\n // Cached tools come from the SDK's validated tools/list result.\n tools: Array.isArray(cache.tools) ? (cache.tools as McpTool[]) : null,\n updatedAt: cache.updatedAt,\n },\n }\n : {}),\n };\n}\n\nfunction authMode(auth: AuthConfig) {\n return auth.type;\n}\n\nexport const mcpRoutesFactory = defineRoutes(mcpFragmentDefinition).create(\n ({ services, defineRoute, config }) => {\n return [\n defineRoute({\n method: \"POST\",\n path: \"/servers\",\n inputSchema: createServerInputSchema,\n outputSchema: serverOutputSchema,\n errorCodes: [\"SERVER_EXISTS\", \"ENDPOINT_NOT_ALLOWED\"],\n handler: async function ({ input }, { json, error }) {\n const body = await input.valid();\n try {\n assertAllowedEndpoint(body.endpointUrl, config);\n } catch (err) {\n return error({ code: \"ENDPOINT_NOT_ALLOWED\", message: (err as Error).message }, 400);\n }\n\n const payload = body.auth.type === \"none\" ? undefined : stringifySecretPayload(body.auth);\n\n const result = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema).findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", body.slug)),\n ),\n )\n .mutate(({ forSchema, retrieveResult: [existing] }) => {\n if (existing) {\n return { exists: true as const };\n }\n\n const uow = forSchema(mcpSchema);\n uow.create(\"server_configuration\", {\n id: body.slug,\n name: body.name ?? null,\n endpointUrl: body.endpointUrl,\n authMode: authMode(body.auth),\n });\n if (payload) {\n uow.create(\"secret\", {\n id: `${body.slug}:auth`,\n serverId: body.slug,\n kind: \"auth\",\n payload,\n expiresAt: null,\n });\n }\n if (body.auth.type !== \"oauth\") {\n uow.triggerHook(\"internalRefreshServerConfiguration\", { serverId: body.slug });\n }\n uow.triggerHook(\"onServerReadinessChanged\", {\n serverId: body.slug,\n ready: isMcpAuthReady(\n authMode(body.auth),\n payload === undefined ? undefined : { payload, expiresAt: null },\n ),\n });\n return { exists: false as const };\n })\n .execute();\n\n if (result.exists) {\n return error({ code: \"SERVER_EXISTS\", message: \"MCP server already exists\" }, 409);\n }\n\n return json(publicServer({ ...body, id: body.slug, authMode: authMode(body.auth) }), 201);\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/servers\",\n outputSchema: z.object({ servers: z.array(serverOutputSchema) }),\n handler: async function (_, { json }) {\n const [servers, caches] = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema)\n .find(\"server_configuration\", (b) => b.whereIndex(\"primary\"))\n .find(\"server_connection_cache\", (b) => b.whereIndex(\"primary\")),\n )\n .execute();\n const cacheByServerId = new Map(caches.map((cache) => [cache.id.toString(), cache]));\n return json({\n servers: servers.map((server) =>\n publicServer(server, cacheByServerId.get(server.id.toString())),\n ),\n });\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/servers/:slug\",\n outputSchema: serverOutputSchema,\n errorCodes: [\"SERVER_NOT_FOUND\"],\n handler: async function ({ pathParams }, { json, error }) {\n const [server, cache] = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema)\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n )\n .findFirst(\"server_connection_cache\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n ),\n )\n .execute();\n if (!server) {\n return error({ code: \"SERVER_NOT_FOUND\", message: \"MCP server not found\" }, 404);\n }\n return json(publicServer(server, cache));\n },\n }),\n\n defineRoute({\n method: \"PUT\",\n path: \"/servers/:slug/configuration\",\n inputSchema: replaceServerConfigurationInputSchema,\n outputSchema: serverOutputSchema,\n errorCodes: [\"SERVER_NOT_FOUND\", \"ENDPOINT_NOT_ALLOWED\"],\n handler: async function ({ input, pathParams }, { json, error }) {\n const body = await input.valid();\n try {\n assertAllowedEndpoint(body.endpointUrl, config);\n } catch (err) {\n return error({ code: \"ENDPOINT_NOT_ALLOWED\", message: (err as Error).message }, 400);\n }\n const payload = body.auth.type === \"none\" ? null : stringifySecretPayload(body.auth);\n const result = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema)\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n )\n .find(\"secret\", (b) =>\n b.whereIndex(\"idx_secret_server_kind\", (eb) =>\n eb(\"serverId\", \"=\", pathParams.slug),\n ),\n )\n .find(\"oauthState\", (b) =>\n b.whereIndex(\"idx_oauth_state_server\", (eb) =>\n eb(\"serverId\", \"=\", pathParams.slug),\n ),\n )\n .findFirst(\"server_connection_cache\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n ),\n )\n .mutate(({ forSchema, retrieveResult: [server, secrets, oauthStates, cache] }) => {\n if (!server) {\n return { server: null };\n }\n const uow = forSchema(mcpSchema);\n const replaced = {\n ...server,\n name: body.name ?? null,\n endpointUrl: body.endpointUrl,\n authMode: authMode(body.auth),\n };\n uow.update(\"server_configuration\", server.id, (b) =>\n b\n .set({\n name: replaced.name,\n endpointUrl: replaced.endpointUrl,\n authMode: replaced.authMode,\n updatedAt: b.now(),\n })\n .check(),\n );\n // Tokens, registered clients, discovery state, and pending links belong to the old\n // endpoint and credentials, so only the replacement auth survives.\n const authSecret = secrets.find((secret) => secret.kind === \"auth\");\n for (const secret of secrets) {\n if (secret !== authSecret || payload === null) {\n uow.delete(\"secret\", secret.id);\n }\n }\n if (payload !== null) {\n if (authSecret) {\n uow.update(\"secret\", authSecret.id, (b) =>\n b.set({ payload, expiresAt: null, updatedAt: b.now() }).check(),\n );\n } else {\n uow.create(\"secret\", {\n id: `${pathParams.slug}:auth`,\n serverId: pathParams.slug,\n kind: \"auth\",\n payload,\n expiresAt: null,\n });\n }\n }\n for (const oauthState of oauthStates) {\n uow.delete(\"oauthState\", oauthState.id);\n }\n if (cache) {\n uow.delete(\"server_connection_cache\", cache.id);\n }\n if (body.auth.type !== \"oauth\") {\n uow.triggerHook(\"internalRefreshServerConfiguration\", {\n serverId: pathParams.slug,\n });\n }\n const ready = isMcpAuthReady(\n replaced.authMode,\n payload === null ? undefined : { payload, expiresAt: null },\n );\n if (ready !== isMcpAuthReady(server.authMode, authSecret)) {\n uow.triggerHook(\"onServerReadinessChanged\", { serverId: pathParams.slug, ready });\n }\n return { server: replaced };\n })\n .execute();\n if (!result.server) {\n return error({ code: \"SERVER_NOT_FOUND\", message: \"MCP server not found\" }, 404);\n }\n return json(publicServer(result.server));\n },\n }),\n\n defineRoute({\n method: \"DELETE\",\n path: \"/servers/:slug\",\n errorCodes: [\"SERVER_NOT_FOUND\"],\n handler: async function ({ pathParams }, { empty, error }) {\n const result = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema)\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n )\n .find(\"secret\", (b) =>\n b.whereIndex(\"idx_secret_server_kind\", (eb) =>\n eb(\"serverId\", \"=\", pathParams.slug),\n ),\n )\n .find(\"oauthState\", (b) =>\n b.whereIndex(\"idx_oauth_state_server\", (eb) =>\n eb(\"serverId\", \"=\", pathParams.slug),\n ),\n )\n .findFirst(\"server_connection_cache\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n ),\n )\n .mutate(({ forSchema, retrieveResult: [server, secrets, oauthStates, cache] }) => {\n if (!server) {\n return { deleted: false as const };\n }\n const uow = forSchema(mcpSchema);\n for (const secret of secrets) {\n uow.delete(\"secret\", secret.id);\n }\n for (const oauthState of oauthStates) {\n uow.delete(\"oauthState\", oauthState.id);\n }\n if (cache) {\n uow.delete(\"server_connection_cache\", cache.id);\n }\n uow.delete(\"server_configuration\", server.id);\n uow.triggerHook(\"onServerConfigurationDeleted\", { serverId: pathParams.slug });\n return { deleted: true as const };\n })\n .execute();\n if (!result.deleted) {\n return error({ code: \"SERVER_NOT_FOUND\", message: \"MCP server not found\" }, 404);\n }\n return empty(204);\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/servers/:slug/auth/status\",\n outputSchema: mcpAuthStatusSchema,\n errorCodes: [\"SERVER_NOT_FOUND\"],\n handler: async function ({ pathParams }, { json, error }) {\n const [server, secret, pendingState] = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema)\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n )\n .findFirst(\"secret\", (b) =>\n b.whereIndex(\"idx_secret_server_kind\", (eb) =>\n eb.and(eb(\"serverId\", \"=\", pathParams.slug), eb(\"kind\", \"=\", \"auth\")),\n ),\n )\n .findFirst(\"oauthState\", (b) =>\n b\n .whereIndex(\"idx_oauth_state_pending\", (eb) =>\n eb.and(\n eb(\"serverId\", \"=\", pathParams.slug),\n eb.isNull(\"consumedAt\"),\n eb(\"expiresAt\", \">\", eb.now()),\n ),\n )\n .orderByIndex(\"idx_oauth_state_pending\", \"desc\"),\n ),\n )\n .execute();\n if (!server) {\n return error({ code: \"SERVER_NOT_FOUND\", message: \"MCP server not found\" }, 404);\n }\n return json(\n projectMcpAuthStatus({\n authMode: server.authMode,\n authSecret: secret ?? undefined,\n hasPendingOAuth: pendingOAuthLink(pendingState) !== null,\n }),\n );\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/servers/:slug/auth/pending\",\n outputSchema: mcpOAuthPendingSchema,\n errorCodes: [\"SERVER_NOT_FOUND\"],\n handler: async function ({ pathParams }, { json, error }) {\n const [server, pendingState] = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema)\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n )\n .findFirst(\"oauthState\", (b) =>\n b\n .whereIndex(\"idx_oauth_state_pending\", (eb) =>\n eb.and(\n eb(\"serverId\", \"=\", pathParams.slug),\n eb.isNull(\"consumedAt\"),\n eb(\"expiresAt\", \">\", eb.now()),\n ),\n )\n .orderByIndex(\"idx_oauth_state_pending\", \"desc\"),\n ),\n )\n .execute();\n if (!server) {\n return error({ code: \"SERVER_NOT_FOUND\", message: \"MCP server not found\" }, 404);\n }\n return json({ pending: pendingOAuthLink(pendingState) });\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/servers/:slug/auth/token\",\n inputSchema: tokenAuthInputSchema,\n outputSchema: mcpAuthStatusSchema,\n errorCodes: [\"SERVER_NOT_FOUND\"],\n handler: async function ({ input, pathParams }, { json, error }) {\n const { token } = await input.valid();\n const payload = stringifySecretPayload({ type: \"bearer\", token });\n const result = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema)\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n )\n .findFirst(\"secret\", (b) =>\n b.whereIndex(\"idx_secret_server_kind\", (eb) =>\n eb.and(eb(\"serverId\", \"=\", pathParams.slug), eb(\"kind\", \"=\", \"auth\")),\n ),\n )\n .findFirst(\"server_connection_cache\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n ),\n )\n .mutate(({ forSchema, retrieveResult: [server, secret, cache] }) => {\n if (!server) {\n return { found: false as const };\n }\n const uow = forSchema(mcpSchema);\n uow.update(\"server_configuration\", server.id, (b) =>\n b.set({ authMode: \"bearer\", updatedAt: b.now() }).check(),\n );\n if (cache) {\n uow.delete(\"server_connection_cache\", cache.id);\n }\n if (secret) {\n uow.update(\"secret\", secret.id, (b) =>\n b.set({ payload, expiresAt: null, updatedAt: b.now() }).check(),\n );\n } else {\n uow.create(\"secret\", {\n id: `${pathParams.slug}:auth`,\n serverId: pathParams.slug,\n kind: \"auth\",\n payload,\n expiresAt: null,\n });\n }\n uow.triggerHook(\"internalRefreshServerConfiguration\", { serverId: pathParams.slug });\n if (!isMcpAuthReady(server.authMode, secret ?? undefined)) {\n uow.triggerHook(\"onServerReadinessChanged\", {\n serverId: pathParams.slug,\n ready: true,\n });\n }\n return { found: true as const };\n })\n .execute();\n if (!result.found) {\n return error({ code: \"SERVER_NOT_FOUND\", message: \"MCP server not found\" }, 404);\n }\n return json({ mode: \"bearer\" as const, credentials: \"present\" as const });\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/servers/:slug/auth/start\",\n inputSchema: oauthStartInputSchema,\n outputSchema: z.object({ authorizationUrl: z.string(), state: z.string() }),\n queryParameters: [MCP_OAUTH_REDIRECT_URI_QUERY_PARAMETER],\n errorCodes: [\n \"INVALID_OAUTH_REDIRECT_URI\",\n \"OAUTH_REDIRECT_URI_NOT_ALLOWED\",\n \"SERVER_NOT_FOUND\",\n \"OAUTH_ERROR\",\n ],\n handler: async function ({ input, pathParams, query }, { json, error }) {\n const body = await input.valid();\n const redirectUri = mcpOAuthRedirectUriSchema.safeParse(\n query.get(MCP_OAUTH_REDIRECT_URI_QUERY_PARAMETER),\n );\n if (!redirectUri.success) {\n return error(\n {\n code: \"INVALID_OAUTH_REDIRECT_URI\",\n message: \"MCP OAuth redirect URI must be an HTTP or HTTPS URL\",\n },\n 400,\n );\n }\n const oauthRedirectUri = new URL(redirectUri.data);\n if (!config.allowedOAuthRedirectUris?.(oauthRedirectUri)) {\n return error(\n {\n code: \"OAUTH_REDIRECT_URI_NOT_ALLOWED\",\n message: \"MCP OAuth redirect URI is not allowed by the fragment configuration\",\n },\n 400,\n );\n }\n const state = `${pathParams.slug}:${crypto.randomUUID()}`;\n try {\n const [result] = await this.handlerTx()\n .withServiceCalls(\n () =>\n [\n services.startOAuth({\n serverId: pathParams.slug,\n stateId: state,\n redirectUri: oauthRedirectUri.toString(),\n scope: body.scope,\n clientId: body.clientId,\n clientSecret: body.clientSecret,\n discardTokens: body.discardTokens,\n }),\n ] as const,\n )\n .execute();\n if (!result.found) {\n return error({ code: \"SERVER_NOT_FOUND\", message: \"MCP server not found\" }, 404);\n }\n return json({ authorizationUrl: result.authorizationUrl, state });\n } catch (err) {\n return error({ code: \"OAUTH_ERROR\", message: (err as Error).message }, 502);\n }\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/oauth/callback\",\n outputSchema: z.object({ authenticated: z.boolean(), mode: z.string() }),\n errorCodes: [\"SERVER_NOT_FOUND\", \"OAUTH_ERROR\", \"INVALID_OAUTH_STATE\"],\n handler: async function ({ query }, { json, error }) {\n const code = query.get(\"code\");\n const stateId = query.get(\"state\");\n if (!code || !stateId) {\n return error(\n { code: \"INVALID_OAUTH_STATE\", message: \"Missing OAuth code or state\" },\n 400,\n );\n }\n try {\n const [result] = await this.handlerTx()\n .withServiceCalls(\n () =>\n [\n services.completeOAuthCallback({\n stateId,\n code,\n iss: query.get(\"iss\") ?? undefined,\n }),\n ] as const,\n )\n .execute();\n if (!result.found) {\n if (result.reason === \"server_not_found\") {\n return error({ code: \"SERVER_NOT_FOUND\", message: \"MCP server not found\" }, 404);\n }\n return error({ code: \"INVALID_OAUTH_STATE\", message: \"Invalid OAuth state\" }, 400);\n }\n return json({ authenticated: true, mode: \"oauth\" });\n } catch (err) {\n return error({ code: \"OAUTH_ERROR\", message: (err as Error).message }, 502);\n }\n },\n }),\n\n defineRoute({\n method: \"DELETE\",\n path: \"/servers/:slug/auth\",\n outputSchema: mcpAuthStatusSchema,\n errorCodes: [\"SERVER_NOT_FOUND\"],\n handler: async function ({ pathParams }, { json, error }) {\n const result = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema)\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n )\n .find(\"secret\", (b) =>\n b.whereIndex(\"idx_secret_server_kind\", (eb) =>\n eb(\"serverId\", \"=\", pathParams.slug),\n ),\n )\n .find(\"oauthState\", (b) =>\n b.whereIndex(\"idx_oauth_state_server\", (eb) =>\n eb(\"serverId\", \"=\", pathParams.slug),\n ),\n )\n .findFirst(\"server_connection_cache\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n ),\n )\n .mutate(({ forSchema, retrieveResult: [server, secrets, oauthStates, cache] }) => {\n if (!server) {\n return { found: false as const };\n }\n const uow = forSchema(mcpSchema);\n const authSecret = secrets.find((secret) => secret.kind === \"auth\");\n // Only OAuth consent is cleared: the registered client and discovery state stay usable.\n const remainingAuth =\n server.authMode === \"oauth\" && authSecret\n ? { payload: withoutOAuthConsent(authSecret.payload), expiresAt: null }\n : undefined;\n if (server.authMode === \"oauth\") {\n if (authSecret && remainingAuth) {\n uow.update(\"secret\", authSecret.id, (b) =>\n b\n .set({ payload: remainingAuth.payload, expiresAt: null, updatedAt: b.now() })\n .check(),\n );\n }\n } else {\n for (const secret of secrets) {\n uow.delete(\"secret\", secret.id);\n }\n }\n const ready = isMcpAuthReady(server.authMode, remainingAuth);\n if (ready !== isMcpAuthReady(server.authMode, authSecret)) {\n uow.triggerHook(\"onServerReadinessChanged\", { serverId: pathParams.slug, ready });\n }\n for (const oauthState of oauthStates) {\n uow.delete(\"oauthState\", oauthState.id);\n }\n if (cache) {\n uow.delete(\"server_connection_cache\", cache.id);\n }\n // Keep the mode: clearing credentials must not turn the server unauthenticated.\n uow.update(\"server_configuration\", server.id, (b) =>\n b.set({ updatedAt: b.now() }).check(),\n );\n return {\n found: true as const,\n status: projectMcpAuthStatus({\n authMode: server.authMode,\n authSecret: undefined,\n hasPendingOAuth: false,\n }),\n };\n })\n .execute();\n if (!result.found) {\n return error({ code: \"SERVER_NOT_FOUND\", message: \"MCP server not found\" }, 404);\n }\n return json(result.status);\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/servers/:slug/refresh\",\n outputSchema: refreshOutputSchema,\n errorCodes: [\"SERVER_NOT_FOUND\"],\n handler: async function ({ pathParams }, { json, error }) {\n const checkedAt = new Date().toISOString();\n let prepared:\n | {\n authChanges?: AuthPersistenceChanges;\n toolsOperation: Awaited<ReturnType<typeof listMcpTools<AuthPersistenceChanges>>>;\n }\n | undefined;\n let authError: unknown;\n\n const result = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema)\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n )\n .find(\"secret\", (b) =>\n b.whereIndex(\"idx_secret_server_kind\", (eb) =>\n eb(\"serverId\", \"=\", pathParams.slug),\n ),\n )\n .findFirst(\"server_connection_cache\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n )\n .find(\"oauthState\", (b) =>\n b.whereIndex(\"idx_oauth_state_server\", (eb) =>\n eb(\"serverId\", \"=\", pathParams.slug),\n ),\n ),\n )\n .afterRetrieve(async (_uow, [server, secrets]) => {\n if (!server) {\n return;\n }\n\n try {\n const auth = await createMcpOperationAuth({ config, server, secrets });\n const toolsOperation = await listMcpTools({\n endpointUrl: server.endpointUrl,\n auth,\n fetchImplementation: config.fetch,\n });\n prepared = {\n authChanges: toolsOperation.authChanges,\n toolsOperation,\n };\n } catch (err) {\n authError = err;\n }\n })\n .mutate(({ forSchema, retrieveResult: [server, secrets, cache, oauthStates] }) => {\n if (!server) {\n return { found: false as const };\n }\n\n const serverId = server.id.toString();\n const previousTools = Array.isArray(cache?.tools) ? cache.tools : null;\n const baseDiagnostics = {\n checkedAt,\n server: publicServer(server),\n cache: {\n presentBeforeCheck: Boolean(cache),\n previousToolCount: previousTools?.length ?? null,\n updatedToolCount: null,\n },\n };\n\n if (authError) {\n return {\n found: true as const,\n refresh: {\n ...baseDiagnostics,\n ok: false,\n tools: [],\n stage: \"auth\" as const,\n auth: buildAuthDiagnostics({\n mode: server.authMode,\n secrets,\n oauthStates,\n }),\n live: {\n reachable: false,\n listToolsOk: false,\n toolCount: null,\n protocolVersion: null,\n serverInfo: null,\n capabilities: null,\n },\n error: { code: \"AUTH_ERROR\", message: errorMessage(authError) },\n },\n };\n }\n\n if (!prepared) {\n throw new Error(\"MCP refresh operation was not prepared\");\n }\n\n const preparedOperation = prepared;\n const uow = forSchema(mcpSchema);\n const upsertSecret = (kind: string, payload: string, expiresAt: Date | null) => {\n const existing = secrets.find((secret) => secret.kind === kind);\n if (existing) {\n uow.update(\"secret\", existing.id, (b) =>\n b.set({ payload, expiresAt, updatedAt: b.now() }).check(),\n );\n return;\n }\n uow.create(\"secret\", {\n id: `${serverId}:${kind}`,\n serverId,\n kind,\n payload,\n expiresAt,\n });\n };\n\n if (preparedOperation.authChanges) {\n writeOAuthSecretChanges(preparedOperation.authChanges, {\n upsert: (kind, payload) => {\n upsertSecret(kind, payload, null);\n },\n remove: (kind) => {\n const existing = secrets.find((secret) => secret.kind === kind);\n if (existing) {\n uow.delete(\"secret\", existing.id);\n }\n },\n });\n }\n if (preparedOperation.authChanges?.authPayload) {\n const after = {\n payload: preparedOperation.authChanges.authPayload,\n expiresAt: preparedOperation.authChanges.authExpiresAt ?? null,\n };\n upsertSecret(\"auth\", after.payload, after.expiresAt);\n const before = secrets.find((secret) => secret.kind === \"auth\");\n const ready = isMcpAuthReady(server.authMode, after);\n if (ready !== isMcpAuthReady(server.authMode, before)) {\n uow.triggerHook(\"onServerReadinessChanged\", { serverId, ready });\n }\n scheduleMcpAuthExpiry(uow, serverId, server.authMode, after);\n }\n\n const auth = buildAuthDiagnostics({\n mode: server.authMode,\n secrets,\n oauthStates,\n authChanges: preparedOperation.authChanges,\n });\n\n if (!preparedOperation.toolsOperation.ok) {\n return {\n found: true as const,\n refresh: {\n ...baseDiagnostics,\n ok: false,\n tools: [],\n stage: \"list_tools\" as const,\n auth,\n live: {\n reachable: false,\n listToolsOk: false,\n toolCount: null,\n protocolVersion: null,\n serverInfo: null,\n capabilities: null,\n },\n error: {\n code: \"MCP_ERROR\",\n message: errorMessage(preparedOperation.toolsOperation.error),\n },\n },\n };\n }\n\n const tools = Array.isArray(preparedOperation.toolsOperation.result.tools)\n ? preparedOperation.toolsOperation.result.tools\n : [];\n if (!previousTools || JSON.stringify(previousTools) !== JSON.stringify(tools)) {\n uow.triggerHook(\"onServerConfigurationChanged\", {\n serverId,\n current: { tools },\n });\n }\n uow.delete(\"server_connection_cache\", serverId);\n uow.create(\"server_connection_cache\", {\n id: serverId,\n serverId,\n protocolVersion: preparedOperation.toolsOperation.metadata.protocolVersion ?? null,\n serverInfo: preparedOperation.toolsOperation.metadata.serverInfo ?? null,\n capabilities: preparedOperation.toolsOperation.metadata.capabilities ?? null,\n tools,\n });\n\n return {\n found: true as const,\n refresh: {\n ...baseDiagnostics,\n ok: true,\n tools,\n stage: null,\n auth,\n live: {\n reachable: true,\n listToolsOk: true,\n toolCount: tools.length,\n protocolVersion:\n preparedOperation.toolsOperation.metadata.protocolVersion ?? null,\n serverInfo: preparedOperation.toolsOperation.metadata.serverInfo ?? null,\n capabilities: preparedOperation.toolsOperation.metadata.capabilities ?? null,\n },\n cache: {\n ...baseDiagnostics.cache,\n updatedToolCount: tools.length,\n },\n error: null,\n },\n };\n })\n .execute();\n\n if (!result.found) {\n return error({ code: \"SERVER_NOT_FOUND\", message: \"MCP server not found\" }, 404);\n }\n\n return json(result.refresh);\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/servers/:slug/tools/execute\",\n inputSchema: toolCallInputSchema,\n outputSchema: mcpToolCallResultSchema,\n errorCodes: [\"SERVER_NOT_FOUND\", \"MCP_ERROR\"],\n handler: async function ({ input, pathParams }, { json, error }) {\n const body = await input.valid();\n try {\n let prepared:\n | {\n serverId: string;\n authChanges?: AuthPersistenceChanges;\n toolOperation: Awaited<ReturnType<typeof callMcpTool<AuthPersistenceChanges>>>;\n }\n | undefined;\n\n const result = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema)\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n )\n .find(\"secret\", (b) =>\n b.whereIndex(\"idx_secret_server_kind\", (eb) =>\n eb(\"serverId\", \"=\", pathParams.slug),\n ),\n )\n .findFirst(\"server_connection_cache\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.slug)),\n ),\n )\n .afterRetrieve(async (_uow, [server, secrets]) => {\n if (!server) {\n return;\n }\n\n const auth = await createMcpOperationAuth({ config, server, secrets });\n const toolOperation = await callMcpTool({\n endpointUrl: server.endpointUrl,\n auth,\n name: body.name,\n toolArguments: body.arguments,\n timeoutMs: body.timeoutMs,\n fetchImplementation: config.fetch,\n });\n prepared = {\n serverId: server.id.toString(),\n authChanges: toolOperation.authChanges,\n toolOperation,\n };\n })\n .mutate(({ forSchema, retrieveResult: [server, secrets, cache] }) => {\n if (!server) {\n return { found: false as const };\n }\n if (!prepared) {\n throw new Error(\"MCP operation was not prepared\");\n }\n\n const preparedOperation = prepared;\n const uow = forSchema(mcpSchema);\n const upsertSecret = (kind: string, payload: string, expiresAt: Date | null) => {\n const existing = secrets.find((secret) => secret.kind === kind);\n if (existing) {\n uow.update(\"secret\", existing.id, (b) =>\n b.set({ payload, expiresAt, updatedAt: b.now() }).check(),\n );\n return;\n }\n uow.create(\"secret\", {\n id: `${preparedOperation.serverId}:${kind}`,\n serverId: preparedOperation.serverId,\n kind,\n payload,\n expiresAt,\n });\n };\n\n if (preparedOperation.authChanges) {\n writeOAuthSecretChanges(preparedOperation.authChanges, {\n upsert: (kind, payload) => {\n upsertSecret(kind, payload, null);\n },\n remove: (kind) => {\n const existing = secrets.find((secret) => secret.kind === kind);\n if (existing) {\n uow.delete(\"secret\", existing.id);\n }\n },\n });\n }\n if (preparedOperation.authChanges?.authPayload) {\n const after = {\n payload: preparedOperation.authChanges.authPayload,\n expiresAt: preparedOperation.authChanges.authExpiresAt ?? null,\n };\n upsertSecret(\"auth\", after.payload, after.expiresAt);\n const before = secrets.find((secret) => secret.kind === \"auth\");\n const ready = isMcpAuthReady(server.authMode, after);\n if (ready !== isMcpAuthReady(server.authMode, before)) {\n uow.triggerHook(\"onServerReadinessChanged\", {\n serverId: preparedOperation.serverId,\n ready,\n });\n }\n scheduleMcpAuthExpiry(uow, preparedOperation.serverId, server.authMode, after);\n }\n\n const toolOperation = preparedOperation.toolOperation;\n if (!toolOperation.ok) {\n return {\n found: true as const,\n error:\n toolOperation.error instanceof Error\n ? toolOperation.error.message\n : String(toolOperation.error),\n };\n }\n\n if (cache) {\n uow.update(\"server_connection_cache\", cache.id, (b) =>\n b\n .set({\n protocolVersion: toolOperation.metadata.protocolVersion ?? null,\n serverInfo: toolOperation.metadata.serverInfo ?? null,\n capabilities: toolOperation.metadata.capabilities ?? null,\n updatedAt: b.now(),\n })\n .check(),\n );\n } else {\n uow.create(\"server_connection_cache\", {\n id: pathParams.slug,\n serverId: pathParams.slug,\n protocolVersion: toolOperation.metadata.protocolVersion ?? null,\n serverInfo: toolOperation.metadata.serverInfo ?? null,\n capabilities: toolOperation.metadata.capabilities ?? null,\n tools: null,\n });\n }\n return { found: true as const, result: toolOperation.result };\n })\n .execute();\n\n if (!result.found) {\n return error({ code: \"SERVER_NOT_FOUND\", message: \"MCP server not found\" }, 404);\n }\n if (\"error\" in result) {\n return error(\n { code: \"MCP_ERROR\", message: result.error ?? \"MCP operation failed\" },\n 502,\n );\n }\n return json(result.result);\n } catch (err) {\n return error({ code: \"MCP_ERROR\", message: (err as Error).message }, 502);\n }\n },\n }),\n ];\n },\n);\n"],"mappings":";;;;;;;;;AAsCA,MAAM,oCAAoC,EAAE,OAAO;CACjD,iBAAiB,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAChD,YAAY,EAAE,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAC5C,cAAc,EAAE,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAC9C,OAAO,EAAE,MAAM,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAClD,WAAW,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;AACtD,CAAC;AAED,MAAM,qBAAqB,EAAE,OAAO;CAClC,MAAM,EAAE,OAAO;CACf,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CACrC,aAAa,EAAE,OAAO;CACtB,UAAU,EAAE,OAAO;CACnB,OAAO,kCAAkC,SAAS,CAAC,CAAC,SAAS;AAC/D,CAAC;AAED,SAAS,aACP,QAMA,OAOA;CACA,OAAO;EACL,MAAM,OAAO,GAAG,SAAS;EACzB,MAAM,OAAO;EACb,aAAa,OAAO;EACpB,UAAU,OAAO;EACjB,GAAI,QACA,EACE,OAAO;GACL,iBAAiB,MAAM,mBAAmB;GAC1C,YAAY,MAAM,cAAc;GAChC,cAAc,MAAM,gBAAgB;GAEpC,OAAO,MAAM,QAAQ,MAAM,KAAK,IAAK,MAAM,QAAsB;GACjE,WAAW,MAAM;EACnB,EACF,IACA,CAAC;CACP;AACF;AAEA,SAAS,SAAS,MAAkB;CAClC,OAAO,KAAK;AACd;AAEA,MAAa,mBAAmB,aAAa,qBAAqB,CAAC,CAAC,QACjE,EAAE,UAAU,aAAa,aAAa;CACrC,OAAO;EACL,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc;GACd,YAAY,CAAC,iBAAiB,sBAAsB;GACpD,SAAS,eAAgB,EAAE,SAAS,EAAE,MAAM,SAAS;IACnD,MAAM,OAAO,MAAM,MAAM,MAAM;IAC/B,IAAI;KACF,sBAAsB,KAAK,aAAa,MAAM;IAChD,SAAS,KAAK;KACZ,OAAO,MAAM;MAAE,MAAM;MAAwB,SAAU,IAAc;KAAQ,GAAG,GAAG;IACrF;IAEA,MAAM,UAAU,KAAK,KAAK,SAAS,SAAS,KAAA,IAAY,uBAAuB,KAAK,IAAI;IA2CxF,KAAI,MAzCiB,KAAK,UAAU,CAAC,CAClC,UAAU,EAAE,gBACX,UAAU,SAAS,CAAC,CAAC,UAAU,yBAAyB,MACtD,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,KAAK,IAAI,CAAC,CAC1D,CACF,CAAC,CACA,QAAQ,EAAE,WAAW,gBAAgB,CAAC,gBAAgB;KACrD,IAAI,UACF,OAAO,EAAE,QAAQ,KAAc;KAGjC,MAAM,MAAM,UAAU,SAAS;KAC/B,IAAI,OAAO,wBAAwB;MACjC,IAAI,KAAK;MACT,MAAM,KAAK,QAAQ;MACnB,aAAa,KAAK;MAClB,UAAU,SAAS,KAAK,IAAI;KAC9B,CAAC;KACD,IAAI,SACF,IAAI,OAAO,UAAU;MACnB,IAAI,GAAG,KAAK,KAAK;MACjB,UAAU,KAAK;MACf,MAAM;MACN;MACA,WAAW;KACb,CAAC;KAEH,IAAI,KAAK,KAAK,SAAS,SACrB,IAAI,YAAY,sCAAsC,EAAE,UAAU,KAAK,KAAK,CAAC;KAE/E,IAAI,YAAY,4BAA4B;MAC1C,UAAU,KAAK;MACf,OAAO,eACL,SAAS,KAAK,IAAI,GAClB,YAAY,KAAA,IAAY,KAAA,IAAY;OAAE;OAAS,WAAW;MAAK,CACjE;KACF,CAAC;KACD,OAAO,EAAE,QAAQ,MAAe;IAClC,CAAC,CAAC,CACD,QAAQ,EAAA,CAEA,QACT,OAAO,MAAM;KAAE,MAAM;KAAiB,SAAS;IAA4B,GAAG,GAAG;IAGnF,OAAO,KAAK,aAAa;KAAE,GAAG;KAAM,IAAI,KAAK;KAAM,UAAU,SAAS,KAAK,IAAI;IAAE,CAAC,GAAG,GAAG;GAC1F;EACF,CAAC;EAED,YAAY;GACV,QAAQ;GACR,MAAM;GACN,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,EAAE,CAAC;GAC/D,SAAS,eAAgB,GAAG,EAAE,QAAQ;IACpC,MAAM,CAAC,SAAS,UAAU,MAAM,KAAK,UAAU,CAAC,CAC7C,UAAU,EAAE,gBACX,UAAU,SAAS,CAAC,CACjB,KAAK,yBAAyB,MAAM,EAAE,WAAW,SAAS,CAAC,CAAC,CAC5D,KAAK,4BAA4B,MAAM,EAAE,WAAW,SAAS,CAAC,CACnE,CAAC,CACA,QAAQ;IACX,MAAM,kBAAkB,IAAI,IAAI,OAAO,KAAK,UAAU,CAAC,MAAM,GAAG,SAAS,GAAG,KAAK,CAAC,CAAC;IACnF,OAAO,KAAK,EACV,SAAS,QAAQ,KAAK,WACpB,aAAa,QAAQ,gBAAgB,IAAI,OAAO,GAAG,SAAS,CAAC,CAAC,CAChE,EACF,CAAC;GACH;EACF,CAAC;EAED,YAAY;GACV,QAAQ;GACR,MAAM;GACN,cAAc;GACd,YAAY,CAAC,kBAAkB;GAC/B,SAAS,eAAgB,EAAE,cAAc,EAAE,MAAM,SAAS;IACxD,MAAM,CAAC,QAAQ,SAAS,MAAM,KAAK,UAAU,CAAC,CAC3C,UAAU,EAAE,gBACX,UAAU,SAAS,CAAC,CACjB,UAAU,yBAAyB,MAClC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CAAC,CACA,UAAU,4BAA4B,MACrC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CACJ,CAAC,CACA,QAAQ;IACX,IAAI,CAAC,QACH,OAAO,MAAM;KAAE,MAAM;KAAoB,SAAS;IAAuB,GAAG,GAAG;IAEjF,OAAO,KAAK,aAAa,QAAQ,KAAK,CAAC;GACzC;EACF,CAAC;EAED,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc;GACd,YAAY,CAAC,oBAAoB,sBAAsB;GACvD,SAAS,eAAgB,EAAE,OAAO,cAAc,EAAE,MAAM,SAAS;IAC/D,MAAM,OAAO,MAAM,MAAM,MAAM;IAC/B,IAAI;KACF,sBAAsB,KAAK,aAAa,MAAM;IAChD,SAAS,KAAK;KACZ,OAAO,MAAM;MAAE,MAAM;MAAwB,SAAU,IAAc;KAAQ,GAAG,GAAG;IACrF;IACA,MAAM,UAAU,KAAK,KAAK,SAAS,SAAS,OAAO,uBAAuB,KAAK,IAAI;IACnF,MAAM,SAAS,MAAM,KAAK,UAAU,CAAC,CAClC,UAAU,EAAE,gBACX,UAAU,SAAS,CAAC,CACjB,UAAU,yBAAyB,MAClC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CAAC,CACA,KAAK,WAAW,MACf,EAAE,WAAW,2BAA2B,OACtC,GAAG,YAAY,KAAK,WAAW,IAAI,CACrC,CACF,CAAC,CACA,KAAK,eAAe,MACnB,EAAE,WAAW,2BAA2B,OACtC,GAAG,YAAY,KAAK,WAAW,IAAI,CACrC,CACF,CAAC,CACA,UAAU,4BAA4B,MACrC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CACJ,CAAC,CACA,QAAQ,EAAE,WAAW,gBAAgB,CAAC,QAAQ,SAAS,aAAa,aAAa;KAChF,IAAI,CAAC,QACH,OAAO,EAAE,QAAQ,KAAK;KAExB,MAAM,MAAM,UAAU,SAAS;KAC/B,MAAM,WAAW;MACf,GAAG;MACH,MAAM,KAAK,QAAQ;MACnB,aAAa,KAAK;MAClB,UAAU,SAAS,KAAK,IAAI;KAC9B;KACA,IAAI,OAAO,wBAAwB,OAAO,KAAK,MAC7C,EACG,IAAI;MACH,MAAM,SAAS;MACf,aAAa,SAAS;MACtB,UAAU,SAAS;MACnB,WAAW,EAAE,IAAI;KACnB,CAAC,CAAC,CACD,MAAM,CACX;KAGA,MAAM,aAAa,QAAQ,MAAM,WAAW,OAAO,SAAS,MAAM;KAClE,KAAK,MAAM,UAAU,SACnB,IAAI,WAAW,cAAc,YAAY,MACvC,IAAI,OAAO,UAAU,OAAO,EAAE;KAGlC,IAAI,YAAY,MAAM;MACpB,IAAI,YACF,IAAI,OAAO,UAAU,WAAW,KAAK,MACnC,EAAE,IAAI;OAAE;OAAS,WAAW;OAAM,WAAW,EAAE,IAAI;MAAE,CAAC,CAAC,CAAC,MAAM,CAChE;WAEA,IAAI,OAAO,UAAU;OACnB,IAAI,GAAG,WAAW,KAAK;OACvB,UAAU,WAAW;OACrB,MAAM;OACN;OACA,WAAW;MACb,CAAC;KAEL;KACA,KAAK,MAAM,cAAc,aACvB,IAAI,OAAO,cAAc,WAAW,EAAE;KAExC,IAAI,OACF,IAAI,OAAO,2BAA2B,MAAM,EAAE;KAEhD,IAAI,KAAK,KAAK,SAAS,SACrB,IAAI,YAAY,sCAAsC,EACpD,UAAU,WAAW,KACvB,CAAC;KAEH,MAAM,QAAQ,eACZ,SAAS,UACT,YAAY,OAAO,KAAA,IAAY;MAAE;MAAS,WAAW;KAAK,CAC5D;KACA,IAAI,UAAU,eAAe,OAAO,UAAU,UAAU,GACtD,IAAI,YAAY,4BAA4B;MAAE,UAAU,WAAW;MAAM;KAAM,CAAC;KAElF,OAAO,EAAE,QAAQ,SAAS;IAC5B,CAAC,CAAC,CACD,QAAQ;IACX,IAAI,CAAC,OAAO,QACV,OAAO,MAAM;KAAE,MAAM;KAAoB,SAAS;IAAuB,GAAG,GAAG;IAEjF,OAAO,KAAK,aAAa,OAAO,MAAM,CAAC;GACzC;EACF,CAAC;EAED,YAAY;GACV,QAAQ;GACR,MAAM;GACN,YAAY,CAAC,kBAAkB;GAC/B,SAAS,eAAgB,EAAE,cAAc,EAAE,OAAO,SAAS;IAwCzD,IAAI,EAAC,MAvCgB,KAAK,UAAU,CAAC,CAClC,UAAU,EAAE,gBACX,UAAU,SAAS,CAAC,CACjB,UAAU,yBAAyB,MAClC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CAAC,CACA,KAAK,WAAW,MACf,EAAE,WAAW,2BAA2B,OACtC,GAAG,YAAY,KAAK,WAAW,IAAI,CACrC,CACF,CAAC,CACA,KAAK,eAAe,MACnB,EAAE,WAAW,2BAA2B,OACtC,GAAG,YAAY,KAAK,WAAW,IAAI,CACrC,CACF,CAAC,CACA,UAAU,4BAA4B,MACrC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CACJ,CAAC,CACA,QAAQ,EAAE,WAAW,gBAAgB,CAAC,QAAQ,SAAS,aAAa,aAAa;KAChF,IAAI,CAAC,QACH,OAAO,EAAE,SAAS,MAAe;KAEnC,MAAM,MAAM,UAAU,SAAS;KAC/B,KAAK,MAAM,UAAU,SACnB,IAAI,OAAO,UAAU,OAAO,EAAE;KAEhC,KAAK,MAAM,cAAc,aACvB,IAAI,OAAO,cAAc,WAAW,EAAE;KAExC,IAAI,OACF,IAAI,OAAO,2BAA2B,MAAM,EAAE;KAEhD,IAAI,OAAO,wBAAwB,OAAO,EAAE;KAC5C,IAAI,YAAY,gCAAgC,EAAE,UAAU,WAAW,KAAK,CAAC;KAC7E,OAAO,EAAE,SAAS,KAAc;IAClC,CAAC,CAAC,CACD,QAAQ,EAAA,CACC,SACV,OAAO,MAAM;KAAE,MAAM;KAAoB,SAAS;IAAuB,GAAG,GAAG;IAEjF,OAAO,MAAM,GAAG;GAClB;EACF,CAAC;EAED,YAAY;GACV,QAAQ;GACR,MAAM;GACN,cAAc;GACd,YAAY,CAAC,kBAAkB;GAC/B,SAAS,eAAgB,EAAE,cAAc,EAAE,MAAM,SAAS;IACxD,MAAM,CAAC,QAAQ,QAAQ,gBAAgB,MAAM,KAAK,UAAU,CAAC,CAC1D,UAAU,EAAE,gBACX,UAAU,SAAS,CAAC,CACjB,UAAU,yBAAyB,MAClC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CAAC,CACA,UAAU,WAAW,MACpB,EAAE,WAAW,2BAA2B,OACtC,GAAG,IAAI,GAAG,YAAY,KAAK,WAAW,IAAI,GAAG,GAAG,QAAQ,KAAK,MAAM,CAAC,CACtE,CACF,CAAC,CACA,UAAU,eAAe,MACxB,EACG,WAAW,4BAA4B,OACtC,GAAG,IACD,GAAG,YAAY,KAAK,WAAW,IAAI,GACnC,GAAG,OAAO,YAAY,GACtB,GAAG,aAAa,KAAK,GAAG,IAAI,CAAC,CAC/B,CACF,CAAC,CACA,aAAa,2BAA2B,MAAM,CACnD,CACJ,CAAC,CACA,QAAQ;IACX,IAAI,CAAC,QACH,OAAO,MAAM;KAAE,MAAM;KAAoB,SAAS;IAAuB,GAAG,GAAG;IAEjF,OAAO,KACL,qBAAqB;KACnB,UAAU,OAAO;KACjB,YAAY,UAAU,KAAA;KACtB,iBAAiB,iBAAiB,YAAY,MAAM;IACtD,CAAC,CACH;GACF;EACF,CAAC;EAED,YAAY;GACV,QAAQ;GACR,MAAM;GACN,cAAc;GACd,YAAY,CAAC,kBAAkB;GAC/B,SAAS,eAAgB,EAAE,cAAc,EAAE,MAAM,SAAS;IACxD,MAAM,CAAC,QAAQ,gBAAgB,MAAM,KAAK,UAAU,CAAC,CAClD,UAAU,EAAE,gBACX,UAAU,SAAS,CAAC,CACjB,UAAU,yBAAyB,MAClC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CAAC,CACA,UAAU,eAAe,MACxB,EACG,WAAW,4BAA4B,OACtC,GAAG,IACD,GAAG,YAAY,KAAK,WAAW,IAAI,GACnC,GAAG,OAAO,YAAY,GACtB,GAAG,aAAa,KAAK,GAAG,IAAI,CAAC,CAC/B,CACF,CAAC,CACA,aAAa,2BAA2B,MAAM,CACnD,CACJ,CAAC,CACA,QAAQ;IACX,IAAI,CAAC,QACH,OAAO,MAAM;KAAE,MAAM;KAAoB,SAAS;IAAuB,GAAG,GAAG;IAEjF,OAAO,KAAK,EAAE,SAAS,iBAAiB,YAAY,EAAE,CAAC;GACzD;EACF,CAAC;EAED,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc;GACd,YAAY,CAAC,kBAAkB;GAC/B,SAAS,eAAgB,EAAE,OAAO,cAAc,EAAE,MAAM,SAAS;IAC/D,MAAM,EAAE,UAAU,MAAM,MAAM,MAAM;IACpC,MAAM,UAAU,uBAAuB;KAAE,MAAM;KAAU;IAAM,CAAC;IAkDhE,IAAI,EAAC,MAjDgB,KAAK,UAAU,CAAC,CAClC,UAAU,EAAE,gBACX,UAAU,SAAS,CAAC,CACjB,UAAU,yBAAyB,MAClC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CAAC,CACA,UAAU,WAAW,MACpB,EAAE,WAAW,2BAA2B,OACtC,GAAG,IAAI,GAAG,YAAY,KAAK,WAAW,IAAI,GAAG,GAAG,QAAQ,KAAK,MAAM,CAAC,CACtE,CACF,CAAC,CACA,UAAU,4BAA4B,MACrC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CACJ,CAAC,CACA,QAAQ,EAAE,WAAW,gBAAgB,CAAC,QAAQ,QAAQ,aAAa;KAClE,IAAI,CAAC,QACH,OAAO,EAAE,OAAO,MAAe;KAEjC,MAAM,MAAM,UAAU,SAAS;KAC/B,IAAI,OAAO,wBAAwB,OAAO,KAAK,MAC7C,EAAE,IAAI;MAAE,UAAU;MAAU,WAAW,EAAE,IAAI;KAAE,CAAC,CAAC,CAAC,MAAM,CAC1D;KACA,IAAI,OACF,IAAI,OAAO,2BAA2B,MAAM,EAAE;KAEhD,IAAI,QACF,IAAI,OAAO,UAAU,OAAO,KAAK,MAC/B,EAAE,IAAI;MAAE;MAAS,WAAW;MAAM,WAAW,EAAE,IAAI;KAAE,CAAC,CAAC,CAAC,MAAM,CAChE;UAEA,IAAI,OAAO,UAAU;MACnB,IAAI,GAAG,WAAW,KAAK;MACvB,UAAU,WAAW;MACrB,MAAM;MACN;MACA,WAAW;KACb,CAAC;KAEH,IAAI,YAAY,sCAAsC,EAAE,UAAU,WAAW,KAAK,CAAC;KACnF,IAAI,CAAC,eAAe,OAAO,UAAU,UAAU,KAAA,CAAS,GACtD,IAAI,YAAY,4BAA4B;MAC1C,UAAU,WAAW;MACrB,OAAO;KACT,CAAC;KAEH,OAAO,EAAE,OAAO,KAAc;IAChC,CAAC,CAAC,CACD,QAAQ,EAAA,CACC,OACV,OAAO,MAAM;KAAE,MAAM;KAAoB,SAAS;IAAuB,GAAG,GAAG;IAEjF,OAAO,KAAK;KAAE,MAAM;KAAmB,aAAa;IAAmB,CAAC;GAC1E;EACF,CAAC;EAED,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc,EAAE,OAAO;IAAE,kBAAkB,EAAE,OAAO;IAAG,OAAO,EAAE,OAAO;GAAE,CAAC;GAC1E,iBAAiB,CAAC,sCAAsC;GACxD,YAAY;IACV;IACA;IACA;IACA;GACF;GACA,SAAS,eAAgB,EAAE,OAAO,YAAY,SAAS,EAAE,MAAM,SAAS;IACtE,MAAM,OAAO,MAAM,MAAM,MAAM;IAC/B,MAAM,cAAc,0BAA0B,UAC5C,MAAM,IAAI,sCAAsC,CAClD;IACA,IAAI,CAAC,YAAY,SACf,OAAO,MACL;KACE,MAAM;KACN,SAAS;IACX,GACA,GACF;IAEF,MAAM,mBAAmB,IAAI,IAAI,YAAY,IAAI;IACjD,IAAI,CAAC,OAAO,2BAA2B,gBAAgB,GACrD,OAAO,MACL;KACE,MAAM;KACN,SAAS;IACX,GACA,GACF;IAEF,MAAM,QAAQ,GAAG,WAAW,KAAK,GAAG,OAAO,WAAW;IACtD,IAAI;KACF,MAAM,CAAC,UAAU,MAAM,KAAK,UAAU,CAAC,CACpC,uBAEG,CACE,SAAS,WAAW;MAClB,UAAU,WAAW;MACrB,SAAS;MACT,aAAa,iBAAiB,SAAS;MACvC,OAAO,KAAK;MACZ,UAAU,KAAK;MACf,cAAc,KAAK;MACnB,eAAe,KAAK;KACtB,CAAC,CACH,CACJ,CAAC,CACA,QAAQ;KACX,IAAI,CAAC,OAAO,OACV,OAAO,MAAM;MAAE,MAAM;MAAoB,SAAS;KAAuB,GAAG,GAAG;KAEjF,OAAO,KAAK;MAAE,kBAAkB,OAAO;MAAkB;KAAM,CAAC;IAClE,SAAS,KAAK;KACZ,OAAO,MAAM;MAAE,MAAM;MAAe,SAAU,IAAc;KAAQ,GAAG,GAAG;IAC5E;GACF;EACF,CAAC;EAED,YAAY;GACV,QAAQ;GACR,MAAM;GACN,cAAc,EAAE,OAAO;IAAE,eAAe,EAAE,QAAQ;IAAG,MAAM,EAAE,OAAO;GAAE,CAAC;GACvE,YAAY;IAAC;IAAoB;IAAe;GAAqB;GACrE,SAAS,eAAgB,EAAE,SAAS,EAAE,MAAM,SAAS;IACnD,MAAM,OAAO,MAAM,IAAI,MAAM;IAC7B,MAAM,UAAU,MAAM,IAAI,OAAO;IACjC,IAAI,CAAC,QAAQ,CAAC,SACZ,OAAO,MACL;KAAE,MAAM;KAAuB,SAAS;IAA8B,GACtE,GACF;IAEF,IAAI;KACF,MAAM,CAAC,UAAU,MAAM,KAAK,UAAU,CAAC,CACpC,uBAEG,CACE,SAAS,sBAAsB;MAC7B;MACA;MACA,KAAK,MAAM,IAAI,KAAK,KAAK,KAAA;KAC3B,CAAC,CACH,CACJ,CAAC,CACA,QAAQ;KACX,IAAI,CAAC,OAAO,OAAO;MACjB,IAAI,OAAO,WAAW,oBACpB,OAAO,MAAM;OAAE,MAAM;OAAoB,SAAS;MAAuB,GAAG,GAAG;MAEjF,OAAO,MAAM;OAAE,MAAM;OAAuB,SAAS;MAAsB,GAAG,GAAG;KACnF;KACA,OAAO,KAAK;MAAE,eAAe;MAAM,MAAM;KAAQ,CAAC;IACpD,SAAS,KAAK;KACZ,OAAO,MAAM;MAAE,MAAM;MAAe,SAAU,IAAc;KAAQ,GAAG,GAAG;IAC5E;GACF;EACF,CAAC;EAED,YAAY;GACV,QAAQ;GACR,MAAM;GACN,cAAc;GACd,YAAY,CAAC,kBAAkB;GAC/B,SAAS,eAAgB,EAAE,cAAc,EAAE,MAAM,SAAS;IACxD,MAAM,SAAS,MAAM,KAAK,UAAU,CAAC,CAClC,UAAU,EAAE,gBACX,UAAU,SAAS,CAAC,CACjB,UAAU,yBAAyB,MAClC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CAAC,CACA,KAAK,WAAW,MACf,EAAE,WAAW,2BAA2B,OACtC,GAAG,YAAY,KAAK,WAAW,IAAI,CACrC,CACF,CAAC,CACA,KAAK,eAAe,MACnB,EAAE,WAAW,2BAA2B,OACtC,GAAG,YAAY,KAAK,WAAW,IAAI,CACrC,CACF,CAAC,CACA,UAAU,4BAA4B,MACrC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CACJ,CAAC,CACA,QAAQ,EAAE,WAAW,gBAAgB,CAAC,QAAQ,SAAS,aAAa,aAAa;KAChF,IAAI,CAAC,QACH,OAAO,EAAE,OAAO,MAAe;KAEjC,MAAM,MAAM,UAAU,SAAS;KAC/B,MAAM,aAAa,QAAQ,MAAM,WAAW,OAAO,SAAS,MAAM;KAElE,MAAM,gBACJ,OAAO,aAAa,WAAW,aAC3B;MAAE,SAAS,oBAAoB,WAAW,OAAO;MAAG,WAAW;KAAK,IACpE,KAAA;KACN,IAAI,OAAO,aAAa,SAClB;UAAA,cAAc,eAChB,IAAI,OAAO,UAAU,WAAW,KAAK,MACnC,EACG,IAAI;OAAE,SAAS,cAAc;OAAS,WAAW;OAAM,WAAW,EAAE,IAAI;MAAE,CAAC,CAAC,CAC5E,MAAM,CACX;KAAA,OAGF,KAAK,MAAM,UAAU,SACnB,IAAI,OAAO,UAAU,OAAO,EAAE;KAGlC,MAAM,QAAQ,eAAe,OAAO,UAAU,aAAa;KAC3D,IAAI,UAAU,eAAe,OAAO,UAAU,UAAU,GACtD,IAAI,YAAY,4BAA4B;MAAE,UAAU,WAAW;MAAM;KAAM,CAAC;KAElF,KAAK,MAAM,cAAc,aACvB,IAAI,OAAO,cAAc,WAAW,EAAE;KAExC,IAAI,OACF,IAAI,OAAO,2BAA2B,MAAM,EAAE;KAGhD,IAAI,OAAO,wBAAwB,OAAO,KAAK,MAC7C,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CACtC;KACA,OAAO;MACL,OAAO;MACP,QAAQ,qBAAqB;OAC3B,UAAU,OAAO;OACjB,YAAY,KAAA;OACZ,iBAAiB;MACnB,CAAC;KACH;IACF,CAAC,CAAC,CACD,QAAQ;IACX,IAAI,CAAC,OAAO,OACV,OAAO,MAAM;KAAE,MAAM;KAAoB,SAAS;IAAuB,GAAG,GAAG;IAEjF,OAAO,KAAK,OAAO,MAAM;GAC3B;EACF,CAAC;EAED,YAAY;GACV,QAAQ;GACR,MAAM;GACN,cAAc;GACd,YAAY,CAAC,kBAAkB;GAC/B,SAAS,eAAgB,EAAE,cAAc,EAAE,MAAM,SAAS;IACxD,MAAM,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IACzC,IAAI;IAMJ,IAAI;IAEJ,MAAM,SAAS,MAAM,KAAK,UAAU,CAAC,CAClC,UAAU,EAAE,gBACX,UAAU,SAAS,CAAC,CACjB,UAAU,yBAAyB,MAClC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CAAC,CACA,KAAK,WAAW,MACf,EAAE,WAAW,2BAA2B,OACtC,GAAG,YAAY,KAAK,WAAW,IAAI,CACrC,CACF,CAAC,CACA,UAAU,4BAA4B,MACrC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CAAC,CACA,KAAK,eAAe,MACnB,EAAE,WAAW,2BAA2B,OACtC,GAAG,YAAY,KAAK,WAAW,IAAI,CACrC,CACF,CACJ,CAAC,CACA,cAAc,OAAO,MAAM,CAAC,QAAQ,aAAa;KAChD,IAAI,CAAC,QACH;KAGF,IAAI;MACF,MAAM,OAAO,MAAM,uBAAuB;OAAE;OAAQ;OAAQ;MAAQ,CAAC;MACrE,MAAM,iBAAiB,MAAM,aAAa;OACxC,aAAa,OAAO;OACpB;OACA,qBAAqB,OAAO;MAC9B,CAAC;MACD,WAAW;OACT,aAAa,eAAe;OAC5B;MACF;KACF,SAAS,KAAK;MACZ,YAAY;KACd;IACF,CAAC,CAAC,CACD,QAAQ,EAAE,WAAW,gBAAgB,CAAC,QAAQ,SAAS,OAAO,mBAAmB;KAChF,IAAI,CAAC,QACH,OAAO,EAAE,OAAO,MAAe;KAGjC,MAAM,WAAW,OAAO,GAAG,SAAS;KACpC,MAAM,gBAAgB,MAAM,QAAQ,OAAO,KAAK,IAAI,MAAM,QAAQ;KAClE,MAAM,kBAAkB;MACtB;MACA,QAAQ,aAAa,MAAM;MAC3B,OAAO;OACL,oBAAoB,QAAQ,KAAK;OACjC,mBAAmB,eAAe,UAAU;OAC5C,kBAAkB;MACpB;KACF;KAEA,IAAI,WACF,OAAO;MACL,OAAO;MACP,SAAS;OACP,GAAG;OACH,IAAI;OACJ,OAAO,CAAC;OACR,OAAO;OACP,MAAM,qBAAqB;QACzB,MAAM,OAAO;QACb;QACA;OACF,CAAC;OACD,MAAM;QACJ,WAAW;QACX,aAAa;QACb,WAAW;QACX,iBAAiB;QACjB,YAAY;QACZ,cAAc;OAChB;OACA,OAAO;QAAE,MAAM;QAAc,SAAS,aAAa,SAAS;OAAE;MAChE;KACF;KAGF,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,wCAAwC;KAG1D,MAAM,oBAAoB;KAC1B,MAAM,MAAM,UAAU,SAAS;KAC/B,MAAM,gBAAgB,MAAc,SAAiB,cAA2B;MAC9E,MAAM,WAAW,QAAQ,MAAM,WAAW,OAAO,SAAS,IAAI;MAC9D,IAAI,UAAU;OACZ,IAAI,OAAO,UAAU,SAAS,KAAK,MACjC,EAAE,IAAI;QAAE;QAAS;QAAW,WAAW,EAAE,IAAI;OAAE,CAAC,CAAC,CAAC,MAAM,CAC1D;OACA;MACF;MACA,IAAI,OAAO,UAAU;OACnB,IAAI,GAAG,SAAS,GAAG;OACnB;OACA;OACA;OACA;MACF,CAAC;KACH;KAEA,IAAI,kBAAkB,aACpB,wBAAwB,kBAAkB,aAAa;MACrD,SAAS,MAAM,YAAY;OACzB,aAAa,MAAM,SAAS,IAAI;MAClC;MACA,SAAS,SAAS;OAChB,MAAM,WAAW,QAAQ,MAAM,WAAW,OAAO,SAAS,IAAI;OAC9D,IAAI,UACF,IAAI,OAAO,UAAU,SAAS,EAAE;MAEpC;KACF,CAAC;KAEH,IAAI,kBAAkB,aAAa,aAAa;MAC9C,MAAM,QAAQ;OACZ,SAAS,kBAAkB,YAAY;OACvC,WAAW,kBAAkB,YAAY,iBAAiB;MAC5D;MACA,aAAa,QAAQ,MAAM,SAAS,MAAM,SAAS;MACnD,MAAM,SAAS,QAAQ,MAAM,WAAW,OAAO,SAAS,MAAM;MAC9D,MAAM,QAAQ,eAAe,OAAO,UAAU,KAAK;MACnD,IAAI,UAAU,eAAe,OAAO,UAAU,MAAM,GAClD,IAAI,YAAY,4BAA4B;OAAE;OAAU;MAAM,CAAC;MAEjE,sBAAsB,KAAK,UAAU,OAAO,UAAU,KAAK;KAC7D;KAEA,MAAM,OAAO,qBAAqB;MAChC,MAAM,OAAO;MACb;MACA;MACA,aAAa,kBAAkB;KACjC,CAAC;KAED,IAAI,CAAC,kBAAkB,eAAe,IACpC,OAAO;MACL,OAAO;MACP,SAAS;OACP,GAAG;OACH,IAAI;OACJ,OAAO,CAAC;OACR,OAAO;OACP;OACA,MAAM;QACJ,WAAW;QACX,aAAa;QACb,WAAW;QACX,iBAAiB;QACjB,YAAY;QACZ,cAAc;OAChB;OACA,OAAO;QACL,MAAM;QACN,SAAS,aAAa,kBAAkB,eAAe,KAAK;OAC9D;MACF;KACF;KAGF,MAAM,QAAQ,MAAM,QAAQ,kBAAkB,eAAe,OAAO,KAAK,IACrE,kBAAkB,eAAe,OAAO,QACxC,CAAC;KACL,IAAI,CAAC,iBAAiB,KAAK,UAAU,aAAa,MAAM,KAAK,UAAU,KAAK,GAC1E,IAAI,YAAY,gCAAgC;MAC9C;MACA,SAAS,EAAE,MAAM;KACnB,CAAC;KAEH,IAAI,OAAO,2BAA2B,QAAQ;KAC9C,IAAI,OAAO,2BAA2B;MACpC,IAAI;MACJ;MACA,iBAAiB,kBAAkB,eAAe,SAAS,mBAAmB;MAC9E,YAAY,kBAAkB,eAAe,SAAS,cAAc;MACpE,cAAc,kBAAkB,eAAe,SAAS,gBAAgB;MACxE;KACF,CAAC;KAED,OAAO;MACL,OAAO;MACP,SAAS;OACP,GAAG;OACH,IAAI;OACJ;OACA,OAAO;OACP;OACA,MAAM;QACJ,WAAW;QACX,aAAa;QACb,WAAW,MAAM;QACjB,iBACE,kBAAkB,eAAe,SAAS,mBAAmB;QAC/D,YAAY,kBAAkB,eAAe,SAAS,cAAc;QACpE,cAAc,kBAAkB,eAAe,SAAS,gBAAgB;OAC1E;OACA,OAAO;QACL,GAAG,gBAAgB;QACnB,kBAAkB,MAAM;OAC1B;OACA,OAAO;MACT;KACF;IACF,CAAC,CAAC,CACD,QAAQ;IAEX,IAAI,CAAC,OAAO,OACV,OAAO,MAAM;KAAE,MAAM;KAAoB,SAAS;IAAuB,GAAG,GAAG;IAGjF,OAAO,KAAK,OAAO,OAAO;GAC5B;EACF,CAAC;EAED,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc;GACd,YAAY,CAAC,oBAAoB,WAAW;GAC5C,SAAS,eAAgB,EAAE,OAAO,cAAc,EAAE,MAAM,SAAS;IAC/D,MAAM,OAAO,MAAM,MAAM,MAAM;IAC/B,IAAI;KACF,IAAI;KAQJ,MAAM,SAAS,MAAM,KAAK,UAAU,CAAC,CAClC,UAAU,EAAE,gBACX,UAAU,SAAS,CAAC,CACjB,UAAU,yBAAyB,MAClC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CAAC,CACA,KAAK,WAAW,MACf,EAAE,WAAW,2BAA2B,OACtC,GAAG,YAAY,KAAK,WAAW,IAAI,CACrC,CACF,CAAC,CACA,UAAU,4BAA4B,MACrC,EAAE,WAAW,YAAY,OAAO,GAAG,MAAM,KAAK,WAAW,IAAI,CAAC,CAChE,CACJ,CAAC,CACA,cAAc,OAAO,MAAM,CAAC,QAAQ,aAAa;MAChD,IAAI,CAAC,QACH;MAGF,MAAM,OAAO,MAAM,uBAAuB;OAAE;OAAQ;OAAQ;MAAQ,CAAC;MACrE,MAAM,gBAAgB,MAAM,YAAY;OACtC,aAAa,OAAO;OACpB;OACA,MAAM,KAAK;OACX,eAAe,KAAK;OACpB,WAAW,KAAK;OAChB,qBAAqB,OAAO;MAC9B,CAAC;MACD,WAAW;OACT,UAAU,OAAO,GAAG,SAAS;OAC7B,aAAa,cAAc;OAC3B;MACF;KACF,CAAC,CAAC,CACD,QAAQ,EAAE,WAAW,gBAAgB,CAAC,QAAQ,SAAS,aAAa;MACnE,IAAI,CAAC,QACH,OAAO,EAAE,OAAO,MAAe;MAEjC,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,gCAAgC;MAGlD,MAAM,oBAAoB;MAC1B,MAAM,MAAM,UAAU,SAAS;MAC/B,MAAM,gBAAgB,MAAc,SAAiB,cAA2B;OAC9E,MAAM,WAAW,QAAQ,MAAM,WAAW,OAAO,SAAS,IAAI;OAC9D,IAAI,UAAU;QACZ,IAAI,OAAO,UAAU,SAAS,KAAK,MACjC,EAAE,IAAI;SAAE;SAAS;SAAW,WAAW,EAAE,IAAI;QAAE,CAAC,CAAC,CAAC,MAAM,CAC1D;QACA;OACF;OACA,IAAI,OAAO,UAAU;QACnB,IAAI,GAAG,kBAAkB,SAAS,GAAG;QACrC,UAAU,kBAAkB;QAC5B;QACA;QACA;OACF,CAAC;MACH;MAEA,IAAI,kBAAkB,aACpB,wBAAwB,kBAAkB,aAAa;OACrD,SAAS,MAAM,YAAY;QACzB,aAAa,MAAM,SAAS,IAAI;OAClC;OACA,SAAS,SAAS;QAChB,MAAM,WAAW,QAAQ,MAAM,WAAW,OAAO,SAAS,IAAI;QAC9D,IAAI,UACF,IAAI,OAAO,UAAU,SAAS,EAAE;OAEpC;MACF,CAAC;MAEH,IAAI,kBAAkB,aAAa,aAAa;OAC9C,MAAM,QAAQ;QACZ,SAAS,kBAAkB,YAAY;QACvC,WAAW,kBAAkB,YAAY,iBAAiB;OAC5D;OACA,aAAa,QAAQ,MAAM,SAAS,MAAM,SAAS;OACnD,MAAM,SAAS,QAAQ,MAAM,WAAW,OAAO,SAAS,MAAM;OAC9D,MAAM,QAAQ,eAAe,OAAO,UAAU,KAAK;OACnD,IAAI,UAAU,eAAe,OAAO,UAAU,MAAM,GAClD,IAAI,YAAY,4BAA4B;QAC1C,UAAU,kBAAkB;QAC5B;OACF,CAAC;OAEH,sBAAsB,KAAK,kBAAkB,UAAU,OAAO,UAAU,KAAK;MAC/E;MAEA,MAAM,gBAAgB,kBAAkB;MACxC,IAAI,CAAC,cAAc,IACjB,OAAO;OACL,OAAO;OACP,OACE,cAAc,iBAAiB,QAC3B,cAAc,MAAM,UACpB,OAAO,cAAc,KAAK;MAClC;MAGF,IAAI,OACF,IAAI,OAAO,2BAA2B,MAAM,KAAK,MAC/C,EACG,IAAI;OACH,iBAAiB,cAAc,SAAS,mBAAmB;OAC3D,YAAY,cAAc,SAAS,cAAc;OACjD,cAAc,cAAc,SAAS,gBAAgB;OACrD,WAAW,EAAE,IAAI;MACnB,CAAC,CAAC,CACD,MAAM,CACX;WAEA,IAAI,OAAO,2BAA2B;OACpC,IAAI,WAAW;OACf,UAAU,WAAW;OACrB,iBAAiB,cAAc,SAAS,mBAAmB;OAC3D,YAAY,cAAc,SAAS,cAAc;OACjD,cAAc,cAAc,SAAS,gBAAgB;OACrD,OAAO;MACT,CAAC;MAEH,OAAO;OAAE,OAAO;OAAe,QAAQ,cAAc;MAAO;KAC9D,CAAC,CAAC,CACD,QAAQ;KAEX,IAAI,CAAC,OAAO,OACV,OAAO,MAAM;MAAE,MAAM;MAAoB,SAAS;KAAuB,GAAG,GAAG;KAEjF,IAAI,WAAW,QACb,OAAO,MACL;MAAE,MAAM;MAAa,SAAS,OAAO,SAAS;KAAuB,GACrE,GACF;KAEF,OAAO,KAAK,OAAO,MAAM;IAC3B,SAAS,KAAK;KACZ,OAAO,MAAM;MAAE,MAAM;MAAa,SAAU,IAAc;KAAQ,GAAG,GAAG;IAC1E;GACF;EACF,CAAC;CACH;AACF,CACF"}
@@ -0,0 +1,13 @@
1
+ import { column, idColumn, referenceColumn, schema } from "@fragno-dev/db/schema";
2
+ //#region src/schema.ts
3
+ const mcpSchema = schema("mcp-fragment", (s) => {
4
+ return s.addTable("server_configuration", (t) => t.addColumn("id", idColumn()).addColumn("name", column("string").nullable()).addColumn("endpointUrl", column("string")).addColumn("authMode", column("string")).addColumn("createdAt", column("timestamp").defaultTo((b) => b.now())).addColumn("updatedAt", column("timestamp").defaultTo((b) => b.now()))).addTable("secret", (t) => t.addColumn("id", idColumn()).addColumn("serverId", referenceColumn({ table: "server_configuration" })).addColumn("kind", column("string")).addColumn("payload", column("text")).addColumn("expiresAt", column("timestamp").nullable()).addColumn("updatedAt", column("timestamp").defaultTo((b) => b.now())).createIndex("idx_secret_server_kind", ["serverId", "kind"], { unique: true })).addTable("oauthState", (t) => t.addColumn("id", idColumn()).addColumn("serverId", referenceColumn({ table: "server_configuration" })).addColumn("codeVerifier", column("text")).addColumn("redirectUri", column("string")).addColumn("scope", column("string").nullable()).addColumn("expiresAt", column("timestamp")).addColumn("consumedAt", column("timestamp").nullable()).createIndex("idx_oauth_state_server", ["serverId"])).addTable("server_connection_cache", (t) => t.addColumn("id", idColumn()).addColumn("serverId", referenceColumn({ table: "server_configuration" })).addColumn("protocolVersion", column("string").nullable()).addColumn("serverInfo", column("json").nullable()).addColumn("capabilities", column("json").nullable()).addColumn("tools", column("json").nullable()).addColumn("updatedAt", column("timestamp").defaultTo((b) => b.now())).createIndex("idx_server_connection_cache_server", ["serverId"], { unique: true })).alterTable("oauthState", (t) => t.addColumn("authorizationUrl", column("text").nullable())).alterTable("oauthState", (t) => t.createIndex("idx_oauth_state_pending", [
5
+ "serverId",
6
+ "consumedAt",
7
+ "expiresAt"
8
+ ]));
9
+ });
10
+ //#endregion
11
+ export { mcpSchema };
12
+
13
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","names":[],"sources":["../../src/schema.ts"],"sourcesContent":["import { column, idColumn, referenceColumn, schema } from \"@fragno-dev/db/schema\";\n\nexport const mcpSchema = schema(\"mcp-fragment\", (s) => {\n return s\n .addTable(\"server_configuration\", (t) =>\n t\n .addColumn(\"id\", idColumn())\n .addColumn(\"name\", column(\"string\").nullable())\n .addColumn(\"endpointUrl\", column(\"string\"))\n .addColumn(\"authMode\", column(\"string\"))\n .addColumn(\n \"createdAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .addColumn(\n \"updatedAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n ),\n )\n .addTable(\"secret\", (t) =>\n t\n .addColumn(\"id\", idColumn())\n .addColumn(\"serverId\", referenceColumn({ table: \"server_configuration\" }))\n .addColumn(\"kind\", column(\"string\"))\n .addColumn(\"payload\", column(\"text\"))\n .addColumn(\"expiresAt\", column(\"timestamp\").nullable())\n .addColumn(\n \"updatedAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .createIndex(\"idx_secret_server_kind\", [\"serverId\", \"kind\"], { unique: true }),\n )\n .addTable(\"oauthState\", (t) =>\n t\n .addColumn(\"id\", idColumn())\n .addColumn(\"serverId\", referenceColumn({ table: \"server_configuration\" }))\n .addColumn(\"codeVerifier\", column(\"text\"))\n .addColumn(\"redirectUri\", column(\"string\"))\n .addColumn(\"scope\", column(\"string\").nullable())\n .addColumn(\"expiresAt\", column(\"timestamp\"))\n .addColumn(\"consumedAt\", column(\"timestamp\").nullable())\n .createIndex(\"idx_oauth_state_server\", [\"serverId\"]),\n )\n .addTable(\"server_connection_cache\", (t) =>\n t\n .addColumn(\"id\", idColumn())\n .addColumn(\"serverId\", referenceColumn({ table: \"server_configuration\" }))\n .addColumn(\"protocolVersion\", column(\"string\").nullable())\n .addColumn(\"serverInfo\", column(\"json\").nullable())\n .addColumn(\"capabilities\", column(\"json\").nullable())\n .addColumn(\"tools\", column(\"json\").nullable())\n .addColumn(\n \"updatedAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .createIndex(\"idx_server_connection_cache_server\", [\"serverId\"], { unique: true }),\n )\n .alterTable(\"oauthState\", (t) =>\n // Null only for states started before links were retained; those cannot be resumed.\n t.addColumn(\"authorizationUrl\", column(\"text\").nullable()),\n )\n .alterTable(\"oauthState\", (t) =>\n // States are retained after use, so pending reads seek the newest live one instead of scanning.\n t.createIndex(\"idx_oauth_state_pending\", [\"serverId\", \"consumedAt\", \"expiresAt\"]),\n );\n});\n"],"mappings":";;AAEA,MAAa,YAAY,OAAO,iBAAiB,MAAM;CACrD,OAAO,EACJ,SAAS,yBAAyB,MACjC,EACG,UAAU,MAAM,SAAS,CAAC,CAAC,CAC3B,UAAU,QAAQ,OAAO,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAC9C,UAAU,eAAe,OAAO,QAAQ,CAAC,CAAC,CAC1C,UAAU,YAAY,OAAO,QAAQ,CAAC,CAAC,CACvC,UACC,aACA,OAAO,WAAW,CAAC,CAAC,WAAW,MAAM,EAAE,IAAI,CAAC,CAC9C,CAAC,CACA,UACC,aACA,OAAO,WAAW,CAAC,CAAC,WAAW,MAAM,EAAE,IAAI,CAAC,CAC9C,CACJ,CAAC,CACA,SAAS,WAAW,MACnB,EACG,UAAU,MAAM,SAAS,CAAC,CAAC,CAC3B,UAAU,YAAY,gBAAgB,EAAE,OAAO,uBAAuB,CAAC,CAAC,CAAC,CACzE,UAAU,QAAQ,OAAO,QAAQ,CAAC,CAAC,CACnC,UAAU,WAAW,OAAO,MAAM,CAAC,CAAC,CACpC,UAAU,aAAa,OAAO,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,CACtD,UACC,aACA,OAAO,WAAW,CAAC,CAAC,WAAW,MAAM,EAAE,IAAI,CAAC,CAC9C,CAAC,CACA,YAAY,0BAA0B,CAAC,YAAY,MAAM,GAAG,EAAE,QAAQ,KAAK,CAAC,CACjF,CAAC,CACA,SAAS,eAAe,MACvB,EACG,UAAU,MAAM,SAAS,CAAC,CAAC,CAC3B,UAAU,YAAY,gBAAgB,EAAE,OAAO,uBAAuB,CAAC,CAAC,CAAC,CACzE,UAAU,gBAAgB,OAAO,MAAM,CAAC,CAAC,CACzC,UAAU,eAAe,OAAO,QAAQ,CAAC,CAAC,CAC1C,UAAU,SAAS,OAAO,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CAC/C,UAAU,aAAa,OAAO,WAAW,CAAC,CAAC,CAC3C,UAAU,cAAc,OAAO,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,CACvD,YAAY,0BAA0B,CAAC,UAAU,CAAC,CACvD,CAAC,CACA,SAAS,4BAA4B,MACpC,EACG,UAAU,MAAM,SAAS,CAAC,CAAC,CAC3B,UAAU,YAAY,gBAAgB,EAAE,OAAO,uBAAuB,CAAC,CAAC,CAAC,CACzE,UAAU,mBAAmB,OAAO,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CACzD,UAAU,cAAc,OAAO,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAClD,UAAU,gBAAgB,OAAO,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CACpD,UAAU,SAAS,OAAO,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAC7C,UACC,aACA,OAAO,WAAW,CAAC,CAAC,WAAW,MAAM,EAAE,IAAI,CAAC,CAC9C,CAAC,CACA,YAAY,sCAAsC,CAAC,UAAU,GAAG,EAAE,QAAQ,KAAK,CAAC,CACrF,CAAC,CACA,WAAW,eAAe,MAEzB,EAAE,UAAU,oBAAoB,OAAO,MAAM,CAAC,CAAC,SAAS,CAAC,CAC3D,CAAC,CACA,WAAW,eAAe,MAEzB,EAAE,YAAY,2BAA2B;EAAC;EAAY;EAAc;CAAW,CAAC,CAClF;AACJ,CAAC"}
@@ -0,0 +1,330 @@
1
+ import { parseSecretPayload, stringifySecretPayload } from "./mcp-api.js";
2
+ import { BufferedOAuthClientProvider } from "./oauth-provider.js";
3
+ import { auth } from "@modelcontextprotocol/client";
4
+ //#region src/services.ts
5
+ function oauthSecretChange(value, invalidated) {
6
+ if (value) return {
7
+ action: "save",
8
+ payload: stringifySecretPayload(value)
9
+ };
10
+ return invalidated ? { action: "remove" } : { action: "keep" };
11
+ }
12
+ async function prepareOAuthChanges(changes) {
13
+ return {
14
+ ...changes,
15
+ clientChange: oauthSecretChange(changes.clientInformation, changes.clientInvalidated),
16
+ discoveryChange: oauthSecretChange(changes.discoveryState, changes.discoveryInvalidated)
17
+ };
18
+ }
19
+ /** Applies the client and discovery changes through a write site's own secret writers. */
20
+ function writeOAuthSecretChanges(changes, writers) {
21
+ for (const [kind, change] of [["oauth-client", changes.clientChange], ["oauth-discovery", changes.discoveryChange]]) switch (change.action) {
22
+ case "keep": break;
23
+ case "save":
24
+ writers.upsert(kind, change.payload);
25
+ break;
26
+ case "remove":
27
+ writers.remove(kind);
28
+ break;
29
+ default: throw new Error("Unknown OAuth secret change.", { cause: change });
30
+ }
31
+ }
32
+ function tokenExpiry(tokens) {
33
+ return typeof tokens.expires_in === "number" ? new Date(Date.now() + tokens.expires_in * 1e3) : null;
34
+ }
35
+ function secretByKind(secrets, kind) {
36
+ return secrets.find((secret) => secret.kind === kind);
37
+ }
38
+ const TOKEN_EXPIRY_SKEW_MS = 3e4;
39
+ function secretExpiresInFuture(secret) {
40
+ if (!secret?.expiresAt) return false;
41
+ return new Date(secret.expiresAt).getTime() > Date.now() + TOKEN_EXPIRY_SKEW_MS;
42
+ }
43
+ function secretIsUnexpired(secret) {
44
+ return !secret?.expiresAt || secretExpiresInFuture(secret);
45
+ }
46
+ /** Projects stored auth without secrets; whether credentials work can only be learned by using them. */
47
+ function projectMcpAuthStatus(args) {
48
+ const mode = args.authMode;
49
+ if (mode === "none") return { mode };
50
+ if (mode !== "oauth") return {
51
+ mode,
52
+ credentials: args.authSecret ? "present" : "missing"
53
+ };
54
+ const auth = args.authSecret ? parseSecretPayload(args.authSecret.payload) : void 0;
55
+ const tokens = auth?.type === "oauth" ? auth.tokens : void 0;
56
+ if (tokens?.access_token && (tokens.refresh_token || secretIsUnexpired(args.authSecret))) return {
57
+ mode,
58
+ state: "authorized"
59
+ };
60
+ if (args.hasPendingOAuth) return {
61
+ mode,
62
+ state: "consent-pending"
63
+ };
64
+ return {
65
+ mode,
66
+ state: tokens?.access_token ? "expired" : "consent-required"
67
+ };
68
+ }
69
+ /** Whether stored auth can authorize operations without new consent or credentials. */
70
+ function isMcpAuthReady(authMode, authSecret) {
71
+ const status = projectMcpAuthStatus({
72
+ authMode,
73
+ authSecret,
74
+ hasPendingOAuth: false
75
+ });
76
+ switch (status.mode) {
77
+ case "none": return true;
78
+ case "oauth": return status.state === "authorized";
79
+ case "bearer":
80
+ case "client_credentials": return status.credentials === "present";
81
+ default: throw new Error("Unknown MCP auth mode.", { cause: status });
82
+ }
83
+ }
84
+ /**
85
+ * When stored auth stops authorizing operations because its access token expires without renewal,
86
+ * whether or not that moment has passed. Null when a refresh token renews it or nothing expires.
87
+ */
88
+ function mcpAuthReadyUntil(authMode, authSecret) {
89
+ if (authMode !== "oauth" || !authSecret.expiresAt) return null;
90
+ const auth = parseSecretPayload(authSecret.payload);
91
+ if (auth.type !== "oauth" || !auth.tokens?.access_token || auth.tokens.refresh_token) return null;
92
+ return /* @__PURE__ */ new Date(new Date(authSecret.expiresAt).getTime() - TOKEN_EXPIRY_SKEW_MS);
93
+ }
94
+ /**
95
+ * Projects the newest unexpired, unconsumed state; any such state completes the same server.
96
+ * States started before links were retained have no URL and cannot be resumed.
97
+ */
98
+ function pendingOAuthLink(state) {
99
+ return state?.authorizationUrl ? {
100
+ authorizationUrl: state.authorizationUrl,
101
+ expiresAt: state.expiresAt
102
+ } : null;
103
+ }
104
+ /** Start requests may override the configured client; otherwise the stored configuration applies. */
105
+ function resolveOAuthStartClient(secrets, input) {
106
+ const authSecret = secretByKind(secrets, "auth");
107
+ const stored = authSecret ? parseSecretPayload(authSecret.payload) : void 0;
108
+ const configured = stored?.type === "oauth" ? stored : void 0;
109
+ return {
110
+ scope: input.scope ?? configured?.scopes?.join(" "),
111
+ ...input.clientId ? {
112
+ clientId: input.clientId,
113
+ clientSecret: input.clientSecret
114
+ } : {
115
+ clientId: configured?.clientId,
116
+ clientSecret: configured?.clientSecret
117
+ }
118
+ };
119
+ }
120
+ /** Clearing OAuth consent keeps the configured client and scopes for the next start. */
121
+ function withoutOAuthConsent(payload) {
122
+ const { tokens: _tokens, redirectUri: _redirectUri, ...configuration } = parseSecretPayload(payload);
123
+ return stringifySecretPayload(configuration);
124
+ }
125
+ async function parseSecretKind(secrets, kind) {
126
+ const secret = secretByKind(secrets, kind);
127
+ return secret ? parseSecretPayload(secret.payload) : void 0;
128
+ }
129
+ async function createOAuthStartSnapshot(args) {
130
+ const snapshot = {
131
+ serverId: args.server.id.toString(),
132
+ endpointUrl: args.server.endpointUrl,
133
+ redirectUrl: args.redirectUri,
134
+ scope: args.scope,
135
+ stateId: args.stateId,
136
+ clientId: args.clientId,
137
+ clientSecret: args.clientSecret,
138
+ clientInformation: await parseSecretKind(args.secrets, "oauth-client"),
139
+ discoveryState: await parseSecretKind(args.secrets, "oauth-discovery")
140
+ };
141
+ const provider = new BufferedOAuthClientProvider(snapshot);
142
+ await auth(provider, {
143
+ serverUrl: snapshot.endpointUrl,
144
+ scope: args.scope,
145
+ fetchFn: args.config.fetch
146
+ });
147
+ const authorizationUrl = provider.changes.authorizationUrl;
148
+ if (!authorizationUrl) throw new Error("OAuth authorization did not produce a redirect URL");
149
+ return {
150
+ authorizationUrl,
151
+ changes: await prepareOAuthChanges(provider.changes)
152
+ };
153
+ }
154
+ async function createOAuthCallbackSnapshot(args) {
155
+ const authPayload = await parseSecretKind(args.secrets, "auth");
156
+ const snapshot = {
157
+ serverId: args.server.id.toString(),
158
+ endpointUrl: args.server.endpointUrl,
159
+ redirectUrl: args.state.redirectUri,
160
+ scope: args.state.scope ?? void 0,
161
+ stateId: args.stateId,
162
+ clientInformation: await parseSecretKind(args.secrets, "oauth-client"),
163
+ tokens: authPayload?.tokens,
164
+ discoveryState: await parseSecretKind(args.secrets, "oauth-discovery"),
165
+ oauthState: {
166
+ id: args.state.id.toString(),
167
+ codeVerifier: args.state.codeVerifier,
168
+ redirectUri: args.state.redirectUri,
169
+ scope: args.state.scope ?? void 0,
170
+ expiresAt: new Date(args.state.expiresAt),
171
+ consumedAt: args.state.consumedAt ? new Date(args.state.consumedAt) : null
172
+ }
173
+ };
174
+ const provider = new BufferedOAuthClientProvider(snapshot);
175
+ await auth(provider, {
176
+ serverUrl: snapshot.endpointUrl,
177
+ authorizationCode: args.code,
178
+ iss: args.iss,
179
+ scope: snapshot.scope,
180
+ fetchFn: args.config.fetch
181
+ });
182
+ provider.consumeState();
183
+ const changes = await prepareOAuthChanges(provider.changes);
184
+ return {
185
+ ...changes,
186
+ ...changes.tokens ? {
187
+ authPayload: stringifySecretPayload({
188
+ ...authPayload,
189
+ type: "oauth",
190
+ redirectUri: args.state.redirectUri,
191
+ tokens: changes.tokens
192
+ }),
193
+ authExpiresAt: tokenExpiry(changes.tokens)
194
+ } : {}
195
+ };
196
+ }
197
+ const providerHasChanges = (changes) => Boolean(changes.clientInformation || changes.discoveryState || changes.tokens || changes.tokensInvalidated || changes.clientInvalidated || changes.discoveryInvalidated);
198
+ function authChangesReader(provider, authPayload) {
199
+ return async () => {
200
+ if (!providerHasChanges(provider.changes)) return;
201
+ const tokens = provider.tokens();
202
+ return {
203
+ ...await prepareOAuthChanges(provider.changes),
204
+ ...provider.changes.tokens || provider.changes.tokensInvalidated ? {
205
+ authPayload: stringifySecretPayload({
206
+ ...authPayload,
207
+ tokens
208
+ }),
209
+ authExpiresAt: tokens ? tokenExpiry(tokens) : null
210
+ } : {}
211
+ };
212
+ };
213
+ }
214
+ async function createMcpOperationAuth(args) {
215
+ const authSecret = secretByKind(args.secrets, "auth");
216
+ const authPayload = authSecret ? parseSecretPayload(authSecret.payload) : void 0;
217
+ if (!authPayload) return;
218
+ if (authPayload.type === "bearer") return {
219
+ type: "bearer",
220
+ token: authPayload.token
221
+ };
222
+ if (authPayload.type === "oauth") {
223
+ if (!authPayload.tokens?.access_token) return;
224
+ const clientSecret = secretByKind(args.secrets, "oauth-client");
225
+ const discoverySecret = secretByKind(args.secrets, "oauth-discovery");
226
+ const provider = new BufferedOAuthClientProvider({
227
+ serverId: args.server.id.toString(),
228
+ endpointUrl: args.server.endpointUrl,
229
+ redirectUrl: authPayload.redirectUri,
230
+ scope: authPayload.tokens.scope,
231
+ clientInformation: clientSecret ? parseSecretPayload(clientSecret.payload) : void 0,
232
+ tokens: authPayload.tokens,
233
+ discoveryState: discoverySecret ? parseSecretPayload(discoverySecret.payload) : void 0
234
+ });
235
+ return {
236
+ type: "provider",
237
+ provider,
238
+ readAuthChanges: authChangesReader(provider, authPayload)
239
+ };
240
+ }
241
+ const discoverySecret = secretByKind(args.secrets, "oauth-discovery");
242
+ const provider = new BufferedOAuthClientProvider({
243
+ serverId: args.server.id.toString(),
244
+ endpointUrl: args.server.endpointUrl,
245
+ scope: authPayload.scopes?.join(" "),
246
+ clientId: authPayload.clientId,
247
+ clientSecret: authPayload.clientSecret,
248
+ tokens: authPayload.tokens,
249
+ discoveryState: discoverySecret ? parseSecretPayload(discoverySecret.payload) : void 0,
250
+ flow: "client_credentials"
251
+ });
252
+ return {
253
+ type: "provider",
254
+ provider,
255
+ readAuthChanges: authChangesReader(provider, authPayload)
256
+ };
257
+ }
258
+ async function resolveMcpOperationAuth(args) {
259
+ const authSecret = secretByKind(args.secrets, "auth");
260
+ const authPayload = authSecret ? parseSecretPayload(authSecret.payload) : void 0;
261
+ if (!authPayload || authPayload.type === "bearer") return { token: authPayload?.token };
262
+ if (authPayload.type === "oauth") {
263
+ if (!authPayload.tokens?.access_token) return {};
264
+ if (secretIsUnexpired(authSecret)) return { token: authPayload.tokens.access_token };
265
+ if (!authPayload.tokens.refresh_token) throw new Error("OAuth access token expired and no refresh token is available");
266
+ const clientSecret = secretByKind(args.secrets, "oauth-client");
267
+ const discoverySecret = secretByKind(args.secrets, "oauth-discovery");
268
+ const provider = new BufferedOAuthClientProvider({
269
+ serverId: args.server.id.toString(),
270
+ endpointUrl: args.server.endpointUrl,
271
+ redirectUrl: authPayload.redirectUri,
272
+ scope: authPayload.tokens.scope,
273
+ clientInformation: clientSecret ? parseSecretPayload(clientSecret.payload) : void 0,
274
+ tokens: authPayload.tokens,
275
+ discoveryState: discoverySecret ? parseSecretPayload(discoverySecret.payload) : void 0
276
+ });
277
+ await auth(provider, {
278
+ serverUrl: args.server.endpointUrl,
279
+ scope: authPayload.tokens.scope,
280
+ fetchFn: args.config.fetch
281
+ });
282
+ const tokens = provider.changes.tokens ?? authPayload.tokens;
283
+ if (!tokens.access_token) throw new Error("OAuth refresh did not return an access token");
284
+ return {
285
+ token: tokens.access_token,
286
+ authChanges: {
287
+ ...await prepareOAuthChanges(provider.changes),
288
+ authPayload: stringifySecretPayload({
289
+ ...authPayload,
290
+ tokens
291
+ }),
292
+ authExpiresAt: tokenExpiry(tokens)
293
+ }
294
+ };
295
+ }
296
+ if (authPayload.tokens?.access_token && secretExpiresInFuture(authSecret)) return { token: authPayload.tokens.access_token };
297
+ const discoverySecret = secretByKind(args.secrets, "oauth-discovery");
298
+ const provider = new BufferedOAuthClientProvider({
299
+ serverId: args.server.id.toString(),
300
+ endpointUrl: args.server.endpointUrl,
301
+ scope: authPayload.scopes?.join(" "),
302
+ clientId: authPayload.clientId,
303
+ clientSecret: authPayload.clientSecret,
304
+ tokens: authPayload.tokens,
305
+ discoveryState: discoverySecret ? parseSecretPayload(discoverySecret.payload) : void 0,
306
+ flow: "client_credentials"
307
+ });
308
+ await auth(provider, {
309
+ serverUrl: args.server.endpointUrl,
310
+ scope: authPayload.scopes?.join(" "),
311
+ fetchFn: args.config.fetch
312
+ });
313
+ const tokens = provider.changes.tokens ?? authPayload.tokens;
314
+ if (!tokens?.access_token) throw new Error("Client credentials flow did not return an access token");
315
+ return {
316
+ token: tokens.access_token,
317
+ authChanges: {
318
+ ...await prepareOAuthChanges(provider.changes),
319
+ authPayload: stringifySecretPayload({
320
+ ...authPayload,
321
+ tokens
322
+ }),
323
+ authExpiresAt: tokenExpiry(tokens)
324
+ }
325
+ };
326
+ }
327
+ //#endregion
328
+ export { createMcpOperationAuth, createOAuthCallbackSnapshot, createOAuthStartSnapshot, isMcpAuthReady, mcpAuthReadyUntil, pendingOAuthLink, prepareOAuthChanges, projectMcpAuthStatus, resolveMcpOperationAuth, resolveOAuthStartClient, tokenExpiry, withoutOAuthConsent, writeOAuthSecretChanges };
329
+
330
+ //# sourceMappingURL=services.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.js","names":[],"sources":["../../src/services.ts"],"sourcesContent":["import { auth, type OAuthTokens } from \"@modelcontextprotocol/client\";\n\nimport { parseSecretPayload, stringifySecretPayload, type McpClientAuth } from \"./mcp-api\";\nimport type { AuthConfig, McpAuthStatus, McpFragmentConfig } from \"./mcp-types\";\nimport {\n BufferedOAuthClientProvider,\n type OAuthProviderChanges,\n type OAuthProviderSnapshot,\n} from \"./oauth-provider\";\n\n/** A buffered OAuth secret is kept, replaced, or removed because the server rejected it. */\ntype OAuthSecretChange =\n | { action: \"keep\" }\n | { action: \"save\"; payload: string }\n | { action: \"remove\" };\n\nfunction oauthSecretChange(value: unknown, invalidated: boolean | undefined): OAuthSecretChange {\n if (value) {\n return { action: \"save\", payload: stringifySecretPayload(value) };\n }\n return invalidated ? { action: \"remove\" } : { action: \"keep\" };\n}\n\nexport async function prepareOAuthChanges(changes: OAuthProviderChanges) {\n return {\n ...changes,\n clientChange: oauthSecretChange(changes.clientInformation, changes.clientInvalidated),\n discoveryChange: oauthSecretChange(changes.discoveryState, changes.discoveryInvalidated),\n };\n}\n\n/** Applies the client and discovery changes through a write site's own secret writers. */\nexport function writeOAuthSecretChanges(\n changes: Pick<AuthPersistenceChanges, \"clientChange\" | \"discoveryChange\">,\n writers: { upsert(kind: string, payload: string): void; remove(kind: string): void },\n) {\n for (const [kind, change] of [\n [\"oauth-client\", changes.clientChange],\n [\"oauth-discovery\", changes.discoveryChange],\n ] as const) {\n switch (change.action) {\n case \"keep\":\n break;\n case \"save\":\n writers.upsert(kind, change.payload);\n break;\n case \"remove\":\n writers.remove(kind);\n break;\n default:\n throw new Error(\"Unknown OAuth secret change.\", { cause: change satisfies never });\n }\n }\n}\n\nexport function tokenExpiry(tokens: NonNullable<OAuthProviderChanges[\"tokens\"]>): Date | null {\n return typeof tokens.expires_in === \"number\"\n ? new Date(Date.now() + tokens.expires_in * 1000)\n : null;\n}\n\nexport type AuthPersistenceChanges = Awaited<ReturnType<typeof prepareOAuthChanges>> & {\n authPayload?: string;\n authExpiresAt?: Date | null;\n};\n\nexport type McpOperationAuth = McpClientAuth<AuthPersistenceChanges>;\n\nexport type SecretRecord = {\n id: { toString(): string } | string;\n kind: string;\n payload: string;\n expiresAt?: Date | string | null;\n};\n\n// OAuth payloads hold the creation-time configuration until consent adds tokens and a redirect URI.\ntype StoredAuthPayload =\n | { type: \"bearer\"; token: string }\n | (Omit<Extract<AuthConfig, { type: \"oauth\" }>, \"type\"> & {\n type: \"oauth\";\n tokens?: OAuthTokens;\n redirectUri?: string;\n })\n | {\n type: \"client_credentials\";\n clientId: string;\n clientSecret: string;\n scopes?: string[];\n tokens?: NonNullable<OAuthProviderChanges[\"tokens\"]>;\n };\n\nfunction secretByKind<TSecret extends { kind: string }>(secrets: TSecret[], kind: string) {\n return secrets.find((secret) => secret.kind === kind);\n}\n\nconst TOKEN_EXPIRY_SKEW_MS = 30_000;\n\nfunction secretExpiresInFuture(secret: Pick<SecretRecord, \"expiresAt\"> | undefined) {\n if (!secret?.expiresAt) {\n return false;\n }\n return new Date(secret.expiresAt).getTime() > Date.now() + TOKEN_EXPIRY_SKEW_MS;\n}\n\nfunction secretIsUnexpired(secret: Pick<SecretRecord, \"expiresAt\"> | undefined) {\n return !secret?.expiresAt || secretExpiresInFuture(secret);\n}\n\n/** Projects stored auth without secrets; whether credentials work can only be learned by using them. */\nexport function projectMcpAuthStatus(args: {\n authMode: string;\n authSecret: Pick<SecretRecord, \"payload\" | \"expiresAt\"> | undefined;\n hasPendingOAuth: boolean;\n}): McpAuthStatus {\n // Routes write authMode only from authConfigSchema discriminators.\n const mode = args.authMode as AuthConfig[\"type\"];\n if (mode === \"none\") {\n return { mode };\n }\n if (mode !== \"oauth\") {\n return { mode, credentials: args.authSecret ? \"present\" : \"missing\" };\n }\n const auth = args.authSecret\n ? parseSecretPayload<StoredAuthPayload>(args.authSecret.payload)\n : undefined;\n const tokens = auth?.type === \"oauth\" ? auth.tokens : undefined;\n // Matches operation-time resolution: a refresh token renews an expired access token.\n if (tokens?.access_token && (tokens.refresh_token || secretIsUnexpired(args.authSecret))) {\n return { mode, state: \"authorized\" };\n }\n // Expired tokens without a refresh token are unusable, so a pending link is the actionable state.\n if (args.hasPendingOAuth) {\n return { mode, state: \"consent-pending\" };\n }\n return { mode, state: tokens?.access_token ? \"expired\" : \"consent-required\" };\n}\n\n/** Whether stored auth can authorize operations without new consent or credentials. */\nexport function isMcpAuthReady(\n authMode: string,\n authSecret: Pick<SecretRecord, \"payload\" | \"expiresAt\"> | undefined,\n): boolean {\n // Pending consent only distinguishes states that are not ready.\n const status = projectMcpAuthStatus({ authMode, authSecret, hasPendingOAuth: false });\n switch (status.mode) {\n case \"none\":\n return true;\n case \"oauth\":\n return status.state === \"authorized\";\n case \"bearer\":\n case \"client_credentials\":\n return status.credentials === \"present\";\n default:\n throw new Error(\"Unknown MCP auth mode.\", { cause: status satisfies never });\n }\n}\n\n/**\n * When stored auth stops authorizing operations because its access token expires without renewal,\n * whether or not that moment has passed. Null when a refresh token renews it or nothing expires.\n */\nexport function mcpAuthReadyUntil(\n authMode: string,\n authSecret: Pick<SecretRecord, \"payload\" | \"expiresAt\">,\n): Date | null {\n if (authMode !== \"oauth\" || !authSecret.expiresAt) {\n return null;\n }\n const auth = parseSecretPayload<StoredAuthPayload>(authSecret.payload);\n if (auth.type !== \"oauth\" || !auth.tokens?.access_token || auth.tokens.refresh_token) {\n return null;\n }\n return new Date(new Date(authSecret.expiresAt).getTime() - TOKEN_EXPIRY_SKEW_MS);\n}\n\n/**\n * Projects the newest unexpired, unconsumed state; any such state completes the same server.\n * States started before links were retained have no URL and cannot be resumed.\n */\nexport function pendingOAuthLink(\n state: { authorizationUrl: string | null; expiresAt: Date } | null,\n): { authorizationUrl: string; expiresAt: Date } | null {\n return state?.authorizationUrl\n ? { authorizationUrl: state.authorizationUrl, expiresAt: state.expiresAt }\n : null;\n}\n\n/** Start requests may override the configured client; otherwise the stored configuration applies. */\nexport function resolveOAuthStartClient(\n secrets: Pick<SecretRecord, \"kind\" | \"payload\">[],\n input: { scope?: string; clientId?: string; clientSecret?: string },\n) {\n const authSecret = secretByKind(secrets, \"auth\");\n const stored = authSecret ? parseSecretPayload<StoredAuthPayload>(authSecret.payload) : undefined;\n const configured = stored?.type === \"oauth\" ? stored : undefined;\n return {\n scope: input.scope ?? configured?.scopes?.join(\" \"),\n // A client ID and secret belong together; never pair an override with a stored secret.\n ...(input.clientId\n ? { clientId: input.clientId, clientSecret: input.clientSecret }\n : { clientId: configured?.clientId, clientSecret: configured?.clientSecret }),\n };\n}\n\n/** Clearing OAuth consent keeps the configured client and scopes for the next start. */\nexport function withoutOAuthConsent(payload: string) {\n const {\n tokens: _tokens,\n redirectUri: _redirectUri,\n ...configuration\n } = parseSecretPayload<Extract<StoredAuthPayload, { type: \"oauth\" }>>(payload);\n return stringifySecretPayload(configuration);\n}\n\nasync function parseSecretKind<T>(\n secrets: Pick<SecretRecord, \"kind\" | \"payload\">[],\n kind: string,\n): Promise<T | undefined> {\n const secret = secretByKind(secrets, kind);\n return secret ? parseSecretPayload<T>(secret.payload) : undefined;\n}\n\nexport async function createOAuthStartSnapshot(args: {\n config: McpFragmentConfig;\n server: { id: { toString(): string } | string; endpointUrl: string };\n secrets: Pick<SecretRecord, \"kind\" | \"payload\">[];\n stateId: string;\n redirectUri: string;\n scope?: string;\n clientId?: string;\n clientSecret?: string;\n}): Promise<{\n authorizationUrl: URL;\n changes: Awaited<ReturnType<typeof prepareOAuthChanges>>;\n}> {\n const snapshot: OAuthProviderSnapshot = {\n serverId: args.server.id.toString(),\n endpointUrl: args.server.endpointUrl,\n redirectUrl: args.redirectUri,\n scope: args.scope,\n stateId: args.stateId,\n clientId: args.clientId,\n clientSecret: args.clientSecret,\n clientInformation: await parseSecretKind(args.secrets, \"oauth-client\"),\n discoveryState: await parseSecretKind(args.secrets, \"oauth-discovery\"),\n };\n const provider = new BufferedOAuthClientProvider(snapshot);\n await auth(provider, {\n serverUrl: snapshot.endpointUrl,\n scope: args.scope,\n fetchFn: args.config.fetch,\n });\n const authorizationUrl = provider.changes.authorizationUrl;\n if (!authorizationUrl) {\n throw new Error(\"OAuth authorization did not produce a redirect URL\");\n }\n return { authorizationUrl, changes: await prepareOAuthChanges(provider.changes) };\n}\n\nexport async function createOAuthCallbackSnapshot(args: {\n config: McpFragmentConfig;\n stateId: string;\n code: string;\n iss: string | undefined;\n state: {\n id: { toString(): string } | string;\n codeVerifier: string;\n redirectUri: string;\n scope?: string | null;\n expiresAt: Date | string;\n consumedAt?: Date | string | null;\n };\n server: { id: { toString(): string } | string; endpointUrl: string };\n secrets: Pick<SecretRecord, \"kind\" | \"payload\">[];\n}): Promise<AuthPersistenceChanges> {\n const authPayload = await parseSecretKind<Extract<StoredAuthPayload, { type: \"oauth\" }>>(\n args.secrets,\n \"auth\",\n );\n const snapshot: OAuthProviderSnapshot = {\n serverId: args.server.id.toString(),\n endpointUrl: args.server.endpointUrl,\n redirectUrl: args.state.redirectUri,\n scope: args.state.scope ?? undefined,\n stateId: args.stateId,\n clientInformation: await parseSecretKind(args.secrets, \"oauth-client\"),\n tokens: authPayload?.tokens,\n discoveryState: await parseSecretKind(args.secrets, \"oauth-discovery\"),\n oauthState: {\n id: args.state.id.toString(),\n codeVerifier: args.state.codeVerifier,\n redirectUri: args.state.redirectUri,\n scope: args.state.scope ?? undefined,\n expiresAt: new Date(args.state.expiresAt),\n consumedAt: args.state.consumedAt ? new Date(args.state.consumedAt) : null,\n },\n };\n const provider = new BufferedOAuthClientProvider(snapshot);\n await auth(provider, {\n serverUrl: snapshot.endpointUrl,\n authorizationCode: args.code,\n iss: args.iss,\n scope: snapshot.scope,\n fetchFn: args.config.fetch,\n });\n provider.consumeState();\n const changes = await prepareOAuthChanges(provider.changes);\n return {\n ...changes,\n ...(changes.tokens\n ? {\n // Keep the configured client and scopes so consent can be started again later.\n authPayload: stringifySecretPayload({\n ...authPayload,\n type: \"oauth\",\n redirectUri: args.state.redirectUri,\n tokens: changes.tokens,\n }),\n authExpiresAt: tokenExpiry(changes.tokens),\n }\n : {}),\n };\n}\n\nconst providerHasChanges = (changes: OAuthProviderChanges) =>\n Boolean(\n changes.clientInformation ||\n changes.discoveryState ||\n changes.tokens ||\n changes.tokensInvalidated ||\n changes.clientInvalidated ||\n changes.discoveryInvalidated,\n );\n\nfunction authChangesReader(\n provider: BufferedOAuthClientProvider,\n authPayload: Exclude<StoredAuthPayload, { type: \"bearer\" }>,\n) {\n return async (): Promise<AuthPersistenceChanges | undefined> => {\n if (!providerHasChanges(provider.changes)) {\n return undefined;\n }\n const tokens = provider.tokens();\n return {\n ...(await prepareOAuthChanges(provider.changes)),\n ...(provider.changes.tokens || provider.changes.tokensInvalidated\n ? {\n authPayload: stringifySecretPayload({ ...authPayload, tokens }),\n authExpiresAt: tokens ? tokenExpiry(tokens) : null,\n }\n : {}),\n };\n };\n}\n\nexport async function createMcpOperationAuth(args: {\n config: McpFragmentConfig;\n server: { id: { toString(): string } | string; endpointUrl: string };\n secrets: SecretRecord[];\n}): Promise<McpOperationAuth | undefined> {\n const authSecret = secretByKind(args.secrets, \"auth\");\n const authPayload = authSecret\n ? parseSecretPayload<StoredAuthPayload>(authSecret.payload)\n : undefined;\n if (!authPayload) {\n return undefined;\n }\n if (authPayload.type === \"bearer\") {\n return { type: \"bearer\", token: authPayload.token };\n }\n if (authPayload.type === \"oauth\") {\n if (!authPayload.tokens?.access_token) {\n return undefined;\n }\n const clientSecret = secretByKind(args.secrets, \"oauth-client\");\n const discoverySecret = secretByKind(args.secrets, \"oauth-discovery\");\n const provider = new BufferedOAuthClientProvider({\n serverId: args.server.id.toString(),\n endpointUrl: args.server.endpointUrl,\n redirectUrl: authPayload.redirectUri,\n scope: authPayload.tokens.scope,\n clientInformation: clientSecret ? parseSecretPayload(clientSecret.payload) : undefined,\n tokens: authPayload.tokens,\n discoveryState: discoverySecret ? parseSecretPayload(discoverySecret.payload) : undefined,\n });\n return {\n type: \"provider\",\n provider,\n readAuthChanges: authChangesReader(provider, authPayload),\n };\n }\n\n const discoverySecret = secretByKind(args.secrets, \"oauth-discovery\");\n const provider = new BufferedOAuthClientProvider({\n serverId: args.server.id.toString(),\n endpointUrl: args.server.endpointUrl,\n scope: authPayload.scopes?.join(\" \"),\n clientId: authPayload.clientId,\n clientSecret: authPayload.clientSecret,\n tokens: authPayload.tokens,\n discoveryState: discoverySecret ? parseSecretPayload(discoverySecret.payload) : undefined,\n flow: \"client_credentials\",\n });\n return {\n type: \"provider\",\n provider,\n readAuthChanges: authChangesReader(provider, authPayload),\n };\n}\n\nexport async function resolveMcpOperationAuth(args: {\n config: McpFragmentConfig;\n server: { id: { toString(): string } | string; endpointUrl: string };\n secrets: SecretRecord[];\n}): Promise<{\n token?: string;\n authChanges?: AuthPersistenceChanges;\n}> {\n const authSecret = secretByKind(args.secrets, \"auth\");\n const authPayload = authSecret\n ? parseSecretPayload<StoredAuthPayload>(authSecret.payload)\n : undefined;\n if (!authPayload || authPayload.type === \"bearer\") {\n return { token: authPayload?.token };\n }\n if (authPayload.type === \"oauth\") {\n if (!authPayload.tokens?.access_token) {\n return {};\n }\n if (secretIsUnexpired(authSecret)) {\n return { token: authPayload.tokens.access_token };\n }\n if (!authPayload.tokens.refresh_token) {\n throw new Error(\"OAuth access token expired and no refresh token is available\");\n }\n\n const clientSecret = secretByKind(args.secrets, \"oauth-client\");\n const discoverySecret = secretByKind(args.secrets, \"oauth-discovery\");\n const provider = new BufferedOAuthClientProvider({\n serverId: args.server.id.toString(),\n endpointUrl: args.server.endpointUrl,\n redirectUrl: authPayload.redirectUri,\n scope: authPayload.tokens.scope,\n clientInformation: clientSecret ? parseSecretPayload(clientSecret.payload) : undefined,\n tokens: authPayload.tokens,\n discoveryState: discoverySecret ? parseSecretPayload(discoverySecret.payload) : undefined,\n });\n await auth(provider, {\n serverUrl: args.server.endpointUrl,\n scope: authPayload.tokens.scope,\n fetchFn: args.config.fetch,\n });\n const tokens = provider.changes.tokens ?? authPayload.tokens;\n if (!tokens.access_token) {\n throw new Error(\"OAuth refresh did not return an access token\");\n }\n return {\n token: tokens.access_token,\n authChanges: {\n ...(await prepareOAuthChanges(provider.changes)),\n authPayload: stringifySecretPayload({ ...authPayload, tokens }),\n authExpiresAt: tokenExpiry(tokens),\n },\n };\n }\n\n if (authPayload.tokens?.access_token && secretExpiresInFuture(authSecret)) {\n return { token: authPayload.tokens.access_token };\n }\n\n const discoverySecret = secretByKind(args.secrets, \"oauth-discovery\");\n const provider = new BufferedOAuthClientProvider({\n serverId: args.server.id.toString(),\n endpointUrl: args.server.endpointUrl,\n scope: authPayload.scopes?.join(\" \"),\n clientId: authPayload.clientId,\n clientSecret: authPayload.clientSecret,\n tokens: authPayload.tokens,\n discoveryState: discoverySecret ? parseSecretPayload(discoverySecret.payload) : undefined,\n flow: \"client_credentials\",\n });\n await auth(provider, {\n serverUrl: args.server.endpointUrl,\n scope: authPayload.scopes?.join(\" \"),\n fetchFn: args.config.fetch,\n });\n const tokens = provider.changes.tokens ?? authPayload.tokens;\n if (!tokens?.access_token) {\n throw new Error(\"Client credentials flow did not return an access token\");\n }\n return {\n token: tokens.access_token,\n authChanges: {\n ...(await prepareOAuthChanges(provider.changes)),\n authPayload: stringifySecretPayload({ ...authPayload, tokens }),\n authExpiresAt: tokenExpiry(tokens),\n },\n };\n}\n"],"mappings":"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"}