@_linked/server 3.11.0 → 3.12.1

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.
@@ -1,3 +1,4 @@
1
+ import { type GraphTargets } from '@_linked/core/utils/graphTargets';
1
2
  /** One dataset the router knows, and its graph routes. */
2
3
  export interface DatasetRoutes {
3
4
  /**
@@ -16,20 +17,20 @@ export interface DatasetRoutes {
16
17
  * default graph: no route of their own and no routed super-shape. Sorted.
17
18
  */
18
19
  defaultGraphShapes: string[];
19
- /**
20
- * Where the dataset keeps the packages' ontology data and shapes (core's graph targets:
21
- * `'package'`, `'default'` or a shared graph IRI), when its store has them.
22
- */
23
- ontologyGraph?: string;
24
- shapeGraph?: string;
25
20
  }
26
21
  /** The body of `GET /admin/routes`. */
27
22
  export interface EffectiveRoutes {
28
23
  /** Every dataset the router knows, the default one first, then in the order they were pinned. */
29
24
  datasets: DatasetRoutes[];
25
+ /**
26
+ * The process's graph targets (core's `getGraphTargets()`: `'package'`, `'default'` or a shared
27
+ * graph IRI each), one global setting for every dataset: where the boot syncs write and where
28
+ * `graphs.allOntologies` / `graphs.allShapes` read.
29
+ */
30
+ graphTargets: GraphTargets;
30
31
  /**
31
32
  * `LINKED_ONTOLOGY_GRAPH` / `LINKED_SHAPE_GRAPH` as the process has them (unset ones left out),
32
- * so a host sees them also for stores that take no graph targets.
33
+ * so a host can tell where {@link graphTargets} came from.
33
34
  */
34
35
  graphTargetEnv: Record<string, string>;
35
36
  }
@@ -8,6 +8,7 @@ import { LinkedStorage } from '@_linked/core/utils/LinkedStorage';
8
8
  import { getShapeGraphs, graphRoutingFor } from '@_linked/core/utils/graphRouting';
9
9
  import { getAllShapeClasses } from '@_linked/core/utils/ShapeClass';
10
10
  import { graphs } from '@_linked/core/ontologies/graphs';
11
+ import { getGraphTargets } from '@_linked/core/utils/graphTargets';
11
12
  import { graphTargetEnv } from './graphTargets.js';
12
13
  /** The routes of every dataset the router knows (see {@link EffectiveRoutes}). */
13
14
  export function effectiveGraphRoutes(env = process.env) {
@@ -28,16 +29,15 @@ export function effectiveGraphRoutes(env = process.env) {
28
29
  datasets: datasets.map((dataset) => {
29
30
  var _a, _b;
30
31
  const id = dataset.id;
31
- const targets = typeof (dataset === null || dataset === void 0 ? void 0 : dataset.graphTargets) === 'function' ? dataset.graphTargets() : undefined;
32
32
  return {
33
33
  store: ((_a = dataset === null || dataset === void 0 ? void 0 : dataset.constructor) === null || _a === void 0 ? void 0 : _a.name) || 'unknown',
34
34
  ...(typeof id === 'string' && id ? { id } : {}),
35
35
  default: dataset === defaultDataset,
36
36
  routes: getShapeGraphs(dataset),
37
37
  defaultGraphShapes: ((_b = defaultGraphShapes.get(dataset)) !== null && _b !== void 0 ? _b : []).sort(),
38
- ...(targets ? { ontologyGraph: targets.ontologyGraph, shapeGraph: targets.shapeGraph } : {}),
39
38
  };
40
39
  }),
40
+ graphTargets: getGraphTargets(),
41
41
  graphTargetEnv: graphTargetEnv(env),
42
42
  };
43
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"effectiveRoutes.js","sourceRoot":"","sources":["../../../src/utils/effectiveRoutes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAuCnD,kFAAkF;AAClF,MAAM,UAAU,oBAAoB,CAAC,MAA0C,OAAO,CAAC,GAAG;;IACxF,MAAM,QAAQ,GAAG,CAAC,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,aAAa,CAAC,iBAAiB,EAAE,CAAC;IACzD,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAqB,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACvF,KAAK,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,kBAAkB,EAAE,EAAE,CAAC;QACrD,MAAM,OAAO,GAAG,aAAa,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAC;QAClE,MAAM,IAAI,GAAG,OAAO,IAAI,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,KAAK,GAAG,MAAA,MAAA,eAAe,CAAC,OAAO,CAAC,0CAAE,aAAa,CAAC,GAAG,CAAC,mCAAI,MAAM,CAAC,OAAO,CAAC;QAC7E,IAAI,KAAK,KAAK,MAAM,CAAC,OAAO;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;;YACjC,MAAM,EAAE,GAAI,OAA4B,CAAC,EAAE,CAAC;YAC5C,MAAM,OAAO,GAAG,OAAO,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,YAAY,CAAA,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;YACjG,OAAO;gBACL,KAAK,EAAE,CAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,WAAW,0CAAE,IAAI,KAAI,SAAS;gBAC9C,GAAG,CAAC,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/C,OAAO,EAAE,OAAO,KAAK,cAAc;gBACnC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC;gBAC/B,kBAAkB,EAAE,CAAC,MAAA,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,mCAAI,EAAE,CAAC,CAAC,IAAI,EAAE;gBAClE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC7F,CAAC;QACJ,CAAC,CAAC;QACF,cAAc,EAAE,cAAc,CAAC,GAAG,CAAC;KACpC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The graph routes the process runs with, as core's routing holds them once the app's storage\n * file has run (`LinkedStorage.setDatasetForShapes(dataset, shapes, {graph})`, or `loadStores`\n * for a datasets config that still carries routes). Answered by `GET /admin/routes`, so a host\n * can compare what it wrote into the storage file with what actually runs.\n */\nimport { LinkedStorage } from '@_linked/core/utils/LinkedStorage';\nimport { getShapeGraphs, graphRoutingFor } from '@_linked/core/utils/graphRouting';\nimport { getAllShapeClasses } from '@_linked/core/utils/ShapeClass';\nimport { graphs } from '@_linked/core/ontologies/graphs';\nimport type { IDataset } from '@_linked/core/interfaces/IDataset';\nimport { graphTargetEnv } from './graphTargets.js';\n\n/** One dataset the router knows, and its graph routes. */\nexport interface DatasetRoutes {\n /**\n * The store's class name (`FusekiStore`, `RemoteDataset`, …). The server never sees the\n * aliases of the storage config, so a dataset is told apart by this, `default` and `id`.\n */\n store: string;\n /** The store's `id`, when it has one (a named `RemoteDataset` does). */\n id?: string;\n /** Whether this is the default dataset (the one for every shape without a pin). */\n default: boolean;\n /** The dataset's routes as registered: shape IRI → graph IRI. */\n routes: Record<string, string>;\n /**\n * The registered shapes that resolve to this dataset and whose instances are written to its\n * default graph: no route of their own and no routed super-shape. Sorted.\n */\n defaultGraphShapes: string[];\n /**\n * Where the dataset keeps the packages' ontology data and shapes (core's graph targets:\n * `'package'`, `'default'` or a shared graph IRI), when its store has them.\n */\n ontologyGraph?: string;\n shapeGraph?: string;\n}\n\n/** The body of `GET /admin/routes`. */\nexport interface EffectiveRoutes {\n /** Every dataset the router knows, the default one first, then in the order they were pinned. */\n datasets: DatasetRoutes[];\n /**\n * `LINKED_ONTOLOGY_GRAPH` / `LINKED_SHAPE_GRAPH` as the process has them (unset ones left out),\n * so a host sees them also for stores that take no graph targets.\n */\n graphTargetEnv: Record<string, string>;\n}\n\n/** The routes of every dataset the router knows (see {@link EffectiveRoutes}). */\nexport function effectiveGraphRoutes(env: Record<string, string | undefined> = process.env): EffectiveRoutes {\n const datasets = [...LinkedStorage.getDatasets()];\n const defaultDataset = LinkedStorage.getDefaultDataset();\n const defaultGraphShapes = new Map<IDataset, string[]>(datasets.map((ds) => [ds, []]));\n for (const [iri, shapeClass] of getAllShapeClasses()) {\n const dataset = LinkedStorage.getDatasetForShapeClass(shapeClass);\n const list = dataset && defaultGraphShapes.get(dataset);\n if (!list) continue;\n const graph = graphRoutingFor(dataset)?.graphForShape(iri) ?? graphs.default;\n if (graph === graphs.default) list.push(iri);\n }\n return {\n datasets: datasets.map((dataset) => {\n const id = (dataset as { id?: unknown }).id;\n const targets = typeof dataset?.graphTargets === 'function' ? dataset.graphTargets() : undefined;\n return {\n store: dataset?.constructor?.name || 'unknown',\n ...(typeof id === 'string' && id ? { id } : {}),\n default: dataset === defaultDataset,\n routes: getShapeGraphs(dataset),\n defaultGraphShapes: (defaultGraphShapes.get(dataset) ?? []).sort(),\n ...(targets ? { ontologyGraph: targets.ontologyGraph, shapeGraph: targets.shapeGraph } : {}),\n };\n }),\n graphTargetEnv: graphTargetEnv(env),\n };\n}\n"]}
1
+ {"version":3,"file":"effectiveRoutes.js","sourceRoot":"","sources":["../../../src/utils/effectiveRoutes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAEzD,OAAO,EAAE,eAAe,EAAqB,MAAM,kCAAkC,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAuCnD,kFAAkF;AAClF,MAAM,UAAU,oBAAoB,CAAC,MAA0C,OAAO,CAAC,GAAG;;IACxF,MAAM,QAAQ,GAAG,CAAC,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,aAAa,CAAC,iBAAiB,EAAE,CAAC;IACzD,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAqB,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACvF,KAAK,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,kBAAkB,EAAE,EAAE,CAAC;QACrD,MAAM,OAAO,GAAG,aAAa,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAC;QAClE,MAAM,IAAI,GAAG,OAAO,IAAI,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,KAAK,GAAG,MAAA,MAAA,eAAe,CAAC,OAAO,CAAC,0CAAE,aAAa,CAAC,GAAG,CAAC,mCAAI,MAAM,CAAC,OAAO,CAAC;QAC7E,IAAI,KAAK,KAAK,MAAM,CAAC,OAAO;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;;YACjC,MAAM,EAAE,GAAI,OAA4B,CAAC,EAAE,CAAC;YAC5C,OAAO;gBACL,KAAK,EAAE,CAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,WAAW,0CAAE,IAAI,KAAI,SAAS;gBAC9C,GAAG,CAAC,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/C,OAAO,EAAE,OAAO,KAAK,cAAc;gBACnC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC;gBAC/B,kBAAkB,EAAE,CAAC,MAAA,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,mCAAI,EAAE,CAAC,CAAC,IAAI,EAAE;aACnE,CAAC;QACJ,CAAC,CAAC;QACF,YAAY,EAAE,eAAe,EAAE;QAC/B,cAAc,EAAE,cAAc,CAAC,GAAG,CAAC;KACpC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The graph routes the process runs with, as core's routing holds them once the app's storage\n * file has run (`LinkedStorage.setDatasetForShapes(dataset, shapes, {graph})`, or `loadStores`\n * for a datasets config that still carries routes). Answered by `GET /admin/routes`, so a host\n * can compare what it wrote into the storage file with what actually runs.\n */\nimport { LinkedStorage } from '@_linked/core/utils/LinkedStorage';\nimport { getShapeGraphs, graphRoutingFor } from '@_linked/core/utils/graphRouting';\nimport { getAllShapeClasses } from '@_linked/core/utils/ShapeClass';\nimport { graphs } from '@_linked/core/ontologies/graphs';\nimport type { IDataset } from '@_linked/core/interfaces/IDataset';\nimport { getGraphTargets, type GraphTargets } from '@_linked/core/utils/graphTargets';\nimport { graphTargetEnv } from './graphTargets.js';\n\n/** One dataset the router knows, and its graph routes. */\nexport interface DatasetRoutes {\n /**\n * The store's class name (`FusekiStore`, `RemoteDataset`, …). The server never sees the\n * aliases of the storage config, so a dataset is told apart by this, `default` and `id`.\n */\n store: string;\n /** The store's `id`, when it has one (a named `RemoteDataset` does). */\n id?: string;\n /** Whether this is the default dataset (the one for every shape without a pin). */\n default: boolean;\n /** The dataset's routes as registered: shape IRI → graph IRI. */\n routes: Record<string, string>;\n /**\n * The registered shapes that resolve to this dataset and whose instances are written to its\n * default graph: no route of their own and no routed super-shape. Sorted.\n */\n defaultGraphShapes: string[];\n}\n\n/** The body of `GET /admin/routes`. */\nexport interface EffectiveRoutes {\n /** Every dataset the router knows, the default one first, then in the order they were pinned. */\n datasets: DatasetRoutes[];\n /**\n * The process's graph targets (core's `getGraphTargets()`: `'package'`, `'default'` or a shared\n * graph IRI each), one global setting for every dataset: where the boot syncs write and where\n * `graphs.allOntologies` / `graphs.allShapes` read.\n */\n graphTargets: GraphTargets;\n /**\n * `LINKED_ONTOLOGY_GRAPH` / `LINKED_SHAPE_GRAPH` as the process has them (unset ones left out),\n * so a host can tell where {@link graphTargets} came from.\n */\n graphTargetEnv: Record<string, string>;\n}\n\n/** The routes of every dataset the router knows (see {@link EffectiveRoutes}). */\nexport function effectiveGraphRoutes(env: Record<string, string | undefined> = process.env): EffectiveRoutes {\n const datasets = [...LinkedStorage.getDatasets()];\n const defaultDataset = LinkedStorage.getDefaultDataset();\n const defaultGraphShapes = new Map<IDataset, string[]>(datasets.map((ds) => [ds, []]));\n for (const [iri, shapeClass] of getAllShapeClasses()) {\n const dataset = LinkedStorage.getDatasetForShapeClass(shapeClass);\n const list = dataset && defaultGraphShapes.get(dataset);\n if (!list) continue;\n const graph = graphRoutingFor(dataset)?.graphForShape(iri) ?? graphs.default;\n if (graph === graphs.default) list.push(iri);\n }\n return {\n datasets: datasets.map((dataset) => {\n const id = (dataset as { id?: unknown }).id;\n return {\n store: dataset?.constructor?.name || 'unknown',\n ...(typeof id === 'string' && id ? { id } : {}),\n default: dataset === defaultDataset,\n routes: getShapeGraphs(dataset),\n defaultGraphShapes: (defaultGraphShapes.get(dataset) ?? []).sort(),\n };\n }),\n graphTargets: getGraphTargets(),\n graphTargetEnv: graphTargetEnv(env),\n };\n}\n"]}
@@ -1,20 +1,42 @@
1
1
  /**
2
- * Where the stores keep the registered packages' ontology data and shapes: core's graph targets
3
- * (`ontologyGraph`, `shapeGraph`; `@_linked/core/utils/graphTargets`), filled from the environment
4
- * at boot. `LINKED_ONTOLOGY_GRAPH` and `LINKED_SHAPE_GRAPH` each take `'package'` (the default, one
5
- * graph per package), `'default'` (the default graph) or the absolute IRI of one shared graph.
2
+ * Where the boot syncs keep the registered packages' ontology data and shapes: core's graph
3
+ * targets (`ontologyGraph`, `shapeGraph`; `@_linked/core/utils/graphTargets`), one global setting
4
+ * of the process. `LINKED_ONTOLOGY_GRAPH` and `LINKED_SHAPE_GRAPH` each take `'package'` (the
5
+ * default, one graph per package), `'default'` (the default graph) or the absolute IRI of one
6
+ * shared graph.
6
7
  *
7
- * The server reads them, checks them (an invalid value stops the boot, naming the variable), and
8
- * sets them on every store registered in `LinkedStorage` at boot that takes graph targets, for
9
- * what the store's own options leave unset. A store that takes none (`RemoteDataset`) runs `'package'`.
8
+ * The server reads them once at boot, checks them (an invalid value stops the boot, naming the
9
+ * variable) and calls core's `setGraphTargets` before the stores are initialised and before the
10
+ * syncs. No store takes a setting of its own, and the frontend needs none: its
11
+ * `.from(graphs.allOntologies)` reaches the backend as the portable name, and the backend's
12
+ * store expands it under this setting.
13
+ *
14
+ * The syncs write into the default dataset only. {@link syncPinWarning} names the shapes whose
15
+ * routing sends their reads elsewhere.
10
16
  */
11
17
  import { type GraphTargets } from '@_linked/core/utils/graphTargets';
12
18
  /**
13
19
  * Read `LINKED_ONTOLOGY_GRAPH` / `LINKED_SHAPE_GRAPH` from `env` (checked: an invalid value throws,
14
- * naming the variable) and fill every store in `stores` that takes graph targets with them, where
15
- * its own options leave a setting unset. A store that takes none gets one warning when the env sets
16
- * a mode other than `'package'` (it runs `'package'`). Returns the settings the env gave.
20
+ * naming the variable) and set them as the process's graph targets (core's `setGraphTargets`;
21
+ * unset ones are `'package'`). Returns the settings the env gave.
17
22
  */
18
- export declare function applyGraphTargetsFromEnv(env: Record<string, string | undefined>, stores: Iterable<unknown>, warn?: (message: string) => void): Partial<GraphTargets>;
23
+ export declare function applyGraphTargetsFromEnv(env: Record<string, string | undefined>): Partial<GraphTargets>;
19
24
  /** The env variables as set (unset and empty ones left out), for `GET /admin/routes`. */
20
25
  export declare function graphTargetEnv(env: Record<string, string | undefined>): Record<string, string>;
26
+ /** The classes of the shape shapes: what the shape sync writes. */
27
+ export declare const SHAPE_SHAPE_CLASSES: readonly string[];
28
+ /**
29
+ * The classes of the ontology term shapes (the class and property shapes core, `@_linked/rdfs`
30
+ * and `@_linked/owl` register): what the ontology sync writes and the hierarchy reads.
31
+ */
32
+ export declare const ONTOLOGY_TERM_CLASSES: readonly string[];
33
+ /**
34
+ * One warning when routing pins a shape the boot syncs write (the shape shapes `NodeShape` /
35
+ * `PropertyShape`, or an ontology term shape such as `rdfs:Class` / `owl:ObjectProperty`) to a
36
+ * dataset other than the default one: the syncs write into the default dataset only, so reads of
37
+ * those shapes on the pinned dataset miss what they wrote. Names each such shape (sub-shapes of a
38
+ * watched shape included) and its dataset. Undefined when there is nothing to warn about (or no
39
+ * default dataset). Reads the registered shapes outside any shape catalog (run it at boot, never
40
+ * inside `withShapeCatalog`).
41
+ */
42
+ export declare function syncPinWarning(): string | undefined;
@@ -1,43 +1,30 @@
1
1
  /**
2
- * Where the stores keep the registered packages' ontology data and shapes: core's graph targets
3
- * (`ontologyGraph`, `shapeGraph`; `@_linked/core/utils/graphTargets`), filled from the environment
4
- * at boot. `LINKED_ONTOLOGY_GRAPH` and `LINKED_SHAPE_GRAPH` each take `'package'` (the default, one
5
- * graph per package), `'default'` (the default graph) or the absolute IRI of one shared graph.
2
+ * Where the boot syncs keep the registered packages' ontology data and shapes: core's graph
3
+ * targets (`ontologyGraph`, `shapeGraph`; `@_linked/core/utils/graphTargets`), one global setting
4
+ * of the process. `LINKED_ONTOLOGY_GRAPH` and `LINKED_SHAPE_GRAPH` each take `'package'` (the
5
+ * default, one graph per package), `'default'` (the default graph) or the absolute IRI of one
6
+ * shared graph.
6
7
  *
7
- * The server reads them, checks them (an invalid value stops the boot, naming the variable), and
8
- * sets them on every store registered in `LinkedStorage` at boot that takes graph targets, for
9
- * what the store's own options leave unset. A store that takes none (`RemoteDataset`) runs `'package'`.
8
+ * The server reads them once at boot, checks them (an invalid value stops the boot, naming the
9
+ * variable) and calls core's `setGraphTargets` before the stores are initialised and before the
10
+ * syncs. No store takes a setting of its own, and the frontend needs none: its
11
+ * `.from(graphs.allOntologies)` reaches the backend as the portable name, and the backend's
12
+ * store expands it under this setting.
13
+ *
14
+ * The syncs write into the default dataset only. {@link syncPinWarning} names the shapes whose
15
+ * routing sends their reads elsewhere.
10
16
  */
11
- import { GRAPH_TARGET_ENV, graphTargetOptionsFromEnv, } from '@_linked/core/utils/graphTargets';
17
+ import { GRAPH_TARGET_ENV, graphTargetOptionsFromEnv, setGraphTargets, } from '@_linked/core/utils/graphTargets';
18
+ import { LinkedStorage } from '@_linked/core/utils/LinkedStorage';
19
+ import { getAllShapeClasses } from '@_linked/core/utils/ShapeClass';
12
20
  /**
13
21
  * Read `LINKED_ONTOLOGY_GRAPH` / `LINKED_SHAPE_GRAPH` from `env` (checked: an invalid value throws,
14
- * naming the variable) and fill every store in `stores` that takes graph targets with them, where
15
- * its own options leave a setting unset. A store that takes none gets one warning when the env sets
16
- * a mode other than `'package'` (it runs `'package'`). Returns the settings the env gave.
22
+ * naming the variable) and set them as the process's graph targets (core's `setGraphTargets`;
23
+ * unset ones are `'package'`). Returns the settings the env gave.
17
24
  */
18
- export function applyGraphTargetsFromEnv(env, stores, warn = console.warn) {
19
- var _a, _b, _c, _d, _e;
25
+ export function applyGraphTargetsFromEnv(env) {
20
26
  const fromEnv = graphTargetOptionsFromEnv(env);
21
- if (Object.keys(fromEnv).length === 0)
22
- return fromEnv;
23
- const nonDefault = Object.values(fromEnv).some((value) => value !== 'package');
24
- for (const store of stores) {
25
- const target = store;
26
- if (typeof (target === null || target === void 0 ? void 0 : target.setGraphTargets) === 'function') {
27
- try {
28
- target.setGraphTargets(fromEnv, { onlyUnset: true });
29
- }
30
- catch (error) {
31
- throw new Error(`${GRAPH_TARGET_ENV.ontologyGraph} / ${GRAPH_TARGET_ENV.shapeGraph} do not fit ` +
32
- `${(_b = (_a = target.constructor) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : 'a store'}'s own graph targets: ${(_c = error === null || error === void 0 ? void 0 : error.message) !== null && _c !== void 0 ? _c : error}`);
33
- }
34
- }
35
- else if (nonDefault) {
36
- warn(`[LinkedServer] ${(_e = (_d = target === null || target === void 0 ? void 0 : target.constructor) === null || _d === void 0 ? void 0 : _d.name) !== null && _e !== void 0 ? _e : 'a store'} takes no graph targets, so it runs ` +
37
- `'package' for the ontology and shape graphs whatever ${GRAPH_TARGET_ENV.ontologyGraph} / ` +
38
- `${GRAPH_TARGET_ENV.shapeGraph} set.`);
39
- }
40
- }
27
+ setGraphTargets(fromEnv);
41
28
  return fromEnv;
42
29
  }
43
30
  /** The env variables as set (unset and empty ones left out), for `GET /admin/routes`. */
@@ -50,4 +37,77 @@ export function graphTargetEnv(env) {
50
37
  }
51
38
  return out;
52
39
  }
40
+ const SH = 'http://www.w3.org/ns/shacl#';
41
+ const RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
42
+ const RDFS = 'http://www.w3.org/2000/01/rdf-schema#';
43
+ const OWL = 'http://www.w3.org/2002/07/owl#';
44
+ /** The classes of the shape shapes: what the shape sync writes. */
45
+ export const SHAPE_SHAPE_CLASSES = [`${SH}NodeShape`, `${SH}PropertyShape`];
46
+ /**
47
+ * The classes of the ontology term shapes (the class and property shapes core, `@_linked/rdfs`
48
+ * and `@_linked/owl` register): what the ontology sync writes and the hierarchy reads.
49
+ */
50
+ export const ONTOLOGY_TERM_CLASSES = [
51
+ `${RDFS}Class`,
52
+ `${OWL}Class`,
53
+ `${RDF}Property`,
54
+ `${OWL}ObjectProperty`,
55
+ `${OWL}DatatypeProperty`,
56
+ `${OWL}AnnotationProperty`,
57
+ ];
58
+ /** A dataset as `GET /admin/routes` tells it apart: its store class, and its `id` when it has one. */
59
+ function datasetName(dataset) {
60
+ var _a;
61
+ const id = dataset.id;
62
+ const store = ((_a = dataset === null || dataset === void 0 ? void 0 : dataset.constructor) === null || _a === void 0 ? void 0 : _a.name) || 'unknown';
63
+ return typeof id === 'string' && id ? `${store} "${id}"` : store;
64
+ }
65
+ /**
66
+ * The watched class `shapeClass` or one of its super-shapes targets (a sub-shape of `owl:Class`,
67
+ * say `owl:Restriction`, goes where its parent is pinned), else undefined.
68
+ */
69
+ function watchedClassOf(shapeClass, watched) {
70
+ var _a;
71
+ for (let current = shapeClass; typeof current === 'function' && current !== Function.prototype; current = Object.getPrototypeOf(current)) {
72
+ const id = (_a = current.targetClass) === null || _a === void 0 ? void 0 : _a.id;
73
+ if (typeof id === 'string' && watched.has(id))
74
+ return id;
75
+ }
76
+ return undefined;
77
+ }
78
+ /**
79
+ * One warning when routing pins a shape the boot syncs write (the shape shapes `NodeShape` /
80
+ * `PropertyShape`, or an ontology term shape such as `rdfs:Class` / `owl:ObjectProperty`) to a
81
+ * dataset other than the default one: the syncs write into the default dataset only, so reads of
82
+ * those shapes on the pinned dataset miss what they wrote. Names each such shape (sub-shapes of a
83
+ * watched shape included) and its dataset. Undefined when there is nothing to warn about (or no
84
+ * default dataset). Reads the registered shapes outside any shape catalog (run it at boot, never
85
+ * inside `withShapeCatalog`).
86
+ */
87
+ export function syncPinWarning() {
88
+ var _a;
89
+ const defaultDataset = LinkedStorage.getDefaultDataset();
90
+ if (!defaultDataset)
91
+ return undefined;
92
+ const watched = new Set([...SHAPE_SHAPE_CLASSES, ...ONTOLOGY_TERM_CLASSES]);
93
+ const pinned = new Map();
94
+ for (const [iri, shapeClass] of getAllShapeClasses()) {
95
+ const targetClass = watchedClassOf(shapeClass, watched);
96
+ if (!targetClass)
97
+ continue;
98
+ const dataset = LinkedStorage.getDatasetForShapeClass(shapeClass);
99
+ if (!dataset || dataset === defaultDataset)
100
+ continue;
101
+ const list = (_a = pinned.get(dataset)) !== null && _a !== void 0 ? _a : [];
102
+ list.push(`${shapeClass.name || iri} (${targetClass})`);
103
+ pinned.set(dataset, list);
104
+ }
105
+ if (pinned.size === 0)
106
+ return undefined;
107
+ const parts = [...pinned].map(([dataset, shapes]) => `${shapes.sort().join(', ')} → ${datasetName(dataset)}`);
108
+ return (`[LinkedServer] Routing pins shapes the boot syncs write to a dataset other than the default ` +
109
+ `one: ${parts.join('; ')}. The ontology and shape syncs, when they run, write into the default dataset ` +
110
+ `(${datasetName(defaultDataset)}) only, so reads of these shapes on the pinned dataset do not ` +
111
+ `see what the syncs wrote.`);
112
+ }
53
113
  //# sourceMappingURL=graphTargets.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"graphTargets.js","sourceRoot":"","sources":["../../../src/utils/graphTargets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,gBAAgB,EAChB,yBAAyB,GAE1B,MAAM,kCAAkC,CAAC;AAQ1C;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,GAAuC,EACvC,MAAyB,EACzB,OAAkC,OAAO,CAAC,IAAI;;IAE9C,MAAM,OAAO,GAAG,yBAAyB,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACtD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;IAC/E,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,KAAuC,CAAC;QACvD,IAAI,OAAO,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,eAAe,CAAA,KAAK,UAAU,EAAE,CAAC;YAClD,IAAI,CAAC;gBACH,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,EAAC,SAAS,EAAE,IAAI,EAAC,CAAC,CAAC;YACrD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CACb,GAAG,gBAAgB,CAAC,aAAa,MAAM,gBAAgB,CAAC,UAAU,cAAc;oBAC9E,GAAG,MAAA,MAAA,MAAM,CAAC,WAAW,0CAAE,IAAI,mCAAI,SAAS,yBAAyB,MAAC,KAAe,aAAf,KAAK,uBAAL,KAAK,CAAY,OAAO,mCAAI,KAAK,EAAE,CACxG,CAAC;YACJ,CAAC;QACH,CAAC;aAAM,IAAI,UAAU,EAAE,CAAC;YACtB,IAAI,CACF,kBAAkB,MAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,WAAW,0CAAE,IAAI,mCAAI,SAAS,sCAAsC;gBAC5F,wDAAwD,gBAAgB,CAAC,aAAa,KAAK;gBAC3F,GAAG,gBAAgB,CAAC,UAAU,OAAO,CACxC,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,cAAc,CAAC,GAAuC;IACpE,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,IAAI,IAAI,CAAC,gBAAgB,CAAC,aAAa,EAAE,gBAAgB,CAAC,UAAU,CAAC,EAAE,CAAC;QACjF,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,KAAK;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IAC/B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["/**\n * Where the stores keep the registered packages' ontology data and shapes: core's graph targets\n * (`ontologyGraph`, `shapeGraph`; `@_linked/core/utils/graphTargets`), filled from the environment\n * at boot. `LINKED_ONTOLOGY_GRAPH` and `LINKED_SHAPE_GRAPH` each take `'package'` (the default, one\n * graph per package), `'default'` (the default graph) or the absolute IRI of one shared graph.\n *\n * The server reads them, checks them (an invalid value stops the boot, naming the variable), and\n * sets them on every store registered in `LinkedStorage` at boot that takes graph targets, for\n * what the store's own options leave unset. A store that takes none (`RemoteDataset`) runs `'package'`.\n */\nimport {\n GRAPH_TARGET_ENV,\n graphTargetOptionsFromEnv,\n type GraphTargets,\n} from '@_linked/core/utils/graphTargets';\n\n/** A store as this module sees it: one that may take graph targets. */\ntype TargetStore = {\n setGraphTargets?: (options: Partial<GraphTargets>, how?: {onlyUnset?: boolean}) => void;\n constructor?: {name?: string};\n};\n\n/**\n * Read `LINKED_ONTOLOGY_GRAPH` / `LINKED_SHAPE_GRAPH` from `env` (checked: an invalid value throws,\n * naming the variable) and fill every store in `stores` that takes graph targets with them, where\n * its own options leave a setting unset. A store that takes none gets one warning when the env sets\n * a mode other than `'package'` (it runs `'package'`). Returns the settings the env gave.\n */\nexport function applyGraphTargetsFromEnv(\n env: Record<string, string | undefined>,\n stores: Iterable<unknown>,\n warn: (message: string) => void = console.warn,\n): Partial<GraphTargets> {\n const fromEnv = graphTargetOptionsFromEnv(env);\n if (Object.keys(fromEnv).length === 0) return fromEnv;\n const nonDefault = Object.values(fromEnv).some((value) => value !== 'package');\n for (const store of stores) {\n const target = store as TargetStore | null | undefined;\n if (typeof target?.setGraphTargets === 'function') {\n try {\n target.setGraphTargets(fromEnv, {onlyUnset: true});\n } catch (error) {\n throw new Error(\n `${GRAPH_TARGET_ENV.ontologyGraph} / ${GRAPH_TARGET_ENV.shapeGraph} do not fit ` +\n `${target.constructor?.name ?? 'a store'}'s own graph targets: ${(error as Error)?.message ?? error}`,\n );\n }\n } else if (nonDefault) {\n warn(\n `[LinkedServer] ${target?.constructor?.name ?? 'a store'} takes no graph targets, so it runs ` +\n `'package' for the ontology and shape graphs whatever ${GRAPH_TARGET_ENV.ontologyGraph} / ` +\n `${GRAPH_TARGET_ENV.shapeGraph} set.`,\n );\n }\n }\n return fromEnv;\n}\n\n/** The env variables as set (unset and empty ones left out), for `GET /admin/routes`. */\nexport function graphTargetEnv(env: Record<string, string | undefined>): Record<string, string> {\n const out: Record<string, string> = {};\n for (const name of [GRAPH_TARGET_ENV.ontologyGraph, GRAPH_TARGET_ENV.shapeGraph]) {\n const value = env[name];\n if (value) out[name] = value;\n }\n return out;\n}\n"]}
1
+ {"version":3,"file":"graphTargets.js","sourceRoot":"","sources":["../../../src/utils/graphTargets.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Where the boot syncs keep the registered packages' ontology data and shapes: core's graph\n * targets (`ontologyGraph`, `shapeGraph`; `@_linked/core/utils/graphTargets`), one global setting\n * of the process. `LINKED_ONTOLOGY_GRAPH` and `LINKED_SHAPE_GRAPH` each take `'package'` (the\n * default, one graph per package), `'default'` (the default graph) or the absolute IRI of one\n * shared graph.\n *\n * The server reads them once at boot, checks them (an invalid value stops the boot, naming the\n * variable) and calls core's `setGraphTargets` before the stores are initialised and before the\n * syncs. No store takes a setting of its own, and the frontend needs none: its\n * `.from(graphs.allOntologies)` reaches the backend as the portable name, and the backend's\n * store expands it under this setting.\n *\n * The syncs write into the default dataset only. {@link syncPinWarning} names the shapes whose\n * routing sends their reads elsewhere.\n */\nimport {\n GRAPH_TARGET_ENV,\n graphTargetOptionsFromEnv,\n setGraphTargets,\n type GraphTargets,\n} from '@_linked/core/utils/graphTargets';\nimport { LinkedStorage } from '@_linked/core/utils/LinkedStorage';\nimport { getAllShapeClasses } from '@_linked/core/utils/ShapeClass';\nimport type { IDataset } from '@_linked/core/interfaces/IDataset';\n\n/**\n * Read `LINKED_ONTOLOGY_GRAPH` / `LINKED_SHAPE_GRAPH` from `env` (checked: an invalid value throws,\n * naming the variable) and set them as the process's graph targets (core's `setGraphTargets`;\n * unset ones are `'package'`). Returns the settings the env gave.\n */\nexport function applyGraphTargetsFromEnv(env: Record<string, string | undefined>): Partial<GraphTargets> {\n const fromEnv = graphTargetOptionsFromEnv(env);\n setGraphTargets(fromEnv);\n return fromEnv;\n}\n\n/** The env variables as set (unset and empty ones left out), for `GET /admin/routes`. */\nexport function graphTargetEnv(env: Record<string, string | undefined>): Record<string, string> {\n const out: Record<string, string> = {};\n for (const name of [GRAPH_TARGET_ENV.ontologyGraph, GRAPH_TARGET_ENV.shapeGraph]) {\n const value = env[name];\n if (value) out[name] = value;\n }\n return out;\n}\n\nconst SH = 'http://www.w3.org/ns/shacl#';\nconst RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';\nconst RDFS = 'http://www.w3.org/2000/01/rdf-schema#';\nconst OWL = 'http://www.w3.org/2002/07/owl#';\n\n/** The classes of the shape shapes: what the shape sync writes. */\nexport const SHAPE_SHAPE_CLASSES: readonly string[] = [`${SH}NodeShape`, `${SH}PropertyShape`];\n\n/**\n * The classes of the ontology term shapes (the class and property shapes core, `@_linked/rdfs`\n * and `@_linked/owl` register): what the ontology sync writes and the hierarchy reads.\n */\nexport const ONTOLOGY_TERM_CLASSES: readonly string[] = [\n `${RDFS}Class`,\n `${OWL}Class`,\n `${RDF}Property`,\n `${OWL}ObjectProperty`,\n `${OWL}DatatypeProperty`,\n `${OWL}AnnotationProperty`,\n];\n\n/** A dataset as `GET /admin/routes` tells it apart: its store class, and its `id` when it has one. */\nfunction datasetName(dataset: IDataset): string {\n const id = (dataset as { id?: unknown }).id;\n const store = dataset?.constructor?.name || 'unknown';\n return typeof id === 'string' && id ? `${store} \"${id}\"` : store;\n}\n\n/**\n * The watched class `shapeClass` or one of its super-shapes targets (a sub-shape of `owl:Class`,\n * say `owl:Restriction`, goes where its parent is pinned), else undefined.\n */\nfunction watchedClassOf(shapeClass: Function, watched: ReadonlySet<string>): string | undefined {\n for (let current: unknown = shapeClass; typeof current === 'function' && current !== Function.prototype; current = Object.getPrototypeOf(current)) {\n const id = (current as { targetClass?: { id?: unknown } }).targetClass?.id;\n if (typeof id === 'string' && watched.has(id)) return id;\n }\n return undefined;\n}\n\n/**\n * One warning when routing pins a shape the boot syncs write (the shape shapes `NodeShape` /\n * `PropertyShape`, or an ontology term shape such as `rdfs:Class` / `owl:ObjectProperty`) to a\n * dataset other than the default one: the syncs write into the default dataset only, so reads of\n * those shapes on the pinned dataset miss what they wrote. Names each such shape (sub-shapes of a\n * watched shape included) and its dataset. Undefined when there is nothing to warn about (or no\n * default dataset). Reads the registered shapes outside any shape catalog (run it at boot, never\n * inside `withShapeCatalog`).\n */\nexport function syncPinWarning(): string | undefined {\n const defaultDataset = LinkedStorage.getDefaultDataset();\n if (!defaultDataset) return undefined;\n const watched = new Set([...SHAPE_SHAPE_CLASSES, ...ONTOLOGY_TERM_CLASSES]);\n const pinned = new Map<IDataset, string[]>();\n for (const [iri, shapeClass] of getAllShapeClasses()) {\n const targetClass = watchedClassOf(shapeClass, watched);\n if (!targetClass) continue;\n const dataset = LinkedStorage.getDatasetForShapeClass(shapeClass);\n if (!dataset || dataset === defaultDataset) continue;\n const list = pinned.get(dataset) ?? [];\n list.push(`${shapeClass.name || iri} (${targetClass})`);\n pinned.set(dataset, list);\n }\n if (pinned.size === 0) return undefined;\n const parts = [...pinned].map(([dataset, shapes]) => `${shapes.sort().join(', ')} → ${datasetName(dataset)}`);\n return (\n `[LinkedServer] Routing pins shapes the boot syncs write to a dataset other than the default ` +\n `one: ${parts.join('; ')}. The ontology and shape syncs, when they run, write into the default dataset ` +\n `(${datasetName(defaultDataset)}) only, so reads of these shapes on the pinned dataset do not ` +\n `see what the syncs wrote.`\n );\n}\n"]}
@@ -94,7 +94,7 @@ export async function runOntologyPhase(ds, { core, sync, orphanScope, dependenci
94
94
  const { graphs, droppedGraphs } = graphsWrittenAndDropped(ops.filter((op) => op.ok));
95
95
  result.ontologies = { written: sync.written, skipped: sync.skipped, graphs, droppedGraphs };
96
96
  hierarchyLoaded = true;
97
- // Core ≥ 2.41 says where it wrote (the store's `ontologyGraph`); an older core is told
97
+ // Core ≥ 2.41 says where it wrote (the global `ontologyGraph`); an older core is told
98
98
  // apart by a write that sent no graph query.
99
99
  const where = sync.target === 'default'
100
100
  ? " (default graph: ontologyGraph is 'default')"
@@ -1 +1 @@
1
- {"version":3,"file":"ontologySync.js","sourceRoot":"","sources":["../../../src/utils/ontologySync.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Ontology sync and the shape check, as the server runs them before its shape sync: at boot and\n * when the host asks for a re-sync (`POST /admin/sync-shapes`).\n *\n * - The ontology sync (core `syncOntologies`) writes each registered package's ontology data into\n * its own named graph of the app's default dataset (`{package IRI}/graph/ontology`, with a\n * record in the graph registry that marks it as a hierarchy source), skipping a package whose\n * stored hash matches, so the store's RDFS view infers the class hierarchy. A store without\n * graph queries (it answers `unsupported-query-kind`, or has no `graphQuery`) gets core's\n * earlier sync of the `rdfs:subClassOf` triples into the default graph instead. The graphs the\n * sync wrote or dropped are observed on core's query dispatch and reported by name.\n * - The shape check (core `checkShapeHierarchy`) compares the registered shapes with that\n * hierarchy. A running app is never stopped by it: its findings are logged and counted.\n * - The in-memory class hierarchy (core `loadOntologyHierarchy`) is loaded also when the sync\n * is off; the sync loads it itself when it runs.\n * - Before either, every linked package directory the server discovered registers its ontologies\n * (core `registerInstalledOntologies`): a package the app only deep-imports shape files from\n * never evaluates its register modules, so its data would be missing from both. A source\n * package without built register modules (a workspace package in dev) registers through\n * `importModule` (Vite's `ssrLoadModule`), when the caller passes one.\n *\n * The four core modules (`ontology/syncOntologies`, `shapes/checkShapeHierarchy`,\n * `ontology/hierarchy`, `ontology/registerInstalled`) are server only and not in core's index, so\n * {@link loadOntologyCore} imports them by their fixed subpaths when the phase runs; the core\n * this server depends on has all of them. Kept apart from `LinkedServer` so the order and the failure handling can be tested without\n * booting a server.\n */\nimport type {BootOrphanScope} from './syncShapes.js';\n\n/** The subset of core's ontology and shape-check API this module calls. */\nexport interface OntologyCore {\n syncOntologies(\n ds: unknown,\n options: {orphanScope: BootOrphanScope},\n ): Promise<{written: string[]; skipped: string[]; pruned: string[]; target?: string; fallback?: true}>;\n checkShapeHierarchy(options: {dependencies?: Record<string, string[]>}): Promise<\n Array<{kind: string; severity: 'error' | 'warning'; shape?: string; iri?: string; message: string}>\n >;\n /** Loads the in-memory class hierarchy. Optional so a test double can leave it out. */\n loadOntologyHierarchy?: () => Promise<unknown>;\n /**\n * Calls `onGraph` for every graph query on `ds` that succeeds until the returned function is\n * called (core's `subscribeQueryDispatch`). Optional so a test double can leave it out.\n */\n observeGraphQueries?: (\n ds: unknown,\n onGraph: (query: {kind: string; graph: string}, settled: Promise<unknown>) => void,\n ) => () => void;\n /**\n * Registers the ontologies of the installed packages in the given directories. Optional so a\n * test double can leave it out.\n */\n registerInstalledOntologies?: (\n packageDirs: string[],\n options?: {importModule?: (file: string) => Promise<unknown>},\n ) => Promise<string[]>;\n}\n\n/** What the ontology sync and the shape check did, as `POST /admin/sync-shapes` reports it. */\nexport interface OntologyPhaseResult {\n /**\n * Packages whose ontology graph (or, on a store without graph queries, hierarchy) was written,\n * packages left as they were (unchanged or unreadable), and the graphs the sync wrote and\n * dropped (empty on a store without graph queries).\n */\n ontologies: {written: string[]; skipped: string[]; graphs?: string[]; droppedGraphs?: string[]};\n /** The shape check's findings, counted by severity. */\n shapeCheck: {errors: number; warnings: number};\n /** The first error the sync or the check threw; the phase went on without it. */\n failure?: Error;\n}\n\n/**\n * Whether the server syncs shapes (and so ontologies) into its app data: off when `linked.config`\n * sets `syncShapesOnBoot: false` or the environment sets `LINKED_SYNC_SHAPES_ON_BOOT=false`. One\n * switch for both syncs, at boot and on the host's request.\n */\nexport function shapeSyncOn(\n env: Record<string, string | undefined>,\n configFlag: unknown,\n): boolean {\n return configFlag !== false && env.LINKED_SYNC_SHAPES_ON_BOOT !== 'false';\n}\n\n/**\n * Whether the boot syncs ontologies: when shape sync is on ({@link shapeSyncOn}) and the\n * environment does not opt out with `LINKED_SYNC_ONTOLOGIES_ON_BOOT=false`.\n */\nexport function bootSyncsOntologies(\n env: Record<string, string | undefined>,\n configFlag?: unknown,\n): boolean {\n return shapeSyncOn(env, configFlag) && env.LINKED_SYNC_ONTOLOGIES_ON_BOOT !== 'false';\n}\n\n/**\n * Import core's ontology sync, shape check, hierarchy loader and installed packages'\n * registration.\n */\nexport async function loadOntologyCore(): Promise<OntologyCore> {\n const sync = await import('@_linked/core/ontology/syncOntologies');\n const check = await import('@_linked/core/shapes/checkShapeHierarchy');\n const hierarchy = await import('@_linked/core/ontology/hierarchy');\n const registerInstalled = await import('@_linked/core/ontology/registerInstalled');\n const dispatch = await import('@_linked/core/queries/queryDispatch');\n return {\n syncOntologies: (ds, options) =>\n sync.syncOntologies(ds as Parameters<typeof sync.syncOntologies>[0], options),\n checkShapeHierarchy: (options) => check.checkShapeHierarchy(options),\n loadOntologyHierarchy: () => hierarchy.loadOntologyHierarchy(),\n registerInstalledOntologies: (packageDirs, options) =>\n registerInstalled.registerInstalledOntologies(packageDirs, options),\n observeGraphQueries: (ds, onGraph) =>\n dispatch.subscribeQueryDispatch((event) => {\n if (event.kind === 'graph' && event.target === ds) onGraph(event.query, event.result);\n }),\n };\n}\n\n/**\n * The package directories whose ontologies register before the sync: every linked package\n * discovered in the app's dependency tree, then the app's own workspace packages (an ontology\n * package in `packages/` that no package imports is one, so the dependency walk never reaches it).\n * Order kept, duplicates dropped.\n */\nexport function ontologyPackageDirs(\n linkedPackageDirs: Iterable<string>,\n workspacePackageDirs: Iterable<string>,\n): string[] {\n return [...new Set([...linkedPackageDirs, ...workspacePackageDirs])];\n}\n\n/**\n * In dev, the loader for source register modules: Vite's `ssrLoadModule`, so a workspace package\n * that was never built registers on the core the SSR graph uses. Undefined without Vite (a built\n * app), where source packages are skipped.\n */\nexport function sourceModuleImporter(\n vite: {ssrLoadModule?: (url: string) => Promise<unknown>} | undefined | null,\n): ((file: string) => Promise<unknown>) | undefined {\n const ssrLoadModule = vite?.ssrLoadModule;\n return typeof ssrLoadModule === 'function' ? (file) => ssrLoadModule.call(vite, file) : undefined;\n}\n\nconst asError = (err: unknown): Error => (err instanceof Error ? err : new Error(String(err)));\nconst list = (names: string[]) => (names.length ? names.join(', ') : 'none');\n\n/**\n * Register the ontologies of the installed linked packages in `packageDirs` (package roots), sync\n * the registered ontologies into `ds` (when `sync` is set and there is a dataset), then run the\n * shape check. Never throws: a failed registration is logged and the phase goes on; a failed sync is logged and returned as `failure`, and the\n * check still runs; a failed check likewise. Logs one line for the sync, one summary line for\n * the check and one line per finding.\n */\nexport async function runOntologyPhase(\n ds: unknown,\n {\n core,\n sync,\n orphanScope,\n dependencies,\n packageDirs = [],\n importModule,\n log = console.log,\n warn = console.warn,\n }: {\n core: OntologyCore;\n sync: boolean;\n orphanScope: BootOrphanScope;\n dependencies?: Record<string, string[]>;\n /** Every linked package directory the server discovered (transitively). */\n packageDirs?: string[];\n /**\n * Imports a source register module (`src/ontologies/*.register.ts`) of a package directory\n * without built ones; in dev, Vite's `ssrLoadModule`.\n */\n importModule?: (file: string) => Promise<unknown>;\n log?: (message: string) => void;\n warn?: (message: string, err?: unknown) => void;\n },\n): Promise<OntologyPhaseResult> {\n const result: OntologyPhaseResult = {\n ontologies: {written: [], skipped: [], graphs: [], droppedGraphs: []},\n shapeCheck: {errors: 0, warnings: 0},\n };\n\n if (core.registerInstalledOntologies && packageDirs.length) {\n try {\n if (importModule) await core.registerInstalledOntologies(packageDirs, {importModule});\n else await core.registerInstalledOntologies(packageDirs);\n } catch (err) {\n warn(\"[LinkedServer] registering the installed packages' ontologies failed:\", err);\n }\n }\n\n let hierarchyLoaded = false;\n if (sync && ds) {\n // Every graph query that succeeded, in the order the sync sent them.\n const ops: Array<{kind: string; graph: string; ok?: boolean}> = [];\n const pending: Promise<unknown>[] = [];\n const stop = core.observeGraphQueries?.(ds, (query, settled) => {\n const op: {kind: string; graph: string; ok?: boolean} = {kind: query.kind, graph: query.graph};\n ops.push(op);\n pending.push(\n settled.then(\n () => (op.ok = true),\n () => undefined,\n ),\n );\n });\n try {\n const sync = await core.syncOntologies(ds, {orphanScope});\n await Promise.all(pending);\n const {graphs, droppedGraphs} = graphsWrittenAndDropped(ops.filter((op) => op.ok));\n result.ontologies = {written: sync.written, skipped: sync.skipped, graphs, droppedGraphs};\n hierarchyLoaded = true;\n // Core ≥ 2.41 says where it wrote (the store's `ontologyGraph`); an older core is told\n // apart by a write that sent no graph query.\n const where =\n sync.target === 'default'\n ? \" (default graph: ontologyGraph is 'default')\"\n : sync.fallback || (sync.target === undefined && !!stop && sync.written.length > 0 && graphs.length === 0)\n ? ' (default graph: the store has no graph queries)'\n : sync.target && sync.target !== 'package'\n ? ` (one shared graph <${sync.target}>)`\n : '';\n log(\n `[LinkedServer] ontology sync${where}: ` +\n `written ${list(sync.written)}; skipped ${list(sync.skipped)}` +\n (orphanScope === 'all' ? `; pruned ${list(sync.pruned)}` : '') +\n (graphs.length ? `; graphs written ${list(graphs)}` : '') +\n (droppedGraphs.length ? `; graphs dropped ${list(droppedGraphs)}` : ''),\n );\n } catch (err) {\n result.failure = asError(err);\n warn('[LinkedServer] ontology sync failed:', err);\n } finally {\n stop?.();\n }\n }\n if (!hierarchyLoaded && core.loadOntologyHierarchy) {\n try {\n await core.loadOntologyHierarchy();\n } catch (err) {\n warn('[LinkedServer] loading the class hierarchy failed:', err);\n }\n }\n\n try {\n const findings = await core.checkShapeHierarchy({dependencies});\n const errors = findings.filter((f) => f.severity === 'error').length;\n result.shapeCheck = {errors, warnings: findings.length - errors};\n log(`[LinkedServer] shape check: ${errors} error(s), ${findings.length - errors} warning(s)`);\n for (const f of findings) warn(`[LinkedServer] shape check ${f.severity} (${f.kind}): ${f.message}`);\n } catch (err) {\n result.failure ??= asError(err);\n warn('[LinkedServer] shape check failed:', err);\n }\n return result;\n}\n\n/**\n * The graphs a sync left written and those it left dropped, from its successful graph queries in\n * order. A graph the run created and then dropped (the inference probe's temporary graphs) is in\n * neither list.\n */\nexport function graphsWrittenAndDropped(ops: Array<{kind: string; graph: string}>): {\n graphs: string[];\n droppedGraphs: string[];\n} {\n const byGraph = new Map<string, string[]>();\n for (const {kind, graph} of ops) {\n const kinds = byGraph.get(graph) ?? [];\n kinds.push(kind);\n byGraph.set(graph, kinds);\n }\n const graphs: string[] = [];\n const droppedGraphs: string[] = [];\n for (const [graph, kinds] of byGraph) {\n const last = kinds[kinds.length - 1];\n if (last !== 'graph_drop') graphs.push(graph);\n else if (kinds[0] !== 'graph_create') droppedGraphs.push(graph);\n }\n return {graphs: graphs.sort(), droppedGraphs: droppedGraphs.sort()};\n}\n\n/**\n * The host's re-sync: the ontology phase, then the shape sync, which runs also when the ontology\n * phase failed. The ontology phase's failure is then thrown, so the route answers with it, as\n * it does for a failed shape sync.\n */\nexport async function syncOntologiesThenShapes<T extends object>(\n ontologyPhase: () => Promise<OntologyPhaseResult>,\n shapeSync: () => Promise<T>,\n): Promise<T & Pick<OntologyPhaseResult, 'ontologies' | 'shapeCheck'>> {\n const {ontologies, shapeCheck, failure} = await ontologyPhase();\n const shapes = await shapeSync();\n if (failure) throw failure;\n return {...shapes, ontologies, shapeCheck};\n}\n"]}
1
+ {"version":3,"file":"ontologySync.js","sourceRoot":"","sources":["../../../src/utils/ontologySync.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Ontology sync and the shape check, as the server runs them before its shape sync: at boot and\n * when the host asks for a re-sync (`POST /admin/sync-shapes`).\n *\n * - The ontology sync (core `syncOntologies`) writes each registered package's ontology data into\n * its own named graph of the app's default dataset (`{package IRI}/graph/ontology`, with a\n * record in the graph registry that marks it as a hierarchy source), skipping a package whose\n * stored hash matches, so the store's RDFS view infers the class hierarchy. A store without\n * graph queries (it answers `unsupported-query-kind`, or has no `graphQuery`) gets core's\n * earlier sync of the `rdfs:subClassOf` triples into the default graph instead. The graphs the\n * sync wrote or dropped are observed on core's query dispatch and reported by name.\n * - The shape check (core `checkShapeHierarchy`) compares the registered shapes with that\n * hierarchy. A running app is never stopped by it: its findings are logged and counted.\n * - The in-memory class hierarchy (core `loadOntologyHierarchy`) is loaded also when the sync\n * is off; the sync loads it itself when it runs.\n * - Before either, every linked package directory the server discovered registers its ontologies\n * (core `registerInstalledOntologies`): a package the app only deep-imports shape files from\n * never evaluates its register modules, so its data would be missing from both. A source\n * package without built register modules (a workspace package in dev) registers through\n * `importModule` (Vite's `ssrLoadModule`), when the caller passes one.\n *\n * The four core modules (`ontology/syncOntologies`, `shapes/checkShapeHierarchy`,\n * `ontology/hierarchy`, `ontology/registerInstalled`) are server only and not in core's index, so\n * {@link loadOntologyCore} imports them by their fixed subpaths when the phase runs; the core\n * this server depends on has all of them. Kept apart from `LinkedServer` so the order and the failure handling can be tested without\n * booting a server.\n */\nimport type {BootOrphanScope} from './syncShapes.js';\n\n/** The subset of core's ontology and shape-check API this module calls. */\nexport interface OntologyCore {\n syncOntologies(\n ds: unknown,\n options: {orphanScope: BootOrphanScope},\n ): Promise<{written: string[]; skipped: string[]; pruned: string[]; target?: string; fallback?: true}>;\n checkShapeHierarchy(options: {dependencies?: Record<string, string[]>}): Promise<\n Array<{kind: string; severity: 'error' | 'warning'; shape?: string; iri?: string; message: string}>\n >;\n /** Loads the in-memory class hierarchy. Optional so a test double can leave it out. */\n loadOntologyHierarchy?: () => Promise<unknown>;\n /**\n * Calls `onGraph` for every graph query on `ds` that succeeds until the returned function is\n * called (core's `subscribeQueryDispatch`). Optional so a test double can leave it out.\n */\n observeGraphQueries?: (\n ds: unknown,\n onGraph: (query: {kind: string; graph: string}, settled: Promise<unknown>) => void,\n ) => () => void;\n /**\n * Registers the ontologies of the installed packages in the given directories. Optional so a\n * test double can leave it out.\n */\n registerInstalledOntologies?: (\n packageDirs: string[],\n options?: {importModule?: (file: string) => Promise<unknown>},\n ) => Promise<string[]>;\n}\n\n/** What the ontology sync and the shape check did, as `POST /admin/sync-shapes` reports it. */\nexport interface OntologyPhaseResult {\n /**\n * Packages whose ontology graph (or, on a store without graph queries, hierarchy) was written,\n * packages left as they were (unchanged or unreadable), and the graphs the sync wrote and\n * dropped (empty on a store without graph queries).\n */\n ontologies: {written: string[]; skipped: string[]; graphs?: string[]; droppedGraphs?: string[]};\n /** The shape check's findings, counted by severity. */\n shapeCheck: {errors: number; warnings: number};\n /** The first error the sync or the check threw; the phase went on without it. */\n failure?: Error;\n}\n\n/**\n * Whether the server syncs shapes (and so ontologies) into its app data: off when `linked.config`\n * sets `syncShapesOnBoot: false` or the environment sets `LINKED_SYNC_SHAPES_ON_BOOT=false`. One\n * switch for both syncs, at boot and on the host's request.\n */\nexport function shapeSyncOn(\n env: Record<string, string | undefined>,\n configFlag: unknown,\n): boolean {\n return configFlag !== false && env.LINKED_SYNC_SHAPES_ON_BOOT !== 'false';\n}\n\n/**\n * Whether the boot syncs ontologies: when shape sync is on ({@link shapeSyncOn}) and the\n * environment does not opt out with `LINKED_SYNC_ONTOLOGIES_ON_BOOT=false`.\n */\nexport function bootSyncsOntologies(\n env: Record<string, string | undefined>,\n configFlag?: unknown,\n): boolean {\n return shapeSyncOn(env, configFlag) && env.LINKED_SYNC_ONTOLOGIES_ON_BOOT !== 'false';\n}\n\n/**\n * Import core's ontology sync, shape check, hierarchy loader and installed packages'\n * registration.\n */\nexport async function loadOntologyCore(): Promise<OntologyCore> {\n const sync = await import('@_linked/core/ontology/syncOntologies');\n const check = await import('@_linked/core/shapes/checkShapeHierarchy');\n const hierarchy = await import('@_linked/core/ontology/hierarchy');\n const registerInstalled = await import('@_linked/core/ontology/registerInstalled');\n const dispatch = await import('@_linked/core/queries/queryDispatch');\n return {\n syncOntologies: (ds, options) =>\n sync.syncOntologies(ds as Parameters<typeof sync.syncOntologies>[0], options),\n checkShapeHierarchy: (options) => check.checkShapeHierarchy(options),\n loadOntologyHierarchy: () => hierarchy.loadOntologyHierarchy(),\n registerInstalledOntologies: (packageDirs, options) =>\n registerInstalled.registerInstalledOntologies(packageDirs, options),\n observeGraphQueries: (ds, onGraph) =>\n dispatch.subscribeQueryDispatch((event) => {\n if (event.kind === 'graph' && event.target === ds) onGraph(event.query, event.result);\n }),\n };\n}\n\n/**\n * The package directories whose ontologies register before the sync: every linked package\n * discovered in the app's dependency tree, then the app's own workspace packages (an ontology\n * package in `packages/` that no package imports is one, so the dependency walk never reaches it).\n * Order kept, duplicates dropped.\n */\nexport function ontologyPackageDirs(\n linkedPackageDirs: Iterable<string>,\n workspacePackageDirs: Iterable<string>,\n): string[] {\n return [...new Set([...linkedPackageDirs, ...workspacePackageDirs])];\n}\n\n/**\n * In dev, the loader for source register modules: Vite's `ssrLoadModule`, so a workspace package\n * that was never built registers on the core the SSR graph uses. Undefined without Vite (a built\n * app), where source packages are skipped.\n */\nexport function sourceModuleImporter(\n vite: {ssrLoadModule?: (url: string) => Promise<unknown>} | undefined | null,\n): ((file: string) => Promise<unknown>) | undefined {\n const ssrLoadModule = vite?.ssrLoadModule;\n return typeof ssrLoadModule === 'function' ? (file) => ssrLoadModule.call(vite, file) : undefined;\n}\n\nconst asError = (err: unknown): Error => (err instanceof Error ? err : new Error(String(err)));\nconst list = (names: string[]) => (names.length ? names.join(', ') : 'none');\n\n/**\n * Register the ontologies of the installed linked packages in `packageDirs` (package roots), sync\n * the registered ontologies into `ds` (when `sync` is set and there is a dataset), then run the\n * shape check. Never throws: a failed registration is logged and the phase goes on; a failed sync is logged and returned as `failure`, and the\n * check still runs; a failed check likewise. Logs one line for the sync, one summary line for\n * the check and one line per finding.\n */\nexport async function runOntologyPhase(\n ds: unknown,\n {\n core,\n sync,\n orphanScope,\n dependencies,\n packageDirs = [],\n importModule,\n log = console.log,\n warn = console.warn,\n }: {\n core: OntologyCore;\n sync: boolean;\n orphanScope: BootOrphanScope;\n dependencies?: Record<string, string[]>;\n /** Every linked package directory the server discovered (transitively). */\n packageDirs?: string[];\n /**\n * Imports a source register module (`src/ontologies/*.register.ts`) of a package directory\n * without built ones; in dev, Vite's `ssrLoadModule`.\n */\n importModule?: (file: string) => Promise<unknown>;\n log?: (message: string) => void;\n warn?: (message: string, err?: unknown) => void;\n },\n): Promise<OntologyPhaseResult> {\n const result: OntologyPhaseResult = {\n ontologies: {written: [], skipped: [], graphs: [], droppedGraphs: []},\n shapeCheck: {errors: 0, warnings: 0},\n };\n\n if (core.registerInstalledOntologies && packageDirs.length) {\n try {\n if (importModule) await core.registerInstalledOntologies(packageDirs, {importModule});\n else await core.registerInstalledOntologies(packageDirs);\n } catch (err) {\n warn(\"[LinkedServer] registering the installed packages' ontologies failed:\", err);\n }\n }\n\n let hierarchyLoaded = false;\n if (sync && ds) {\n // Every graph query that succeeded, in the order the sync sent them.\n const ops: Array<{kind: string; graph: string; ok?: boolean}> = [];\n const pending: Promise<unknown>[] = [];\n const stop = core.observeGraphQueries?.(ds, (query, settled) => {\n const op: {kind: string; graph: string; ok?: boolean} = {kind: query.kind, graph: query.graph};\n ops.push(op);\n pending.push(\n settled.then(\n () => (op.ok = true),\n () => undefined,\n ),\n );\n });\n try {\n const sync = await core.syncOntologies(ds, {orphanScope});\n await Promise.all(pending);\n const {graphs, droppedGraphs} = graphsWrittenAndDropped(ops.filter((op) => op.ok));\n result.ontologies = {written: sync.written, skipped: sync.skipped, graphs, droppedGraphs};\n hierarchyLoaded = true;\n // Core ≥ 2.41 says where it wrote (the global `ontologyGraph`); an older core is told\n // apart by a write that sent no graph query.\n const where =\n sync.target === 'default'\n ? \" (default graph: ontologyGraph is 'default')\"\n : sync.fallback || (sync.target === undefined && !!stop && sync.written.length > 0 && graphs.length === 0)\n ? ' (default graph: the store has no graph queries)'\n : sync.target && sync.target !== 'package'\n ? ` (one shared graph <${sync.target}>)`\n : '';\n log(\n `[LinkedServer] ontology sync${where}: ` +\n `written ${list(sync.written)}; skipped ${list(sync.skipped)}` +\n (orphanScope === 'all' ? `; pruned ${list(sync.pruned)}` : '') +\n (graphs.length ? `; graphs written ${list(graphs)}` : '') +\n (droppedGraphs.length ? `; graphs dropped ${list(droppedGraphs)}` : ''),\n );\n } catch (err) {\n result.failure = asError(err);\n warn('[LinkedServer] ontology sync failed:', err);\n } finally {\n stop?.();\n }\n }\n if (!hierarchyLoaded && core.loadOntologyHierarchy) {\n try {\n await core.loadOntologyHierarchy();\n } catch (err) {\n warn('[LinkedServer] loading the class hierarchy failed:', err);\n }\n }\n\n try {\n const findings = await core.checkShapeHierarchy({dependencies});\n const errors = findings.filter((f) => f.severity === 'error').length;\n result.shapeCheck = {errors, warnings: findings.length - errors};\n log(`[LinkedServer] shape check: ${errors} error(s), ${findings.length - errors} warning(s)`);\n for (const f of findings) warn(`[LinkedServer] shape check ${f.severity} (${f.kind}): ${f.message}`);\n } catch (err) {\n result.failure ??= asError(err);\n warn('[LinkedServer] shape check failed:', err);\n }\n return result;\n}\n\n/**\n * The graphs a sync left written and those it left dropped, from its successful graph queries in\n * order. A graph the run created and then dropped (the inference probe's temporary graphs) is in\n * neither list.\n */\nexport function graphsWrittenAndDropped(ops: Array<{kind: string; graph: string}>): {\n graphs: string[];\n droppedGraphs: string[];\n} {\n const byGraph = new Map<string, string[]>();\n for (const {kind, graph} of ops) {\n const kinds = byGraph.get(graph) ?? [];\n kinds.push(kind);\n byGraph.set(graph, kinds);\n }\n const graphs: string[] = [];\n const droppedGraphs: string[] = [];\n for (const [graph, kinds] of byGraph) {\n const last = kinds[kinds.length - 1];\n if (last !== 'graph_drop') graphs.push(graph);\n else if (kinds[0] !== 'graph_create') droppedGraphs.push(graph);\n }\n return {graphs: graphs.sort(), droppedGraphs: droppedGraphs.sort()};\n}\n\n/**\n * The host's re-sync: the ontology phase, then the shape sync, which runs also when the ontology\n * phase failed. The ontology phase's failure is then thrown, so the route answers with it, as\n * it does for a failed shape sync.\n */\nexport async function syncOntologiesThenShapes<T extends object>(\n ontologyPhase: () => Promise<OntologyPhaseResult>,\n shapeSync: () => Promise<T>,\n): Promise<T & Pick<OntologyPhaseResult, 'ontologies' | 'shapeCheck'>> {\n const {ontologies, shapeCheck, failure} = await ontologyPhase();\n const shapes = await shapeSync();\n if (failure) throw failure;\n return {...shapes, ontologies, shapeCheck};\n}\n"]}
@@ -20,7 +20,7 @@ export interface ShapeGraphSyncResult {
20
20
  cleaned: number;
21
21
  appGraph?: 'written' | 'skipped' | 'dropped';
22
22
  defaultGraph?: number;
23
- /** The store's `shapeGraph` target the run wrote in (core ≥ 2.41): `'package'`, `'default'` or an IRI. */
23
+ /** The global `shapeGraph` target the run wrote in (core ≥ 2.41): `'package'`, `'default'` or an IRI. */
24
24
  target?: string;
25
25
  /** Set when a store without graph queries took the default-graph sync instead of `target`. */
26
26
  fallback?: true;
@@ -105,11 +105,11 @@ export interface ShapeGraphsReport {
105
105
  /** Shapes an earlier sync had written into the default graph, removed now. */
106
106
  cleaned: number;
107
107
  /**
108
- * Set when the shapes went into the default graph (the store's `shapeGraph` is `'default'`, or
108
+ * Set when the shapes went into the default graph (the global `shapeGraph` is `'default'`, or
109
109
  * it has no graph queries): the default-graph sync's writes.
110
110
  */
111
111
  defaultGraph?: number;
112
- /** The store's `shapeGraph` target (`'package'`, `'default'` or a shared graph IRI), when core reports it. */
112
+ /** The global `shapeGraph` target (`'package'`, `'default'` or a shared graph IRI), when core reports it. */
113
113
  target?: string;
114
114
  /** Set when the store has no graph queries, so the shapes went into the default graph instead of `target`. */
115
115
  fallback?: true;
@@ -144,7 +144,7 @@ export async function syncShapeGraphsInto(ds, { core, orphanScope, isOwn, dev, p
144
144
  `${notGenerated.length === 1 ? 'it has' : 'they have'} no shape graph this sync`);
145
145
  }
146
146
  const withoutTurtle = [...noFile, ...notGenerated].sort();
147
- // A shared graph (the store's `shapeGraph` is an IRI) holds every package and the app's shapes.
147
+ // A shared graph (the global `shapeGraph` is an IRI) holds every package and the app's shapes.
148
148
  const shared = result.target && result.target !== 'package' && result.target !== 'default' ? result.target : undefined;
149
149
  const report = {
150
150
  written: result.written,