@powerhousedao/reactor-api 6.2.3-dev.5 → 6.2.3-dev.50

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 (45) hide show
  1. package/README.md +7 -2
  2. package/dist/{adapter-gateway-apollo-CxJNBVyD.mjs → adapter-gateway-apollo-B54G_cXT.mjs} +15 -13
  3. package/dist/{adapter-gateway-apollo-CxJNBVyD.mjs.map → adapter-gateway-apollo-B54G_cXT.mjs.map} +1 -1
  4. package/dist/{adapter-gateway-apollo-DowrX6E_.mjs → adapter-gateway-apollo-D2DNlPY0.mjs} +3 -3
  5. package/dist/{adapter-gateway-mercurius-CZVy88Za.mjs → adapter-gateway-mercurius-rbKlwF9m.mjs} +4 -4
  6. package/dist/{adapter-gateway-mercurius-CZVy88Za.mjs.map → adapter-gateway-mercurius-rbKlwF9m.mjs.map} +1 -1
  7. package/dist/{adapter-gateway-stitching-CaZjvRzx.mjs → adapter-gateway-stitching-Dzv10u8D.mjs} +15 -10
  8. package/dist/{adapter-gateway-stitching-CaZjvRzx.mjs.map → adapter-gateway-stitching-Dzv10u8D.mjs.map} +1 -1
  9. package/dist/{adapter-http-express-B39rPhqH.mjs → adapter-http-express-P0t-mdMV.mjs} +10 -10
  10. package/dist/adapter-http-express-P0t-mdMV.mjs.map +1 -0
  11. package/dist/{adapter-http-fastify-BwXO6rqE.mjs → adapter-http-fastify-D0OP5q9K.mjs} +13 -12
  12. package/dist/adapter-http-fastify-D0OP5q9K.mjs.map +1 -0
  13. package/dist/index.d.mts +1621 -604
  14. package/dist/index.d.mts.map +1 -1
  15. package/dist/index.mjs +2622 -617
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/pglite-node-Ow9i5Rb4.mjs +573 -0
  18. package/dist/pglite-node-Ow9i5Rb4.mjs.map +1 -0
  19. package/dist/rolldown-runtime-8H4AJuhK.mjs +16 -0
  20. package/dist/run-node-handler-CQjyjOuN.mjs +52 -0
  21. package/dist/run-node-handler-CQjyjOuN.mjs.map +1 -0
  22. package/dist/src/packages/https-hooks.d.mts +4 -4
  23. package/dist/src/packages/https-hooks.d.mts.map +1 -1
  24. package/dist/src/packages/https-hooks.mjs +2 -2
  25. package/dist/src/packages/https-hooks.mjs.map +1 -1
  26. package/dist/src/packages/vite-loader.d.mts +19 -9
  27. package/dist/src/packages/vite-loader.d.mts.map +1 -1
  28. package/dist/src/packages/vite-loader.mjs +114 -50
  29. package/dist/src/packages/vite-loader.mjs.map +1 -1
  30. package/dist/src/pglite/pglite-node.d.mts +130 -0
  31. package/dist/src/pglite/pglite-node.d.mts.map +1 -0
  32. package/dist/src/pglite/pglite-node.mjs +4 -0
  33. package/dist/{utils-XWVecaNn.mjs → subgraph-extraction-DTFoN_bS.mjs} +266 -11
  34. package/dist/subgraph-extraction-DTFoN_bS.mjs.map +1 -0
  35. package/dist/{types-DcYyNcHJ.d.mts → types-DlTiz6AA.d.mts} +27 -4
  36. package/dist/types-DlTiz6AA.d.mts.map +1 -0
  37. package/dist/{websocket-DncAB9XK.mjs → websocket-_SH5aBcy.mjs} +3 -3
  38. package/dist/{websocket-DncAB9XK.mjs.map → websocket-_SH5aBcy.mjs.map} +1 -1
  39. package/package.json +24 -19
  40. package/dist/adapter-http-express-B39rPhqH.mjs.map +0 -1
  41. package/dist/adapter-http-fastify-BwXO6rqE.mjs.map +0 -1
  42. package/dist/path-normalize-BOQwY9wR.mjs +0 -23
  43. package/dist/path-normalize-BOQwY9wR.mjs.map +0 -1
  44. package/dist/types-DcYyNcHJ.d.mts.map +0 -1
  45. package/dist/utils-XWVecaNn.mjs.map +0 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @powerhousedao/reactor-api
2
2
 
3
- A powerful API server implementation for the Powerhouse ecosystem that provides GraphQL capabilities, document processing, and package management.
3
+ An API server for Powerhouse: GraphQL, document processing and package management.
4
4
 
5
5
  ## Features
6
6
 
@@ -39,12 +39,17 @@ const api = await startAPI(reactor, {
39
39
 
40
40
  ### API Server
41
41
 
42
- The API server provides a robust Express-based implementation with GraphQL support, authentication middleware, and HTTPS capabilities.
42
+ An Express server with GraphQL, authentication middleware and HTTPS.
43
43
 
44
44
  ### Package Manager
45
45
 
46
46
  Manages document models, subgraphs, and processors through a flexible loading system that supports multiple package sources.
47
47
 
48
+ It also finds each package's pieces through its `./pieces` export, the built
49
+ `pieces/index.ts` list. It imports only that list, never piece code, reads each
50
+ piece's version from the package's `package.json`, and hands the entry paths to
51
+ the workflow runtime, which runs them in a forked worker.
52
+
48
53
  ### GraphQL Manager
49
54
 
50
55
  Handles GraphQL operations, subgraph management, and schema composition using Apollo Server.
@@ -1,6 +1,6 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="809aa815-7246-5ce0-b96c-d0e4099401e4")}catch(e){}}();
3
- import { t as useServer } from "./websocket-DncAB9XK.mjs";
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="cec74315-a3ad-5b30-a06a-f13108285db4")}catch(e){}}();
3
+ import { t as useServer } from "./websocket-_SH5aBcy.mjs";
4
4
  import { buildSubgraphSchema } from "@apollo/subgraph";
5
5
  import { ApolloGateway, LocalCompose, RemoteGraphQLDataSource } from "@apollo/gateway";
6
6
  import { ApolloServer, HeaderMap } from "@apollo/server";
@@ -66,14 +66,15 @@ var ApolloGatewayAdapter = class {
66
66
  async createSupergraphHandler(getSubgraphs, httpServer, contextFactory) {
67
67
  if (this.#supergraphServer) throw new Error("Supergraph server is already running");
68
68
  this.#getSubgraphs = getSubgraphs;
69
+ const gateway = new ApolloGateway({
70
+ supergraphSdl: async (options) => {
71
+ this.#gatewayOptions = options;
72
+ return await this.#buildSupergraphSdl();
73
+ },
74
+ buildService: (serviceConfig) => new AuthenticatedDataSource(serviceConfig)
75
+ });
69
76
  this.#supergraphServer = new ApolloServer({
70
- gateway: new ApolloGateway({
71
- supergraphSdl: async (options) => {
72
- this.#gatewayOptions = options;
73
- return await this.#buildSupergraphSdl();
74
- },
75
- buildService: (serviceConfig) => new AuthenticatedDataSource(serviceConfig)
76
- }),
77
+ gateway,
77
78
  logger: this.#logger,
78
79
  introspection: true,
79
80
  stopOnTerminationSignals: false,
@@ -93,11 +94,12 @@ var ApolloGatewayAdapter = class {
93
94
  }
94
95
  async #buildSupergraphSdl() {
95
96
  if (!this.#gatewayOptions || !this.#getSubgraphs) throw new Error("Gateway is not ready");
96
- return new LocalCompose({ localServiceList: filterComposableSubgraphs(this.#getSubgraphs().map((s) => ({
97
+ const composableServiceList = filterComposableSubgraphs(this.#getSubgraphs().map((s) => ({
97
98
  name: s.name,
98
99
  typeDefs: s.typeDefs,
99
100
  url: s.url
100
- })), this.#logger) }).initialize(this.#gatewayOptions);
101
+ })), this.#logger);
102
+ return new LocalCompose({ localServiceList: composableServiceList }).initialize(this.#gatewayOptions);
101
103
  }
102
104
  attachWebSocket(wsServer, schema, handlers) {
103
105
  return useServer({
@@ -157,5 +159,5 @@ function createApolloFetchHandler(server, contextFactory) {
157
159
  //#endregion
158
160
  export { createApolloFetchHandler as n, filterComposableSubgraphs as r, ApolloGatewayAdapter as t };
159
161
 
160
- //# sourceMappingURL=adapter-gateway-apollo-CxJNBVyD.mjs.map
161
- //# debugId=809aa815-7246-5ce0-b96c-d0e4099401e4
162
+ //# sourceMappingURL=adapter-gateway-apollo-B54G_cXT.mjs.map
163
+ //# debugId=cec74315-a3ad-5b30-a06a-f13108285db4
@@ -1 +1 @@
1
- {"version":3,"file":"adapter-gateway-apollo-CxJNBVyD.mjs","sources":["../src/graphql/gateway/adapter-gateway-apollo.ts"],"sourcesContent":["import type {\n GetDataSourceFunction,\n GraphQLDataSourceProcessOptions,\n ServiceDefinition,\n SubgraphHealthCheckFunction,\n SupergraphSdlUpdateFunction,\n} from \"@apollo/gateway\";\nimport {\n ApolloGateway,\n LocalCompose,\n RemoteGraphQLDataSource,\n} from \"@apollo/gateway\";\nimport { ApolloServer, HeaderMap } from \"@apollo/server\";\nimport { ApolloServerPluginInlineTraceDisabled } from \"@apollo/server/plugin/disabled\";\nimport { ApolloServerPluginDrainHttpServer } from \"@apollo/server/plugin/drainHttpServer\";\nimport { ApolloServerPluginLandingPageLocalDefault } from \"@apollo/server/plugin/landingPage/default\";\nimport { buildSubgraphSchema } from \"@apollo/subgraph\";\nimport type { ILogger } from \"document-model\";\nimport type { GraphQLSchema } from \"graphql\";\nimport type http from \"node:http\";\nimport type { WebSocketServer } from \"ws\";\nimport type { Context } from \"../types.js\";\nimport { useServer } from \"../websocket.js\";\nimport type {\n FetchHandler,\n GatewayContextFactory,\n IGatewayAdapter,\n SubgraphDefinition,\n WsDisposer,\n WsHandlers,\n} from \"./types.js\";\n\n/**\n * Drop subgraphs whose typeDefs cannot be built into a valid subgraph schema in\n * isolation — e.g. a duplicate type definition within a single subgraph (Sentry\n * #917) — so one broken subgraph is excluded instead of failing the build for\n * everyone. Each excluded subgraph is logged; the rest are composed.\n *\n * Scope: this only catches per-subgraph build failures. Errors that surface only\n * when subgraphs are composed together (cross-subgraph type or `@key` conflicts)\n * are still thrown by `LocalCompose.initialize()` and are NOT handled here.\n */\nexport function filterComposableSubgraphs(\n serviceList: ServiceDefinition[],\n logger?: Pick<ILogger, \"error\">,\n): ServiceDefinition[] {\n return serviceList.filter((service) => {\n try {\n // Array form: @apollo/subgraph 2.15 dropped the bare-module overload.\n buildSubgraphSchema([{ typeDefs: service.typeDefs }]);\n return true;\n } catch (error) {\n logger?.error(\n `Excluding subgraph \"${service.name}\" from supergraph composition: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n return false;\n }\n });\n}\n\n// Forwards the incoming authorization header to federated subgraph requests.\nclass AuthenticatedDataSource extends RemoteGraphQLDataSource {\n constructor(\n config?: ConstructorParameters<typeof RemoteGraphQLDataSource>[0],\n ) {\n // Node's fetch retires a pooled connection before the subgraph server's advertised keep-alive\n // timeout; Apollo's default make-fetch-happen agent holds it until the server closes it under us.\n super({\n fetcher: fetch as RemoteGraphQLDataSource[\"fetcher\"],\n ...config,\n });\n }\n\n willSendRequest(options: GraphQLDataSourceProcessOptions) {\n const { authorization } = options.context.headers as {\n authorization: string;\n };\n if (authorization && options?.request.http) {\n options.request.http.headers.set(\"authorization\", authorization);\n }\n }\n}\n\nexport class ApolloGatewayAdapter implements IGatewayAdapter<Context> {\n readonly #logger: ILogger;\n readonly #servers: ApolloServer<Context>[] = [];\n\n #supergraphServer: ApolloServer<Context> | null = null;\n #gatewayOptions: {\n update: SupergraphSdlUpdateFunction;\n healthCheck: SubgraphHealthCheckFunction;\n getDataSource: GetDataSourceFunction;\n } | null = null;\n #getSubgraphs: (() => SubgraphDefinition[]) | null = null;\n\n constructor(logger: ILogger) {\n this.#logger = logger;\n }\n\n async start(_httpServer: http.Server): Promise<void> {\n // Per-subgraph Apollo servers start lazily in createHandler.\n // Nothing to do here.\n }\n\n async createHandler(\n schema: GraphQLSchema,\n contextFactory: GatewayContextFactory<Context>,\n ): Promise<FetchHandler> {\n const server = new ApolloServer<Context>({\n schema,\n logger: this.#logger,\n introspection: true,\n // Each ApolloServer otherwise registers its own SIGINT/SIGTERM handler\n // that re-emits the signal via process.kill after server.stop() resolves.\n // With many subgraph servers that re-emit lands while the reactor's\n // graceful-shutdown chain is mid-flight, looking like a \"second SIGINT\"\n // to the reactor and aborting cleanup. The reactor drives our shutdown\n // end-to-end (see ReactorBuilder.attachSignalHandlers), so opt out.\n stopOnTerminationSignals: false,\n plugins: [\n ApolloServerPluginInlineTraceDisabled(),\n ApolloServerPluginLandingPageLocalDefault(),\n ],\n });\n await server.start();\n this.#servers.push(server);\n return createApolloFetchHandler(server, contextFactory);\n }\n\n async createSupergraphHandler(\n getSubgraphs: () => SubgraphDefinition[],\n httpServer: http.Server,\n contextFactory: GatewayContextFactory<Context>,\n ): Promise<FetchHandler> {\n if (this.#supergraphServer) {\n throw new Error(\"Supergraph server is already running\");\n }\n\n this.#getSubgraphs = getSubgraphs;\n\n const gateway = new ApolloGateway({\n supergraphSdl: async (options) => {\n this.#gatewayOptions = options;\n return await this.#buildSupergraphSdl();\n },\n buildService: (serviceConfig) =>\n new AuthenticatedDataSource(serviceConfig),\n });\n\n this.#supergraphServer = new ApolloServer<Context>({\n gateway,\n logger: this.#logger,\n introspection: true,\n stopOnTerminationSignals: false,\n plugins: [\n ApolloServerPluginDrainHttpServer({ httpServer }),\n ApolloServerPluginInlineTraceDisabled(),\n ApolloServerPluginLandingPageLocalDefault(),\n ],\n });\n\n await this.#supergraphServer.start();\n return createApolloFetchHandler(this.#supergraphServer, contextFactory);\n }\n\n async updateSupergraph(): Promise<void> {\n if (!this.#gatewayOptions || !this.#getSubgraphs) {\n // Not yet initialized - no-op.\n return;\n }\n const { supergraphSdl } = await this.#buildSupergraphSdl();\n this.#gatewayOptions.update(supergraphSdl);\n }\n\n async #buildSupergraphSdl() {\n if (!this.#gatewayOptions || !this.#getSubgraphs) {\n throw new Error(\"Gateway is not ready\");\n }\n const serviceList: ServiceDefinition[] = this.#getSubgraphs().map((s) => ({\n name: s.name,\n typeDefs: s.typeDefs,\n url: s.url,\n }));\n const composableServiceList = filterComposableSubgraphs(\n serviceList,\n this.#logger,\n );\n const localCompose = new LocalCompose({\n localServiceList: composableServiceList,\n });\n return localCompose.initialize(this.#gatewayOptions);\n }\n\n attachWebSocket(\n wsServer: WebSocketServer,\n schema: GraphQLSchema,\n handlers: WsHandlers<Context>,\n ): WsDisposer {\n return useServer(\n {\n schema,\n onConnect: (ctx) =>\n handlers.onConnect(ctx.connectionParams ?? {}, ctx.extra as object),\n context: (ctx) =>\n handlers.context(ctx.connectionParams ?? {}, ctx.extra as object),\n },\n wsServer,\n );\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.#servers.map((s) => s.stop()));\n this.#servers.length = 0;\n\n if (this.#supergraphServer) {\n await this.#supergraphServer.stop();\n this.#supergraphServer = null;\n }\n this.#gatewayOptions = null;\n this.#getSubgraphs = null;\n }\n}\n\n/**\n * Wrap an existing ApolloServer as a Fetch API handler.\n * Does not manage server lifecycle; caller is responsible for start/stop.\n */\nexport function createApolloFetchHandler(\n server: ApolloServer<Context>,\n contextFactory: GatewayContextFactory<Context>,\n): FetchHandler {\n return async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n const headers = new HeaderMap();\n request.headers.forEach((value, key) => headers.set(key, value));\n\n let body: unknown = undefined;\n if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n try {\n body = (await request.json()) as unknown;\n } catch {\n // body may be empty for some requests\n }\n }\n\n const result = await server.executeHTTPGraphQLRequest({\n httpGraphQLRequest: {\n method: request.method.toUpperCase(),\n headers,\n search: url.search,\n body,\n },\n context: () => contextFactory(request),\n });\n\n const responseHeaders = new Headers();\n for (const [key, value] of result.headers) {\n responseHeaders.set(key, value);\n }\n\n let responseBody: string;\n if (result.body.kind === \"complete\") {\n responseBody = result.body.string;\n } else {\n const chunks: string[] = [];\n for await (const chunk of result.body.asyncIterator) {\n chunks.push(chunk);\n }\n responseBody = chunks.join(\"\");\n }\n\n return new Response(responseBody, {\n status: result.status ?? 200,\n headers: responseHeaders,\n });\n };\n}\n"],"names":["#logger","#servers","#supergraphServer","#getSubgraphs","#gatewayOptions","#buildSupergraphSdl"],"mappings":"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","debug_id":"809aa815-7246-5ce0-b96c-d0e4099401e4"}
1
+ {"version":3,"file":"adapter-gateway-apollo-B54G_cXT.mjs","sources":["../src/graphql/gateway/adapter-gateway-apollo.ts"],"sourcesContent":["import type {\n GetDataSourceFunction,\n GraphQLDataSourceProcessOptions,\n ServiceDefinition,\n SubgraphHealthCheckFunction,\n SupergraphSdlUpdateFunction,\n} from \"@apollo/gateway\";\nimport {\n ApolloGateway,\n LocalCompose,\n RemoteGraphQLDataSource,\n} from \"@apollo/gateway\";\nimport { ApolloServer, HeaderMap } from \"@apollo/server\";\nimport { ApolloServerPluginInlineTraceDisabled } from \"@apollo/server/plugin/disabled\";\nimport { ApolloServerPluginDrainHttpServer } from \"@apollo/server/plugin/drainHttpServer\";\nimport { ApolloServerPluginLandingPageLocalDefault } from \"@apollo/server/plugin/landingPage/default\";\nimport { buildSubgraphSchema } from \"@apollo/subgraph\";\nimport type { ILogger } from \"document-model\";\nimport type { GraphQLSchema } from \"graphql\";\nimport type http from \"node:http\";\nimport type { WebSocketServer } from \"ws\";\nimport type { Context } from \"../types.js\";\nimport { useServer } from \"../websocket.js\";\nimport type {\n FetchHandler,\n GatewayContextFactory,\n IGatewayAdapter,\n SubgraphDefinition,\n WsDisposer,\n WsHandlers,\n} from \"./types.js\";\n\n/**\n * Drop subgraphs whose typeDefs cannot be built into a valid subgraph schema in\n * isolation — e.g. a duplicate type definition within a single subgraph (Sentry\n * #917) — so one broken subgraph is excluded instead of failing the build for\n * everyone. Each excluded subgraph is logged; the rest are composed.\n *\n * Scope: this only catches per-subgraph build failures. Errors that surface only\n * when subgraphs are composed together (cross-subgraph type or `@key` conflicts)\n * are still thrown by `LocalCompose.initialize()` and are NOT handled here.\n */\nexport function filterComposableSubgraphs(\n serviceList: ServiceDefinition[],\n logger?: Pick<ILogger, \"error\">,\n): ServiceDefinition[] {\n return serviceList.filter((service) => {\n try {\n // Array form: @apollo/subgraph 2.15 dropped the bare-module overload.\n buildSubgraphSchema([{ typeDefs: service.typeDefs }]);\n return true;\n } catch (error) {\n logger?.error(\n `Excluding subgraph \"${service.name}\" from supergraph composition: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n return false;\n }\n });\n}\n\n// Forwards the incoming authorization header to federated subgraph requests.\nclass AuthenticatedDataSource extends RemoteGraphQLDataSource {\n constructor(\n config?: ConstructorParameters<typeof RemoteGraphQLDataSource>[0],\n ) {\n // Node's fetch retires a pooled connection before the subgraph server's advertised keep-alive\n // timeout; Apollo's default make-fetch-happen agent holds it until the server closes it under us.\n super({\n fetcher: fetch as RemoteGraphQLDataSource[\"fetcher\"],\n ...config,\n });\n }\n\n willSendRequest(options: GraphQLDataSourceProcessOptions) {\n const { authorization } = options.context.headers as {\n authorization: string;\n };\n if (authorization && options?.request.http) {\n options.request.http.headers.set(\"authorization\", authorization);\n }\n }\n}\n\nexport class ApolloGatewayAdapter implements IGatewayAdapter<Context> {\n readonly #logger: ILogger;\n readonly #servers: ApolloServer<Context>[] = [];\n\n #supergraphServer: ApolloServer<Context> | null = null;\n #gatewayOptions: {\n update: SupergraphSdlUpdateFunction;\n healthCheck: SubgraphHealthCheckFunction;\n getDataSource: GetDataSourceFunction;\n } | null = null;\n #getSubgraphs: (() => SubgraphDefinition[]) | null = null;\n\n constructor(logger: ILogger) {\n this.#logger = logger;\n }\n\n async start(_httpServer: http.Server): Promise<void> {\n // Per-subgraph Apollo servers start lazily in createHandler.\n // Nothing to do here.\n }\n\n async createHandler(\n schema: GraphQLSchema,\n contextFactory: GatewayContextFactory<Context>,\n ): Promise<FetchHandler> {\n const server = new ApolloServer<Context>({\n schema,\n logger: this.#logger,\n introspection: true,\n // Each ApolloServer otherwise registers its own SIGINT/SIGTERM handler\n // that re-emits the signal via process.kill after server.stop() resolves.\n // With many subgraph servers that re-emit lands while the reactor's\n // graceful-shutdown chain is mid-flight, looking like a \"second SIGINT\"\n // to the reactor and aborting cleanup. The reactor drives our shutdown\n // end-to-end (see ReactorBuilder.attachSignalHandlers), so opt out.\n stopOnTerminationSignals: false,\n plugins: [\n ApolloServerPluginInlineTraceDisabled(),\n ApolloServerPluginLandingPageLocalDefault(),\n ],\n });\n await server.start();\n this.#servers.push(server);\n return createApolloFetchHandler(server, contextFactory);\n }\n\n async createSupergraphHandler(\n getSubgraphs: () => SubgraphDefinition[],\n httpServer: http.Server,\n contextFactory: GatewayContextFactory<Context>,\n ): Promise<FetchHandler> {\n if (this.#supergraphServer) {\n throw new Error(\"Supergraph server is already running\");\n }\n\n this.#getSubgraphs = getSubgraphs;\n\n const gateway = new ApolloGateway({\n supergraphSdl: async (options) => {\n this.#gatewayOptions = options;\n return await this.#buildSupergraphSdl();\n },\n buildService: (serviceConfig) =>\n new AuthenticatedDataSource(serviceConfig),\n });\n\n this.#supergraphServer = new ApolloServer<Context>({\n gateway,\n logger: this.#logger,\n introspection: true,\n stopOnTerminationSignals: false,\n plugins: [\n ApolloServerPluginDrainHttpServer({ httpServer }),\n ApolloServerPluginInlineTraceDisabled(),\n ApolloServerPluginLandingPageLocalDefault(),\n ],\n });\n\n await this.#supergraphServer.start();\n return createApolloFetchHandler(this.#supergraphServer, contextFactory);\n }\n\n async updateSupergraph(): Promise<void> {\n if (!this.#gatewayOptions || !this.#getSubgraphs) {\n // Not yet initialized - no-op.\n return;\n }\n const { supergraphSdl } = await this.#buildSupergraphSdl();\n this.#gatewayOptions.update(supergraphSdl);\n }\n\n async #buildSupergraphSdl() {\n if (!this.#gatewayOptions || !this.#getSubgraphs) {\n throw new Error(\"Gateway is not ready\");\n }\n const serviceList: ServiceDefinition[] = this.#getSubgraphs().map((s) => ({\n name: s.name,\n typeDefs: s.typeDefs,\n url: s.url,\n }));\n const composableServiceList = filterComposableSubgraphs(\n serviceList,\n this.#logger,\n );\n const localCompose = new LocalCompose({\n localServiceList: composableServiceList,\n });\n return localCompose.initialize(this.#gatewayOptions);\n }\n\n attachWebSocket(\n wsServer: WebSocketServer,\n schema: GraphQLSchema,\n handlers: WsHandlers<Context>,\n ): WsDisposer {\n return useServer(\n {\n schema,\n onConnect: (ctx) =>\n handlers.onConnect(ctx.connectionParams ?? {}, ctx.extra as object),\n context: (ctx) =>\n handlers.context(ctx.connectionParams ?? {}, ctx.extra as object),\n },\n wsServer,\n );\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.#servers.map((s) => s.stop()));\n this.#servers.length = 0;\n\n if (this.#supergraphServer) {\n await this.#supergraphServer.stop();\n this.#supergraphServer = null;\n }\n this.#gatewayOptions = null;\n this.#getSubgraphs = null;\n }\n}\n\n/**\n * Wrap an existing ApolloServer as a Fetch API handler.\n * Does not manage server lifecycle; caller is responsible for start/stop.\n */\nexport function createApolloFetchHandler(\n server: ApolloServer<Context>,\n contextFactory: GatewayContextFactory<Context>,\n): FetchHandler {\n return async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n const headers = new HeaderMap();\n request.headers.forEach((value, key) => headers.set(key, value));\n\n let body: unknown = undefined;\n if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n try {\n body = (await request.json()) as unknown;\n } catch {\n // body may be empty for some requests\n }\n }\n\n const result = await server.executeHTTPGraphQLRequest({\n httpGraphQLRequest: {\n method: request.method.toUpperCase(),\n headers,\n search: url.search,\n body,\n },\n context: () => contextFactory(request),\n });\n\n const responseHeaders = new Headers();\n for (const [key, value] of result.headers) {\n responseHeaders.set(key, value);\n }\n\n let responseBody: string;\n if (result.body.kind === \"complete\") {\n responseBody = result.body.string;\n } else {\n const chunks: string[] = [];\n for await (const chunk of result.body.asyncIterator) {\n chunks.push(chunk);\n }\n responseBody = chunks.join(\"\");\n }\n\n return new Response(responseBody, {\n status: result.status ?? 200,\n headers: responseHeaders,\n });\n };\n}\n"],"names":[],"mappings":"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","debug_id":"cec74315-a3ad-5b30-a06a-f13108285db4"}
@@ -1,4 +1,4 @@
1
- import { t as ApolloGatewayAdapter } from "./adapter-gateway-apollo-CxJNBVyD.mjs";
1
+ import { t as ApolloGatewayAdapter } from "./adapter-gateway-apollo-B54G_cXT.mjs";
2
2
  export { ApolloGatewayAdapter };
3
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a8c5706d-01fd-527f-9800-c1dfcf880e84")}catch(e){}}();
4
- //# debugId=a8c5706d-01fd-527f-9800-c1dfcf880e84
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="65868ada-1705-55c6-bedd-92c2ef113956")}catch(e){}}();
4
+ //# debugId=65868ada-1705-55c6-bedd-92c2ef113956
@@ -1,6 +1,6 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="7f833c7b-5df3-5dc1-8fb7-f221c05f2977")}catch(e){}}();
3
- import { t as useServer } from "./websocket-DncAB9XK.mjs";
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6ddd7998-f0f6-54a1-b9e8-fa189ecfedc9")}catch(e){}}();
3
+ import { t as useServer } from "./websocket-_SH5aBcy.mjs";
4
4
  import mercuriusGateway from "@mercuriusjs/gateway";
5
5
  import Fastify from "fastify";
6
6
  import mercurius from "mercurius";
@@ -129,5 +129,5 @@ async function injectRequest(app, request) {
129
129
  //#endregion
130
130
  export { MercuriusGatewayAdapter };
131
131
 
132
- //# sourceMappingURL=adapter-gateway-mercurius-CZVy88Za.mjs.map
133
- //# debugId=7f833c7b-5df3-5dc1-8fb7-f221c05f2977
132
+ //# sourceMappingURL=adapter-gateway-mercurius-rbKlwF9m.mjs.map
133
+ //# debugId=6ddd7998-f0f6-54a1-b9e8-fa189ecfedc9
@@ -1 +1 @@
1
- {"version":3,"file":"adapter-gateway-mercurius-CZVy88Za.mjs","sources":["../src/graphql/gateway/adapter-gateway-mercurius.ts"],"sourcesContent":["import type { MercuriusGatewayOptions } from \"@mercuriusjs/gateway\";\nimport mercuriusGateway from \"@mercuriusjs/gateway\";\nimport Fastify from \"fastify\";\nimport type {\n FastifyInstance,\n FastifyPluginCallback,\n FastifyReply,\n FastifyRequest,\n} from \"fastify\";\nimport mercurius from \"mercurius\";\nimport type { MercuriusOptions } from \"mercurius\";\nimport type { ILogger } from \"document-model\";\nimport type { GraphQLSchema } from \"graphql\";\nimport type http from \"node:http\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { WebSocketServer } from \"ws\";\nimport type { Context } from \"../types.js\";\nimport { useServer } from \"../websocket.js\";\nimport type {\n FetchHandler,\n GatewayContextFactory,\n IGatewayAdapter,\n SubgraphDefinition,\n WsDisposer,\n WsHandlers,\n} from \"./types.js\";\n\n/**\n * Threads the original Fetch API Request through Mercurius's internal\n * fastify.inject() call so that contextFactory (which uses the auth WeakMap\n * from auth-middleware.ts) receives the same Request object that auth\n * middleware populated before calling the handler.\n */\nconst requestAls = new AsyncLocalStorage<Request>();\n\n// @mercuriusjs/gateway exports a plain `(instance, opts) => void` rather than\n// a typed FastifyPluginCallback — cast once here.\n// The gateway plugin's accepted options are the intersection of the base\n// MercuriusOptions and MercuriusGatewayOptions (mirroring the unexported\n// MercuriusFederationOptions type in the package).\ntype GatewayPluginOptions = MercuriusOptions & MercuriusGatewayOptions;\nconst mercuriusGatewayPlugin =\n mercuriusGateway as unknown as FastifyPluginCallback<GatewayPluginOptions>;\n\nexport class MercuriusGatewayAdapter implements IGatewayAdapter<Context> {\n readonly #logger: ILogger;\n readonly #subgraphApps: FastifyInstance[] = [];\n\n #supergraphApp: FastifyInstance | null = null;\n #getSubgraphs: (() => SubgraphDefinition[]) | null = null;\n #supergraphContextFactory: GatewayContextFactory<Context> | null = null;\n\n constructor(logger: ILogger) {\n this.#logger = logger;\n }\n\n async start(_httpServer: http.Server): Promise<void> {\n // Mercurius instances are started lazily in createHandler /\n // createSupergraphHandler — nothing to do here.\n }\n\n async createHandler(\n schema: GraphQLSchema,\n contextFactory: GatewayContextFactory<Context>,\n ): Promise<FetchHandler> {\n const app = await buildMercuriusApp(schema, contextFactory, this.#logger);\n this.#subgraphApps.push(app);\n return buildFetchHandler(app);\n }\n\n async createSupergraphHandler(\n getSubgraphs: () => SubgraphDefinition[],\n _httpServer: http.Server,\n contextFactory: GatewayContextFactory<Context>,\n ): Promise<FetchHandler> {\n if (this.#supergraphApp) {\n throw new Error(\"Supergraph is already running\");\n }\n this.#getSubgraphs = getSubgraphs;\n this.#supergraphContextFactory = contextFactory;\n this.#supergraphApp = await buildGatewayApp(\n getSubgraphs(),\n contextFactory,\n this.#logger,\n );\n\n // Capture `this` so the returned handler always delegates to the *current*\n // #supergraphApp, allowing updateSupergraph() to swap it atomically.\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const adapter = this;\n return (request: Request): Promise<Response> => {\n if (!adapter.#supergraphApp) {\n return Promise.resolve(\n new Response(\"Gateway not ready\", { status: 503 }),\n );\n }\n return requestAls.run(request, () =>\n injectRequest(adapter.#supergraphApp!, request),\n );\n };\n }\n\n async updateSupergraph(): Promise<void> {\n if (!this.#getSubgraphs || !this.#supergraphContextFactory) return;\n const newApp = await buildGatewayApp(\n this.#getSubgraphs(),\n this.#supergraphContextFactory,\n this.#logger,\n );\n const oldApp = this.#supergraphApp;\n // Swap atomically — in-flight requests on the old app finish normally.\n this.#supergraphApp = newApp;\n if (oldApp) await oldApp.close();\n }\n\n attachWebSocket(\n wsServer: WebSocketServer,\n schema: GraphQLSchema,\n handlers: WsHandlers<Context>,\n ): WsDisposer {\n // Use graphql-ws directly; Mercurius's own subscription transport is\n // Fastify-specific and not applicable here.\n return useServer(\n {\n schema,\n onConnect: (ctx) =>\n handlers.onConnect(ctx.connectionParams ?? {}, ctx.extra as object),\n context: (ctx) =>\n handlers.context(ctx.connectionParams ?? {}, ctx.extra as object),\n },\n wsServer,\n );\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.#subgraphApps.map((app) => app.close()));\n this.#subgraphApps.length = 0;\n if (this.#supergraphApp) {\n await this.#supergraphApp.close();\n this.#supergraphApp = null;\n }\n this.#getSubgraphs = null;\n this.#supergraphContextFactory = null;\n }\n}\n\n// ── Fastify instance factories ────────────────────────────────────────────────\n\nfunction makeContextFn(\n contextFactory: GatewayContextFactory<Context>,\n logger: ILogger,\n) {\n return (_req: FastifyRequest, _reply: FastifyReply) => {\n const request = requestAls.getStore();\n if (!request) {\n logger.error(\"[mercurius] No Fetch Request in AsyncLocalStorage\");\n throw new Error(\"No Fetch Request in AsyncLocalStorage\");\n }\n return contextFactory(request);\n };\n}\n\nasync function buildMercuriusApp(\n schema: GraphQLSchema,\n contextFactory: GatewayContextFactory<Context>,\n logger: ILogger,\n): Promise<FastifyInstance> {\n const app = Fastify({ logger: false });\n\n await app.register(mercurius, {\n schema,\n graphiql: false,\n context: makeContextFn(contextFactory, logger),\n // Override _Service.sdl to rewrite \"type Query/Mutation/Subscription {\"\n // as \"extend type … {\" so that @mercuriusjs/gateway v5 (which follows the\n // Federation v1 convention of using extensionTypeMap) correctly maps root\n // operation fields to this service during query planning.\n resolvers: {\n _Service: {\n sdl: (parent: { sdl?: string }) =>\n (parent.sdl ?? \"\").replace(\n /\\btype\\s+(Query|Mutation|Subscription)\\s*\\{/g,\n \"extend type $1 {\",\n ),\n },\n },\n } satisfies MercuriusOptions);\n\n await app.ready();\n return app;\n}\n\n/**\n * Builds a Mercurius federation gateway that composes the given subgraph\n * services. Each service URL must be reachable so that the gateway can fetch\n * its SDL via `_service { sdl }` (Apollo Federation protocol).\n */\nasync function buildGatewayApp(\n subgraphs: SubgraphDefinition[],\n contextFactory: GatewayContextFactory<Context>,\n logger: ILogger,\n): Promise<FastifyInstance> {\n const app = Fastify({ logger: false });\n\n await app.register(mercuriusGatewayPlugin, {\n gateway: {\n services: subgraphs.map((s) => ({ name: s.name, url: s.url })),\n },\n graphiql: false,\n context: makeContextFn(contextFactory, logger),\n });\n\n await app.ready();\n return app;\n}\n\n// ── Fetch API bridge ──────────────────────────────────────────────────────────\n\nfunction buildFetchHandler(app: FastifyInstance): FetchHandler {\n return (request: Request): Promise<Response> =>\n requestAls.run(request, () => injectRequest(app, request));\n}\n\nasync function injectRequest(\n app: FastifyInstance,\n request: Request,\n): Promise<Response> {\n const body =\n request.method !== \"GET\" && request.method !== \"HEAD\"\n ? await request.text()\n : undefined;\n\n const headers: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n headers[key] = value;\n });\n\n const response = await app.inject({\n method: request.method as\n | \"DELETE\"\n | \"GET\"\n | \"HEAD\"\n | \"OPTIONS\"\n | \"PATCH\"\n | \"POST\"\n | \"PUT\",\n url: \"/graphql\",\n headers,\n payload: body,\n });\n\n const responseHeaders: Record<string, string> = {};\n for (const [key, value] of Object.entries(response.headers)) {\n if (value !== undefined) responseHeaders[key] = String(value);\n }\n\n return new Response(response.payload, {\n status: response.statusCode,\n headers: responseHeaders,\n });\n}\n"],"names":["#logger","#subgraphApps","#supergraphApp","#getSubgraphs","#supergraphContextFactory"],"mappings":"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","debug_id":"7f833c7b-5df3-5dc1-8fb7-f221c05f2977"}
1
+ {"version":3,"file":"adapter-gateway-mercurius-rbKlwF9m.mjs","sources":["../src/graphql/gateway/adapter-gateway-mercurius.ts"],"sourcesContent":["import type { MercuriusGatewayOptions } from \"@mercuriusjs/gateway\";\nimport mercuriusGateway from \"@mercuriusjs/gateway\";\nimport Fastify from \"fastify\";\nimport type {\n FastifyInstance,\n FastifyPluginCallback,\n FastifyReply,\n FastifyRequest,\n} from \"fastify\";\nimport mercurius from \"mercurius\";\nimport type { MercuriusOptions } from \"mercurius\";\nimport type { ILogger } from \"document-model\";\nimport type { GraphQLSchema } from \"graphql\";\nimport type http from \"node:http\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { WebSocketServer } from \"ws\";\nimport type { Context } from \"../types.js\";\nimport { useServer } from \"../websocket.js\";\nimport type {\n FetchHandler,\n GatewayContextFactory,\n IGatewayAdapter,\n SubgraphDefinition,\n WsDisposer,\n WsHandlers,\n} from \"./types.js\";\n\n/**\n * Threads the original Fetch API Request through Mercurius's internal\n * fastify.inject() call so that contextFactory (which uses the auth WeakMap\n * from auth-middleware.ts) receives the same Request object that auth\n * middleware populated before calling the handler.\n */\nconst requestAls = new AsyncLocalStorage<Request>();\n\n// @mercuriusjs/gateway exports a plain `(instance, opts) => void` rather than\n// a typed FastifyPluginCallback — cast once here.\n// The gateway plugin's accepted options are the intersection of the base\n// MercuriusOptions and MercuriusGatewayOptions (mirroring the unexported\n// MercuriusFederationOptions type in the package).\ntype GatewayPluginOptions = MercuriusOptions & MercuriusGatewayOptions;\nconst mercuriusGatewayPlugin =\n mercuriusGateway as unknown as FastifyPluginCallback<GatewayPluginOptions>;\n\nexport class MercuriusGatewayAdapter implements IGatewayAdapter<Context> {\n readonly #logger: ILogger;\n readonly #subgraphApps: FastifyInstance[] = [];\n\n #supergraphApp: FastifyInstance | null = null;\n #getSubgraphs: (() => SubgraphDefinition[]) | null = null;\n #supergraphContextFactory: GatewayContextFactory<Context> | null = null;\n\n constructor(logger: ILogger) {\n this.#logger = logger;\n }\n\n async start(_httpServer: http.Server): Promise<void> {\n // Mercurius instances are started lazily in createHandler /\n // createSupergraphHandler — nothing to do here.\n }\n\n async createHandler(\n schema: GraphQLSchema,\n contextFactory: GatewayContextFactory<Context>,\n ): Promise<FetchHandler> {\n const app = await buildMercuriusApp(schema, contextFactory, this.#logger);\n this.#subgraphApps.push(app);\n return buildFetchHandler(app);\n }\n\n async createSupergraphHandler(\n getSubgraphs: () => SubgraphDefinition[],\n _httpServer: http.Server,\n contextFactory: GatewayContextFactory<Context>,\n ): Promise<FetchHandler> {\n if (this.#supergraphApp) {\n throw new Error(\"Supergraph is already running\");\n }\n this.#getSubgraphs = getSubgraphs;\n this.#supergraphContextFactory = contextFactory;\n this.#supergraphApp = await buildGatewayApp(\n getSubgraphs(),\n contextFactory,\n this.#logger,\n );\n\n // Capture `this` so the returned handler always delegates to the *current*\n // #supergraphApp, allowing updateSupergraph() to swap it atomically.\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const adapter = this;\n return (request: Request): Promise<Response> => {\n if (!adapter.#supergraphApp) {\n return Promise.resolve(\n new Response(\"Gateway not ready\", { status: 503 }),\n );\n }\n return requestAls.run(request, () =>\n injectRequest(adapter.#supergraphApp!, request),\n );\n };\n }\n\n async updateSupergraph(): Promise<void> {\n if (!this.#getSubgraphs || !this.#supergraphContextFactory) return;\n const newApp = await buildGatewayApp(\n this.#getSubgraphs(),\n this.#supergraphContextFactory,\n this.#logger,\n );\n const oldApp = this.#supergraphApp;\n // Swap atomically — in-flight requests on the old app finish normally.\n this.#supergraphApp = newApp;\n if (oldApp) await oldApp.close();\n }\n\n attachWebSocket(\n wsServer: WebSocketServer,\n schema: GraphQLSchema,\n handlers: WsHandlers<Context>,\n ): WsDisposer {\n // Use graphql-ws directly; Mercurius's own subscription transport is\n // Fastify-specific and not applicable here.\n return useServer(\n {\n schema,\n onConnect: (ctx) =>\n handlers.onConnect(ctx.connectionParams ?? {}, ctx.extra as object),\n context: (ctx) =>\n handlers.context(ctx.connectionParams ?? {}, ctx.extra as object),\n },\n wsServer,\n );\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.#subgraphApps.map((app) => app.close()));\n this.#subgraphApps.length = 0;\n if (this.#supergraphApp) {\n await this.#supergraphApp.close();\n this.#supergraphApp = null;\n }\n this.#getSubgraphs = null;\n this.#supergraphContextFactory = null;\n }\n}\n\n// ── Fastify instance factories ────────────────────────────────────────────────\n\nfunction makeContextFn(\n contextFactory: GatewayContextFactory<Context>,\n logger: ILogger,\n) {\n return (_req: FastifyRequest, _reply: FastifyReply) => {\n const request = requestAls.getStore();\n if (!request) {\n logger.error(\"[mercurius] No Fetch Request in AsyncLocalStorage\");\n throw new Error(\"No Fetch Request in AsyncLocalStorage\");\n }\n return contextFactory(request);\n };\n}\n\nasync function buildMercuriusApp(\n schema: GraphQLSchema,\n contextFactory: GatewayContextFactory<Context>,\n logger: ILogger,\n): Promise<FastifyInstance> {\n const app = Fastify({ logger: false });\n\n await app.register(mercurius, {\n schema,\n graphiql: false,\n context: makeContextFn(contextFactory, logger),\n // Override _Service.sdl to rewrite \"type Query/Mutation/Subscription {\"\n // as \"extend type … {\" so that @mercuriusjs/gateway v5 (which follows the\n // Federation v1 convention of using extensionTypeMap) correctly maps root\n // operation fields to this service during query planning.\n resolvers: {\n _Service: {\n sdl: (parent: { sdl?: string }) =>\n (parent.sdl ?? \"\").replace(\n /\\btype\\s+(Query|Mutation|Subscription)\\s*\\{/g,\n \"extend type $1 {\",\n ),\n },\n },\n } satisfies MercuriusOptions);\n\n await app.ready();\n return app;\n}\n\n/**\n * Builds a Mercurius federation gateway that composes the given subgraph\n * services. Each service URL must be reachable so that the gateway can fetch\n * its SDL via `_service { sdl }` (Apollo Federation protocol).\n */\nasync function buildGatewayApp(\n subgraphs: SubgraphDefinition[],\n contextFactory: GatewayContextFactory<Context>,\n logger: ILogger,\n): Promise<FastifyInstance> {\n const app = Fastify({ logger: false });\n\n await app.register(mercuriusGatewayPlugin, {\n gateway: {\n services: subgraphs.map((s) => ({ name: s.name, url: s.url })),\n },\n graphiql: false,\n context: makeContextFn(contextFactory, logger),\n });\n\n await app.ready();\n return app;\n}\n\n// ── Fetch API bridge ──────────────────────────────────────────────────────────\n\nfunction buildFetchHandler(app: FastifyInstance): FetchHandler {\n return (request: Request): Promise<Response> =>\n requestAls.run(request, () => injectRequest(app, request));\n}\n\nasync function injectRequest(\n app: FastifyInstance,\n request: Request,\n): Promise<Response> {\n const body =\n request.method !== \"GET\" && request.method !== \"HEAD\"\n ? await request.text()\n : undefined;\n\n const headers: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n headers[key] = value;\n });\n\n const response = await app.inject({\n method: request.method as\n | \"DELETE\"\n | \"GET\"\n | \"HEAD\"\n | \"OPTIONS\"\n | \"PATCH\"\n | \"POST\"\n | \"PUT\",\n url: \"/graphql\",\n headers,\n payload: body,\n });\n\n const responseHeaders: Record<string, string> = {};\n for (const [key, value] of Object.entries(response.headers)) {\n if (value !== undefined) responseHeaders[key] = String(value);\n }\n\n return new Response(response.payload, {\n status: response.statusCode,\n headers: responseHeaders,\n });\n}\n"],"names":[],"mappings":"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","debug_id":"6ddd7998-f0f6-54a1-b9e8-fa189ecfedc9"}
@@ -1,7 +1,7 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1cb2831c-f802-59f7-955e-11295cb2c38d")}catch(e){}}();
3
- import { t as useServer } from "./websocket-DncAB9XK.mjs";
4
- import { n as createApolloFetchHandler } from "./adapter-gateway-apollo-CxJNBVyD.mjs";
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="86579686-a510-5b69-bb5b-7db68995aac8")}catch(e){}}();
3
+ import { t as useServer } from "./websocket-_SH5aBcy.mjs";
4
+ import { n as createApolloFetchHandler } from "./adapter-gateway-apollo-B54G_cXT.mjs";
5
5
  import { Kind, buildASTSchema, isTypeDefinitionNode, isTypeExtensionNode, parse, print, validateSchema } from "graphql";
6
6
  import { ApolloServer } from "@apollo/server";
7
7
  import { ApolloServerPluginInlineTraceDisabled } from "@apollo/server/plugin/disabled";
@@ -70,10 +70,12 @@ function filterBuildableSubgraphs(subgraphs, logger) {
70
70
  for (const def of subgraph.typeDefs.definitions) if (isTypeDefinitionNode(def)) own.add(def.name.value);
71
71
  else if (def.kind === Kind.DIRECTIVE_DEFINITION) ownDirectives.add(def.name.value);
72
72
  const stubs = [];
73
- for (const name of new Set([...owners.keys(), ...ROOT_TYPE_NAMES])) if (!own.has(name)) stubs.push(stubDeclaration(name, owners.get(name)));
73
+ for (const name of /* @__PURE__ */ new Set([...owners.keys(), ...ROOT_TYPE_NAMES])) if (!own.has(name)) stubs.push(stubDeclaration(name, owners.get(name)));
74
74
  for (const [name, def] of directiveDefs) if (!ownDirectives.has(name)) stubs.push(print(def));
75
75
  try {
76
- const errors = validateSchema(buildASTSchema(mergeTypeDefs(stubs.length > 0 ? [subgraph.typeDefs, parse(stubs.join("\n"))] : [subgraph.typeDefs], { useSchemaDefinition: false })));
76
+ const documents = stubs.length > 0 ? [subgraph.typeDefs, parse(stubs.join("\n"))] : [subgraph.typeDefs];
77
+ const merged = mergeTypeDefs(documents, { useSchemaDefinition: false });
78
+ const errors = validateSchema(buildASTSchema(merged));
77
79
  if (errors.length > 0) throw new Error(errors.map((error) => error.message).join("; "));
78
80
  return true;
79
81
  } catch (error) {
@@ -167,7 +169,8 @@ function mergeSubgraphTypeDefs(subgraphs, policy) {
167
169
  * subgraph's resolver ran.
168
170
  */
169
171
  function mergeSubgraphResolvers(subgraphs, policy) {
170
- return mergeResolvers((policy === "first" ? [...subgraphs].reverse() : subgraphs).map((s) => s.resolvers));
172
+ const ordered = policy === "first" ? [...subgraphs].reverse() : subgraphs;
173
+ return mergeResolvers(ordered.map((s) => s.resolvers));
171
174
  }
172
175
  /**
173
176
  * Drops resolver entries that have no matching type or field in the merged
@@ -207,9 +210,10 @@ function filterResolversToSchema(typeMap, resolvers, logger) {
207
210
  * resolvers (shared by the adapter and the pure merge helper).
208
211
  */
209
212
  function buildMergedSchema(typeDefs, resolvers, logger) {
213
+ const filtered = filterResolversToSchema(buildASTSchema(typeDefs, { assumeValid: true }).getTypeMap(), resolvers, logger);
210
214
  return makeExecutableSchema({
211
215
  typeDefs,
212
- resolvers: filterResolversToSchema(buildASTSchema(typeDefs, { assumeValid: true }).getTypeMap(), resolvers, logger)
216
+ resolvers: filtered
213
217
  });
214
218
  }
215
219
  /**
@@ -305,12 +309,13 @@ var StitchingGatewayAdapter = class {
305
309
  #installSupergraphServer(server) {
306
310
  if (this.#contextFactory === null) throw new Error("Supergraph context factory not set");
307
311
  this.#supergraphServer = server;
308
- this.#handler = createApolloFetchHandler(server, this.#contextFactory);
312
+ const handler = createApolloFetchHandler(server, this.#contextFactory);
313
+ this.#handler = handler;
309
314
  return (request) => this.#handler(request);
310
315
  }
311
316
  };
312
317
  //#endregion
313
318
  export { StitchingGatewayAdapter };
314
319
 
315
- //# sourceMappingURL=adapter-gateway-stitching-CaZjvRzx.mjs.map
316
- //# debugId=1cb2831c-f802-59f7-955e-11295cb2c38d
320
+ //# sourceMappingURL=adapter-gateway-stitching-Dzv10u8D.mjs.map
321
+ //# debugId=86579686-a510-5b69-bb5b-7db68995aac8
@@ -1 +1 @@
1
- {"version":3,"file":"adapter-gateway-stitching-CaZjvRzx.mjs","sources":["../src/graphql/gateway/adapter-gateway-stitching.ts"],"sourcesContent":["import { ApolloServer } from \"@apollo/server\";\nimport { ApolloServerPluginInlineTraceDisabled } from \"@apollo/server/plugin/disabled\";\nimport { ApolloServerPluginLandingPageLocalDefault } from \"@apollo/server/plugin/landingPage/default\";\nimport { mergeResolvers, mergeTypeDefs } from \"@graphql-tools/merge\";\nimport { makeExecutableSchema } from \"@graphql-tools/schema\";\nimport type { IResolvers } from \"@graphql-tools/utils\";\nimport {\n buildASTSchema,\n type DefinitionNode,\n type DocumentNode,\n isTypeDefinitionNode,\n isTypeExtensionNode,\n Kind,\n parse,\n print,\n type GraphQLNamedType,\n type GraphQLSchema,\n type TypeDefinitionNode,\n validateSchema,\n} from \"graphql\";\nimport type http from \"node:http\";\nimport type { WebSocketServer } from \"ws\";\nimport type { ILogger } from \"document-model\";\nimport type { Context } from \"../types.js\";\nimport { useServer } from \"../websocket.js\";\nimport { createApolloFetchHandler } from \"./adapter-gateway-apollo.js\";\nimport type {\n FetchHandler,\n GatewayContextFactory,\n IGatewayAdapter,\n SubgraphDefinition,\n WsDisposer,\n WsHandlers,\n} from \"./types.js\";\n\n/**\n * How to resolve two subgraphs that define the same field with incompatible\n * types (a name clash, the #1565 scenario).\n *\n * - `\"last\"` (default): the later-registered subgraph's field definition wins.\n * - `\"first\"`: the earlier-registered subgraph's field definition wins.\n *\n * Every conflict is logged either way; unlike federation composition, the\n * supergraph is still built. The policy applies to field type clashes only:\n * a type-KIND clash (the same type name declared as an object by one subgraph\n * and as an enum/input/interface/union by another) is resolved by\n * `mergeTypeDefs` itself, which always keeps the last declaration. Those are\n * detected separately and reported through the same channel so they are\n * logged rather than dropped in silence.\n */\nexport type StitchConflictPolicy = \"first\" | \"last\";\n\nexport type StitchingGatewayOptions = {\n onFieldTypeConflict?: StitchConflictPolicy;\n};\n\n/** Root operation types, which a subgraph may extend without defining. */\nconst ROOT_TYPE_NAMES = [\"Query\", \"Mutation\", \"Subscription\"];\n\n/**\n * A placeholder declaration for a type name a subgraph borrows from another\n * subgraph. Same kind as the real declaration, so the borrowing subgraph's\n * SDL validates the same way it does in the merged supergraph:\n *\n * - scalar/enum/input/object: a minimal declaration of that kind.\n * - interface: the real declaration, because a subgraph that implements the\n * interface has to satisfy its field set.\n * - union: a self-contained union over one placeholder member, so nothing the\n * real declaration references has to be resolvable here.\n */\nfunction stubDeclaration(\n name: string,\n owner: TypeDefinitionNode | undefined,\n): string {\n switch (owner?.kind) {\n case Kind.SCALAR_TYPE_DEFINITION:\n return `scalar ${name}`;\n case Kind.ENUM_TYPE_DEFINITION:\n return `enum ${name} { _STUB }`;\n case Kind.INPUT_OBJECT_TYPE_DEFINITION:\n return `input ${name} { _stub: Boolean }`;\n case Kind.INTERFACE_TYPE_DEFINITION:\n return print(owner);\n case Kind.UNION_TYPE_DEFINITION:\n return `type ${name}_Stub { _stub: Boolean } union ${name} = ${name}_Stub`;\n default:\n return `type ${name} { _stub: Boolean }`;\n }\n}\n\n/**\n * Drops subgraphs whose own typeDefs cannot be built into a valid schema, so\n * one malformed subgraph is excluded instead of failing the whole supergraph\n * build (which, since GraphQLManager.init() does not guard the supergraph\n * gateway, would be a boot failure). Each excluded subgraph is logged; the\n * rest are merged. This is the stitching counterpart of the federation path's\n * `filterComposableSubgraphs`.\n *\n * A stitching subgraph is not self-contained the way a federation subgraph is:\n * it may extend a root type it never defines (`analytics` only does\n * `extend type Query`) and reference types another subgraph owns (in raw form\n * `analytics` uses `DateTime`, declared by `auth`/`reactor`/`packages`).\n * Building it alone would therefore reject perfectly good subgraphs. So the isolation build adds\n * a placeholder declaration for every type name declared by some *other*\n * subgraph in the set, plus the root types, plus every directive definition in\n * the set. What is left to fail is the subgraph's own SDL: a dangling type\n * reference no subgraph declares, a duplicated field, an invalid implements\n * clause.\n *\n * Scope: like the federation filter, this only catches per-subgraph failures.\n * Errors that appear only once subgraphs are merged (a field type or type kind\n * clash) are reported by `mergeSubgraphTypeDefs`, not here.\n */\nexport function filterBuildableSubgraphs(\n subgraphs: SubgraphDefinition[],\n logger?: Pick<ILogger, \"error\">,\n): SubgraphDefinition[] {\n // First declaration of each type name across the whole set, for stub kinds.\n const owners = new Map<string, TypeDefinitionNode>();\n const directiveDefs = new Map<string, DefinitionNode>();\n for (const subgraph of subgraphs) {\n for (const def of subgraph.typeDefs.definitions) {\n if (isTypeDefinitionNode(def) && !owners.has(def.name.value)) {\n owners.set(def.name.value, def);\n } else if (\n def.kind === Kind.DIRECTIVE_DEFINITION &&\n !directiveDefs.has(def.name.value)\n ) {\n directiveDefs.set(def.name.value, def);\n }\n }\n }\n\n return subgraphs.filter((subgraph) => {\n const own = new Set<string>();\n const ownDirectives = new Set<string>();\n for (const def of subgraph.typeDefs.definitions) {\n if (isTypeDefinitionNode(def)) {\n own.add(def.name.value);\n } else if (def.kind === Kind.DIRECTIVE_DEFINITION) {\n ownDirectives.add(def.name.value);\n }\n }\n\n const stubs: string[] = [];\n for (const name of new Set([...owners.keys(), ...ROOT_TYPE_NAMES])) {\n if (!own.has(name)) {\n stubs.push(stubDeclaration(name, owners.get(name)));\n }\n }\n for (const [name, def] of directiveDefs) {\n if (!ownDirectives.has(name)) {\n stubs.push(print(def));\n }\n }\n\n try {\n // Merge the same way the supergraph does, so a subgraph that declares a\n // type twice within itself is normalized here too, then build and\n // validate: buildASTSchema asserts the SDL, validateSchema the result.\n const documents =\n stubs.length > 0\n ? [subgraph.typeDefs, parse(stubs.join(\"\\n\"))]\n : [subgraph.typeDefs];\n const merged = mergeTypeDefs(documents, { useSchemaDefinition: false });\n const errors = validateSchema(buildASTSchema(merged));\n if (errors.length > 0) {\n throw new Error(errors.map((error) => error.message).join(\"; \"));\n }\n return true;\n } catch (error) {\n logger?.error(\n `Stitching gateway: excluding subgraph \"${subgraph.name}\" from the supergraph: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n return false;\n }\n });\n}\n\n/**\n * The SDL keyword for a type definition or extension node, or undefined for a\n * node that does not declare a named type (schema definitions, directive\n * definitions, executable definitions). Extensions map to the same keyword as\n * their definition: `extend type Query` and `type Query` are the same kind.\n */\nfunction typeKeyword(def: DefinitionNode): string | undefined {\n switch (def.kind) {\n case Kind.OBJECT_TYPE_DEFINITION:\n case Kind.OBJECT_TYPE_EXTENSION:\n return \"type\";\n case Kind.INTERFACE_TYPE_DEFINITION:\n case Kind.INTERFACE_TYPE_EXTENSION:\n return \"interface\";\n case Kind.UNION_TYPE_DEFINITION:\n case Kind.UNION_TYPE_EXTENSION:\n return \"union\";\n case Kind.ENUM_TYPE_DEFINITION:\n case Kind.ENUM_TYPE_EXTENSION:\n return \"enum\";\n case Kind.INPUT_OBJECT_TYPE_DEFINITION:\n case Kind.INPUT_OBJECT_TYPE_EXTENSION:\n return \"input\";\n case Kind.SCALAR_TYPE_DEFINITION:\n case Kind.SCALAR_TYPE_EXTENSION:\n return \"scalar\";\n default:\n return undefined;\n }\n}\n\n/**\n * Finds type names that two subgraphs declare with different kinds (object vs\n * enum, input, interface or union). `mergeTypeDefs` does not call\n * `onFieldTypeConflict` for these - it keeps the last declaration and drops\n * the other subgraph's type entirely, with no diagnostic - so they are\n * scanned for before the merge and reported alongside field conflicts.\n */\nfunction scanTypeKindClashes(subgraphs: SubgraphDefinition[]): string[] {\n const clashes: string[] = [];\n const declaredBy = new Map<string, { keyword: string; subgraph: string }>();\n for (const subgraph of subgraphs) {\n for (const def of subgraph.typeDefs.definitions) {\n if (!isTypeDefinitionNode(def) && !isTypeExtensionNode(def)) {\n continue;\n }\n const keyword = typeKeyword(def);\n if (keyword === undefined) {\n continue;\n }\n const name = def.name.value;\n const previous = declaredBy.get(name);\n if (previous === undefined) {\n declaredBy.set(name, { keyword, subgraph: subgraph.name });\n continue;\n }\n if (previous.keyword === keyword) {\n continue;\n }\n clashes.push(\n `type kind clash on ${name}: declared as ${previous.keyword} by ` +\n `subgraph \"${previous.subgraph}\" and as ${keyword} by subgraph ` +\n `\"${subgraph.name}\"; mergeTypeDefs keeps the last declaration ` +\n `(${keyword}) and drops the other, whatever the conflict policy`,\n );\n // Track what the merge actually keeps, so a third declaration is\n // compared against the surviving kind.\n declaredBy.set(name, { keyword, subgraph: subgraph.name });\n }\n }\n return clashes;\n}\n\n/**\n * Merges all subgraph type definitions into one schema, applying the field\n * conflict policy. Exported so tests and the benchmark can exercise the merge\n * without a full adapter.\n */\nexport function mergeSubgraphTypeDefs(\n subgraphs: SubgraphDefinition[],\n policy: StitchConflictPolicy,\n): { typeDefs: DocumentNode; conflicts: string[] } {\n const conflicts: string[] = scanTypeKindClashes(subgraphs);\n const typeDefs = mergeTypeDefs(\n subgraphs.map((s) => s.typeDefs),\n {\n // Never emit a `schema { ... }` block: the merged root types are\n // determined by whichever subgraphs define Query/Mutation/Subscription.\n useSchemaDefinition: false,\n onFieldTypeConflict: (existing, other, type) => {\n // Identical definitions are normal stitching (shared types across\n // subgraphs); only differing definitions are conflicts.\n if (print(existing) === print(other)) {\n return existing;\n }\n const winner = policy === \"first\" ? existing : other;\n const loser = policy === \"first\" ? other : existing;\n conflicts.push(\n `field type clash on ${type.name.value}.${existing.name.value}: kept ` +\n `${print(winner.type)} (${\n policy === \"first\" ? \"first\" : \"last\"\n } subgraph), dropped ${print(loser.type)}`,\n );\n return winner;\n },\n },\n );\n return { typeDefs, conflicts };\n}\n\n/**\n * Merges the subgraph resolver maps in the order the conflict policy implies.\n * `mergeResolvers` is unconditionally last-wins, so under `\"first\"` the array\n * is reversed: the first-registered subgraph's resolver ends up applied last\n * and wins, matching the field type the merged schema advertises. Without\n * this the schema would advertise one subgraph's type while another\n * subgraph's resolver ran.\n */\nfunction mergeSubgraphResolvers(\n subgraphs: SubgraphDefinition[],\n policy: StitchConflictPolicy,\n): IResolvers {\n const ordered = policy === \"first\" ? [...subgraphs].reverse() : subgraphs;\n return mergeResolvers(\n ordered.map((s) => s.resolvers as IResolvers | undefined),\n );\n}\n\n/**\n * Drops resolver entries that have no matching type or field in the merged\n * schema. Document-model subgraphs generate resolver entries for operations\n * their SDL does not declare (the federation runtime silently ignores those);\n * makeExecutableSchema rejects them, so they are filtered before the build.\n */\nfunction filterResolversToSchema(\n typeMap: Record<string, GraphQLNamedType | undefined>,\n resolvers: Record<string, unknown>,\n logger?: Pick<ILogger, \"debug\">,\n): Record<string, unknown> {\n const filtered: Record<string, unknown> = {};\n for (const [typeName, entry] of Object.entries(resolvers)) {\n const type = typeMap[typeName];\n if (type === undefined) {\n // Type not part of the merged schema.\n logger?.debug(\n `Stitching gateway: dropped resolvers for type \"${typeName}\": the merged schema has no such type`,\n );\n continue;\n }\n const fields =\n type instanceof Object && \"getFields\" in type\n ? (type as { getFields(): Record<string, unknown> }).getFields()\n : undefined;\n if (fields === undefined) {\n // Scalar, enum, or union resolver: keep as-is.\n filtered[typeName] = entry;\n continue;\n }\n if (entry === null || typeof entry !== \"object\") {\n // Not a resolver map: nothing to keep.\n logger?.debug(\n `Stitching gateway: dropped resolver entry for type \"${typeName}\": expected a field map, got ${entry === null ? \"null\" : typeof entry}`,\n );\n continue;\n }\n const map = entry as { [key: string]: unknown };\n const kept: Record<string, unknown> = {};\n const dropped: string[] = [];\n for (const [key, value] of Object.entries(map)) {\n if (key === \"__resolveReference\" || fields[key] !== undefined) {\n kept[key] = value;\n } else {\n dropped.push(key);\n }\n }\n if (dropped.length > 0) {\n logger?.debug(\n `Stitching gateway: dropped resolvers ${dropped\n .map((field) => `${typeName}.${field}`)\n .join(\", \")}: the merged schema declares no such field(s)`,\n );\n }\n if (Object.keys(kept).length > 0) {\n filtered[typeName] = kept;\n }\n }\n return filtered;\n}\n\n/**\n * Builds the executable supergraph schema from merged type definitions and\n * resolvers (shared by the adapter and the pure merge helper).\n */\nfunction buildMergedSchema(\n typeDefs: DocumentNode,\n resolvers: IResolvers,\n logger?: Pick<ILogger, \"debug\">,\n): GraphQLSchema {\n // A type-only build to get the merged type map; assumeValid skips SDL\n // validation, which makeExecutableSchema performs on the real build.\n const typeMap = buildASTSchema(typeDefs, { assumeValid: true }).getTypeMap();\n // The filter works on the raw resolver shape; the result is a valid\n // IResolvers because it only removes entries from one.\n const filtered = filterResolversToSchema(\n typeMap,\n resolvers as Record<string, unknown>,\n logger,\n );\n return makeExecutableSchema({ typeDefs, resolvers: filtered as IResolvers });\n}\n\n/**\n * Merges multiple subgraphs into a single in-process executable schema.\n * This is the \"Guild\" (graphql-tools) composition path: instead of federation\n * (which hard-fails on cross-subgraph type conflicts and executes subgraph\n * fields over loopback HTTP), the type definitions are merged with an\n * explicit conflict policy and the resolvers run in-process.\n */\nexport function mergeSubgraphSchemas(\n subgraphs: SubgraphDefinition[],\n policy: StitchConflictPolicy,\n): GraphQLSchema {\n if (subgraphs.length === 0) {\n throw new Error(\"Cannot merge zero subgraphs\");\n }\n const { typeDefs } = mergeSubgraphTypeDefs(subgraphs, policy);\n const resolvers = mergeSubgraphResolvers(subgraphs, policy);\n return buildMergedSchema(typeDefs, resolvers);\n}\n\n/**\n * A stitching gateway adapter: the supergraph is one merged schema executed\n * in-process. Subgraph routes (`/graphql/<name>`) are served exactly like the\n * Apollo adapter, so direct subgraph access is unchanged.\n *\n * Note: unlike the Apollo adapter, the supergraph ApolloServer is NOT given\n * ApolloServerPluginDrainHttpServer. The plugin closes the (shared) HTTP\n * server on stop, which would kill every mounted subgraph route when\n * updateSupergraph() swaps the supergraph server. The shared server is drained\n * explicitly in stop() instead.\n */\nexport class StitchingGatewayAdapter implements IGatewayAdapter<Context> {\n readonly #logger: ILogger;\n readonly #policy: StitchConflictPolicy;\n\n readonly #servers: ApolloServer<Context>[] = [];\n #supergraphServer: ApolloServer<Context> | null = null;\n #handler: FetchHandler | null = null;\n #httpServer: http.Server | null = null;\n #getSubgraphs: (() => SubgraphDefinition[]) | null = null;\n #contextFactory: GatewayContextFactory<Context> | null = null;\n\n constructor(logger: ILogger, options: StitchingGatewayOptions = {}) {\n this.#logger = logger;\n this.#policy = options.onFieldTypeConflict ?? \"last\";\n }\n\n async start(_httpServer: http.Server): Promise<void> {\n // Per-subgraph Apollo servers start lazily in createHandler.\n // Nothing to do here.\n }\n\n async createHandler(\n schema: GraphQLSchema,\n contextFactory: GatewayContextFactory<Context>,\n ): Promise<FetchHandler> {\n const server = await this.#makeServer(schema);\n this.#servers.push(server);\n return createApolloFetchHandler(server, contextFactory);\n }\n\n async createSupergraphHandler(\n getSubgraphs: () => SubgraphDefinition[],\n httpServer: http.Server,\n contextFactory: GatewayContextFactory<Context>,\n ): Promise<FetchHandler> {\n if (this.#supergraphServer) {\n throw new Error(\"Supergraph server is already running\");\n }\n\n this.#getSubgraphs = getSubgraphs;\n this.#httpServer = httpServer;\n this.#contextFactory = contextFactory;\n\n const server = await this.#buildSupergraphServer(getSubgraphs());\n return this.#installSupergraphServer(server);\n }\n\n async updateSupergraph(): Promise<void> {\n if (!this.#getSubgraphs || !this.#contextFactory) {\n // Not yet initialized - no-op.\n return;\n }\n const server = await this.#buildSupergraphServer(this.#getSubgraphs());\n const old = this.#supergraphServer;\n this.#installSupergraphServer(server);\n // The handler swap above is atomic: new requests use the new server,\n // in-flight requests on the old one finish normally.\n if (old) {\n await old.stop();\n }\n }\n\n attachWebSocket(\n wsServer: WebSocketServer,\n schema: GraphQLSchema,\n handlers: WsHandlers<Context>,\n ): WsDisposer {\n return useServer(\n {\n schema,\n onConnect: (ctx) =>\n handlers.onConnect(ctx.connectionParams ?? {}, ctx.extra as object),\n context: (ctx) =>\n handlers.context(ctx.connectionParams ?? {}, ctx.extra as object),\n },\n wsServer,\n );\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.#servers.map((s) => s.stop()));\n this.#servers.length = 0;\n\n if (this.#supergraphServer) {\n await this.#supergraphServer.stop();\n this.#supergraphServer = null;\n }\n this.#handler = null;\n // Same as the Apollo adapter: clearing these makes a later\n // updateSupergraph() a no-op instead of resurrecting a stopped adapter.\n this.#getSubgraphs = null;\n this.#contextFactory = null;\n\n // Drain the shared HTTP server ourselves (the Apollo adapter gets this\n // from ApolloServerPluginDrainHttpServer, which we cannot use here - see\n // class comment). Only close a server that is still accepting connections\n // so a later close by the owner is a no-op instead of an error.\n const httpServer = this.#httpServer;\n this.#httpServer = null;\n if (httpServer?.listening) {\n await new Promise<void>((resolve) => httpServer.close(() => resolve()));\n }\n }\n\n // ── internals ──────────────────────────────────────────────────────────────\n\n async #makeServer(schema: GraphQLSchema): Promise<ApolloServer<Context>> {\n const server = new ApolloServer<Context>({\n schema,\n logger: this.#logger,\n introspection: true,\n // Same rationale as the Apollo adapter: the reactor drives shutdown\n // end-to-end; per-subgraph servers must not re-emit SIGINT.\n stopOnTerminationSignals: false,\n plugins: [\n ApolloServerPluginInlineTraceDisabled(),\n ApolloServerPluginLandingPageLocalDefault(),\n ],\n });\n await server.start();\n return server;\n }\n\n async #buildSupergraphServer(\n all: SubgraphDefinition[],\n ): Promise<ApolloServer<Context>> {\n let subgraphs = filterBuildableSubgraphs(all, this.#logger);\n if (subgraphs.length === 0 && all.length > 0) {\n // Excluding every subgraph would trade one subgraph's error for a\n // supergraph with no root type at all; keep the original set so the\n // build fails with the underlying error instead.\n this.#logger.error(\n \"Stitching gateway: every subgraph failed its isolation build; merging the unfiltered set so the underlying error surfaces\",\n );\n subgraphs = all;\n }\n const { typeDefs, conflicts } = mergeSubgraphTypeDefs(\n subgraphs,\n this.#policy,\n );\n for (const conflict of conflicts) {\n this.#logger.warn(\n `Stitching gateway (policy \"${this.#policy}\"): ${conflict}`,\n );\n }\n if (conflicts.length > 0) {\n this.#logger.warn(\n `Stitching gateway: merged ${subgraphs.length} subgraphs with ${conflicts.length} schema conflict(s); each resolution is logged above`,\n );\n } else {\n this.#logger.debug(\n `Stitching gateway: merged ${subgraphs.length} subgraphs without conflicts`,\n );\n }\n const resolvers = mergeSubgraphResolvers(subgraphs, this.#policy);\n const schema = buildMergedSchema(typeDefs, resolvers, this.#logger);\n return this.#makeServer(schema);\n }\n\n #installSupergraphServer(server: ApolloServer<Context>): FetchHandler {\n if (this.#contextFactory === null) {\n throw new Error(\"Supergraph context factory not set\");\n }\n this.#supergraphServer = server;\n const handler = createApolloFetchHandler(server, this.#contextFactory);\n this.#handler = handler;\n // The returned handler always delegates to the *current* server so\n // updateSupergraph() swaps are picked up without re-mounting the route.\n return (request: Request) => this.#handler!(request);\n }\n}\n"],"names":["#logger","#policy","#servers","#makeServer","#supergraphServer","#getSubgraphs","#httpServer","#contextFactory","#buildSupergraphServer","#installSupergraphServer","#handler"],"mappings":"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","debug_id":"1cb2831c-f802-59f7-955e-11295cb2c38d"}
1
+ {"version":3,"file":"adapter-gateway-stitching-Dzv10u8D.mjs","sources":["../src/graphql/gateway/adapter-gateway-stitching.ts"],"sourcesContent":["import { ApolloServer } from \"@apollo/server\";\nimport { ApolloServerPluginInlineTraceDisabled } from \"@apollo/server/plugin/disabled\";\nimport { ApolloServerPluginLandingPageLocalDefault } from \"@apollo/server/plugin/landingPage/default\";\nimport { mergeResolvers, mergeTypeDefs } from \"@graphql-tools/merge\";\nimport { makeExecutableSchema } from \"@graphql-tools/schema\";\nimport type { IResolvers } from \"@graphql-tools/utils\";\nimport {\n buildASTSchema,\n type DefinitionNode,\n type DocumentNode,\n isTypeDefinitionNode,\n isTypeExtensionNode,\n Kind,\n parse,\n print,\n type GraphQLNamedType,\n type GraphQLSchema,\n type TypeDefinitionNode,\n validateSchema,\n} from \"graphql\";\nimport type http from \"node:http\";\nimport type { WebSocketServer } from \"ws\";\nimport type { ILogger } from \"document-model\";\nimport type { Context } from \"../types.js\";\nimport { useServer } from \"../websocket.js\";\nimport { createApolloFetchHandler } from \"./adapter-gateway-apollo.js\";\nimport type {\n FetchHandler,\n GatewayContextFactory,\n IGatewayAdapter,\n SubgraphDefinition,\n WsDisposer,\n WsHandlers,\n} from \"./types.js\";\n\n/**\n * How to resolve two subgraphs that define the same field with incompatible\n * types (a name clash, the #1565 scenario).\n *\n * - `\"last\"` (default): the later-registered subgraph's field definition wins.\n * - `\"first\"`: the earlier-registered subgraph's field definition wins.\n *\n * Every conflict is logged either way; unlike federation composition, the\n * supergraph is still built. The policy applies to field type clashes only:\n * a type-KIND clash (the same type name declared as an object by one subgraph\n * and as an enum/input/interface/union by another) is resolved by\n * `mergeTypeDefs` itself, which always keeps the last declaration. Those are\n * detected separately and reported through the same channel so they are\n * logged rather than dropped in silence.\n */\nexport type StitchConflictPolicy = \"first\" | \"last\";\n\nexport type StitchingGatewayOptions = {\n onFieldTypeConflict?: StitchConflictPolicy;\n};\n\n/** Root operation types, which a subgraph may extend without defining. */\nconst ROOT_TYPE_NAMES = [\"Query\", \"Mutation\", \"Subscription\"];\n\n/**\n * A placeholder declaration for a type name a subgraph borrows from another\n * subgraph. Same kind as the real declaration, so the borrowing subgraph's\n * SDL validates the same way it does in the merged supergraph:\n *\n * - scalar/enum/input/object: a minimal declaration of that kind.\n * - interface: the real declaration, because a subgraph that implements the\n * interface has to satisfy its field set.\n * - union: a self-contained union over one placeholder member, so nothing the\n * real declaration references has to be resolvable here.\n */\nfunction stubDeclaration(\n name: string,\n owner: TypeDefinitionNode | undefined,\n): string {\n switch (owner?.kind) {\n case Kind.SCALAR_TYPE_DEFINITION:\n return `scalar ${name}`;\n case Kind.ENUM_TYPE_DEFINITION:\n return `enum ${name} { _STUB }`;\n case Kind.INPUT_OBJECT_TYPE_DEFINITION:\n return `input ${name} { _stub: Boolean }`;\n case Kind.INTERFACE_TYPE_DEFINITION:\n return print(owner);\n case Kind.UNION_TYPE_DEFINITION:\n return `type ${name}_Stub { _stub: Boolean } union ${name} = ${name}_Stub`;\n default:\n return `type ${name} { _stub: Boolean }`;\n }\n}\n\n/**\n * Drops subgraphs whose own typeDefs cannot be built into a valid schema, so\n * one malformed subgraph is excluded instead of failing the whole supergraph\n * build (which, since GraphQLManager.init() does not guard the supergraph\n * gateway, would be a boot failure). Each excluded subgraph is logged; the\n * rest are merged. This is the stitching counterpart of the federation path's\n * `filterComposableSubgraphs`.\n *\n * A stitching subgraph is not self-contained the way a federation subgraph is:\n * it may extend a root type it never defines (`analytics` only does\n * `extend type Query`) and reference types another subgraph owns (in raw form\n * `analytics` uses `DateTime`, declared by `auth`/`reactor`/`packages`).\n * Building it alone would therefore reject perfectly good subgraphs. So the isolation build adds\n * a placeholder declaration for every type name declared by some *other*\n * subgraph in the set, plus the root types, plus every directive definition in\n * the set. What is left to fail is the subgraph's own SDL: a dangling type\n * reference no subgraph declares, a duplicated field, an invalid implements\n * clause.\n *\n * Scope: like the federation filter, this only catches per-subgraph failures.\n * Errors that appear only once subgraphs are merged (a field type or type kind\n * clash) are reported by `mergeSubgraphTypeDefs`, not here.\n */\nexport function filterBuildableSubgraphs(\n subgraphs: SubgraphDefinition[],\n logger?: Pick<ILogger, \"error\">,\n): SubgraphDefinition[] {\n // First declaration of each type name across the whole set, for stub kinds.\n const owners = new Map<string, TypeDefinitionNode>();\n const directiveDefs = new Map<string, DefinitionNode>();\n for (const subgraph of subgraphs) {\n for (const def of subgraph.typeDefs.definitions) {\n if (isTypeDefinitionNode(def) && !owners.has(def.name.value)) {\n owners.set(def.name.value, def);\n } else if (\n def.kind === Kind.DIRECTIVE_DEFINITION &&\n !directiveDefs.has(def.name.value)\n ) {\n directiveDefs.set(def.name.value, def);\n }\n }\n }\n\n return subgraphs.filter((subgraph) => {\n const own = new Set<string>();\n const ownDirectives = new Set<string>();\n for (const def of subgraph.typeDefs.definitions) {\n if (isTypeDefinitionNode(def)) {\n own.add(def.name.value);\n } else if (def.kind === Kind.DIRECTIVE_DEFINITION) {\n ownDirectives.add(def.name.value);\n }\n }\n\n const stubs: string[] = [];\n for (const name of new Set([...owners.keys(), ...ROOT_TYPE_NAMES])) {\n if (!own.has(name)) {\n stubs.push(stubDeclaration(name, owners.get(name)));\n }\n }\n for (const [name, def] of directiveDefs) {\n if (!ownDirectives.has(name)) {\n stubs.push(print(def));\n }\n }\n\n try {\n // Merge the same way the supergraph does, so a subgraph that declares a\n // type twice within itself is normalized here too, then build and\n // validate: buildASTSchema asserts the SDL, validateSchema the result.\n const documents =\n stubs.length > 0\n ? [subgraph.typeDefs, parse(stubs.join(\"\\n\"))]\n : [subgraph.typeDefs];\n const merged = mergeTypeDefs(documents, { useSchemaDefinition: false });\n const errors = validateSchema(buildASTSchema(merged));\n if (errors.length > 0) {\n throw new Error(errors.map((error) => error.message).join(\"; \"));\n }\n return true;\n } catch (error) {\n logger?.error(\n `Stitching gateway: excluding subgraph \"${subgraph.name}\" from the supergraph: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n return false;\n }\n });\n}\n\n/**\n * The SDL keyword for a type definition or extension node, or undefined for a\n * node that does not declare a named type (schema definitions, directive\n * definitions, executable definitions). Extensions map to the same keyword as\n * their definition: `extend type Query` and `type Query` are the same kind.\n */\nfunction typeKeyword(def: DefinitionNode): string | undefined {\n switch (def.kind) {\n case Kind.OBJECT_TYPE_DEFINITION:\n case Kind.OBJECT_TYPE_EXTENSION:\n return \"type\";\n case Kind.INTERFACE_TYPE_DEFINITION:\n case Kind.INTERFACE_TYPE_EXTENSION:\n return \"interface\";\n case Kind.UNION_TYPE_DEFINITION:\n case Kind.UNION_TYPE_EXTENSION:\n return \"union\";\n case Kind.ENUM_TYPE_DEFINITION:\n case Kind.ENUM_TYPE_EXTENSION:\n return \"enum\";\n case Kind.INPUT_OBJECT_TYPE_DEFINITION:\n case Kind.INPUT_OBJECT_TYPE_EXTENSION:\n return \"input\";\n case Kind.SCALAR_TYPE_DEFINITION:\n case Kind.SCALAR_TYPE_EXTENSION:\n return \"scalar\";\n default:\n return undefined;\n }\n}\n\n/**\n * Finds type names that two subgraphs declare with different kinds (object vs\n * enum, input, interface or union). `mergeTypeDefs` does not call\n * `onFieldTypeConflict` for these - it keeps the last declaration and drops\n * the other subgraph's type entirely, with no diagnostic - so they are\n * scanned for before the merge and reported alongside field conflicts.\n */\nfunction scanTypeKindClashes(subgraphs: SubgraphDefinition[]): string[] {\n const clashes: string[] = [];\n const declaredBy = new Map<string, { keyword: string; subgraph: string }>();\n for (const subgraph of subgraphs) {\n for (const def of subgraph.typeDefs.definitions) {\n if (!isTypeDefinitionNode(def) && !isTypeExtensionNode(def)) {\n continue;\n }\n const keyword = typeKeyword(def);\n if (keyword === undefined) {\n continue;\n }\n const name = def.name.value;\n const previous = declaredBy.get(name);\n if (previous === undefined) {\n declaredBy.set(name, { keyword, subgraph: subgraph.name });\n continue;\n }\n if (previous.keyword === keyword) {\n continue;\n }\n clashes.push(\n `type kind clash on ${name}: declared as ${previous.keyword} by ` +\n `subgraph \"${previous.subgraph}\" and as ${keyword} by subgraph ` +\n `\"${subgraph.name}\"; mergeTypeDefs keeps the last declaration ` +\n `(${keyword}) and drops the other, whatever the conflict policy`,\n );\n // Track what the merge actually keeps, so a third declaration is\n // compared against the surviving kind.\n declaredBy.set(name, { keyword, subgraph: subgraph.name });\n }\n }\n return clashes;\n}\n\n/**\n * Merges all subgraph type definitions into one schema, applying the field\n * conflict policy. Exported so tests and the benchmark can exercise the merge\n * without a full adapter.\n */\nexport function mergeSubgraphTypeDefs(\n subgraphs: SubgraphDefinition[],\n policy: StitchConflictPolicy,\n): { typeDefs: DocumentNode; conflicts: string[] } {\n const conflicts: string[] = scanTypeKindClashes(subgraphs);\n const typeDefs = mergeTypeDefs(\n subgraphs.map((s) => s.typeDefs),\n {\n // Never emit a `schema { ... }` block: the merged root types are\n // determined by whichever subgraphs define Query/Mutation/Subscription.\n useSchemaDefinition: false,\n onFieldTypeConflict: (existing, other, type) => {\n // Identical definitions are normal stitching (shared types across\n // subgraphs); only differing definitions are conflicts.\n if (print(existing) === print(other)) {\n return existing;\n }\n const winner = policy === \"first\" ? existing : other;\n const loser = policy === \"first\" ? other : existing;\n conflicts.push(\n `field type clash on ${type.name.value}.${existing.name.value}: kept ` +\n `${print(winner.type)} (${\n policy === \"first\" ? \"first\" : \"last\"\n } subgraph), dropped ${print(loser.type)}`,\n );\n return winner;\n },\n },\n );\n return { typeDefs, conflicts };\n}\n\n/**\n * Merges the subgraph resolver maps in the order the conflict policy implies.\n * `mergeResolvers` is unconditionally last-wins, so under `\"first\"` the array\n * is reversed: the first-registered subgraph's resolver ends up applied last\n * and wins, matching the field type the merged schema advertises. Without\n * this the schema would advertise one subgraph's type while another\n * subgraph's resolver ran.\n */\nfunction mergeSubgraphResolvers(\n subgraphs: SubgraphDefinition[],\n policy: StitchConflictPolicy,\n): IResolvers {\n const ordered = policy === \"first\" ? [...subgraphs].reverse() : subgraphs;\n return mergeResolvers(\n ordered.map((s) => s.resolvers as IResolvers | undefined),\n );\n}\n\n/**\n * Drops resolver entries that have no matching type or field in the merged\n * schema. Document-model subgraphs generate resolver entries for operations\n * their SDL does not declare (the federation runtime silently ignores those);\n * makeExecutableSchema rejects them, so they are filtered before the build.\n */\nfunction filterResolversToSchema(\n typeMap: Record<string, GraphQLNamedType | undefined>,\n resolvers: Record<string, unknown>,\n logger?: Pick<ILogger, \"debug\">,\n): Record<string, unknown> {\n const filtered: Record<string, unknown> = {};\n for (const [typeName, entry] of Object.entries(resolvers)) {\n const type = typeMap[typeName];\n if (type === undefined) {\n // Type not part of the merged schema.\n logger?.debug(\n `Stitching gateway: dropped resolvers for type \"${typeName}\": the merged schema has no such type`,\n );\n continue;\n }\n const fields =\n type instanceof Object && \"getFields\" in type\n ? (type as { getFields(): Record<string, unknown> }).getFields()\n : undefined;\n if (fields === undefined) {\n // Scalar, enum, or union resolver: keep as-is.\n filtered[typeName] = entry;\n continue;\n }\n if (entry === null || typeof entry !== \"object\") {\n // Not a resolver map: nothing to keep.\n logger?.debug(\n `Stitching gateway: dropped resolver entry for type \"${typeName}\": expected a field map, got ${entry === null ? \"null\" : typeof entry}`,\n );\n continue;\n }\n const map = entry as { [key: string]: unknown };\n const kept: Record<string, unknown> = {};\n const dropped: string[] = [];\n for (const [key, value] of Object.entries(map)) {\n if (key === \"__resolveReference\" || fields[key] !== undefined) {\n kept[key] = value;\n } else {\n dropped.push(key);\n }\n }\n if (dropped.length > 0) {\n logger?.debug(\n `Stitching gateway: dropped resolvers ${dropped\n .map((field) => `${typeName}.${field}`)\n .join(\", \")}: the merged schema declares no such field(s)`,\n );\n }\n if (Object.keys(kept).length > 0) {\n filtered[typeName] = kept;\n }\n }\n return filtered;\n}\n\n/**\n * Builds the executable supergraph schema from merged type definitions and\n * resolvers (shared by the adapter and the pure merge helper).\n */\nfunction buildMergedSchema(\n typeDefs: DocumentNode,\n resolvers: IResolvers,\n logger?: Pick<ILogger, \"debug\">,\n): GraphQLSchema {\n // A type-only build to get the merged type map; assumeValid skips SDL\n // validation, which makeExecutableSchema performs on the real build.\n const typeMap = buildASTSchema(typeDefs, { assumeValid: true }).getTypeMap();\n // The filter works on the raw resolver shape; the result is a valid\n // IResolvers because it only removes entries from one.\n const filtered = filterResolversToSchema(\n typeMap,\n resolvers as Record<string, unknown>,\n logger,\n );\n return makeExecutableSchema({ typeDefs, resolvers: filtered as IResolvers });\n}\n\n/**\n * Merges multiple subgraphs into a single in-process executable schema.\n * This is the \"Guild\" (graphql-tools) composition path: instead of federation\n * (which hard-fails on cross-subgraph type conflicts and executes subgraph\n * fields over loopback HTTP), the type definitions are merged with an\n * explicit conflict policy and the resolvers run in-process.\n */\nexport function mergeSubgraphSchemas(\n subgraphs: SubgraphDefinition[],\n policy: StitchConflictPolicy,\n): GraphQLSchema {\n if (subgraphs.length === 0) {\n throw new Error(\"Cannot merge zero subgraphs\");\n }\n const { typeDefs } = mergeSubgraphTypeDefs(subgraphs, policy);\n const resolvers = mergeSubgraphResolvers(subgraphs, policy);\n return buildMergedSchema(typeDefs, resolvers);\n}\n\n/**\n * A stitching gateway adapter: the supergraph is one merged schema executed\n * in-process. Subgraph routes (`/graphql/<name>`) are served exactly like the\n * Apollo adapter, so direct subgraph access is unchanged.\n *\n * Note: unlike the Apollo adapter, the supergraph ApolloServer is NOT given\n * ApolloServerPluginDrainHttpServer. The plugin closes the (shared) HTTP\n * server on stop, which would kill every mounted subgraph route when\n * updateSupergraph() swaps the supergraph server. The shared server is drained\n * explicitly in stop() instead.\n */\nexport class StitchingGatewayAdapter implements IGatewayAdapter<Context> {\n readonly #logger: ILogger;\n readonly #policy: StitchConflictPolicy;\n\n readonly #servers: ApolloServer<Context>[] = [];\n #supergraphServer: ApolloServer<Context> | null = null;\n #handler: FetchHandler | null = null;\n #httpServer: http.Server | null = null;\n #getSubgraphs: (() => SubgraphDefinition[]) | null = null;\n #contextFactory: GatewayContextFactory<Context> | null = null;\n\n constructor(logger: ILogger, options: StitchingGatewayOptions = {}) {\n this.#logger = logger;\n this.#policy = options.onFieldTypeConflict ?? \"last\";\n }\n\n async start(_httpServer: http.Server): Promise<void> {\n // Per-subgraph Apollo servers start lazily in createHandler.\n // Nothing to do here.\n }\n\n async createHandler(\n schema: GraphQLSchema,\n contextFactory: GatewayContextFactory<Context>,\n ): Promise<FetchHandler> {\n const server = await this.#makeServer(schema);\n this.#servers.push(server);\n return createApolloFetchHandler(server, contextFactory);\n }\n\n async createSupergraphHandler(\n getSubgraphs: () => SubgraphDefinition[],\n httpServer: http.Server,\n contextFactory: GatewayContextFactory<Context>,\n ): Promise<FetchHandler> {\n if (this.#supergraphServer) {\n throw new Error(\"Supergraph server is already running\");\n }\n\n this.#getSubgraphs = getSubgraphs;\n this.#httpServer = httpServer;\n this.#contextFactory = contextFactory;\n\n const server = await this.#buildSupergraphServer(getSubgraphs());\n return this.#installSupergraphServer(server);\n }\n\n async updateSupergraph(): Promise<void> {\n if (!this.#getSubgraphs || !this.#contextFactory) {\n // Not yet initialized - no-op.\n return;\n }\n const server = await this.#buildSupergraphServer(this.#getSubgraphs());\n const old = this.#supergraphServer;\n this.#installSupergraphServer(server);\n // The handler swap above is atomic: new requests use the new server,\n // in-flight requests on the old one finish normally.\n if (old) {\n await old.stop();\n }\n }\n\n attachWebSocket(\n wsServer: WebSocketServer,\n schema: GraphQLSchema,\n handlers: WsHandlers<Context>,\n ): WsDisposer {\n return useServer(\n {\n schema,\n onConnect: (ctx) =>\n handlers.onConnect(ctx.connectionParams ?? {}, ctx.extra as object),\n context: (ctx) =>\n handlers.context(ctx.connectionParams ?? {}, ctx.extra as object),\n },\n wsServer,\n );\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.#servers.map((s) => s.stop()));\n this.#servers.length = 0;\n\n if (this.#supergraphServer) {\n await this.#supergraphServer.stop();\n this.#supergraphServer = null;\n }\n this.#handler = null;\n // Same as the Apollo adapter: clearing these makes a later\n // updateSupergraph() a no-op instead of resurrecting a stopped adapter.\n this.#getSubgraphs = null;\n this.#contextFactory = null;\n\n // Drain the shared HTTP server ourselves (the Apollo adapter gets this\n // from ApolloServerPluginDrainHttpServer, which we cannot use here - see\n // class comment). Only close a server that is still accepting connections\n // so a later close by the owner is a no-op instead of an error.\n const httpServer = this.#httpServer;\n this.#httpServer = null;\n if (httpServer?.listening) {\n await new Promise<void>((resolve) => httpServer.close(() => resolve()));\n }\n }\n\n // ── internals ──────────────────────────────────────────────────────────────\n\n async #makeServer(schema: GraphQLSchema): Promise<ApolloServer<Context>> {\n const server = new ApolloServer<Context>({\n schema,\n logger: this.#logger,\n introspection: true,\n // Same rationale as the Apollo adapter: the reactor drives shutdown\n // end-to-end; per-subgraph servers must not re-emit SIGINT.\n stopOnTerminationSignals: false,\n plugins: [\n ApolloServerPluginInlineTraceDisabled(),\n ApolloServerPluginLandingPageLocalDefault(),\n ],\n });\n await server.start();\n return server;\n }\n\n async #buildSupergraphServer(\n all: SubgraphDefinition[],\n ): Promise<ApolloServer<Context>> {\n let subgraphs = filterBuildableSubgraphs(all, this.#logger);\n if (subgraphs.length === 0 && all.length > 0) {\n // Excluding every subgraph would trade one subgraph's error for a\n // supergraph with no root type at all; keep the original set so the\n // build fails with the underlying error instead.\n this.#logger.error(\n \"Stitching gateway: every subgraph failed its isolation build; merging the unfiltered set so the underlying error surfaces\",\n );\n subgraphs = all;\n }\n const { typeDefs, conflicts } = mergeSubgraphTypeDefs(\n subgraphs,\n this.#policy,\n );\n for (const conflict of conflicts) {\n this.#logger.warn(\n `Stitching gateway (policy \"${this.#policy}\"): ${conflict}`,\n );\n }\n if (conflicts.length > 0) {\n this.#logger.warn(\n `Stitching gateway: merged ${subgraphs.length} subgraphs with ${conflicts.length} schema conflict(s); each resolution is logged above`,\n );\n } else {\n this.#logger.debug(\n `Stitching gateway: merged ${subgraphs.length} subgraphs without conflicts`,\n );\n }\n const resolvers = mergeSubgraphResolvers(subgraphs, this.#policy);\n const schema = buildMergedSchema(typeDefs, resolvers, this.#logger);\n return this.#makeServer(schema);\n }\n\n #installSupergraphServer(server: ApolloServer<Context>): FetchHandler {\n if (this.#contextFactory === null) {\n throw new Error(\"Supergraph context factory not set\");\n }\n this.#supergraphServer = server;\n const handler = createApolloFetchHandler(server, this.#contextFactory);\n this.#handler = handler;\n // The returned handler always delegates to the *current* server so\n // updateSupergraph() swaps are picked up without re-mounting the route.\n return (request: Request) => this.#handler!(request);\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAyDA,MAAM,kBAAkB;CAAC;CAAS;CAAY;AAAc;;;;;;;;;;;;AAa5D,SAAS,gBACP,MACA,OACQ;CACR,QAAQ,OAAO,MAAf;EACE,KAAK,KAAK,wBACR,OAAO,UAAU;EACnB,KAAK,KAAK,sBACR,OAAO,QAAQ,KAAK;EACtB,KAAK,KAAK,8BACR,OAAO,SAAS,KAAK;EACvB,KAAK,KAAK,2BACR,OAAO,MAAM,KAAK;EACpB,KAAK,KAAK,uBACR,OAAO,QAAQ,KAAK,iCAAiC,KAAK,KAAK,KAAK;EACtE,SACE,OAAO,QAAQ,KAAK;CACxB;AACF;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,yBACd,WACA,QACsB;CAEtB,MAAM,yBAAS,IAAI,IAAgC;CACnD,MAAM,gCAAgB,IAAI,IAA4B;CACtD,KAAK,MAAM,YAAY,WACrB,KAAK,MAAM,OAAO,SAAS,SAAS,aAClC,IAAI,qBAAqB,GAAG,KAAK,CAAC,OAAO,IAAI,IAAI,KAAK,KAAK,GACzD,OAAO,IAAI,IAAI,KAAK,OAAO,GAAG;MACzB,IACL,IAAI,SAAS,KAAK,wBAClB,CAAC,cAAc,IAAI,IAAI,KAAK,KAAK,GAEjC,cAAc,IAAI,IAAI,KAAK,OAAO,GAAG;CAK3C,OAAO,UAAU,QAAQ,aAAa;EACpC,MAAM,sBAAM,IAAI,IAAY;EAC5B,MAAM,gCAAgB,IAAI,IAAY;EACtC,KAAK,MAAM,OAAO,SAAS,SAAS,aAClC,IAAI,qBAAqB,GAAG,GAC1B,IAAI,IAAI,IAAI,KAAK,KAAK;OACjB,IAAI,IAAI,SAAS,KAAK,sBAC3B,cAAc,IAAI,IAAI,KAAK,KAAK;EAIpC,MAAM,QAAkB,CAAC;EACzB,KAAK,MAAM,wBAAQ,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,GAAG,GAAG,eAAe,CAAC,GAC/D,IAAI,CAAC,IAAI,IAAI,IAAI,GACf,MAAM,KAAK,gBAAgB,MAAM,OAAO,IAAI,IAAI,CAAC,CAAC;EAGtD,KAAK,MAAM,CAAC,MAAM,QAAQ,eACxB,IAAI,CAAC,cAAc,IAAI,IAAI,GACzB,MAAM,KAAK,MAAM,GAAG,CAAC;EAIzB,IAAI;GAIF,MAAM,YACJ,MAAM,SAAS,IACX,CAAC,SAAS,UAAU,MAAM,MAAM,KAAK,IAAI,CAAC,CAAC,IAC3C,CAAC,SAAS,QAAQ;GACxB,MAAM,SAAS,cAAc,WAAW,EAAE,qBAAqB,MAAM,CAAC;GACtE,MAAM,SAAS,eAAe,eAAe,MAAM,CAAC;GACpD,IAAI,OAAO,SAAS,GAClB,MAAM,IAAI,MAAM,OAAO,KAAK,UAAU,MAAM,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC;GAEjE,OAAO;EACT,SAAS,OAAO;GACd,QAAQ,MACN,0CAA0C,SAAS,KAAK,yBACtD,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAEzD;GACA,OAAO;EACT;CACF,CAAC;AACH;;;;;;;AAQA,SAAS,YAAY,KAAyC;CAC5D,QAAQ,IAAI,MAAZ;EACE,KAAK,KAAK;EACV,KAAK,KAAK,uBACR,OAAO;EACT,KAAK,KAAK;EACV,KAAK,KAAK,0BACR,OAAO;EACT,KAAK,KAAK;EACV,KAAK,KAAK,sBACR,OAAO;EACT,KAAK,KAAK;EACV,KAAK,KAAK,qBACR,OAAO;EACT,KAAK,KAAK;EACV,KAAK,KAAK,6BACR,OAAO;EACT,KAAK,KAAK;EACV,KAAK,KAAK,uBACR,OAAO;EACT,SACE;CACJ;AACF;;;;;;;;AASA,SAAS,oBAAoB,WAA2C;CACtE,MAAM,UAAoB,CAAC;CAC3B,MAAM,6BAAa,IAAI,IAAmD;CAC1E,KAAK,MAAM,YAAY,WACrB,KAAK,MAAM,OAAO,SAAS,SAAS,aAAa;EAC/C,IAAI,CAAC,qBAAqB,GAAG,KAAK,CAAC,oBAAoB,GAAG,GACxD;EAEF,MAAM,UAAU,YAAY,GAAG;EAC/B,IAAI,YAAY,KAAA,GACd;EAEF,MAAM,OAAO,IAAI,KAAK;EACtB,MAAM,WAAW,WAAW,IAAI,IAAI;EACpC,IAAI,aAAa,KAAA,GAAW;GAC1B,WAAW,IAAI,MAAM;IAAE;IAAS,UAAU,SAAS;GAAK,CAAC;GACzD;EACF;EACA,IAAI,SAAS,YAAY,SACvB;EAEF,QAAQ,KACN,sBAAsB,KAAK,gBAAgB,SAAS,QAAQ,gBAC7C,SAAS,SAAS,WAAW,QAAQ,gBAC9C,SAAS,KAAK,+CACd,QAAQ,oDAChB;EAGA,WAAW,IAAI,MAAM;GAAE;GAAS,UAAU,SAAS;EAAK,CAAC;CAC3D;CAEF,OAAO;AACT;;;;;;AAOA,SAAgB,sBACd,WACA,QACiD;CACjD,MAAM,YAAsB,oBAAoB,SAAS;CAyBzD,OAAO;EAAE,UAxBQ,cACf,UAAU,KAAK,MAAM,EAAE,QAAQ,GAC/B;GAGE,qBAAqB;GACrB,sBAAsB,UAAU,OAAO,SAAS;IAG9C,IAAI,MAAM,QAAQ,MAAM,MAAM,KAAK,GACjC,OAAO;IAET,MAAM,SAAS,WAAW,UAAU,WAAW;IAC/C,MAAM,QAAQ,WAAW,UAAU,QAAQ;IAC3C,UAAU,KACR,uBAAuB,KAAK,KAAK,MAAM,GAAG,SAAS,KAAK,MAAM,SACzD,MAAM,OAAO,IAAI,EAAE,IACpB,WAAW,UAAU,UAAU,OAChC,sBAAsB,MAAM,MAAM,IAAI,GAC3C;IACA,OAAO;GACT;EACF,CAEc;EAAG;CAAU;AAC/B;;;;;;;;;AAUA,SAAS,uBACP,WACA,QACY;CACZ,MAAM,UAAU,WAAW,UAAU,CAAC,GAAG,SAAS,CAAC,CAAC,QAAQ,IAAI;CAChE,OAAO,eACL,QAAQ,KAAK,MAAM,EAAE,SAAmC,CAC1D;AACF;;;;;;;AAQA,SAAS,wBACP,SACA,WACA,QACyB;CACzB,MAAM,WAAoC,CAAC;CAC3C,KAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,SAAS,GAAG;EACzD,MAAM,OAAO,QAAQ;EACrB,IAAI,SAAS,KAAA,GAAW;GAEtB,QAAQ,MACN,kDAAkD,SAAS,sCAC7D;GACA;EACF;EACA,MAAM,SACJ,gBAAgB,UAAU,eAAe,OACpC,KAAkD,UAAU,IAC7D,KAAA;EACN,IAAI,WAAW,KAAA,GAAW;GAExB,SAAS,YAAY;GACrB;EACF;EACA,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;GAE/C,QAAQ,MACN,uDAAuD,SAAS,+BAA+B,UAAU,OAAO,SAAS,OAAO,OAClI;GACA;EACF;EACA,MAAM,MAAM;EACZ,MAAM,OAAgC,CAAC;EACvC,MAAM,UAAoB,CAAC;EAC3B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAC3C,IAAI,QAAQ,wBAAwB,OAAO,SAAS,KAAA,GAClD,KAAK,OAAO;OAEZ,QAAQ,KAAK,GAAG;EAGpB,IAAI,QAAQ,SAAS,GACnB,QAAQ,MACN,wCAAwC,QACrC,KAAK,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,CACtC,KAAK,IAAI,EAAE,8CAChB;EAEF,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,GAC7B,SAAS,YAAY;CAEzB;CACA,OAAO;AACT;;;;;AAMA,SAAS,kBACP,UACA,WACA,QACe;CAMf,MAAM,WAAW,wBAHD,eAAe,UAAU,EAAE,aAAa,KAAK,CAAC,CAAC,CAAC,WAIxD,GACN,WACA,MACF;CACA,OAAO,qBAAqB;EAAE;EAAU,WAAW;CAAuB,CAAC;AAC7E;;;;;;;;;;;;AAgCA,IAAa,0BAAb,MAAyE;CACvE;CACA;CAEA,WAA6C,CAAC;CAC9C,oBAAkD;CAClD,WAAgC;CAChC,cAAkC;CAClC,gBAAqD;CACrD,kBAAyD;CAEzD,YAAY,QAAiB,UAAmC,CAAC,GAAG;EAClE,KAAK,UAAU;EACf,KAAK,UAAU,QAAQ,uBAAuB;CAChD;CAEA,MAAM,MAAM,aAAyC,CAGrD;CAEA,MAAM,cACJ,QACA,gBACuB;EACvB,MAAM,SAAS,MAAM,KAAK,YAAY,MAAM;EAC5C,KAAK,SAAS,KAAK,MAAM;EACzB,OAAO,yBAAyB,QAAQ,cAAc;CACxD;CAEA,MAAM,wBACJ,cACA,YACA,gBACuB;EACvB,IAAI,KAAK,mBACP,MAAM,IAAI,MAAM,sCAAsC;EAGxD,KAAK,gBAAgB;EACrB,KAAK,cAAc;EACnB,KAAK,kBAAkB;EAEvB,MAAM,SAAS,MAAM,KAAK,uBAAuB,aAAa,CAAC;EAC/D,OAAO,KAAK,yBAAyB,MAAM;CAC7C;CAEA,MAAM,mBAAkC;EACtC,IAAI,CAAC,KAAK,iBAAiB,CAAC,KAAK,iBAE/B;EAEF,MAAM,SAAS,MAAM,KAAK,uBAAuB,KAAK,cAAc,CAAC;EACrE,MAAM,MAAM,KAAK;EACjB,KAAK,yBAAyB,MAAM;EAGpC,IAAI,KACF,MAAM,IAAI,KAAK;CAEnB;CAEA,gBACE,UACA,QACA,UACY;EACZ,OAAO,UACL;GACE;GACA,YAAY,QACV,SAAS,UAAU,IAAI,oBAAoB,CAAC,GAAG,IAAI,KAAe;GACpE,UAAU,QACR,SAAS,QAAQ,IAAI,oBAAoB,CAAC,GAAG,IAAI,KAAe;EACpE,GACA,QACF;CACF;CAEA,MAAM,OAAsB;EAC1B,MAAM,QAAQ,IAAI,KAAK,SAAS,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC;EACpD,KAAK,SAAS,SAAS;EAEvB,IAAI,KAAK,mBAAmB;GAC1B,MAAM,KAAK,kBAAkB,KAAK;GAClC,KAAK,oBAAoB;EAC3B;EACA,KAAK,WAAW;EAGhB,KAAK,gBAAgB;EACrB,KAAK,kBAAkB;EAMvB,MAAM,aAAa,KAAK;EACxB,KAAK,cAAc;EACnB,IAAI,YAAY,WACd,MAAM,IAAI,SAAe,YAAY,WAAW,YAAY,QAAQ,CAAC,CAAC;CAE1E;CAIA,MAAM,YAAY,QAAuD;EACvE,MAAM,SAAS,IAAI,aAAsB;GACvC;GACA,QAAQ,KAAK;GACb,eAAe;GAGf,0BAA0B;GAC1B,SAAS,CACP,sCAAsC,GACtC,0CAA0C,CAC5C;EACF,CAAC;EACD,MAAM,OAAO,MAAM;EACnB,OAAO;CACT;CAEA,MAAM,uBACJ,KACgC;EAChC,IAAI,YAAY,yBAAyB,KAAK,KAAK,OAAO;EAC1D,IAAI,UAAU,WAAW,KAAK,IAAI,SAAS,GAAG;GAI5C,KAAK,QAAQ,MACX,2HACF;GACA,YAAY;EACd;EACA,MAAM,EAAE,UAAU,cAAc,sBAC9B,WACA,KAAK,OACP;EACA,KAAK,MAAM,YAAY,WACrB,KAAK,QAAQ,KACX,8BAA8B,KAAK,QAAQ,MAAM,UACnD;EAEF,IAAI,UAAU,SAAS,GACrB,KAAK,QAAQ,KACX,6BAA6B,UAAU,OAAO,kBAAkB,UAAU,OAAO,qDACnF;OAEA,KAAK,QAAQ,MACX,6BAA6B,UAAU,OAAO,6BAChD;EAGF,MAAM,SAAS,kBAAkB,UADf,uBAAuB,WAAW,KAAK,OACN,GAAG,KAAK,OAAO;EAClE,OAAO,KAAK,YAAY,MAAM;CAChC;CAEA,yBAAyB,QAA6C;EACpE,IAAI,KAAK,oBAAoB,MAC3B,MAAM,IAAI,MAAM,oCAAoC;EAEtD,KAAK,oBAAoB;EACzB,MAAM,UAAU,yBAAyB,QAAQ,KAAK,eAAe;EACrE,KAAK,WAAW;EAGhB,QAAQ,YAAqB,KAAK,SAAU,OAAO;CACrD;AACF","debug_id":"86579686-a510-5b69-bb5b-7db68995aac8"}
@@ -1,10 +1,10 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="af482776-5e68-5345-a965-0937af984537")}catch(e){}}();
3
- import { t as normalizePath } from "./path-normalize-BOQwY9wR.mjs";
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="b10aa351-8ded-5463-91b0-6cfb882abce2")}catch(e){}}();
3
+ import { n as normalizePath, t as runNodeHandler } from "./run-node-handler-CQjyjOuN.mjs";
4
4
  import path from "node:path";
5
5
  import { match } from "path-to-regexp";
6
6
  import { Readable } from "node:stream";
7
- import fs from "node:fs";
7
+ import nodeFs from "node:fs";
8
8
  import http from "node:http";
9
9
  import https from "node:https";
10
10
  import bodyParser from "body-parser";
@@ -93,7 +93,7 @@ var ExpressHttpAdapter = class {
93
93
  const matched = entry.matcher(pathname);
94
94
  if (!matched) continue;
95
95
  req.params = matched.params;
96
- entry.handler(req, res, entry.rawBody ? void 0 : req.body);
96
+ runNodeHandler(entry.handler, req, res, entry.rawBody ? void 0 : req.body);
97
97
  return true;
98
98
  }
99
99
  next();
@@ -135,7 +135,7 @@ var ExpressHttpAdapter = class {
135
135
  this.#routes.delete(handle);
136
136
  }
137
137
  }
138
- async listen(port, tls) {
138
+ async listen(port, tls, host) {
139
139
  let server;
140
140
  if (tls === true) {
141
141
  const { cert, key } = await devcert.certificateFor("localhost");
@@ -147,8 +147,8 @@ var ExpressHttpAdapter = class {
147
147
  } else if (tls && "keyPath" in tls) {
148
148
  const currentDir = process.cwd();
149
149
  server = https.createServer({
150
- key: fs.readFileSync(path.join(currentDir, tls.keyPath)),
151
- cert: fs.readFileSync(path.join(currentDir, tls.certPath))
150
+ key: nodeFs.readFileSync(path.join(currentDir, tls.keyPath)),
151
+ cert: nodeFs.readFileSync(path.join(currentDir, tls.certPath))
152
152
  }, this.#app);
153
153
  } else if (tls && "cert" in tls) server = https.createServer({
154
154
  cert: tls.cert,
@@ -157,7 +157,7 @@ var ExpressHttpAdapter = class {
157
157
  else server = http.createServer(this.#app);
158
158
  return new Promise((resolve, reject) => {
159
159
  server.once("error", reject);
160
- server.listen(port, () => {
160
+ server.listen(port, host, () => {
161
161
  server.off("error", reject);
162
162
  resolve(server);
163
163
  });
@@ -235,5 +235,5 @@ function createExpressHttpAdapter(existingApp) {
235
235
  //#endregion
236
236
  export { createExpressHttpAdapter };
237
237
 
238
- //# sourceMappingURL=adapter-http-express-B39rPhqH.mjs.map
239
- //# debugId=af482776-5e68-5345-a965-0937af984537
238
+ //# sourceMappingURL=adapter-http-express-P0t-mdMV.mjs.map
239
+ //# debugId=b10aa351-8ded-5463-91b0-6cfb882abce2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-http-express-P0t-mdMV.mjs","sources":["../src/graphql/gateway/adapter-http-express.ts"],"sourcesContent":["import bodyParser from \"body-parser\";\nimport cors from \"cors\";\nimport type { CorsOptions } from \"cors\";\nimport devcert from \"devcert\";\nimport type express from \"express\";\nimport type { Express } from \"express\";\nimport { Router } from \"express\";\nimport expressLib from \"express\";\nimport type { IRouter } from \"express\";\nimport fs from \"node:fs\";\nimport http from \"node:http\";\nimport https from \"node:https\";\nimport path from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport type { ReadableStream as WebReadableStream } from \"node:stream/web\";\nimport { match, type MatchFunction, type ParamData } from \"path-to-regexp\";\nimport type {\n FetchHandler,\n HttpMethod,\n IHttpAdapter,\n NodeRouteOptions,\n AdapterRouteHandle,\n TlsOptions,\n} from \"./types.js\";\nimport { normalizePath } from \"./path-normalize.js\";\nimport { runNodeHandler, type NodeHandler } from \"./run-node-handler.js\";\n\ntype GetHandler = (r: Request) => Response | Promise<Response>;\n\ntype RouteEntry =\n | {\n kind: \"fetch\";\n path: string;\n matcher: MatchFunction<ParamData>;\n prefix: boolean;\n handler: FetchHandler;\n }\n | {\n kind: \"get\";\n path: string;\n matcher: MatchFunction<ParamData>;\n handler: GetHandler;\n }\n | {\n kind: \"node\";\n method: string;\n path: string;\n matcher: MatchFunction<ParamData>;\n handler: NodeHandler;\n /** Dispatched ahead of the body parsers, with the stream unread. */\n rawBody: boolean;\n };\n\nexport class ExpressHttpAdapter implements IHttpAdapter {\n readonly #app: Express;\n readonly #router: IRouter;\n\n /**\n * Every route lives in this registry and is served by one\n * permanently-registered dispatcher (installed by setupMiddleware), because\n * Express 4 has no route-removal API: routes registered directly on the\n * app or router can never be taken back. Entries iterate in registration\n * order; mounting a path that already holds a route of the same kind (and\n * method, for node routes) replaces the old entry, so re-mounting is\n * last-write-wins without accumulating.\n */\n readonly #routes = new Map<number, RouteEntry>();\n #nextHandle = 0;\n\n constructor(existingApp?: Express) {\n this.#app = existingApp ?? expressLib();\n this.#router = Router();\n this.#app.use(this.#router);\n }\n\n setupSentryErrorHandler(sentry: object): void {\n const s = sentry as {\n setupExpressErrorHandler(app: Express): void;\n };\n s.setupExpressErrorHandler(this.#app);\n }\n\n get handle(): unknown {\n return this.#app;\n }\n\n mountRawMiddleware(middleware: unknown): void {\n // Connect/Express middleware shape; the caller owns its typing.\n this.#app.use(middleware as express.RequestHandler);\n }\n\n mountNodeRoute(\n method: HttpMethod,\n path: string,\n handler: (\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body?: unknown,\n ) => void | Promise<void>,\n { rawBody = false, prefix = false }: NodeRouteOptions = {},\n ): AdapterRouteHandle {\n this.#replaceDuplicates(\"node\", path, method.toUpperCase());\n const handle = this.#nextHandle++;\n this.#routes.set(handle, {\n kind: \"node\",\n method: method.toUpperCase(),\n path,\n matcher: match(normalizePath(path), { end: !prefix }),\n rawBody,\n handler,\n });\n return { dispose: () => this.#routes.delete(handle) };\n }\n\n setupMiddleware({\n corsOptions,\n bodyLimit = \"50mb\",\n }: {\n corsOptions?: CorsOptions;\n bodyLimit?: string;\n }): void {\n this.#router.use(cors(corsOptions));\n\n // Ahead of the parsers: a raw route's whole point is that nothing has read\n // the stream. Behind them, `req` is a consumed stream and only a\n // re-encoded `req.body` survives — which cannot carry a signature over the\n // octets the client actually sent.\n this.#router.use((req, res, next) => {\n this.#dispatchNodeRoute(req, res, next, true);\n });\n\n this.#router.use(bodyParser.json({ limit: bodyLimit }));\n this.#router.use(\n bodyParser.urlencoded({ extended: true, limit: bodyLimit }),\n );\n\n // The single dispatch point for every registered route, registered\n // AFTER the body parsers so node routes receive a parsed req.body.\n // A request matching no route falls through to app-level middleware\n // (mountRawMiddleware) and then Express's default 404.\n this.#router.use((req, res, next) => {\n const pathname = req.path;\n\n // Node routes first, then GET routes, then Fetch mounts — the same\n // order the Fastify adapter uses. A node route is the most specific\n // registration there is (method plus exact path), while a Fetch mount is\n // often a prefix; letting the prefix win would silently shadow an exact\n // route, and would do it in only one of the two adapters.\n if (this.#dispatchNodeRoute(req, res, () => undefined, false)) return;\n\n if (req.method === \"GET\" || req.method === \"HEAD\") {\n for (const entry of this.#routes.values()) {\n if (entry.kind !== \"get\" || !entry.matcher(pathname)) continue;\n this.#serveGetEntry(entry, req, res);\n return;\n }\n }\n\n for (const entry of this.#routes.values()) {\n if (entry.kind !== \"fetch\" || !entry.matcher(pathname)) continue;\n this.#serveFetchHandler(entry.handler, req, res, next);\n return;\n }\n\n next();\n });\n }\n\n /**\n * Serves the first node route matching this request, or calls `next()`.\n * `raw` selects which half of the registry to consider, so the two passes —\n * one before the body parsers, one after — never serve the same route twice.\n */\n #dispatchNodeRoute(\n req: express.Request,\n res: express.Response,\n next: express.NextFunction,\n raw: boolean,\n ): boolean {\n const pathname = req.path;\n for (const entry of this.#routes.values()) {\n if (entry.kind !== \"node\") continue;\n if (entry.rawBody !== raw) continue;\n if (entry.method !== req.method) continue;\n const matched = entry.matcher(pathname);\n if (!matched) continue;\n req.params = matched.params as Record<string, string>;\n runNodeHandler(\n entry.handler,\n req,\n res,\n entry.rawBody ? undefined : req.body,\n );\n return true;\n }\n next();\n return false;\n }\n\n mount(\n path: string,\n handler: FetchHandler,\n { prefix, exact }: { prefix?: boolean; exact?: boolean } = {},\n ): AdapterRouteHandle {\n // `exact` never meant exact: it selected prefix matching. Kept as an alias\n // so existing callers keep working while the name is retired.\n const asPrefix = prefix ?? exact ?? false;\n this.#replaceDuplicates(\"fetch\", path);\n const handle = this.#nextHandle++;\n this.#routes.set(handle, {\n kind: \"fetch\",\n path,\n matcher: match(normalizePath(path), { end: !asPrefix }),\n prefix: asPrefix,\n handler,\n });\n return { dispose: () => this.#routes.delete(handle) };\n }\n\n getRoute(\n path: string,\n handler: (request: Request) => Response | Promise<Response>,\n ): AdapterRouteHandle {\n this.#replaceDuplicates(\"get\", path);\n const handle = this.#nextHandle++;\n this.#routes.set(handle, {\n kind: \"get\",\n path,\n matcher: match(normalizePath(path)),\n handler,\n });\n return { dispose: () => this.#routes.delete(handle) };\n }\n\n /**\n * Drop any existing entry the new registration would duplicate (same kind\n * and path, plus method for node routes) so a re-mount replaces instead of\n * shadowing. Map iteration tolerates concurrent deletion.\n */\n #replaceDuplicates(\n kind: RouteEntry[\"kind\"],\n path: string,\n method?: string,\n ): void {\n for (const [handle, entry] of this.#routes) {\n if (entry.kind !== kind || entry.path !== path) continue;\n if (kind === \"node\" && entry.kind === \"node\" && entry.method !== method) {\n continue;\n }\n this.#routes.delete(handle);\n }\n }\n\n async listen(\n port: number,\n tls?: TlsOptions,\n host?: string,\n ): Promise<http.Server> {\n let server: http.Server;\n\n if (tls === true) {\n const { cert, key } = (await devcert.certificateFor(\"localhost\")) as {\n cert: Buffer;\n key: Buffer;\n };\n if (!cert || !key) {\n throw new Error(\"Invalid certificate generated\");\n }\n server = https.createServer({ cert, key }, this.#app);\n } else if (tls && \"keyPath\" in tls) {\n const currentDir = process.cwd();\n server = https.createServer(\n {\n key: fs.readFileSync(path.join(currentDir, tls.keyPath)),\n cert: fs.readFileSync(path.join(currentDir, tls.certPath)),\n },\n this.#app,\n );\n } else if (tls && \"cert\" in tls) {\n server = https.createServer({ cert: tls.cert, key: tls.key }, this.#app);\n } else {\n server = http.createServer(this.#app);\n }\n\n return new Promise<http.Server>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(port, host, () => {\n server.off(\"error\", reject);\n resolve(server);\n });\n });\n }\n\n #serveFetchHandler(\n handler: FetchHandler,\n req: express.Request,\n res: express.Response,\n next: express.NextFunction,\n ): void {\n // Build the full URL for the Fetch Request\n const protocol = req.protocol;\n const host = req.get(\"host\") ?? \"localhost\";\n const url = `${protocol}://${host}${req.originalUrl}`;\n\n // Convert Node.js incoming headers to Fetch Headers\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (typeof value === \"string\") {\n headers.set(key, value);\n } else if (Array.isArray(value)) {\n headers.set(key, value.join(\", \"));\n }\n }\n\n // bodyParser has already run, so req.body is a parsed JS value.\n // Re-serialize it so the Fetch Request body stream is readable.\n let body: string | undefined;\n if (\n req.method !== \"GET\" &&\n req.method !== \"HEAD\" &&\n req.body !== undefined\n ) {\n body = JSON.stringify(req.body);\n }\n\n const fetchRequest = new Request(url, {\n method: req.method,\n headers,\n body,\n });\n\n Promise.resolve(handler(fetchRequest))\n .then(async (response) => {\n res.status(response.status);\n response.headers.forEach((value, key) => {\n res.setHeader(key, value);\n });\n if (response.body === null) {\n res.send(await response.text());\n return;\n }\n // Stream the body to the socket instead of awaiting .text(): a\n // stream-backed body (e.g. graphql-sse) only closes when the\n // subscription completes, so awaiting would hang the request.\n // `response.body` is typed against the global (lib) ReadableStream\n // declaration, while Readable.fromWeb wants node:stream/web's; at\n // runtime they are the same stream, so the cast is safe.\n const bodyStream = response.body as WebReadableStream;\n const nodeStream = Readable.fromWeb(bodyStream);\n req.on(\"close\", () => {\n // The client went away mid-stream; stop pulling from the source.\n nodeStream.destroy();\n });\n nodeStream.on(\"error\", (err) => {\n if (res.headersSent) {\n // The response has already started; nothing left to say.\n res.destroy();\n } else {\n next(err);\n }\n });\n nodeStream.pipe(res);\n })\n .catch(next);\n }\n\n #serveGetEntry(\n entry: Extract<RouteEntry, { kind: \"get\" }>,\n req: express.Request,\n res: express.Response,\n ): void {\n const protocol = req.protocol;\n const host = req.get(\"host\") ?? \"localhost\";\n const url = `${protocol}://${host}${req.originalUrl}`;\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (typeof value === \"string\") {\n headers.set(key, value);\n } else if (Array.isArray(value)) {\n headers.set(key, value.join(\", \"));\n }\n }\n // GET is forced (matching the pre-refactor behavior, which also\n // normalized HEAD requests through the GET route handler).\n const fetchRequest = new Request(url, { method: \"GET\", headers });\n Promise.resolve(entry.handler(fetchRequest))\n .then(async (response) => {\n res.status(response.status);\n response.headers.forEach((value, key) => {\n res.setHeader(key, value);\n });\n if (response.body === null) {\n res.send(await response.text());\n return;\n }\n // Stream the body to the socket instead of awaiting .text(): a\n // stream-backed body (e.g. graphql-sse) only closes when the\n // subscription completes, so awaiting would hang the request.\n // `response.body` is typed against the global (lib) ReadableStream\n // declaration, while Readable.fromWeb wants node:stream/web's; at\n // runtime they are the same stream, so the cast is safe.\n const bodyStream = response.body as WebReadableStream;\n const nodeStream = Readable.fromWeb(bodyStream);\n req.on(\"close\", () => {\n // The client went away mid-stream; stop pulling from the source.\n nodeStream.destroy();\n });\n nodeStream.on(\"error\", (err) => {\n if (res.headersSent) {\n // The response has already started; nothing left to say.\n res.destroy();\n } else {\n res.status(500).send(String(err));\n }\n });\n nodeStream.pipe(res);\n })\n .catch((err: unknown) => {\n res.status(500).send(String(err));\n });\n }\n}\n\nexport function createExpressHttpAdapter(existingApp?: Express): {\n adapter: IHttpAdapter;\n} {\n return { adapter: new ExpressHttpAdapter(existingApp) };\n}\n"],"names":["fs"],"mappings":"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","debug_id":"b10aa351-8ded-5463-91b0-6cfb882abce2"}