bhooai-nexus 0.1.2

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 (219) hide show
  1. package/README.md +184 -0
  2. package/apps/admin/index.html +12 -0
  3. package/apps/admin/package.json +25 -0
  4. package/apps/admin/postcss.config.js +6 -0
  5. package/apps/admin/public/anime-girl.svg +84 -0
  6. package/apps/admin/public/bhooai-nexus-logo.png +0 -0
  7. package/apps/admin/public/bhooai-nexus-logo.svg +135 -0
  8. package/apps/admin/public/favicon.ico +0 -0
  9. package/apps/admin/src/main.tsx +10 -0
  10. package/apps/admin/src/vite-env.d.ts +18 -0
  11. package/apps/admin/tailwind.config.js +10 -0
  12. package/apps/admin/tsconfig.json +17 -0
  13. package/apps/admin/vite.config.ts +68 -0
  14. package/bin/nexus.js +52 -0
  15. package/package.json +108 -0
  16. package/packages/nexus-admin/package.json +32 -0
  17. package/packages/nexus-admin/src/App.tsx +4878 -0
  18. package/packages/nexus-admin/src/alertCenter.tsx +150 -0
  19. package/packages/nexus-admin/src/api.ts +601 -0
  20. package/packages/nexus-admin/src/assets/bhooai-nexus-logo.svg +25 -0
  21. package/packages/nexus-admin/src/index.css +3635 -0
  22. package/packages/nexus-admin/src/vite-env.d.ts +19 -0
  23. package/packages/nexus-ads/package.json +20 -0
  24. package/packages/nexus-ads/src/GaqlBuilder.ts +72 -0
  25. package/packages/nexus-ads/src/GoogleAdsClient.ts +121 -0
  26. package/packages/nexus-ads/src/fetchTransport.ts +10 -0
  27. package/packages/nexus-ads/src/index.ts +20 -0
  28. package/packages/nexus-ads/src/types.ts +41 -0
  29. package/packages/nexus-ai-client/package.json +18 -0
  30. package/packages/nexus-ai-client/src/client.ts +159 -0
  31. package/packages/nexus-ai-client/src/errors.ts +21 -0
  32. package/packages/nexus-ai-client/src/index.ts +4 -0
  33. package/packages/nexus-ai-client/src/sse.ts +53 -0
  34. package/packages/nexus-ai-client/src/types.ts +174 -0
  35. package/packages/nexus-auth/package.json +22 -0
  36. package/packages/nexus-auth/src/auth.ts +116 -0
  37. package/packages/nexus-auth/src/bcryptjs.d.ts +10 -0
  38. package/packages/nexus-auth/src/cors.ts +91 -0
  39. package/packages/nexus-auth/src/csrf.ts +158 -0
  40. package/packages/nexus-auth/src/headers.ts +55 -0
  41. package/packages/nexus-auth/src/index.ts +11 -0
  42. package/packages/nexus-auth/src/jwt.ts +65 -0
  43. package/packages/nexus-auth/src/middleware.ts +94 -0
  44. package/packages/nexus-auth/src/oauth.ts +199 -0
  45. package/packages/nexus-auth/src/password.ts +33 -0
  46. package/packages/nexus-auth/src/rateLimit.ts +59 -0
  47. package/packages/nexus-auth/src/rbac.ts +94 -0
  48. package/packages/nexus-auth/src/session.ts +91 -0
  49. package/packages/nexus-cache/package.json +21 -0
  50. package/packages/nexus-cache/src/Cache.ts +155 -0
  51. package/packages/nexus-cache/src/PubSub.ts +98 -0
  52. package/packages/nexus-cache/src/RateLimiter.ts +43 -0
  53. package/packages/nexus-cache/src/index.ts +9 -0
  54. package/packages/nexus-cache/src/types.ts +47 -0
  55. package/packages/nexus-cli/package.json +25 -0
  56. package/packages/nexus-cli/src/commands/cluster.ts +133 -0
  57. package/packages/nexus-cli/src/commands/dev.ts +200 -0
  58. package/packages/nexus-cli/src/commands/doctor.ts +199 -0
  59. package/packages/nexus-cli/src/commands/init.ts +1009 -0
  60. package/packages/nexus-cli/src/commands/node.ts +106 -0
  61. package/packages/nexus-cli/src/commands/pysetup.ts +142 -0
  62. package/packages/nexus-cli/src/commands/sync.ts +116 -0
  63. package/packages/nexus-cli/src/commands/uninstall.ts +287 -0
  64. package/packages/nexus-cli/src/config-sync.ts +384 -0
  65. package/packages/nexus-cli/src/dotenv.ts +39 -0
  66. package/packages/nexus-cli/src/index.ts +94 -0
  67. package/packages/nexus-cli/src/supervisor.ts +394 -0
  68. package/packages/nexus-cli/src/util.ts +132 -0
  69. package/packages/nexus-cli/src/wizard.ts +149 -0
  70. package/packages/nexus-cli/templates/Dockerfile +60 -0
  71. package/packages/nexus-cli/templates/README.md +69 -0
  72. package/packages/nexus-cli/templates/apps/admin/index.html +12 -0
  73. package/packages/nexus-cli/templates/apps/admin/package.json +24 -0
  74. package/packages/nexus-cli/templates/apps/admin/postcss.config.js +6 -0
  75. package/packages/nexus-cli/templates/apps/admin/src/main.tsx +10 -0
  76. package/packages/nexus-cli/templates/apps/admin/src/vite-env.d.ts +18 -0
  77. package/packages/nexus-cli/templates/apps/admin/tailwind.config.js +9 -0
  78. package/packages/nexus-cli/templates/apps/admin/tsconfig.json +17 -0
  79. package/packages/nexus-cli/templates/apps/admin/vite.config.ts +64 -0
  80. package/packages/nexus-cli/templates/apps/ai-server/main.py +43 -0
  81. package/packages/nexus-cli/templates/apps/ai-server/providers/__init__.py +3 -0
  82. package/packages/nexus-cli/templates/apps/ai-server/providers/base.py +111 -0
  83. package/packages/nexus-cli/templates/apps/ai-server/requirements.txt +3 -0
  84. package/packages/nexus-cli/templates/apps/ai-server/routers/__init__.py +3 -0
  85. package/packages/nexus-cli/templates/apps/ai-server/routers/chat.py +47 -0
  86. package/packages/nexus-cli/templates/apps/ai-server/routers/embeddings.py +30 -0
  87. package/packages/nexus-cli/templates/apps/ai-server/routers/lint.py +167 -0
  88. package/packages/nexus-cli/templates/apps/ai-server/routers/models.py +23 -0
  89. package/packages/nexus-cli/templates/apps/ai-server/routers/preflight.py +169 -0
  90. package/packages/nexus-cli/templates/apps/ai-server/settings.py +48 -0
  91. package/packages/nexus-cli/templates/apps/backend/package.json +34 -0
  92. package/packages/nexus-cli/templates/apps/backend/src/main.ts +375 -0
  93. package/packages/nexus-cli/templates/apps/backend/src/modules/admin/adminRoutes.ts +732 -0
  94. package/packages/nexus-cli/templates/apps/backend/src/modules/admin/clusterRoutes.ts +391 -0
  95. package/packages/nexus-cli/templates/apps/backend/src/modules/admin/databaseRoutes.ts +161 -0
  96. package/packages/nexus-cli/templates/apps/backend/src/modules/admin/lintProxy.ts +89 -0
  97. package/packages/nexus-cli/templates/apps/backend/src/modules/admin/preflightProxy.ts +242 -0
  98. package/packages/nexus-cli/templates/apps/backend/src/modules/admin/roleCatalog.ts +78 -0
  99. package/packages/nexus-cli/templates/apps/backend/src/modules/admin/schemaRoutes.ts +449 -0
  100. package/packages/nexus-cli/templates/apps/backend/src/modules/ai/aiProxy.ts +265 -0
  101. package/packages/nexus-cli/templates/apps/backend/src/modules/auth/authRoutes.ts +220 -0
  102. package/packages/nexus-cli/templates/apps/backend/src/modules/payments/paymentRoutes.ts +100 -0
  103. package/packages/nexus-cli/templates/apps/backend/src/modules/payments/paymentStore.ts +172 -0
  104. package/packages/nexus-cli/templates/apps/backend/src/modules/requests/requestLog.ts +175 -0
  105. package/packages/nexus-cli/templates/apps/backend/src/modules/users/userGraph.ts +83 -0
  106. package/packages/nexus-cli/templates/apps/backend/src/modules/users/userModel.ts +88 -0
  107. package/packages/nexus-cli/templates/apps/backend/src/plugins/CronScheduler.ts +69 -0
  108. package/packages/nexus-cli/templates/apps/backend/src/plugins/loadPlugins.ts +107 -0
  109. package/packages/nexus-cli/templates/apps/backend/tsconfig.json +14 -0
  110. package/packages/nexus-cli/templates/apps/frontend/index.html +12 -0
  111. package/packages/nexus-cli/templates/apps/frontend/package.json +19 -0
  112. package/packages/nexus-cli/templates/apps/frontend/src/main.tsx +64 -0
  113. package/packages/nexus-cli/templates/apps/frontend/vite.config.ts +72 -0
  114. package/packages/nexus-cli/templates/bin/nexus.js +35 -0
  115. package/packages/nexus-cli/templates/bin/serve-all.mjs +45 -0
  116. package/packages/nexus-cli/templates/dockerignore +15 -0
  117. package/packages/nexus-cli/templates/gitignore +12 -0
  118. package/packages/nexus-cli/templates/nexus.config.ts +69 -0
  119. package/packages/nexus-cli/templates/package.json +47 -0
  120. package/packages/nexus-cli/templates/tsconfig.json +17 -0
  121. package/packages/nexus-cli/templates/uploads/.gitkeep +0 -0
  122. package/packages/nexus-core/package.json +38 -0
  123. package/packages/nexus-core/src/config/ConfigLoader.ts +161 -0
  124. package/packages/nexus-core/src/config/defaults.ts +155 -0
  125. package/packages/nexus-core/src/config/env.ts +113 -0
  126. package/packages/nexus-core/src/config/index.ts +6 -0
  127. package/packages/nexus-core/src/config/merge.ts +28 -0
  128. package/packages/nexus-core/src/config/schema.ts +184 -0
  129. package/packages/nexus-core/src/config/types.ts +352 -0
  130. package/packages/nexus-core/src/di/Container.ts +98 -0
  131. package/packages/nexus-core/src/di/index.ts +1 -0
  132. package/packages/nexus-core/src/errors.ts +62 -0
  133. package/packages/nexus-core/src/http/Router.ts +149 -0
  134. package/packages/nexus-core/src/http/Server.ts +145 -0
  135. package/packages/nexus-core/src/http/bodyParser.ts +129 -0
  136. package/packages/nexus-core/src/http/context.ts +112 -0
  137. package/packages/nexus-core/src/http/index.ts +6 -0
  138. package/packages/nexus-core/src/http/static.ts +85 -0
  139. package/packages/nexus-core/src/http/uploads.ts +94 -0
  140. package/packages/nexus-core/src/index.ts +4 -0
  141. package/packages/nexus-crypto/package.json +18 -0
  142. package/packages/nexus-crypto/src/csr.ts +165 -0
  143. package/packages/nexus-crypto/src/der.ts +262 -0
  144. package/packages/nexus-crypto/src/https.ts +36 -0
  145. package/packages/nexus-crypto/src/index.ts +5 -0
  146. package/packages/nexus-crypto/src/keypair.ts +59 -0
  147. package/packages/nexus-crypto/src/x509.ts +156 -0
  148. package/packages/nexus-data/package.json +27 -0
  149. package/packages/nexus-data/src/connection/Connection.ts +57 -0
  150. package/packages/nexus-data/src/connection/ConnectionManager.ts +37 -0
  151. package/packages/nexus-data/src/errors.ts +17 -0
  152. package/packages/nexus-data/src/index.ts +66 -0
  153. package/packages/nexus-data/src/model/Document.ts +126 -0
  154. package/packages/nexus-data/src/model/Model.ts +189 -0
  155. package/packages/nexus-data/src/model/hydrate.ts +12 -0
  156. package/packages/nexus-data/src/populate/populate.ts +114 -0
  157. package/packages/nexus-data/src/projects.ts +185 -0
  158. package/packages/nexus-data/src/query/Query.ts +158 -0
  159. package/packages/nexus-data/src/schema/Schema.ts +173 -0
  160. package/packages/nexus-data/src/schema/SchemaType.ts +80 -0
  161. package/packages/nexus-data/src/schema/validators.ts +88 -0
  162. package/packages/nexus-email/package.json +22 -0
  163. package/packages/nexus-email/src/EmailService.ts +76 -0
  164. package/packages/nexus-email/src/TemplateEngine.ts +62 -0
  165. package/packages/nexus-email/src/index.ts +37 -0
  166. package/packages/nexus-email/src/providers.ts +63 -0
  167. package/packages/nexus-email/src/queue.ts +103 -0
  168. package/packages/nexus-email/src/types.ts +49 -0
  169. package/packages/nexus-graphql/package.json +24 -0
  170. package/packages/nexus-graphql/src/federation/composeSupergraph.ts +153 -0
  171. package/packages/nexus-graphql/src/federation/createFederatedGateway.ts +36 -0
  172. package/packages/nexus-graphql/src/federation/executor.ts +305 -0
  173. package/packages/nexus-graphql/src/federation/parseMetadata.ts +87 -0
  174. package/packages/nexus-graphql/src/gateway/createGateway.ts +77 -0
  175. package/packages/nexus-graphql/src/gateway/fieldResolver.ts +45 -0
  176. package/packages/nexus-graphql/src/gateway/graphqlHttpHandler.ts +90 -0
  177. package/packages/nexus-graphql/src/gateway/publicSchema.ts +26 -0
  178. package/packages/nexus-graphql/src/index.ts +14 -0
  179. package/packages/nexus-graphql/src/subgraph/defineSubgraph.ts +115 -0
  180. package/packages/nexus-graphql/src/subgraph/federationDirectives.ts +47 -0
  181. package/packages/nexus-graphql/src/subgraph/parseKeys.ts +25 -0
  182. package/packages/nexus-graphql/src/subscriptions/PubSub.ts +64 -0
  183. package/packages/nexus-graphql/src/subscriptions/SubscriptionServer.ts +203 -0
  184. package/packages/nexus-graphql/src/types.ts +77 -0
  185. package/packages/nexus-payments/package.json +20 -0
  186. package/packages/nexus-payments/src/errors.ts +15 -0
  187. package/packages/nexus-payments/src/http.ts +53 -0
  188. package/packages/nexus-payments/src/index.ts +106 -0
  189. package/packages/nexus-payments/src/providers/PayPalProvider.ts +192 -0
  190. package/packages/nexus-payments/src/providers/PayUProvider.ts +164 -0
  191. package/packages/nexus-payments/src/providers/PayoneerProvider.ts +122 -0
  192. package/packages/nexus-payments/src/providers/RazorpayProvider.ts +184 -0
  193. package/packages/nexus-payments/src/providers/SkrillProvider.ts +117 -0
  194. package/packages/nexus-payments/src/signature.ts +24 -0
  195. package/packages/nexus-payments/src/types.ts +150 -0
  196. package/packages/nexus-payments/src/webhooks.ts +58 -0
  197. package/packages/nexus-plugins/package.json +20 -0
  198. package/packages/nexus-plugins/src/HookBus.ts +42 -0
  199. package/packages/nexus-plugins/src/admin/adminExtensions.ts +53 -0
  200. package/packages/nexus-plugins/src/host.ts +105 -0
  201. package/packages/nexus-plugins/src/index.ts +8 -0
  202. package/packages/nexus-plugins/src/manifest.ts +73 -0
  203. package/packages/nexus-plugins/src/registry.ts +123 -0
  204. package/packages/nexus-plugins/src/runtime/TrustedPlugin.ts +134 -0
  205. package/packages/nexus-plugins/src/sandbox/SandboxedPlugin.ts +279 -0
  206. package/packages/nexus-plugins/src/sandbox/capabilityPolicy.ts +68 -0
  207. package/packages/nexus-plugins/src/sandbox/workerBootstrap.mjs +211 -0
  208. package/packages/nexus-realtime/package.json +26 -0
  209. package/packages/nexus-realtime/src/adapter/PubSubAdapter.ts +42 -0
  210. package/packages/nexus-realtime/src/adapter/RedisPubSubAdapter.ts +59 -0
  211. package/packages/nexus-realtime/src/index.ts +5 -0
  212. package/packages/nexus-realtime/src/mediasoup/MediasoupAdapter.ts +176 -0
  213. package/packages/nexus-realtime/src/server/RealtimeServer.ts +252 -0
  214. package/packages/nexus-realtime/src/types.ts +52 -0
  215. package/packages/nexus-telemetry/package.json +20 -0
  216. package/packages/nexus-telemetry/src/index.ts +3 -0
  217. package/packages/nexus-telemetry/src/logger/Logger.ts +178 -0
  218. package/packages/nexus-telemetry/src/metrics/Metrics.ts +123 -0
  219. package/packages/nexus-telemetry/src/trace.ts +28 -0
@@ -0,0 +1,305 @@
1
+ import { execute, parse, isObjectType, isInterfaceType, type DocumentNode, type SelectionSetNode, type FieldNode, type InlineFragmentNode, type FragmentSpreadNode, type ExecutionResult } from 'graphql';
2
+ import type { Supergraph } from './composeSupergraph.js';
3
+ import type { Subgraph, GraphQLContext } from '../types.js';
4
+ import { createFieldResolver } from '../gateway/fieldResolver.js';
5
+
6
+ /**
7
+ * Naive sequential federated executor (Phase 6, v1).
8
+ *
9
+ * Algorithm:
10
+ * 1. Root pass — group the operation's top-level fields by their owning
11
+ * subgraph; for each group, execute a trimmed subquery against that
12
+ * subgraph in-process. Trim keeps only fields owned by that subgraph,
13
+ * plus `__typename` and entity key fields (so later passes can join).
14
+ * 2. Entity-join passes — scan the stitched result for entity-typed objects
15
+ * whose requested fields are owned by *other* subgraphs; for each such
16
+ * (subgraph, type) pair, call that subgraph's `_entities` with
17
+ * representations built from the parents' keys and a trimmed subquery,
18
+ * then merge the returned fields back by key. Repeat until no missing
19
+ * fields remain (handles nested joins, one level per pass).
20
+ *
21
+ * Limitations (documented): sequential (no parallel fetch fan-out), `@requires`
22
+ * supported as "fetch the required external fields first, then resolve", no
23
+ * `@shareable` arbitration, no `@override`. Composition is ours; execution is
24
+ * in-process (shared nothing is Phase 6-distributed, designed not built).
25
+ */
26
+
27
+ export interface FetchNode {
28
+ kind: 'root' | 'entities';
29
+ subgraph: string;
30
+ /** SDL selection set this fetch executes. */
31
+ selection: string;
32
+ /** For entity fetches: the entity type name being resolved. */
33
+ typeName?: string;
34
+ /** For entity fetches: key fields used to build representations. */
35
+ keyFields?: string[];
36
+ }
37
+ export interface FetchPlan {
38
+ nodes: FetchNode[];
39
+ }
40
+
41
+ /** Build a FetchPlan description for inspection/golden tests. */
42
+ export function planQuery(supergraph: Supergraph, document: DocumentNode): FetchPlan {
43
+ const nodes: FetchNode[] = [];
44
+ const op = document.definitions.find((d) => d.kind === 'OperationDefinition') as
45
+ | { selectionSet: SelectionSetNode }
46
+ | undefined;
47
+ if (!op) return { nodes };
48
+ const rootType = 'Query';
49
+ const bySub = new Map<string, string[]>();
50
+ for (const sel of op.selectionSet.selections) {
51
+ if (sel.kind === 'Field') {
52
+ const owner = supergraph.ownership.get(rootType)?.get((sel as FieldNode).name.value);
53
+ if (owner) bySub.set(owner, [...(bySub.get(owner) ?? []), (sel as FieldNode).name.value]);
54
+ }
55
+ }
56
+ for (const [sub, fields] of bySub) {
57
+ nodes.push({ kind: 'root', subgraph: sub, selection: `{ ${fields.join(' ') } }` });
58
+ }
59
+ return { nodes };
60
+ }
61
+
62
+ /** Execute a federated query in-process against the composed subgraphs. */
63
+ export async function executeFederated(
64
+ supergraph: Supergraph,
65
+ document: DocumentNode,
66
+ variableValues: Record<string, any> | undefined,
67
+ contextValue: GraphQLContext,
68
+ ): Promise<ExecutionResult> {
69
+ const op = document.definitions.find((d) => d.kind === 'OperationDefinition') as
70
+ | { selectionSet: SelectionSetNode; operation: string }
71
+ | undefined;
72
+ if (!op) return { errors: [{ message: 'No operation in document' }] as unknown as NonNullable<ExecutionResult['errors']> };
73
+ const rootType = op.operation === 'mutation' ? 'Mutation' : op.operation === 'subscription' ? 'Subscription' : 'Query';
74
+
75
+ const subgraphByName = new Map<string, Subgraph>(supergraph.subgraphs.map((s) => [s.name, s]));
76
+
77
+ // 1. Root pass: group top-level fields by owner and execute trimmed subqueries.
78
+ const rootGroups = new Map<string, FieldNode[]>();
79
+ for (const sel of op.selectionSet.selections) {
80
+ if (sel.kind !== 'Field') continue; // v1: no fragment spreads at root
81
+ const owner = supergraph.ownership.get(rootType)?.get(sel.name.value);
82
+ if (!owner) return { errors: [{ message: `No subgraph owns ${rootType}.${sel.name.value}` }] as unknown as NonNullable<ExecutionResult['errors']> };
83
+ const arr = rootGroups.get(owner) ?? [];
84
+ arr.push(sel);
85
+ rootGroups.set(owner, arr);
86
+ }
87
+
88
+ const data: Record<string, unknown> = {};
89
+ for (const [subName, fields] of rootGroups) {
90
+ const sub = subgraphByName.get(subName)!;
91
+ const sel = trimSelection(fields, rootType, subName, supergraph, true);
92
+ const sdl = `${op.operation} { ${sel} }`;
93
+ const res = await execSubgraph(sub, parse(sdl), variableValues, contextValue);
94
+ if (res.errors) return { errors: res.errors };
95
+ Object.assign(data, res.data as Record<string, unknown>);
96
+ }
97
+
98
+ // 2. Iterative entity-join passes.
99
+ for (let pass = 0; pass < 8; pass++) {
100
+ const pending = collectMissing(supergraph, op.selectionSet, rootType, data);
101
+ if (pending.length === 0) break;
102
+ for (const job of pending) {
103
+ const sub = subgraphByName.get(job.subgraph)!;
104
+ const reps = job.parents.map((p) => pickKeys(p, job.keyFields));
105
+ const sel = trimSelection(job.fieldNodes, job.typeName, job.subgraph, supergraph, true);
106
+ const sdl = `query($reps: [_Any!]!){ _entities(representations: $reps){ ... on ${job.typeName} { ${sel} } } }`;
107
+ const res = await execSubgraph(sub, parse(sdl), { ...variableValues, reps }, contextValue);
108
+ if (res.errors) return { errors: res.errors };
109
+ const entities = (res.data as Record<string, unknown> | undefined)?._entities as any[] | undefined;
110
+ if (!entities) continue;
111
+ mergeEntities(job.parents, entities, job.keyFields, job.typeName, job.missingFields);
112
+ }
113
+ }
114
+
115
+ return { data };
116
+ }
117
+
118
+ /** Run a document against a subgraph's federation schema + resolvers in-process. */
119
+ async function execSubgraph(sub: Subgraph, document: DocumentNode, variableValues: Record<string, any> | undefined, contextValue: GraphQLContext): Promise<ExecutionResult> {
120
+ return execute({
121
+ schema: sub.schema,
122
+ document,
123
+ rootValue: undefined,
124
+ contextValue,
125
+ variableValues,
126
+ fieldResolver: createFieldResolver(sub.resolvers),
127
+ });
128
+ }
129
+
130
+ /** Unwrap a GraphQL type name to its base named type. */
131
+ function baseType(type: string): string {
132
+ return type.replace(/[\[\]!]/g, '');
133
+ }
134
+
135
+ /** Output SDL type of a field on a type, from the supergraph (merged) schema. */
136
+ function fieldType(supergraph: Supergraph, parentType: string, fieldName: string): string | undefined {
137
+ const t = supergraph.schema.getType(parentType);
138
+ if (isObjectType(t)) return t.getFields()[fieldName]?.type.toString();
139
+ if (isInterfaceType(t)) return t.getFields()[fieldName]?.type.toString();
140
+ return undefined;
141
+ }
142
+
143
+ /**
144
+ * Trim a list of selections (for one parent type) to fields owned by `subgraphName`,
145
+ * preserving field arguments, plus `__typename`. For entity-typed parents, the
146
+ * entity's @key fields owned by `subgraphName` are force-included so downstream
147
+ * join passes can build representations. Fields owned by other subgraphs are
148
+ * omitted here (a later entity-join pass fills them). Returns an SDL selection-set.
149
+ */
150
+ function trimSelection(selections: readonly (FieldNode | InlineFragmentNode | FragmentSpreadNode)[], parentType: string, subgraphName: string, supergraph: Supergraph, _includeKeys: boolean): string {
151
+ const parts: string[] = [];
152
+ const included = new Set<string>();
153
+ for (const sel of selections) {
154
+ if (sel.kind === 'Field') {
155
+ const name = sel.name.value;
156
+ if (name === '__typename') { parts.push('__typename'); included.add(name); continue; }
157
+ const owner = supergraph.ownership.get(parentType)?.get(name);
158
+ const ft = fieldType(supergraph, parentType, name);
159
+ const childType = ft ? baseType(ft) : undefined;
160
+ if (owner === subgraphName) {
161
+ const sub = sel.selectionSet ? trimSelection(sel.selectionSet.selections, childType!, subgraphName, supergraph, true) : '';
162
+ const args = argsToSdl(sel.arguments);
163
+ parts.push(sub ? `${name}${args} { ${sub} }` : `${name}${args}`);
164
+ included.add(name);
165
+ }
166
+ // Fields owned by other subgraphs are omitted here; an entity-join pass fills them.
167
+ } else if (sel.kind === 'InlineFragment') {
168
+ const fragType = sel.typeCondition?.name.value ?? parentType;
169
+ const sub = trimSelection(sel.selectionSet.selections, fragType, subgraphName, supergraph, _includeKeys);
170
+ parts.push(`... on ${fragType} { ${sub} }`);
171
+ }
172
+ // FragmentSpread: v1 ignores (rare in generated clients)
173
+ }
174
+ // Force-include this entity's key fields (owned by this subgraph) so join passes
175
+ // can build representations even when the client didn't request them.
176
+ if (supergraph.entities.has(parentType)) {
177
+ const src = (supergraph.entities.get(parentType) ?? []).find((s) => s.subgraph === subgraphName);
178
+ if (src) {
179
+ for (const kf of src.keyFields) {
180
+ if (supergraph.ownership.get(parentType)?.get(kf) === subgraphName && !included.has(kf)) {
181
+ parts.push(kf);
182
+ included.add(kf);
183
+ }
184
+ }
185
+ }
186
+ }
187
+ return parts.join(' ');
188
+ }
189
+
190
+ /** Serialize a field's arguments to SDL, e.g. `(id: "u1", limit: $limit)`. */
191
+ function argsToSdl(args: readonly import('graphql').ArgumentNode[] | undefined): string {
192
+ if (!args || args.length === 0) return '';
193
+ return '(' + args.map((a) => `${a.name.value}: ${valueToSdl(a.value)}`).join(', ') + ')';
194
+ }
195
+ function valueToSdl(v: import('graphql').ValueNode): string {
196
+ switch (v.kind) {
197
+ case 'IntValue': case 'FloatValue': return v.value;
198
+ case 'StringValue': return JSON.stringify(v.value);
199
+ case 'BooleanValue': return String(v.value);
200
+ case 'EnumValue': return v.value;
201
+ case 'NullValue': return 'null';
202
+ case 'Variable': return '$' + v.name.value;
203
+ case 'ListValue': return '[' + v.values.map(valueToSdl).join(', ') + ']';
204
+ case 'ObjectValue': return '{' + v.fields.map((f) => `${f.name.value}: ${valueToSdl(f.value)}`).join(', ') + '}';
205
+ default: return '';
206
+ }
207
+ }
208
+
209
+ function pickKeys(obj: Record<string, unknown>, keys: string[]): Record<string, unknown> {
210
+ const out: Record<string, unknown> = { __typename: obj.__typename };
211
+ for (const k of keys) if (k in obj) out[k] = obj[k];
212
+ return out;
213
+ }
214
+
215
+ interface JoinJob {
216
+ subgraph: string;
217
+ typeName: string;
218
+ keyFields: string[];
219
+ parents: Record<string, unknown>[];
220
+ missingFields: string[];
221
+ fieldNodes: (FieldNode | InlineFragmentNode | FragmentSpreadNode)[];
222
+ }
223
+
224
+ /**
225
+ * Walk the stitched `data` against the query selection set; for each entity-typed
226
+ * object, find fields the query wants that are owned by a *different* subgraph
227
+ * than the one that produced the object, and emit a JoinJob to fetch them.
228
+ */
229
+ function collectMissing(supergraph: Supergraph, selectionSet: SelectionSetNode, parentType: string, data: Record<string, unknown> | unknown[]): JoinJob[] {
230
+ const jobs: JoinJob[] = [];
231
+ walk(supergraph, selectionSet, parentType, data, jobs, new Set());
232
+ return jobs;
233
+ }
234
+
235
+ function walk(supergraph: Supergraph, selectionSet: SelectionSetNode, parentType: string, data: unknown, jobs: JoinJob[], seen: Set<Record<string, unknown>>): void {
236
+ if (data == null) return;
237
+ if (Array.isArray(data)) { for (const item of data) walk(supergraph, selectionSet, parentType, item, jobs, seen); return; }
238
+ if (typeof data !== 'object') return;
239
+ const obj = data as Record<string, unknown>;
240
+
241
+ // Group requested fields by their owning subgraph; identify fields owned by a
242
+ // subgraph other than the one that produced this object (inferred from the
243
+ // fields already present). For each foreign owner, build a job.
244
+ const requestedByOwner = new Map<string, FieldNode[]>();
245
+ for (const sel of selectionSet.selections) {
246
+ if (sel.kind !== 'Field') continue;
247
+ const name = sel.name.value;
248
+ if (name === '__typename') continue;
249
+ const owner = supergraph.ownership.get(parentType)?.get(name);
250
+ if (!owner) continue;
251
+ if (!(name in obj)) { // missing → needs fetching from `owner`
252
+ const arr = requestedByOwner.get(owner) ?? [];
253
+ arr.push(sel);
254
+ requestedByOwner.set(owner, arr);
255
+ } else if (sel.selectionSet) {
256
+ // present → recurse into children for nested joins
257
+ const ft = fieldType(supergraph, parentType, name);
258
+ const childType = ft ? baseType(ft) : undefined;
259
+ if (childType) walk(supergraph, sel.selectionSet, childType, obj[name], jobs, seen);
260
+ }
261
+ }
262
+
263
+ if (requestedByOwner.size === 0) return;
264
+ if (seen.has(obj)) return;
265
+ seen.add(obj);
266
+
267
+ const entitySources = supergraph.entities.get(parentType) ?? [];
268
+ if (entitySources.length === 0) return; // can't join a non-entity
269
+
270
+ for (const [owner, fieldNodes] of requestedByOwner) {
271
+ // Pick a key for this owner: an entity source whose subgraph == owner, else first.
272
+ const source = entitySources.find((s) => s.subgraph === owner) ?? entitySources[0]!;
273
+ const keyFields = source.keyFields;
274
+ // Only emit if we actually have the key fields present on the object.
275
+ if (!keyFields.every((k) => k in obj)) continue;
276
+ jobs.push({
277
+ subgraph: owner,
278
+ typeName: parentType,
279
+ keyFields,
280
+ parents: [obj],
281
+ missingFields: fieldNodes.map((f) => f.name.value),
282
+ fieldNodes,
283
+ });
284
+ }
285
+ }
286
+
287
+ /**
288
+ * Merge fetched entity fields back into the parent objects. `_entities` returns
289
+ * one resolved entity per representation, in order; `reps` were built from
290
+ * `parents` in order, so `entities[i]` corresponds to `parents[i]`. We merge by
291
+ * index (not by key tuple) because the fetched entity may not carry its `@key`
292
+ * fields — they may be `@external` on the resolving subgraph and absent from the
293
+ * trimmed selection. Null entries (entity resolver returned null) are skipped.
294
+ */
295
+ function mergeEntities(parents: Record<string, unknown>[], entities: any[], _keyFields: string[], typeName: string, missingFields: string[]): void {
296
+ for (let i = 0; i < parents.length; i++) {
297
+ const e = entities[i];
298
+ const p = parents[i]!;
299
+ if (!e || typeof e !== 'object') continue;
300
+ for (const f of missingFields) {
301
+ if (f in e) p[f] = e[f];
302
+ }
303
+ if (!p.__typename) p.__typename = typeName;
304
+ }
305
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Parse federation metadata from subgraph SDL: per type, its `@key` sets,
3
+ * whether it is an `@extends` extension, and per field whether it is
4
+ * `@external`, `@provides(fields)`, or `@requires(fields)`. Uses brace matching
5
+ * (not a full AST) — sufficient for the v1 federation subset and the kind of
6
+ * type blocks we generate/accept.
7
+ */
8
+ export interface FieldMeta {
9
+ /** Field is declared `@external` (resolved by another subgraph). */
10
+ external: boolean;
11
+ /** `@provides(fields: "...")` — this subgraph provides this field on an entity. */
12
+ provides?: string[];
13
+ /** `@requires(fields: "...")` — this field is computed from external fields. */
14
+ requires?: string[];
15
+ }
16
+ export interface TypeMeta {
17
+ isExtend: boolean;
18
+ keys: string[][];
19
+ fields: Map<string, FieldMeta>;
20
+ }
21
+
22
+ export function parseFederationMetadata(sdl: string): Map<string, TypeMeta> {
23
+ const types = new Map<string, TypeMeta>();
24
+ // Find `type|interface Name <header> {` and capture the balanced body.
25
+ const headerRe = /(?:extend\s+)?(?:type|interface)\s+(\w+)([^{]*)\{/g;
26
+ let m: RegExpExecArray | null;
27
+ while ((m = headerRe.exec(sdl)) !== null) {
28
+ const name = m[1]!;
29
+ const header = m[2]!;
30
+ const bodyStart = m.index + m[0].length;
31
+ const body = balancedBody(sdl, bodyStart);
32
+ headerRe.lastIndex = bodyStart + body.length + 1; // skip past closing brace
33
+
34
+ const isExtend = /\bextends\b/.test(header) || /@extends\b/.test(header);
35
+ const keys: string[][] = [];
36
+ const keyRe = /@key\s*\(\s*fields:\s*"([^"]+)"\s*\)/g;
37
+ let k: RegExpExecArray | null;
38
+ while ((k = keyRe.exec(header)) !== null) keys.push(k[1]!.split(/\s+/).filter(Boolean));
39
+
40
+ const fields = parseFields(body);
41
+ const existing = types.get(name);
42
+ if (existing) {
43
+ existing.keys.push(...keys);
44
+ for (const [fn, fm] of fields) existing.fields.set(fn, fm);
45
+ } else {
46
+ types.set(name, { isExtend, keys, fields });
47
+ }
48
+ }
49
+ return types;
50
+ }
51
+
52
+ /** Extract the balanced `{ ... }` body starting just after an opening brace at `start-1`. */
53
+ function balancedBody(s: string, start: number): string {
54
+ let depth = 1;
55
+ let i = start;
56
+ for (; i < s.length; i++) {
57
+ const c = s[i];
58
+ if (c === '{') depth++;
59
+ else if (c === '}') { depth--; if (depth === 0) break; }
60
+ }
61
+ return s.slice(start, i);
62
+ }
63
+
64
+ /** Parse field definitions in a type body into name → FieldMeta. */
65
+ function parseFields(body: string): Map<string, FieldMeta> {
66
+ const out = new Map<string, FieldMeta>();
67
+ // Each field line roughly: `name(args): Type <directives>` separated by newlines.
68
+ // We scan line-ish fragments split on top-level commas/newlines.
69
+ const lines = body.split('\n').map((l) => l.trim()).filter(Boolean);
70
+ for (const line of lines) {
71
+ // Strip leading modifiers; capture field name as the first identifier.
72
+ const nameMatch = /^(\w+)/.exec(line);
73
+ if (!nameMatch) continue;
74
+ const name = nameMatch[1]!;
75
+ const external = /@external\b/.test(line);
76
+ const provides = matchFields(line, '@provides');
77
+ const requires = matchFields(line, '@requires');
78
+ out.set(name, { external, provides, requires });
79
+ }
80
+ return out;
81
+ }
82
+
83
+ function matchFields(line: string, directive: string): string[] | undefined {
84
+ const re = new RegExp(`${directive}\\s*\\(\\s*fields:\\s*"([^"]+)"\\s*\\)`);
85
+ const m = re.exec(line);
86
+ return m ? m[1]!.split(/\s+/).filter(Boolean) : undefined;
87
+ }
@@ -0,0 +1,77 @@
1
+ import { execute, subscribe, validate, type GraphQLSchema, type ExecutionResult, type DocumentNode } from 'graphql';
2
+ import type { Gateway, Subgraph, Resolvers, GraphQLContext, ExecuteParams } from '../types.js';
3
+ import { createFieldResolver, createSubscribeFieldResolver } from './fieldResolver.js';
4
+ import { buildPublicSchema } from './publicSchema.js';
5
+
6
+ /**
7
+ * Create an in-process gateway over one or more subgraphs.
8
+ *
9
+ * Single-subgraph mode (Phase 5): the gateway exposes the subgraph's public
10
+ * schema and executes operations directly against the subgraph's resolvers —
11
+ * no network hop, shared in-process context (DB pool, services). This is the
12
+ * default app shape; federation overhead only kicks in when there are multiple
13
+ * subgraphs.
14
+ *
15
+ * Multi-subgraph composition + query planning is Phase 6; calling with >1
16
+ * subgraph here throws a clear "not yet" error so the API is forward-compatible.
17
+ */
18
+ export function createGateway(input: { subgraph: Subgraph } | { subgraphs: Subgraph[] }): Gateway {
19
+ const subgraphs: Subgraph[] = 'subgraph' in input ? [input.subgraph] : input.subgraphs;
20
+ if (subgraphs.length === 0) throw new Error('[nexus-graphql] createGateway requires at least one subgraph');
21
+ if (subgraphs.length > 1) {
22
+ throw new Error(
23
+ '[nexus-graphql] Multi-subgraph federation (composition + query planning) is implemented in Phase 6. ' +
24
+ 'Pass a single subgraph here, or use the Phase 6 composeSupergraph/createFederatedGateway.',
25
+ );
26
+ }
27
+
28
+ const only = subgraphs[0]!;
29
+ const resolvers: Resolvers = only.resolvers;
30
+ const schema: GraphQLSchema = buildPublicSchema(only.sdl);
31
+ const fieldResolver = createFieldResolver(resolvers);
32
+ const subscribeFieldResolver = createSubscribeFieldResolver(resolvers);
33
+
34
+ async function run(document: DocumentNode, params: Omit<ExecuteParams, 'schema' | 'resolvers' | 'document'>) {
35
+ const errors = validate(schema, document);
36
+ if (errors.length) return ({ errors: errors.map((e) => ({ message: e.message })) } as unknown) as ExecutionResult;
37
+ return execute({
38
+ schema,
39
+ document,
40
+ rootValue: params.rootValue,
41
+ contextValue: params.contextValue as GraphQLContext,
42
+ variableValues: params.variableValues,
43
+ operationName: params.operationName,
44
+ fieldResolver,
45
+ });
46
+ }
47
+
48
+ return {
49
+ schema,
50
+ subgraphs,
51
+ async execute(params) {
52
+ return run(params.document, params);
53
+ },
54
+ async subscribe(params) {
55
+ const document = params.document;
56
+ const errors = validate(schema, document);
57
+ if (errors.length) {
58
+ return (async function* () { yield { errors: errors.map((e) => ({ message: e.message })) }; })() as AsyncIterable<ExecutionResult>;
59
+ }
60
+ const result = await subscribe({
61
+ schema,
62
+ document,
63
+ rootValue: params.rootValue,
64
+ contextValue: params.contextValue as GraphQLContext,
65
+ variableValues: params.variableValues,
66
+ operationName: params.operationName,
67
+ subscribeFieldResolver,
68
+ fieldResolver,
69
+ });
70
+ // graphql-js returns an AsyncIterable on success or an ExecutionResult (with errors) otherwise.
71
+ if (Symbol.asyncIterator in (result as any)) {
72
+ return result as AsyncIterable<ExecutionResult>;
73
+ }
74
+ return (async function* () { yield result as ExecutionResult; })() as AsyncIterable<ExecutionResult>;
75
+ },
76
+ };
77
+ }
@@ -0,0 +1,45 @@
1
+ import type { GraphQLFieldResolver, GraphQLResolveInfo } from 'graphql';
2
+ import type { Resolvers, GraphQLContext, SubscribeResolver } from '../types.js';
3
+
4
+ /**
5
+ * Build a graphql-js `fieldResolver` that dispatches to the user's resolvers
6
+ * map. Resolution order:
7
+ * 1. `__typename` → the parent's `__typename` (or the field's parent type name).
8
+ * 2. `resolvers[typeName][fieldName]` — if it's a `{ resolve, subscribe }`
9
+ * shape (subscription field), use `.resolve`; otherwise call it directly.
10
+ * 3. Default property access: `parent[fieldName]`.
11
+ */
12
+ export function createFieldResolver(resolvers: Resolvers): GraphQLFieldResolver<any, GraphQLContext> {
13
+ return (parent, args, context, info: GraphQLResolveInfo) => {
14
+ const fieldName = info.fieldName;
15
+ if (fieldName === '__typename') {
16
+ return parent?.__typename ?? info.parentType.name;
17
+ }
18
+ const typeResolvers = resolvers[info.parentType.name];
19
+ if (typeResolvers) {
20
+ const field = typeResolvers[fieldName];
21
+ if (field) {
22
+ if (typeof field === 'function') return field(parent, args, context, info);
23
+ if (typeof field === 'object' && field && typeof field.resolve === 'function') {
24
+ return field.resolve(parent, args, context, info);
25
+ }
26
+ }
27
+ }
28
+ // Default: read the property off the parent (works for DB docs/objects).
29
+ return parent != null ? parent[fieldName] : undefined;
30
+ };
31
+ }
32
+
33
+ /** Build a `subscribeFieldResolver` for subscription root fields. */
34
+ export function createSubscribeFieldResolver(resolvers: Resolvers): GraphQLFieldResolver<any, GraphQLContext> {
35
+ return (parent, args, context, info: GraphQLResolveInfo): AsyncIterable<any> | Promise<AsyncIterable<any>> => {
36
+ const typeResolvers = resolvers[info.parentType.name];
37
+ const field = typeResolvers?.[info.fieldName];
38
+ const subscribe: SubscribeResolver | undefined =
39
+ field && typeof field === 'object' && field ? field.subscribe : undefined;
40
+ if (typeof subscribe !== 'function') {
41
+ throw new Error(`No 'subscribe' resolver for ${info.parentType.name}.${info.fieldName}`);
42
+ }
43
+ return subscribe(parent, args, context, info);
44
+ };
45
+ }
@@ -0,0 +1,90 @@
1
+ import { parse, type DocumentNode } from 'graphql';
2
+ import type { RequestContext, Handler } from '@bhooai/nexus-core';
3
+ import type { Gateway, GraphQLContext } from '../types.js';
4
+
5
+ export interface GraphqlHandlerOptions {
6
+ /** The gateway to execute against. */
7
+ gateway: Gateway;
8
+ /** Build the per-request resolver context. Defaults to `{ request: ctx, user: ctx.state.user }`. */
9
+ context?: (ctx: RequestContext) => GraphQLContext | Promise<GraphQLContext>;
10
+ /** Allow introspection queries (default follows config.graphql.introspection = true). */
11
+ introspection?: boolean;
12
+ }
13
+
14
+ interface GraphQLRequestBody {
15
+ query?: string;
16
+ variables?: Record<string, any>;
17
+ operationName?: string;
18
+ }
19
+
20
+ /** True when a parsed operation set contains an introspection field (`__schema`/`__type`). */
21
+ function isIntrospectionDocument(doc: DocumentNode): boolean {
22
+ for (const def of doc.definitions) {
23
+ if (def.kind === 'OperationDefinition') {
24
+ const sels = def.selectionSet.selections;
25
+ for (const s of sels) {
26
+ if (s.kind === 'Field' && (s.name.value === '__schema' || s.name.value === '__type')) return true;
27
+ }
28
+ }
29
+ }
30
+ return false;
31
+ }
32
+
33
+ /**
34
+ * HTTP handler for `/graphql`. Accepts POST with `{ query, variables, operationName }`
35
+ * (or GET with `?query=`). Applies the gateway in-process. Introspection is
36
+ * rejected when disabled.
37
+ */
38
+ export function graphqlHttpHandler(options: GraphqlHandlerOptions): Handler {
39
+ const { gateway, introspection = true } = options;
40
+ return async (ctx: RequestContext) => {
41
+ let body: GraphQLRequestBody;
42
+ if (ctx.method === 'GET') {
43
+ const q = ctx.query.query;
44
+ body = { query: Array.isArray(q) ? q[0] : q, variables: parseJsonQuery(ctx.query.variables), operationName: single(ctx.query.operationName) };
45
+ } else {
46
+ body = (ctx.body as GraphQLRequestBody) ?? {};
47
+ }
48
+
49
+ if (!body.query) {
50
+ ctx.json({ errors: [{ message: 'Must provide a query string.' }] }, 400);
51
+ return;
52
+ }
53
+
54
+ let document: DocumentNode;
55
+ try {
56
+ document = parse(body.query);
57
+ } catch (err) {
58
+ ctx.json({ errors: [{ message: (err as Error).message }] }, 400);
59
+ return;
60
+ }
61
+
62
+ if (!introspection && isIntrospectionDocument(document)) {
63
+ ctx.json({ errors: [{ message: 'Introspection is disabled.' }] }, 403);
64
+ return;
65
+ }
66
+
67
+ const contextValue = options.context
68
+ ? await options.context(ctx)
69
+ : { request: ctx, user: (ctx.state.user as GraphQLContext['user']) };
70
+
71
+ const result = await gateway.execute({
72
+ document,
73
+ variableValues: body.variables,
74
+ operationName: body.operationName,
75
+ contextValue,
76
+ });
77
+ ctx.json(result);
78
+ };
79
+ }
80
+
81
+ function parseJsonQuery(v: string | string[] | undefined): Record<string, any> | undefined {
82
+ if (v === undefined) return undefined;
83
+ const s = Array.isArray(v) ? v[0] : v;
84
+ if (!s) return undefined;
85
+ try { return JSON.parse(s as string); } catch { return undefined; }
86
+ }
87
+ function single(v: string | string[] | undefined): string | undefined {
88
+ if (v === undefined) return undefined;
89
+ return Array.isArray(v) ? v[0] : v;
90
+ }
@@ -0,0 +1,26 @@
1
+ import { buildSchema, GraphQLSchema } from 'graphql';
2
+
3
+ /**
4
+ * Strip federation directives from subgraph SDL to produce the *public*
5
+ * (client-facing) schema. The gateway exposes this clean schema; the federation
6
+ * internals (`_service`, `_entities`, `@key`, `@external`, ...) are not part of
7
+ * the public API. For the single-subgraph case the public schema is simply the
8
+ * user's types without the federation markers.
9
+ */
10
+ export function buildPublicSchema(subgraphSdl: string): GraphQLSchema {
11
+ const cleaned = subgraphSdl
12
+ // Drop the `extend schema @link(...)` clause and any standalone @link.
13
+ .replace(/extend\s+schema\s*@\s*link\s*\([^)]*\)/g, '')
14
+ .replace(/@\s*link\s*\([^)]*\)/g, '')
15
+ // Drop federation field/type directives.
16
+ .replace(/@\s*key\s*\([^)]*\)/g, '')
17
+ .replace(/@\s*requires\s*\([^)]*\)/g, '')
18
+ .replace(/@\s*provides\s*\([^)]*\)/g, '')
19
+ .replace(/@\s*external\b/g, '')
20
+ .replace(/@\s*extends\b/g, '')
21
+ // Collapse multiple blank lines left behind.
22
+ .replace(/\n{3,}/g, '\n\n')
23
+ .trim();
24
+
25
+ return buildSchema(cleaned);
26
+ }
@@ -0,0 +1,14 @@
1
+ export * from './types.js';
2
+ export * from './subgraph/federationDirectives.js';
3
+ export * from './subgraph/parseKeys.js';
4
+ export * from './subgraph/defineSubgraph.js';
5
+ export * from './gateway/fieldResolver.js';
6
+ export * from './gateway/publicSchema.js';
7
+ export * from './gateway/createGateway.js';
8
+ export * from './gateway/graphqlHttpHandler.js';
9
+ export * from './subscriptions/PubSub.js';
10
+ export * from './subscriptions/SubscriptionServer.js';
11
+ export * from './federation/parseMetadata.js';
12
+ export * from './federation/composeSupergraph.js';
13
+ export * from './federation/executor.js';
14
+ export * from './federation/createFederatedGateway.js';