@semiont/core 0.5.23 → 0.5.24
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/chunk-3WTQZOGO.js +143 -0
- package/dist/chunk-3WTQZOGO.js.map +1 -0
- package/dist/chunk-4JTZMWZB.js +330 -0
- package/dist/chunk-4JTZMWZB.js.map +1 -0
- package/dist/chunk-XQTWEBJ5.js +293 -0
- package/dist/chunk-XQTWEBJ5.js.map +1 -0
- package/dist/config/node-config-loader.d.ts +7 -7
- package/dist/config/node-config-loader.js +1 -288
- package/dist/config/node-config-loader.js.map +1 -1
- package/dist/index.d.ts +22 -4
- package/dist/index.js +20 -618
- package/dist/index.js.map +1 -1
- package/dist/testing/axioms.d.ts +180 -0
- package/dist/testing/axioms.js +365 -0
- package/dist/testing/axioms.js.map +1 -0
- package/dist/testing.d.ts +16 -178
- package/dist/testing.js +2 -761
- package/dist/testing.js.map +1 -1
- package/package.json +6 -1
package/dist/testing.d.ts
CHANGED
|
@@ -1,71 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import * as fc from 'fast-check';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Executable enforcement of the StateUnit pattern — the runtime twin of
|
|
7
|
-
* `packages/sdk/docs/STATE-UNITS.md` and the ledger in
|
|
8
|
-
* `.plans/STATE-UNIT-AXIOMS.md`. The `StateUnit` interface's own comment notes
|
|
9
|
-
* the pattern is convention; this file makes it executable.
|
|
10
|
-
*
|
|
11
|
-
* `assertStateUnitAxioms(spec)` runs every applicable axiom against a factory in
|
|
12
|
-
* one shot, throwing a labeled Error on the first violation (the axiom id is in
|
|
13
|
-
* the message). It is framework-agnostic on purpose — only `rxjs` + `fast-check`,
|
|
14
|
-
* no `vitest` — so it ships through `@semiont/core/testing` and any package's test
|
|
15
|
-
* runner can invoke it from a single `it(...)` per state unit. It lives in core
|
|
16
|
-
* (not sdk) so even packages below sdk (e.g. `http-transport`) can use it without
|
|
17
|
-
* a dependency cycle.
|
|
18
|
-
*
|
|
19
|
-
* Axioms (random-input dimension; fast-check):
|
|
20
|
-
* A5 dispose() is idempotent and total (n ∈ [1,20] calls never throw)
|
|
21
|
-
* A5b post-dispose inertness — every public method is a no-op after dispose
|
|
22
|
-
* A6 every pre-dispose subscriber (k ∈ [1,10]) sees `complete` on dispose
|
|
23
|
-
* X3-runtime instance isolation — driving one instance never moves another's surfaces
|
|
24
|
-
* Structural assertions (single-shot):
|
|
25
|
-
* A1 plain-object identity (no class instance)
|
|
26
|
-
* X1 no raw Subject on the public surface
|
|
27
|
-
* A7-passed disposing the unit must NOT dispose an injected dependency
|
|
28
|
-
* A7-owned disposing the unit MUST dispose its internally-constructed children
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* A disposable stand-in for an injected dependency. Pass one as a unit's
|
|
33
|
-
* constructor arg, then list it in `setup().passedIn` so A7-passed can assert
|
|
34
|
-
* the unit never disposed it. Counts calls so A7-passed also holds under the
|
|
35
|
-
* repeated-dispose stress of A5.
|
|
36
|
-
*/
|
|
37
|
-
interface DisposeProbe extends StateUnit {
|
|
38
|
-
readonly disposeCount: number;
|
|
39
|
-
}
|
|
40
|
-
declare function disposeProbe(): DisposeProbe;
|
|
41
|
-
type SetupResult<T extends StateUnit> = T | {
|
|
42
|
-
unit: T;
|
|
43
|
-
passedIn?: readonly DisposeProbe[];
|
|
44
|
-
teardown?: () => void;
|
|
45
|
-
};
|
|
46
|
-
interface StateUnitAxiomSpec<T extends StateUnit> {
|
|
47
|
-
/**
|
|
48
|
-
* Build a FRESH unit. Called many times (fast-check re-runs), so it must
|
|
49
|
-
* return an independent instance each call. Return the bare unit, or an object
|
|
50
|
-
* carrying the injected `passedIn` probes (A7-passed) and a `teardown` to
|
|
51
|
-
* release per-instance resources (e.g. a mock bus).
|
|
52
|
-
*/
|
|
53
|
-
setup: () => SetupResult<T>;
|
|
54
|
-
/** Owned public Observables — Subjects the unit completes on dispose (A6, X3, post-dispose inertness). */
|
|
55
|
-
surfaces?: (unit: T) => readonly Observable<unknown>[];
|
|
56
|
-
/** Public input methods as zero-arg callers (A5b post-dispose, X3 drive). */
|
|
57
|
-
invocations?: (unit: T) => readonly (() => unknown)[];
|
|
58
|
-
/** Surfaces of internally-constructed children — must complete when the outer disposes (A7-owned). */
|
|
59
|
-
ownedChildSurfaces?: (unit: T) => readonly Observable<unknown>[];
|
|
60
|
-
/** fast-check run budget per property (default 30). */
|
|
61
|
-
numRuns?: number;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Run every applicable axiom against `spec`. Throws a labeled Error on the first
|
|
65
|
-
* violation. Axioms whose accessors are omitted are skipped (e.g. A7-passed
|
|
66
|
-
* runs only when `setup` returns `passedIn`; A6 only when `surfaces` is given).
|
|
67
|
-
*/
|
|
68
|
-
declare function assertStateUnitAxioms<T extends StateUnit>(spec: StateUnitAxiomSpec<T>): void;
|
|
1
|
+
import { BehaviorSubject, Observable } from 'rxjs';
|
|
2
|
+
import { ITransport, BaseUrl, ConnectionState, SemiontError, BusOperationKey, EventMap, ResourceId, EventBus } from '@semiont/core';
|
|
69
3
|
|
|
70
4
|
/**
|
|
71
5
|
* FaultyTransport — a seeded, scriptable `ITransport` simulator for the
|
|
@@ -111,6 +45,18 @@ interface RequestLogEntry {
|
|
|
111
45
|
* the same key are the same logical request re-issued.
|
|
112
46
|
*/
|
|
113
47
|
retryKey: string;
|
|
48
|
+
/**
|
|
49
|
+
* The payload as emitted — envelope, options, params, `correlationId` and
|
|
50
|
+
* all. This is the surface for "assert what my orchestrator actually SENT"
|
|
51
|
+
* (SDK-TESTING-DOUBLE gap 6): without it every consumer harness re-invented
|
|
52
|
+
* a per-channel `transport.on(...)` wire recorder alongside this log.
|
|
53
|
+
*
|
|
54
|
+
* SHALLOW snapshot: the top level is copied at emit time, so a caller that
|
|
55
|
+
* mutates its own payload object afterwards cannot rewrite history. Nested
|
|
56
|
+
* objects are shared by reference — deep-freeze is not worth the cost in a
|
|
57
|
+
* double, and no in-repo caller mutates nested request payloads.
|
|
58
|
+
*/
|
|
59
|
+
payload: Record<string, unknown>;
|
|
114
60
|
}
|
|
115
61
|
interface FaultyTransportConfig {
|
|
116
62
|
/**
|
|
@@ -169,113 +115,5 @@ declare class FaultyTransport implements ITransport {
|
|
|
169
115
|
dispose(): void;
|
|
170
116
|
}
|
|
171
117
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
* `.plans/LIVENESS-AXIOMS.md`, and the composition-level sibling of
|
|
175
|
-
* `assertStateUnitAxioms` (state-unit-axioms.ts). Where the StateUnit axioms
|
|
176
|
-
* make *per-unit* wrongness mechanically detectable, these make *silence*
|
|
177
|
-
* detectable: every existing enforcement tier is safety (nothing wrong is
|
|
178
|
-
* delivered); these assert liveness (something is eventually delivered).
|
|
179
|
-
*
|
|
180
|
-
* Axioms (fault-schedule dimension; fast-check):
|
|
181
|
-
* L1 Subscriber liveness — every output emits next|error within the bound,
|
|
182
|
-
* under any fault schedule. Error is a permitted outcome; the forbidden
|
|
183
|
-
* fourth state is pending-forever.
|
|
184
|
-
* L2 Request settlement — every awaited path settles within the bound;
|
|
185
|
-
* re-issues per logical request stay within the retry budget (B14: one);
|
|
186
|
-
* a faulted request must be re-issued or surfaced, never swallowed.
|
|
187
|
-
* L3 Delivery across lifecycle transitions — every event written to a live
|
|
188
|
-
* connection reaches the output exactly once, wherever a client-initiated
|
|
189
|
-
* transition (handover / reconnect / scope change) lands. Retirement is
|
|
190
|
-
* by drain, never by abort (TRANSPORT-HTTP.md, Abort discipline).
|
|
191
|
-
*
|
|
192
|
-
* Framework-agnostic on purpose — only `rxjs` + `fast-check`, no `vitest` — so
|
|
193
|
-
* it ships through `@semiont/core/testing` and any package's test runner can
|
|
194
|
-
* invoke it. Deterministic virtual time: properties pass a small explicit
|
|
195
|
-
* `timeoutMs` to `busRequest`; no `Date.now`, no 30 s real waits.
|
|
196
|
-
*/
|
|
197
|
-
|
|
198
|
-
/** What one fresh run of the composition exposes to the axioms. */
|
|
199
|
-
interface LivenessScenario {
|
|
200
|
-
/**
|
|
201
|
-
* Live-query-shaped outputs. The harness subscribes each one; every
|
|
202
|
-
* subscription must see `next` or `error` within the bound (L1).
|
|
203
|
-
*/
|
|
204
|
-
outputs: readonly Observable<unknown>[];
|
|
205
|
-
/**
|
|
206
|
-
* Awaited paths. Each promise must settle — resolve or reject — within the
|
|
207
|
-
* bound (L2). Rejections are fine; pending-forever is the violation.
|
|
208
|
-
*/
|
|
209
|
-
settlements?: readonly Promise<unknown>[];
|
|
210
|
-
teardown?: () => void;
|
|
211
|
-
}
|
|
212
|
-
interface LivenessAxiomSpec {
|
|
213
|
-
/** Build a FRESH composition wired to the given transport. Called per run. */
|
|
214
|
-
setup: (transport: FaultyTransport) => LivenessScenario | Promise<LivenessScenario>;
|
|
215
|
-
/**
|
|
216
|
-
* The timeoutMs the scenario passes to `busRequest` — the bound is derived
|
|
217
|
-
* from it: (timeoutMs × (1 + retryBudget) + Σdelays) × slackFactor.
|
|
218
|
-
*/
|
|
219
|
-
timeoutMs: number;
|
|
220
|
-
/** Max sanctioned re-issues per logical request (B14 budget). Default 1. */
|
|
221
|
-
retryBudget?: number;
|
|
222
|
-
/** Override the generated fault schedules (teeth tests pin one). */
|
|
223
|
-
scheduleArb?: fc.Arbitrary<readonly FaultAction[]>;
|
|
224
|
-
/** Passed through to FaultyTransport (reply synthesis). */
|
|
225
|
-
makeResponse?: (operation: string, payload: Record<string, unknown>) => unknown;
|
|
226
|
-
/** fast-check run budget (default 25 — CI-fast; crank locally). */
|
|
227
|
-
numRuns?: number;
|
|
228
|
-
/** Real-scheduler jitter headroom on the bound (default 4×). */
|
|
229
|
-
slackFactor?: number;
|
|
230
|
-
}
|
|
231
|
-
/** The five wire behaviors, uniformly weighted; delays stay small (≤5 ms). */
|
|
232
|
-
declare function arbFaultAction(): fc.Arbitrary<FaultAction>;
|
|
233
|
-
declare function arbFaultSchedule(maxLength?: number): fc.Arbitrary<readonly FaultAction[]>;
|
|
234
|
-
/**
|
|
235
|
-
* Run L1 + L2 against `spec` across generated fault schedules. Throws a
|
|
236
|
-
* labeled Error (`L1: …` / `L2: …`) on the first violation.
|
|
237
|
-
*/
|
|
238
|
-
declare function assertLivenessAxioms(spec: LivenessAxiomSpec): Promise<void>;
|
|
239
|
-
/**
|
|
240
|
-
* A connection-stream-shaped subject: something that accepts writes to the
|
|
241
|
-
* live connection, can be told to transition (handover / reconnect / scope
|
|
242
|
-
* change), and exposes the subscriber-facing output. P3 adapts the real
|
|
243
|
-
* actor's mock-connection harness to this shape; the teeth tests drive
|
|
244
|
-
* reconstructed pre-fix doubles.
|
|
245
|
-
*/
|
|
246
|
-
interface DeliverySubject {
|
|
247
|
-
/** Write the event with this id to the currently-live connection. */
|
|
248
|
-
write: (eventId: string) => void;
|
|
249
|
-
/** Client-initiated lifecycle transition. */
|
|
250
|
-
transition: () => void | Promise<void>;
|
|
251
|
-
/** Subscriber-facing output; each emission is a delivered event id. */
|
|
252
|
-
output$: Observable<string>;
|
|
253
|
-
/**
|
|
254
|
-
* Drain pending asynchronous delivery at end of sequence (a live connection
|
|
255
|
-
* eventually flushes). Default: one macrotask tick.
|
|
256
|
-
*/
|
|
257
|
-
settle?: () => Promise<void>;
|
|
258
|
-
teardown?: () => void;
|
|
259
|
-
}
|
|
260
|
-
type DeliveryOp = 'write' | 'transition';
|
|
261
|
-
interface DeliveryAxiomSpec {
|
|
262
|
-
/** Build a FRESH subject. Called per run. */
|
|
263
|
-
setup: () => DeliverySubject;
|
|
264
|
-
/** Override the generated op sequences (teeth tests pin one). */
|
|
265
|
-
opsArb?: fc.Arbitrary<readonly DeliveryOp[]>;
|
|
266
|
-
/** Max generated sequence length (default 12). */
|
|
267
|
-
maxOps?: number;
|
|
268
|
-
/** fast-check run budget (default 50 — these runs are cheap). */
|
|
269
|
-
numRuns?: number;
|
|
270
|
-
}
|
|
271
|
-
declare function arbDeliveryOps(maxOps?: number): fc.Arbitrary<readonly DeliveryOp[]>;
|
|
272
|
-
/**
|
|
273
|
-
* Run L3 against `spec` across generated write/transition interleavings.
|
|
274
|
-
* Throws a labeled Error (`L3: …`) on the first violation: an event written
|
|
275
|
-
* to a live connection delivered zero times (lost — retired by abort instead
|
|
276
|
-
* of drain) or more than once (duplicate).
|
|
277
|
-
*/
|
|
278
|
-
declare function assertExactlyOnceDelivery(spec: DeliveryAxiomSpec): Promise<void>;
|
|
279
|
-
|
|
280
|
-
export { FaultyTransport, arbDeliveryOps, arbFaultAction, arbFaultSchedule, assertExactlyOnceDelivery, assertLivenessAxioms, assertStateUnitAxioms, disposeProbe, retryKeyOf };
|
|
281
|
-
export type { DeliveryAxiomSpec, DeliveryOp, DeliverySubject, DisposeProbe, FaultAction, FaultyTransportConfig, LivenessAxiomSpec, LivenessScenario, RequestLogEntry, StateUnitAxiomSpec };
|
|
118
|
+
export { FaultyTransport, retryKeyOf };
|
|
119
|
+
export type { FaultAction, FaultyTransportConfig, RequestLogEntry };
|