@btravstack/core 0.17.0 → 0.18.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/dist/index.cjs +25 -6
- package/dist/index.d.cts +15 -2
- package/dist/index.d.mts +15 -2
- package/dist/index.mjs +25 -7
- package/package.json +7 -6
package/dist/index.cjs
CHANGED
|
@@ -5,6 +5,7 @@ let node_timers_promises = require("node:timers/promises");
|
|
|
5
5
|
let _btravstack_config = require("@btravstack/config");
|
|
6
6
|
let node_http = require("node:http");
|
|
7
7
|
let node_async_hooks = require("node:async_hooks");
|
|
8
|
+
let node_crypto = require("node:crypto");
|
|
8
9
|
//#region src/instrumentation.ts
|
|
9
10
|
/**
|
|
10
11
|
* The set port a package contributes its instrumentation to.
|
|
@@ -432,10 +433,22 @@ const installUncaughtHandlers = (onUncaught) => {
|
|
|
432
433
|
const storage = new node_async_hooks.AsyncLocalStorage();
|
|
433
434
|
const runWithUnit = (record, fn) => storage.run(record, fn);
|
|
434
435
|
const currentUnit = () => storage.getStore();
|
|
435
|
-
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
436
|
+
const outcomes = /* @__PURE__ */ new WeakMap();
|
|
437
|
+
const settleUnit = (record, outcome) => {
|
|
438
|
+
outcomes.set(record, outcome);
|
|
439
|
+
};
|
|
440
|
+
/**
|
|
441
|
+
* How the current unit's work settled, for the code that runs AFTER it: a
|
|
442
|
+
* unit module's `onStop`, which tears down inside the record but is handed
|
|
443
|
+
* only its own service. `undefined` outside a unit and while the work is still
|
|
444
|
+
* running. Whether the unit was aborted is the record's own `signal`.
|
|
445
|
+
*
|
|
446
|
+
* It is the kernel's outcome, not the transport's: an HTTP unit that answered
|
|
447
|
+
* a `500` still settled `ok`, since the kernel never maps a status.
|
|
448
|
+
*/
|
|
449
|
+
const unitOutcome = () => {
|
|
450
|
+
const unit = currentUnit();
|
|
451
|
+
return unit === void 0 ? void 0 : outcomes.get(unit);
|
|
439
452
|
};
|
|
440
453
|
const createUnitRegistry = () => {
|
|
441
454
|
const open = /* @__PURE__ */ new Set();
|
|
@@ -451,7 +464,7 @@ const createUnitRegistry = () => {
|
|
|
451
464
|
const controller = new AbortController();
|
|
452
465
|
open.add(controller);
|
|
453
466
|
const record = {
|
|
454
|
-
unitId:
|
|
467
|
+
unitId: (0, node_crypto.randomUUID)(),
|
|
455
468
|
traceId: meta.traceId ?? meta.id,
|
|
456
469
|
tenantId: meta.tenantId,
|
|
457
470
|
signal: controller.signal
|
|
@@ -741,13 +754,18 @@ const start = (module, options = {}) => {
|
|
|
741
754
|
}).get();
|
|
742
755
|
return (0, unthrown.fromSafePromise)(ready.promise);
|
|
743
756
|
};
|
|
757
|
+
const record = currentUnit();
|
|
744
758
|
const outcome = (async () => {
|
|
759
|
+
let settledAs = "error";
|
|
745
760
|
try {
|
|
746
|
-
|
|
761
|
+
const result = await work({
|
|
747
762
|
ctx: runtimeCtx,
|
|
748
763
|
fork
|
|
749
764
|
}, signal);
|
|
765
|
+
if (result.isOk()) settledAs = "ok";
|
|
766
|
+
return result;
|
|
750
767
|
} finally {
|
|
768
|
+
if (record !== void 0) settleUnit(record, settledAs);
|
|
751
769
|
hasSettled = true;
|
|
752
770
|
settled.resolve();
|
|
753
771
|
if (closing !== void 0) await closing;
|
|
@@ -976,4 +994,5 @@ exports.start = start;
|
|
|
976
994
|
exports.stderrSink = stderrSink;
|
|
977
995
|
exports.systemClock = systemClock;
|
|
978
996
|
exports.traceIdOfTraceparent = traceIdOfTraceparent;
|
|
997
|
+
exports.unitOutcome = unitOutcome;
|
|
979
998
|
exports.withUnitRecord = withUnitRecord;
|
package/dist/index.d.cts
CHANGED
|
@@ -352,6 +352,18 @@ type UnitRecord = {
|
|
|
352
352
|
readonly signal: AbortSignal;
|
|
353
353
|
};
|
|
354
354
|
export declare const currentUnit: () => UnitRecord | undefined;
|
|
355
|
+
/** How a unit's work settled: `ok`, or `error` for an `Err`, a `Defect` and a throw alike. */
|
|
356
|
+
type UnitOutcome = "ok" | "error";
|
|
357
|
+
/**
|
|
358
|
+
* How the current unit's work settled, for the code that runs AFTER it: a
|
|
359
|
+
* unit module's `onStop`, which tears down inside the record but is handed
|
|
360
|
+
* only its own service. `undefined` outside a unit and while the work is still
|
|
361
|
+
* running. Whether the unit was aborted is the record's own `signal`.
|
|
362
|
+
*
|
|
363
|
+
* It is the kernel's outcome, not the transport's: an HTTP unit that answered
|
|
364
|
+
* a `500` still settled `ok`, since the kernel never maps a status.
|
|
365
|
+
*/
|
|
366
|
+
export declare const unitOutcome: () => UnitOutcome | undefined;
|
|
355
367
|
/**
|
|
356
368
|
* What a runtime says about one piece of work as it submits it. `kind` is the
|
|
357
369
|
* category (`"http"`, `"tick"`, `"job"`); `id` identifies **this** unit.
|
|
@@ -363,7 +375,8 @@ export declare const currentUnit: () => UnitRecord | undefined;
|
|
|
363
375
|
* silently defeats the ambient record. A route template is a `kind`.
|
|
364
376
|
*
|
|
365
377
|
* The kernel cannot check this, so uniqueness is the runtime's to guarantee.
|
|
366
|
-
* What it does guarantee is {@link UnitRecord}'s `unitId`, minted per
|
|
378
|
+
* What it does guarantee is {@link UnitRecord}'s `unitId`, a UUID minted per
|
|
379
|
+
* unit, so no two units share one across replicas either;
|
|
367
380
|
* `traceId` is the CORRELATION id, which is why it is the one a runtime may
|
|
368
381
|
* supply — it carries an id from outside the process.
|
|
369
382
|
*/
|
|
@@ -942,4 +955,4 @@ export declare const noObserverMember: Provider<Observers, never, never> & {
|
|
|
942
955
|
readonly port: typeof Observers;
|
|
943
956
|
};
|
|
944
957
|
//#endregion
|
|
945
|
-
export type { AnyUnitModule, Attributes, Clock, ComponentHealth, Counter, DrainReport, EventSink, ExitReport, HealthCheck, HealthReport, Histogram, InstrumentationLoader, KernelEvent, Level, LoggerService, MeterService, Operation, Phase, Refuse, RunUnit, RunningApp, Runtime, RuntimeHost, RuntimeInfoOf, Serving, Settle, Settled, Span, SpanStatusCode, StartGate, StartOptions, TeardownError, TracerService, UnitExportsOf, UnitGate, UnitHost, UnitMeta, UnitNeedsOf, UnitRecord, UnitRecordOf, UnitRegistry, UnitWork };
|
|
958
|
+
export type { AnyUnitModule, Attributes, Clock, ComponentHealth, Counter, DrainReport, EventSink, ExitReport, HealthCheck, HealthReport, Histogram, InstrumentationLoader, KernelEvent, Level, LoggerService, MeterService, Operation, Phase, Refuse, RunUnit, RunningApp, Runtime, RuntimeHost, RuntimeInfoOf, Serving, Settle, Settled, Span, SpanStatusCode, StartGate, StartOptions, TeardownError, TracerService, UnitExportsOf, UnitGate, UnitHost, UnitMeta, UnitNeedsOf, UnitOutcome, UnitRecord, UnitRecordOf, UnitRegistry, UnitWork };
|
package/dist/index.d.mts
CHANGED
|
@@ -352,6 +352,18 @@ type UnitRecord = {
|
|
|
352
352
|
readonly signal: AbortSignal;
|
|
353
353
|
};
|
|
354
354
|
export declare const currentUnit: () => UnitRecord | undefined;
|
|
355
|
+
/** How a unit's work settled: `ok`, or `error` for an `Err`, a `Defect` and a throw alike. */
|
|
356
|
+
type UnitOutcome = "ok" | "error";
|
|
357
|
+
/**
|
|
358
|
+
* How the current unit's work settled, for the code that runs AFTER it: a
|
|
359
|
+
* unit module's `onStop`, which tears down inside the record but is handed
|
|
360
|
+
* only its own service. `undefined` outside a unit and while the work is still
|
|
361
|
+
* running. Whether the unit was aborted is the record's own `signal`.
|
|
362
|
+
*
|
|
363
|
+
* It is the kernel's outcome, not the transport's: an HTTP unit that answered
|
|
364
|
+
* a `500` still settled `ok`, since the kernel never maps a status.
|
|
365
|
+
*/
|
|
366
|
+
export declare const unitOutcome: () => UnitOutcome | undefined;
|
|
355
367
|
/**
|
|
356
368
|
* What a runtime says about one piece of work as it submits it. `kind` is the
|
|
357
369
|
* category (`"http"`, `"tick"`, `"job"`); `id` identifies **this** unit.
|
|
@@ -363,7 +375,8 @@ export declare const currentUnit: () => UnitRecord | undefined;
|
|
|
363
375
|
* silently defeats the ambient record. A route template is a `kind`.
|
|
364
376
|
*
|
|
365
377
|
* The kernel cannot check this, so uniqueness is the runtime's to guarantee.
|
|
366
|
-
* What it does guarantee is {@link UnitRecord}'s `unitId`, minted per
|
|
378
|
+
* What it does guarantee is {@link UnitRecord}'s `unitId`, a UUID minted per
|
|
379
|
+
* unit, so no two units share one across replicas either;
|
|
367
380
|
* `traceId` is the CORRELATION id, which is why it is the one a runtime may
|
|
368
381
|
* supply — it carries an id from outside the process.
|
|
369
382
|
*/
|
|
@@ -942,4 +955,4 @@ export declare const noObserverMember: Provider<Observers, never, never> & {
|
|
|
942
955
|
readonly port: typeof Observers;
|
|
943
956
|
};
|
|
944
957
|
//#endregion
|
|
945
|
-
export type { AnyUnitModule, Attributes, Clock, ComponentHealth, Counter, DrainReport, EventSink, ExitReport, HealthCheck, HealthReport, Histogram, InstrumentationLoader, KernelEvent, Level, LoggerService, MeterService, Operation, Phase, Refuse, RunUnit, RunningApp, Runtime, RuntimeHost, RuntimeInfoOf, Serving, Settle, Settled, Span, SpanStatusCode, StartGate, StartOptions, TeardownError, TracerService, UnitExportsOf, UnitGate, UnitHost, UnitMeta, UnitNeedsOf, UnitRecord, UnitRecordOf, UnitRegistry, UnitWork };
|
|
958
|
+
export type { AnyUnitModule, Attributes, Clock, ComponentHealth, Counter, DrainReport, EventSink, ExitReport, HealthCheck, HealthReport, Histogram, InstrumentationLoader, KernelEvent, Level, LoggerService, MeterService, Operation, Phase, Refuse, RunUnit, RunningApp, Runtime, RuntimeHost, RuntimeInfoOf, Serving, Settle, Settled, Span, SpanStatusCode, StartGate, StartOptions, TeardownError, TracerService, UnitExportsOf, UnitGate, UnitHost, UnitMeta, UnitNeedsOf, UnitOutcome, UnitRecord, UnitRecordOf, UnitRegistry, UnitWork };
|
package/dist/index.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
|
4
4
|
import { Config, ConfigInvalid, Env } from "@btravstack/config";
|
|
5
5
|
import { createServer } from "node:http";
|
|
6
6
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
|
+
import { randomUUID } from "node:crypto";
|
|
7
8
|
//#region src/instrumentation.ts
|
|
8
9
|
/**
|
|
9
10
|
* The set port a package contributes its instrumentation to.
|
|
@@ -431,10 +432,22 @@ const installUncaughtHandlers = (onUncaught) => {
|
|
|
431
432
|
const storage = new AsyncLocalStorage();
|
|
432
433
|
const runWithUnit = (record, fn) => storage.run(record, fn);
|
|
433
434
|
const currentUnit = () => storage.getStore();
|
|
434
|
-
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
|
|
435
|
+
const outcomes = /* @__PURE__ */ new WeakMap();
|
|
436
|
+
const settleUnit = (record, outcome) => {
|
|
437
|
+
outcomes.set(record, outcome);
|
|
438
|
+
};
|
|
439
|
+
/**
|
|
440
|
+
* How the current unit's work settled, for the code that runs AFTER it: a
|
|
441
|
+
* unit module's `onStop`, which tears down inside the record but is handed
|
|
442
|
+
* only its own service. `undefined` outside a unit and while the work is still
|
|
443
|
+
* running. Whether the unit was aborted is the record's own `signal`.
|
|
444
|
+
*
|
|
445
|
+
* It is the kernel's outcome, not the transport's: an HTTP unit that answered
|
|
446
|
+
* a `500` still settled `ok`, since the kernel never maps a status.
|
|
447
|
+
*/
|
|
448
|
+
const unitOutcome = () => {
|
|
449
|
+
const unit = currentUnit();
|
|
450
|
+
return unit === void 0 ? void 0 : outcomes.get(unit);
|
|
438
451
|
};
|
|
439
452
|
const createUnitRegistry = () => {
|
|
440
453
|
const open = /* @__PURE__ */ new Set();
|
|
@@ -450,7 +463,7 @@ const createUnitRegistry = () => {
|
|
|
450
463
|
const controller = new AbortController();
|
|
451
464
|
open.add(controller);
|
|
452
465
|
const record = {
|
|
453
|
-
unitId:
|
|
466
|
+
unitId: randomUUID(),
|
|
454
467
|
traceId: meta.traceId ?? meta.id,
|
|
455
468
|
tenantId: meta.tenantId,
|
|
456
469
|
signal: controller.signal
|
|
@@ -740,13 +753,18 @@ const start = (module, options = {}) => {
|
|
|
740
753
|
}).get();
|
|
741
754
|
return fromSafePromise(ready.promise);
|
|
742
755
|
};
|
|
756
|
+
const record = currentUnit();
|
|
743
757
|
const outcome = (async () => {
|
|
758
|
+
let settledAs = "error";
|
|
744
759
|
try {
|
|
745
|
-
|
|
760
|
+
const result = await work({
|
|
746
761
|
ctx: runtimeCtx,
|
|
747
762
|
fork
|
|
748
763
|
}, signal);
|
|
764
|
+
if (result.isOk()) settledAs = "ok";
|
|
765
|
+
return result;
|
|
749
766
|
} finally {
|
|
767
|
+
if (record !== void 0) settleUnit(record, settledAs);
|
|
750
768
|
hasSettled = true;
|
|
751
769
|
settled.resolve();
|
|
752
770
|
if (closing !== void 0) await closing;
|
|
@@ -949,4 +967,4 @@ const noObserverMember = Provider.member(Observers)({
|
|
|
949
967
|
value: noObserver
|
|
950
968
|
});
|
|
951
969
|
//#endregion
|
|
952
|
-
export { HealthCheckFailed, HealthChecks, Instrumentations, LEVELS, Logger, Meter, Observers, RuntimePort, RuntimeStartFailed, SPAN_STATUS, Tracer, composeByPrefix, currentUnit, dispatchUnit, mintPiece, noObserver, noObserverMember, observe, observed, releasedBy, runHealthChecks, runMain, start, stderrSink, systemClock, traceIdOfTraceparent, withUnitRecord };
|
|
970
|
+
export { HealthCheckFailed, HealthChecks, Instrumentations, LEVELS, Logger, Meter, Observers, RuntimePort, RuntimeStartFailed, SPAN_STATUS, Tracer, composeByPrefix, currentUnit, dispatchUnit, mintPiece, noObserver, noObserverMember, observe, observed, releasedBy, runHealthChecks, runMain, start, stderrSink, systemClock, traceIdOfTraceparent, unitOutcome, withUnitRecord };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btravstack/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "The application kernel: boot a di module into a running process, and stop it without losing work",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"application",
|
|
@@ -45,20 +45,21 @@
|
|
|
45
45
|
"./package.json": "./package.json"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@btravstack/config": "0.
|
|
49
|
-
"@btravstack/di": "0.
|
|
48
|
+
"@btravstack/config": "0.18.0",
|
|
49
|
+
"@btravstack/di": "0.18.0",
|
|
50
50
|
"@btravstack/tsconfig": "0.4.0",
|
|
51
51
|
"@types/node": "26.6.4",
|
|
52
52
|
"@unthrown/vitest": "5.12.0",
|
|
53
53
|
"@vitest/coverage-v8": "5.0.3",
|
|
54
54
|
"tsdown": "0.23.0",
|
|
55
55
|
"typescript": "7.0.2",
|
|
56
|
+
"typescript-consumer": "npm:typescript@5.9.3",
|
|
56
57
|
"unthrown": "5.12.0",
|
|
57
58
|
"vitest": "5.0.3"
|
|
58
59
|
},
|
|
59
60
|
"peerDependencies": {
|
|
60
|
-
"@btravstack/config": "^0.
|
|
61
|
-
"@btravstack/di": "^0.
|
|
61
|
+
"@btravstack/config": "^0.18.0",
|
|
62
|
+
"@btravstack/di": "^0.18.0",
|
|
62
63
|
"unthrown": "^5.0.0"
|
|
63
64
|
},
|
|
64
65
|
"engines": {
|
|
@@ -69,6 +70,6 @@
|
|
|
69
70
|
"dev": "tsdown src/index.ts --format cjs,esm --dts --watch --tsconfig tsconfig.build.json",
|
|
70
71
|
"generate": "node ../../docs/scripts/extract-doc-samples.ts --group core --out src/generated/doc-samples",
|
|
71
72
|
"test": "vitest run --coverage",
|
|
72
|
-
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test-d.json"
|
|
73
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test-d.json && node ./node_modules/typescript-consumer/bin/tsc --noEmit -p tsconfig.test-d.json"
|
|
73
74
|
}
|
|
74
75
|
}
|