@_linked/server 3.7.0 → 3.8.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 +45 -0
- package/lib/esm/backend.d.ts +9 -0
- package/lib/esm/backend.js +28 -1
- package/lib/esm/backend.js.map +1 -1
- package/lib/esm/shapes/LinkedServer.d.ts +3 -3
- package/lib/esm/shapes/LinkedServer.js +8 -5
- package/lib/esm/shapes/LinkedServer.js.map +1 -1
- package/lib/esm/shapes/quadstores/RemoteDataset.d.ts +41 -1
- package/lib/esm/shapes/quadstores/RemoteDataset.js +152 -4
- package/lib/esm/shapes/quadstores/RemoteDataset.js.map +1 -1
- package/lib/esm/utils/adminChannel.d.ts +24 -2
- package/lib/esm/utils/adminChannel.js +43 -2
- package/lib/esm/utils/adminChannel.js.map +1 -1
- package/lib/esm/utils/ontologySync.d.ts +22 -4
- package/lib/esm/utils/ontologySync.js +28 -7
- package/lib/esm/utils/ontologySync.js.map +1 -1
- package/lib/esm/utils/queryPlane.d.ts +21 -0
- package/lib/esm/utils/queryPlane.js +54 -0
- package/lib/esm/utils/queryPlane.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
1
1
|
# @\_linked/server
|
|
2
2
|
|
|
3
|
+
## 3.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#204](https://github.com/linked-fw/server/pull/204) [`f1dc1a6`](https://github.com/linked-fw/server/commit/f1dc1a6fec0abae90c711daec51e929a9587b582) Thanks [@flyon](https://github.com/flyon)! - Graph queries through the server (named graphs and the graph registry, `@_linked/core`'s
|
|
8
|
+
`graphQuery`):
|
|
9
|
+
|
|
10
|
+
- `RemoteDataset.graphQuery`: graph queries (`graph_create`, `graph_replace`, `graph_patch`,
|
|
11
|
+
`graph_drop`) go out on the query wire like every other query, with the same token and
|
|
12
|
+
end-user header. A refusal comes back as core's `GraphQueryError` with its code; a server or
|
|
13
|
+
gateway without the method (404, 501) reads as `unsupported-query-kind`, so the ontology sync
|
|
14
|
+
falls back to the default graph there.
|
|
15
|
+
- In the url form, `RemoteDataset` expands `graphs.allOntologies` and `graphs.allShapes` in a
|
|
16
|
+
read's `.from()` set from its own graph-registry cache (per dataset, keyed by the url and the
|
|
17
|
+
dataset the server names in its `ping`, updated by its own graph queries, re-read after 30
|
|
18
|
+
seconds); `invalidateGraphRegistry(dataset?)` drops it. When the registry cannot be read, the
|
|
19
|
+
names are sent unexpanded.
|
|
20
|
+
- The generic plane answers `/call/@_linked/server/graphQuery`: the body is checked with core's
|
|
21
|
+
`parseGraphQuery`, the `graph` rule of the store its record class routes to decides
|
|
22
|
+
(`withAccess({graph})`; no rule refuses with 403), and `LinkedStorage.graphQuery` runs it. A
|
|
23
|
+
store's refusal answers with a status and its code: `{error, code}` (409 `graph-exists`, 409
|
|
24
|
+
`graph-not-registered`, 400 `graph-name-read-only`, 501 `unsupported-query-kind`). Any
|
|
25
|
+
`ServerCallError` carrying a string `code` now sends it in the error body.
|
|
26
|
+
- Control channel: `POST /admin/graph-registry-changed {dataset}` (with `CN_APP_ADMIN_SECRET`)
|
|
27
|
+
drops the process's cached graph registry, so the next expanding read re-reads it.
|
|
28
|
+
- The ontology phase (boot and `POST /admin/sync-shapes`) reports and logs the graphs the sync
|
|
29
|
+
wrote and dropped (`ontologies.graphs`, `ontologies.droppedGraphs`), and says when a store
|
|
30
|
+
without graph queries got the default-graph sync.
|
|
31
|
+
|
|
32
|
+
Breaking changes:
|
|
33
|
+
|
|
34
|
+
- Requires the `@_linked/core` with graph queries (`IDataset.graphQuery`, `NamedGraph`, the graph
|
|
35
|
+
registry cache), which in turn requires `ghcr.io/linked-fw/fuseki:6.2.0-2` or a store that
|
|
36
|
+
builds its hierarchy from the registry; and the `@_linked/server-utils` whose `QueryAccess` has
|
|
37
|
+
the `graph` operation (with an older one every graph query is refused). Both ranges are raised
|
|
38
|
+
at release.
|
|
39
|
+
- Graph queries on the generic plane are refused unless the store declares a `graph` rule with
|
|
40
|
+
`withAccess`.
|
|
41
|
+
- `.from(graphs.allOntologies)` and `.from(graphs.allShapes)` reads through a url-form
|
|
42
|
+
`RemoteDataset` now also select the `OntologyGraph` and `ShapesGraph` records on the data
|
|
43
|
+
server; its read rule decides whether they are answered (when refused, the names go
|
|
44
|
+
unexpanded).
|
|
45
|
+
- A `ServerCallError` that carries a string `code` now sends it in the error body
|
|
46
|
+
(`{error, code}`).
|
|
47
|
+
|
|
3
48
|
## 3.7.0
|
|
4
49
|
|
|
5
50
|
### Minor Changes
|
package/lib/esm/backend.d.ts
CHANGED
|
@@ -14,4 +14,13 @@ export default class LincdServerBackendProvider extends BackendProvider {
|
|
|
14
14
|
updateQuery(json: any): Promise<unknown>;
|
|
15
15
|
createQuery(json: any): Promise<unknown>;
|
|
16
16
|
deleteQuery(json: any): Promise<import("@_linked/core/queries/DeleteQuery.js").DeleteResponse>;
|
|
17
|
+
/**
|
|
18
|
+
* A whole-graph operation (`graph_create`, `graph_replace`, `graph_patch`, `graph_drop`), as
|
|
19
|
+
* `RemoteDataset.graphQuery` sends it. The query is plain data: core's `parseGraphQuery` checks
|
|
20
|
+
* it, the `graph` rule of the store its record class routes to decides (no rule refuses), and
|
|
21
|
+
* `LinkedStorage.graphQuery` runs it outside any shape catalog; no catalog is resolved for it,
|
|
22
|
+
* so the check resolves the same store. A store's refusal answers with its code (see
|
|
23
|
+
* `graphQueryCallError`).
|
|
24
|
+
*/
|
|
25
|
+
graphQuery(json: any): Promise<import("@_linked/core").GraphResult>;
|
|
17
26
|
}
|
package/lib/esm/backend.js
CHANGED
|
@@ -12,7 +12,8 @@ import { callable } from '@_linked/server-utils/utils/callable';
|
|
|
12
12
|
import { LinkedFileStorage } from '@_linked/core/utils/LinkedFileStorage';
|
|
13
13
|
import { LinkedStorage } from '@_linked/core/utils/LinkedStorage';
|
|
14
14
|
import { LocalFileStore } from './shapes/filestores/LocalFileStore.js';
|
|
15
|
-
import { authorizeGenericQuery, resolveQueryCatalog, toQueryBuilder, } from './utils/queryPlane.js';
|
|
15
|
+
import { authorizeGenericQuery, authorizeGraphQuery, graphQueryCallError, resolveQueryCatalog, toGraphQuery, toQueryBuilder, } from './utils/queryPlane.js';
|
|
16
|
+
import { ServerCallError } from '@_linked/server-utils/utils/ServerCallError';
|
|
16
17
|
import path from 'path';
|
|
17
18
|
import fs from 'fs/promises';
|
|
18
19
|
export default class LincdServerBackendProvider extends BackendProvider {
|
|
@@ -82,6 +83,26 @@ export default class LincdServerBackendProvider extends BackendProvider {
|
|
|
82
83
|
await authorizeGenericQuery('delete', json, query, 'deleteQuery');
|
|
83
84
|
return LinkedStorage.deleteQuery(query);
|
|
84
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* A whole-graph operation (`graph_create`, `graph_replace`, `graph_patch`, `graph_drop`), as
|
|
88
|
+
* `RemoteDataset.graphQuery` sends it. The query is plain data: core's `parseGraphQuery` checks
|
|
89
|
+
* it, the `graph` rule of the store its record class routes to decides (no rule refuses), and
|
|
90
|
+
* `LinkedStorage.graphQuery` runs it outside any shape catalog; no catalog is resolved for it,
|
|
91
|
+
* so the check resolves the same store. A store's refusal answers with its code (see
|
|
92
|
+
* `graphQueryCallError`).
|
|
93
|
+
*/
|
|
94
|
+
async graphQuery(json) {
|
|
95
|
+
const query = toGraphQuery(json);
|
|
96
|
+
await authorizeGraphQuery(json, query, 'graphQuery');
|
|
97
|
+
if (!query)
|
|
98
|
+
throw new ServerCallError(400, 'Invalid graph query');
|
|
99
|
+
try {
|
|
100
|
+
return await LinkedStorage.graphQuery(query);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
throw graphQueryCallError(err);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
85
106
|
}
|
|
86
107
|
__decorate([
|
|
87
108
|
callable('public'),
|
|
@@ -119,4 +140,10 @@ __decorate([
|
|
|
119
140
|
__metadata("design:paramtypes", [Object]),
|
|
120
141
|
__metadata("design:returntype", Promise)
|
|
121
142
|
], LincdServerBackendProvider.prototype, "deleteQuery", null);
|
|
143
|
+
__decorate([
|
|
144
|
+
callable('public'),
|
|
145
|
+
__metadata("design:type", Function),
|
|
146
|
+
__metadata("design:paramtypes", [Object]),
|
|
147
|
+
__metadata("design:returntype", Promise)
|
|
148
|
+
], LincdServerBackendProvider.prototype, "graphQuery", null);
|
|
122
149
|
//# sourceMappingURL=backend.js.map
|
package/lib/esm/backend.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../../src/backend.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AACvE,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,aAAa,CAAC;AAE7B,MAAM,CAAC,OAAO,OAAO,0BAA2B,SAAQ,eAAe;IACrE,KAAK,CAAC,sBAAsB;QAC1B,IAAI,CAAC,iBAAiB,CAAC,eAAe,EAAE,EAAE,CAAC;YACzC,iBAAiB,CAAC,eAAe,CAC/B,IAAI,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,YAAY,CAAC,CACxD,CAAC;QACJ,CAAC;QACD,IAAI,oBAAoB,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAC3D,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,YAAY,CAAC,EAAE;gBAC5D,SAAS,EAAE,IAAI;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED;;;;OAIG;IAEG,AAAN,KAAK,CAAC,IAAI;QACR,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAED,4EAA4E;IAC5E,EAAE;IACF,wDAAwD;IACxD,0FAA0F;IAC1F,wFAAwF;IACxF,qFAAqF;IACrF,EAAE;IACF,sFAAsF;IACtF,sFAAsF;IACtF,oFAAoF;IACpF,wFAAwF;IACxF,2EAA2E;IAC3E,EAAE;IACF,yEAAyE;IACzE,4EAA4E;IAC5E,0EAA0E;IAC1E,4EAA4E;IAC5E,4EAA4E;IAC5E,eAAe;IAGT,AAAN,KAAK,CAAC,WAAW,CAAC,IAAS;QACzB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,MAAM,qBAAqB,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;QAClE,OAAO,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAGK,AAAN,KAAK,CAAC,QAAQ,CAAC,IAAS;QACtB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,MAAM,qBAAqB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;QAC5D,OAAO,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAGK,AAAN,KAAK,CAAC,WAAW,CAAC,IAAS;QACzB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,MAAM,qBAAqB,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;QAClE,OAAO,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAGK,AAAN,KAAK,CAAC,WAAW,CAAC,IAAS;QACzB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,MAAM,qBAAqB,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;QAClE,OAAO,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAGK,AAAN,KAAK,CAAC,WAAW,CAAC,IAAS;QACzB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,MAAM,qBAAqB,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;QAClE,OAAO,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../../src/backend.ts"],"names":[],"mappings":"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","sourcesContent":["import { BackendProvider } from '@_linked/server-utils/utils/BackendProvider';\nimport { callable } from '@_linked/server-utils/utils/callable';\nimport { LinkedFileStorage } from '@_linked/core/utils/LinkedFileStorage';\nimport { LinkedStorage } from '@_linked/core/utils/LinkedStorage';\nimport { LocalFileStore } from './shapes/filestores/LocalFileStore.js';\nimport {\n authorizeGenericQuery,\n authorizeGraphQuery,\n graphQueryCallError,\n resolveQueryCatalog,\n toGraphQuery,\n toQueryBuilder,\n} from './utils/queryPlane.js';\nimport { ServerCallError } from '@_linked/server-utils/utils/ServerCallError';\nimport path from 'path';\nimport fs from 'fs/promises';\n\nexport default class LincdServerBackendProvider extends BackendProvider {\n async setupBeforeControllers() {\n if (!LinkedFileStorage.getDefaultStore()) {\n LinkedFileStorage.setDefaultStore(\n new LocalFileStore(process.env.NODE_ENV + '-filestore')\n );\n }\n let fileSystemUploadPath = path.join('data', 'filestores');\n try {\n await fs.access(fileSystemUploadPath);\n } catch (err) {\n await fs.mkdir(path.join(fileSystemUploadPath, 'filestores'), {\n recursive: true,\n });\n }\n }\n\n /**\n * Reachability check for a `RemoteDataset` pointed at this server: reads nothing, changes\n * nothing. A plain linked server has no token concept, so it always answers `{ok: true}`;\n * a host that serves the wire with tokens answers 401 for a refused one.\n */\n @callable('public')\n async ping(): Promise<{ ok: true }> {\n return { ok: true };\n }\n\n // ── Generic query execution ──────────────────────────────────────────────\n //\n // These answer `RemoteDataset`: a browser's store calls\n // `Server.call(packageName, {method}, json)` (the PACKAGE form), and a remote app's store\n // posts the same `{args}` body to `{url}/call/@_linked/server/<method>`. Either way the\n // request arrives here on the generic provider rather than through Shape resolution.\n //\n // A query cannot cross the wire live, so the client ships `toJSON()` and `fromJSON()`\n // rehydrates it here into a live, closed query. `LinkedStorage` then routes it by the\n // QUERY's shape, which is what decides the target dataset; the store instance never\n // participates. The host's catalog resolver (`setQueryCatalogResolver`) picks the shape\n // catalog the JSON is decoded in; the builder keeps it for both lowerings.\n //\n // Every query is checked first against the access rules of the stores it\n // maps to, declared in the app's storage config (`withAccess`; a store with\n // no rule requires a session): see utils/queryPlane. INTERIM model, to be\n // rethought. The store runs the builder that was checked. They are declared\n // 'public' because that check, not the RPC layer, decides whether a session\n // is required.\n\n @callable('public')\n async selectQuery(json: any) {\n const query = toQueryBuilder(json, await resolveQueryCatalog(json));\n await authorizeGenericQuery('select', json, query, 'selectQuery');\n return LinkedStorage.selectQuery(query);\n }\n\n @callable('public')\n async askQuery(json: any) {\n const query = toQueryBuilder(json, await resolveQueryCatalog(json));\n await authorizeGenericQuery('ask', json, query, 'askQuery');\n return LinkedStorage.askQuery(query);\n }\n\n @callable('public')\n async updateQuery(json: any) {\n const query = toQueryBuilder(json, await resolveQueryCatalog(json));\n await authorizeGenericQuery('update', json, query, 'updateQuery');\n return LinkedStorage.updateQuery(query);\n }\n\n @callable('public')\n async createQuery(json: any) {\n const query = toQueryBuilder(json, await resolveQueryCatalog(json));\n await authorizeGenericQuery('create', json, query, 'createQuery');\n return LinkedStorage.createQuery(query);\n }\n\n @callable('public')\n async deleteQuery(json: any) {\n const query = toQueryBuilder(json, await resolveQueryCatalog(json));\n await authorizeGenericQuery('delete', json, query, 'deleteQuery');\n return LinkedStorage.deleteQuery(query);\n }\n\n /**\n * A whole-graph operation (`graph_create`, `graph_replace`, `graph_patch`, `graph_drop`), as\n * `RemoteDataset.graphQuery` sends it. The query is plain data: core's `parseGraphQuery` checks\n * it, the `graph` rule of the store its record class routes to decides (no rule refuses), and\n * `LinkedStorage.graphQuery` runs it outside any shape catalog; no catalog is resolved for it,\n * so the check resolves the same store. A store's refusal answers with its code (see\n * `graphQueryCallError`).\n */\n @callable('public')\n async graphQuery(json: any) {\n const query = toGraphQuery(json);\n await authorizeGraphQuery(json, query, 'graphQuery');\n if (!query) throw new ServerCallError(400, 'Invalid graph query');\n try {\n return await LinkedStorage.graphQuery(query);\n } catch (err) {\n throw graphQueryCallError(err);\n }\n }\n}\n"]}
|
|
@@ -130,7 +130,7 @@ export declare class LinkedServer extends Shape {
|
|
|
130
130
|
/** One shape sync into the default dataset; throws when it fails. */
|
|
131
131
|
private syncRegisteredShapes;
|
|
132
132
|
/**
|
|
133
|
-
* Boot: sync the registered ontologies
|
|
133
|
+
* Boot: sync the registered ontologies into their graphs in app data and run the shape
|
|
134
134
|
* check, before the shape sync (see utils/ontologySync). The sync follows the shape sync's
|
|
135
135
|
* switch (`syncShapesOnBoot`, `LINKED_SYNC_SHAPES_ON_BOOT`), plus the opt-out
|
|
136
136
|
* `LINKED_SYNC_ONTOLOGIES_ON_BOOT=false`; the in-memory class hierarchy is loaded either way.
|
|
@@ -141,7 +141,7 @@ export declare class LinkedServer extends Shape {
|
|
|
141
141
|
* Every discovered linked package and every workspace package of the app registers its
|
|
142
142
|
* ontologies (in dev, an unbuilt one through Vite), then the ontology sync (when
|
|
143
143
|
* `sync` is set) into the default dataset, then the shape check.
|
|
144
|
-
* Orphaned sync nodes are pruned under the shape sync's orphan policy
|
|
144
|
+
* Orphaned ontology graphs (and earlier sync nodes) are pruned under the shape sync's orphan policy
|
|
145
145
|
* (`LINKED_SYNC_SHAPES_PRUNE_ORPHANS`).
|
|
146
146
|
*/
|
|
147
147
|
private runOntologyPhase;
|
|
@@ -318,7 +318,7 @@ export declare class LinkedServer extends Shape {
|
|
|
318
318
|
private assertSessionForLevel;
|
|
319
319
|
handleErrors(fn: any): (req: any, res: any, next: any) => Promise<any>;
|
|
320
320
|
handleErrorsJson(fn: any): (req: any, res: any, next: any) => Promise<any>;
|
|
321
|
-
sendError(res: any, statusCode: number, message: any, logMessage?: string): void;
|
|
321
|
+
sendError(res: any, statusCode: number, message: any, logMessage?: string, code?: string): void;
|
|
322
322
|
/**
|
|
323
323
|
* The stylesheets a dev (Vite) page render needs, inlined into
|
|
324
324
|
* `<style id="ssr-css">` so the first paint is styled before Vite's client
|
|
@@ -411,7 +411,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
411
411
|
return { written: count, orphanScope };
|
|
412
412
|
}
|
|
413
413
|
/**
|
|
414
|
-
* Boot: sync the registered ontologies
|
|
414
|
+
* Boot: sync the registered ontologies into their graphs in app data and run the shape
|
|
415
415
|
* check, before the shape sync (see utils/ontologySync). The sync follows the shape sync's
|
|
416
416
|
* switch (`syncShapesOnBoot`, `LINKED_SYNC_SHAPES_ON_BOOT`), plus the opt-out
|
|
417
417
|
* `LINKED_SYNC_ONTOLOGIES_ON_BOOT=false`; the in-memory class hierarchy is loaded either way.
|
|
@@ -429,7 +429,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
429
429
|
* Every discovered linked package and every workspace package of the app registers its
|
|
430
430
|
* ontologies (in dev, an unbuilt one through Vite), then the ontology sync (when
|
|
431
431
|
* `sync` is set) into the default dataset, then the shape check.
|
|
432
|
-
* Orphaned sync nodes are pruned under the shape sync's orphan policy
|
|
432
|
+
* Orphaned ontology graphs (and earlier sync nodes) are pruned under the shape sync's orphan policy
|
|
433
433
|
* (`LINKED_SYNC_SHAPES_PRUNE_ORPHANS`).
|
|
434
434
|
*/
|
|
435
435
|
async runOntologyPhase(sync) {
|
|
@@ -1819,17 +1819,20 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
1819
1819
|
catch (err) {
|
|
1820
1820
|
// A ServerCallError (e.g. 501 for a call no provider handles) carries
|
|
1821
1821
|
// its own status and a message that is safe to send to the client.
|
|
1822
|
+
// A `code` on it (a graph query refusal, see utils/queryPlane) is sent along, so
|
|
1823
|
+
// a remote caller can tell the refusals apart.
|
|
1822
1824
|
if (ServerCallError.is(err)) {
|
|
1823
|
-
|
|
1825
|
+
const code = err.code;
|
|
1826
|
+
return this.sendError(res, err.status, err.message, undefined, typeof code === 'string' ? code : undefined);
|
|
1824
1827
|
}
|
|
1825
1828
|
this.sendError(res, 500, 'internal server error' + (isDevelopment ? ': ' + (err === null || err === void 0 ? void 0 : err.stack) : ''), 'internal server error: ' + (err === null || err === void 0 ? void 0 : err.stack));
|
|
1826
1829
|
}
|
|
1827
1830
|
};
|
|
1828
1831
|
}
|
|
1829
|
-
sendError(res, statusCode = 500, message, logMessage) {
|
|
1832
|
+
sendError(res, statusCode = 500, message, logMessage, code) {
|
|
1830
1833
|
res === null || res === void 0 ? void 0 : res.status(statusCode);
|
|
1831
1834
|
if (message) {
|
|
1832
|
-
res === null || res === void 0 ? void 0 : res.send({ error: message });
|
|
1835
|
+
res === null || res === void 0 ? void 0 : res.send(code ? { error: message, code } : { error: message });
|
|
1833
1836
|
console.warn(paint('red', logMessage || message));
|
|
1834
1837
|
}
|
|
1835
1838
|
}
|