@btravstack/core 0.12.0 → 0.14.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/README.md +5 -4
- package/dist/index.cjs +36 -8
- package/dist/index.d.cts +63 -52
- package/dist/index.d.mts +63 -52
- package/dist/index.mjs +36 -8
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -68,8 +68,8 @@ const ticker: Runtime<typeof Greeter> = {
|
|
|
68
68
|
// and stays out of it. A timer has nowhere to return one, so it observes
|
|
69
69
|
// it instead; dropping it would hide the work's `Err` *and* a `Defect`.
|
|
70
70
|
void host
|
|
71
|
-
.run({ kind: "tick", id: `${Date.now()}` }, (
|
|
72
|
-
signal.aborted ? Ok("") : Ok(ctx.get(Greeter).greet("world")),
|
|
71
|
+
.run({ kind: "tick", id: `${Date.now()}` }, (unit, signal) =>
|
|
72
|
+
signal.aborted ? Ok("") : Ok(unit.ctx.get(Greeter).greet("world")),
|
|
73
73
|
)
|
|
74
74
|
.tapFailure((failure) => {
|
|
75
75
|
process.stderr.write(`${JSON.stringify({ tick: failure.tag })}\n`);
|
|
@@ -145,8 +145,9 @@ them and none should own a private copy:
|
|
|
145
145
|
bad value is a `ConfigInvalid` naming every fault at once, and exit `78`.
|
|
146
146
|
- **Teardown on every path**, with failing finalisers in
|
|
147
147
|
`ExitReport.teardownErrors`, never masking the exit reason.
|
|
148
|
-
- **A per-unit scope no handler manages** —
|
|
149
|
-
`
|
|
148
|
+
- **A per-unit scope no handler manages** — the runtime calls
|
|
149
|
+
`unit.fork(module, seed)` from inside `host.run`'s work callback, and the
|
|
150
|
+
kernel closes the scope when the unit settles.
|
|
150
151
|
- **An ambient record, not an ambient container** — `currentUnit()` reads
|
|
151
152
|
`{ unitId, traceId, tenantId, signal }`; services never travel
|
|
152
153
|
there. `signal` is the very `AbortSignal` the unit's work callback is handed,
|
package/dist/index.cjs
CHANGED
|
@@ -613,15 +613,43 @@ const start = (module, options = {}) => {
|
|
|
613
613
|
runtimeName = runtime.name;
|
|
614
614
|
healthChecks = ctx.get(HealthChecks);
|
|
615
615
|
const runtimeCtx = ctx;
|
|
616
|
-
const unit = options.unit;
|
|
617
616
|
const run = (meta, work) => registry.run(meta, (signal) => {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
617
|
+
const settled = Promise.withResolvers();
|
|
618
|
+
let closing;
|
|
619
|
+
let hasSettled = false;
|
|
620
|
+
const fork = (module, seed) => {
|
|
621
|
+
if (hasSettled) return (0, unthrown.fromSafePromise)(Promise.reject(/* @__PURE__ */ new Error("a unit forks after it has already settled")));
|
|
622
|
+
if (closing !== void 0) return (0, unthrown.fromSafePromise)(Promise.reject(/* @__PURE__ */ new Error("a unit forks its scope once")));
|
|
623
|
+
const ready = Promise.withResolvers();
|
|
624
|
+
closing = _btravstack_di.Module.forkScope(ctx, module, (forked) => {
|
|
625
|
+
ready.resolve(forked);
|
|
626
|
+
return (0, unthrown.fromSafePromise)(settled.promise);
|
|
627
|
+
}, {
|
|
628
|
+
seed,
|
|
629
|
+
onTeardownError: (port, cause) => emit({
|
|
630
|
+
type: "teardownError",
|
|
631
|
+
port,
|
|
632
|
+
cause
|
|
633
|
+
})
|
|
634
|
+
}).recoverDefect((cause) => {
|
|
635
|
+
ready.reject(cause);
|
|
636
|
+
return (0, unthrown.Ok)();
|
|
637
|
+
}).get();
|
|
638
|
+
return (0, unthrown.fromSafePromise)(ready.promise);
|
|
639
|
+
};
|
|
640
|
+
const outcome = (async () => {
|
|
641
|
+
try {
|
|
642
|
+
return await work({
|
|
643
|
+
ctx: runtimeCtx,
|
|
644
|
+
fork
|
|
645
|
+
}, signal);
|
|
646
|
+
} finally {
|
|
647
|
+
hasSettled = true;
|
|
648
|
+
settled.resolve();
|
|
649
|
+
if (closing !== void 0) await closing;
|
|
650
|
+
}
|
|
651
|
+
})();
|
|
652
|
+
return (0, unthrown.fromSafePromise)(outcome).flatMap((result) => result);
|
|
625
653
|
});
|
|
626
654
|
const host = {
|
|
627
655
|
ctx: runtimeCtx,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AsyncResult, Result } from "unthrown";
|
|
2
|
-
import { AnyPort, Context, Module, PortClass, PortInstance, Scope, ServiceOf } from "@btravstack/di";
|
|
2
|
+
import { AnyPort, Context, DependencyGate, Module, PortClass, PortInstance, Scope, SeedEntry, ServiceOf } from "@btravstack/di";
|
|
3
3
|
import { Env, Environment } from "@btravstack/config";
|
|
4
4
|
//#region src/instrumentation.d.ts
|
|
5
5
|
/**
|
|
@@ -31,7 +31,7 @@ declare const Instrumentations_base: import("@btravstack/di").ManyPortClass<"Ins
|
|
|
31
31
|
* without it registers nothing and pays nothing — the Spring Boot starter
|
|
32
32
|
* shape, in one port.
|
|
33
33
|
*/
|
|
34
|
-
declare class Instrumentations extends Instrumentations_base<InstrumentationLoader> {}
|
|
34
|
+
export declare class Instrumentations extends Instrumentations_base<InstrumentationLoader> {}
|
|
35
35
|
//#endregion
|
|
36
36
|
//#region src/health.d.ts
|
|
37
37
|
declare const HealthCheckFailed_base: import("unthrown").TaggedErrorConstructor<"HealthCheckFailed">;
|
|
@@ -40,7 +40,7 @@ declare const HealthCheckFailed_base: import("unthrown").TaggedErrorConstructor<
|
|
|
40
40
|
* a health check that throws is a bug in the check; one that fails is the news
|
|
41
41
|
* `/healthz` exists to carry.
|
|
42
42
|
*/
|
|
43
|
-
declare class HealthCheckFailed extends HealthCheckFailed_base<{
|
|
43
|
+
export declare class HealthCheckFailed extends HealthCheckFailed_base<{
|
|
44
44
|
readonly reason: string;
|
|
45
45
|
}> {}
|
|
46
46
|
/** One contribution: what to call the component, and how to ask it. */
|
|
@@ -57,7 +57,7 @@ declare const HealthChecks_base: import("@btravstack/di").ManyPortClass<"HealthC
|
|
|
57
57
|
* application never composed contributes nothing — no registration call to
|
|
58
58
|
* forget, and no order to get wrong.
|
|
59
59
|
*/
|
|
60
|
-
declare class HealthChecks extends HealthChecks_base<HealthCheck> {}
|
|
60
|
+
export declare class HealthChecks extends HealthChecks_base<HealthCheck> {}
|
|
61
61
|
type ComponentHealth = {
|
|
62
62
|
readonly name: string;
|
|
63
63
|
readonly status: "healthy" | "unhealthy";
|
|
@@ -81,7 +81,7 @@ type HealthReport = {
|
|
|
81
81
|
* escaped, the first would reach the kernel's own `uncaughtException` handler
|
|
82
82
|
* and the second would leave `/healthz` hanging with nothing written.
|
|
83
83
|
*/
|
|
84
|
-
declare const runHealthChecks: (checks: readonly HealthCheck[]) => AsyncResult<HealthReport, never>;
|
|
84
|
+
export declare const runHealthChecks: (checks: readonly HealthCheck[]) => AsyncResult<HealthReport, never>;
|
|
85
85
|
//#endregion
|
|
86
86
|
//#region src/observability.d.ts
|
|
87
87
|
/**
|
|
@@ -91,7 +91,7 @@ declare const runHealthChecks: (checks: readonly HealthCheck[]) => AsyncResult<H
|
|
|
91
91
|
*/
|
|
92
92
|
type Level = "trace" | "debug" | "info" | "warn" | "error" | "fatal";
|
|
93
93
|
/** The levels in order, least severe first — what `isEnabled` compares through. */
|
|
94
|
-
declare const LEVELS: readonly Level[];
|
|
94
|
+
export declare const LEVELS: readonly Level[];
|
|
95
95
|
/**
|
|
96
96
|
* What a line, a span or a measurement carries besides itself: a flat record of
|
|
97
97
|
* scalars.
|
|
@@ -137,9 +137,9 @@ declare const Logger_base: import("@btravstack/di").PortClass<"Logger">;
|
|
|
137
137
|
* problem into an outage. Synchronous `void`, not an `AsyncResult` — thesis 6's
|
|
138
138
|
* one deliberate exemption, since a lost line is not a modeled error.
|
|
139
139
|
*/
|
|
140
|
-
declare class Logger extends Logger_base<LoggerService> {}
|
|
140
|
+
export declare class Logger extends Logger_base<LoggerService> {}
|
|
141
141
|
/** A span's outcome: unset until something says otherwise, then `ok` or `error`. */
|
|
142
|
-
declare const SPAN_STATUS: {
|
|
142
|
+
export declare const SPAN_STATUS: {
|
|
143
143
|
readonly unset: 0;
|
|
144
144
|
readonly ok: 1;
|
|
145
145
|
readonly error: 2;
|
|
@@ -169,7 +169,7 @@ declare const Tracer_base: import("@btravstack/di").PortClass<"Tracer">;
|
|
|
169
169
|
* because a port typed as a vendor's type points the dependency arrow outwards
|
|
170
170
|
* and makes the whole family install that vendor.
|
|
171
171
|
*/
|
|
172
|
-
declare class Tracer extends Tracer_base<TracerService> {}
|
|
172
|
+
export declare class Tracer extends Tracer_base<TracerService> {}
|
|
173
173
|
/** A monotonic count. */
|
|
174
174
|
type Counter = {
|
|
175
175
|
readonly add: (value: number, attributes?: Attributes) => void;
|
|
@@ -196,7 +196,7 @@ type MeterService = {
|
|
|
196
196
|
};
|
|
197
197
|
declare const Meter_base: import("@btravstack/di").PortClass<"Meter">;
|
|
198
198
|
/** The application's meter, as a port. See {@link Tracer} for why it does not name a vendor. */
|
|
199
|
-
declare class Meter extends Meter_base<MeterService> {}
|
|
199
|
+
export declare class Meter extends Meter_base<MeterService> {}
|
|
200
200
|
//#endregion
|
|
201
201
|
//#region src/observation.d.ts
|
|
202
202
|
/**
|
|
@@ -277,9 +277,9 @@ declare const Observers_base: import("@btravstack/di").ManyPortClass<"Observers"
|
|
|
277
277
|
* NOTHING provides is an unmet dependency, at plan time and in `Needs` alike.
|
|
278
278
|
* Several no-ops in one graph cost a call each and nothing else.
|
|
279
279
|
*/
|
|
280
|
-
declare class Observers extends Observers_base<(operation: Operation) => Settle> {}
|
|
280
|
+
export declare class Observers extends Observers_base<(operation: Operation) => Settle> {}
|
|
281
281
|
/** The no-op member every reader of {@link Observers} contributes, so the set is never empty. */
|
|
282
|
-
declare const noObserver: () => Settle;
|
|
282
|
+
export declare const noObserver: () => Settle;
|
|
283
283
|
/**
|
|
284
284
|
* Run every observer around one operation, and hand back the one finisher that
|
|
285
285
|
* settles them all.
|
|
@@ -291,14 +291,14 @@ declare const noObserver: () => Settle;
|
|
|
291
291
|
* `tapFailure` on the same chain, or a retry, is exactly the shape that fires
|
|
292
292
|
* twice and doubles a failure count.
|
|
293
293
|
*/
|
|
294
|
-
declare const observe: (observers: readonly ((operation: Operation) => Settle)[], operation: Operation) => Settle;
|
|
294
|
+
export declare const observe: (observers: readonly ((operation: Operation) => Settle)[], operation: Operation) => Settle;
|
|
295
295
|
//#endregion
|
|
296
296
|
//#region src/clock.d.ts
|
|
297
297
|
type Clock = {
|
|
298
298
|
readonly now: () => number;
|
|
299
299
|
readonly sleep: (ms: number, signal?: AbortSignal) => AsyncResult<void, never>;
|
|
300
300
|
};
|
|
301
|
-
declare const systemClock: Clock;
|
|
301
|
+
export declare const systemClock: Clock;
|
|
302
302
|
//#endregion
|
|
303
303
|
//#region src/units.d.ts
|
|
304
304
|
/**
|
|
@@ -317,7 +317,7 @@ type UnitRecord = {
|
|
|
317
317
|
readonly tenantId: string | undefined;
|
|
318
318
|
readonly signal: AbortSignal;
|
|
319
319
|
};
|
|
320
|
-
declare const currentUnit: () => UnitRecord | undefined;
|
|
320
|
+
export declare const currentUnit: () => UnitRecord | undefined;
|
|
321
321
|
/**
|
|
322
322
|
* What a runtime says about one piece of work as it submits it. `kind` is the
|
|
323
323
|
* category (`"http"`, `"tick"`, `"job"`); `id` identifies **this** unit.
|
|
@@ -350,7 +350,7 @@ type UnitRegistry = {
|
|
|
350
350
|
//#endregion
|
|
351
351
|
//#region src/runtime.d.ts
|
|
352
352
|
declare const RuntimeStartFailed_base: import("unthrown").TaggedErrorConstructor<"RuntimeStartFailed">;
|
|
353
|
-
declare class RuntimeStartFailed extends RuntimeStartFailed_base<{
|
|
353
|
+
export declare class RuntimeStartFailed extends RuntimeStartFailed_base<{
|
|
354
354
|
readonly runtime: string;
|
|
355
355
|
readonly cause: unknown;
|
|
356
356
|
}> {
|
|
@@ -372,11 +372,28 @@ declare class RuntimeStartFailed extends RuntimeStartFailed_base<{
|
|
|
372
372
|
* `UnitMeta.id` must be unique per unit unless a `traceId` is supplied — see
|
|
373
373
|
* {@link UnitMeta}.
|
|
374
374
|
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
375
|
+
* A runtime forks the unit's scope itself, through `UnitHost.fork`, at the
|
|
376
|
+
* moment it holds the unit's input; the kernel closes that scope when the
|
|
377
|
+
* unit settles, after the response is flushed. Work that subscribes to an
|
|
378
|
+
* event after a `fork` must first check whether it already fired.
|
|
378
379
|
*/
|
|
379
|
-
type RunUnit<Resolves extends AnyPort> = <T, E>(meta: UnitMeta, work: (
|
|
380
|
+
type RunUnit<Resolves extends AnyPort> = <T, E>(meta: UnitMeta, work: (unit: UnitHost<Resolves>, signal: AbortSignal) => ReturnType<UnitWork<T, E>>) => AsyncResult<T, E>;
|
|
381
|
+
/**
|
|
382
|
+
* What the kernel hands a unit's work: the application context, and the one
|
|
383
|
+
* way to open the unit's own scope.
|
|
384
|
+
*
|
|
385
|
+
* `fork` builds `module` over the application context plus `seed` and hands
|
|
386
|
+
* the forked context back. The scope is torn down when the unit closes —
|
|
387
|
+
* inside the registry's unit, so the unit is not counted closed until its
|
|
388
|
+
* finalisers have run, and inside the unit's ambient record, so a teardown
|
|
389
|
+
* log line carries the unit's ids. A construction failure rides the unit's
|
|
390
|
+
* defect path. A unit forks once; a second call is a defect, and so is a call
|
|
391
|
+
* made after the unit has settled — nothing awaits that scope's teardown.
|
|
392
|
+
*/
|
|
393
|
+
type UnitHost<Resolves extends AnyPort> = {
|
|
394
|
+
readonly ctx: Context<InstanceType<Resolves>>;
|
|
395
|
+
readonly fork: <UnitX, N, Seeded extends AnyPort = never>(module: Module<UnitX, never, N> & DependencyGate<Exclude<N, InstanceType<Resolves> | InstanceType<Seeded> | Scope>>, seed: readonly SeedEntry<Seeded>[]) => AsyncResult<Context<InstanceType<Resolves> | UnitX | InstanceType<Seeded>>, never>;
|
|
396
|
+
};
|
|
380
397
|
/**
|
|
381
398
|
* What a runtime is handed at `start`: the application services **and** the
|
|
382
399
|
* kernel's {@link RunUnit}. Handing it a bare `Context` would leave every
|
|
@@ -388,8 +405,8 @@ type RunUnit<Resolves extends AnyPort> = <T, E>(meta: UnitMeta, work: (ctx: Cont
|
|
|
388
405
|
* {@link RunUnit}), and `UnitMeta.id` must be unique per unit unless a
|
|
389
406
|
* `traceId` is supplied (see {@link UnitMeta}).
|
|
390
407
|
*
|
|
391
|
-
* `ctx` is the **application** context: a port a
|
|
392
|
-
*
|
|
408
|
+
* `ctx` is the **application** context: a port a unit's `fork` module provides
|
|
409
|
+
* exists only in the `Context` `fork` hands back, so a runtime naming it in
|
|
393
410
|
* `resolves` is rejected at `start`'s call site.
|
|
394
411
|
*/
|
|
395
412
|
type RuntimeHost<Resolves extends AnyPort> = {
|
|
@@ -425,13 +442,17 @@ type Runtime<Resolves extends AnyPort = never, Info = never> = {
|
|
|
425
442
|
* process boots exactly one, while each carries its own `Resolves`/`Info` in
|
|
426
443
|
* the type.
|
|
427
444
|
*/
|
|
428
|
-
declare const RuntimePort: PortClass<"Runtime">;
|
|
445
|
+
export declare const RuntimePort: PortClass<"Runtime">;
|
|
429
446
|
/** The instance type every runtime port shares — `Extract` this from a module's exports to find its runtime. */
|
|
430
447
|
type RuntimeInstance = InstanceType<PortClass<"Runtime">>;
|
|
431
448
|
/** The `Runtime<Resolves, Info>` a module exports, or `never` when it exports none. */
|
|
432
449
|
type RuntimeOf<X> = ServiceOf<Extract<X, RuntimeInstance>>;
|
|
433
|
-
type RuntimeResolvesOf<X> = RuntimeOf<X> extends
|
|
434
|
-
|
|
450
|
+
type RuntimeResolvesOf<X> = RuntimeOf<X> extends {
|
|
451
|
+
readonly resolves: readonly (infer Resolves extends AnyPort)[];
|
|
452
|
+
} ? Resolves : never;
|
|
453
|
+
type RuntimeInfoOf<X> = RuntimeOf<X> extends {
|
|
454
|
+
readonly start: (host: never) => AsyncResult<Serving<infer Info>, RuntimeStartFailed>;
|
|
455
|
+
} ? Info : never;
|
|
435
456
|
/**
|
|
436
457
|
* The trace id inside a W3C `traceparent` header, and nothing else of it.
|
|
437
458
|
*
|
|
@@ -459,7 +480,7 @@ type RuntimeInfoOf<X> = RuntimeOf<X> extends Runtime<AnyPort, infer Info> ? Info
|
|
|
459
480
|
* const traceId = typeof parent === "string" ? traceIdOfTraceparent(parent) : undefined;
|
|
460
481
|
* ```
|
|
461
482
|
*/
|
|
462
|
-
declare const traceIdOfTraceparent: (header: string) => string | undefined;
|
|
483
|
+
export declare const traceIdOfTraceparent: (header: string) => string | undefined;
|
|
463
484
|
/**
|
|
464
485
|
* `running`, but no later than the kernel's drain deadline — the primitive a
|
|
465
486
|
* `Serving.drain` needs when the work it awaits settles on somebody else's
|
|
@@ -479,7 +500,7 @@ declare const traceIdOfTraceparent: (header: string) => string | undefined;
|
|
|
479
500
|
* (`drain.ts` uses `clock.sleep` for exactly that, so a fake clock can control
|
|
480
501
|
* it) — do not fold the two together.
|
|
481
502
|
*/
|
|
482
|
-
declare const releasedBy: (signal: AbortSignal, running: AsyncResult<void, never>) => AsyncResult<void, never>;
|
|
503
|
+
export declare const releasedBy: (signal: AbortSignal, running: AsyncResult<void, never>) => AsyncResult<void, never>;
|
|
483
504
|
//#endregion
|
|
484
505
|
//#region src/drain.d.ts
|
|
485
506
|
type DrainReport = {
|
|
@@ -539,7 +560,7 @@ type KernelEvent = {
|
|
|
539
560
|
readonly cause: unknown;
|
|
540
561
|
};
|
|
541
562
|
type EventSink = (event: KernelEvent) => void;
|
|
542
|
-
declare const stderrSink: EventSink;
|
|
563
|
+
export declare const stderrSink: EventSink;
|
|
543
564
|
//#endregion
|
|
544
565
|
//#region src/phase.d.ts
|
|
545
566
|
type Phase = "building" | "starting" | "serving" | "draining" | "stopping" | "exited";
|
|
@@ -555,26 +576,13 @@ type ExitReport = {
|
|
|
555
576
|
readonly teardownErrors: readonly TeardownError[];
|
|
556
577
|
readonly uptimeMs: number;
|
|
557
578
|
};
|
|
558
|
-
type StartOptions
|
|
579
|
+
type StartOptions = {
|
|
559
580
|
/**
|
|
560
581
|
* The environment the graph is configured from, provided to it as the `Env`
|
|
561
582
|
* port and read for the kernel's own `PROBE_PORT`. Defaults to
|
|
562
583
|
* `process.env`.
|
|
563
584
|
*/
|
|
564
585
|
readonly env?: Environment;
|
|
565
|
-
/**
|
|
566
|
-
* A module forked around **every unit** — a unit being one bounded piece of
|
|
567
|
-
* work, whatever the transport calls it: an HTTP request, a Temporal
|
|
568
|
-
* activity, an AMQP delivery. Built as the unit opens, torn down as it
|
|
569
|
-
* closes — while the unit's ambient record is still open — reading anything
|
|
570
|
-
* the application context carries.
|
|
571
|
-
*
|
|
572
|
-
* A failing unit finaliser is reported as a `teardownError` event and never
|
|
573
|
-
* in `ExitReport.teardownErrors`. With this option the unit's work runs only
|
|
574
|
-
* once the fork is built, so a runtime that subscribes to an event from
|
|
575
|
-
* inside its work must be ready for it to have already fired.
|
|
576
|
-
*/
|
|
577
|
-
readonly unit?: Module<UnitX, never, UnitNeeds>;
|
|
578
586
|
readonly clock?: Clock;
|
|
579
587
|
readonly signals?: boolean;
|
|
580
588
|
/**
|
|
@@ -627,15 +635,18 @@ type RunningApp<E, Info = never> = {
|
|
|
627
635
|
/**
|
|
628
636
|
* The phantom marker `start`, `runMain` and `Boot` all intersect onto their
|
|
629
637
|
* `module` parameter: `unknown` — and invisible — when nothing the module
|
|
630
|
-
* needs is unprovided, it exports a runtime
|
|
631
|
-
* runtime resolves
|
|
632
|
-
*
|
|
633
|
-
* not match.
|
|
638
|
+
* needs is unprovided, it exports a runtime and its exports cover what that
|
|
639
|
+
* runtime resolves; a diagnostic otherwise, printed at the call site as the
|
|
640
|
+
* parameter type the argument did not match.
|
|
634
641
|
*
|
|
635
642
|
* `unknown` is the satisfied arm because intersecting it leaves the module
|
|
636
643
|
* type untouched. A runtime's `resolves` is checked against the module's
|
|
637
|
-
* exports only
|
|
638
|
-
*
|
|
644
|
+
* exports only: `RuntimeHost.ctx` is the application context, so a port only
|
|
645
|
+
* a `fork` provides would resolve to nothing there. A `fork`'s own needs are
|
|
646
|
+
* not this marker's business at all — a `fork` module is forked over the
|
|
647
|
+
* application context, so its needs are exactly what a starter's own `needs`
|
|
648
|
+
* channel already asks the composition root to supply, and di's ordinary
|
|
649
|
+
* `UNSATISFIED DEPENDENCIES` gate is what refuses a root that does not.
|
|
639
650
|
*
|
|
640
651
|
* **Unmet needs are checked FIRST, and answered in di's own words rather than
|
|
641
652
|
* a sentence of the kernel's.** A root that forgot `provides: [router]` used
|
|
@@ -654,10 +665,10 @@ type RunningApp<E, Info = never> = {
|
|
|
654
665
|
* name is reached.
|
|
655
666
|
*/
|
|
656
667
|
type PortIdOf<P> = P extends PortInstance<infer Id, infer _Service> ? Id : P;
|
|
657
|
-
type StartGate<X,
|
|
668
|
+
type StartGate<X, N = never> = [Exclude<N, Scope | Env>] extends [never] ? [Extract<X, RuntimeInstance>] extends [never] ? "NO RUNTIME — the module exports no port declared over RuntimePort" : [InstanceType<RuntimeResolvesOf<X>>] extends [X] ? unknown : "UNSATISFIED RUNTIME PORTS — the runtime resolves a port the module does not export" : {
|
|
658
669
|
readonly "UNSATISFIED DEPENDENCIES — nothing provides": PortIdOf<Exclude<N, Scope | Env>>;
|
|
659
670
|
};
|
|
660
|
-
declare const start: <X, E, N
|
|
671
|
+
export declare const start: <X, E, N>(module: Module<X, E, N> & StartGate<X, N>, options?: StartOptions) => RunningApp<E, RuntimeInfoOf<X>>;
|
|
661
672
|
//#endregion
|
|
662
673
|
//#region src/run-main.d.ts
|
|
663
674
|
/**
|
|
@@ -692,6 +703,6 @@ declare const start: <X, E, N, UnitX = never, UnitNeeds = never>(module: Module<
|
|
|
692
703
|
* await runMain(OrderApi);
|
|
693
704
|
* ```
|
|
694
705
|
*/
|
|
695
|
-
declare const runMain: <X, E, N
|
|
706
|
+
export declare const runMain: <X, E, N>(module: Module<X, E, N> & StartGate<X, N>, options?: StartOptions, exit?: (code: number) => void) => Promise<void>;
|
|
696
707
|
//#endregion
|
|
697
|
-
export {
|
|
708
|
+
export type { Attributes, Clock, ComponentHealth, Counter, DrainReport, EventSink, ExitReport, HealthCheck, HealthReport, Histogram, InstrumentationLoader, KernelEvent, Level, LoggerService, MeterService, Operation, Phase, RunUnit, RunningApp, Runtime, RuntimeHost, RuntimeInfoOf, Serving, Settle, Settled, Span, SpanStatusCode, StartGate, StartOptions, TeardownError, TracerService, UnitHost, UnitMeta, UnitRecord, UnitRegistry, UnitWork };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnyPort, Context, Module, PortClass, PortInstance, Scope, ServiceOf } from "@btravstack/di";
|
|
1
|
+
import { AnyPort, Context, DependencyGate, Module, PortClass, PortInstance, Scope, SeedEntry, ServiceOf } from "@btravstack/di";
|
|
2
2
|
import { AsyncResult, Result } from "unthrown";
|
|
3
3
|
import { Env, Environment } from "@btravstack/config";
|
|
4
4
|
//#region src/instrumentation.d.ts
|
|
@@ -31,7 +31,7 @@ declare const Instrumentations_base: import("@btravstack/di").ManyPortClass<"Ins
|
|
|
31
31
|
* without it registers nothing and pays nothing — the Spring Boot starter
|
|
32
32
|
* shape, in one port.
|
|
33
33
|
*/
|
|
34
|
-
declare class Instrumentations extends Instrumentations_base<InstrumentationLoader> {}
|
|
34
|
+
export declare class Instrumentations extends Instrumentations_base<InstrumentationLoader> {}
|
|
35
35
|
//#endregion
|
|
36
36
|
//#region src/health.d.ts
|
|
37
37
|
declare const HealthCheckFailed_base: import("unthrown").TaggedErrorConstructor<"HealthCheckFailed">;
|
|
@@ -40,7 +40,7 @@ declare const HealthCheckFailed_base: import("unthrown").TaggedErrorConstructor<
|
|
|
40
40
|
* a health check that throws is a bug in the check; one that fails is the news
|
|
41
41
|
* `/healthz` exists to carry.
|
|
42
42
|
*/
|
|
43
|
-
declare class HealthCheckFailed extends HealthCheckFailed_base<{
|
|
43
|
+
export declare class HealthCheckFailed extends HealthCheckFailed_base<{
|
|
44
44
|
readonly reason: string;
|
|
45
45
|
}> {}
|
|
46
46
|
/** One contribution: what to call the component, and how to ask it. */
|
|
@@ -57,7 +57,7 @@ declare const HealthChecks_base: import("@btravstack/di").ManyPortClass<"HealthC
|
|
|
57
57
|
* application never composed contributes nothing — no registration call to
|
|
58
58
|
* forget, and no order to get wrong.
|
|
59
59
|
*/
|
|
60
|
-
declare class HealthChecks extends HealthChecks_base<HealthCheck> {}
|
|
60
|
+
export declare class HealthChecks extends HealthChecks_base<HealthCheck> {}
|
|
61
61
|
type ComponentHealth = {
|
|
62
62
|
readonly name: string;
|
|
63
63
|
readonly status: "healthy" | "unhealthy";
|
|
@@ -81,7 +81,7 @@ type HealthReport = {
|
|
|
81
81
|
* escaped, the first would reach the kernel's own `uncaughtException` handler
|
|
82
82
|
* and the second would leave `/healthz` hanging with nothing written.
|
|
83
83
|
*/
|
|
84
|
-
declare const runHealthChecks: (checks: readonly HealthCheck[]) => AsyncResult<HealthReport, never>;
|
|
84
|
+
export declare const runHealthChecks: (checks: readonly HealthCheck[]) => AsyncResult<HealthReport, never>;
|
|
85
85
|
//#endregion
|
|
86
86
|
//#region src/observability.d.ts
|
|
87
87
|
/**
|
|
@@ -91,7 +91,7 @@ declare const runHealthChecks: (checks: readonly HealthCheck[]) => AsyncResult<H
|
|
|
91
91
|
*/
|
|
92
92
|
type Level = "trace" | "debug" | "info" | "warn" | "error" | "fatal";
|
|
93
93
|
/** The levels in order, least severe first — what `isEnabled` compares through. */
|
|
94
|
-
declare const LEVELS: readonly Level[];
|
|
94
|
+
export declare const LEVELS: readonly Level[];
|
|
95
95
|
/**
|
|
96
96
|
* What a line, a span or a measurement carries besides itself: a flat record of
|
|
97
97
|
* scalars.
|
|
@@ -137,9 +137,9 @@ declare const Logger_base: import("@btravstack/di").PortClass<"Logger">;
|
|
|
137
137
|
* problem into an outage. Synchronous `void`, not an `AsyncResult` — thesis 6's
|
|
138
138
|
* one deliberate exemption, since a lost line is not a modeled error.
|
|
139
139
|
*/
|
|
140
|
-
declare class Logger extends Logger_base<LoggerService> {}
|
|
140
|
+
export declare class Logger extends Logger_base<LoggerService> {}
|
|
141
141
|
/** A span's outcome: unset until something says otherwise, then `ok` or `error`. */
|
|
142
|
-
declare const SPAN_STATUS: {
|
|
142
|
+
export declare const SPAN_STATUS: {
|
|
143
143
|
readonly unset: 0;
|
|
144
144
|
readonly ok: 1;
|
|
145
145
|
readonly error: 2;
|
|
@@ -169,7 +169,7 @@ declare const Tracer_base: import("@btravstack/di").PortClass<"Tracer">;
|
|
|
169
169
|
* because a port typed as a vendor's type points the dependency arrow outwards
|
|
170
170
|
* and makes the whole family install that vendor.
|
|
171
171
|
*/
|
|
172
|
-
declare class Tracer extends Tracer_base<TracerService> {}
|
|
172
|
+
export declare class Tracer extends Tracer_base<TracerService> {}
|
|
173
173
|
/** A monotonic count. */
|
|
174
174
|
type Counter = {
|
|
175
175
|
readonly add: (value: number, attributes?: Attributes) => void;
|
|
@@ -196,7 +196,7 @@ type MeterService = {
|
|
|
196
196
|
};
|
|
197
197
|
declare const Meter_base: import("@btravstack/di").PortClass<"Meter">;
|
|
198
198
|
/** The application's meter, as a port. See {@link Tracer} for why it does not name a vendor. */
|
|
199
|
-
declare class Meter extends Meter_base<MeterService> {}
|
|
199
|
+
export declare class Meter extends Meter_base<MeterService> {}
|
|
200
200
|
//#endregion
|
|
201
201
|
//#region src/observation.d.ts
|
|
202
202
|
/**
|
|
@@ -277,9 +277,9 @@ declare const Observers_base: import("@btravstack/di").ManyPortClass<"Observers"
|
|
|
277
277
|
* NOTHING provides is an unmet dependency, at plan time and in `Needs` alike.
|
|
278
278
|
* Several no-ops in one graph cost a call each and nothing else.
|
|
279
279
|
*/
|
|
280
|
-
declare class Observers extends Observers_base<(operation: Operation) => Settle> {}
|
|
280
|
+
export declare class Observers extends Observers_base<(operation: Operation) => Settle> {}
|
|
281
281
|
/** The no-op member every reader of {@link Observers} contributes, so the set is never empty. */
|
|
282
|
-
declare const noObserver: () => Settle;
|
|
282
|
+
export declare const noObserver: () => Settle;
|
|
283
283
|
/**
|
|
284
284
|
* Run every observer around one operation, and hand back the one finisher that
|
|
285
285
|
* settles them all.
|
|
@@ -291,14 +291,14 @@ declare const noObserver: () => Settle;
|
|
|
291
291
|
* `tapFailure` on the same chain, or a retry, is exactly the shape that fires
|
|
292
292
|
* twice and doubles a failure count.
|
|
293
293
|
*/
|
|
294
|
-
declare const observe: (observers: readonly ((operation: Operation) => Settle)[], operation: Operation) => Settle;
|
|
294
|
+
export declare const observe: (observers: readonly ((operation: Operation) => Settle)[], operation: Operation) => Settle;
|
|
295
295
|
//#endregion
|
|
296
296
|
//#region src/clock.d.ts
|
|
297
297
|
type Clock = {
|
|
298
298
|
readonly now: () => number;
|
|
299
299
|
readonly sleep: (ms: number, signal?: AbortSignal) => AsyncResult<void, never>;
|
|
300
300
|
};
|
|
301
|
-
declare const systemClock: Clock;
|
|
301
|
+
export declare const systemClock: Clock;
|
|
302
302
|
//#endregion
|
|
303
303
|
//#region src/units.d.ts
|
|
304
304
|
/**
|
|
@@ -317,7 +317,7 @@ type UnitRecord = {
|
|
|
317
317
|
readonly tenantId: string | undefined;
|
|
318
318
|
readonly signal: AbortSignal;
|
|
319
319
|
};
|
|
320
|
-
declare const currentUnit: () => UnitRecord | undefined;
|
|
320
|
+
export declare const currentUnit: () => UnitRecord | undefined;
|
|
321
321
|
/**
|
|
322
322
|
* What a runtime says about one piece of work as it submits it. `kind` is the
|
|
323
323
|
* category (`"http"`, `"tick"`, `"job"`); `id` identifies **this** unit.
|
|
@@ -350,7 +350,7 @@ type UnitRegistry = {
|
|
|
350
350
|
//#endregion
|
|
351
351
|
//#region src/runtime.d.ts
|
|
352
352
|
declare const RuntimeStartFailed_base: import("unthrown").TaggedErrorConstructor<"RuntimeStartFailed">;
|
|
353
|
-
declare class RuntimeStartFailed extends RuntimeStartFailed_base<{
|
|
353
|
+
export declare class RuntimeStartFailed extends RuntimeStartFailed_base<{
|
|
354
354
|
readonly runtime: string;
|
|
355
355
|
readonly cause: unknown;
|
|
356
356
|
}> {
|
|
@@ -372,11 +372,28 @@ declare class RuntimeStartFailed extends RuntimeStartFailed_base<{
|
|
|
372
372
|
* `UnitMeta.id` must be unique per unit unless a `traceId` is supplied — see
|
|
373
373
|
* {@link UnitMeta}.
|
|
374
374
|
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
375
|
+
* A runtime forks the unit's scope itself, through `UnitHost.fork`, at the
|
|
376
|
+
* moment it holds the unit's input; the kernel closes that scope when the
|
|
377
|
+
* unit settles, after the response is flushed. Work that subscribes to an
|
|
378
|
+
* event after a `fork` must first check whether it already fired.
|
|
378
379
|
*/
|
|
379
|
-
type RunUnit<Resolves extends AnyPort> = <T, E>(meta: UnitMeta, work: (
|
|
380
|
+
type RunUnit<Resolves extends AnyPort> = <T, E>(meta: UnitMeta, work: (unit: UnitHost<Resolves>, signal: AbortSignal) => ReturnType<UnitWork<T, E>>) => AsyncResult<T, E>;
|
|
381
|
+
/**
|
|
382
|
+
* What the kernel hands a unit's work: the application context, and the one
|
|
383
|
+
* way to open the unit's own scope.
|
|
384
|
+
*
|
|
385
|
+
* `fork` builds `module` over the application context plus `seed` and hands
|
|
386
|
+
* the forked context back. The scope is torn down when the unit closes —
|
|
387
|
+
* inside the registry's unit, so the unit is not counted closed until its
|
|
388
|
+
* finalisers have run, and inside the unit's ambient record, so a teardown
|
|
389
|
+
* log line carries the unit's ids. A construction failure rides the unit's
|
|
390
|
+
* defect path. A unit forks once; a second call is a defect, and so is a call
|
|
391
|
+
* made after the unit has settled — nothing awaits that scope's teardown.
|
|
392
|
+
*/
|
|
393
|
+
type UnitHost<Resolves extends AnyPort> = {
|
|
394
|
+
readonly ctx: Context<InstanceType<Resolves>>;
|
|
395
|
+
readonly fork: <UnitX, N, Seeded extends AnyPort = never>(module: Module<UnitX, never, N> & DependencyGate<Exclude<N, InstanceType<Resolves> | InstanceType<Seeded> | Scope>>, seed: readonly SeedEntry<Seeded>[]) => AsyncResult<Context<InstanceType<Resolves> | UnitX | InstanceType<Seeded>>, never>;
|
|
396
|
+
};
|
|
380
397
|
/**
|
|
381
398
|
* What a runtime is handed at `start`: the application services **and** the
|
|
382
399
|
* kernel's {@link RunUnit}. Handing it a bare `Context` would leave every
|
|
@@ -388,8 +405,8 @@ type RunUnit<Resolves extends AnyPort> = <T, E>(meta: UnitMeta, work: (ctx: Cont
|
|
|
388
405
|
* {@link RunUnit}), and `UnitMeta.id` must be unique per unit unless a
|
|
389
406
|
* `traceId` is supplied (see {@link UnitMeta}).
|
|
390
407
|
*
|
|
391
|
-
* `ctx` is the **application** context: a port a
|
|
392
|
-
*
|
|
408
|
+
* `ctx` is the **application** context: a port a unit's `fork` module provides
|
|
409
|
+
* exists only in the `Context` `fork` hands back, so a runtime naming it in
|
|
393
410
|
* `resolves` is rejected at `start`'s call site.
|
|
394
411
|
*/
|
|
395
412
|
type RuntimeHost<Resolves extends AnyPort> = {
|
|
@@ -425,13 +442,17 @@ type Runtime<Resolves extends AnyPort = never, Info = never> = {
|
|
|
425
442
|
* process boots exactly one, while each carries its own `Resolves`/`Info` in
|
|
426
443
|
* the type.
|
|
427
444
|
*/
|
|
428
|
-
declare const RuntimePort: PortClass<"Runtime">;
|
|
445
|
+
export declare const RuntimePort: PortClass<"Runtime">;
|
|
429
446
|
/** The instance type every runtime port shares — `Extract` this from a module's exports to find its runtime. */
|
|
430
447
|
type RuntimeInstance = InstanceType<PortClass<"Runtime">>;
|
|
431
448
|
/** The `Runtime<Resolves, Info>` a module exports, or `never` when it exports none. */
|
|
432
449
|
type RuntimeOf<X> = ServiceOf<Extract<X, RuntimeInstance>>;
|
|
433
|
-
type RuntimeResolvesOf<X> = RuntimeOf<X> extends
|
|
434
|
-
|
|
450
|
+
type RuntimeResolvesOf<X> = RuntimeOf<X> extends {
|
|
451
|
+
readonly resolves: readonly (infer Resolves extends AnyPort)[];
|
|
452
|
+
} ? Resolves : never;
|
|
453
|
+
type RuntimeInfoOf<X> = RuntimeOf<X> extends {
|
|
454
|
+
readonly start: (host: never) => AsyncResult<Serving<infer Info>, RuntimeStartFailed>;
|
|
455
|
+
} ? Info : never;
|
|
435
456
|
/**
|
|
436
457
|
* The trace id inside a W3C `traceparent` header, and nothing else of it.
|
|
437
458
|
*
|
|
@@ -459,7 +480,7 @@ type RuntimeInfoOf<X> = RuntimeOf<X> extends Runtime<AnyPort, infer Info> ? Info
|
|
|
459
480
|
* const traceId = typeof parent === "string" ? traceIdOfTraceparent(parent) : undefined;
|
|
460
481
|
* ```
|
|
461
482
|
*/
|
|
462
|
-
declare const traceIdOfTraceparent: (header: string) => string | undefined;
|
|
483
|
+
export declare const traceIdOfTraceparent: (header: string) => string | undefined;
|
|
463
484
|
/**
|
|
464
485
|
* `running`, but no later than the kernel's drain deadline — the primitive a
|
|
465
486
|
* `Serving.drain` needs when the work it awaits settles on somebody else's
|
|
@@ -479,7 +500,7 @@ declare const traceIdOfTraceparent: (header: string) => string | undefined;
|
|
|
479
500
|
* (`drain.ts` uses `clock.sleep` for exactly that, so a fake clock can control
|
|
480
501
|
* it) — do not fold the two together.
|
|
481
502
|
*/
|
|
482
|
-
declare const releasedBy: (signal: AbortSignal, running: AsyncResult<void, never>) => AsyncResult<void, never>;
|
|
503
|
+
export declare const releasedBy: (signal: AbortSignal, running: AsyncResult<void, never>) => AsyncResult<void, never>;
|
|
483
504
|
//#endregion
|
|
484
505
|
//#region src/drain.d.ts
|
|
485
506
|
type DrainReport = {
|
|
@@ -539,7 +560,7 @@ type KernelEvent = {
|
|
|
539
560
|
readonly cause: unknown;
|
|
540
561
|
};
|
|
541
562
|
type EventSink = (event: KernelEvent) => void;
|
|
542
|
-
declare const stderrSink: EventSink;
|
|
563
|
+
export declare const stderrSink: EventSink;
|
|
543
564
|
//#endregion
|
|
544
565
|
//#region src/phase.d.ts
|
|
545
566
|
type Phase = "building" | "starting" | "serving" | "draining" | "stopping" | "exited";
|
|
@@ -555,26 +576,13 @@ type ExitReport = {
|
|
|
555
576
|
readonly teardownErrors: readonly TeardownError[];
|
|
556
577
|
readonly uptimeMs: number;
|
|
557
578
|
};
|
|
558
|
-
type StartOptions
|
|
579
|
+
type StartOptions = {
|
|
559
580
|
/**
|
|
560
581
|
* The environment the graph is configured from, provided to it as the `Env`
|
|
561
582
|
* port and read for the kernel's own `PROBE_PORT`. Defaults to
|
|
562
583
|
* `process.env`.
|
|
563
584
|
*/
|
|
564
585
|
readonly env?: Environment;
|
|
565
|
-
/**
|
|
566
|
-
* A module forked around **every unit** — a unit being one bounded piece of
|
|
567
|
-
* work, whatever the transport calls it: an HTTP request, a Temporal
|
|
568
|
-
* activity, an AMQP delivery. Built as the unit opens, torn down as it
|
|
569
|
-
* closes — while the unit's ambient record is still open — reading anything
|
|
570
|
-
* the application context carries.
|
|
571
|
-
*
|
|
572
|
-
* A failing unit finaliser is reported as a `teardownError` event and never
|
|
573
|
-
* in `ExitReport.teardownErrors`. With this option the unit's work runs only
|
|
574
|
-
* once the fork is built, so a runtime that subscribes to an event from
|
|
575
|
-
* inside its work must be ready for it to have already fired.
|
|
576
|
-
*/
|
|
577
|
-
readonly unit?: Module<UnitX, never, UnitNeeds>;
|
|
578
586
|
readonly clock?: Clock;
|
|
579
587
|
readonly signals?: boolean;
|
|
580
588
|
/**
|
|
@@ -627,15 +635,18 @@ type RunningApp<E, Info = never> = {
|
|
|
627
635
|
/**
|
|
628
636
|
* The phantom marker `start`, `runMain` and `Boot` all intersect onto their
|
|
629
637
|
* `module` parameter: `unknown` — and invisible — when nothing the module
|
|
630
|
-
* needs is unprovided, it exports a runtime
|
|
631
|
-
* runtime resolves
|
|
632
|
-
*
|
|
633
|
-
* not match.
|
|
638
|
+
* needs is unprovided, it exports a runtime and its exports cover what that
|
|
639
|
+
* runtime resolves; a diagnostic otherwise, printed at the call site as the
|
|
640
|
+
* parameter type the argument did not match.
|
|
634
641
|
*
|
|
635
642
|
* `unknown` is the satisfied arm because intersecting it leaves the module
|
|
636
643
|
* type untouched. A runtime's `resolves` is checked against the module's
|
|
637
|
-
* exports only
|
|
638
|
-
*
|
|
644
|
+
* exports only: `RuntimeHost.ctx` is the application context, so a port only
|
|
645
|
+
* a `fork` provides would resolve to nothing there. A `fork`'s own needs are
|
|
646
|
+
* not this marker's business at all — a `fork` module is forked over the
|
|
647
|
+
* application context, so its needs are exactly what a starter's own `needs`
|
|
648
|
+
* channel already asks the composition root to supply, and di's ordinary
|
|
649
|
+
* `UNSATISFIED DEPENDENCIES` gate is what refuses a root that does not.
|
|
639
650
|
*
|
|
640
651
|
* **Unmet needs are checked FIRST, and answered in di's own words rather than
|
|
641
652
|
* a sentence of the kernel's.** A root that forgot `provides: [router]` used
|
|
@@ -654,10 +665,10 @@ type RunningApp<E, Info = never> = {
|
|
|
654
665
|
* name is reached.
|
|
655
666
|
*/
|
|
656
667
|
type PortIdOf<P> = P extends PortInstance<infer Id, infer _Service> ? Id : P;
|
|
657
|
-
type StartGate<X,
|
|
668
|
+
type StartGate<X, N = never> = [Exclude<N, Scope | Env>] extends [never] ? [Extract<X, RuntimeInstance>] extends [never] ? "NO RUNTIME — the module exports no port declared over RuntimePort" : [InstanceType<RuntimeResolvesOf<X>>] extends [X] ? unknown : "UNSATISFIED RUNTIME PORTS — the runtime resolves a port the module does not export" : {
|
|
658
669
|
readonly "UNSATISFIED DEPENDENCIES — nothing provides": PortIdOf<Exclude<N, Scope | Env>>;
|
|
659
670
|
};
|
|
660
|
-
declare const start: <X, E, N
|
|
671
|
+
export declare const start: <X, E, N>(module: Module<X, E, N> & StartGate<X, N>, options?: StartOptions) => RunningApp<E, RuntimeInfoOf<X>>;
|
|
661
672
|
//#endregion
|
|
662
673
|
//#region src/run-main.d.ts
|
|
663
674
|
/**
|
|
@@ -692,6 +703,6 @@ declare const start: <X, E, N, UnitX = never, UnitNeeds = never>(module: Module<
|
|
|
692
703
|
* await runMain(OrderApi);
|
|
693
704
|
* ```
|
|
694
705
|
*/
|
|
695
|
-
declare const runMain: <X, E, N
|
|
706
|
+
export declare const runMain: <X, E, N>(module: Module<X, E, N> & StartGate<X, N>, options?: StartOptions, exit?: (code: number) => void) => Promise<void>;
|
|
696
707
|
//#endregion
|
|
697
|
-
export {
|
|
708
|
+
export type { Attributes, Clock, ComponentHealth, Counter, DrainReport, EventSink, ExitReport, HealthCheck, HealthReport, Histogram, InstrumentationLoader, KernelEvent, Level, LoggerService, MeterService, Operation, Phase, RunUnit, RunningApp, Runtime, RuntimeHost, RuntimeInfoOf, Serving, Settle, Settled, Span, SpanStatusCode, StartGate, StartOptions, TeardownError, TracerService, UnitHost, UnitMeta, UnitRecord, UnitRegistry, UnitWork };
|
package/dist/index.mjs
CHANGED
|
@@ -612,15 +612,43 @@ const start = (module, options = {}) => {
|
|
|
612
612
|
runtimeName = runtime.name;
|
|
613
613
|
healthChecks = ctx.get(HealthChecks);
|
|
614
614
|
const runtimeCtx = ctx;
|
|
615
|
-
const unit = options.unit;
|
|
616
615
|
const run = (meta, work) => registry.run(meta, (signal) => {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
616
|
+
const settled = Promise.withResolvers();
|
|
617
|
+
let closing;
|
|
618
|
+
let hasSettled = false;
|
|
619
|
+
const fork = (module, seed) => {
|
|
620
|
+
if (hasSettled) return fromSafePromise(Promise.reject(/* @__PURE__ */ new Error("a unit forks after it has already settled")));
|
|
621
|
+
if (closing !== void 0) return fromSafePromise(Promise.reject(/* @__PURE__ */ new Error("a unit forks its scope once")));
|
|
622
|
+
const ready = Promise.withResolvers();
|
|
623
|
+
closing = Module.forkScope(ctx, module, (forked) => {
|
|
624
|
+
ready.resolve(forked);
|
|
625
|
+
return fromSafePromise(settled.promise);
|
|
626
|
+
}, {
|
|
627
|
+
seed,
|
|
628
|
+
onTeardownError: (port, cause) => emit({
|
|
629
|
+
type: "teardownError",
|
|
630
|
+
port,
|
|
631
|
+
cause
|
|
632
|
+
})
|
|
633
|
+
}).recoverDefect((cause) => {
|
|
634
|
+
ready.reject(cause);
|
|
635
|
+
return Ok();
|
|
636
|
+
}).get();
|
|
637
|
+
return fromSafePromise(ready.promise);
|
|
638
|
+
};
|
|
639
|
+
const outcome = (async () => {
|
|
640
|
+
try {
|
|
641
|
+
return await work({
|
|
642
|
+
ctx: runtimeCtx,
|
|
643
|
+
fork
|
|
644
|
+
}, signal);
|
|
645
|
+
} finally {
|
|
646
|
+
hasSettled = true;
|
|
647
|
+
settled.resolve();
|
|
648
|
+
if (closing !== void 0) await closing;
|
|
649
|
+
}
|
|
650
|
+
})();
|
|
651
|
+
return fromSafePromise(outcome).flatMap((result) => result);
|
|
624
652
|
});
|
|
625
653
|
const host = {
|
|
626
654
|
ctx: runtimeCtx,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btravstack/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.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,21 +45,21 @@
|
|
|
45
45
|
"./package.json": "./package.json"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@btravstack/tsconfig": "0.
|
|
49
|
-
"@types/node": "26.4.
|
|
50
|
-
"@unthrown/vitest": "5.
|
|
48
|
+
"@btravstack/tsconfig": "0.4.0",
|
|
49
|
+
"@types/node": "26.4.1",
|
|
50
|
+
"@unthrown/vitest": "5.8.0",
|
|
51
51
|
"@vitest/coverage-v8": "4.1.11",
|
|
52
|
-
"tsdown": "0.
|
|
52
|
+
"tsdown": "0.23.0",
|
|
53
53
|
"typescript": "7.0.2",
|
|
54
|
-
"unthrown": "5.
|
|
54
|
+
"unthrown": "5.8.0",
|
|
55
55
|
"vitest": "4.1.11",
|
|
56
|
-
"@btravstack/config": "0.
|
|
57
|
-
"@btravstack/di": "0.
|
|
56
|
+
"@btravstack/config": "0.14.0",
|
|
57
|
+
"@btravstack/di": "0.14.0"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"unthrown": "^5.0.0",
|
|
61
|
-
"@btravstack/config": "^0.
|
|
62
|
-
"@btravstack/di": "^0.
|
|
61
|
+
"@btravstack/config": "^0.14.0",
|
|
62
|
+
"@btravstack/di": "^0.14.0"
|
|
63
63
|
},
|
|
64
64
|
"engines": {
|
|
65
65
|
"node": ">=22"
|