@powerhousedao/reactor-api 6.2.3-dev.9 → 6.2.3-staging.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) 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-CWqziB1p.mjs} +7 -7
  10. package/dist/adapter-http-express-CWqziB1p.mjs.map +1 -0
  11. package/dist/{adapter-http-fastify-BwXO6rqE.mjs → adapter-http-fastify-CYZQ6FFv.mjs} +10 -9
  12. package/dist/adapter-http-fastify-CYZQ6FFv.mjs.map +1 -0
  13. package/dist/index.d.mts +959 -459
  14. package/dist/index.d.mts.map +1 -1
  15. package/dist/index.mjs +1209 -312
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/{utils-XWVecaNn.mjs → pieces-swupjgIO.mjs} +146 -9
  18. package/dist/pieces-swupjgIO.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 +18 -8
  27. package/dist/src/packages/vite-loader.d.mts.map +1 -1
  28. package/dist/src/packages/vite-loader.mjs +114 -46
  29. package/dist/src/packages/vite-loader.mjs.map +1 -1
  30. package/dist/{types-DcYyNcHJ.d.mts → types-CuSz_zv6.d.mts} +26 -3
  31. package/dist/types-CuSz_zv6.d.mts.map +1 -0
  32. package/dist/{websocket-DncAB9XK.mjs → websocket-_SH5aBcy.mjs} +3 -3
  33. package/dist/{websocket-DncAB9XK.mjs.map → websocket-_SH5aBcy.mjs.map} +1 -1
  34. package/package.json +18 -18
  35. package/dist/adapter-http-express-B39rPhqH.mjs.map +0 -1
  36. package/dist/adapter-http-fastify-BwXO6rqE.mjs.map +0 -1
  37. package/dist/path-normalize-BOQwY9wR.mjs +0 -23
  38. package/dist/path-normalize-BOQwY9wR.mjs.map +0 -1
  39. package/dist/types-DcYyNcHJ.d.mts.map +0 -1
  40. package/dist/utils-XWVecaNn.mjs.map +0 -1
@@ -1,8 +1,9 @@
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]="9da64ff1-d15d-5b85-94b1-f1b0dad67551")}catch(e){}}();
3
- import { a as isSubgraphClass, c as isSubpath, o as debounce, s as extractUpgradeManifests } from "../../utils-XWVecaNn.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]="33a7684d-ff05-56ac-b4f5-910a2adca3e5")}catch(e){}}();
3
+ import { a as pieceListLocation, f as isSubgraphClass, h as isSubpath, i as packageRootOf, m as extractUpgradeManifests, n as PIECES_SUBPATH, p as debounce, s as piecesFromListModule, t as BUILT_PIECE_LIST } from "../../pieces-swupjgIO.mjs";
4
4
  import { childLogger } from "document-model";
5
5
  import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
6
7
  import { viteCommonjs } from "@originjs/vite-plugin-commonjs";
7
8
  import { readPackage } from "read-pkg";
8
9
  import { createLogger, createServer } from "vite";
@@ -17,12 +18,42 @@ function createViteLogger(logger, prefix = "") {
17
18
  var VitePackageLoader = class VitePackageLoader {
18
19
  logger = childLogger(["reactor-api", "vite-loader"]);
19
20
  vite;
21
+ importers;
20
22
  name = "VitePackageLoader";
21
- static build(vite) {
22
- return new VitePackageLoader(vite);
23
+ static build(vite, options) {
24
+ return new VitePackageLoader(vite, options);
23
25
  }
24
- constructor(vite) {
26
+ constructor(vite, options = {}) {
25
27
  this.vite = vite;
28
+ this.importers = [...options.resolveFrom ?? [], import.meta.url].map((from) => from.startsWith("file:") ? fileURLToPath(from) : from);
29
+ }
30
+ async #resolve(identifier, subpath) {
31
+ const aliased = path.isAbsolute(identifier) ? void 0 : this.aliasedRoot(identifier);
32
+ const specifier = path.posix.join(aliased ?? identifier, subpath);
33
+ const importers = !aliased && !path.isAbsolute(identifier) ? [void 0, ...this.importers] : [void 0];
34
+ const container = this.vite.environments.ssr.pluginContainer;
35
+ for (const importer of importers) try {
36
+ const resolved = await container.resolveId(specifier, importer);
37
+ if (resolved && !resolved.external) return resolved.id;
38
+ } catch (e) {
39
+ this.logger.debug("Could not resolve @specifier: @error", specifier, e);
40
+ }
41
+ }
42
+ async #load(identifier, subpath) {
43
+ const id = await this.#resolve(identifier, subpath);
44
+ if (id === void 0) {
45
+ this.logger.debug("No @subpath module in @pkg", subpath, identifier);
46
+ return;
47
+ }
48
+ try {
49
+ return {
50
+ id,
51
+ namespace: await this.vite.ssrLoadModule(id)
52
+ };
53
+ } catch (e) {
54
+ this.logger.error("Failed to load @subpath of @pkg from @id: @error", subpath, identifier, id, e instanceof Error ? e.message : e);
55
+ return;
56
+ }
26
57
  }
27
58
  getDocumentModelsPath(identifier) {
28
59
  return path.posix.join(identifier, "./document-models");
@@ -33,50 +64,56 @@ var VitePackageLoader = class VitePackageLoader {
33
64
  getProcessorsPath(identifier) {
34
65
  return path.posix.join(identifier, "./processors");
35
66
  }
67
+ getPiecesPath(identifier) {
68
+ return path.posix.join(identifier, `./${PIECES_SUBPATH}`);
69
+ }
70
+ aliasedRoot(identifier) {
71
+ const alias = this.vite.config.resolve.alias;
72
+ const hit = (Array.isArray(alias) ? alias : []).find((entry) => entry.find === identifier);
73
+ return typeof hit?.replacement === "string" ? hit.replacement : void 0;
74
+ }
75
+ pieceRoot(identifier, listId) {
76
+ if (!path.isAbsolute(identifier)) {
77
+ const aliased = this.aliasedRoot(identifier);
78
+ if (aliased) return aliased;
79
+ if (listId) return packageRootOf(path.dirname(listId));
80
+ }
81
+ try {
82
+ return pieceListLocation(identifier).root;
83
+ } catch {
84
+ return;
85
+ }
86
+ }
36
87
  loadDocumentModels(identifier, immediate = false) {
37
88
  return this.#loadDocumentModelsWithDebounce(immediate, identifier);
38
89
  }
39
90
  #loadDocumentModelsWithDebounce = debounce(this.#loadDocumentModels.bind(this), 500);
40
91
  async #loadDocumentModels(identifier) {
41
- const fullPath = this.getDocumentModelsPath(identifier);
42
- this.logger.debug("Loading document models from", fullPath);
43
- try {
44
- const localDMs = await this.vite.ssrLoadModule(fullPath);
45
- const exports = Object.values(localDMs);
46
- const documentModels = [];
47
- for (const dm of exports) if (dm.documentModel) documentModels.push(dm);
48
- this.logger.verbose(` ➜ Loaded ${documentModels.length} Document Models from: ${identifier}`);
49
- return documentModels;
50
- } catch (e) {
51
- this.logger.debug(` ➜ No Document Models found for: ${identifier}`, e);
52
- }
53
- return [];
92
+ this.logger.debug("Loading document models from", this.getDocumentModelsPath(identifier));
93
+ const loaded = await this.#load(identifier, "document-models");
94
+ if (!loaded) return [];
95
+ const documentModels = Object.values(loaded.namespace).filter((dm) => dm !== null && typeof dm === "object" && "documentModel" in dm);
96
+ this.logger.verbose(` ➜ Loaded ${documentModels.length} Document Models from: ${identifier}`);
97
+ return documentModels;
54
98
  }
55
99
  async loadUpgradeManifests(identifier) {
56
- const candidatePaths = [this.getDocumentModelsPath(identifier), path.posix.join(this.getDocumentModelsPath(identifier), "upgrade-manifests")];
57
- for (const fullPath of candidatePaths) try {
58
- const manifests = extractUpgradeManifests(await this.vite.ssrLoadModule(fullPath));
100
+ for (const subpath of ["document-models", "document-models/upgrade-manifests"]) {
101
+ const loaded = await this.#load(identifier, subpath);
102
+ if (!loaded) continue;
103
+ const manifests = extractUpgradeManifests(loaded.namespace);
59
104
  if (manifests.length > 0) {
60
105
  this.logger.verbose(` ➜ Loaded ${manifests.length} Upgrade Manifests from: ${identifier}`);
61
106
  return manifests;
62
107
  }
63
- } catch (e) {
64
- this.logger.debug(` ➜ No Upgrade Manifests found at ${fullPath} for: ${identifier}`, e);
65
108
  }
66
109
  return [];
67
110
  }
68
111
  async loadSubgraphs(identifier) {
69
- const fullPath = this.getSubgraphsPath(identifier);
70
- this.logger.verbose("Loading subgraphs from", fullPath);
71
- let localSubgraphs = {};
72
- try {
73
- localSubgraphs = await this.vite.ssrLoadModule(fullPath);
74
- } catch (e) {
75
- this.logger.debug(` ➜ No Subgraphs found for: ${identifier}`, e);
76
- return [];
77
- }
112
+ this.logger.verbose("Loading subgraphs from", this.getSubgraphsPath(identifier));
113
+ const loaded = await this.#load(identifier, "subgraphs");
114
+ if (!loaded) return [];
78
115
  const subgraphs = [];
79
- for (const [name, subgraph] of Object.entries(localSubgraphs)) {
116
+ for (const [name, subgraph] of Object.entries(loaded.namespace)) {
80
117
  const SubgraphClass = subgraph[name];
81
118
  if (isSubgraphClass(SubgraphClass)) subgraphs.push(SubgraphClass);
82
119
  }
@@ -84,23 +121,36 @@ var VitePackageLoader = class VitePackageLoader {
84
121
  return subgraphs;
85
122
  }
86
123
  async loadProcessors(identifier) {
87
- const fullPath = this.getProcessorsPath(identifier);
88
- this.logger.verbose("Loading processors from", fullPath);
89
- try {
90
- const factory = (await this.vite.ssrLoadModule(fullPath))?.processorFactory;
91
- if (factory && typeof factory === "function") {
92
- this.logger.verbose(` ➜ Loaded Processor Factory from: ${identifier}`);
93
- return factory;
94
- }
95
- } catch (e) {
96
- this.logger.debug(` ➜ No Processor Factory found for: ${identifier}`, e);
124
+ this.logger.verbose("Loading processors from", this.getProcessorsPath(identifier));
125
+ const factory = (await this.#load(identifier, "processors"))?.namespace.processorFactory;
126
+ if (typeof factory === "function") {
127
+ this.logger.verbose(` ➜ Loaded Processor Factory from: ${identifier}`);
128
+ return factory;
97
129
  }
98
130
  this.logger.verbose(` ➜ No Processor Factory found for: ${identifier}`);
99
131
  return null;
100
132
  }
133
+ async loadPieces(identifier) {
134
+ this.logger.verbose("Loading pieces from", this.getPiecesPath(identifier));
135
+ const loaded = await this.#load(identifier, PIECES_SUBPATH);
136
+ if (!loaded) return [];
137
+ const root = this.pieceRoot(identifier, loaded.id);
138
+ if (root === void 0) {
139
+ this.logger.debug(` ➜ No package root found for: ${identifier}`);
140
+ return [];
141
+ }
142
+ const pieces = piecesFromListModule(loaded.namespace, {
143
+ root,
144
+ identifier,
145
+ logger: this.logger
146
+ });
147
+ this.logger.debug(` ➜ Loaded ${pieces.length} Pieces from: ${identifier}`);
148
+ return pieces;
149
+ }
101
150
  onDocumentModelsChange(identifier, handler, options) {
102
151
  const listener = async (changedPath) => {
103
- if (isSubpath(this.getDocumentModelsPath(identifier), changedPath)) handler(await this.loadDocumentModels(identifier));
152
+ const documentModelsPath = this.getDocumentModelsPath(identifier);
153
+ if (isSubpath(documentModelsPath, changedPath)) handler(await this.loadDocumentModels(identifier));
104
154
  };
105
155
  this.vite.watcher.on("change", listener);
106
156
  this.vite.watcher.on("add", listener);
@@ -139,8 +189,26 @@ var VitePackageLoader = class VitePackageLoader {
139
189
  this.vite.watcher.off("unlink", listener);
140
190
  };
141
191
  }
192
+ onPiecesChange(identifier, handler, options) {
193
+ const watched = [this.getPiecesPath(identifier)];
194
+ const root = this.pieceRoot(identifier);
195
+ if (root !== void 0) watched.push(path.dirname(path.resolve(root, BUILT_PIECE_LIST)));
196
+ const listener = async (changedPath) => {
197
+ if (!watched.some((dir) => isSubpath(dir, changedPath))) return;
198
+ handler(await this.loadPieces(identifier));
199
+ };
200
+ this.vite.watcher.on("change", listener);
201
+ this.vite.watcher.on("add", listener);
202
+ this.vite.watcher.on("unlink", listener);
203
+ return () => {
204
+ this.vite.watcher.off("change", listener);
205
+ this.vite.watcher.off("add", listener);
206
+ this.vite.watcher.off("unlink", listener);
207
+ };
208
+ }
142
209
  };
143
210
  async function startViteServer(root, logger) {
211
+ const packageJson = await readPackage({ cwd: root });
144
212
  return await createServer({
145
213
  root,
146
214
  configFile: false,
@@ -153,7 +221,7 @@ async function startViteServer(root, logger) {
153
221
  build: { rollupOptions: { input: [] } },
154
222
  resolve: {
155
223
  tsconfigPaths: true,
156
- alias: { [(await readPackage({ cwd: root })).name]: root }
224
+ alias: { [packageJson.name]: root }
157
225
  },
158
226
  plugins: [viteCommonjs(), {
159
227
  name: "suppress-hmr",
@@ -167,4 +235,4 @@ async function startViteServer(root, logger) {
167
235
  export { VitePackageLoader, createViteLogger, startViteServer };
168
236
 
169
237
  //# sourceMappingURL=vite-loader.mjs.map
170
- //# debugId=9da64ff1-d15d-5b85-94b1-f1b0dad67551
238
+ //# debugId=33a7684d-ff05-56ac-b4f5-910a2adca3e5
@@ -1 +1 @@
1
- {"version":3,"file":"vite-loader.mjs","sources":["../../../src/packages/vite-loader.mts"],"sourcesContent":["import { viteCommonjs } from \"@originjs/vite-plugin-commonjs\";\nimport type {\n ProcessorFactoryBuilder,\n SubgraphClass,\n} from \"@powerhousedao/reactor-api\";\nimport type {\n DocumentModelModule,\n UpgradeManifest,\n} from \"@powerhousedao/shared/document-model\";\nimport { childLogger, type ILogger } from \"document-model\";\nimport path from \"node:path\";\nimport { readPackage } from \"read-pkg\";\nimport type { Logger, PluginOption, ViteDevServer } from \"vite\";\nimport { createLogger, createServer } from \"vite\";\nimport { isSubgraphClass } from \"../graphql/utils.js\";\nimport type {\n ISubscribablePackageLoader,\n ISubscriptionOptions,\n} from \"./types.js\";\nimport { debounce, extractUpgradeManifests, isSubpath } from \"./util.js\";\n\nexport function createViteLogger(logger: ILogger, prefix = \"\") {\n const customLogger = createLogger(\"info\", {\n prefix,\n });\n // Wrapped rather than assigned: the logger methods are bound to their own\n // instance, and re-homing them onto Vite's logger object made every Vite\n // log line throw.\n //\n // Vite's text goes through as a replacement, never as the format string: it\n // is somebody else's prose, not a template. `ILogger` substitutes `@token`,\n // and Vite log lines are full of npm scopes, so `pre-transforming\n // @powerhousedao/design-system` came out as `pre-transforming\n // null/design-system`. Substituting into `@line` instead emits it verbatim.\n //\n // Vite's second argument is dropped for the same reason. It is `LogOptions`\n // -- `{ clear, timestamp }` -- and forwarding it made it the replacement for\n // whatever `@token` the line happened to contain, or got appended as JSON.\n // Only `error` keeps it, where it carries the error itself.\n customLogger.info = (msg) => logger.info(\"@line\", msg);\n customLogger.warn = (msg) => logger.warn(\"@line\", msg);\n customLogger.error = (msg, options) =>\n options?.error\n ? logger.error(\"@line\", msg, options.error)\n : logger.error(\"@line\", msg);\n return customLogger;\n}\n\nexport class VitePackageLoader implements ISubscribablePackageLoader {\n private readonly logger = childLogger([\"reactor-api\", \"vite-loader\"]);\n\n private readonly vite: ViteDevServer;\n\n readonly name = \"VitePackageLoader\";\n\n static build(vite: ViteDevServer) {\n return new VitePackageLoader(vite);\n }\n\n constructor(vite: ViteDevServer) {\n this.vite = vite;\n }\n\n private getDocumentModelsPath(identifier: string): string {\n return path.posix.join(identifier, \"./document-models\");\n }\n\n private getSubgraphsPath(identifier: string): string {\n return path.posix.join(identifier, \"./subgraphs\");\n }\n\n private getProcessorsPath(identifier: string): string {\n return path.posix.join(identifier, \"./processors\");\n }\n\n public loadDocumentModels(identifier: string, immediate = false) {\n return this.#loadDocumentModelsWithDebounce(immediate, identifier);\n }\n\n #loadDocumentModelsWithDebounce = debounce(\n this.#loadDocumentModels.bind(this),\n 500,\n );\n\n async #loadDocumentModels(\n identifier: string,\n ): Promise<DocumentModelModule[]> {\n const fullPath = this.getDocumentModelsPath(identifier);\n this.logger.debug(\"Loading document models from\", fullPath);\n\n try {\n const localDMs = (await this.vite.ssrLoadModule(fullPath)) as Record<\n string,\n DocumentModelModule\n >;\n\n const exports = Object.values(localDMs);\n\n // duck type\n const documentModels: DocumentModelModule[] = [];\n for (const dm of exports) {\n if (dm.documentModel) {\n documentModels.push(dm);\n }\n }\n\n this.logger.verbose(\n ` ➜ Loaded ${documentModels.length} Document Models from: ${identifier}`,\n );\n\n return documentModels;\n } catch (e) {\n this.logger.debug(` ➜ No Document Models found for: ${identifier}`, e);\n }\n\n return [];\n }\n\n async loadUpgradeManifests(\n identifier: string,\n ): Promise<UpgradeManifest<readonly number[]>[]> {\n // Projects generated before the aggregate index re-exported the\n // manifests only expose them at document-models/upgrade-manifests, so\n // try both without requiring a regeneration.\n const candidatePaths = [\n this.getDocumentModelsPath(identifier),\n path.posix.join(this.getDocumentModelsPath(identifier), \"upgrade-manifests\"),\n ];\n for (const fullPath of candidatePaths) {\n try {\n const namespace = (await this.vite.ssrLoadModule(fullPath)) as Record<\n string,\n unknown\n >;\n const manifests = extractUpgradeManifests(namespace);\n if (manifests.length > 0) {\n this.logger.verbose(\n ` ➜ Loaded ${manifests.length} Upgrade Manifests from: ${identifier}`,\n );\n return manifests;\n }\n } catch (e) {\n this.logger.debug(\n ` ➜ No Upgrade Manifests found at ${fullPath} for: ${identifier}`,\n e,\n );\n }\n }\n return [];\n }\n\n async loadSubgraphs(identifier: string): Promise<SubgraphClass[]> {\n const fullPath = this.getSubgraphsPath(identifier);\n\n this.logger.verbose(\"Loading subgraphs from\", fullPath);\n\n let localSubgraphs: Record<string, Record<string, SubgraphClass>> = {};\n try {\n localSubgraphs = await this.vite.ssrLoadModule(fullPath);\n } catch (e) {\n this.logger.debug(` ➜ No Subgraphs found for: ${identifier}`, e);\n return [];\n }\n\n const subgraphs: SubgraphClass[] = [];\n for (const [name, subgraph] of Object.entries(localSubgraphs)) {\n const SubgraphClass = subgraph[name];\n if (isSubgraphClass(SubgraphClass)) {\n subgraphs.push(SubgraphClass);\n }\n }\n\n this.logger.debug(\n ` ➜ Loaded ${subgraphs.length} Subgraphs from: ${identifier}`,\n );\n\n return subgraphs;\n }\n\n async loadProcessors(\n identifier: string,\n ): Promise<ProcessorFactoryBuilder | null> {\n const fullPath = this.getProcessorsPath(identifier);\n\n this.logger.verbose(\"Loading processors from\", fullPath);\n\n try {\n const pkgModule = await this.vite.ssrLoadModule(fullPath);\n\n const factory = (\n pkgModule as Record<string, ProcessorFactoryBuilder | undefined>\n )?.processorFactory;\n\n if (factory && typeof factory === \"function\") {\n this.logger.verbose(\n ` ➜ Loaded Processor Factory from: ${identifier}`,\n );\n return factory;\n }\n } catch (e) {\n this.logger.debug(\n ` ➜ No Processor Factory found for: ${identifier}`,\n e,\n );\n }\n\n this.logger.verbose(` ➜ No Processor Factory found for: ${identifier}`);\n\n // return empty processor factory\n return null;\n }\n\n onDocumentModelsChange(\n identifier: string,\n handler: (documentModels: DocumentModelModule[]) => void,\n options?: ISubscriptionOptions,\n ): () => void {\n const listener = async (changedPath: string) => {\n const documentModelsPath = this.getDocumentModelsPath(identifier);\n if (isSubpath(documentModelsPath, changedPath)) {\n const documentModels = await this.loadDocumentModels(identifier);\n handler(documentModels);\n }\n };\n\n // \"change\" alone misses files that are created or deleted: a removed\n // document-models/ entry would never report an empty result, and the\n // package's registered models would leak.\n this.vite.watcher.on(\"change\", listener);\n this.vite.watcher.on(\"add\", listener);\n this.vite.watcher.on(\"unlink\", listener);\n\n return () => {\n this.vite.watcher.off(\"change\", listener);\n this.vite.watcher.off(\"add\", listener);\n this.vite.watcher.off(\"unlink\", listener);\n };\n }\n\n onSubgraphsChange(\n identifier: string,\n handler: (subgraphs: SubgraphClass[]) => void,\n options?: ISubscriptionOptions,\n ): () => void {\n const subgraphsPath = this.getSubgraphsPath(identifier);\n const listener = async (changedPath: string) => {\n if (isSubpath(subgraphsPath, changedPath)) {\n const subgraphs = await this.loadSubgraphs(identifier);\n handler(subgraphs);\n }\n };\n // \"change\" alone misses files that are created or deleted: a removed\n // subgraphs/ entry would never report an empty result, and the\n // package's registered subgraphs would leak.\n this.vite.watcher.on(\"change\", listener);\n this.vite.watcher.on(\"add\", listener);\n this.vite.watcher.on(\"unlink\", listener);\n\n return () => {\n this.vite.watcher.off(\"change\", listener);\n this.vite.watcher.off(\"add\", listener);\n this.vite.watcher.off(\"unlink\", listener);\n };\n }\n\n onProcessorsChange(\n identifier: string,\n handler: (processors: ProcessorFactoryBuilder | null) => void,\n options?: ISubscriptionOptions,\n ): () => void {\n const processorsPath = this.getProcessorsPath(identifier);\n const listener = async (changedPath: string) => {\n if (isSubpath(processorsPath, changedPath)) {\n const processors = await this.loadProcessors(identifier);\n handler(processors);\n }\n };\n // \"change\" alone misses files that are created or deleted: a removed\n // processors/ entry would never report an empty result, and the\n // package's registered processor factories would leak.\n this.vite.watcher.on(\"change\", listener);\n this.vite.watcher.on(\"add\", listener);\n this.vite.watcher.on(\"unlink\", listener);\n\n return () => {\n this.vite.watcher.off(\"change\", listener);\n this.vite.watcher.off(\"add\", listener);\n this.vite.watcher.off(\"unlink\", listener);\n };\n }\n}\n\nexport async function startViteServer(root: string, logger?: Logger) {\n const packageJson = await readPackage({ cwd: root });\n\n const vite = await createServer({\n root,\n configFile: false,\n logger,\n server: { middlewareMode: true, watch: { ignored: [\"**/.ph/**\"] } },\n appType: \"custom\",\n build: {\n rollupOptions: {\n input: [],\n },\n },\n resolve: {\n tsconfigPaths: true,\n alias: {\n [packageJson.name]: root,\n },\n },\n plugins: [\n // cast: the plugin ships types built against an older vite, and the\n // mismatched Plugin type crashes tsc 6 during assignability checking\n viteCommonjs() as PluginOption,\n {\n name: \"suppress-hmr\",\n handleHotUpdate() {\n return []; // return empty array to suppress server refresh\n },\n },\n ],\n });\n\n return vite;\n}\n"],"names":["#loadDocumentModelsWithDebounce","#loadDocumentModels"],"mappings":"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","debug_id":"9da64ff1-d15d-5b85-94b1-f1b0dad67551"}
1
+ {"version":3,"file":"vite-loader.mjs","sources":["../../../src/packages/vite-loader.mts"],"sourcesContent":["import { viteCommonjs } from \"@originjs/vite-plugin-commonjs\";\nimport type {\n ProcessorFactoryBuilder,\n SubgraphClass,\n} from \"@powerhousedao/reactor-api\";\nimport type {\n DocumentModelModule,\n UpgradeManifest,\n} from \"@powerhousedao/shared/document-model\";\nimport { childLogger, type ILogger } from \"document-model\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { readPackage } from \"read-pkg\";\nimport type { Logger, PluginOption, ViteDevServer } from \"vite\";\nimport { createLogger, createServer } from \"vite\";\nimport { isSubgraphClass } from \"../graphql/utils.js\";\nimport {\n BUILT_PIECE_LIST,\n PIECES_SUBPATH,\n packageRootOf,\n pieceListLocation,\n piecesFromListModule,\n} from \"./pieces.js\";\nimport type {\n ISubscribablePackageLoader,\n ISubscriptionOptions,\n PackagePieceEntry,\n} from \"./types.js\";\nimport { debounce, extractUpgradeManifests, isSubpath } from \"./util.js\";\n\nexport function createViteLogger(logger: ILogger, prefix = \"\") {\n const customLogger = createLogger(\"info\", {\n prefix,\n });\n // Wrapped rather than assigned: the logger methods are bound to their own\n // instance, and re-homing them onto Vite's logger object made every Vite\n // log line throw.\n //\n // Vite's text goes through as a replacement, never as the format string: it\n // is somebody else's prose, not a template. `ILogger` substitutes `@token`,\n // and Vite log lines are full of npm scopes, so `pre-transforming\n // @powerhousedao/design-system` came out as `pre-transforming\n // null/design-system`. Substituting into `@line` instead emits it verbatim.\n //\n // Vite's second argument is dropped for the same reason. It is `LogOptions`\n // -- `{ clear, timestamp }` -- and forwarding it made it the replacement for\n // whatever `@token` the line happened to contain, or got appended as JSON.\n // Only `error` keeps it, where it carries the error itself.\n customLogger.info = (msg) => logger.info(\"@line\", msg);\n customLogger.warn = (msg) => logger.warn(\"@line\", msg);\n customLogger.error = (msg, options) =>\n options?.error\n ? logger.error(\"@line\", msg, options.error)\n : logger.error(\"@line\", msg);\n return customLogger;\n}\n\nexport interface VitePackageLoaderOptions {\n /** Modules, as paths or file URLs, whose dependencies a package the project\n * does not install may resolve from. This loader's own module always is. */\n resolveFrom?: string[];\n}\n\ninterface LoadedModule {\n id: string;\n namespace: Record<string, unknown>;\n}\n\nexport class VitePackageLoader implements ISubscribablePackageLoader {\n private readonly logger = childLogger([\"reactor-api\", \"vite-loader\"]);\n\n private readonly vite: ViteDevServer;\n\n private readonly importers: string[];\n\n readonly name = \"VitePackageLoader\";\n\n static build(vite: ViteDevServer, options?: VitePackageLoaderOptions) {\n return new VitePackageLoader(vite, options);\n }\n\n constructor(vite: ViteDevServer, options: VitePackageLoaderOptions = {}) {\n this.vite = vite;\n this.importers = [...(options.resolveFrom ?? []), import.meta.url].map(\n (from) => (from.startsWith(\"file:\") ? fileURLToPath(from) : from),\n );\n }\n\n // The project first, then the host's own dependencies. A bare name or a path\n // Vite cannot resolve is a package without that module, not an error.\n async #resolve(identifier: string, subpath: string) {\n const aliased = path.isAbsolute(identifier)\n ? undefined\n : this.aliasedRoot(identifier);\n const specifier = path.posix.join(aliased ?? identifier, subpath);\n const bare = !aliased && !path.isAbsolute(identifier);\n const importers = bare ? [undefined, ...this.importers] : [undefined];\n const container = this.vite.environments.ssr.pluginContainer;\n for (const importer of importers) {\n try {\n const resolved = await container.resolveId(specifier, importer);\n if (resolved && !resolved.external) return resolved.id;\n } catch (e) {\n this.logger.debug(\"Could not resolve @specifier: @error\", specifier, e);\n }\n }\n return undefined;\n }\n\n // Resolved before it is loaded, so only a module that exists and fails is\n // reported; one a package does not have is a debug-level miss.\n async #load(\n identifier: string,\n subpath: string,\n ): Promise<LoadedModule | undefined> {\n const id = await this.#resolve(identifier, subpath);\n if (id === undefined) {\n this.logger.debug(\"No @subpath module in @pkg\", subpath, identifier);\n return undefined;\n }\n try {\n const namespace = (await this.vite.ssrLoadModule(id)) as Record<\n string,\n unknown\n >;\n return { id, namespace };\n } catch (e) {\n this.logger.error(\n \"Failed to load @subpath of @pkg from @id: @error\",\n subpath,\n identifier,\n id,\n e instanceof Error ? e.message : e,\n );\n return undefined;\n }\n }\n\n private getDocumentModelsPath(identifier: string): string {\n return path.posix.join(identifier, \"./document-models\");\n }\n\n private getSubgraphsPath(identifier: string): string {\n return path.posix.join(identifier, \"./subgraphs\");\n }\n\n private getProcessorsPath(identifier: string): string {\n return path.posix.join(identifier, \"./processors\");\n }\n\n private getPiecesPath(identifier: string): string {\n return path.posix.join(identifier, `./${PIECES_SUBPATH}`);\n }\n\n // The dev server aliases the local project by its own package name, so a\n // package that is this project is rooted at the source tree vite serves.\n private aliasedRoot(identifier: string): string | undefined {\n const alias = this.vite.config.resolve.alias;\n const entries = Array.isArray(alias) ? alias : [];\n const hit = entries.find((entry) => entry.find === identifier);\n return typeof hit?.replacement === \"string\" ? hit.replacement : undefined;\n }\n\n // What a declared piece path is relative to. Not the module vite loaded: a\n // list read from source still points at the built output beside it.\n private pieceRoot(identifier: string, listId?: string): string | undefined {\n if (!path.isAbsolute(identifier)) {\n const aliased = this.aliasedRoot(identifier);\n if (aliased) return aliased;\n // A built list resolved from wherever the package is installed.\n if (listId) return packageRootOf(path.dirname(listId));\n }\n try {\n return pieceListLocation(identifier).root;\n } catch {\n return undefined;\n }\n }\n\n public loadDocumentModels(identifier: string, immediate = false) {\n return this.#loadDocumentModelsWithDebounce(immediate, identifier);\n }\n\n #loadDocumentModelsWithDebounce = debounce(\n this.#loadDocumentModels.bind(this),\n 500,\n );\n\n async #loadDocumentModels(\n identifier: string,\n ): Promise<DocumentModelModule[]> {\n this.logger.debug(\n \"Loading document models from\",\n this.getDocumentModelsPath(identifier),\n );\n const loaded = await this.#load(identifier, \"document-models\");\n if (!loaded) return [];\n\n // duck type\n const documentModels = Object.values(loaded.namespace).filter(\n (dm): dm is DocumentModelModule =>\n dm !== null && typeof dm === \"object\" && \"documentModel\" in dm,\n );\n this.logger.verbose(\n ` ➜ Loaded ${documentModels.length} Document Models from: ${identifier}`,\n );\n return documentModels;\n }\n\n async loadUpgradeManifests(\n identifier: string,\n ): Promise<UpgradeManifest<readonly number[]>[]> {\n // Projects generated before the aggregate index re-exported the\n // manifests only expose them at document-models/upgrade-manifests.\n for (const subpath of [\n \"document-models\",\n \"document-models/upgrade-manifests\",\n ]) {\n const loaded = await this.#load(identifier, subpath);\n if (!loaded) continue;\n const manifests = extractUpgradeManifests(loaded.namespace);\n if (manifests.length > 0) {\n this.logger.verbose(\n ` ➜ Loaded ${manifests.length} Upgrade Manifests from: ${identifier}`,\n );\n return manifests;\n }\n }\n return [];\n }\n\n async loadSubgraphs(identifier: string): Promise<SubgraphClass[]> {\n this.logger.verbose(\n \"Loading subgraphs from\",\n this.getSubgraphsPath(identifier),\n );\n const loaded = await this.#load(identifier, \"subgraphs\");\n if (!loaded) return [];\n\n const subgraphs: SubgraphClass[] = [];\n for (const [name, subgraph] of Object.entries(\n loaded.namespace as Record<string, Record<string, SubgraphClass>>,\n )) {\n const SubgraphClass = subgraph[name];\n if (isSubgraphClass(SubgraphClass)) {\n subgraphs.push(SubgraphClass);\n }\n }\n\n this.logger.debug(\n ` ➜ Loaded ${subgraphs.length} Subgraphs from: ${identifier}`,\n );\n\n return subgraphs;\n }\n\n async loadProcessors(\n identifier: string,\n ): Promise<ProcessorFactoryBuilder | null> {\n this.logger.verbose(\n \"Loading processors from\",\n this.getProcessorsPath(identifier),\n );\n const loaded = await this.#load(identifier, \"processors\");\n const factory = loaded?.namespace.processorFactory;\n if (typeof factory === \"function\") {\n this.logger.verbose(` ➜ Loaded Processor Factory from: ${identifier}`);\n return factory as ProcessorFactoryBuilder;\n }\n\n this.logger.verbose(` ➜ No Processor Factory found for: ${identifier}`);\n return null;\n }\n\n // The list only, never a piece: in dev it is usually the TypeScript source,\n // and what it names is still the built bundle a worker will load.\n async loadPieces(identifier: string): Promise<PackagePieceEntry[]> {\n this.logger.verbose(\"Loading pieces from\", this.getPiecesPath(identifier));\n const loaded = await this.#load(identifier, PIECES_SUBPATH);\n if (!loaded) return [];\n\n const root = this.pieceRoot(identifier, loaded.id);\n if (root === undefined) {\n this.logger.debug(` ➜ No package root found for: ${identifier}`);\n return [];\n }\n\n const pieces = piecesFromListModule(loaded.namespace, {\n root,\n identifier,\n logger: this.logger,\n });\n this.logger.debug(\n ` ➜ Loaded ${pieces.length} Pieces from: ${identifier}`,\n );\n return pieces;\n }\n\n onDocumentModelsChange(\n identifier: string,\n handler: (documentModels: DocumentModelModule[]) => void,\n options?: ISubscriptionOptions,\n ): () => void {\n const listener = async (changedPath: string) => {\n const documentModelsPath = this.getDocumentModelsPath(identifier);\n if (isSubpath(documentModelsPath, changedPath)) {\n const documentModels = await this.loadDocumentModels(identifier);\n handler(documentModels);\n }\n };\n\n // \"change\" alone misses files that are created or deleted: a removed\n // document-models/ entry would never report an empty result, and the\n // package's registered models would leak.\n this.vite.watcher.on(\"change\", listener);\n this.vite.watcher.on(\"add\", listener);\n this.vite.watcher.on(\"unlink\", listener);\n\n return () => {\n this.vite.watcher.off(\"change\", listener);\n this.vite.watcher.off(\"add\", listener);\n this.vite.watcher.off(\"unlink\", listener);\n };\n }\n\n onSubgraphsChange(\n identifier: string,\n handler: (subgraphs: SubgraphClass[]) => void,\n options?: ISubscriptionOptions,\n ): () => void {\n const subgraphsPath = this.getSubgraphsPath(identifier);\n const listener = async (changedPath: string) => {\n if (isSubpath(subgraphsPath, changedPath)) {\n const subgraphs = await this.loadSubgraphs(identifier);\n handler(subgraphs);\n }\n };\n // \"change\" alone misses files that are created or deleted: a removed\n // subgraphs/ entry would never report an empty result, and the\n // package's registered subgraphs would leak.\n this.vite.watcher.on(\"change\", listener);\n this.vite.watcher.on(\"add\", listener);\n this.vite.watcher.on(\"unlink\", listener);\n\n return () => {\n this.vite.watcher.off(\"change\", listener);\n this.vite.watcher.off(\"add\", listener);\n this.vite.watcher.off(\"unlink\", listener);\n };\n }\n\n onProcessorsChange(\n identifier: string,\n handler: (processors: ProcessorFactoryBuilder | null) => void,\n options?: ISubscriptionOptions,\n ): () => void {\n const processorsPath = this.getProcessorsPath(identifier);\n const listener = async (changedPath: string) => {\n if (isSubpath(processorsPath, changedPath)) {\n const processors = await this.loadProcessors(identifier);\n handler(processors);\n }\n };\n // \"change\" alone misses files that are created or deleted: a removed\n // processors/ entry would never report an empty result, and the\n // package's registered processor factories would leak.\n this.vite.watcher.on(\"change\", listener);\n this.vite.watcher.on(\"add\", listener);\n this.vite.watcher.on(\"unlink\", listener);\n\n return () => {\n this.vite.watcher.off(\"change\", listener);\n this.vite.watcher.off(\"add\", listener);\n this.vite.watcher.off(\"unlink\", listener);\n };\n }\n\n onPiecesChange(\n identifier: string,\n handler: (pieces: PackagePieceEntry[]) => void,\n options?: ISubscriptionOptions,\n ): () => void {\n // Both the source list and the build output: the list says which pieces a\n // package ships, and only the build decides whether one is there to run.\n const watched = [this.getPiecesPath(identifier)];\n const root = this.pieceRoot(identifier);\n if (root !== undefined) {\n watched.push(path.dirname(path.resolve(root, BUILT_PIECE_LIST)));\n }\n const listener = async (changedPath: string) => {\n if (!watched.some((dir) => isSubpath(dir, changedPath))) return;\n handler(await this.loadPieces(identifier));\n };\n // \"change\" alone misses files that are created or deleted, and a piece\n // appearing for the first time is exactly the build this watches for.\n this.vite.watcher.on(\"change\", listener);\n this.vite.watcher.on(\"add\", listener);\n this.vite.watcher.on(\"unlink\", listener);\n\n return () => {\n this.vite.watcher.off(\"change\", listener);\n this.vite.watcher.off(\"add\", listener);\n this.vite.watcher.off(\"unlink\", listener);\n };\n }\n}\n\nexport async function startViteServer(root: string, logger?: Logger) {\n const packageJson = await readPackage({ cwd: root });\n\n const vite = await createServer({\n root,\n configFile: false,\n logger,\n server: { middlewareMode: true, watch: { ignored: [\"**/.ph/**\"] } },\n appType: \"custom\",\n build: {\n rollupOptions: {\n input: [],\n },\n },\n resolve: {\n tsconfigPaths: true,\n alias: {\n [packageJson.name]: root,\n },\n },\n plugins: [\n // cast: the plugin ships types built against an older vite, and the\n // mismatched Plugin type crashes tsc 6 during assignability checking\n viteCommonjs() as PluginOption,\n {\n name: \"suppress-hmr\",\n handleHotUpdate() {\n return []; // return empty array to suppress server refresh\n },\n },\n ],\n });\n\n return vite;\n}\n"],"names":[],"mappings":"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","debug_id":"33a7684d-ff05-56ac-b4f5-910a2adca3e5"}
@@ -1,8 +1,22 @@
1
1
  import { ILogger } from "document-model";
2
2
  import { DocumentModelModule, UpgradeManifest } from "@powerhousedao/shared/document-model";
3
3
  import { ProcessorFactoryBuilder, SubgraphClass } from "@powerhousedao/reactor-api";
4
-
5
4
  //#region src/packages/types.d.ts
5
+ interface PackagePiece {
6
+ name: string;
7
+ /** Built output, relative to the package root: a directory in npm shape. */
8
+ bundle?: string;
9
+ /** Built output, relative to the package root: a single module file. */
10
+ entry?: string;
11
+ }
12
+ interface PackagePieceEntry {
13
+ name: string;
14
+ /** The version of the package that ships it. */
15
+ version: string;
16
+ entryPath?: string;
17
+ bundleDir?: string;
18
+ entryUrl?: string;
19
+ }
6
20
  interface IPackageLoader {
7
21
  name: string;
8
22
  loadDocumentModels(identifier: string, immediate?: boolean): Promise<DocumentModelModule[]>;
@@ -13,6 +27,8 @@ interface IPackageLoader {
13
27
  loadUpgradeManifests?(identifier: string): Promise<UpgradeManifest<readonly number[]>[]>;
14
28
  loadSubgraphs(identifier: string, immediate?: boolean): Promise<SubgraphClass[]>;
15
29
  loadProcessors(identifier: string, immediate?: boolean): Promise<ProcessorFactoryBuilder | null>;
30
+ /** The pieces a package ships, each located absolutely on this disk. */
31
+ loadPieces(identifier: string, immediate?: boolean): Promise<PackagePieceEntry[]>;
16
32
  }
17
33
  interface ISubscriptionOptions {
18
34
  debounce?: number;
@@ -21,6 +37,7 @@ interface ISubscribablePackageLoader extends IPackageLoader {
21
37
  onDocumentModelsChange?(identifier: string, handler: (documentModels: DocumentModelModule[]) => void, options?: ISubscriptionOptions): () => void;
22
38
  onSubgraphsChange?(identifier: string, handler: (subgraphs: SubgraphClass[]) => void, options?: ISubscriptionOptions): () => void;
23
39
  onProcessorsChange?(identifier: string, handler: (processors: ProcessorFactoryBuilder | null) => void, options?: ISubscriptionOptions): () => void;
40
+ onPiecesChange?(identifier: string, handler: (pieces: PackagePieceEntry[]) => void, options?: ISubscriptionOptions): () => void;
24
41
  }
25
42
  interface IPackageManager {
26
43
  onDocumentModelsChange(handler: (documentModels: Record<string, DocumentModelModule[]>) => void): void;
@@ -42,7 +59,13 @@ type PackageManagerResult = {
42
59
  upgradeManifests: UpgradeManifest<readonly number[]>[];
43
60
  subgraphs: Map<string, SubgraphClass[]>;
44
61
  processors: Map<string, ProcessorFactoryBuilder[]>;
62
+ pieces: Map<string, PackagePieceEntry[]>;
45
63
  };
64
+ interface IPackagePieceSource {
65
+ getPieces(): Map<string, PackagePieceEntry[]>;
66
+ onPiecesChange(handler: (pieces: Map<string, PackagePieceEntry[]>) => void): void;
67
+ }
46
68
  //#endregion
47
- export { ISubscribablePackageLoader as a, IPackageManagerOptions as i, IPackageLoaderOptions as n, ISubscriptionOptions as o, IPackageManager as r, PackageManagerResult as s, IPackageLoader as t };
48
- //# sourceMappingURL=types-DcYyNcHJ.d.mts.map
69
+ export { IPackagePieceSource as a, PackageManagerResult as c, IPackageManagerOptions as i, PackagePiece as l, IPackageLoaderOptions as n, ISubscribablePackageLoader as o, IPackageManager as r, ISubscriptionOptions as s, IPackageLoader as t, PackagePieceEntry as u };
70
+ export {};
71
+ //# sourceMappingURL=types-CuSz_zv6.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-CuSz_zv6.d.mts","names":[],"sources":["../src/packages/types.ts"],"mappings":";;;;UAYiB;EACf;;EAEA;;EAEA;;UAQe;EACf;;EAEA;EACA;EACA;EACA;;UAGe;EACf;EACA,mBACE,oBACA,sBACC,QAAQ;;;;;EAKX,sBACE,qBACC,QAAQ;EACX,cACE,oBACA,sBACC,QAAQ;EACX,eACE,oBACA,sBACC,QAAQ;;EAEX,WACE,oBACA,sBACC,QAAQ;;UAGI;EACf;;UAGe,mCAAmC;EAClD,wBACE,oBACA,UAAU,gBAAgB,gCAC1B,UAAU;EAEZ,mBACE,oBACA,UAAU,WAAW,0BACrB,UAAU;EAEZ,oBACE,oBACA,UAAU,YAAY,yCACtB,UAAU;EAEZ,gBACE,oBACA,UAAU,QAAQ,8BAClB,UAAU;;UAIG;EACf,uBACE,UAAU,gBAAgB,eAAe;;;;;EAM3C,cAAc;;KAGJ;EACV,SAAS;;KAGC;EACV;EACA;;KAWU;EACV,gBAAgB;EAChB,kBAAkB;EAClB,WAAW,YAAY;EACvB,YAAY,YAAY;EACxB,QAAQ,YAAY;;UAKL;EACf,aAAa,YAAY;EACzB,eACE,UAAU,QAAQ,YAAY"}
@@ -1,6 +1,6 @@
1
1
  //#region src/graphql/websocket.ts
2
2
 
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]="663fe2c0-10df-557e-b45d-57d4135d09f2")}catch(e){}}();
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]="bddc5b47-cb23-58b9-bb18-09b08c412430")}catch(e){}}();
4
4
  let useServerImpl = null;
5
5
  if (process.env.VITEST !== "true" && process.env.NODE_ENV !== "test") try {
6
6
  const { useServer } = await import("graphql-ws/use/ws");
@@ -14,5 +14,5 @@ const useServer = useServerImpl || (() => {
14
14
  //#endregion
15
15
  export { useServer as t };
16
16
 
17
- //# sourceMappingURL=websocket-DncAB9XK.mjs.map
18
- //# debugId=663fe2c0-10df-557e-b45d-57d4135d09f2
17
+ //# sourceMappingURL=websocket-_SH5aBcy.mjs.map
18
+ //# debugId=bddc5b47-cb23-58b9-bb18-09b08c412430
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-DncAB9XK.mjs","sources":["../src/graphql/websocket.ts"],"sourcesContent":["import type { useServer as wsUseServer } from \"graphql-ws/use/ws\";\n\nlet useServerImpl: typeof wsUseServer | null = null;\n\nif (process.env.VITEST !== \"true\" && process.env.NODE_ENV !== \"test\") {\n try {\n const { useServer } = await import(\"graphql-ws/use/ws\");\n useServerImpl = useServer;\n } catch (error) {\n console.warn(\n \"Failed to load graphql-ws WebSocket server. Subscriptions will not work.\",\n error,\n );\n }\n}\n\nexport const useServer =\n useServerImpl ||\n (() => {\n throw new Error(\n \"WebSocket server not available in test mode. Set NODE_ENV=production to enable.\",\n );\n });\n"],"names":[],"mappings":";;;AAEA,IAAI,gBAA2C;AAE/C,IAAI,QAAQ,IAAI,WAAW,UAAU,QAAQ,IAAI,aAAa,OAC5D,KAAI;CACF,MAAM,EAAE,cAAc,MAAM,OAAO;AACnC,iBAAgB;SACT,OAAO;AACd,SAAQ,KACN,4EACA,MACD;;AAIL,MAAa,YACX,wBACO;AACL,OAAM,IAAI,MACR,kFACD","debug_id":"663fe2c0-10df-557e-b45d-57d4135d09f2"}
1
+ {"version":3,"file":"websocket-_SH5aBcy.mjs","sources":["../src/graphql/websocket.ts"],"sourcesContent":["import type { useServer as wsUseServer } from \"graphql-ws/use/ws\";\n\nlet useServerImpl: typeof wsUseServer | null = null;\n\nif (process.env.VITEST !== \"true\" && process.env.NODE_ENV !== \"test\") {\n try {\n const { useServer } = await import(\"graphql-ws/use/ws\");\n useServerImpl = useServer;\n } catch (error) {\n console.warn(\n \"Failed to load graphql-ws WebSocket server. Subscriptions will not work.\",\n error,\n );\n }\n}\n\nexport const useServer =\n useServerImpl ||\n (() => {\n throw new Error(\n \"WebSocket server not available in test mode. Set NODE_ENV=production to enable.\",\n );\n });\n"],"names":[],"mappings":";;;AAEA,IAAI,gBAA2C;AAE/C,IAAI,QAAQ,IAAI,WAAW,UAAU,QAAQ,IAAI,aAAa,QAC5D,IAAI;CACF,MAAM,EAAE,cAAc,MAAM,OAAO;CACnC,gBAAgB;AAClB,SAAS,OAAO;CACd,QAAQ,KACN,4EACA,KACF;AACF;AAGF,MAAa,YACX,wBACO;CACL,MAAM,IAAI,MACR,iFACF;AACF","debug_id":"bddc5b47-cb23-58b9-bb18-09b08c412430"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powerhousedao/reactor-api",
3
- "version": "6.2.3-dev.9",
3
+ "version": "6.2.3-staging.0",
4
4
  "description": "GraphQL API layer for the Powerhouse reactor — auto-generated subgraphs per document model plus the core reactor subgraph for drive and document management.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -59,26 +59,26 @@
59
59
  "@graphql-tools/schema": "10.0.31",
60
60
  "@graphql-tools/utils": "11.0.0",
61
61
  "@originjs/vite-plugin-commonjs": "^1.0.3",
62
- "@powerhousedao/analytics-engine-core": "6.2.3-dev.9",
63
- "@powerhousedao/analytics-engine-graphql": "6.2.3-dev.9",
64
- "@powerhousedao/analytics-engine-pg": "6.2.3-dev.9",
65
- "@powerhousedao/config": "6.2.3-dev.9",
62
+ "@powerhousedao/analytics-engine-core": "6.2.3-staging.0",
63
+ "@powerhousedao/analytics-engine-graphql": "6.2.3-staging.0",
64
+ "@powerhousedao/analytics-engine-pg": "6.2.3-staging.0",
65
+ "@powerhousedao/config": "6.2.3-staging.0",
66
66
  "@powerhousedao/document-engineering": "1.40.5",
67
- "@powerhousedao/pglite-fs": "6.2.3-dev.9",
68
- "@powerhousedao/reactor": "6.2.3-dev.9",
69
- "@powerhousedao/reactor-attachments": "6.2.3-dev.9",
70
- "@powerhousedao/reactor-drive": "6.2.3-dev.9",
71
- "@powerhousedao/reactor-group": "6.2.3-dev.9",
72
- "@powerhousedao/reactor-mcp": "6.2.3-dev.9",
73
- "@powerhousedao/shared": "6.2.3-dev.9",
74
- "@renown/sdk": "6.2.3-dev.9",
67
+ "@powerhousedao/pglite-fs": "6.2.3-staging.0",
68
+ "@powerhousedao/reactor": "6.2.3-staging.0",
69
+ "@powerhousedao/reactor-attachments": "6.2.3-staging.0",
70
+ "@powerhousedao/reactor-drive": "6.2.3-staging.0",
71
+ "@powerhousedao/reactor-group": "6.2.3-staging.0",
72
+ "@powerhousedao/reactor-mcp": "6.2.3-staging.0",
73
+ "@powerhousedao/shared": "6.2.3-staging.0",
74
+ "@renown/sdk": "6.2.3-staging.0",
75
75
  "body-parser": "^1.20.3",
76
76
  "change-case": "5.4.4",
77
77
  "cors": "^2.8.5",
78
78
  "devcert": "^1.2.2",
79
- "document-model": "6.2.3-dev.9",
79
+ "document-model": "6.2.3-staging.0",
80
80
  "dotenv": "^16.4.5",
81
- "express": "4.21.1",
81
+ "express": "^4.22.1",
82
82
  "graphql-sse": "2.6.0",
83
83
  "graphql-subscriptions": "^3.0.0",
84
84
  "graphql-type-json": "^0.3.2",
@@ -115,7 +115,7 @@
115
115
  "@types/ws": "^8.18.1",
116
116
  "graphql": "^16",
117
117
  "graphql-tag": "^2",
118
- "tsdown": "0.21.1",
118
+ "tsdown": "0.23.0",
119
119
  "msw": "^2.7.3",
120
120
  "vitest": "4.1.1"
121
121
  },
@@ -157,11 +157,11 @@
157
157
  "scripts": {
158
158
  "tsc": "tsc",
159
159
  "build": "tsdown",
160
- "lint": "eslint",
160
+ "lint": "cd ../.. && oxlint packages/reactor-api",
161
161
  "test": "vitest --run",
162
162
  "test:integration": "cross-env RUN_HUB_SPOKE_INTEGRATION=1 vitest --run test/hub-spoke-catchup.integration.test.ts",
163
163
  "bench": "vitest bench",
164
- "codegen": "graphql-codegen --config codegen.ts && prettier --write src/graphql/reactor/gen/*.ts && eslint --fix src/graphql/reactor/gen/*.ts --no-warn-ignored",
164
+ "codegen": "graphql-codegen --config codegen.ts && oxlint --fix src/graphql/reactor/gen/*.ts && oxfmt src/graphql/reactor/gen/*.ts",
165
165
  "codegen:watch": "graphql-codegen --config codegen.ts --watch",
166
166
  "dev": "tsx src/dev.ts",
167
167
  "capture-hub-dump": "tsx scripts/capture-hub-dump.ts",
@@ -1 +0,0 @@
1
- {"version":3,"file":"adapter-http-express-B39rPhqH.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\";\n\ntype GetHandler = (r: Request) => Response | Promise<Response>;\n\ntype NodeHandler = (\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body?: unknown,\n) => void | Promise<void>;\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 // Fire-and-forget, as before: the node handler manages its own response\n // and the adapter does not await its promise.\n void entry.handler(req, res, entry.rawBody ? undefined : req.body);\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(port: number, tls?: TlsOptions): 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, () => {\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":["#app","#router","#routes","#replaceDuplicates","#nextHandle","#dispatchNodeRoute","#serveGetEntry","#serveFetchHandler"],"mappings":"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","debug_id":"af482776-5e68-5345-a965-0937af984537"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"adapter-http-fastify-BwXO6rqE.mjs","sources":["../src/graphql/gateway/adapter-http-fastify.ts"],"sourcesContent":["import fastifyCors from \"@fastify/cors\";\nimport fastifyFormbody from \"@fastify/formbody\";\nimport fastifyMiddie from \"@fastify/middie\";\nimport type { CorsOptions } from \"cors\";\nimport devcert from \"devcert\";\nimport Fastify from \"fastify\";\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\nimport fs from \"node:fs\";\nimport http from \"node:http\";\nimport https from \"node:https\";\nimport nodePath 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\";\n\n/** Parses body-limit strings like \"50mb\" to bytes. */\nfunction parseBodyLimit(limit: string): number {\n const m = /^(\\d+(?:\\.\\d+)?)\\s*(b|kb|mb|gb)?$/i.exec(limit.trim());\n if (!m) return 52_428_800; // 50 MB fallback\n const n = parseFloat(m[1]);\n const units: Record<string, number> = {\n b: 1,\n kb: 1_024,\n mb: 1_048_576,\n gb: 1_073_741_824,\n };\n return Math.round(n * (units[(m[2] ?? \"b\").toLowerCase()] ?? 1));\n}\n\ntype FetchEntry = {\n path: string;\n handler: FetchHandler;\n matcher: MatchFunction<ParamData>;\n prefix: boolean;\n};\n\ntype GetEntry = {\n path: string;\n handler: (r: Request) => Response | Promise<Response>;\n matcher: MatchFunction<ParamData>;\n};\n\ntype NodeHandler = (\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body?: unknown,\n) => void;\n\ntype NodeEntry = {\n path: string;\n method: HttpMethod;\n matcher: MatchFunction<ParamData>;\n handler: NodeHandler;\n /** Claimed in the onRequest hook, before any body parsing. */\n rawBody: boolean;\n};\n\n// Pre-listen configuration ops (need the Fastify instance to apply).\ntype SetupOp =\n | { kind: \"cors\"; options?: CorsOptions; bodyLimit: number }\n | { kind: \"middie\"; middleware: unknown };\n\nexport class FastifyHttpAdapter implements IHttpAdapter {\n // Dispatch maps, keyed by route handle and iterated in registration\n // order — populated at any time (before or after listen). Mounting a\n // path that already holds a route of the same kind (and method, for\n // node routes) replaces the old entry, so re-mounting is last-write-\n // wins without accumulating; a handle's dispose() removes its own entry.\n readonly #fetchRoutes = new Map<number, FetchEntry>();\n readonly #getRoutes = new Map<number, GetEntry>();\n readonly #nodeRoutes = new Map<number, NodeEntry>();\n #nextHandle = 0;\n\n // Ops that need the Fastify instance (CORS config, Connect middleware).\n readonly #setupOps: SetupOp[] = [];\n\n #instance: FastifyInstance | undefined;\n\n get handle(): unknown {\n return this.#instance;\n }\n\n setupMiddleware({\n corsOptions,\n bodyLimit = \"50mb\",\n }: {\n corsOptions?: CorsOptions;\n bodyLimit?: string;\n }): void {\n this.#setupOps.push({\n kind: \"cors\",\n options: corsOptions,\n bodyLimit: parseBodyLimit(bodyLimit),\n });\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 for (const [handle, entry] of this.#fetchRoutes) {\n if (entry.path === path) this.#fetchRoutes.delete(handle);\n }\n const handle = this.#nextHandle++;\n this.#fetchRoutes.set(handle, {\n path,\n handler,\n matcher: match(normalizePath(path), { end: !asPrefix }),\n prefix: asPrefix,\n });\n return { dispose: () => this.#fetchRoutes.delete(handle) };\n }\n\n getRoute(\n path: string,\n handler: (r: Request) => Response | Promise<Response>,\n ): AdapterRouteHandle {\n for (const [handle, entry] of this.#getRoutes) {\n if (entry.path === path) this.#getRoutes.delete(handle);\n }\n const handle = this.#nextHandle++;\n this.#getRoutes.set(handle, {\n path,\n handler,\n matcher: match(normalizePath(path)),\n });\n return { dispose: () => this.#getRoutes.delete(handle) };\n }\n\n mountNodeRoute(\n method: HttpMethod,\n path: string,\n handler: NodeHandler,\n { rawBody = false, prefix = false }: NodeRouteOptions = {},\n ): AdapterRouteHandle {\n for (const [handle, entry] of this.#nodeRoutes) {\n if (entry.path === path && entry.method === method) {\n this.#nodeRoutes.delete(handle);\n }\n }\n const handle = this.#nextHandle++;\n this.#nodeRoutes.set(handle, {\n path,\n method,\n matcher: match(normalizePath(path), { end: !prefix }),\n handler,\n rawBody,\n });\n return { dispose: () => this.#nodeRoutes.delete(handle) };\n }\n\n mountRawMiddleware(middleware: unknown): void {\n if (this.#instance) {\n // @fastify/middie is always registered, so .use() is available post-listen.\n (\n this.#instance as FastifyInstance & {\n use(middleware: unknown): FastifyInstance;\n }\n ).use(middleware);\n } else {\n this.#setupOps.push({ kind: \"middie\", middleware });\n }\n }\n\n setupSentryErrorHandler(sentry: object): void {\n if (!this.#instance) return;\n const s = sentry as {\n setupFastifyErrorHandler(app: FastifyInstance): void;\n };\n s.setupFastifyErrorHandler(this.#instance);\n }\n\n async listen(port: number, tls?: TlsOptions): Promise<http.Server> {\n let httpServer: 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) throw new Error(\"Invalid certificate generated\");\n httpServer = https.createServer({ cert, key });\n } else if (tls && \"keyPath\" in tls) {\n const cwd = process.cwd();\n httpServer = https.createServer({\n key: fs.readFileSync(nodePath.join(cwd, tls.keyPath)),\n cert: fs.readFileSync(nodePath.join(cwd, tls.certPath)),\n });\n } else if (tls && \"cert\" in tls) {\n httpServer = https.createServer({ cert: tls.cert, key: tls.key });\n } else {\n httpServer = http.createServer();\n }\n\n const corsOp = this.#setupOps.find(\n (op): op is Extract<SetupOp, { kind: \"cors\" }> => op.kind === \"cors\",\n );\n const bodyLimit = corsOp?.bodyLimit ?? 52_428_800;\n\n const instance = Fastify({\n serverFactory: (handler) => {\n httpServer.on(\"request\", handler);\n return httpServer;\n },\n bodyLimit,\n logger: false,\n });\n\n this.#instance = instance;\n\n // Always register middie first so .use() is available post-listen.\n await instance.register(fastifyMiddie);\n await instance.register(fastifyFormbody);\n\n for (const op of this.#setupOps) {\n if (op.kind === \"cors\") {\n await instance.register(\n fastifyCors,\n op.options as Parameters<typeof fastifyCors>[1],\n );\n } else {\n (\n instance as FastifyInstance & {\n use(middleware: unknown): FastifyInstance;\n }\n ).use(op.middleware);\n }\n }\n\n // Raw routes are claimed here, in the earliest hook there is: Fastify\n // parses the body before the handler runs, and it 415s an unknown content\n // type outright, so a route that needs the octets as sent cannot wait for\n // dispatch. `hijack()` takes the reply out of Fastify's lifecycle and the\n // handler owns the socket from here.\n instance.addHook(\"onRequest\", (req, reply, done) => {\n const claimed = this.#matchNodeRoute(req, true);\n if (!claimed) {\n done();\n return;\n }\n (req.raw as http.IncomingMessage & { params?: ParamData }).params =\n claimed.params;\n reply.hijack();\n claimed.route.handler(req.raw, reply.raw, undefined);\n });\n\n // Single catch-all route — all dispatching is done via the Maps above so\n // that routes registered after listen() are picked up automatically.\n // OPTIONS is excluded because @fastify/cors registers its own OPTIONS /*\n // handler for preflight; including it here would cause a duplicate-route\n // conflict at startup.\n instance.route({\n method: [\"DELETE\", \"GET\", \"HEAD\", \"PATCH\", \"POST\", \"PUT\"],\n url: \"/*\",\n handler: (req, reply) => this.#dispatch(req, reply),\n });\n\n await instance.ready();\n\n return new Promise<http.Server>((resolve, reject) => {\n httpServer.once(\"error\", reject);\n httpServer.listen(port, () => {\n httpServer.off(\"error\", reject);\n resolve(httpServer);\n });\n });\n }\n\n /**\n * Finds a node route for this request. `raw` selects which half of the\n * registry to consider: raw routes are claimed in the onRequest hook, the\n * rest in the catch-all handler once the body is parsed.\n */\n #matchNodeRoute(\n req: FastifyRequest,\n raw: boolean,\n ): { route: NodeEntry; params: ParamData } | undefined {\n const pathname = new URL(req.url, \"http://localhost\").pathname;\n const method = req.method.toUpperCase();\n for (const entry of this.#nodeRoutes.values()) {\n if (entry.rawBody !== raw) continue;\n if (entry.method !== method) continue;\n const result = entry.matcher(pathname);\n if (result) return { route: entry, params: result.params };\n }\n return undefined;\n }\n\n #dispatch(\n req: FastifyRequest,\n reply: FastifyReply,\n ): void | Promise<FastifyReply> {\n const pathname = new URL(req.url, \"http://localhost\").pathname;\n const method = req.method.toUpperCase() as\n | \"DELETE\"\n | \"GET\"\n | \"HEAD\"\n | \"PATCH\"\n | \"POST\"\n | \"PUT\";\n\n // 1. Node routes — path-to-regexp match + method, handler manages raw\n // response. Attach decoded params onto `req.raw` so downstream handlers\n // can read them via the same `req.params` API the Express adapter exposes.\n const node = this.#matchNodeRoute(req, false);\n if (node) {\n (req.raw as http.IncomingMessage & { params?: ParamData }).params =\n node.params;\n reply.hijack();\n node.route.handler(req.raw, reply.raw, req.body);\n return;\n }\n\n // 2. GET-specific routes (health, explorer, etc.).\n if (method === \"GET\") {\n for (const entry of this.#getRoutes.values()) {\n if (entry.matcher(pathname)) {\n return this.#serveGetEntry(entry, req, reply);\n }\n }\n }\n\n // 3. Fetch routes (GraphQL handlers, SSE, etc.).\n // Iterate in reverse so that the last-mounted handler wins when the same\n // path is mounted more than once (e.g. supergraph remount after reload).\n for (const entry of [...this.#fetchRoutes.values()].reverse()) {\n if (entry.matcher(pathname)) {\n return serveFetchHandler(entry.handler, req, reply);\n }\n }\n\n void reply.status(404).send({\n message: `Route ${req.method}:${pathname} not found`,\n error: \"Not Found\",\n statusCode: 404,\n });\n }\n\n async #serveGetEntry(\n entry: GetEntry,\n req: FastifyRequest,\n reply: FastifyReply,\n ): Promise<FastifyReply> {\n const url = buildUrl(req);\n const headers = buildHeaders(req);\n const fetchReq = new Request(url, { method: \"GET\", headers });\n const response = await entry.handler(fetchReq);\n writeResponse(reply, response);\n if (response.body === null) {\n return reply.send(await response.text());\n }\n // Stream the body instead of awaiting .text(): a stream-backed body\n // (e.g. graphql-sse) only closes when the subscription completes, so\n // awaiting would hang the request. Fastify tears the source down on\n // client disconnect and routes pre-header stream errors to the\n // error handler.\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 return reply.send(Readable.fromWeb(bodyStream));\n }\n}\n\nasync function serveFetchHandler(\n handler: FetchHandler,\n req: FastifyRequest,\n reply: FastifyReply,\n): Promise<FastifyReply> {\n const url = buildUrl(req);\n const headers = buildHeaders(req);\n let body: string | undefined;\n if (req.method !== \"GET\" && req.method !== \"HEAD\" && req.body !== undefined) {\n body = JSON.stringify(req.body);\n }\n const response = await handler(\n new Request(url, { method: req.method, headers, body }),\n );\n writeResponse(reply, response);\n if (response.body === null) {\n return reply.send(await response.text());\n }\n // Stream the body instead of awaiting .text(): a stream-backed body\n // (e.g. graphql-sse) only closes when the subscription completes, so\n // awaiting would hang the request. Fastify tears the source down on\n // client disconnect and routes pre-header stream errors to the\n // error handler.\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 return reply.send(Readable.fromWeb(bodyStream));\n}\n\nfunction buildUrl(req: FastifyRequest): string {\n const protocol = req.protocol;\n const host = req.headers.host ?? \"localhost\";\n return `${protocol}://${host}${req.url}`;\n}\n\nfunction buildHeaders(req: FastifyRequest): 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 return headers;\n}\n\nfunction writeResponse(reply: FastifyReply, response: Response): void {\n reply.statusCode = response.status;\n response.headers.forEach((value, key) => {\n reply.header(key, value);\n });\n}\n\nexport function createFastifyHttpAdapter(): { adapter: IHttpAdapter } {\n return { adapter: new FastifyHttpAdapter() };\n}\n"],"names":["#fetchRoutes","#getRoutes","#nodeRoutes","#setupOps","#instance","#nextHandle","nodePath","#matchNodeRoute","#dispatch","#serveGetEntry"],"mappings":"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","debug_id":"07c62958-83d2-55bc-b138-149275988013"}
@@ -1,23 +0,0 @@
1
- //#region src/graphql/gateway/path-normalize.ts
2
- /**
3
- * Normalises a route path for path-to-regexp v8:
4
- * - Collapses duplicate slashes (e.g. "//explorer" → "/explorer")
5
- * - Converts legacy optional-param syntax "/:param?" → "{/:param}". The
6
- * slash must move inside the group: in p-r v8 a group whose content
7
- * begins with "/" is what makes the slash and the parameter optional
8
- * together, while a literal "/" left in front of the group compiles to
9
- * a pattern that matches nothing (and v8 rejects a bare ":param?").
10
- *
11
- * Shared by both http adapters so registry dispatch matches the same path
12
- * shapes regardless of which framework is in use.
13
- */
14
-
15
- !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]="f73d6dcb-dc2c-52e3-abd2-3653df07260f")}catch(e){}}();
16
- function normalizePath(path) {
17
- return path.replace(/\/+/g, "/").replace(/\/:(\w+)\?/g, "{/:$1}");
18
- }
19
- //#endregion
20
- export { normalizePath as t };
21
-
22
- //# sourceMappingURL=path-normalize-BOQwY9wR.mjs.map
23
- //# debugId=f73d6dcb-dc2c-52e3-abd2-3653df07260f
@@ -1 +0,0 @@
1
- {"version":3,"file":"path-normalize-BOQwY9wR.mjs","sources":["../src/graphql/gateway/path-normalize.ts"],"sourcesContent":["/**\n * Normalises a route path for path-to-regexp v8:\n * - Collapses duplicate slashes (e.g. \"//explorer\" → \"/explorer\")\n * - Converts legacy optional-param syntax \"/:param?\" → \"{/:param}\". The\n * slash must move inside the group: in p-r v8 a group whose content\n * begins with \"/\" is what makes the slash and the parameter optional\n * together, while a literal \"/\" left in front of the group compiles to\n * a pattern that matches nothing (and v8 rejects a bare \":param?\").\n *\n * Shared by both http adapters so registry dispatch matches the same path\n * shapes regardless of which framework is in use.\n */\nexport function normalizePath(path: string): string {\n return path.replace(/\\/+/g, \"/\").replace(/\\/:(\\w+)\\?/g, \"{/:$1}\");\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAYA,SAAgB,cAAc,MAAsB;AAClD,QAAO,KAAK,QAAQ,QAAQ,IAAI,CAAC,QAAQ,eAAe,SAAS","debug_id":"f73d6dcb-dc2c-52e3-abd2-3653df07260f"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-DcYyNcHJ.d.mts","names":[],"sources":["../src/packages/types.ts"],"mappings":";;;;;UAUiB,cAAA;EACf,IAAA;EACA,kBAAA,CACE,UAAA,UACA,SAAA,aACC,OAAA,CAAQ,mBAAA;EALkB;;;;EAU7B,oBAAA,EACE,UAAA,WACC,OAAA,CAAQ,eAAA;EACX,aAAA,CACE,UAAA,UACA,SAAA,aACC,OAAA,CAAQ,aAAA;EACX,cAAA,CACE,UAAA,UACA,SAAA,aACC,OAAA,CAAQ,uBAAA;AAAA;AAAA,UAGI,oBAAA;EACf,QAAA;AAAA;AAAA,UAGe,0BAAA,SAAmC,cAAA;EAClD,sBAAA,EACE,UAAA,UACA,OAAA,GAAU,cAAA,EAAgB,mBAAA,aAC1B,OAAA,GAAU,oBAAA;EAEZ,iBAAA,EACE,UAAA,UACA,OAAA,GAAU,SAAA,EAAW,aAAA,aACrB,OAAA,GAAU,oBAAA;EAEZ,kBAAA,EACE,UAAA,UACA,OAAA,GAAU,UAAA,EAAY,uBAAA,kBACtB,OAAA,GAAU,oBAAA;AAAA;AAAA,UAIG,eAAA;EACf,sBAAA,CACE,OAAA,GAAU,cAAA,EAAgB,MAAA,SAAe,mBAAA;EArC3C;;;;EA2CA,aAAA,CAAc,WAAA;AAAA;AAAA,KAGJ,qBAAA;EACV,MAAA,GAAS,OAAA;AAAA;AAAA,KAGC,sBAAA;EACV,QAAA;EACA,UAAA;AAAA;AAAA,KAWU,oBAAA;EACV,cAAA,EAAgB,mBAAA;EAChB,gBAAA,EAAkB,eAAA;EAClB,SAAA,EAAW,GAAA,SAAY,aAAA;EACvB,UAAA,EAAY,GAAA,SAAY,uBAAA;AAAA"}