@_linked/server 2.21.0 → 2.22.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 +9 -0
- 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 +1 -1
- package/lib/esm/utils/queryPlane.js +3 -1
- 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,14 @@
|
|
|
1
1
|
# @\_linked/server
|
|
2
2
|
|
|
3
|
+
## 2.22.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#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.
|
|
8
|
+
|
|
9
|
+
### Behaviour changes
|
|
10
|
+
- `/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'`.
|
|
11
|
+
|
|
3
12
|
## 2.21.0
|
|
4
13
|
|
|
5
14
|
### Minor Changes
|
|
@@ -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]
|