@_linked/server 3.12.1 → 3.14.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 (44) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/lib/esm/backend.d.ts +23 -5
  3. package/lib/esm/backend.js +116 -25
  4. package/lib/esm/backend.js.map +1 -1
  5. package/lib/esm/shapes/LincdAPI.d.ts +1 -1
  6. package/lib/esm/shapes/LincdAPI.js +43 -7
  7. package/lib/esm/shapes/LincdAPI.js.map +1 -1
  8. package/lib/esm/shapes/LinkedServer.d.ts +59 -39
  9. package/lib/esm/shapes/LinkedServer.js +158 -93
  10. package/lib/esm/shapes/LinkedServer.js.map +1 -1
  11. package/lib/esm/shapes/quadstores/RemoteDataset.d.ts +52 -20
  12. package/lib/esm/shapes/quadstores/RemoteDataset.js +134 -32
  13. package/lib/esm/shapes/quadstores/RemoteDataset.js.map +1 -1
  14. package/lib/esm/utils/adminChannel.d.ts +23 -51
  15. package/lib/esm/utils/adminChannel.js +50 -38
  16. package/lib/esm/utils/adminChannel.js.map +1 -1
  17. package/lib/esm/utils/effectiveRoutes.d.ts +6 -0
  18. package/lib/esm/utils/effectiveRoutes.js +2 -1
  19. package/lib/esm/utils/effectiveRoutes.js.map +1 -1
  20. package/lib/esm/utils/forwardedTransactions.d.ts +46 -0
  21. package/lib/esm/utils/forwardedTransactions.js +155 -0
  22. package/lib/esm/utils/forwardedTransactions.js.map +1 -0
  23. package/lib/esm/utils/graphTargets.d.ts +42 -17
  24. package/lib/esm/utils/graphTargets.js +62 -69
  25. package/lib/esm/utils/graphTargets.js.map +1 -1
  26. package/lib/esm/utils/linkedDependencies.d.ts +53 -7
  27. package/lib/esm/utils/linkedDependencies.js +130 -12
  28. package/lib/esm/utils/linkedDependencies.js.map +1 -1
  29. package/lib/esm/utils/ontologySync.d.ts +55 -31
  30. package/lib/esm/utils/ontologySync.js +94 -42
  31. package/lib/esm/utils/ontologySync.js.map +1 -1
  32. package/lib/esm/utils/queryPlane.d.ts +13 -0
  33. package/lib/esm/utils/queryPlane.js +49 -2
  34. package/lib/esm/utils/queryPlane.js.map +1 -1
  35. package/lib/esm/utils/reloadSource.js +1 -1
  36. package/lib/esm/utils/reloadSource.js.map +1 -1
  37. package/lib/esm/utils/serverTransactions.d.ts +22 -0
  38. package/lib/esm/utils/serverTransactions.js +81 -0
  39. package/lib/esm/utils/serverTransactions.js.map +1 -0
  40. package/lib/esm/utils/syncShapes.d.ts +123 -6
  41. package/lib/esm/utils/syncShapes.js +166 -35
  42. package/lib/esm/utils/syncShapes.js.map +1 -1
  43. package/package.json +4 -4
  44. package/readme.md +158 -38
@@ -1,8 +1,9 @@
1
1
  /**
2
- * The shape sync, as the server runs it at boot and when the host asks for a re-sync
3
- * (`POST /admin/sync-shapes`): core's `syncShapeGraphs` writes each package's shapes into its own
4
- * named graph of the app's default dataset (`{package IRI}/graph/shapes`, a `ShapesGraph` record
5
- * in the graph registry), skipped when the stored content hash matches, and the app's generated
2
+ * The shape sync, as the server runs it at boot, and the graph content it would write
3
+ * (`POST /admin/graph-content`, {@link graphContentOf}): core's `syncShapeGraphsRouted` writes each package's shapes into its
4
+ * own named graph (`{package IRI}/graph/shapes`, a `ShapesGraph` record in the graph registry) of
5
+ * every dataset the storage routing needs them in (see "Which datasets the syncs write to" in
6
+ * core's README), skipped when the stored content hash matches, and the app's generated
6
7
  * single-owner shapes into the app's own shape graph, `{DATA_ROOT}/graph/shapes`. Shapes an
7
8
  * earlier sync wrote into the default graph are removed there once their package's graph holds
8
9
  * them. A store without graph queries gets core's default-graph shape sync instead.
@@ -39,8 +40,11 @@ export async function loadShapeGraphCore() {
39
40
  const sync = await import('@_linked/core/shapes/syncShapeGraphs');
40
41
  const turtle = await import('@_linked/core/shapes/shapesToTurtle');
41
42
  const graphs = await import('@_linked/core/shapes/NamedGraph');
43
+ const targets = await import('@_linked/core/shapes/syncTargets');
42
44
  return {
43
45
  syncShapeGraphs: (ds, options) => sync.syncShapeGraphs(ds, options),
46
+ syncShapeGraphsRouted: (options) => targets.syncShapeGraphsRouted(options),
47
+ graphContent: (options) => targets.graphContent(options),
44
48
  packagesWithShapes: () => turtle.packagesWithShapes(),
45
49
  shapesGraphFor: (packageName) => graphs.ShapesGraph.iriFor(packageName),
46
50
  };
@@ -101,11 +105,23 @@ export function viteShapesTurtleGenerator(vite) {
101
105
  }
102
106
  const list = (names) => (names.length ? names.join(', ') : 'none');
103
107
  /**
104
- * Sync the registered shapes into `ds`, one shape graph per package (see the module doc), and log
105
- * one line naming what was written and skipped, the graphs written, the packages without
106
- * `shapes.ttl` and the default-graph shapes removed. Throws when the sync fails.
108
+ * The head of a sync's log line: the packages written, then how many were unchanged (`skipped`
109
+ * in the syncs' results): `written a, b; 17 unchanged`, `written a, b`, or `19 unchanged`.
110
+ */
111
+ export function writtenAndUnchanged(written, unchanged) {
112
+ const parts = written.length ? [`written ${written.join(', ')}`] : [];
113
+ if (unchanged.length || !written.length)
114
+ parts.push(`${unchanged.length} unchanged`);
115
+ return parts.join('; ');
116
+ }
117
+ /** An app graph's status in a log line: core's `skipped` is an unchanged graph. */
118
+ const appGraphStatus = (status) => (status === 'skipped' ? 'unchanged' : status);
119
+ /**
120
+ * Where each registered package's Turtle comes from ({@link shapeTurtleSource}) and the
121
+ * `turtleFor` the syncs read it through. Shared by the syncs and the graph content endpoint, so
122
+ * both see the same bytes.
107
123
  */
108
- export async function syncShapeGraphsInto(ds, { core, orphanScope, isOwn, dev, packageDirOf, generate, appGraph, appPackage, read = readShapesTurtle, log = console.log, warn = console.warn, }) {
124
+ export function shapeTurtleSources({ core, isOwn, dev, packageDirOf, generate, read = readShapesTurtle, warn = console.warn, }) {
109
125
  const sources = new Map();
110
126
  for (const name of core.packagesWithShapes()) {
111
127
  sources.set(name, shapeTurtleSource(name, { own: isOwn(name), dev, packageDir: packageDirOf(name), read }));
@@ -125,32 +141,36 @@ export async function syncShapeGraphsInto(ds, { core, orphanScope, isOwn, dev, p
125
141
  return undefined;
126
142
  }
127
143
  };
128
- const result = await core.syncShapeGraphs(ds, {
129
- orphanScope,
130
- // A package without Turtle is left out: core would generate it otherwise.
144
+ return {
145
+ sources,
146
+ noFile,
131
147
  ...(noFile.length ? { packages: [...sources.keys()].filter((n) => !noFile.includes(n)) } : {}),
132
148
  turtleFor,
133
- ...(appGraph ? { appShapes: { graph: appGraph, ...(appPackage ? { package: appPackage } : {}) } } : {}),
134
- });
135
- // A package core neither wrote nor skipped got no Turtle at all: generation produced nothing
136
- // (in dev, the server's core may not hold the source shapes the dev loader registered). The
137
- // default-graph sync (a store without graph queries) reports no packages, so it is not checked.
138
- const covered = new Set([...result.written, ...result.skipped]);
139
- const notGenerated = result.defaultGraph !== undefined
140
- ? []
141
- : [...sources.keys()].filter((n) => !noFile.includes(n) && !covered.has(n));
149
+ };
150
+ }
151
+ /**
152
+ * The packages with a Turtle source that no run covered (their generation gave nothing), with one
153
+ * warning naming them. None when the shapes went into the default graph.
154
+ */
155
+ function notGeneratedIn(results, { sources, noFile }, warn) {
156
+ if (results.some((r) => r.defaultGraph !== undefined))
157
+ return [];
158
+ const covered = new Set(results.flatMap((r) => [...r.written, ...r.skipped]));
159
+ const notGenerated = [...sources.keys()].filter((n) => !noFile.includes(n) && !covered.has(n)).sort();
142
160
  if (notGenerated.length) {
143
- warn(`[LinkedServer] no shapes could be generated for ${list(notGenerated.sort())}, so ` +
161
+ warn(`[LinkedServer] no shapes could be generated for ${list(notGenerated)}, so ` +
144
162
  `${notGenerated.length === 1 ? 'it has' : 'they have'} no shape graph this sync`);
145
163
  }
164
+ return notGenerated;
165
+ }
166
+ /** One sync's report (one dataset), from core's result. */
167
+ function reportOf(result, core, { noFile }, appGraph, notGenerated) {
146
168
  const withoutTurtle = [...noFile, ...notGenerated].sort();
147
- // A shared graph (the global `shapeGraph` is an IRI) holds every package and the app's shapes.
148
- const shared = result.target && result.target !== 'package' && result.target !== 'default' ? result.target : undefined;
169
+ const shared = sharedTarget(result);
149
170
  const report = {
150
171
  written: result.written,
151
172
  skipped: result.skipped,
152
173
  pruned: result.pruned,
153
- // A shared graph is written whole or not at all: listed when the run wrote anything into it.
154
174
  graphs: shared
155
175
  ? result.written.length || result.appGraph === 'written' || result.pruned.length
156
176
  ? [shared]
@@ -170,28 +190,31 @@ export async function syncShapeGraphsInto(ds, { core, orphanScope, isOwn, dev, p
170
190
  }
171
191
  if (result.defaultGraph !== undefined)
172
192
  report.defaultGraph = result.defaultGraph;
193
+ return report;
194
+ }
195
+ const sharedTarget = (result) => result.target && result.target !== 'package' && result.target !== 'default' ? result.target : undefined;
196
+ /** Log one sync's report; `where` names the dataset when a routed sync wrote into several. */
197
+ function logReport(report, orphanScope, where, log, warn) {
198
+ const { withoutTurtle } = report;
199
+ const shared = sharedTarget(report);
173
200
  if (report.defaultGraph !== undefined) {
174
- const why = result.target === 'default' && !result.fallback
175
- ? "shapeGraph is 'default'"
176
- : 'the store has no graph queries';
177
- log(`[LinkedServer] shape sync (default graph: ${why}): ${report.defaultGraph} shape(s) written`);
201
+ const why = report.target === 'default' && !report.fallback ? "shapeGraph is 'default'" : 'the store has no graph queries';
202
+ log(`[LinkedServer] shape sync${where} (default graph: ${why}): ${report.defaultGraph} shape(s) written`);
178
203
  }
179
204
  else if (shared) {
180
- log(`[LinkedServer] shape graph sync (one shared graph <${shared}>): written ${list(report.written)}; ` +
181
- `skipped ${list(report.skipped)}` +
182
- (report.appGraph ? `; app shapes ${report.appGraph.status}` : '') +
205
+ log(`[LinkedServer] shape graph sync${where} (one shared graph <${shared}>): ` +
206
+ writtenAndUnchanged(report.written, report.skipped) +
207
+ (report.appGraph ? `; app shapes ${appGraphStatus(report.appGraph.status)}` : '') +
183
208
  (report.pruned.length ? `; dropped from the graph ${list(report.pruned)}` : '') +
184
209
  (withoutTurtle.length ? `; no shapes.ttl (not in the graph): ${list(withoutTurtle)}` : ''));
185
- // Unlike package graphs, which stay when a package goes missing, the shared graph is rebuilt
186
- // from the packages the run covers.
187
210
  if (withoutTurtle.length) {
188
211
  warn(`[LinkedServer] the shared shape graph <${shared}> holds no shapes of ${list(withoutTurtle)}: ` +
189
212
  'a package without Turtle in a run is left out of the rebuilt graph');
190
213
  }
191
214
  }
192
215
  else {
193
- log(`[LinkedServer] shape graph sync: written ${list(report.written)}; skipped ${list(report.skipped)}` +
194
- (report.appGraph ? `; app graph ${report.appGraph.status}` : '; no app graph (DATA_ROOT not set)') +
216
+ log(`[LinkedServer] shape graph sync${where}: ${writtenAndUnchanged(report.written, report.skipped)}` +
217
+ (report.appGraph ? `; app graph ${appGraphStatus(report.appGraph.status)}` : '; no app graph (DATA_ROOT not set)') +
195
218
  (report.graphs.length ? `; graphs written ${list(report.graphs)}` : '') +
196
219
  (orphanScope === 'all' ? `; pruned ${list(report.pruned)}` : '') +
197
220
  (report.cleaned ? `; ${report.cleaned} default-graph shape(s) removed` : '') +
@@ -201,6 +224,85 @@ export async function syncShapeGraphsInto(ds, { core, orphanScope, isOwn, dev, p
201
224
  warn('[LinkedServer] orphaned shape graphs were not pruned: core prunes only when the sync covers ' +
202
225
  `every registered package, and ${list(withoutTurtle)} has no Turtle`);
203
226
  }
227
+ }
228
+ /**
229
+ * Sync the registered shapes into `ds`, one shape graph per package (see the module doc), and log
230
+ * one line naming what was written and skipped, the graphs written, the packages without
231
+ * `shapes.ttl` and the default-graph shapes removed. Throws when the sync fails. The server's boot
232
+ * follows the routing instead ({@link syncRoutedShapeGraphs}); this syncs one given dataset.
233
+ */
234
+ export async function syncShapeGraphsInto(ds, options) {
235
+ const { core, orphanScope, appGraph, appPackage, log = console.log, warn = console.warn } = options;
236
+ const turtle = shapeTurtleSources(options);
237
+ const result = await core.syncShapeGraphs(ds, {
238
+ orphanScope,
239
+ ...(turtle.packages ? { packages: turtle.packages } : {}),
240
+ turtleFor: turtle.turtleFor,
241
+ ...(appGraph ? { appShapes: { graph: appGraph, ...(appPackage ? { package: appPackage } : {}) } } : {}),
242
+ });
243
+ const report = reportOf(result, core, turtle, appGraph, notGeneratedIn([result], turtle, warn));
244
+ logReport(report, orphanScope, '', log, warn);
245
+ return report;
246
+ }
247
+ const union = (lists) => [...new Set(lists.flat())].sort();
248
+ /**
249
+ * Sync the registered shapes where the routing needs them (core's `syncShapeGraphsRouted`): each
250
+ * package's shape graph into every dataset its shapes and the shape shapes route to, the app graph
251
+ * into the datasets of the shapes declaring `contains` properties, and the graphs routing no longer
252
+ * sends to the default dataset dropped there. Logs one line per dataset (as
253
+ * {@link syncShapeGraphsInto} does, naming the dataset when there are several) and one per graph
254
+ * dropped or left behind. The answer's top-level fields join the datasets'. Throws, after the other
255
+ * datasets synced, when one failed, naming each.
256
+ */
257
+ export async function syncRoutedShapeGraphs(options) {
258
+ var _a;
259
+ const { core, orphanScope, appGraph, appPackage, log = console.log, warn = console.warn } = options;
260
+ if (!core.syncShapeGraphsRouted) {
261
+ throw new Error("@_linked/core has no syncShapeGraphsRouted: this server needs the core it was built with");
262
+ }
263
+ const turtle = shapeTurtleSources(options);
264
+ const routed = await core.syncShapeGraphsRouted({
265
+ orphanScope,
266
+ ...(turtle.packages ? { packages: turtle.packages } : {}),
267
+ turtleFor: turtle.turtleFor,
268
+ ...(appGraph ? { appShapes: { graph: appGraph, ...(appPackage ? { package: appPackage } : {}) } } : {}),
269
+ });
270
+ const several = routed.targets.length > 1;
271
+ const notGenerated = notGeneratedIn(routed.targets.map((t) => t.result), turtle, warn);
272
+ const datasets = routed.targets.map(({ dataset, result }) => {
273
+ const report = reportOf(result, core, turtle, appGraph, notGenerated);
274
+ logReport(report, orphanScope, several ? ` in ${dataset}` : '', log, warn);
275
+ return { dataset, ...report };
276
+ });
277
+ for (const { dataset, package: name, graph } of routed.pruned) {
278
+ log(`[LinkedServer] shape graph sync: dropped <${graph}> (${name}) from ${dataset}: routing sends its shapes elsewhere`);
279
+ }
280
+ const first = datasets[0];
281
+ const report = {
282
+ written: union(datasets.map((d) => d.written)),
283
+ skipped: union(datasets.map((d) => d.skipped)).filter((n) => !datasets.some((d) => d.written.includes(n))),
284
+ pruned: union(datasets.map((d) => d.pruned)),
285
+ graphs: union(datasets.map((d) => d.graphs)),
286
+ withoutTurtle: union(datasets.map((d) => d.withoutTurtle)),
287
+ cleaned: datasets.reduce((n, d) => n + d.cleaned, 0),
288
+ datasets,
289
+ prunedGraphs: routed.pruned,
290
+ leftovers: routed.leftovers,
291
+ };
292
+ const app = (_a = datasets.find((d) => { var _a; return ((_a = d.appGraph) === null || _a === void 0 ? void 0 : _a.status) === 'written'; })) !== null && _a !== void 0 ? _a : datasets.find((d) => d.appGraph);
293
+ if (app === null || app === void 0 ? void 0 : app.appGraph)
294
+ report.appGraph = app.appGraph;
295
+ if (datasets.some((d) => d.defaultGraph !== undefined)) {
296
+ report.defaultGraph = datasets.reduce((n, d) => { var _a; return n + ((_a = d.defaultGraph) !== null && _a !== void 0 ? _a : 0); }, 0);
297
+ }
298
+ if (first === null || first === void 0 ? void 0 : first.target)
299
+ report.target = first.target;
300
+ if (datasets.some((d) => d.fallback))
301
+ report.fallback = true;
302
+ if (routed.failed.length) {
303
+ throw new Error(`the shape sync failed in ${routed.failed.map((f) => `${f.dataset}: ${f.error}`).join('; ')}` +
304
+ (datasets.length ? ` (synced: ${datasets.map((d) => d.dataset).join(', ')})` : ''));
305
+ }
204
306
  return report;
205
307
  }
206
308
  /**
@@ -219,4 +321,33 @@ export async function materializeShapes(ds, syncShapes, { env = process.env, log
219
321
  `${thunks.length} operation(s)`);
220
322
  return { count: thunks.length, orphanScope };
221
323
  }
324
+ /**
325
+ * The content of the app's graphs as the `'package'`-mode syncs would write them, writing nothing
326
+ * (core's `graphContent`), with the server's choice of each package's Turtle
327
+ * ({@link shapeTurtleSources}): an installed package without `shapes.ttl` gets no shape graph here
328
+ * either (it is listed in `withoutTurtle`), exactly as the sync leaves it out. `packages` limits
329
+ * the answer; without it every registered package with shapes or ontology data. The app graph is
330
+ * answered when `appGraph` (`{DATA_ROOT}/graph/shapes`) is given.
331
+ */
332
+ export async function graphContentOf(options) {
333
+ const { core, packages, appGraph } = options;
334
+ if (!core.graphContent) {
335
+ throw new Error('@_linked/core has no graphContent: this server needs the core it was built with');
336
+ }
337
+ const turtle = shapeTurtleSources(options);
338
+ const content = await core.graphContent({
339
+ ...(packages ? { packages } : {}),
340
+ turtleFor: turtle.turtleFor,
341
+ ...(appGraph ? { appShapes: { graph: appGraph } } : {}),
342
+ });
343
+ const noFile = new Set(turtle.noFile);
344
+ const withoutTurtle = new Set(content.withoutTurtle);
345
+ for (const entry of content.packages) {
346
+ if (!noFile.has(entry.name))
347
+ continue;
348
+ delete entry.shapes;
349
+ withoutTurtle.add(entry.name);
350
+ }
351
+ return { ...content, withoutTurtle: [...withoutTurtle].sort() };
352
+ }
222
353
  //# sourceMappingURL=syncShapes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"syncShapes.js","sourceRoot":"","sources":["../../../src/utils/syncShapes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The shape sync, as the server runs it at boot and when the host asks for a re-sync\n * (`POST /admin/sync-shapes`): core's `syncShapeGraphs` writes each package's shapes into its own\n * named graph of the app's default dataset (`{package IRI}/graph/shapes`, a `ShapesGraph` record\n * in the graph registry), skipped when the stored content hash matches, and the app's generated\n * single-owner shapes into the app's own shape graph, `{DATA_ROOT}/graph/shapes`. Shapes an\n * earlier sync wrote into the default graph are removed there once their package's graph holds\n * them. A store without graph queries gets core's default-graph shape sync instead.\n *\n * Where a package's Turtle comes from ({@link shapeTurtleSource}):\n * - an installed package: its built `lib/esm/data/shapes.ttl` (written by `linked build`); a\n * package without that file gets no shape graph, and nothing is generated for it;\n * - the app's own packages (the app and its workspace packages): in dev, generated in process\n * from their source shapes, through Vite's loader, so the core the SSR graph registered the\n * shapes on writes them (the same bytes as `packageShapesTurtle`, which `linked build` writes);\n * in a built app, their `lib/esm/data/shapes.ttl` when there is one, else generated in process.\n *\n * Kept apart from `LinkedServer` so the choices and the log can be tested without booting a\n * server.\n */\nimport fs from 'fs';\nimport path from 'path';\n\n/** The orphan policies a booting server may run with. */\nexport type BootOrphanScope = 'all' | 'none';\n\n/**\n * The orphan policy for the shape sync.\n *\n * `'none'` unless the operator sets `LINKED_SYNC_SHAPES_PRUNE_ORPHANS=true`, which drops the\n * shape graph of every package that is no longer registered in this process (never the app's own\n * graph).\n *\n * The registry is routinely a subset of what the dataset holds: shapes are deep-importable one\n * file at a time, an app's backend may import no shapes at all, and an app-data dataset also holds\n * shapes other writers put there. So nothing is pruned by default.\n */\nexport function bootOrphanScope(\n env: Record<string, string | undefined> = process.env,\n): BootOrphanScope {\n return env.LINKED_SYNC_SHAPES_PRUNE_ORPHANS === 'true' ? 'all' : 'none';\n}\n\n/** What core's `syncShapeGraphs` reports (`@_linked/core/shapes/syncShapeGraphs`). */\nexport interface ShapeGraphSyncResult {\n written: string[];\n skipped: string[];\n pruned: string[];\n cleaned: number;\n appGraph?: 'written' | 'skipped' | 'dropped';\n defaultGraph?: number;\n /** The global `shapeGraph` target the run wrote in (core ≥ 2.41): `'package'`, `'default'` or an IRI. */\n target?: string;\n /** Set when a store without graph queries took the default-graph sync instead of `target`. */\n fallback?: true;\n}\n\n/** The subset of core's shape graph API this module calls. */\nexport interface ShapeGraphCore {\n syncShapeGraphs(\n ds: unknown,\n options: {\n orphanScope: BootOrphanScope;\n packages?: string[];\n turtleFor: (packageName: string) => Promise<string | undefined>;\n appShapes?: {graph: string; package?: string};\n },\n ): Promise<ShapeGraphSyncResult>;\n /** Every package with registered shapes (core counted for its built-ins). */\n packagesWithShapes(): string[];\n /** A package's shape graph IRI (`ShapesGraph.iriFor`). */\n shapesGraphFor(packageName: string): string;\n}\n\n/** Import core's shape graph sync. */\nexport async function loadShapeGraphCore(): Promise<ShapeGraphCore> {\n const sync = await import('@_linked/core/shapes/syncShapeGraphs');\n const turtle = await import('@_linked/core/shapes/shapesToTurtle');\n const graphs = await import('@_linked/core/shapes/NamedGraph');\n return {\n syncShapeGraphs: (ds, options) =>\n sync.syncShapeGraphs(ds as Parameters<typeof sync.syncShapeGraphs>[0], options),\n packagesWithShapes: () => turtle.packagesWithShapes(),\n shapesGraphFor: (packageName) => graphs.ShapesGraph.iriFor(packageName),\n };\n}\n\n/** Where `linked build` writes a package's shapes, relative to the package root. */\nexport const SHAPES_TURTLE_FILE = path.join('lib', 'esm', 'data', 'shapes.ttl');\n\n/** A package's built `shapes.ttl`, or undefined when the package root has none. */\nexport function readShapesTurtle(packageDir: string | undefined): string | undefined {\n if (!packageDir) return undefined;\n try {\n return fs.readFileSync(path.join(packageDir, SHAPES_TURTLE_FILE), 'utf-8');\n } catch {\n return undefined;\n }\n}\n\n/** Where one package's Turtle comes from. */\nexport type ShapeTurtleSource =\n | {source: 'file'; text: string}\n | {source: 'generated'}\n | {source: 'none'};\n\n/**\n * Where a registered package's Turtle comes from: in dev an own package is generated; otherwise\n * its built file when it has one; else an own package is generated and an installed one has\n * none (no shape graph, no generation).\n */\nexport function shapeTurtleSource(\n packageName: string,\n {\n own,\n dev,\n packageDir,\n read = readShapesTurtle,\n }: {\n /** Whether the package is the app or one of its workspace packages. */\n own: boolean;\n /** Whether the server runs with Vite (dev). */\n dev: boolean;\n /** The package root, when the server knows it. */\n packageDir: string | undefined;\n read?: (packageDir: string | undefined) => string | undefined;\n },\n): ShapeTurtleSource {\n if (own && dev) return {source: 'generated'};\n const text = read(packageDir);\n if (text !== undefined) return {source: 'file', text};\n return own ? {source: 'generated'} : {source: 'none'};\n}\n\n/**\n * The app's own shape graph, `{DATA_ROOT}/graph/shapes`, or undefined when `DATA_ROOT` is not\n * an absolute IRI.\n */\nexport function appShapesGraph(\n env: Record<string, string | undefined> = process.env,\n): string | undefined {\n const root = env.DATA_ROOT?.trim().replace(/\\/+$/, '');\n if (!root || !/^[a-z][a-z0-9+.-]*:\\/\\/[^/]/i.test(root)) return undefined;\n return `${root}/graph/shapes`;\n}\n\n/**\n * In dev, the generator for the app's own packages: core's `packageShapesTurtle` imported through\n * Vite's `ssrLoadModule`, the core the SSR graph registered the source shapes on. Undefined\n * without Vite.\n */\nexport function viteShapesTurtleGenerator(\n vite: {ssrLoadModule?: (url: string) => Promise<unknown>} | undefined | null,\n): ((packageName: string) => Promise<string | undefined>) | undefined {\n const ssrLoadModule = vite?.ssrLoadModule;\n if (typeof ssrLoadModule !== 'function') return undefined;\n return async (packageName) => {\n const mod = (await ssrLoadModule.call(vite, '@_linked/core/shapes/shapesToTurtle')) as {\n packageShapesTurtle?: (name: string) => string | undefined;\n };\n if (typeof mod?.packageShapesTurtle !== 'function') {\n throw new Error('@_linked/core/shapes/shapesToTurtle has no packageShapesTurtle');\n }\n return mod.packageShapesTurtle(packageName);\n };\n}\n\n/** What one shape sync did, as the boot logs it and `POST /admin/sync-shapes` reports it. */\nexport interface ShapeGraphsReport {\n /** Packages whose shape graph was written, and those left as they were. */\n written: string[];\n skipped: string[];\n /** Packages no longer registered whose shape graph was dropped (`orphanScope: 'all'`). */\n pruned: string[];\n /** The shape graphs written (package graphs, then the app graph), by IRI. */\n graphs: string[];\n /** The app's own shape graph and what the sync did with it; absent without `DATA_ROOT`. */\n appGraph?: {graph: string; status: 'written' | 'skipped' | 'dropped'};\n /**\n * Registered packages with no Turtle, so with no shape graph: an installed package without\n * `shapes.ttl`, or an own package whose shapes could not be generated.\n */\n withoutTurtle: string[];\n /** Shapes an earlier sync had written into the default graph, removed now. */\n cleaned: number;\n /**\n * Set when the shapes went into the default graph (the global `shapeGraph` is `'default'`, or\n * it has no graph queries): the default-graph sync's writes.\n */\n defaultGraph?: number;\n /** The global `shapeGraph` target (`'package'`, `'default'` or a shared graph IRI), when core reports it. */\n target?: string;\n /** Set when the store has no graph queries, so the shapes went into the default graph instead of `target`. */\n fallback?: true;\n}\n\nconst list = (names: string[]) => (names.length ? names.join(', ') : 'none');\n\n/**\n * Sync the registered shapes into `ds`, one shape graph per package (see the module doc), and log\n * one line naming what was written and skipped, the graphs written, the packages without\n * `shapes.ttl` and the default-graph shapes removed. Throws when the sync fails.\n */\nexport async function syncShapeGraphsInto(\n ds: unknown,\n {\n core,\n orphanScope,\n isOwn,\n dev,\n packageDirOf,\n generate,\n appGraph,\n appPackage,\n read = readShapesTurtle,\n log = console.log,\n warn = console.warn,\n }: {\n core: ShapeGraphCore;\n orphanScope: BootOrphanScope;\n /** Whether a package is the app or one of its workspace packages. */\n isOwn: (packageName: string) => boolean;\n /** Whether the server runs with Vite (dev). */\n dev: boolean;\n /** A package's root directory, when the server knows it. */\n packageDirOf: (packageName: string) => string | undefined;\n /**\n * Generates an own package's Turtle (in dev through Vite's loader); undefined, or a result of\n * undefined, leaves the generation to the core that runs the sync.\n */\n generate?: (packageName: string) => Promise<string | undefined>;\n /** The app's own shape graph (`{DATA_ROOT}/graph/shapes`). */\n appGraph?: string;\n /** The app's package name, recorded on its shape graph's record. */\n appPackage?: string;\n read?: (packageDir: string | undefined) => string | undefined;\n log?: (message: string) => void;\n warn?: (message: string, err?: unknown) => void;\n },\n): Promise<ShapeGraphsReport> {\n const sources = new Map<string, ShapeTurtleSource>();\n for (const name of core.packagesWithShapes()) {\n sources.set(name, shapeTurtleSource(name, {own: isOwn(name), dev, packageDir: packageDirOf(name), read}));\n }\n const noFile = [...sources].filter(([, s]) => s.source === 'none').map(([name]) => name);\n\n const turtleFor = async (name: string): Promise<string | undefined> => {\n const source = sources.get(name);\n if (source?.source === 'file') return source.text;\n if (source?.source !== 'generated' || !generate) return undefined;\n try {\n return await generate(name);\n } catch (err) {\n warn(`[LinkedServer] generating the shapes of ${name} through the dev loader failed; trying the server's core instead:`, err);\n return undefined;\n }\n };\n\n const result = await core.syncShapeGraphs(ds, {\n orphanScope,\n // A package without Turtle is left out: core would generate it otherwise.\n ...(noFile.length ? {packages: [...sources.keys()].filter((n) => !noFile.includes(n))} : {}),\n turtleFor,\n ...(appGraph ? {appShapes: {graph: appGraph, ...(appPackage ? {package: appPackage} : {})}} : {}),\n });\n\n // A package core neither wrote nor skipped got no Turtle at all: generation produced nothing\n // (in dev, the server's core may not hold the source shapes the dev loader registered). The\n // default-graph sync (a store without graph queries) reports no packages, so it is not checked.\n const covered = new Set([...result.written, ...result.skipped]);\n const notGenerated =\n result.defaultGraph !== undefined\n ? []\n : [...sources.keys()].filter((n) => !noFile.includes(n) && !covered.has(n));\n if (notGenerated.length) {\n warn(\n `[LinkedServer] no shapes could be generated for ${list(notGenerated.sort())}, so ` +\n `${notGenerated.length === 1 ? 'it has' : 'they have'} no shape graph this sync`,\n );\n }\n const withoutTurtle = [...noFile, ...notGenerated].sort();\n\n // A shared graph (the global `shapeGraph` is an IRI) holds every package and the app's shapes.\n const shared = result.target && result.target !== 'package' && result.target !== 'default' ? result.target : undefined;\n const report: ShapeGraphsReport = {\n written: result.written,\n skipped: result.skipped,\n pruned: result.pruned,\n // A shared graph is written whole or not at all: listed when the run wrote anything into it.\n graphs: shared\n ? result.written.length || result.appGraph === 'written' || result.pruned.length\n ? [shared]\n : []\n : result.written.map((name) => core.shapesGraphFor(name)),\n withoutTurtle,\n cleaned: result.cleaned,\n };\n if (result.target) report.target = result.target;\n if (result.fallback) report.fallback = true;\n if (appGraph && result.appGraph) {\n report.appGraph = {graph: shared ?? appGraph, status: result.appGraph};\n if (result.appGraph === 'written' && !shared) report.graphs.push(appGraph);\n }\n if (result.defaultGraph !== undefined) report.defaultGraph = result.defaultGraph;\n\n if (report.defaultGraph !== undefined) {\n const why =\n result.target === 'default' && !result.fallback\n ? \"shapeGraph is 'default'\"\n : 'the store has no graph queries';\n log(`[LinkedServer] shape sync (default graph: ${why}): ${report.defaultGraph} shape(s) written`);\n } else if (shared) {\n log(\n `[LinkedServer] shape graph sync (one shared graph <${shared}>): written ${list(report.written)}; ` +\n `skipped ${list(report.skipped)}` +\n (report.appGraph ? `; app shapes ${report.appGraph.status}` : '') +\n (report.pruned.length ? `; dropped from the graph ${list(report.pruned)}` : '') +\n (withoutTurtle.length ? `; no shapes.ttl (not in the graph): ${list(withoutTurtle)}` : ''),\n );\n // Unlike package graphs, which stay when a package goes missing, the shared graph is rebuilt\n // from the packages the run covers.\n if (withoutTurtle.length) {\n warn(\n `[LinkedServer] the shared shape graph <${shared}> holds no shapes of ${list(withoutTurtle)}: ` +\n 'a package without Turtle in a run is left out of the rebuilt graph',\n );\n }\n } else {\n log(\n `[LinkedServer] shape graph sync: written ${list(report.written)}; skipped ${list(report.skipped)}` +\n (report.appGraph ? `; app graph ${report.appGraph.status}` : '; no app graph (DATA_ROOT not set)') +\n (report.graphs.length ? `; graphs written ${list(report.graphs)}` : '') +\n (orphanScope === 'all' ? `; pruned ${list(report.pruned)}` : '') +\n (report.cleaned ? `; ${report.cleaned} default-graph shape(s) removed` : '') +\n (withoutTurtle.length ? `; no shapes.ttl (no shape graph): ${list(withoutTurtle)}` : ''),\n );\n }\n if (orphanScope === 'all' && withoutTurtle.length && !shared) {\n warn(\n '[LinkedServer] orphaned shape graphs were not pruned: core prunes only when the sync covers ' +\n `every registered package, and ${list(withoutTurtle)} has no Turtle`,\n );\n }\n return report;\n}\n\n/**\n * @deprecated The default-graph shape sync's callback type; the server now syncs shape graphs with\n * {@link syncShapeGraphsInto}. Kept so code built against an earlier server still compiles.\n */\nexport type SyncShapesFn = (\n ds: unknown,\n options: {orphanScope: BootOrphanScope},\n) => Promise<Array<() => Promise<void>>>;\n\n/**\n * @deprecated Use {@link syncShapeGraphsInto}, which writes each package's shapes into its own\n * shape graph. This runs the old default-graph sync: it plans every registered shape with\n * `syncShapes` (the orphan policy from {@link bootOrphanScope}) and runs the writes in batches\n * of 8. Kept so code built against an earlier server keeps working.\n */\nexport async function materializeShapes(\n ds: unknown,\n syncShapes: SyncShapesFn,\n {\n env = process.env,\n log = console.log,\n }: {\n env?: Record<string, string | undefined>;\n log?: (message: string) => void;\n } = {},\n): Promise<{count: number; orphanScope: BootOrphanScope}> {\n const orphanScope = bootOrphanScope(env);\n const thunks = await syncShapes(ds, {orphanScope});\n for (let i = 0; i < thunks.length; i += 8) {\n await Promise.all(thunks.slice(i, i + 8).map((run) => run()));\n }\n log(\n `[LinkedServer] synced shapes into the default graph with orphanScope '${orphanScope}': ` +\n `${thunks.length} operation(s)`,\n );\n return {count: thunks.length, orphanScope};\n}\n"]}
1
+ {"version":3,"file":"syncShapes.js","sourceRoot":"","sources":["../../../src/utils/syncShapes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The shape sync, as the server runs it at boot, and the graph content it would write\n * (`POST /admin/graph-content`, {@link graphContentOf}): core's `syncShapeGraphsRouted` writes each package's shapes into its\n * own named graph (`{package IRI}/graph/shapes`, a `ShapesGraph` record in the graph registry) of\n * every dataset the storage routing needs them in (see \"Which datasets the syncs write to\" in\n * core's README), skipped when the stored content hash matches, and the app's generated\n * single-owner shapes into the app's own shape graph, `{DATA_ROOT}/graph/shapes`. Shapes an\n * earlier sync wrote into the default graph are removed there once their package's graph holds\n * them. A store without graph queries gets core's default-graph shape sync instead.\n *\n * Where a package's Turtle comes from ({@link shapeTurtleSource}):\n * - an installed package: its built `lib/esm/data/shapes.ttl` (written by `linked build`); a\n * package without that file gets no shape graph, and nothing is generated for it;\n * - the app's own packages (the app and its workspace packages): in dev, generated in process\n * from their source shapes, through Vite's loader, so the core the SSR graph registered the\n * shapes on writes them (the same bytes as `packageShapesTurtle`, which `linked build` writes);\n * in a built app, their `lib/esm/data/shapes.ttl` when there is one, else generated in process.\n *\n * Kept apart from `LinkedServer` so the choices and the log can be tested without booting a\n * server.\n */\nimport fs from 'fs';\nimport path from 'path';\n\n/** The orphan policies a booting server may run with. */\nexport type BootOrphanScope = 'all' | 'none';\n\n/**\n * The orphan policy for the shape sync.\n *\n * `'none'` unless the operator sets `LINKED_SYNC_SHAPES_PRUNE_ORPHANS=true`, which drops the\n * shape graph of every package that is no longer registered in this process (never the app's own\n * graph).\n *\n * The registry is routinely a subset of what the dataset holds: shapes are deep-importable one\n * file at a time, an app's backend may import no shapes at all, and an app-data dataset also holds\n * shapes other writers put there. So nothing is pruned by default.\n */\nexport function bootOrphanScope(\n env: Record<string, string | undefined> = process.env,\n): BootOrphanScope {\n return env.LINKED_SYNC_SHAPES_PRUNE_ORPHANS === 'true' ? 'all' : 'none';\n}\n\n/** What core's `syncShapeGraphs` reports (`@_linked/core/shapes/syncShapeGraphs`). */\nexport interface ShapeGraphSyncResult {\n written: string[];\n skipped: string[];\n pruned: string[];\n cleaned: number;\n appGraph?: 'written' | 'skipped' | 'dropped';\n defaultGraph?: number;\n /** The global `shapeGraph` target the run wrote in (core ≥ 2.41): `'package'`, `'default'` or an IRI. */\n target?: string;\n /** Set when a store without graph queries took the default-graph sync instead of `target`. */\n fallback?: true;\n}\n\n/** The subset of core's shape graph API this module calls. */\nexport interface ShapeGraphCore {\n syncShapeGraphs(\n ds: unknown,\n options: {\n orphanScope: BootOrphanScope;\n packages?: string[];\n turtleFor: (packageName: string) => Promise<string | undefined>;\n appShapes?: {graph: string; package?: string};\n },\n ): Promise<ShapeGraphSyncResult>;\n /**\n * Core's routed sync (`@_linked/core/shapes/syncTargets`): the same options without a dataset;\n * each package's graph goes where the routing needs it. Optional so a test double can leave it out.\n */\n syncShapeGraphsRouted?(options: {\n orphanScope: BootOrphanScope;\n packages?: string[];\n turtleFor: (packageName: string) => Promise<string | undefined>;\n appShapes?: {graph: string; package?: string};\n }): Promise<RoutedSyncReport<ShapeGraphSyncResult>>;\n /**\n * Core's `graphContent` (`@_linked/core/shapes/syncTargets`): what the `'package'`-mode syncs\n * would write, writing nothing. Optional so a test double can leave it out.\n */\n graphContent?(options: {\n packages?: string[];\n turtleFor: (packageName: string) => Promise<string | undefined>;\n appShapes?: {graph: string};\n }): Promise<GraphContents>;\n /** Every package with registered shapes (core counted for its built-ins). */\n packagesWithShapes(): string[];\n /** A package's shape graph IRI (`ShapesGraph.iriFor`). */\n shapesGraphFor(packageName: string): string;\n}\n\n/** Import core's shape graph sync. */\nexport async function loadShapeGraphCore(): Promise<ShapeGraphCore> {\n const sync = await import('@_linked/core/shapes/syncShapeGraphs');\n const turtle = await import('@_linked/core/shapes/shapesToTurtle');\n const graphs = await import('@_linked/core/shapes/NamedGraph');\n const targets = await import('@_linked/core/shapes/syncTargets');\n return {\n syncShapeGraphs: (ds, options) =>\n sync.syncShapeGraphs(ds as Parameters<typeof sync.syncShapeGraphs>[0], options),\n syncShapeGraphsRouted: (options) => targets.syncShapeGraphsRouted(options),\n graphContent: (options) => targets.graphContent(options),\n packagesWithShapes: () => turtle.packagesWithShapes(),\n shapesGraphFor: (packageName) => graphs.ShapesGraph.iriFor(packageName),\n };\n}\n\n/** Where `linked build` writes a package's shapes, relative to the package root. */\nexport const SHAPES_TURTLE_FILE = path.join('lib', 'esm', 'data', 'shapes.ttl');\n\n/** A package's built `shapes.ttl`, or undefined when the package root has none. */\nexport function readShapesTurtle(packageDir: string | undefined): string | undefined {\n if (!packageDir) return undefined;\n try {\n return fs.readFileSync(path.join(packageDir, SHAPES_TURTLE_FILE), 'utf-8');\n } catch {\n return undefined;\n }\n}\n\n/** Where one package's Turtle comes from. */\nexport type ShapeTurtleSource =\n | {source: 'file'; text: string}\n | {source: 'generated'}\n | {source: 'none'};\n\n/**\n * Where a registered package's Turtle comes from: in dev an own package is generated; otherwise\n * its built file when it has one; else an own package is generated and an installed one has\n * none (no shape graph, no generation).\n */\nexport function shapeTurtleSource(\n packageName: string,\n {\n own,\n dev,\n packageDir,\n read = readShapesTurtle,\n }: {\n /** Whether the package is the app or one of its workspace packages. */\n own: boolean;\n /** Whether the server runs with Vite (dev). */\n dev: boolean;\n /** The package root, when the server knows it. */\n packageDir: string | undefined;\n read?: (packageDir: string | undefined) => string | undefined;\n },\n): ShapeTurtleSource {\n if (own && dev) return {source: 'generated'};\n const text = read(packageDir);\n if (text !== undefined) return {source: 'file', text};\n return own ? {source: 'generated'} : {source: 'none'};\n}\n\n/**\n * The app's own shape graph, `{DATA_ROOT}/graph/shapes`, or undefined when `DATA_ROOT` is not\n * an absolute IRI.\n */\nexport function appShapesGraph(\n env: Record<string, string | undefined> = process.env,\n): string | undefined {\n const root = env.DATA_ROOT?.trim().replace(/\\/+$/, '');\n if (!root || !/^[a-z][a-z0-9+.-]*:\\/\\/[^/]/i.test(root)) return undefined;\n return `${root}/graph/shapes`;\n}\n\n/**\n * In dev, the generator for the app's own packages: core's `packageShapesTurtle` imported through\n * Vite's `ssrLoadModule`, the core the SSR graph registered the source shapes on. Undefined\n * without Vite.\n */\nexport function viteShapesTurtleGenerator(\n vite: {ssrLoadModule?: (url: string) => Promise<unknown>} | undefined | null,\n): ((packageName: string) => Promise<string | undefined>) | undefined {\n const ssrLoadModule = vite?.ssrLoadModule;\n if (typeof ssrLoadModule !== 'function') return undefined;\n return async (packageName) => {\n const mod = (await ssrLoadModule.call(vite, '@_linked/core/shapes/shapesToTurtle')) as {\n packageShapesTurtle?: (name: string) => string | undefined;\n };\n if (typeof mod?.packageShapesTurtle !== 'function') {\n throw new Error('@_linked/core/shapes/shapesToTurtle has no packageShapesTurtle');\n }\n return mod.packageShapesTurtle(packageName);\n };\n}\n\n/** What one shape sync did, as the boot logs it. */\nexport interface ShapeGraphsReport {\n /** Packages whose shape graph was written, and those left as they were. */\n written: string[];\n skipped: string[];\n /** Packages no longer registered whose shape graph was dropped (`orphanScope: 'all'`). */\n pruned: string[];\n /** The shape graphs written (package graphs, then the app graph), by IRI. */\n graphs: string[];\n /** The app's own shape graph and what the sync did with it; absent without `DATA_ROOT`. */\n appGraph?: {graph: string; status: 'written' | 'skipped' | 'dropped'};\n /**\n * Registered packages with no Turtle, so with no shape graph: an installed package without\n * `shapes.ttl`, or an own package whose shapes could not be generated.\n */\n withoutTurtle: string[];\n /** Shapes an earlier sync had written into the default graph, removed now. */\n cleaned: number;\n /**\n * Set when the shapes went into the default graph (the global `shapeGraph` is `'default'`, or\n * it has no graph queries): the default-graph sync's writes.\n */\n defaultGraph?: number;\n /** The global `shapeGraph` target (`'package'`, `'default'` or a shared graph IRI), when core reports it. */\n target?: string;\n /** Set when the store has no graph queries, so the shapes went into the default graph instead of `target`. */\n fallback?: true;\n}\n\nconst list = (names: string[]) => (names.length ? names.join(', ') : 'none');\n\n/**\n * The head of a sync's log line: the packages written, then how many were unchanged (`skipped`\n * in the syncs' results): `written a, b; 17 unchanged`, `written a, b`, or `19 unchanged`.\n */\nexport function writtenAndUnchanged(written: string[], unchanged: string[]): string {\n const parts = written.length ? [`written ${written.join(', ')}`] : [];\n if (unchanged.length || !written.length) parts.push(`${unchanged.length} unchanged`);\n return parts.join('; ');\n}\n\n/** An app graph's status in a log line: core's `skipped` is an unchanged graph. */\nconst appGraphStatus = (status: 'written' | 'skipped' | 'dropped') => (status === 'skipped' ? 'unchanged' : status);\n\n/** The options of {@link syncShapeGraphsInto} and {@link syncRoutedShapeGraphs}. */\nexport interface ShapeGraphSyncOptions {\n core: ShapeGraphCore;\n orphanScope: BootOrphanScope;\n /** Whether a package is the app or one of its workspace packages. */\n isOwn: (packageName: string) => boolean;\n /** Whether the server runs with Vite (dev). */\n dev: boolean;\n /** A package's root directory, when the server knows it. */\n packageDirOf: (packageName: string) => string | undefined;\n /**\n * Generates an own package's Turtle (in dev through Vite's loader); undefined, or a result of\n * undefined, leaves the generation to the core that runs the sync.\n */\n generate?: (packageName: string) => Promise<string | undefined>;\n /** The app's own shape graph (`{DATA_ROOT}/graph/shapes`). */\n appGraph?: string;\n /** The app's package name, recorded on its shape graph's record. */\n appPackage?: string;\n read?: (packageDir: string | undefined) => string | undefined;\n log?: (message: string) => void;\n warn?: (message: string, err?: unknown) => void;\n}\n\n/** Where each registered package's Turtle comes from, and the sync options that follow from it. */\nexport interface ShapeTurtleSources {\n sources: Map<string, ShapeTurtleSource>;\n /** Installed packages without `shapes.ttl`: no shape graph, left out of the run. */\n noFile: string[];\n /** The package subset to sync: set only when some package has no Turtle file. */\n packages?: string[];\n turtleFor: (packageName: string) => Promise<string | undefined>;\n}\n\n/**\n * Where each registered package's Turtle comes from ({@link shapeTurtleSource}) and the\n * `turtleFor` the syncs read it through. Shared by the syncs and the graph content endpoint, so\n * both see the same bytes.\n */\nexport function shapeTurtleSources({\n core,\n isOwn,\n dev,\n packageDirOf,\n generate,\n read = readShapesTurtle,\n warn = console.warn,\n}: Pick<ShapeGraphSyncOptions, 'core' | 'isOwn' | 'dev' | 'packageDirOf' | 'generate' | 'read' | 'warn'>): ShapeTurtleSources {\n const sources = new Map<string, ShapeTurtleSource>();\n for (const name of core.packagesWithShapes()) {\n sources.set(name, shapeTurtleSource(name, {own: isOwn(name), dev, packageDir: packageDirOf(name), read}));\n }\n const noFile = [...sources].filter(([, s]) => s.source === 'none').map(([name]) => name);\n const turtleFor = async (name: string): Promise<string | undefined> => {\n const source = sources.get(name);\n if (source?.source === 'file') return source.text;\n if (source?.source !== 'generated' || !generate) return undefined;\n try {\n return await generate(name);\n } catch (err) {\n warn(`[LinkedServer] generating the shapes of ${name} through the dev loader failed; trying the server's core instead:`, err);\n return undefined;\n }\n };\n return {\n sources,\n noFile,\n ...(noFile.length ? {packages: [...sources.keys()].filter((n) => !noFile.includes(n))} : {}),\n turtleFor,\n };\n}\n\n/**\n * The packages with a Turtle source that no run covered (their generation gave nothing), with one\n * warning naming them. None when the shapes went into the default graph.\n */\nfunction notGeneratedIn(\n results: ShapeGraphSyncResult[],\n {sources, noFile}: ShapeTurtleSources,\n warn: (message: string, err?: unknown) => void,\n): string[] {\n if (results.some((r) => r.defaultGraph !== undefined)) return [];\n const covered = new Set(results.flatMap((r) => [...r.written, ...r.skipped]));\n const notGenerated = [...sources.keys()].filter((n) => !noFile.includes(n) && !covered.has(n)).sort();\n if (notGenerated.length) {\n warn(\n `[LinkedServer] no shapes could be generated for ${list(notGenerated)}, so ` +\n `${notGenerated.length === 1 ? 'it has' : 'they have'} no shape graph this sync`,\n );\n }\n return notGenerated;\n}\n\n/** One sync's report (one dataset), from core's result. */\nfunction reportOf(\n result: ShapeGraphSyncResult,\n core: ShapeGraphCore,\n {noFile}: ShapeTurtleSources,\n appGraph: string | undefined,\n notGenerated: string[],\n): ShapeGraphsReport {\n const withoutTurtle = [...noFile, ...notGenerated].sort();\n const shared = sharedTarget(result);\n const report: ShapeGraphsReport = {\n written: result.written,\n skipped: result.skipped,\n pruned: result.pruned,\n graphs: shared\n ? result.written.length || result.appGraph === 'written' || result.pruned.length\n ? [shared]\n : []\n : result.written.map((name) => core.shapesGraphFor(name)),\n withoutTurtle,\n cleaned: result.cleaned,\n };\n if (result.target) report.target = result.target;\n if (result.fallback) report.fallback = true;\n if (appGraph && result.appGraph) {\n report.appGraph = {graph: shared ?? appGraph, status: result.appGraph};\n if (result.appGraph === 'written' && !shared) report.graphs.push(appGraph);\n }\n if (result.defaultGraph !== undefined) report.defaultGraph = result.defaultGraph;\n return report;\n}\n\nconst sharedTarget = (result: {target?: string}): string | undefined =>\n result.target && result.target !== 'package' && result.target !== 'default' ? result.target : undefined;\n\n/** Log one sync's report; `where` names the dataset when a routed sync wrote into several. */\nfunction logReport(\n report: ShapeGraphsReport,\n orphanScope: BootOrphanScope,\n where: string,\n log: (message: string) => void,\n warn: (message: string, err?: unknown) => void,\n): void {\n const {withoutTurtle} = report;\n const shared = sharedTarget(report);\n if (report.defaultGraph !== undefined) {\n const why =\n report.target === 'default' && !report.fallback ? \"shapeGraph is 'default'\" : 'the store has no graph queries';\n log(`[LinkedServer] shape sync${where} (default graph: ${why}): ${report.defaultGraph} shape(s) written`);\n } else if (shared) {\n log(\n `[LinkedServer] shape graph sync${where} (one shared graph <${shared}>): ` +\n writtenAndUnchanged(report.written, report.skipped) +\n (report.appGraph ? `; app shapes ${appGraphStatus(report.appGraph.status)}` : '') +\n (report.pruned.length ? `; dropped from the graph ${list(report.pruned)}` : '') +\n (withoutTurtle.length ? `; no shapes.ttl (not in the graph): ${list(withoutTurtle)}` : ''),\n );\n if (withoutTurtle.length) {\n warn(\n `[LinkedServer] the shared shape graph <${shared}> holds no shapes of ${list(withoutTurtle)}: ` +\n 'a package without Turtle in a run is left out of the rebuilt graph',\n );\n }\n } else {\n log(\n `[LinkedServer] shape graph sync${where}: ${writtenAndUnchanged(report.written, report.skipped)}` +\n (report.appGraph ? `; app graph ${appGraphStatus(report.appGraph.status)}` : '; no app graph (DATA_ROOT not set)') +\n (report.graphs.length ? `; graphs written ${list(report.graphs)}` : '') +\n (orphanScope === 'all' ? `; pruned ${list(report.pruned)}` : '') +\n (report.cleaned ? `; ${report.cleaned} default-graph shape(s) removed` : '') +\n (withoutTurtle.length ? `; no shapes.ttl (no shape graph): ${list(withoutTurtle)}` : ''),\n );\n }\n if (orphanScope === 'all' && withoutTurtle.length && !shared) {\n warn(\n '[LinkedServer] orphaned shape graphs were not pruned: core prunes only when the sync covers ' +\n `every registered package, and ${list(withoutTurtle)} has no Turtle`,\n );\n }\n}\n\n/**\n * Sync the registered shapes into `ds`, one shape graph per package (see the module doc), and log\n * one line naming what was written and skipped, the graphs written, the packages without\n * `shapes.ttl` and the default-graph shapes removed. Throws when the sync fails. The server's boot\n * follows the routing instead ({@link syncRoutedShapeGraphs}); this syncs one given dataset.\n */\nexport async function syncShapeGraphsInto(ds: unknown, options: ShapeGraphSyncOptions): Promise<ShapeGraphsReport> {\n const {core, orphanScope, appGraph, appPackage, log = console.log, warn = console.warn} = options;\n const turtle = shapeTurtleSources(options);\n const result = await core.syncShapeGraphs(ds, {\n orphanScope,\n ...(turtle.packages ? {packages: turtle.packages} : {}),\n turtleFor: turtle.turtleFor,\n ...(appGraph ? {appShapes: {graph: appGraph, ...(appPackage ? {package: appPackage} : {})}} : {}),\n });\n const report = reportOf(result, core, turtle, appGraph, notGeneratedIn([result], turtle, warn));\n logReport(report, orphanScope, '', log, warn);\n return report;\n}\n\n/** A package graph a routed sync dropped or found left behind (core's `RoutedGraph`). */\nexport interface RoutedGraphReport {\n dataset: string;\n package: string;\n graph: string;\n}\n\n/** What core's routed syncs report (`@_linked/core/shapes/syncTargets`). */\nexport interface RoutedSyncReport<R> {\n targets: Array<{dataset: string; result: R}>;\n pruned: RoutedGraphReport[];\n leftovers: RoutedGraphReport[];\n failed: Array<{dataset: string; error: string}>;\n}\n\n/** The routed part of a shape sync's report: per target dataset, and what routing left behind. */\nexport interface RoutedShapeGraphsReport extends ShapeGraphsReport {\n /** Each dataset the shapes went to (the default one first) and what the sync did there. */\n datasets: Array<{dataset: string} & ShapeGraphsReport>;\n /** Package shape graphs dropped from the default dataset: routing sends them elsewhere now. */\n prunedGraphs: RoutedGraphReport[];\n /** Package shape graphs left in another dataset routing no longer sends them to (reported, never dropped). */\n leftovers: RoutedGraphReport[];\n}\n\nconst union = (lists: string[][]): string[] => [...new Set(lists.flat())].sort();\n\n/**\n * Sync the registered shapes where the routing needs them (core's `syncShapeGraphsRouted`): each\n * package's shape graph into every dataset its shapes and the shape shapes route to, the app graph\n * into the datasets of the shapes declaring `contains` properties, and the graphs routing no longer\n * sends to the default dataset dropped there. Logs one line per dataset (as\n * {@link syncShapeGraphsInto} does, naming the dataset when there are several) and one per graph\n * dropped or left behind. The answer's top-level fields join the datasets'. Throws, after the other\n * datasets synced, when one failed, naming each.\n */\nexport async function syncRoutedShapeGraphs(options: ShapeGraphSyncOptions): Promise<RoutedShapeGraphsReport> {\n const {core, orphanScope, appGraph, appPackage, log = console.log, warn = console.warn} = options;\n if (!core.syncShapeGraphsRouted) {\n throw new Error(\"@_linked/core has no syncShapeGraphsRouted: this server needs the core it was built with\");\n }\n const turtle = shapeTurtleSources(options);\n const routed = await core.syncShapeGraphsRouted({\n orphanScope,\n ...(turtle.packages ? {packages: turtle.packages} : {}),\n turtleFor: turtle.turtleFor,\n ...(appGraph ? {appShapes: {graph: appGraph, ...(appPackage ? {package: appPackage} : {})}} : {}),\n });\n const several = routed.targets.length > 1;\n const notGenerated = notGeneratedIn(routed.targets.map((t) => t.result), turtle, warn);\n const datasets = routed.targets.map(({dataset, result}) => {\n const report = reportOf(result, core, turtle, appGraph, notGenerated);\n logReport(report, orphanScope, several ? ` in ${dataset}` : '', log, warn);\n return {dataset, ...report};\n });\n for (const {dataset, package: name, graph} of routed.pruned) {\n log(`[LinkedServer] shape graph sync: dropped <${graph}> (${name}) from ${dataset}: routing sends its shapes elsewhere`);\n }\n const first = datasets[0];\n const report: RoutedShapeGraphsReport = {\n written: union(datasets.map((d) => d.written)),\n skipped: union(datasets.map((d) => d.skipped)).filter((n) => !datasets.some((d) => d.written.includes(n))),\n pruned: union(datasets.map((d) => d.pruned)),\n graphs: union(datasets.map((d) => d.graphs)),\n withoutTurtle: union(datasets.map((d) => d.withoutTurtle)),\n cleaned: datasets.reduce((n, d) => n + d.cleaned, 0),\n datasets,\n prunedGraphs: routed.pruned,\n leftovers: routed.leftovers,\n };\n const app = datasets.find((d) => d.appGraph?.status === 'written') ?? datasets.find((d) => d.appGraph);\n if (app?.appGraph) report.appGraph = app.appGraph;\n if (datasets.some((d) => d.defaultGraph !== undefined)) {\n report.defaultGraph = datasets.reduce((n, d) => n + (d.defaultGraph ?? 0), 0);\n }\n if (first?.target) report.target = first.target;\n if (datasets.some((d) => d.fallback)) report.fallback = true;\n if (routed.failed.length) {\n throw new Error(\n `the shape sync failed in ${routed.failed.map((f) => `${f.dataset}: ${f.error}`).join('; ')}` +\n (datasets.length ? ` (synced: ${datasets.map((d) => d.dataset).join(', ')})` : ''),\n );\n }\n return report;\n}\n\n/**\n * @deprecated The default-graph shape sync's callback type; the server now syncs shape graphs with\n * {@link syncShapeGraphsInto}. Kept so code built against an earlier server still compiles.\n */\nexport type SyncShapesFn = (\n ds: unknown,\n options: {orphanScope: BootOrphanScope},\n) => Promise<Array<() => Promise<void>>>;\n\n/**\n * @deprecated Use {@link syncShapeGraphsInto}, which writes each package's shapes into its own\n * shape graph. This runs the old default-graph sync: it plans every registered shape with\n * `syncShapes` (the orphan policy from {@link bootOrphanScope}) and runs the writes in batches\n * of 8. Kept so code built against an earlier server keeps working.\n */\nexport async function materializeShapes(\n ds: unknown,\n syncShapes: SyncShapesFn,\n {\n env = process.env,\n log = console.log,\n }: {\n env?: Record<string, string | undefined>;\n log?: (message: string) => void;\n } = {},\n): Promise<{count: number; orphanScope: BootOrphanScope}> {\n const orphanScope = bootOrphanScope(env);\n const thunks = await syncShapes(ds, {orphanScope});\n for (let i = 0; i < thunks.length; i += 8) {\n await Promise.all(thunks.slice(i, i + 8).map((run) => run()));\n }\n log(\n `[LinkedServer] synced shapes into the default graph with orphanScope '${orphanScope}': ` +\n `${thunks.length} operation(s)`,\n );\n return {count: thunks.length, orphanScope};\n}\n\n/** One graph's content as the `'package'`-mode sync writes and records it (core's `GraphContentPart`). */\nexport interface GraphContentPart {\n graph: string;\n mediaType: 'text/turtle' | 'application/n-triples';\n text: string;\n hash: string;\n sources: string[];\n}\n\n/** What core's `graphContent` answers. */\nexport interface GraphContents {\n packages: Array<{name: string; shapes?: GraphContentPart; ontology?: GraphContentPart}>;\n appGraph?: GraphContentPart | null;\n withoutTurtle: string[];\n unreadable: string[];\n}\n\n/**\n * The content of the app's graphs as the `'package'`-mode syncs would write them, writing nothing\n * (core's `graphContent`), with the server's choice of each package's Turtle\n * ({@link shapeTurtleSources}): an installed package without `shapes.ttl` gets no shape graph here\n * either (it is listed in `withoutTurtle`), exactly as the sync leaves it out. `packages` limits\n * the answer; without it every registered package with shapes or ontology data. The app graph is\n * answered when `appGraph` (`{DATA_ROOT}/graph/shapes`) is given.\n */\nexport async function graphContentOf(\n options: Pick<ShapeGraphSyncOptions, 'core' | 'isOwn' | 'dev' | 'packageDirOf' | 'generate' | 'read' | 'warn' | 'appGraph'> & {\n packages?: string[];\n },\n): Promise<GraphContents> {\n const {core, packages, appGraph} = options;\n if (!core.graphContent) {\n throw new Error('@_linked/core has no graphContent: this server needs the core it was built with');\n }\n const turtle = shapeTurtleSources(options);\n const content = await core.graphContent({\n ...(packages ? {packages} : {}),\n turtleFor: turtle.turtleFor,\n ...(appGraph ? {appShapes: {graph: appGraph}} : {}),\n });\n const noFile = new Set(turtle.noFile);\n const withoutTurtle = new Set(content.withoutTurtle);\n for (const entry of content.packages) {\n if (!noFile.has(entry.name)) continue;\n delete entry.shapes;\n withoutTurtle.add(entry.name);\n }\n return {...content, withoutTurtle: [...withoutTurtle].sort()};\n}\n"]}
package/package.json CHANGED
@@ -10,9 +10,8 @@
10
10
  "type": "git",
11
11
  "url": "git+https://github.com/linked-fw/server.git"
12
12
  },
13
- "version": "3.12.1",
13
+ "version": "3.14.0",
14
14
  "packageManager": "npm@12.2.0",
15
- "linkedPackage": true,
16
15
  "type": "module",
17
16
  "main": "lib/esm/index.js",
18
17
  "types": "index.d.ts",
@@ -39,8 +38,8 @@
39
38
  "web3"
40
39
  ],
41
40
  "dependencies": {
42
- "@_linked/cli": "^1.54.0",
43
- "@_linked/core": "^2.42.0",
41
+ "@_linked/cli": "^1.58.0",
42
+ "@_linked/core": "^2.46.0",
44
43
  "@_linked/server-utils": "^1.16.1",
45
44
  "autoprefixer": "^10.4.18",
46
45
  "compression": "^1.7.4",
@@ -91,6 +90,7 @@
91
90
  }
92
91
  },
93
92
  "linked": {
93
+ "kind": "library",
94
94
  "serverOnly": [
95
95
  ".",
96
96
  "./backend",