@_linked/server 2.22.0 → 2.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @\_linked/server
2
2
 
3
+ ## 2.23.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#146](https://github.com/linked-fw/server/pull/146) [`93c8692`](https://github.com/linked-fw/server/commit/93c8692b9fb5eb89e222680dda8f78d7a850f1ee) Thanks [@flyon](https://github.com/flyon)! - Remove unused dependency n3
8
+
9
+ ## 2.23.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [#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.
14
+
15
+ **This access model is interim. It needs to be revised and rethought from the ground up.**
16
+
17
+ - Removed from `utils/queryPlane`: `setProtectedNodeProbe`, `askProtectedNodes` and `protectedNodeAsk`. The server no longer runs an `ASK` against the store before a mutation.
18
+ - 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.
19
+ - Queries providers run themselves are not checked.
20
+ - Requires `@_linked/server-utils` ^1.11.0.
21
+
3
22
  ## 2.22.0
4
23
 
5
24
  ### Minor Changes
@@ -6,5 +6,5 @@ export default class LincdServerBackendProvider extends BackendProvider {
6
6
  askQuery(json: any): Promise<boolean>;
7
7
  updateQuery(json: any): Promise<unknown>;
8
8
  createQuery(json: any): Promise<unknown>;
9
- deleteQuery(json: any): Promise<import("@_linked/core/queries/DeleteQuery").DeleteResponse>;
9
+ deleteQuery(json: any): Promise<import("@_linked/core/queries/DeleteQuery.js").DeleteResponse>;
10
10
  }
@@ -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"]}
@@ -35,32 +35,32 @@ export declare var loadData: () => Promise<{
35
35
  * `LinkedServer`, `LincdAPI` and `LincdWebApp` (`sh:targetClass`, `sh:path`), which boot sync
36
36
  * rewrites (delete, then recreate) the next time the server starts.
37
37
  */
38
- export declare var ns: (term: string) => import("@_linked/core/utils/NodeReference").NodeReferenceValue;
39
- export declare var _self: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
38
+ export declare var ns: (term: string) => import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
39
+ export declare var _self: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
40
40
  export declare const server: {
41
- LincdServer: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
42
- BackendFileStore: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
43
- NodeFileStore: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
44
- BackendStore: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
45
- N3FileStore: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
46
- BackendAPIStore: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
47
- LincdWebApp: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
48
- ownPackage: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
49
- maintainsPackage: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
50
- LincdAPI: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
51
- hasAPI: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
41
+ LincdServer: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
42
+ BackendFileStore: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
43
+ NodeFileStore: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
44
+ BackendStore: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
45
+ N3FileStore: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
46
+ BackendAPIStore: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
47
+ LincdWebApp: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
48
+ ownPackage: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
49
+ maintainsPackage: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
50
+ LincdAPI: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
51
+ hasAPI: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
52
52
  };
53
53
  /** @deprecated use `server` — same object, kept under its old name. */
54
54
  export declare const lincdServer: {
55
- LincdServer: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
56
- BackendFileStore: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
57
- NodeFileStore: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
58
- BackendStore: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
59
- N3FileStore: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
60
- BackendAPIStore: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
61
- LincdWebApp: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
62
- ownPackage: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
63
- maintainsPackage: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
64
- LincdAPI: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
65
- hasAPI: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
55
+ LincdServer: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
56
+ BackendFileStore: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
57
+ NodeFileStore: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
58
+ BackendStore: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
59
+ N3FileStore: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
60
+ BackendAPIStore: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
61
+ LincdWebApp: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
62
+ ownPackage: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
63
+ maintainsPackage: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
64
+ LincdAPI: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
65
+ hasAPI: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
66
66
  };
@@ -1,4 +1,4 @@
1
1
  export declare const linkedShape: {
2
2
  <T extends typeof import("@_linked/core").Shape>(constructor: T): void;
3
3
  <T extends typeof import("@_linked/core").Shape>(config?: import("@_linked/core/utils/Package").ShapeConfig): (constructor: T) => void;
4
- }, linkedUtil: (constructor: any) => any, linkedOntology: (allFileExports: any, nameSpace: (term: string) => import("@_linked/core/utils/NodeReference").NodeReferenceValue, suggestedPrefixAndFileName: string, loadDataFunction?: () => Promise<any>, dataSource?: string | string[]) => void, packageExports: any, packageName: string;
4
+ }, linkedUtil: (constructor: any) => any, linkedOntology: (allFileExports: any, nameSpace: (term: string) => import("@_linked/core/utils/NodeReference.js").NodeReferenceValue, suggestedPrefixAndFileName: string, loadDataFunction?: () => Promise<any>, dataSource?: string | string[]) => void, packageExports: any, packageName: string;
@@ -13,7 +13,7 @@ export type ShapeSummary = {
13
13
  numInstances: number;
14
14
  };
15
15
  export declare class LincdAPI extends Shape {
16
- static targetClass: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
16
+ static targetClass: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
17
17
  process(request: any, response: any, httpMethod: 'get' | 'post' | 'put' | 'delete'): Promise<void>;
18
18
  get_shape_details({ shapes, }: {
19
19
  shapes: string[];
@@ -33,9 +33,9 @@ export declare class LincdAPI extends Shape {
33
33
  }): Promise<unknown>;
34
34
  post_delete({ query }: {
35
35
  query: any;
36
- }): Promise<import("@_linked/core/queries/DeleteQuery").DeleteResponse>;
36
+ }): Promise<import("@_linked/core/queries/DeleteQuery.js").DeleteResponse>;
37
37
  post_select_raw({ query }: {
38
38
  query: any;
39
- }): Promise<void | import("@_linked/core/sparql/resultMapping").SparqlQueryResults>;
39
+ }): Promise<void | import("@_linked/core/sparql/resultMapping.js").SparqlQueryResults>;
40
40
  private checkRawQuerySupport;
41
41
  }
@@ -1,7 +1,7 @@
1
1
  import { Shape } from '@_linked/core/shapes/Shape';
2
2
  import { Lincd_API_Client } from '@_linked/server-utils/shapes/Lincd_API_Client';
3
3
  export declare class LincdWebApp extends Shape {
4
- static targetClass: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
4
+ static targetClass: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
5
5
  static get localApp(): LincdWebApp;
6
6
  get api(): Lincd_API_Client;
7
7
  }
@@ -26,7 +26,7 @@ export declare class LinkedServer extends Shape {
26
26
  /**
27
27
  * indicates that instances of this shape need to have this rdf.type
28
28
  */
29
- static targetClass: import("@_linked/core/utils/NodeReference").NodeReferenceValue;
29
+ static targetClass: import("@_linked/core/utils/NodeReference.js").NodeReferenceValue;
30
30
  private config;
31
31
  private cachedPaths;
32
32
  private assets;
@@ -1,4 +1,4 @@
1
- import { type ProtectedNodeCheck, type ProtectedNodeProbe, type QueryOperation } from '@_linked/server-utils/utils/QueryAccess';
1
+ import { type QueryOperation } from '@_linked/server-utils/utils/QueryAccess';
2
2
  /**
3
3
  * Whether DSL-JSON carries a query-context reference (`{"@ctx": name}`) in any
4
4
  * position: a select or count subject, an update target, a delete id, a
@@ -26,28 +26,9 @@ export declare function containsContextRef(json: unknown): boolean;
26
26
  export declare function toQueryBuilder(query: any): any;
27
27
  /** The lowered IR of a query, or `undefined` when it cannot be lowered (refused). */
28
28
  export declare function lowerForAccessCheck(builder: any): unknown;
29
- /**
30
- * The `ASK` that answers a protected-node check: is any node the mutation would
31
- * write or delete typed with a protected class, or a subclass of one?
32
- * `undefined` when there is nothing to ask.
33
- */
34
- export declare function protectedNodeAsk(check: ProtectedNodeCheck): string | undefined;
35
- /**
36
- * The default protected-node lookup: one `ASK` on the dataset the mutation's
37
- * shape routes to (run in the current call's context, so a routing dataset
38
- * resolves it exactly as it will resolve the mutation). A dataset that cannot
39
- * run SPARQL (`rawQuery`) cannot be checked, and the mutation is refused.
40
- */
41
- export declare const askProtectedNodes: ProtectedNodeProbe;
42
- /**
43
- * Replace the protected-node lookup (see `checkQueryAccess`): an app whose
44
- * protected nodes live in a known store can answer it there. Pass `undefined`
45
- * to restore the default `ASK`.
46
- */
47
- export declare function setProtectedNodeProbe(fn: ProtectedNodeProbe | undefined): void;
48
29
  /**
49
30
  * Check `builder` (rehydrated from `query` with `toQueryBuilder`) against the
50
- * generic-plane rules. Throws a `ServerCallError` (400/401/403) when the current
31
+ * store access rules. Throws a `ServerCallError` (400/401/403) when the current
51
32
  * call may not run it; the caller then hands the same builder to the store.
52
33
  *
53
34
  * Deliberately returns nothing: a query builder is a thenable, so resolving an
@@ -3,16 +3,18 @@
3
3
  * client built (`LincdServerBackendProvider.*Query` behind
4
4
  * `/call/@_linked/server/*Query`, and `LincdAPI` `post_*` behind `/api/*`).
5
5
  *
6
- * The rules themselves (protected shapes, authorizers) are registered through
7
- * `@_linked/server-utils/utils/QueryAccess`; see `checkQueryAccess` there for the
8
- * order they apply in. This module turns the incoming query into the builder the
9
- * store runs and the IR the rules read, and answers the rules' protected-node
10
- * lookup with a SPARQL `ASK` against the store the mutation routes to.
6
+ * The rules are declared per store in the app's storage config
7
+ * (`linked.backend.storage.js`) with `withAccess` from
8
+ * `@_linked/server-utils/utils/QueryAccess`; see `checkQueryAccess` there for
9
+ * how a query is mapped to stores and the order the checks apply in. This
10
+ * module turns the incoming query into the builder the store runs and the IR
11
+ * the rules read.
12
+ *
13
+ * INTERIM: that per-store access model needs to be revised and rethought from
14
+ * the ground up (see QueryAccess).
11
15
  */
12
16
  import { fromJSON } from '@_linked/core';
13
17
  import { lower } from '@_linked/core/queries/lower';
14
- import { LinkedStorage } from '@_linked/core/utils/LinkedStorage';
15
- import { getShapeClass } from '@_linked/core/utils/ShapeClass';
16
18
  import { checkQueryAccess, } from '@_linked/server-utils/utils/QueryAccess';
17
19
  import { ServerCallError } from '@_linked/server-utils/utils/ServerCallError';
18
20
  import { getRawQueriesMode } from './rawQueries.js';
@@ -92,89 +94,9 @@ export function lowerForAccessCheck(builder) {
92
94
  return undefined;
93
95
  }
94
96
  }
95
- const RDF_TYPE = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';
96
- const RDFS_SUBCLASS_OF = 'http://www.w3.org/2000/01/rdf-schema#subClassOf';
97
- /** `<iri>`, refusing anything that is not a plain absolute IRI. */
98
- function iriTerm(value) {
99
- if (typeof value !== 'string' ||
100
- !/^[A-Za-z][A-Za-z0-9+.-]*:[^\s<>"{}|^`\\\u0000-\u001f\u007f]*$/.test(value)) {
101
- throw new ServerCallError(400, 'Invalid node id');
102
- }
103
- return `<${value}>`;
104
- }
105
- /**
106
- * The `ASK` that answers a protected-node check: is any node the mutation would
107
- * write or delete typed with a protected class, or a subclass of one?
108
- * `undefined` when there is nothing to ask.
109
- */
110
- export function protectedNodeAsk(check) {
111
- if (!check.classes.length)
112
- return undefined;
113
- const branches = [];
114
- const owned = check.containsPredicates.length
115
- ? '(' + check.containsPredicates.map(iriTerm).join('|') + ')+'
116
- : undefined;
117
- if (check.ids.length) {
118
- branches.push(`{ VALUES ?n { ${check.ids.map(iriTerm).join(' ')} } }`);
119
- }
120
- if (owned && check.ownerIds.length) {
121
- branches.push(`{ VALUES ?owner { ${check.ownerIds.map(iriTerm).join(' ')} } ?owner ${owned} ?n . }`);
122
- }
123
- for (const cls of check.scanClasses) {
124
- branches.push(`{ ?n <${RDF_TYPE}> ${iriTerm(cls)} . }`);
125
- if (owned)
126
- branches.push(`{ ?s <${RDF_TYPE}> ${iriTerm(cls)} . ?s ${owned} ?n . }`);
127
- }
128
- if (!branches.length)
129
- return undefined;
130
- return (`ASK WHERE {\n ${branches.join('\n UNION ')}\n` +
131
- ` ?n <${RDF_TYPE}> ?t .\n` +
132
- ` VALUES ?c { ${check.classes.map(iriTerm).join(' ')} }\n` +
133
- ` ?t <${RDFS_SUBCLASS_OF}>* ?c .\n}`);
134
- }
135
- /**
136
- * The default protected-node lookup: one `ASK` on the dataset the mutation's
137
- * shape routes to (run in the current call's context, so a routing dataset
138
- * resolves it exactly as it will resolve the mutation). A dataset that cannot
139
- * run SPARQL (`rawQuery`) cannot be checked, and the mutation is refused.
140
- */
141
- export const askProtectedNodes = async (check) => {
142
- var _a;
143
- const sparql = protectedNodeAsk(check);
144
- if (!sparql)
145
- return false;
146
- let shapeClass;
147
- try {
148
- shapeClass = getShapeClass(check.shape);
149
- }
150
- catch (_b) {
151
- shapeClass = undefined;
152
- }
153
- const dataset = (_a = LinkedStorage.getDatasetForShapeClass(shapeClass)) !== null && _a !== void 0 ? _a : LinkedStorage.getDefaultDataset();
154
- if (!dataset || typeof dataset.rawQuery !== 'function') {
155
- throw new Error(`the dataset for ${check.shape} cannot run SPARQL, so the nodes this mutation writes cannot be checked`);
156
- }
157
- const json = await dataset.rawQuery(sparql);
158
- if (typeof (json === null || json === void 0 ? void 0 : json.boolean) !== 'boolean') {
159
- throw new Error('the dataset did not answer the ASK with a boolean');
160
- }
161
- return json.boolean;
162
- };
163
- let probe = askProtectedNodes;
164
- /**
165
- * Replace the protected-node lookup (see `checkQueryAccess`): an app whose
166
- * protected nodes live in a known store can answer it there. Pass `undefined`
167
- * to restore the default `ASK`.
168
- */
169
- export function setProtectedNodeProbe(fn) {
170
- if (fn !== undefined && typeof fn !== 'function') {
171
- throw new TypeError('setProtectedNodeProbe: expected a function');
172
- }
173
- probe = fn !== null && fn !== void 0 ? fn : askProtectedNodes;
174
- }
175
97
  /**
176
98
  * Check `builder` (rehydrated from `query` with `toQueryBuilder`) against the
177
- * generic-plane rules. Throws a `ServerCallError` (400/401/403) when the current
99
+ * store access rules. Throws a `ServerCallError` (400/401/403) when the current
178
100
  * call may not run it; the caller then hands the same builder to the store.
179
101
  *
180
102
  * Deliberately returns nothing: a query builder is a thenable, so resolving an
@@ -187,7 +109,6 @@ export async function authorizeGenericQuery(operation, query, builder, endpoint)
187
109
  ir: lowerForAccessCheck(builder),
188
110
  mode: getRpcExposureMode(),
189
111
  endpoint,
190
- probeProtectedNodes: probe,
191
112
  });
192
113
  }
193
114
  /** Check a raw SPARQL query against the `rawQueries` setting (see utils/rawQueries). */
@@ -1 +1 @@
1
- {"version":3,"file":"queryPlane.js","sourceRoot":"","sources":["../../../src/utils/queryPlane.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Authorization for the generic query plane: the endpoints that run a query the\n * client built (`LincdServerBackendProvider.*Query` behind\n * `/call/@_linked/server/*Query`, and `LincdAPI` `post_*` behind `/api/*`).\n *\n * The rules themselves (protected shapes, authorizers) are registered through\n * `@_linked/server-utils/utils/QueryAccess`; see `checkQueryAccess` there for the\n * order they apply in. This module turns the incoming query into the builder the\n * store runs and the IR the rules read, and answers the rules' protected-node\n * lookup with a SPARQL `ASK` against the store the mutation routes to.\n */\nimport { fromJSON } from '@_linked/core';\nimport { lower } from '@_linked/core/queries/lower';\nimport { LinkedStorage } from '@_linked/core/utils/LinkedStorage';\nimport { getShapeClass } from '@_linked/core/utils/ShapeClass';\nimport {\n checkQueryAccess,\n type ProtectedNodeCheck,\n type ProtectedNodeProbe,\n type QueryOperation,\n} from '@_linked/server-utils/utils/QueryAccess';\nimport { ServerCallError } from '@_linked/server-utils/utils/ServerCallError';\nimport { getRawQueriesMode } from './rawQueries.js';\nimport { getRpcExposureMode } from './rpcExposure.js';\n\n/** The DSL-JSON tag of a query-context reference (`CONTEXT_REF_KEY` in core). */\nconst CONTEXT_REF_KEY = '@ctx';\n\n/**\n * Whether DSL-JSON carries a query-context reference (`{\"@ctx\": name}`) in any\n * position: a select or count subject, an update target, a delete id, a\n * where-clause operand or a mutation field value. Every DSL-JSON decoder in\n * core reads a context reference from this one key.\n */\nexport function containsContextRef(json: unknown): boolean {\n const seen = new Set<object>();\n const stack: unknown[] = [json];\n while (stack.length) {\n const value = stack.pop();\n if (!value || typeof value !== 'object' || seen.has(value)) continue;\n seen.add(value);\n if (Array.isArray(value)) {\n for (const item of value) stack.push(item);\n continue;\n }\n if (Object.prototype.hasOwnProperty.call(value, CONTEXT_REF_KEY)) return true;\n for (const key of Object.keys(value)) stack.push((value as any)[key]);\n }\n return false;\n}\n\n/**\n * A rehydrated query builder from the DSL-JSON a client sent. The result is\n * what the store runs, so the access check and the store see the same query.\n * A body that is not a query answers 400.\n *\n * A query-context reference (`{\"@ctx\": \"user\"}`) also answers 400. Core\n * resolves one at lowering time against a process-wide context map, which on a\n * server holds whatever some code last set there, not the caller's identity,\n * and lowering runs twice (once for the access check, once in the store), so\n * the two could even resolve it differently. A query built from client JSON\n * names its nodes by id.\n *\n * Without context references, lowering a rehydrated builder is a pure function\n * of the builder (closed and never mutated after `fromJSON`) and the shape\n * registry: the IR `authorizeGenericQuery` checks is the IR the store lowers\n * from the same builder.\n */\nexport function toQueryBuilder(query: any): any {\n // A live builder passed by backend code (never a plain object from JSON).\n if (\n query &&\n typeof query === 'object' &&\n Object.getPrototypeOf(query) !== Object.prototype &&\n typeof query.__queryKind === 'string'\n ) {\n return query;\n }\n if (containsContextRef(query)) {\n throw new ServerCallError(\n 400,\n 'Query context references (@ctx) are not accepted by the generic query endpoints'\n );\n }\n try {\n const builder = fromJSON(query);\n if (!builder || typeof builder !== 'object') throw new Error('not a query');\n return builder;\n } catch {\n throw new ServerCallError(400, 'Invalid query');\n }\n}\n\n/** The lowered IR of a query, or `undefined` when it cannot be lowered (refused). */\nexport function lowerForAccessCheck(builder: any): unknown {\n try {\n return lower(builder);\n } catch {\n return undefined;\n }\n}\n\nconst RDF_TYPE = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';\nconst RDFS_SUBCLASS_OF = 'http://www.w3.org/2000/01/rdf-schema#subClassOf';\n\n/** `<iri>`, refusing anything that is not a plain absolute IRI. */\nfunction iriTerm(value: unknown): string {\n if (\n typeof value !== 'string' ||\n !/^[A-Za-z][A-Za-z0-9+.-]*:[^\\s<>\"{}|^`\\\\\\u0000-\\u001f\\u007f]*$/.test(value)\n ) {\n throw new ServerCallError(400, 'Invalid node id');\n }\n return `<${value}>`;\n}\n\n/**\n * The `ASK` that answers a protected-node check: is any node the mutation would\n * write or delete typed with a protected class, or a subclass of one?\n * `undefined` when there is nothing to ask.\n */\nexport function protectedNodeAsk(check: ProtectedNodeCheck): string | undefined {\n if (!check.classes.length) return undefined;\n const branches: string[] = [];\n const owned = check.containsPredicates.length\n ? '(' + check.containsPredicates.map(iriTerm).join('|') + ')+'\n : undefined;\n if (check.ids.length) {\n branches.push(`{ VALUES ?n { ${check.ids.map(iriTerm).join(' ')} } }`);\n }\n if (owned && check.ownerIds.length) {\n branches.push(\n `{ VALUES ?owner { ${check.ownerIds.map(iriTerm).join(' ')} } ?owner ${owned} ?n . }`\n );\n }\n for (const cls of check.scanClasses) {\n branches.push(`{ ?n <${RDF_TYPE}> ${iriTerm(cls)} . }`);\n if (owned) branches.push(`{ ?s <${RDF_TYPE}> ${iriTerm(cls)} . ?s ${owned} ?n . }`);\n }\n if (!branches.length) return undefined;\n return (\n `ASK WHERE {\\n ${branches.join('\\n UNION ')}\\n` +\n ` ?n <${RDF_TYPE}> ?t .\\n` +\n ` VALUES ?c { ${check.classes.map(iriTerm).join(' ')} }\\n` +\n ` ?t <${RDFS_SUBCLASS_OF}>* ?c .\\n}`\n );\n}\n\n/**\n * The default protected-node lookup: one `ASK` on the dataset the mutation's\n * shape routes to (run in the current call's context, so a routing dataset\n * resolves it exactly as it will resolve the mutation). A dataset that cannot\n * run SPARQL (`rawQuery`) cannot be checked, and the mutation is refused.\n */\nexport const askProtectedNodes: ProtectedNodeProbe = async (check) => {\n const sparql = protectedNodeAsk(check);\n if (!sparql) return false;\n let shapeClass: any;\n try {\n shapeClass = getShapeClass(check.shape as any);\n } catch {\n shapeClass = undefined;\n }\n const dataset: any =\n LinkedStorage.getDatasetForShapeClass(shapeClass) ?? LinkedStorage.getDefaultDataset();\n if (!dataset || typeof dataset.rawQuery !== 'function') {\n throw new Error(\n `the dataset for ${check.shape} cannot run SPARQL, so the nodes this mutation writes cannot be checked`\n );\n }\n const json = await dataset.rawQuery(sparql);\n if (typeof json?.boolean !== 'boolean') {\n throw new Error('the dataset did not answer the ASK with a boolean');\n }\n return json.boolean;\n};\n\nlet probe: ProtectedNodeProbe = askProtectedNodes;\n\n/**\n * Replace the protected-node lookup (see `checkQueryAccess`): an app whose\n * protected nodes live in a known store can answer it there. Pass `undefined`\n * to restore the default `ASK`.\n */\nexport function setProtectedNodeProbe(fn: ProtectedNodeProbe | undefined): void {\n if (fn !== undefined && typeof fn !== 'function') {\n throw new TypeError('setProtectedNodeProbe: expected a function');\n }\n probe = fn ?? askProtectedNodes;\n}\n\n/**\n * Check `builder` (rehydrated from `query` with `toQueryBuilder`) against the\n * generic-plane rules. Throws a `ServerCallError` (400/401/403) when the current\n * call may not run it; the caller then hands the same builder to the store.\n *\n * Deliberately returns nothing: a query builder is a thenable, so resolving an\n * async function with one would run it.\n */\nexport async function authorizeGenericQuery(\n operation: QueryOperation,\n query: unknown,\n builder: any,\n endpoint: string\n): Promise<void> {\n await checkQueryAccess({\n operation,\n query,\n ir: lowerForAccessCheck(builder),\n mode: getRpcExposureMode(),\n endpoint,\n probeProtectedNodes: probe,\n });\n}\n\n/** Check a raw SPARQL query against the `rawQueries` setting (see utils/rawQueries). */\nexport async function authorizeRawQuery(query: unknown, endpoint: string): Promise<void> {\n if (typeof query !== 'string') {\n throw new ServerCallError(400, 'Invalid query');\n }\n await checkQueryAccess({\n operation: 'select',\n query,\n ir: undefined,\n raw: true,\n rawQueries: getRawQueriesMode(),\n mode: getRpcExposureMode(),\n endpoint,\n });\n}\n"]}
1
+ {"version":3,"file":"queryPlane.js","sourceRoot":"","sources":["../../../src/utils/queryPlane.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACpD,OAAO,EACL,gBAAgB,GAEjB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,iFAAiF;AACjF,MAAM,eAAe,GAAG,MAAM,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAa;IAC9C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,KAAK,GAAc,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS;QACrE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,MAAM,IAAI,IAAI,KAAK;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3C,SAAS;QACX,CAAC;QACD,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,eAAe,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9E,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,KAAK,CAAC,IAAI,CAAE,KAAa,CAAC,GAAG,CAAC,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,cAAc,CAAC,KAAU;IACvC,0EAA0E;IAC1E,IACE,KAAK;QACL,OAAO,KAAK,KAAK,QAAQ;QACzB,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,SAAS;QACjD,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,EACrC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,eAAe,CACvB,GAAG,EACH,iFAAiF,CAClF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;QAC5E,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,WAAM,CAAC;QACP,MAAM,IAAI,eAAe,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,mBAAmB,CAAC,OAAY;IAC9C,IAAI,CAAC;QACH,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,SAAyB,EACzB,KAAc,EACd,OAAY,EACZ,QAAgB;IAEhB,MAAM,gBAAgB,CAAC;QACrB,SAAS;QACT,KAAK;QACL,EAAE,EAAE,mBAAmB,CAAC,OAAO,CAAC;QAChC,IAAI,EAAE,kBAAkB,EAAE;QAC1B,QAAQ;KACT,CAAC,CAAC;AACL,CAAC;AAED,wFAAwF;AACxF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAc,EAAE,QAAgB;IACtE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,eAAe,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,gBAAgB,CAAC;QACrB,SAAS,EAAE,QAAQ;QACnB,KAAK;QACL,EAAE,EAAE,SAAS;QACb,GAAG,EAAE,IAAI;QACT,UAAU,EAAE,iBAAiB,EAAE;QAC/B,IAAI,EAAE,kBAAkB,EAAE;QAC1B,QAAQ;KACT,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * Authorization for the generic query plane: the endpoints that run a query the\n * client built (`LincdServerBackendProvider.*Query` behind\n * `/call/@_linked/server/*Query`, and `LincdAPI` `post_*` behind `/api/*`).\n *\n * The rules are declared per store in the app's storage config\n * (`linked.backend.storage.js`) with `withAccess` from\n * `@_linked/server-utils/utils/QueryAccess`; see `checkQueryAccess` there for\n * how a query is mapped to stores and the order the checks apply in. This\n * module turns the incoming query into the builder the store runs and the IR\n * the rules read.\n *\n * INTERIM: that per-store access model needs to be revised and rethought from\n * the ground up (see QueryAccess).\n */\nimport { fromJSON } from '@_linked/core';\nimport { lower } from '@_linked/core/queries/lower';\nimport {\n checkQueryAccess,\n type QueryOperation,\n} from '@_linked/server-utils/utils/QueryAccess';\nimport { ServerCallError } from '@_linked/server-utils/utils/ServerCallError';\nimport { getRawQueriesMode } from './rawQueries.js';\nimport { getRpcExposureMode } from './rpcExposure.js';\n\n/** The DSL-JSON tag of a query-context reference (`CONTEXT_REF_KEY` in core). */\nconst CONTEXT_REF_KEY = '@ctx';\n\n/**\n * Whether DSL-JSON carries a query-context reference (`{\"@ctx\": name}`) in any\n * position: a select or count subject, an update target, a delete id, a\n * where-clause operand or a mutation field value. Every DSL-JSON decoder in\n * core reads a context reference from this one key.\n */\nexport function containsContextRef(json: unknown): boolean {\n const seen = new Set<object>();\n const stack: unknown[] = [json];\n while (stack.length) {\n const value = stack.pop();\n if (!value || typeof value !== 'object' || seen.has(value)) continue;\n seen.add(value);\n if (Array.isArray(value)) {\n for (const item of value) stack.push(item);\n continue;\n }\n if (Object.prototype.hasOwnProperty.call(value, CONTEXT_REF_KEY)) return true;\n for (const key of Object.keys(value)) stack.push((value as any)[key]);\n }\n return false;\n}\n\n/**\n * A rehydrated query builder from the DSL-JSON a client sent. The result is\n * what the store runs, so the access check and the store see the same query.\n * A body that is not a query answers 400.\n *\n * A query-context reference (`{\"@ctx\": \"user\"}`) also answers 400. Core\n * resolves one at lowering time against a process-wide context map, which on a\n * server holds whatever some code last set there, not the caller's identity,\n * and lowering runs twice (once for the access check, once in the store), so\n * the two could even resolve it differently. A query built from client JSON\n * names its nodes by id.\n *\n * Without context references, lowering a rehydrated builder is a pure function\n * of the builder (closed and never mutated after `fromJSON`) and the shape\n * registry: the IR `authorizeGenericQuery` checks is the IR the store lowers\n * from the same builder.\n */\nexport function toQueryBuilder(query: any): any {\n // A live builder passed by backend code (never a plain object from JSON).\n if (\n query &&\n typeof query === 'object' &&\n Object.getPrototypeOf(query) !== Object.prototype &&\n typeof query.__queryKind === 'string'\n ) {\n return query;\n }\n if (containsContextRef(query)) {\n throw new ServerCallError(\n 400,\n 'Query context references (@ctx) are not accepted by the generic query endpoints'\n );\n }\n try {\n const builder = fromJSON(query);\n if (!builder || typeof builder !== 'object') throw new Error('not a query');\n return builder;\n } catch {\n throw new ServerCallError(400, 'Invalid query');\n }\n}\n\n/** The lowered IR of a query, or `undefined` when it cannot be lowered (refused). */\nexport function lowerForAccessCheck(builder: any): unknown {\n try {\n return lower(builder);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Check `builder` (rehydrated from `query` with `toQueryBuilder`) against the\n * store access rules. Throws a `ServerCallError` (400/401/403) when the current\n * call may not run it; the caller then hands the same builder to the store.\n *\n * Deliberately returns nothing: a query builder is a thenable, so resolving an\n * async function with one would run it.\n */\nexport async function authorizeGenericQuery(\n operation: QueryOperation,\n query: unknown,\n builder: any,\n endpoint: string\n): Promise<void> {\n await checkQueryAccess({\n operation,\n query,\n ir: lowerForAccessCheck(builder),\n mode: getRpcExposureMode(),\n endpoint,\n });\n}\n\n/** Check a raw SPARQL query against the `rawQueries` setting (see utils/rawQueries). */\nexport async function authorizeRawQuery(query: unknown, endpoint: string): Promise<void> {\n if (typeof query !== 'string') {\n throw new ServerCallError(400, 'Invalid query');\n }\n await checkQueryAccess({\n operation: 'select',\n query,\n ir: undefined,\n raw: true,\n rawQueries: getRawQueriesMode(),\n mode: getRpcExposureMode(),\n endpoint,\n });\n}\n"]}
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Who may run raw SPARQL through the generic query plane (`/api/select-raw`).
3
3
  *
4
- * Raw SPARQL cannot be analysed for the shapes it touches, so the protected
5
- * shapes and query authorizers of `@_linked/server-utils/utils/QueryAccess`
6
- * do not apply to it. This one setting decides instead:
4
+ * Raw SPARQL cannot be analysed for the shapes it touches, so the per-store
5
+ * access rules of `@_linked/server-utils/utils/QueryAccess` do not apply to
6
+ * it. This one setting decides instead:
7
7
  *
8
8
  * - `'session'` (the default): any signed-in session may run it; 401 without one.
9
9
  * - `'off'`: every raw query is refused (403).
@@ -1 +1 @@
1
- {"version":3,"file":"rawQueries.js","sourceRoot":"","sources":["../../../src/utils/rawQueries.ts"],"names":[],"mappings":"AAgBA,IAAI,cAA0C,CAAC;AAC/C,IAAI,gBAAgB,GAAG,KAAK,CAAC;AAE7B,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACpE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAa;IAC7C,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QACxC,cAAc,GAAG,SAAS,CAAC;QAC3B,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CACV,8DAA8D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,uBAAuB,CAC1G,CAAC;QACF,cAAc,GAAG,KAAK,CAAC;QACvB,OAAO;IACT,CAAC;IACD,cAAc,GAAG,MAAM,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC3C,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IACtD,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,gBAAgB,GAAG,IAAI,CAAC;QACxB,OAAO,CAAC,IAAI,CACV,+DAA+D,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,uBAAuB,CAC1G,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["/**\n * Who may run raw SPARQL through the generic query plane (`/api/select-raw`).\n *\n * Raw SPARQL cannot be analysed for the shapes it touches, so the protected\n * shapes and query authorizers of `@_linked/server-utils/utils/QueryAccess`\n * do not apply to it. This one setting decides instead:\n *\n * - `'session'` (the default): any signed-in session may run it; 401 without one.\n * - `'off'`: every raw query is refused (403).\n *\n * Set it with `server.rawQueries` in the app's config, or `LINKED_RAW_QUERIES`.\n */\nimport type { RawQueriesMode } from '@_linked/server-utils/utils/QueryAccess';\n\nexport type { RawQueriesMode };\n\nlet configuredMode: RawQueriesMode | undefined;\nlet invalidEnvWarned = false;\n\nfunction parseMode(value: unknown): RawQueriesMode | undefined {\n return value === 'off' || value === 'session' ? value : undefined;\n}\n\n/**\n * Set from the server's config (`server.rawQueries`). An invalid value turns\n * raw queries off, with a warning: a typo must not open them up.\n */\nexport function setRawQueriesMode(mode: unknown): void {\n if (mode === undefined || mode === null) {\n configuredMode = undefined;\n return;\n }\n const parsed = parseMode(mode);\n if (!parsed) {\n console.warn(\n `[linked] server.rawQueries must be 'off' or 'session', got ${JSON.stringify(mode)}; raw queries are off`\n );\n configuredMode = 'off';\n return;\n }\n configuredMode = parsed;\n}\n\n/**\n * `server.rawQueries`, else `LINKED_RAW_QUERIES`, else `'session'`. An invalid\n * `LINKED_RAW_QUERIES` turns raw queries off.\n */\nexport function getRawQueriesMode(): RawQueriesMode {\n if (configuredMode) return configuredMode;\n const env = process.env.LINKED_RAW_QUERIES;\n if (env === undefined || env === '') return 'session';\n const parsed = parseMode(env);\n if (parsed) return parsed;\n if (!invalidEnvWarned) {\n invalidEnvWarned = true;\n console.warn(\n `[linked] LINKED_RAW_QUERIES must be 'off' or 'session', got ${JSON.stringify(env)}; raw queries are off`\n );\n }\n return 'off';\n}\n"]}
1
+ {"version":3,"file":"rawQueries.js","sourceRoot":"","sources":["../../../src/utils/rawQueries.ts"],"names":[],"mappings":"AAgBA,IAAI,cAA0C,CAAC;AAC/C,IAAI,gBAAgB,GAAG,KAAK,CAAC;AAE7B,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACpE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAa;IAC7C,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QACxC,cAAc,GAAG,SAAS,CAAC;QAC3B,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CACV,8DAA8D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,uBAAuB,CAC1G,CAAC;QACF,cAAc,GAAG,KAAK,CAAC;QACvB,OAAO;IACT,CAAC;IACD,cAAc,GAAG,MAAM,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC3C,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IACtD,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,gBAAgB,GAAG,IAAI,CAAC;QACxB,OAAO,CAAC,IAAI,CACV,+DAA+D,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,uBAAuB,CAC1G,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["/**\n * Who may run raw SPARQL through the generic query plane (`/api/select-raw`).\n *\n * Raw SPARQL cannot be analysed for the shapes it touches, so the per-store\n * access rules of `@_linked/server-utils/utils/QueryAccess` do not apply to\n * it. This one setting decides instead:\n *\n * - `'session'` (the default): any signed-in session may run it; 401 without one.\n * - `'off'`: every raw query is refused (403).\n *\n * Set it with `server.rawQueries` in the app's config, or `LINKED_RAW_QUERIES`.\n */\nimport type { RawQueriesMode } from '@_linked/server-utils/utils/QueryAccess';\n\nexport type { RawQueriesMode };\n\nlet configuredMode: RawQueriesMode | undefined;\nlet invalidEnvWarned = false;\n\nfunction parseMode(value: unknown): RawQueriesMode | undefined {\n return value === 'off' || value === 'session' ? value : undefined;\n}\n\n/**\n * Set from the server's config (`server.rawQueries`). An invalid value turns\n * raw queries off, with a warning: a typo must not open them up.\n */\nexport function setRawQueriesMode(mode: unknown): void {\n if (mode === undefined || mode === null) {\n configuredMode = undefined;\n return;\n }\n const parsed = parseMode(mode);\n if (!parsed) {\n console.warn(\n `[linked] server.rawQueries must be 'off' or 'session', got ${JSON.stringify(mode)}; raw queries are off`\n );\n configuredMode = 'off';\n return;\n }\n configuredMode = parsed;\n}\n\n/**\n * `server.rawQueries`, else `LINKED_RAW_QUERIES`, else `'session'`. An invalid\n * `LINKED_RAW_QUERIES` turns raw queries off.\n */\nexport function getRawQueriesMode(): RawQueriesMode {\n if (configuredMode) return configuredMode;\n const env = process.env.LINKED_RAW_QUERIES;\n if (env === undefined || env === '') return 'session';\n const parsed = parseMode(env);\n if (parsed) return parsed;\n if (!invalidEnvWarned) {\n invalidEnvWarned = true;\n console.warn(\n `[linked] LINKED_RAW_QUERIES must be 'off' or 'session', got ${JSON.stringify(env)}; raw queries are off`\n );\n }\n return 'off';\n}\n"]}
@@ -30,4 +30,4 @@ export declare const resizedImagesPurpose = "resizedImages";
30
30
  * request handler surfaces as a hung request rather than an error. Registering
31
31
  * on the way past is idempotent and removes the ordering rule entirely.
32
32
  */
33
- export declare function getResizedImagesStore(): import("@_linked/core/interfaces/IFileStore").IFileStore;
33
+ export declare function getResizedImagesStore(): import("@_linked/core/interfaces/IFileStore.js").IFileStore;
package/package.json CHANGED
@@ -10,8 +10,8 @@
10
10
  "type": "git",
11
11
  "url": "git+https://github.com/linked-fw/server.git"
12
12
  },
13
- "version": "2.22.0",
14
- "packageManager": "npm@11.20.0",
13
+ "version": "2.23.1",
14
+ "packageManager": "npm@11.21.0",
15
15
  "linkedPackage": true,
16
16
  "type": "module",
17
17
  "main": "lib/esm/index.js",
@@ -37,14 +37,13 @@
37
37
  "dependencies": {
38
38
  "@_linked/cli": "^1.2",
39
39
  "@_linked/core": "^2.22.8",
40
- "@_linked/server-utils": "^1.10.0",
40
+ "@_linked/server-utils": "^1.11.0",
41
41
  "autoprefixer": "^10.4.18",
42
42
  "compression": "^1.7.4",
43
43
  "cors": "^2.8.5",
44
44
  "cron": "^4.3.4",
45
45
  "express": "^4.18.3",
46
46
  "fetch-cookie": "^3.1.0",
47
- "n3": "^1.17.2",
48
47
  "node-addon-api": "^8.2.2",
49
48
  "open": "^8.4.0",
50
49
  "proper-lockfile": "^4.1.2",
@@ -65,12 +64,12 @@
65
64
  "@changesets/changelog-github": "^1.0.0",
66
65
  "@changesets/cli": "^3.0.0",
67
66
  "@jest/globals": "^30.0.0",
68
- "@types/jest": "^29.5.14",
67
+ "@types/jest": "^30.0.0",
69
68
  "@types/node": "^24.0.0",
70
69
  "@types/react-dom": "^19.3.0",
71
70
  "copyfiles": "^2.4.1",
72
71
  "cross-env": "^7.0.3",
73
- "jest": "^29.7.0",
72
+ "jest": "^30.0.0",
74
73
  "prettier": "3.9.9",
75
74
  "ts-jest": "^29.4.12",
76
75
  "typescript-plugin-css-modules": "^5.1.0"