@_linked/server 2.18.0 → 2.20.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 +16 -0
- package/lib/esm/data/{lincd-server.json → server.json} +9 -9
- package/lib/esm/index.d.ts +3 -1
- package/lib/esm/index.js +3 -1
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/ontologies/lincd-server.d.ts +4 -47
- package/lib/esm/ontologies/lincd-server.js +4 -55
- package/lib/esm/ontologies/lincd-server.js.map +1 -1
- package/lib/esm/ontologies/lincd-server.register.d.ts +5 -1
- package/lib/esm/ontologies/lincd-server.register.js +3 -14
- package/lib/esm/ontologies/lincd-server.register.js.map +1 -1
- package/lib/esm/ontologies/server.d.ts +66 -0
- package/lib/esm/ontologies/server.js +63 -0
- package/lib/esm/ontologies/server.js.map +1 -0
- package/lib/esm/ontologies/server.register.d.ts +1 -0
- package/lib/esm/ontologies/server.register.js +24 -0
- package/lib/esm/ontologies/server.register.js.map +1 -0
- package/lib/esm/shapes/LincdAPI.js +2 -2
- package/lib/esm/shapes/LincdAPI.js.map +1 -1
- package/lib/esm/shapes/LincdWebApp.js +3 -3
- package/lib/esm/shapes/LincdWebApp.js.map +1 -1
- package/lib/esm/shapes/LinkedServer.d.ts +32 -0
- package/lib/esm/shapes/LinkedServer.js +90 -6
- package/lib/esm/shapes/LinkedServer.js.map +1 -1
- package/lib/esm/shapes/index.d.ts +1 -1
- package/lib/esm/shapes/index.js +1 -1
- package/lib/esm/shapes/index.js.map +1 -1
- package/lib/esm/utils/fatalError.d.ts +36 -0
- package/lib/esm/utils/fatalError.js +22 -0
- package/lib/esm/utils/fatalError.js.map +1 -0
- package/package.json +1 -1
- package/readme.md +20 -0
|
@@ -37,6 +37,7 @@ import { autoLoadOntologyData } from '@_linked/core/utils/Package';
|
|
|
37
37
|
import { getShapeClass, getSuperShapesClasses, } from '@_linked/core/utils/ShapeClass';
|
|
38
38
|
import path from 'path';
|
|
39
39
|
import { pathToFileURL } from 'node:url';
|
|
40
|
+
import { isFatalError } from '../utils/fatalError.js';
|
|
40
41
|
import { discoverLinkedDependencies, isBundledBySsr, NODE_IMPORT_CONDITIONS, readInstalledPackage, resolveBackendEntry, ssrNoExternalOf, } from '../utils/linkedDependencies.js';
|
|
41
42
|
/**
|
|
42
43
|
* `instanceof ShapeProvider`, tolerating a second copy of server-utils.
|
|
@@ -63,16 +64,38 @@ function isShapeProvider(provider) {
|
|
|
63
64
|
* for hooks that run for every provider (boot lifecycle hooks and per-request
|
|
64
65
|
* hooks), where one provider's bug must not take down boot or every request
|
|
65
66
|
* without saying which provider it was.
|
|
67
|
+
*
|
|
68
|
+
* The exception is a fatal error (see utils/fatalError): with `atBoot` it is
|
|
69
|
+
* logged and re-thrown, so the server refuses to start. Without it — the
|
|
70
|
+
* server is already serving — it is logged as fatal and contained like any
|
|
71
|
+
* other error: one provider must not take a running server down.
|
|
66
72
|
*/
|
|
67
|
-
async function runProviderHook(pkg, hook, call) {
|
|
73
|
+
async function runProviderHook(pkg, hook, call, atBoot = false) {
|
|
68
74
|
var _a;
|
|
69
75
|
try {
|
|
70
76
|
await call();
|
|
71
77
|
}
|
|
72
78
|
catch (err) {
|
|
79
|
+
if (isFatalError(err)) {
|
|
80
|
+
logFatalError(pkg, hook, err, atBoot);
|
|
81
|
+
if (atBoot)
|
|
82
|
+
throw err;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
73
85
|
console.error(paint('red', `[linked] ${pkg} ${hook} failed: ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}`), (err === null || err === void 0 ? void 0 : err.stack) ? `\n${err.stack}` : '');
|
|
74
86
|
}
|
|
75
87
|
}
|
|
88
|
+
/** Log a fatal error once, at the point it was thrown (see runProviderHook). */
|
|
89
|
+
function logFatalError(pkg, hook, err, atBoot) {
|
|
90
|
+
var _a, _b;
|
|
91
|
+
if (loggedFatalErrors.has(err))
|
|
92
|
+
return;
|
|
93
|
+
loggedFatalErrors.add(err);
|
|
94
|
+
console.error(paint('red', atBoot
|
|
95
|
+
? `[linked] ${pkg} ${hook}: fatal error, refusing to start: ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}`
|
|
96
|
+
: `[linked] ${pkg} ${hook}: fatal error after start, server keeps running: ${(_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : err}`), (err === null || err === void 0 ? void 0 : err.stack) ? `\n${err.stack}` : '');
|
|
97
|
+
}
|
|
98
|
+
const loggedFatalErrors = new WeakSet();
|
|
76
99
|
import process from 'process';
|
|
77
100
|
import * as React from 'react';
|
|
78
101
|
import { renderToPipeableStream, renderToStaticMarkup } from 'react-dom/server';
|
|
@@ -81,7 +104,7 @@ import sharp from 'sharp';
|
|
|
81
104
|
import { findStoredKey, resolveResizeSource, } from '../utils/resizeSource.js';
|
|
82
105
|
import { Transform } from 'stream';
|
|
83
106
|
import { CookieJar } from 'tough-cookie';
|
|
84
|
-
import {
|
|
107
|
+
import { server } from '../ontologies/server.js';
|
|
85
108
|
import { linkedShape } from '../package.js';
|
|
86
109
|
import { resolveStaticAccessURL, staticAssetURL, } from '../utils/releaseManifest.js';
|
|
87
110
|
import { resolveBootstrapEntry, resolveViteMainEntry, resolveViteServingMode, } from '../utils/bootstrapEntry.js';
|
|
@@ -178,6 +201,12 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
178
201
|
this.warnedDuplicateInstalls = new Set();
|
|
179
202
|
//from resizedFileName to full resized path (CDN or similar)
|
|
180
203
|
this.resizePathsMap = new Map();
|
|
204
|
+
/**
|
|
205
|
+
* True while start() / initOnly() runs. A fatal provider error (see
|
|
206
|
+
* utils/fatalError) thrown while booting stops the boot; after it, the same
|
|
207
|
+
* error is logged and contained.
|
|
208
|
+
*/
|
|
209
|
+
this.booting = false;
|
|
181
210
|
if (config && typeof config !== 'string' && !('id' in config)) {
|
|
182
211
|
// The absence of `id` is the runtime discriminator for a LinkedConfig;
|
|
183
212
|
// the widened `{id?: string}` member of the union keeps TS from narrowing
|
|
@@ -232,6 +261,9 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
232
261
|
this.package = JSON.parse(fsNative.readFileSync(path.resolve(process.cwd(), 'package.json'), 'utf-8'));
|
|
233
262
|
}
|
|
234
263
|
async initOnly() {
|
|
264
|
+
return this.bootOrRefuse(() => this.initOnlyBoot());
|
|
265
|
+
}
|
|
266
|
+
async initOnlyBoot() {
|
|
235
267
|
await this.initOntologies();
|
|
236
268
|
await this.initStores();
|
|
237
269
|
this.initPackage();
|
|
@@ -290,7 +322,50 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
290
322
|
// return nodeURI.includes(store.namedNode.uri)
|
|
291
323
|
// })
|
|
292
324
|
// }
|
|
325
|
+
/**
|
|
326
|
+
* Boot the server and listen. Rejects — and makes the process exit non-zero —
|
|
327
|
+
* when a provider throws a fatal error while booting (see utils/fatalError).
|
|
328
|
+
*/
|
|
293
329
|
async start() {
|
|
330
|
+
return this.bootOrRefuse(() => this.startBoot());
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Run a boot with `booting` set. A fatal provider error rejects it and hands
|
|
334
|
+
* the error to exitAfterFatalStartupError; any other boot error rejects as it
|
|
335
|
+
* always did.
|
|
336
|
+
*/
|
|
337
|
+
async bootOrRefuse(boot) {
|
|
338
|
+
this.booting = true;
|
|
339
|
+
try {
|
|
340
|
+
return await boot();
|
|
341
|
+
}
|
|
342
|
+
catch (err) {
|
|
343
|
+
if (isFatalError(err))
|
|
344
|
+
this.exitAfterFatalStartupError(err);
|
|
345
|
+
throw err;
|
|
346
|
+
}
|
|
347
|
+
finally {
|
|
348
|
+
this.booting = false;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Make sure a server that refused to start does not stay up as a process.
|
|
353
|
+
*
|
|
354
|
+
* start() rejects either way, so the caller can report the error. But a
|
|
355
|
+
* rejected start() does not end the process on its own: the CLI's `linked
|
|
356
|
+
* start` turns an unhandled rejection into a log line, and the Vite dev
|
|
357
|
+
* server, a store connection or a provider's timer keeps the event loop
|
|
358
|
+
* alive. So the exit code is set now — a process with nothing left running
|
|
359
|
+
* exits 1 — and, as a backstop, the process is exited after a moment, on an
|
|
360
|
+
* unref'd timer that never itself keeps the process alive.
|
|
361
|
+
*
|
|
362
|
+
* Override to embed the server somewhere that must not exit (tests).
|
|
363
|
+
*/
|
|
364
|
+
exitAfterFatalStartupError(_err) {
|
|
365
|
+
process.exitCode = 1;
|
|
366
|
+
setTimeout(() => process.exit(1), 1000).unref();
|
|
367
|
+
}
|
|
368
|
+
async startBoot() {
|
|
294
369
|
var _a, _b, _c, _d;
|
|
295
370
|
this.initPackage();
|
|
296
371
|
// Static assets should come from the static store URL (versioned path),
|
|
@@ -563,7 +638,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
563
638
|
if (!genericProvider || typeof genericProvider[method] !== 'function') {
|
|
564
639
|
continue;
|
|
565
640
|
}
|
|
566
|
-
await runProviderHook(pkg, method, () => genericProvider[method](...args));
|
|
641
|
+
await runProviderHook(pkg, method, () => genericProvider[method](...args), this.booting);
|
|
567
642
|
}
|
|
568
643
|
}
|
|
569
644
|
/**
|
|
@@ -627,6 +702,9 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
627
702
|
});
|
|
628
703
|
}
|
|
629
704
|
catch (err) {
|
|
705
|
+
// Already logged where it was thrown; it must reach start().
|
|
706
|
+
if (isFatalError(err))
|
|
707
|
+
throw err;
|
|
630
708
|
console.warn(err);
|
|
631
709
|
}
|
|
632
710
|
}
|
|
@@ -1053,6 +1131,12 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
1053
1131
|
// console.log(`✅ Successfully loaded: ${pkg}`);
|
|
1054
1132
|
}
|
|
1055
1133
|
catch (e) {
|
|
1134
|
+
if (isFatalError(e)) {
|
|
1135
|
+
logFatalError(pkg, 'module load', e, this.booting);
|
|
1136
|
+
if (this.booting)
|
|
1137
|
+
throw e;
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1056
1140
|
let providerNotFound = e.code === 'MODULE_NOT_FOUND' &&
|
|
1057
1141
|
e.message.indexOf(`Cannot find package '${pkg}'`) !== -1;
|
|
1058
1142
|
if (providerNotFound) {
|
|
@@ -1168,7 +1252,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
1168
1252
|
await runProviderHook(pkg, `backend ${entry}`, async () => {
|
|
1169
1253
|
backendProviderExports = await load();
|
|
1170
1254
|
loaded = true;
|
|
1171
|
-
});
|
|
1255
|
+
}, this.booting);
|
|
1172
1256
|
if (loaded) {
|
|
1173
1257
|
for (const key of Object.keys(backendProviderExports)) {
|
|
1174
1258
|
const providerClass = backendProviderExports[key];
|
|
@@ -1177,7 +1261,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
1177
1261
|
//TODO: do not create an instance, just save the class and instantiate it when needed
|
|
1178
1262
|
await runProviderHook(pkg, `${key} constructor`, () => {
|
|
1179
1263
|
provider = new providerClass(this.server, this);
|
|
1180
|
-
});
|
|
1264
|
+
}, this.booting);
|
|
1181
1265
|
if (!provider)
|
|
1182
1266
|
continue;
|
|
1183
1267
|
if (isShapeProvider(provider)) {
|
|
@@ -1888,7 +1972,7 @@ let LinkedServer = class LinkedServer extends Shape {
|
|
|
1888
1972
|
/**
|
|
1889
1973
|
* indicates that instances of this shape need to have this rdf.type
|
|
1890
1974
|
*/
|
|
1891
|
-
LinkedServer.targetClass =
|
|
1975
|
+
LinkedServer.targetClass = server.LincdServer;
|
|
1892
1976
|
LinkedServer = __decorate([
|
|
1893
1977
|
linkedShape({ name: 'LinkedServer' }),
|
|
1894
1978
|
__metadata("design:paramtypes", [Object])
|