@_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
package/lib/esm/shapes/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Registers every shape this package defines. Side-effect imports only: a
|
|
2
2
|
// consumer (or the host app) can load this one module to get the full set of
|
|
3
3
|
// shapes registered, without pulling in components, providers or other exports.
|
|
4
|
-
import '../ontologies/
|
|
4
|
+
import '../ontologies/server.register.js';
|
|
5
5
|
import './LinkedServer.js';
|
|
6
6
|
import './LincdAPI.js';
|
|
7
7
|
import './LincdWebApp.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shapes/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,6EAA6E;AAC7E,gFAAgF;AAChF,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shapes/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,6EAA6E;AAC7E,gFAAgF;AAChF,OAAO,kCAAkC,CAAC;AAE1C,OAAO,mBAAmB,CAAC;AAC3B,OAAO,eAAe,CAAC;AACvB,OAAO,kBAAkB,CAAC","sourcesContent":["// Registers every shape this package defines. Side-effect imports only: a\n// consumer (or the host app) can load this one module to get the full set of\n// shapes registered, without pulling in components, providers or other exports.\nimport '../ontologies/server.register.js';\n\nimport './LinkedServer.js';\nimport './LincdAPI.js';\nimport './LincdWebApp.js';\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fatal-error contract between providers and the server's boot.
|
|
3
|
+
*
|
|
4
|
+
* The server isolates provider failures: a provider constructor, a backend
|
|
5
|
+
* module load or a boot hook that throws is logged with the package name and
|
|
6
|
+
* boot carries on without that provider. That is right for a bug, and wrong
|
|
7
|
+
* for a provider that has decided the app must not serve at all — auth with
|
|
8
|
+
* no signing secret in production, say. Serving anyway looks healthy and
|
|
9
|
+
* fails every request that needs it.
|
|
10
|
+
*
|
|
11
|
+
* So: an error with an OWN property `fatal` set to `true` is not swallowed
|
|
12
|
+
* when it is thrown at boot. The server logs it, `start()` rejects with it,
|
|
13
|
+
* and the process exits non-zero. Any error object qualifies — a provider
|
|
14
|
+
* does not need to depend on this package to use the contract:
|
|
15
|
+
*
|
|
16
|
+
* throw Object.assign(new Error('JWT_SECRET is not set'), {fatal: true});
|
|
17
|
+
*
|
|
18
|
+
* or, with this package available:
|
|
19
|
+
*
|
|
20
|
+
* throw new FatalStartupError('JWT_SECRET is not set');
|
|
21
|
+
*
|
|
22
|
+
* Thrown after boot (a per-request hook, a lazy load on a later /call, an
|
|
23
|
+
* HMR reload) it is logged as fatal but does not stop a running server.
|
|
24
|
+
*/
|
|
25
|
+
export interface FatalError extends Error {
|
|
26
|
+
fatal: true;
|
|
27
|
+
}
|
|
28
|
+
/** An error that refuses to let the server start. See {@link FatalError}. */
|
|
29
|
+
export declare class FatalStartupError extends Error implements FatalError {
|
|
30
|
+
fatal: true;
|
|
31
|
+
constructor(message: string, options?: {
|
|
32
|
+
cause?: unknown;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/** True for an error that carries the fatal contract: own `fatal === true`. */
|
|
36
|
+
export declare function isFatalError(err: unknown): err is FatalError;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** An error that refuses to let the server start. See {@link FatalError}. */
|
|
2
|
+
export class FatalStartupError extends Error {
|
|
3
|
+
constructor(message, options) {
|
|
4
|
+
super(message);
|
|
5
|
+
// `cause` by hand: the ES2022 Error(message, options) signature is not in
|
|
6
|
+
// this package's lib target.
|
|
7
|
+
if (options && 'cause' in options)
|
|
8
|
+
this.cause = options.cause;
|
|
9
|
+
this.name = 'FatalStartupError';
|
|
10
|
+
// Assigned, not declared with an initializer, so it is an own property
|
|
11
|
+
// whatever the class-field emit.
|
|
12
|
+
this.fatal = true;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** True for an error that carries the fatal contract: own `fatal === true`. */
|
|
16
|
+
export function isFatalError(err) {
|
|
17
|
+
return (!!err &&
|
|
18
|
+
typeof err === 'object' &&
|
|
19
|
+
Object.prototype.hasOwnProperty.call(err, 'fatal') &&
|
|
20
|
+
err.fatal === true);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=fatalError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fatalError.js","sourceRoot":"","sources":["../../../src/utils/fatalError.ts"],"names":[],"mappings":"AA4BA,6EAA6E;AAC7E,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAE1C,YAAY,OAAe,EAAE,OAA6B;QACxD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,0EAA0E;QAC1E,6BAA6B;QAC7B,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO;YAAG,IAAY,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QACvE,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,uEAAuE;QACvE,iCAAiC;QACjC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;CACF;AAED,+EAA+E;AAC/E,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,OAAO,CACL,CAAC,CAAC,GAAG;QACL,OAAO,GAAG,KAAK,QAAQ;QACvB,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC;QACjD,GAAW,CAAC,KAAK,KAAK,IAAI,CAC5B,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The fatal-error contract between providers and the server's boot.\n *\n * The server isolates provider failures: a provider constructor, a backend\n * module load or a boot hook that throws is logged with the package name and\n * boot carries on without that provider. That is right for a bug, and wrong\n * for a provider that has decided the app must not serve at all — auth with\n * no signing secret in production, say. Serving anyway looks healthy and\n * fails every request that needs it.\n *\n * So: an error with an OWN property `fatal` set to `true` is not swallowed\n * when it is thrown at boot. The server logs it, `start()` rejects with it,\n * and the process exits non-zero. Any error object qualifies — a provider\n * does not need to depend on this package to use the contract:\n *\n * throw Object.assign(new Error('JWT_SECRET is not set'), {fatal: true});\n *\n * or, with this package available:\n *\n * throw new FatalStartupError('JWT_SECRET is not set');\n *\n * Thrown after boot (a per-request hook, a lazy load on a later /call, an\n * HMR reload) it is logged as fatal but does not stop a running server.\n */\nexport interface FatalError extends Error {\n fatal: true;\n}\n\n/** An error that refuses to let the server start. See {@link FatalError}. */\nexport class FatalStartupError extends Error implements FatalError {\n fatal: true;\n constructor(message: string, options?: { cause?: unknown }) {\n super(message);\n // `cause` by hand: the ES2022 Error(message, options) signature is not in\n // this package's lib target.\n if (options && 'cause' in options) (this as any).cause = options.cause;\n this.name = 'FatalStartupError';\n // Assigned, not declared with an initializer, so it is an own property\n // whatever the class-field emit.\n this.fatal = true;\n }\n}\n\n/** True for an error that carries the fatal contract: own `fatal === true`. */\nexport function isFatalError(err: unknown): err is FatalError {\n return (\n !!err &&\n typeof err === 'object' &&\n Object.prototype.hasOwnProperty.call(err, 'fatal') &&\n (err as any).fatal === true\n );\n}\n"]}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -21,6 +21,7 @@ If you want to further adjust the functionality of LincdServer yourself, either
|
|
|
21
21
|
- [Error semantics](#error-semantics)
|
|
22
22
|
- [API-only servers (`server.apiOnly`)](#api-only-servers-serverapionly)
|
|
23
23
|
- [Provider lifecycle and HMR](#provider-lifecycle-and-hmr)
|
|
24
|
+
- [When a provider throws, and refusing to start](#when-a-provider-throws-and-refusing-to-start)
|
|
24
25
|
- [When to implement `dispose()`](#when-to-implement-dispose)
|
|
25
26
|
- [Route tracking helpers](#route-tracking-helpers)
|
|
26
27
|
- [Examples](#examples)
|
|
@@ -257,6 +258,25 @@ Every provider — generic (`BackendProvider`) or shape-scoped (`ShapeProvider`)
|
|
|
257
258
|
|
|
258
259
|
The dispose step is what makes hot-reload safe. Without it, anything the constructor or boot hooks registered — Express routes, middleware, listeners, timers, global-singleton mutations — would accumulate every time the source file changed. The framework calls `dispose()` on the OLD provider before replacing it with a freshly-instantiated one.
|
|
259
260
|
|
|
261
|
+
### When a provider throws, and refusing to start
|
|
262
|
+
|
|
263
|
+
A provider that throws is isolated: a failing constructor, a backend module that throws when it loads, or a boot hook that throws or rejects is logged with the package and hook name (`[linked] <pkg> <hook> failed: …`), and the rest of the app still starts without it. Per-request hooks (`initRequest`, `supplyDataForRequest`) are isolated the same way — the request is served with the other providers' data.
|
|
264
|
+
|
|
265
|
+
Sometimes a provider must not let the app serve at all — auth with no signing secret in production, say, where serving anyway looks healthy and fails every sign-in. For that, throw an error with an **own property `fatal` set to `true`**:
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
// No dependency on @_linked/server needed:
|
|
269
|
+
throw Object.assign(new Error('JWT_SECRET is not set'), {fatal: true});
|
|
270
|
+
|
|
271
|
+
// or, with the helper:
|
|
272
|
+
import {FatalStartupError} from '@_linked/server/utils/fatalError';
|
|
273
|
+
throw new FatalStartupError('JWT_SECRET is not set');
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Thrown while the server boots — from a provider constructor, a backend module's top level, or `setupBeforeControllers` / `setupBeforeCatchAllControllers` / `setupAfterControllers` — it is logged as `[linked] <pkg> <hook>: fatal error, refusing to start: <message>`, `start()` (and `initOnly()`) rejects with it before the server listens, and the process exits with code 1. The exit code is set immediately; because a rejected `start()` alone does not end a process that still has a Vite dev server, a store connection or a timer open, the server also calls `process.exit(1)` a second later (an embedder can override `exitAfterFatalStartupError`). `isFatalError(err)` checks the contract.
|
|
277
|
+
|
|
278
|
+
Thrown after boot — from a per-request hook, a backend loaded lazily by a later `/call`, or an HMR reload — the error is logged as fatal (`… fatal error after start, server keeps running: …`) and contained like any other: one provider does not take down a server that is already serving. A provider that must refuse should therefore decide at construction or in a boot hook.
|
|
279
|
+
|
|
260
280
|
### When to implement `dispose()`
|
|
261
281
|
|
|
262
282
|
Implement `dispose()` when your provider does any of the following at construction or boot:
|