@_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 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
@@ -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 generic-plane rules first (session,
58
- // protected shapes and nodes, registered authorizers): see utils/queryPlane.
59
- // The store runs the builder that was checked. They are declared 'public'
60
- // because that check, not the RPC layer, decides whether a session is
61
- // required (always for mutations; for reads it follows `rpcExposure`).
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');
@@ -1 +1 @@
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 against the generic-plane rules first (session,\n // protected shapes and nodes, registered authorizers): see utils/queryPlane.\n // The store runs the builder that was checked. They are declared 'public'\n // because that check, not the RPC layer, decides whether a session is\n // required (always for mutations; for reads it follows `rpcExposure`).\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"]}
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: it is
129
- // refused unless the app registers a raw query authorizer.
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: (_c = this.config.server) === null || _c === void 0 ? void 0 : _c.vite,
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 ((_d = mainEntry === null || mainEntry === void 0 ? void 0 : mainEntry.css) === null || _d === void 0 ? void 0 : _d[0]) {
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 = (_e = this.config.server) === null || _e === void 0 ? void 0 : _e.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 (!((_f = this.config.server) === null || _f === void 0 ? void 0 : _f.apiOnly)) {
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]