@_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.
- package/CHANGELOG.md +72 -0
- package/lib/esm/backend.d.ts +23 -5
- package/lib/esm/backend.js +116 -25
- package/lib/esm/backend.js.map +1 -1
- package/lib/esm/shapes/LincdAPI.d.ts +1 -1
- package/lib/esm/shapes/LincdAPI.js +43 -7
- package/lib/esm/shapes/LincdAPI.js.map +1 -1
- package/lib/esm/shapes/LinkedServer.d.ts +59 -39
- package/lib/esm/shapes/LinkedServer.js +158 -93
- package/lib/esm/shapes/LinkedServer.js.map +1 -1
- package/lib/esm/shapes/quadstores/RemoteDataset.d.ts +52 -20
- package/lib/esm/shapes/quadstores/RemoteDataset.js +134 -32
- package/lib/esm/shapes/quadstores/RemoteDataset.js.map +1 -1
- package/lib/esm/utils/adminChannel.d.ts +23 -51
- package/lib/esm/utils/adminChannel.js +50 -38
- package/lib/esm/utils/adminChannel.js.map +1 -1
- package/lib/esm/utils/effectiveRoutes.d.ts +6 -0
- package/lib/esm/utils/effectiveRoutes.js +2 -1
- package/lib/esm/utils/effectiveRoutes.js.map +1 -1
- package/lib/esm/utils/forwardedTransactions.d.ts +46 -0
- package/lib/esm/utils/forwardedTransactions.js +155 -0
- package/lib/esm/utils/forwardedTransactions.js.map +1 -0
- package/lib/esm/utils/graphTargets.d.ts +42 -17
- package/lib/esm/utils/graphTargets.js +62 -69
- package/lib/esm/utils/graphTargets.js.map +1 -1
- package/lib/esm/utils/linkedDependencies.d.ts +53 -7
- package/lib/esm/utils/linkedDependencies.js +130 -12
- package/lib/esm/utils/linkedDependencies.js.map +1 -1
- package/lib/esm/utils/ontologySync.d.ts +55 -31
- package/lib/esm/utils/ontologySync.js +94 -42
- package/lib/esm/utils/ontologySync.js.map +1 -1
- package/lib/esm/utils/queryPlane.d.ts +13 -0
- package/lib/esm/utils/queryPlane.js +49 -2
- package/lib/esm/utils/queryPlane.js.map +1 -1
- package/lib/esm/utils/reloadSource.js +1 -1
- package/lib/esm/utils/reloadSource.js.map +1 -1
- package/lib/esm/utils/serverTransactions.d.ts +22 -0
- package/lib/esm/utils/serverTransactions.js +81 -0
- package/lib/esm/utils/serverTransactions.js.map +1 -0
- package/lib/esm/utils/syncShapes.d.ts +123 -6
- package/lib/esm/utils/syncShapes.js +166 -35
- package/lib/esm/utils/syncShapes.js.map +1 -1
- package/package.json +4 -4
- package/readme.md +158 -38
|
@@ -11,32 +11,57 @@
|
|
|
11
11
|
* `.from(graphs.allOntologies)` reaches the backend as the portable name, and the backend's
|
|
12
12
|
* store expands it under this setting.
|
|
13
13
|
*
|
|
14
|
-
* The syncs
|
|
15
|
-
*
|
|
14
|
+
* The syncs follow the storage routing (core's `syncTargets`); {@link syncTargetsLine} names the
|
|
15
|
+
* datasets they write into when that is more than the default dataset.
|
|
16
16
|
*/
|
|
17
17
|
import { type GraphTargets } from '@_linked/core/utils/graphTargets';
|
|
18
|
+
import type { GraphSyncTargets } from '@_linked/core/shapes/syncTargets';
|
|
19
|
+
import type { IDataset } from '@_linked/core/interfaces/IDataset';
|
|
18
20
|
/**
|
|
19
21
|
* Read `LINKED_ONTOLOGY_GRAPH` / `LINKED_SHAPE_GRAPH` from `env` (checked: an invalid value throws,
|
|
20
22
|
* naming the variable) and set them as the process's graph targets (core's `setGraphTargets`;
|
|
21
23
|
* unset ones are `'package'`). Returns the settings the env gave.
|
|
22
24
|
*/
|
|
23
25
|
export declare function applyGraphTargetsFromEnv(env: Record<string, string | undefined>): Partial<GraphTargets>;
|
|
24
|
-
/** The
|
|
25
|
-
export declare
|
|
26
|
-
/**
|
|
27
|
-
|
|
26
|
+
/** The variable that says who writes the app's shape and ontology graphs. */
|
|
27
|
+
export declare const GRAPH_WRITER_ENV = "LINKED_GRAPH_WRITER";
|
|
28
|
+
/**
|
|
29
|
+
* Who writes the app's shape and ontology graphs: `'app'` (the default) the app itself, at boot;
|
|
30
|
+
* `'host'` a host that runs it (Create Now), which reads the
|
|
31
|
+
* content through `POST /admin/graph-content` and writes it itself, so the app writes none.
|
|
32
|
+
*/
|
|
33
|
+
export type GraphWriter = 'app' | 'host';
|
|
28
34
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
35
|
+
* `LINKED_GRAPH_WRITER` from `env`: unset or empty is `'app'`; any value other than `app` or
|
|
36
|
+
* `host` throws, naming the variable (the boot stops on it).
|
|
31
37
|
*/
|
|
32
|
-
export declare
|
|
38
|
+
export declare function graphWriterFromEnv(env: Record<string, string | undefined>): GraphWriter;
|
|
39
|
+
/**
|
|
40
|
+
* Whether this process writes its shape and ontology graphs: the one check every write path of the
|
|
41
|
+
* syncs goes through (the boot's ontology and shape syncs). False
|
|
42
|
+
* under `LINKED_GRAPH_WRITER=host`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function appWritesGraphs(env?: Record<string, string | undefined>): boolean;
|
|
45
|
+
/** The env variables as set (unset and empty ones left out), for `GET /admin/routes`. */
|
|
46
|
+
export declare function graphTargetEnv(env: Record<string, string | undefined>): Record<string, string>;
|
|
47
|
+
/** Which boot syncs run: only the graphs a running sync writes are named. */
|
|
48
|
+
export interface BootSyncs {
|
|
49
|
+
/** The shape sync runs (`shapeSyncOn`): it writes the shape graphs and the app's shape graph. */
|
|
50
|
+
shapeSync: boolean;
|
|
51
|
+
/** The ontology sync runs (the same switch as the shape sync): it writes the ontology graphs. */
|
|
52
|
+
ontologySync: boolean;
|
|
53
|
+
}
|
|
33
54
|
/**
|
|
34
|
-
* One
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
55
|
+
* One log line naming the datasets the boot syncs that run write into, per graph kind, when the
|
|
56
|
+
* routing sends any graph beyond the default dataset (core's `graphSyncTargets`: a package's
|
|
57
|
+
* shape graph goes wherever its shapes or the shape shapes route, its ontology graph also
|
|
58
|
+
* wherever shapes using its classes or the term shapes route, the app's graph wherever shapes
|
|
59
|
+
* declaring `contains`, or their sub-shapes, route). Undefined when every graph goes to the default dataset only (the
|
|
60
|
+
* syncs' own lines say enough), when no sync runs or without a default dataset. `core` is
|
|
61
|
+
* `@_linked/core/shapes/syncTargets` (server only, imported when the boot runs). Reads the
|
|
62
|
+
* registered shapes outside any shape catalog (run it at boot, never inside `withShapeCatalog`).
|
|
41
63
|
*/
|
|
42
|
-
export declare function
|
|
64
|
+
export declare function syncTargetsLine(syncs: BootSyncs, core: {
|
|
65
|
+
graphSyncTargets: () => GraphSyncTargets;
|
|
66
|
+
datasetLabel: (dataset: IDataset) => string;
|
|
67
|
+
}): string | undefined;
|
|
@@ -11,12 +11,11 @@
|
|
|
11
11
|
* `.from(graphs.allOntologies)` reaches the backend as the portable name, and the backend's
|
|
12
12
|
* store expands it under this setting.
|
|
13
13
|
*
|
|
14
|
-
* The syncs
|
|
15
|
-
*
|
|
14
|
+
* The syncs follow the storage routing (core's `syncTargets`); {@link syncTargetsLine} names the
|
|
15
|
+
* datasets they write into when that is more than the default dataset.
|
|
16
16
|
*/
|
|
17
17
|
import { GRAPH_TARGET_ENV, graphTargetOptionsFromEnv, setGraphTargets, } from '@_linked/core/utils/graphTargets';
|
|
18
18
|
import { LinkedStorage } from '@_linked/core/utils/LinkedStorage';
|
|
19
|
-
import { getAllShapeClasses } from '@_linked/core/utils/ShapeClass';
|
|
20
19
|
/**
|
|
21
20
|
* Read `LINKED_ONTOLOGY_GRAPH` / `LINKED_SHAPE_GRAPH` from `env` (checked: an invalid value throws,
|
|
22
21
|
* naming the variable) and set them as the process's graph targets (core's `setGraphTargets`;
|
|
@@ -27,6 +26,29 @@ export function applyGraphTargetsFromEnv(env) {
|
|
|
27
26
|
setGraphTargets(fromEnv);
|
|
28
27
|
return fromEnv;
|
|
29
28
|
}
|
|
29
|
+
/** The variable that says who writes the app's shape and ontology graphs. */
|
|
30
|
+
export const GRAPH_WRITER_ENV = 'LINKED_GRAPH_WRITER';
|
|
31
|
+
/**
|
|
32
|
+
* `LINKED_GRAPH_WRITER` from `env`: unset or empty is `'app'`; any value other than `app` or
|
|
33
|
+
* `host` throws, naming the variable (the boot stops on it).
|
|
34
|
+
*/
|
|
35
|
+
export function graphWriterFromEnv(env) {
|
|
36
|
+
var _a;
|
|
37
|
+
const value = (_a = env[GRAPH_WRITER_ENV]) === null || _a === void 0 ? void 0 : _a.trim();
|
|
38
|
+
if (!value || value === 'app')
|
|
39
|
+
return 'app';
|
|
40
|
+
if (value === 'host')
|
|
41
|
+
return 'host';
|
|
42
|
+
throw new Error(`${GRAPH_WRITER_ENV} must be 'app' or 'host' (who writes the app's shape and ontology graphs), not ${JSON.stringify(value)}`);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Whether this process writes its shape and ontology graphs: the one check every write path of the
|
|
46
|
+
* syncs goes through (the boot's ontology and shape syncs). False
|
|
47
|
+
* under `LINKED_GRAPH_WRITER=host`.
|
|
48
|
+
*/
|
|
49
|
+
export function appWritesGraphs(env = process.env) {
|
|
50
|
+
return graphWriterFromEnv(env) === 'app';
|
|
51
|
+
}
|
|
30
52
|
/** The env variables as set (unset and empty ones left out), for `GET /admin/routes`. */
|
|
31
53
|
export function graphTargetEnv(env) {
|
|
32
54
|
const out = {};
|
|
@@ -37,77 +59,48 @@ export function graphTargetEnv(env) {
|
|
|
37
59
|
}
|
|
38
60
|
return out;
|
|
39
61
|
}
|
|
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
62
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
63
|
+
* One log line naming the datasets the boot syncs that run write into, per graph kind, when the
|
|
64
|
+
* routing sends any graph beyond the default dataset (core's `graphSyncTargets`: a package's
|
|
65
|
+
* shape graph goes wherever its shapes or the shape shapes route, its ontology graph also
|
|
66
|
+
* wherever shapes using its classes or the term shapes route, the app's graph wherever shapes
|
|
67
|
+
* declaring `contains`, or their sub-shapes, route). Undefined when every graph goes to the default dataset only (the
|
|
68
|
+
* syncs' own lines say enough), when no sync runs or without a default dataset. `core` is
|
|
69
|
+
* `@_linked/core/shapes/syncTargets` (server only, imported when the boot runs). Reads the
|
|
70
|
+
* registered shapes outside any shape catalog (run it at boot, never inside `withShapeCatalog`).
|
|
68
71
|
*/
|
|
69
|
-
function
|
|
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;
|
|
72
|
+
export function syncTargetsLine(syncs, core) {
|
|
89
73
|
const defaultDataset = LinkedStorage.getDefaultDataset();
|
|
90
|
-
if (!defaultDataset)
|
|
74
|
+
if (!defaultDataset || (!syncs.shapeSync && !syncs.ontologySync))
|
|
91
75
|
return undefined;
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
76
|
+
const { datasetLabel } = core;
|
|
77
|
+
const targets = core.graphSyncTargets();
|
|
78
|
+
const beyondDefault = (lists) => [...lists].some((list) => list.some((ds) => ds !== defaultDataset));
|
|
79
|
+
const kinds = [];
|
|
80
|
+
const perDataset = (byPackage) => {
|
|
81
|
+
const all = [...byPackage.keys()];
|
|
82
|
+
return targets.datasets
|
|
83
|
+
.map((ds) => {
|
|
84
|
+
const names = all.filter((name) => { var _a; return (_a = byPackage.get(name)) === null || _a === void 0 ? void 0 : _a.includes(ds); }).sort();
|
|
85
|
+
if (!names.length)
|
|
86
|
+
return undefined;
|
|
87
|
+
return `${datasetLabel(ds)} (${names.length === all.length ? 'every package' : names.join(', ')})`;
|
|
88
|
+
})
|
|
89
|
+
.filter((part) => !!part)
|
|
90
|
+
.join(', ');
|
|
91
|
+
};
|
|
92
|
+
let routed = false;
|
|
93
|
+
if (syncs.shapeSync) {
|
|
94
|
+
routed || (routed = beyondDefault(targets.shapes.values()) || beyondDefault([targets.appShapes]));
|
|
95
|
+
kinds.push(`shape graphs → ${perDataset(targets.shapes)}`);
|
|
96
|
+
kinds.push(`app shape graph → ${targets.appShapes.map(datasetLabel).join(', ')}`);
|
|
97
|
+
}
|
|
98
|
+
if (syncs.ontologySync) {
|
|
99
|
+
routed || (routed = beyondDefault(targets.ontologies.values()));
|
|
100
|
+
kinds.push(`ontology graphs → ${perDataset(targets.ontologies)}`);
|
|
104
101
|
}
|
|
105
|
-
if (
|
|
102
|
+
if (!routed)
|
|
106
103
|
return undefined;
|
|
107
|
-
|
|
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.`);
|
|
104
|
+
return `[LinkedServer] The boot syncs follow the routing: ${kinds.join('; ')}.`;
|
|
112
105
|
}
|
|
113
106
|
//# sourceMappingURL=graphTargets.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphTargets.js","sourceRoot":"","sources":["../../../src/utils/graphTargets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EACL,gBAAgB,EAChB,yBAAyB,EACzB,eAAe,GAEhB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;
|
|
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 follow the storage routing (core's `syncTargets`); {@link syncTargetsLine} names the\n * datasets they write into when that is more than the default dataset.\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 type { GraphSyncTargets } from '@_linked/core/shapes/syncTargets';\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 variable that says who writes the app's shape and ontology graphs. */\nexport const GRAPH_WRITER_ENV = 'LINKED_GRAPH_WRITER';\n\n/**\n * Who writes the app's shape and ontology graphs: `'app'` (the default) the app itself, at boot;\n * `'host'` a host that runs it (Create Now), which reads the\n * content through `POST /admin/graph-content` and writes it itself, so the app writes none.\n */\nexport type GraphWriter = 'app' | 'host';\n\n/**\n * `LINKED_GRAPH_WRITER` from `env`: unset or empty is `'app'`; any value other than `app` or\n * `host` throws, naming the variable (the boot stops on it).\n */\nexport function graphWriterFromEnv(env: Record<string, string | undefined>): GraphWriter {\n const value = env[GRAPH_WRITER_ENV]?.trim();\n if (!value || value === 'app') return 'app';\n if (value === 'host') return 'host';\n throw new Error(\n `${GRAPH_WRITER_ENV} must be 'app' or 'host' (who writes the app's shape and ontology graphs), not ${JSON.stringify(value)}`,\n );\n}\n\n/**\n * Whether this process writes its shape and ontology graphs: the one check every write path of the\n * syncs goes through (the boot's ontology and shape syncs). False\n * under `LINKED_GRAPH_WRITER=host`.\n */\nexport function appWritesGraphs(env: Record<string, string | undefined> = process.env): boolean {\n return graphWriterFromEnv(env) === 'app';\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\n/** Which boot syncs run: only the graphs a running sync writes are named. */\nexport interface BootSyncs {\n /** The shape sync runs (`shapeSyncOn`): it writes the shape graphs and the app's shape graph. */\n shapeSync: boolean;\n /** The ontology sync runs (the same switch as the shape sync): it writes the ontology graphs. */\n ontologySync: boolean;\n}\n\n/**\n * One log line naming the datasets the boot syncs that run write into, per graph kind, when the\n * routing sends any graph beyond the default dataset (core's `graphSyncTargets`: a package's\n * shape graph goes wherever its shapes or the shape shapes route, its ontology graph also\n * wherever shapes using its classes or the term shapes route, the app's graph wherever shapes\n * declaring `contains`, or their sub-shapes, route). Undefined when every graph goes to the default dataset only (the\n * syncs' own lines say enough), when no sync runs or without a default dataset. `core` is\n * `@_linked/core/shapes/syncTargets` (server only, imported when the boot runs). Reads the\n * registered shapes outside any shape catalog (run it at boot, never inside `withShapeCatalog`).\n */\nexport function syncTargetsLine(\n syncs: BootSyncs,\n core: {\n graphSyncTargets: () => GraphSyncTargets;\n datasetLabel: (dataset: IDataset) => string;\n },\n): string | undefined {\n const defaultDataset = LinkedStorage.getDefaultDataset();\n if (!defaultDataset || (!syncs.shapeSync && !syncs.ontologySync)) return undefined;\n const { datasetLabel } = core;\n const targets = core.graphSyncTargets();\n const beyondDefault = (lists: Iterable<IDataset[]>) =>\n [...lists].some((list) => list.some((ds) => ds !== defaultDataset));\n const kinds: string[] = [];\n const perDataset = (byPackage: Map<string, IDataset[]>): string => {\n const all = [...byPackage.keys()];\n return targets.datasets\n .map((ds) => {\n const names = all.filter((name) => byPackage.get(name)?.includes(ds)).sort();\n if (!names.length) return undefined;\n return `${datasetLabel(ds)} (${names.length === all.length ? 'every package' : names.join(', ')})`;\n })\n .filter((part): part is string => !!part)\n .join(', ');\n };\n let routed = false;\n if (syncs.shapeSync) {\n routed ||= beyondDefault(targets.shapes.values()) || beyondDefault([targets.appShapes]);\n kinds.push(`shape graphs → ${perDataset(targets.shapes)}`);\n kinds.push(`app shape graph → ${targets.appShapes.map(datasetLabel).join(', ')}`);\n }\n if (syncs.ontologySync) {\n routed ||= beyondDefault(targets.ontologies.values());\n kinds.push(`ontology graphs → ${perDataset(targets.ontologies)}`);\n }\n if (!routed) return undefined;\n return `[LinkedServer] The boot syncs follow the routing: ${kinds.join('; ')}.`;\n}\n"]}
|
|
@@ -20,12 +20,26 @@ export interface LinkedDependency {
|
|
|
20
20
|
version?: string;
|
|
21
21
|
}[];
|
|
22
22
|
}
|
|
23
|
+
/** What a `package.json` is, by its `linked.kind`. */
|
|
24
|
+
export type LinkedKind = 'app' | 'ontology' | 'assets' | 'library';
|
|
25
|
+
/** Every value `linked.kind` may take. */
|
|
26
|
+
export declare const LINKED_KINDS: readonly LinkedKind[];
|
|
23
27
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
28
|
+
* THE way to tell what a `package.json` is: its `"linked": {"kind": …}`. `app` is an app (built
|
|
29
|
+
* by `linked build-app`); `ontology`, `assets` and `library` are linked packages (an ontology
|
|
30
|
+
* package may carry shapes for its own terms; `library` is framework code). Undefined for
|
|
31
|
+
* anything else: no `linked` object and a kind that is not one of these.
|
|
32
|
+
*
|
|
33
|
+
* Until every published package carries `linked.kind`, a `package.json` without one is still
|
|
34
|
+
* read by the retired flags: `linkedApp: true` is an `app`, `linkedPackage: true` a `library`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function linkedKind(json: unknown): LinkedKind | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* A package whose backend providers the server loads at boot: a named package
|
|
39
|
+
* whose `linked.kind` is not `app` ({@link linkedKind}). That is the only test —
|
|
26
40
|
* not the package's scope. `@_linked/localize` is in the `@_linked` scope and
|
|
27
|
-
* is a CLI tool, not a linked package; a custom-scope package with
|
|
28
|
-
* a linked package. The CLI's workspace discovery uses the same
|
|
41
|
+
* is a CLI tool, not a linked package; a custom-scope package with a kind is
|
|
42
|
+
* a linked package. The CLI's workspace discovery uses the same test.
|
|
29
43
|
*
|
|
30
44
|
* The legacy `"lincd": true` flag is deliberately NOT enough. Those packages
|
|
31
45
|
* import the old `lincd` core, and loading them at boot is what produced
|
|
@@ -50,7 +64,34 @@ export declare function readInstalledPackage(name: string, fromDir: string): {
|
|
|
50
64
|
json: any;
|
|
51
65
|
} | null;
|
|
52
66
|
/**
|
|
53
|
-
*
|
|
67
|
+
* The npm names a `package.json` lists in `linked.unpublishedPackages` (K-unpublished): packages
|
|
68
|
+
* it uses that are not on npm, localized into the app's `packages-local/`. The server treats them
|
|
69
|
+
* as direct dependencies of whoever lists them. Read with the cli's one reader, so a malformed
|
|
70
|
+
* list throws rather than shrinking silently.
|
|
71
|
+
*/
|
|
72
|
+
export declare function unpublishedNames(json: unknown): string[];
|
|
73
|
+
/**
|
|
74
|
+
* A package the app lists in `linked.unpublishedPackages`, found by its npm name: first the
|
|
75
|
+
* way Node finds it (`node_modules/<name>` from `fromDir` up, which is npm's workspace link into
|
|
76
|
+
* `packages-local/` once the app is installed), else among `<appDir>/packages-local/<dir>`
|
|
77
|
+
* by the `name` in each `package.json` (a checkout not yet installed). Null when there is no
|
|
78
|
+
* checkout of it.
|
|
79
|
+
*/
|
|
80
|
+
export declare function findListedPackage(name: string, fromDir: string, appDir: string): {
|
|
81
|
+
root: string;
|
|
82
|
+
json: any;
|
|
83
|
+
} | null;
|
|
84
|
+
/**
|
|
85
|
+
* Every name in the app's `linked.unpublishedPackages`, and transitively in the lists of the
|
|
86
|
+
* listed packages it finds ({@link findListedPackage}): the packages the server treats as the
|
|
87
|
+
* app's own direct dependencies. A listed package without a checkout still counts; only its own
|
|
88
|
+
* list cannot be read.
|
|
89
|
+
*/
|
|
90
|
+
export declare function listedPackageNames(appDir: string, appPackageJson: any): Set<string>;
|
|
91
|
+
/**
|
|
92
|
+
* Every linked package reachable from the app's `dependencies` and its
|
|
93
|
+
* `linked.unpublishedPackages` (transitively, through each package's own
|
|
94
|
+
* `dependencies` and list), each one AFTER
|
|
54
95
|
* the linked packages it depends on. Providers register middleware in the
|
|
55
96
|
* order they are indexed, so a package's middleware must not run before that
|
|
56
97
|
* of a package it builds on (e.g. anything reading `request.linkedAuth` after
|
|
@@ -68,10 +109,15 @@ export declare function readInstalledPackage(name: string, fromDir: string): {
|
|
|
68
109
|
* is the one the app itself resolves, so it is the same module instance the
|
|
69
110
|
* app's own imports reach; when the app cannot resolve the package at all
|
|
70
111
|
* (it is only installed nested) it is the first copy found.
|
|
112
|
+
*
|
|
113
|
+
* `isLinked` decides which installed packages are linked ones (default
|
|
114
|
+
* {@link isLinkedPackageJson}); a caller reading installs of another
|
|
115
|
+
* generation passes its own.
|
|
71
116
|
*/
|
|
72
|
-
export declare function discoverLinkedDependencies(appDir: string, appPackageJson: any): LinkedDependency[];
|
|
117
|
+
export declare function discoverLinkedDependencies(appDir: string, appPackageJson: any, isLinked?: (json: any) => boolean): LinkedDependency[];
|
|
73
118
|
/**
|
|
74
|
-
* Package name → the names of its direct `dependencies
|
|
119
|
+
* Package name → the names of its direct `dependencies`, `peerDependencies` and
|
|
120
|
+
* `linked.unpublishedPackages`, for the app
|
|
75
121
|
* (`appPackageJson`) and every package in `packageDirs` (name → package root, as discovery
|
|
76
122
|
* found it). The shape check scopes its direction-I errors with it. A package whose
|
|
77
123
|
* `package.json` cannot be read is left out.
|
|
@@ -1,11 +1,48 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
+
import { unpublishedPackages } from '@_linked/cli/installed-packages';
|
|
4
|
+
/** Every value `linked.kind` may take. */
|
|
5
|
+
export const LINKED_KINDS = [
|
|
6
|
+
'app',
|
|
7
|
+
'ontology',
|
|
8
|
+
'assets',
|
|
9
|
+
'library',
|
|
10
|
+
];
|
|
3
11
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
12
|
+
* THE way to tell what a `package.json` is: its `"linked": {"kind": …}`. `app` is an app (built
|
|
13
|
+
* by `linked build-app`); `ontology`, `assets` and `library` are linked packages (an ontology
|
|
14
|
+
* package may carry shapes for its own terms; `library` is framework code). Undefined for
|
|
15
|
+
* anything else: no `linked` object and a kind that is not one of these.
|
|
16
|
+
*
|
|
17
|
+
* Until every published package carries `linked.kind`, a `package.json` without one is still
|
|
18
|
+
* read by the retired flags: `linkedApp: true` is an `app`, `linkedPackage: true` a `library`.
|
|
19
|
+
*/
|
|
20
|
+
export function linkedKind(json) {
|
|
21
|
+
var _a;
|
|
22
|
+
if (!json || typeof json !== 'object')
|
|
23
|
+
return undefined;
|
|
24
|
+
const linked = json.linked;
|
|
25
|
+
if (!linked || typeof linked !== 'object')
|
|
26
|
+
return retiredFlagKind(json);
|
|
27
|
+
const kind = linked.kind;
|
|
28
|
+
return (_a = LINKED_KINDS.find((k) => k === kind)) !== null && _a !== void 0 ? _a : retiredFlagKind(json);
|
|
29
|
+
}
|
|
30
|
+
/** The kind a `package.json` published before `linked.kind` declares by its retired flags. */
|
|
31
|
+
function retiredFlagKind(json) {
|
|
32
|
+
const flags = json;
|
|
33
|
+
if (flags.linkedApp === true)
|
|
34
|
+
return 'app';
|
|
35
|
+
if (flags.linkedPackage === true)
|
|
36
|
+
return 'library';
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
// end of the linkedKind twin.
|
|
40
|
+
/**
|
|
41
|
+
* A package whose backend providers the server loads at boot: a named package
|
|
42
|
+
* whose `linked.kind` is not `app` ({@link linkedKind}). That is the only test —
|
|
6
43
|
* not the package's scope. `@_linked/localize` is in the `@_linked` scope and
|
|
7
|
-
* is a CLI tool, not a linked package; a custom-scope package with
|
|
8
|
-
* a linked package. The CLI's workspace discovery uses the same
|
|
44
|
+
* is a CLI tool, not a linked package; a custom-scope package with a kind is
|
|
45
|
+
* a linked package. The CLI's workspace discovery uses the same test.
|
|
9
46
|
*
|
|
10
47
|
* The legacy `"lincd": true` flag is deliberately NOT enough. Those packages
|
|
11
48
|
* import the old `lincd` core, and loading them at boot is what produced
|
|
@@ -15,7 +52,8 @@ import * as path from 'path';
|
|
|
15
52
|
export function isLinkedPackageJson(json) {
|
|
16
53
|
if (!json || typeof json.name !== 'string')
|
|
17
54
|
return false;
|
|
18
|
-
|
|
55
|
+
const kind = linkedKind(json);
|
|
56
|
+
return kind !== undefined && kind !== 'app';
|
|
19
57
|
}
|
|
20
58
|
/**
|
|
21
59
|
* Find an installed package the way Node does: `<dir>/node_modules/<name>`,
|
|
@@ -66,7 +104,73 @@ export function readInstalledPackage(name, fromDir) {
|
|
|
66
104
|
}
|
|
67
105
|
}
|
|
68
106
|
/**
|
|
69
|
-
*
|
|
107
|
+
* The npm names a `package.json` lists in `linked.unpublishedPackages` (K-unpublished): packages
|
|
108
|
+
* it uses that are not on npm, localized into the app's `packages-local/`. The server treats them
|
|
109
|
+
* as direct dependencies of whoever lists them. Read with the cli's one reader, so a malformed
|
|
110
|
+
* list throws rather than shrinking silently.
|
|
111
|
+
*/
|
|
112
|
+
export function unpublishedNames(json) {
|
|
113
|
+
return unpublishedPackages(json).map((p) => p.name);
|
|
114
|
+
}
|
|
115
|
+
/** Where a listed package's checkout lives in the app, when npm has not linked it yet. */
|
|
116
|
+
const LOCAL_DIR = 'packages-local';
|
|
117
|
+
/**
|
|
118
|
+
* A package the app lists in `linked.unpublishedPackages`, found by its npm name: first the
|
|
119
|
+
* way Node finds it (`node_modules/<name>` from `fromDir` up, which is npm's workspace link into
|
|
120
|
+
* `packages-local/` once the app is installed), else among `<appDir>/packages-local/<dir>`
|
|
121
|
+
* by the `name` in each `package.json` (a checkout not yet installed). Null when there is no
|
|
122
|
+
* checkout of it.
|
|
123
|
+
*/
|
|
124
|
+
export function findListedPackage(name, fromDir, appDir) {
|
|
125
|
+
const installed = readInstalledPackage(name, fromDir);
|
|
126
|
+
if (installed)
|
|
127
|
+
return installed;
|
|
128
|
+
const localDir = path.join(appDir, LOCAL_DIR);
|
|
129
|
+
let entries = [];
|
|
130
|
+
try {
|
|
131
|
+
entries = fs.readdirSync(localDir).sort();
|
|
132
|
+
}
|
|
133
|
+
catch (_a) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
for (const entry of entries) {
|
|
137
|
+
const root = path.join(localDir, entry);
|
|
138
|
+
try {
|
|
139
|
+
const json = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf-8'));
|
|
140
|
+
if ((json === null || json === void 0 ? void 0 : json.name) === name)
|
|
141
|
+
return { root, json };
|
|
142
|
+
}
|
|
143
|
+
catch (_b) { }
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Every name in the app's `linked.unpublishedPackages`, and transitively in the lists of the
|
|
149
|
+
* listed packages it finds ({@link findListedPackage}): the packages the server treats as the
|
|
150
|
+
* app's own direct dependencies. A listed package without a checkout still counts; only its own
|
|
151
|
+
* list cannot be read.
|
|
152
|
+
*/
|
|
153
|
+
export function listedPackageNames(appDir, appPackageJson) {
|
|
154
|
+
const names = new Set();
|
|
155
|
+
const queue = unpublishedNames(appPackageJson).map((name) => ({ name, fromDir: appDir }));
|
|
156
|
+
while (queue.length) {
|
|
157
|
+
const { name, fromDir } = queue.shift();
|
|
158
|
+
if (names.has(name) || name === (appPackageJson === null || appPackageJson === void 0 ? void 0 : appPackageJson.name))
|
|
159
|
+
continue;
|
|
160
|
+
names.add(name);
|
|
161
|
+
const found = findListedPackage(name, fromDir, appDir);
|
|
162
|
+
if (!found)
|
|
163
|
+
continue;
|
|
164
|
+
const root = realpathOr(found.root);
|
|
165
|
+
for (const next of unpublishedNames(found.json))
|
|
166
|
+
queue.push({ name: next, fromDir: root });
|
|
167
|
+
}
|
|
168
|
+
return names;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Every linked package reachable from the app's `dependencies` and its
|
|
172
|
+
* `linked.unpublishedPackages` (transitively, through each package's own
|
|
173
|
+
* `dependencies` and list), each one AFTER
|
|
70
174
|
* the linked packages it depends on. Providers register middleware in the
|
|
71
175
|
* order they are indexed, so a package's middleware must not run before that
|
|
72
176
|
* of a package it builds on (e.g. anything reading `request.linkedAuth` after
|
|
@@ -84,19 +188,25 @@ export function readInstalledPackage(name, fromDir) {
|
|
|
84
188
|
* is the one the app itself resolves, so it is the same module instance the
|
|
85
189
|
* app's own imports reach; when the app cannot resolve the package at all
|
|
86
190
|
* (it is only installed nested) it is the first copy found.
|
|
191
|
+
*
|
|
192
|
+
* `isLinked` decides which installed packages are linked ones (default
|
|
193
|
+
* {@link isLinkedPackageJson}); a caller reading installs of another
|
|
194
|
+
* generation passes its own.
|
|
87
195
|
*/
|
|
88
|
-
export function discoverLinkedDependencies(appDir, appPackageJson) {
|
|
196
|
+
export function discoverLinkedDependencies(appDir, appPackageJson, isLinked = isLinkedPackageJson) {
|
|
89
197
|
var _a;
|
|
90
198
|
const out = [];
|
|
91
199
|
const byName = new Map();
|
|
92
200
|
const visitedRoots = new Set();
|
|
93
201
|
const appName = appPackageJson === null || appPackageJson === void 0 ? void 0 : appPackageJson.name;
|
|
94
|
-
const visit = (name, fromDir) => {
|
|
202
|
+
const visit = (name, fromDir, listed = false) => {
|
|
95
203
|
var _a;
|
|
96
204
|
if (name === appName)
|
|
97
205
|
return;
|
|
98
|
-
const installed =
|
|
99
|
-
|
|
206
|
+
const installed = listed
|
|
207
|
+
? findListedPackage(name, fromDir, appDir)
|
|
208
|
+
: readInstalledPackage(name, fromDir);
|
|
209
|
+
if (!installed || !isLinked(installed.json))
|
|
100
210
|
return;
|
|
101
211
|
const realRoot = realpathOr(installed.root);
|
|
102
212
|
if (visitedRoots.has(realRoot))
|
|
@@ -111,6 +221,9 @@ export function discoverLinkedDependencies(appDir, appPackageJson) {
|
|
|
111
221
|
for (const dep of Object.keys((_a = installed.json.dependencies) !== null && _a !== void 0 ? _a : {})) {
|
|
112
222
|
visit(dep, realRoot);
|
|
113
223
|
}
|
|
224
|
+
for (const dep of unpublishedNames(installed.json)) {
|
|
225
|
+
visit(dep, realRoot, true);
|
|
226
|
+
}
|
|
114
227
|
// Pushed after its dependencies, once per name: the first copy found
|
|
115
228
|
// fixes the package's place in the order.
|
|
116
229
|
if (!out.includes(entry))
|
|
@@ -119,11 +232,14 @@ export function discoverLinkedDependencies(appDir, appPackageJson) {
|
|
|
119
232
|
for (const name of Object.keys((_a = appPackageJson === null || appPackageJson === void 0 ? void 0 : appPackageJson.dependencies) !== null && _a !== void 0 ? _a : {})) {
|
|
120
233
|
visit(name, appDir);
|
|
121
234
|
}
|
|
235
|
+
for (const name of unpublishedNames(appPackageJson)) {
|
|
236
|
+
visit(name, appDir, true);
|
|
237
|
+
}
|
|
122
238
|
for (const entry of out) {
|
|
123
239
|
if (entry.copies.length < 2)
|
|
124
240
|
continue;
|
|
125
241
|
const fromApp = readInstalledPackage(entry.packageName, appDir);
|
|
126
|
-
if (fromApp &&
|
|
242
|
+
if (fromApp && isLinked(fromApp.json)) {
|
|
127
243
|
const appCopy = realpathOr(fromApp.root);
|
|
128
244
|
if (entry.copies.some((c) => c.path === appCopy))
|
|
129
245
|
entry.path = appCopy;
|
|
@@ -132,7 +248,8 @@ export function discoverLinkedDependencies(appDir, appPackageJson) {
|
|
|
132
248
|
return out;
|
|
133
249
|
}
|
|
134
250
|
/**
|
|
135
|
-
* Package name → the names of its direct `dependencies
|
|
251
|
+
* Package name → the names of its direct `dependencies`, `peerDependencies` and
|
|
252
|
+
* `linked.unpublishedPackages`, for the app
|
|
136
253
|
* (`appPackageJson`) and every package in `packageDirs` (name → package root, as discovery
|
|
137
254
|
* found it). The shape check scopes its direction-I errors with it. A package whose
|
|
138
255
|
* `package.json` cannot be read is left out.
|
|
@@ -147,6 +264,7 @@ export function readDependencyLists(packageDirs, appPackageJson) {
|
|
|
147
264
|
...new Set([
|
|
148
265
|
...Object.keys((_a = json === null || json === void 0 ? void 0 : json.dependencies) !== null && _a !== void 0 ? _a : {}),
|
|
149
266
|
...Object.keys((_b = json === null || json === void 0 ? void 0 : json.peerDependencies) !== null && _b !== void 0 ? _b : {}),
|
|
267
|
+
...unpublishedNames(json),
|
|
150
268
|
]),
|
|
151
269
|
].sort();
|
|
152
270
|
};
|