@_linked/server 2.21.0 → 2.23.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 +22 -0
- package/lib/esm/backend.js +6 -5
- package/lib/esm/backend.js.map +1 -1
- package/lib/esm/shapes/LincdAPI.js +2 -2
- package/lib/esm/shapes/LincdAPI.js.map +1 -1
- package/lib/esm/shapes/LinkedServer.js +8 -5
- package/lib/esm/shapes/LinkedServer.js.map +1 -1
- package/lib/esm/utils/jsonBodyParser.js +1 -16
- package/lib/esm/utils/jsonBodyParser.js.map +1 -1
- package/lib/esm/utils/queryPlane.d.ts +3 -22
- package/lib/esm/utils/queryPlane.js +13 -90
- package/lib/esm/utils/queryPlane.js.map +1 -1
- package/lib/esm/utils/rawQueries.d.ts +24 -0
- package/lib/esm/utils/rawQueries.js +42 -0
- package/lib/esm/utils/rawQueries.js.map +1 -0
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @\_linked/server
|
|
2
2
|
|
|
3
|
+
## 2.23.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#138](https://github.com/linked-fw/server/pull/138) [`e1cc552`](https://github.com/linked-fw/server/commit/e1cc5523c5147830c7b363a72b7d225396418835) Thanks [@flyon](https://github.com/flyon)! - The generic query endpoints (`/call/@_linked/server/*Query` and `LincdAPI` `/api/*`) now apply the per-store access rules of `@_linked/server-utils` 1.11 (`withAccess`), declared on the stores in the app's `linked.backend.storage.js`. A store without a rule requires a session.
|
|
8
|
+
|
|
9
|
+
**This access model is interim. It needs to be revised and rethought from the ground up.**
|
|
10
|
+
|
|
11
|
+
- Removed from `utils/queryPlane`: `setProtectedNodeProbe`, `askProtectedNodes` and `protectedNodeAsk`. The server no longer runs an `ASK` against the store before a mutation.
|
|
12
|
+
- Kept: `@ctx` references are refused (400), the query that was checked is the builder the store runs, an operation must match its query's kind, a mutation may not choose the ids of new nodes, and `server.rawQueries` decides raw SPARQL.
|
|
13
|
+
- Queries providers run themselves are not checked.
|
|
14
|
+
- Requires `@_linked/server-utils` ^1.11.0.
|
|
15
|
+
|
|
16
|
+
## 2.22.0
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- [#136](https://github.com/linked-fw/server/pull/136) [`0944148`](https://github.com/linked-fw/server/commit/09441482df4c56093a45364b1c899b5f5968c09f) Thanks [@flyon](https://github.com/flyon)! - New server option `server.rawQueries: 'off' | 'session'` (or the `LINKED_RAW_QUERIES` environment variable; the config wins) decides who may run raw SPARQL through `/api/select-raw`. `'session'`, the default, runs it for any signed-in session; `'off'` refuses it. An invalid value turns raw queries off, with a warning. The JSON body parser no longer keeps the unparsed body on `request.rawBody`. Requires `@_linked/server-utils` ^1.10.0.
|
|
21
|
+
|
|
22
|
+
### Behaviour changes
|
|
23
|
+
- `/api/select-raw` now needs a signed-in session (401 without one, in every `rpcExposure` mode), or is refused (403) when `rawQueries` is `'off'`. Before, it was refused unless the app registered a raw query authorizer (`registerRawQueryAuthorizer`, now removed from server-utils), which could also admit a caller without a session. Apps that do not want raw SPARQL reachable should set `rawQueries: 'off'`.
|
|
24
|
+
|
|
3
25
|
## 2.21.0
|
|
4
26
|
|
|
5
27
|
### Minor Changes
|
package/lib/esm/backend.js
CHANGED
|
@@ -54,11 +54,12 @@ export default class LincdServerBackendProvider extends BackendProvider {
|
|
|
54
54
|
// `LinkedStorage` then routes it by the QUERY's shape — which is, and always was, what
|
|
55
55
|
// decides the target dataset. The store instance never participated.
|
|
56
56
|
//
|
|
57
|
-
// Every query is checked against the
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
57
|
+
// Every query is checked first against the access rules of the stores it
|
|
58
|
+
// maps to, declared in the app's storage config (`withAccess`; a store with
|
|
59
|
+
// no rule requires a session): see utils/queryPlane. INTERIM model, to be
|
|
60
|
+
// rethought. The store runs the builder that was checked. They are declared
|
|
61
|
+
// 'public' because that check, not the RPC layer, decides whether a session
|
|
62
|
+
// is required.
|
|
62
63
|
async selectQuery(json) {
|
|
63
64
|
const query = toQueryBuilder(json);
|
|
64
65
|
await authorizeGenericQuery('select', json, query, 'selectQuery');
|
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,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC9E,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,yEAAyE;IACzE,8EAA8E;IAC9E,iDAAiD;IACjD,SAAS;QACP,OAAO,aAAa,EAAE,CAAC;IACzB,CAAC;IAED,4EAA4E;IAC5E,EAAE;IACF,2DAA2D;IAC3D,gFAAgF;IAChF,6EAA6E;IAC7E,EAAE;IACF,mFAAmF;IACnF,qFAAqF;IACrF,uFAAuF;IACvF,uFAAuF;IACvF,4DAA4D;IAC5D,EAAE;IACF,sFAAsF;IACtF,4EAA4E;IAC5E,uFAAuF;IACvF,qEAAqE;IAErE,EAAE;IACF,yEAAyE;IACzE,
|
|
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 { getShapeIndex } from './utils/Shapes.js';\nimport { authorizeGenericQuery, toQueryBuilder } from './utils/queryPlane.js';\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 // Not callable over RPC: no client calls it. Clients read the same index\n // through LincdAPI's `/api/all-shapes` and `/api/shape-details`; backend code\n // can still reach it with a local `Server.call`.\n getShapes() {\n return getShapeIndex();\n }\n\n // ── BackendAPIStore query execution ──────────────────────────────────────\n //\n // These answer the frontend `BackendAPIStore`, which calls\n // `Server.call(packageName, {method}, json)` — the PACKAGE form, so the request\n // arrives here on the generic provider rather than through Shape resolution.\n //\n // They used to live on `BackendAPIStoreProvider`, a `ShapeProvider`, whose methods\n // took the store as a first argument and never read it. Reaching that provider meant\n // the transport had to carry a `shapeURI` and an `instanceNode`, and the server had to\n // rebuild the store with `new (providerShapeClass)({id})` — instantiating a Shape only\n // to discard it. Addressing by package removes all of that.\n //\n // A query cannot cross the wire live (core 2.10.0 contract flip), so the client ships\n // `toJSON()` and `fromJSON()` rehydrates it here into a live, closed query.\n // `LinkedStorage` then routes it by the QUERY's shape — which is, and always was, what\n // decides the target dataset. The store instance never participated.\n\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);\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);\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);\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);\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);\n await authorizeGenericQuery('delete', json, query, 'deleteQuery');\n return LinkedStorage.deleteQuery(query);\n }\n}\n"]}
|
|
@@ -125,8 +125,8 @@ let LincdAPI = class LincdAPI extends Shape {
|
|
|
125
125
|
return LinkedStorage.deleteQuery(builder);
|
|
126
126
|
}
|
|
127
127
|
async post_select_raw({ query }) {
|
|
128
|
-
// A raw SPARQL string cannot be analysed for the shapes it touches:
|
|
129
|
-
//
|
|
128
|
+
// A raw SPARQL string cannot be analysed for the shapes it touches: the
|
|
129
|
+
// `rawQueries` setting decides (a session by default, or off).
|
|
130
130
|
await authorizeRawQuery(query, 'api/select-raw');
|
|
131
131
|
this.checkRawQuerySupport();
|
|
132
132
|
return LinkedStorage.getDefaultDataset().rawQuery(query);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LincdAPI.js","sourceRoot":"","sources":["../../../src/shapes/LincdAPI.ts"],"names":[],"mappings":"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","sourcesContent":["import { Shape } from '@_linked/core/shapes/Shape';\nimport { linkedShape } from '../package.js';\nimport { server } from '../ontologies/server.js';\nimport { JSONParser } from '@_linked/server-utils/utils/JSONParser';\nimport { LinkedStorage } from '@_linked/core/utils/LinkedStorage';\nimport { JSONWriter } from '@_linked/server-utils/utils/JSONWriter';\nimport { cached } from '@_linked/core/utils/cached';\nimport { getShapeIndex, ShapeDetails } from '../utils/Shapes.js';\nimport { SparqlDataset as SPARQLStore } from '@_linked/core/sparql/SparqlDataset';\nimport {\n authorizeGenericQuery,\n authorizeRawQuery,\n toQueryBuilder,\n} from '../utils/queryPlane.js';\nimport { getRpcExposureMode } from '../utils/rpcExposure.js';\n\n/** An error carrying an HTTP status, such as a `ServerCallError` (401/403). */\nfunction isStatusError(error: any): error is { status: number; message: string } {\n return (\n !!error &&\n typeof error.status === 'number' &&\n error.status >= 400 &&\n error.status < 600 &&\n error.name === 'ServerCallError'\n );\n}\n\nconst cacheTime = process.env.NODE_ENV === 'development' ? 0 : Infinity;\nexport type ShapeSummary = {\n id: string;\n label: string;\n description: string;\n target: { id: string };\n extends?: { id: string };\n numInstances: number;\n};\n// Named explicitly: tsc emits `let X = class X`, and any later esbuild pass over that JS (Vite's\n// SSR `define` replacement runs one on every file mentioning a defined `process.env.*`) renames\n// the inner binding to `X2`, which would otherwise become this shape's IRI.\n@linkedShape({name: 'LincdAPI'})\nexport class LincdAPI extends Shape {\n static targetClass = server.LincdAPI;\n\n async process(\n request,\n response,\n httpMethod: 'get' | 'post' | 'put' | 'delete'\n ) {\n let { method, action } = request.params;\n const body = JSONParser.parseObject<any>(request.body, {\n shapeClasses: getRpcExposureMode() === 'enforce' ? 'reject' : 'warn',\n });\n\n //replace - with _ in action names\n let localMethod = httpMethod + '_' + method.replace(/-/g, '_');\n if (typeof this[localMethod] !== 'function') {\n throw new Error('Unknown method: ' + localMethod);\n }\n\n // The query routes (`post_*`) check access themselves, through\n // utils/queryPlane. The `get_*` routes describe shapes and stay reachable:\n // apps read each other's `/api/all-shapes` server to server.\n try {\n const result = await this[localMethod](body, request, response);\n if (typeof result !== 'undefined' || !response.headersSent) {\n const jsonObject = JSONWriter.toJsObject(result);\n response.json(jsonObject);\n }\n } catch (error) {\n if (!response.headersSent && isStatusError(error)) {\n response.status(error.status).json({ error: error.message });\n return;\n }\n console.error(`Error while processing ${localMethod}:`, error);\n if (!response.headersSent) {\n const message =\n error instanceof Error ? error.message : 'Unknown server error';\n response.status(500).json({ error: message });\n }\n }\n }\n\n get_shape_details({\n shapes,\n }: {\n shapes: string[];\n }): Record<string, ShapeDetails> {\n return cached(\n () => {\n const shapeIndex = getShapeIndex();\n const filteredShapeIndex = {};\n for (const shapeId of shapes) {\n if (shapeIndex[shapeId]) {\n filteredShapeIndex[shapeId] = shapeIndex[shapeId];\n }\n }\n return filteredShapeIndex;\n },\n [shapes],\n cacheTime\n );\n }\n\n get_all_shapes(): Promise<{\n shapes: Record<string, ShapeDetails>;\n defaultGraph: string;\n }> {\n return cached(\n async () => {\n const shapeIndex = getShapeIndex();\n\n const typesWithInstances = new Map<string, number>();\n this.checkRawQuerySupport();\n await (LinkedStorage.getDefaultDataset() as unknown as SPARQLStore)\n .rawQuery(\n `SELECT (COUNT(?s) AS ?count) ?type WHERE { ?s a ?type } GROUP BY ?type`\n )\n .then((results) => {\n // rawQuery also types ASK results (a boolean envelope); this is a SELECT.\n if (!results || !('results' in results)) return;\n results.results.bindings.forEach((binding) => {\n if (binding.type && binding.type.value) {\n typesWithInstances.set(\n binding.type.value,\n parseInt(binding.count.value)\n );\n }\n });\n })\n .catch(console.error);\n\n const shapesWithInstances: Record<string, ShapeDetails> = {};\n for (const shapeId in shapeIndex) {\n const shape = shapeIndex[shapeId];\n shapesWithInstances[shapeId] = {\n ...shape,\n numInstances: typesWithInstances.get(shape.targetClass?.id) || 0,\n };\n }\n return {\n shapes: shapesWithInstances,\n defaultGraph: process.env.DATA_ROOT,\n };\n },\n [],\n cacheTime\n );\n }\n\n async post_select({ query }) {\n const builder = toQueryBuilder(query);\n await authorizeGenericQuery('select', query, builder, 'api/select');\n return LinkedStorage.selectQuery(builder);\n }\n async post_create({ query }) {\n const builder = toQueryBuilder(query);\n await authorizeGenericQuery('create', query, builder, 'api/create');\n return LinkedStorage.createQuery(builder);\n }\n async post_update({ query }) {\n const builder = toQueryBuilder(query);\n await authorizeGenericQuery('update', query, builder, 'api/update');\n return LinkedStorage.updateQuery(builder);\n }\n async post_delete({ query }) {\n const builder = toQueryBuilder(query);\n await authorizeGenericQuery('delete', query, builder, 'api/delete');\n return LinkedStorage.deleteQuery(builder);\n }\n\n async post_select_raw({ query }) {\n // A raw SPARQL string cannot be analysed for the shapes it touches: it is\n // refused unless the app registers a raw query authorizer.\n await authorizeRawQuery(query, 'api/select-raw');\n this.checkRawQuerySupport();\n return (LinkedStorage.getDefaultDataset() as unknown as SPARQLStore).rawQuery(\n query\n );\n }\n\n private checkRawQuerySupport() {\n if (!(LinkedStorage.getDefaultDataset() as unknown as SPARQLStore).rawQuery) {\n throw new Error(\n `Default store (${\n Object.getPrototypeOf(LinkedStorage.getDefaultDataset()).constructor\n .name\n }) does not support raw SPARQL queries`\n );\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"LincdAPI.js","sourceRoot":"","sources":["../../../src/shapes/LincdAPI.ts"],"names":[],"mappings":"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","sourcesContent":["import { Shape } from '@_linked/core/shapes/Shape';\nimport { linkedShape } from '../package.js';\nimport { server } from '../ontologies/server.js';\nimport { JSONParser } from '@_linked/server-utils/utils/JSONParser';\nimport { LinkedStorage } from '@_linked/core/utils/LinkedStorage';\nimport { JSONWriter } from '@_linked/server-utils/utils/JSONWriter';\nimport { cached } from '@_linked/core/utils/cached';\nimport { getShapeIndex, ShapeDetails } from '../utils/Shapes.js';\nimport { SparqlDataset as SPARQLStore } from '@_linked/core/sparql/SparqlDataset';\nimport {\n authorizeGenericQuery,\n authorizeRawQuery,\n toQueryBuilder,\n} from '../utils/queryPlane.js';\nimport { getRpcExposureMode } from '../utils/rpcExposure.js';\n\n/** An error carrying an HTTP status, such as a `ServerCallError` (401/403). */\nfunction isStatusError(error: any): error is { status: number; message: string } {\n return (\n !!error &&\n typeof error.status === 'number' &&\n error.status >= 400 &&\n error.status < 600 &&\n error.name === 'ServerCallError'\n );\n}\n\nconst cacheTime = process.env.NODE_ENV === 'development' ? 0 : Infinity;\nexport type ShapeSummary = {\n id: string;\n label: string;\n description: string;\n target: { id: string };\n extends?: { id: string };\n numInstances: number;\n};\n// Named explicitly: tsc emits `let X = class X`, and any later esbuild pass over that JS (Vite's\n// SSR `define` replacement runs one on every file mentioning a defined `process.env.*`) renames\n// the inner binding to `X2`, which would otherwise become this shape's IRI.\n@linkedShape({name: 'LincdAPI'})\nexport class LincdAPI extends Shape {\n static targetClass = server.LincdAPI;\n\n async process(\n request,\n response,\n httpMethod: 'get' | 'post' | 'put' | 'delete'\n ) {\n let { method, action } = request.params;\n const body = JSONParser.parseObject<any>(request.body, {\n shapeClasses: getRpcExposureMode() === 'enforce' ? 'reject' : 'warn',\n });\n\n //replace - with _ in action names\n let localMethod = httpMethod + '_' + method.replace(/-/g, '_');\n if (typeof this[localMethod] !== 'function') {\n throw new Error('Unknown method: ' + localMethod);\n }\n\n // The query routes (`post_*`) check access themselves, through\n // utils/queryPlane. The `get_*` routes describe shapes and stay reachable:\n // apps read each other's `/api/all-shapes` server to server.\n try {\n const result = await this[localMethod](body, request, response);\n if (typeof result !== 'undefined' || !response.headersSent) {\n const jsonObject = JSONWriter.toJsObject(result);\n response.json(jsonObject);\n }\n } catch (error) {\n if (!response.headersSent && isStatusError(error)) {\n response.status(error.status).json({ error: error.message });\n return;\n }\n console.error(`Error while processing ${localMethod}:`, error);\n if (!response.headersSent) {\n const message =\n error instanceof Error ? error.message : 'Unknown server error';\n response.status(500).json({ error: message });\n }\n }\n }\n\n get_shape_details({\n shapes,\n }: {\n shapes: string[];\n }): Record<string, ShapeDetails> {\n return cached(\n () => {\n const shapeIndex = getShapeIndex();\n const filteredShapeIndex = {};\n for (const shapeId of shapes) {\n if (shapeIndex[shapeId]) {\n filteredShapeIndex[shapeId] = shapeIndex[shapeId];\n }\n }\n return filteredShapeIndex;\n },\n [shapes],\n cacheTime\n );\n }\n\n get_all_shapes(): Promise<{\n shapes: Record<string, ShapeDetails>;\n defaultGraph: string;\n }> {\n return cached(\n async () => {\n const shapeIndex = getShapeIndex();\n\n const typesWithInstances = new Map<string, number>();\n this.checkRawQuerySupport();\n await (LinkedStorage.getDefaultDataset() as unknown as SPARQLStore)\n .rawQuery(\n `SELECT (COUNT(?s) AS ?count) ?type WHERE { ?s a ?type } GROUP BY ?type`\n )\n .then((results) => {\n // rawQuery also types ASK results (a boolean envelope); this is a SELECT.\n if (!results || !('results' in results)) return;\n results.results.bindings.forEach((binding) => {\n if (binding.type && binding.type.value) {\n typesWithInstances.set(\n binding.type.value,\n parseInt(binding.count.value)\n );\n }\n });\n })\n .catch(console.error);\n\n const shapesWithInstances: Record<string, ShapeDetails> = {};\n for (const shapeId in shapeIndex) {\n const shape = shapeIndex[shapeId];\n shapesWithInstances[shapeId] = {\n ...shape,\n numInstances: typesWithInstances.get(shape.targetClass?.id) || 0,\n };\n }\n return {\n shapes: shapesWithInstances,\n defaultGraph: process.env.DATA_ROOT,\n };\n },\n [],\n cacheTime\n );\n }\n\n async post_select({ query }) {\n const builder = toQueryBuilder(query);\n await authorizeGenericQuery('select', query, builder, 'api/select');\n return LinkedStorage.selectQuery(builder);\n }\n async post_create({ query }) {\n const builder = toQueryBuilder(query);\n await authorizeGenericQuery('create', query, builder, 'api/create');\n return LinkedStorage.createQuery(builder);\n }\n async post_update({ query }) {\n const builder = toQueryBuilder(query);\n await authorizeGenericQuery('update', query, builder, 'api/update');\n return LinkedStorage.updateQuery(builder);\n }\n async post_delete({ query }) {\n const builder = toQueryBuilder(query);\n await authorizeGenericQuery('delete', query, builder, 'api/delete');\n return LinkedStorage.deleteQuery(builder);\n }\n\n async post_select_raw({ query }) {\n // A raw SPARQL string cannot be analysed for the shapes it touches: the\n // `rawQueries` setting decides (a session by default, or off).\n await authorizeRawQuery(query, 'api/select-raw');\n this.checkRawQuerySupport();\n return (LinkedStorage.getDefaultDataset() as unknown as SPARQLStore).rawQuery(\n query\n );\n }\n\n private checkRawQuerySupport() {\n if (!(LinkedStorage.getDefaultDataset() as unknown as SPARQLStore).rawQuery) {\n throw new Error(\n `Default store (${\n Object.getPrototypeOf(LinkedStorage.getDefaultDataset()).constructor\n .name\n }) does not support raw SPARQL queries`\n );\n }\n }\n}\n"]}
|
|
@@ -116,6 +116,7 @@ import { materializeShapes } from '../utils/syncShapes.js';
|
|
|
116
116
|
import { installSpaFallback, repinSpaFallback, } from '../utils/spaFallback.js';
|
|
117
117
|
import { LincdAPI } from './LincdAPI.js';
|
|
118
118
|
import { getRpcExposureMode, isGenericRpcDisabled, logSafe, resolveCallable, setRpcExposureMode, warnUndeclaredCall, } from '../utils/rpcExposure.js';
|
|
119
|
+
import { setRawQueriesMode } from '../utils/rawQueries.js';
|
|
119
120
|
//prevent errors in node.js when (s)css files are imported in js
|
|
120
121
|
const isProduction = process.env.NODE_ENV === 'production';
|
|
121
122
|
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
@@ -410,10 +411,12 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
410
411
|
setTimeout(() => process.exit(1), 1000).unref();
|
|
411
412
|
}
|
|
412
413
|
async startBoot() {
|
|
413
|
-
var _a, _b, _c, _d, _e, _f;
|
|
414
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
414
415
|
this.initPackage();
|
|
415
416
|
// 'warn' (default) or 'enforce'; see utils/rpcExposure.
|
|
416
417
|
setRpcExposureMode((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.server) === null || _b === void 0 ? void 0 : _b.rpcExposure);
|
|
418
|
+
// 'session' (default) or 'off'; see utils/rawQueries.
|
|
419
|
+
setRawQueriesMode((_d = (_c = this.config) === null || _c === void 0 ? void 0 : _c.server) === null || _d === void 0 ? void 0 : _d.rawQueries);
|
|
417
420
|
// Static assets should come from the static store URL (versioned path),
|
|
418
421
|
// not the upload store URL. An explicit STATIC_ACCESS_URL still wins;
|
|
419
422
|
// otherwise the release manifest `linked build-app` wrote next to the
|
|
@@ -442,7 +445,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
442
445
|
// one left on disk by an earlier `vite build` would otherwise swap in
|
|
443
446
|
// stale built CSS while Vite serves the live styles.
|
|
444
447
|
const servingMode = resolveViteServingMode({
|
|
445
|
-
viteConfig: (
|
|
448
|
+
viteConfig: (_e = this.config.server) === null || _e === void 0 ? void 0 : _e.vite,
|
|
446
449
|
nodeEnv: process.env.NODE_ENV,
|
|
447
450
|
readManifest: () => {
|
|
448
451
|
try {
|
|
@@ -468,7 +471,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
468
471
|
this.assets['main.js'] = staticAsset(`/bundles/${mainEntry.file}`);
|
|
469
472
|
this.mainEntryIsModule = true;
|
|
470
473
|
}
|
|
471
|
-
if ((
|
|
474
|
+
if ((_f = mainEntry === null || mainEntry === void 0 ? void 0 : mainEntry.css) === null || _f === void 0 ? void 0 : _f[0]) {
|
|
472
475
|
this.assets['main.css'] = staticAsset(`/bundles/${mainEntry.css[0]}`);
|
|
473
476
|
}
|
|
474
477
|
}
|
|
@@ -526,7 +529,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
526
529
|
// (`linked start --vite`), the orchestrator passes the Vite handle
|
|
527
530
|
// through config.server.viteMiddleware. We mount it and skip the
|
|
528
531
|
// entire webpack-dev-middleware setup below.
|
|
529
|
-
const viteMiddleware = (
|
|
532
|
+
const viteMiddleware = (_g = this.config.server) === null || _g === void 0 ? void 0 : _g.viteMiddleware;
|
|
530
533
|
if (viteMiddleware) {
|
|
531
534
|
this.server.use(viteMiddleware);
|
|
532
535
|
}
|
|
@@ -612,7 +615,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
612
615
|
// answering them with the client shell at status 200.
|
|
613
616
|
// An API-only backend (`linked start --api-only`) has no app to render:
|
|
614
617
|
// without the catch-all, page requests get express's plain 404.
|
|
615
|
-
if (!((
|
|
618
|
+
if (!((_h = this.config.server) === null || _h === void 0 ? void 0 : _h.apiOnly)) {
|
|
616
619
|
this.installSpaFallback();
|
|
617
620
|
}
|
|
618
621
|
//remove http(s):// and remove port :[port]
|