@demlik/tea 0.14.0 → 0.16.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 +30 -7
- package/dist/agent/index.d.ts +49 -36
- package/dist/agent/index.js +12 -8
- package/dist/chunk-4LPY67E4.js +18 -0
- package/dist/chunk-4LPY67E4.js.map +1 -0
- package/dist/chunk-5XU6ZJO2.js +533 -0
- package/dist/chunk-5XU6ZJO2.js.map +1 -0
- package/dist/{chunk-AQ6ZIMEA.js → chunk-6NG4V5SB.js} +89 -115
- package/dist/chunk-6NG4V5SB.js.map +1 -0
- package/dist/{chunk-HYDWG35Q.js → chunk-7MGXQZPW.js} +11 -9
- package/dist/chunk-7MGXQZPW.js.map +1 -0
- package/dist/{chunk-BLJ2JQSH.js → chunk-BCTEOVOU.js} +3 -3
- package/dist/{chunk-BLJ2JQSH.js.map → chunk-BCTEOVOU.js.map} +1 -1
- package/dist/chunk-CH5KTOEZ.js +710 -0
- package/dist/chunk-CH5KTOEZ.js.map +1 -0
- package/dist/chunk-CIHSHLQX.js +64 -0
- package/dist/chunk-CIHSHLQX.js.map +1 -0
- package/dist/{chunk-Z2L3LSNV.js → chunk-EHUDXAKC.js} +246 -210
- package/dist/chunk-EHUDXAKC.js.map +1 -0
- package/dist/chunk-GOX2CYIM.js +380 -0
- package/dist/chunk-GOX2CYIM.js.map +1 -0
- package/dist/chunk-IVJP3GKJ.js +104 -0
- package/dist/chunk-IVJP3GKJ.js.map +1 -0
- package/dist/{chunk-F7FMAWLA.js → chunk-MVZS5FDM.js} +13 -6
- package/dist/chunk-MVZS5FDM.js.map +1 -0
- package/dist/{chunk-LYLTKJWM.js → chunk-MYNLY3HP.js} +9 -8
- package/dist/chunk-MYNLY3HP.js.map +1 -0
- package/dist/{chunk-I5MQMJDW.js → chunk-NSIAORRY.js} +20 -30
- package/dist/chunk-NSIAORRY.js.map +1 -0
- package/dist/{chunk-MYXFNWAJ.js → chunk-QNGYQMZB.js} +4 -4
- package/dist/chunk-QNGYQMZB.js.map +1 -0
- package/dist/chunk-WT5PBPLB.js +98 -0
- package/dist/chunk-WT5PBPLB.js.map +1 -0
- package/dist/{core-CTzMJ82M.d.ts → core-BbgtiXdg.d.ts} +231 -139
- package/dist/do/index.d.ts +37 -32
- package/dist/do/index.js +21 -14
- package/dist/do/index.js.map +1 -1
- package/dist/{durable-effects-B0-qGQDy.d.ts → durable-effects-7MTK_jnj.d.ts} +1 -1
- package/dist/effect/index.d.ts +151 -0
- package/dist/effect/index.js +98 -0
- package/dist/effect/index.js.map +1 -0
- package/dist/extension/index.d.ts +6 -7
- package/dist/extension/index.js +3 -2
- package/dist/extension/index.js.map +1 -1
- package/dist/flow/index.d.ts +68 -70
- package/dist/flow/index.js +32 -27
- package/dist/flow/index.js.map +1 -1
- package/dist/idempotency/index.d.ts +6 -7
- package/dist/idempotency/index.js +4 -2
- package/dist/{index-DJWIER_3.d.ts → index-7vV8xmsD.d.ts} +1 -1
- package/dist/{index-NjrT3fL2.d.ts → index-Bz5Rh9Ga.d.ts} +19 -96
- package/dist/index-CjFDUBeq.d.ts +207 -0
- package/dist/{index-6A7dB8f6.d.ts → index-CkFYA9Y6.d.ts} +14 -16
- package/dist/{index-B5BZ-_cT.d.ts → index-Cou86-GX.d.ts} +189 -108
- package/dist/{index-TvRb1KVf.d.ts → index-DU6JpQ8G.d.ts} +1 -1
- package/dist/{index-q0hXFeZ0.d.ts → index-Xufl55W8.d.ts} +286 -215
- package/dist/{index-4vZzljCD.d.ts → index-_dOR3xqA.d.ts} +57 -45
- package/dist/index.d.ts +181 -385
- package/dist/index.js +2 -1
- package/dist/jev/index.d.ts +147 -99
- package/dist/jev/index.js +329 -233
- package/dist/jev/index.js.map +1 -1
- package/dist/{machine-CdIcN2Xm.d.ts → machine-BQzTV8On.d.ts} +171 -280
- package/dist/machine-viz/index.d.ts +5 -5
- package/dist/machine-viz/index.js +8 -4
- package/dist/machine-viz/index.js.map +1 -1
- package/dist/mem/index.d.ts +3 -4
- package/dist/mem/index.js +2 -1
- package/dist/mem/index.js.map +1 -1
- package/dist/node/index.d.ts +119 -78
- package/dist/node/index.js +52 -38
- package/dist/node/index.js.map +1 -1
- package/dist/paginate/index.d.ts +27 -33
- package/dist/paginate/index.js +6 -4
- package/dist/parity/index.d.ts +4 -5
- package/dist/parity/index.js +3 -2
- package/dist/parity/index.js.map +1 -1
- package/dist/pbt/index.d.ts +2 -2
- package/dist/pbt/index.js +2 -1
- package/dist/pbt/index.js.map +1 -1
- package/dist/persistence/index.d.ts +6 -7
- package/dist/persistence/index.js +5 -3
- package/dist/promise/index.d.ts +186 -0
- package/dist/promise/index.js +5 -0
- package/dist/promise/index.js.map +1 -0
- package/dist/protocol-ClRZBhHQ.d.ts +53 -0
- package/dist/react/index.d.ts +36 -17
- package/dist/react/index.js +27 -4
- package/dist/react/index.js.map +1 -1
- package/dist/resilience/index.d.ts +63 -455
- package/dist/resilience/index.js +37 -483
- package/dist/resilience/index.js.map +1 -1
- package/dist/{runtime-types-LWDoi943.d.ts → runtime-types-CiVpC0HN.d.ts} +131 -388
- package/dist/testing/index.d.ts +165 -15
- package/dist/testing/index.js +104 -3
- package/dist/testing/index.js.map +1 -1
- package/dist/timing/index.d.ts +25 -22
- package/dist/timing/index.js +4 -3
- package/dist/timing/index.js.map +1 -1
- package/dist/{types-DP3f5NIl.d.ts → types-LxZxGYda.d.ts} +2 -2
- package/dist/work-queue/index.d.ts +5 -6
- package/package.json +18 -5
- package/dist/chunk-AQ6ZIMEA.js.map +0 -1
- package/dist/chunk-F2US5BW6.js +0 -72
- package/dist/chunk-F2US5BW6.js.map +0 -1
- package/dist/chunk-F7FMAWLA.js.map +0 -1
- package/dist/chunk-HUKZQX6U.js +0 -97
- package/dist/chunk-HUKZQX6U.js.map +0 -1
- package/dist/chunk-HYDWG35Q.js.map +0 -1
- package/dist/chunk-I5MQMJDW.js.map +0 -1
- package/dist/chunk-LYLTKJWM.js.map +0 -1
- package/dist/chunk-MYXFNWAJ.js.map +0 -1
- package/dist/chunk-RQULHGYH.js +0 -1804
- package/dist/chunk-RQULHGYH.js.map +0 -1
- package/dist/chunk-Z2L3LSNV.js.map +0 -1
- package/dist/index-DMCeMPMJ.d.ts +0 -272
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { C as Cmd, S as Sub, M as Machine } from '../core-
|
|
2
|
-
import { R as Runtime } from '../runtime-types-
|
|
3
|
-
import '
|
|
4
|
-
import 'better-result';
|
|
1
|
+
import { C as Cmd, S as Sub, M as Machine, a as BuiltinSub, p as Interpret } from '../core-BbgtiXdg.js';
|
|
2
|
+
import { C as CtxArg, R as Runtime } from '../runtime-types-CiVpC0HN.js';
|
|
3
|
+
import '@standard-schema/spec';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* The composed Model shape every `withX` wrapper produces: the base machine's
|
|
@@ -31,10 +30,10 @@ interface AssertWrapperFaithfulOpts<S, WM, BaseM, BaseCtx, WrapperCtx> {
|
|
|
31
30
|
*/
|
|
32
31
|
readonly baseLoaded?: S | null;
|
|
33
32
|
/**
|
|
34
|
-
* Opt-in relaxation for an INTERCEPTING wrapper (e.g.
|
|
33
|
+
* Opt-in relaxation for an INTERCEPTING wrapper (e.g. a retry wrapper).
|
|
35
34
|
*
|
|
36
|
-
* DEFAULT (`undefined` / `false`) — the OBSERVE-ONLY contract that
|
|
37
|
-
*
|
|
35
|
+
* DEFAULT (`undefined` / `false`) — the OBSERVE-ONLY contract that a
|
|
36
|
+
* deadline wrapper satisfies: every bare base Cmd must appear
|
|
38
37
|
* UNCHANGED, in order, as a subsequence of the wrapped Cmd stream (properties
|
|
39
38
|
* 1 and 3b). The wrapper may APPEND its own Cmds but may NOT alter, drop, or
|
|
40
39
|
* retime a base Cmd. This is the strict default and it is NOT weakened.
|
|
@@ -58,7 +57,7 @@ interface AssertWrapperFaithfulOpts<S, WM, BaseM, BaseCtx, WrapperCtx> {
|
|
|
58
57
|
* Cmd in its window is a SWALLOW betrayal and still fails the gate.
|
|
59
58
|
*
|
|
60
59
|
* Provide the field names the carrier uses so the gate can unwrap it
|
|
61
|
-
* structurally without hard-coding
|
|
60
|
+
* structurally without hard-coding any one wrapper's vocabulary.
|
|
62
61
|
*/
|
|
63
62
|
readonly intercepting?: InterceptingOpt;
|
|
64
63
|
}
|
|
@@ -94,10 +93,11 @@ interface InterceptingOpt {
|
|
|
94
93
|
*
|
|
95
94
|
* @param base the bare base `Machine`.
|
|
96
95
|
* @param makeWrapped a thunk that wraps `base` and returns the composed machine
|
|
97
|
-
* (e.g. `() =>
|
|
98
|
-
* so a wrapper that registers
|
|
99
|
-
* constructed inside the assertion's
|
|
100
|
-
*
|
|
96
|
+
* (e.g. `() => withTimeout(wired, cfg).machine`, where `wired.machine` is
|
|
97
|
+
* `base`). A thunk — not the wrapped value — so a wrapper that registers
|
|
98
|
+
* process-scoped ports (`definePort`) is constructed inside the assertion's
|
|
99
|
+
* control, and so the same betrayal-detector reads as
|
|
100
|
+
* `assertWrapperFaithful(wired.machine, () => withX(wired, cfg).machine, ...)`
|
|
101
101
|
* at every wrapper's test site.
|
|
102
102
|
* @param opts the conformance replay options.
|
|
103
103
|
*/
|
|
@@ -239,7 +239,7 @@ interface BoundMachine<S, M extends {
|
|
|
239
239
|
* Assert the exact set of subs desired at the final state. Mirrors the
|
|
240
240
|
* free `expectActiveSubs(machine, opts, expected)`.
|
|
241
241
|
*/
|
|
242
|
-
expectActiveSubs(opts: BoundOpts<S, M>, expected: readonly NoInfer<U
|
|
242
|
+
expectActiveSubs(opts: BoundOpts<S, M>, expected: readonly NoInfer<U | BuiltinSub<M>>[]): void;
|
|
243
243
|
/**
|
|
244
244
|
* Bound `replay` — returns `{ state, cmds, subs }` for the given opts.
|
|
245
245
|
* Use for the "narrow-then-assert" pattern where the test inspects a
|
|
@@ -248,7 +248,7 @@ interface BoundMachine<S, M extends {
|
|
|
248
248
|
replay(opts: BoundOpts<S, M>): {
|
|
249
249
|
state: S;
|
|
250
250
|
cmds: readonly C[];
|
|
251
|
-
subs: readonly U[];
|
|
251
|
+
subs: readonly (U | BuiltinSub<M>)[];
|
|
252
252
|
};
|
|
253
253
|
}
|
|
254
254
|
/**
|
|
@@ -265,6 +265,156 @@ declare function bindMachine<S, M extends {
|
|
|
265
265
|
type: string;
|
|
266
266
|
}, C extends Cmd, U extends Sub, Ctx>(machine: Machine<S, M, C, U, Ctx>, ctx: Ctx): BoundMachine<S, M, C, U, Ctx>;
|
|
267
267
|
|
|
268
|
+
/**
|
|
269
|
+
* The default round bound when `opts.maxRounds` is omitted: **100**.
|
|
270
|
+
*
|
|
271
|
+
* A round is one drain of the pending Msgs plus one drain of the Cmds those
|
|
272
|
+
* folds emitted, so a settling machine costs a handful; 100 is loose enough
|
|
273
|
+
* that a legitimate retry ladder finishes inside it and tight enough that a
|
|
274
|
+
* genuine cycle stops rather than hangs.
|
|
275
|
+
*/
|
|
276
|
+
declare const DEFAULT_MAX_ROUNDS = 100;
|
|
277
|
+
/**
|
|
278
|
+
* One entry of a driven run's history, in dispatch order.
|
|
279
|
+
*
|
|
280
|
+
* - `msg` — a Msg folded through the machine's reducer. The seed Msg is the
|
|
281
|
+
* first entry of every trace; every later one is a settle Msg a handler
|
|
282
|
+
* returned (or fired through its injected `dispatch`).
|
|
283
|
+
* - `cmd` — a Cmd handed to an interpret handler. It is recorded BEFORE the
|
|
284
|
+
* handler is awaited, so a trace recovered from a rejected handler names the
|
|
285
|
+
* Cmd that rejected as its last entry.
|
|
286
|
+
*/
|
|
287
|
+
type DriveTraceEntry<M, C> = {
|
|
288
|
+
readonly kind: "msg";
|
|
289
|
+
readonly msg: M;
|
|
290
|
+
} | {
|
|
291
|
+
readonly kind: "cmd";
|
|
292
|
+
readonly cmd: C;
|
|
293
|
+
};
|
|
294
|
+
/** What a settled {@link drive} hands back. */
|
|
295
|
+
interface DriveResult<S, M, C> {
|
|
296
|
+
/** The state after the machine went quiet — no Msg pending, no Cmd unperformed. */
|
|
297
|
+
readonly state: S;
|
|
298
|
+
/**
|
|
299
|
+
* Every Msg folded and every Cmd dispatched, in order. Filtering it to its
|
|
300
|
+
* `msg` entries and replaying those through `replay` from the same initial
|
|
301
|
+
* state reproduces {@link DriveResult.state}.
|
|
302
|
+
*/
|
|
303
|
+
readonly trace: readonly DriveTraceEntry<M, C>[];
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* {@link drive}'s `ctx` field. `CtxArg` widened by exactly one case: a machine
|
|
307
|
+
* declaring `ctx: undefined` in its `types` block — the pure shape every
|
|
308
|
+
* how-to on this package writes — may omit it too. `CtxArg` alone keeps `ctx`
|
|
309
|
+
* REQUIRED there, because `{}` is not assignable to `undefined`, which would
|
|
310
|
+
* make the common pure call site spell `{ ctx: undefined }` to say nothing.
|
|
311
|
+
* A machine whose `Ctx` carries a field a handler reads still requires it.
|
|
312
|
+
*/
|
|
313
|
+
type DriveCtxArg<Ctx> = [undefined] extends [Ctx] ? {
|
|
314
|
+
readonly ctx?: Ctx;
|
|
315
|
+
} : CtxArg<Ctx>;
|
|
316
|
+
/**
|
|
317
|
+
* {@link drive}'s options. `ctx` is conditionally optional (see
|
|
318
|
+
* {@link DriveCtxArg}).
|
|
319
|
+
*/
|
|
320
|
+
type DriveOptions<Ctx> = DriveCtxArg<Ctx> & {
|
|
321
|
+
/**
|
|
322
|
+
* The round bound. Exceeding it throws {@link DriveRoundsExceededError};
|
|
323
|
+
* `drive` never returns a half-driven state. Defaults to
|
|
324
|
+
* {@link DEFAULT_MAX_ROUNDS} (100).
|
|
325
|
+
*/
|
|
326
|
+
readonly maxRounds?: number;
|
|
327
|
+
/**
|
|
328
|
+
* The clock that stamps `at` on a `Cmd.define`d Cmd's minted `_ok` / `_err`
|
|
329
|
+
* Msg — the one `run` takes. Defaults to `Date.now`; pin it for a test that
|
|
330
|
+
* asserts on `at`.
|
|
331
|
+
*/
|
|
332
|
+
readonly clock?: () => number;
|
|
333
|
+
};
|
|
334
|
+
/**
|
|
335
|
+
* Raised when a driven machine is still emitting work after `maxRounds` rounds.
|
|
336
|
+
* Follows the tea error dialect (`override readonly name`) and carries a `_tag`
|
|
337
|
+
* discriminant, so a test branches on it by `instanceof` or on the tag.
|
|
338
|
+
*
|
|
339
|
+
* It carries the round count it stopped at and the PARTIAL trace up to that
|
|
340
|
+
* point, which is what a test needs to see the cycle — the bound alone says
|
|
341
|
+
* only that one exists.
|
|
342
|
+
*/
|
|
343
|
+
declare class DriveRoundsExceededError<M, C> extends Error {
|
|
344
|
+
/** The bound that was exceeded. */
|
|
345
|
+
readonly maxRounds: number;
|
|
346
|
+
/** The round the driver stopped at — always `maxRounds + 1`. */
|
|
347
|
+
readonly rounds: number;
|
|
348
|
+
/** Every Msg folded and Cmd dispatched before the driver gave up. */
|
|
349
|
+
readonly trace: readonly DriveTraceEntry<M, C>[];
|
|
350
|
+
readonly name = "DriveRoundsExceededError";
|
|
351
|
+
readonly _tag: "DriveRoundsExceededError";
|
|
352
|
+
constructor(
|
|
353
|
+
/** The bound that was exceeded. */
|
|
354
|
+
maxRounds: number,
|
|
355
|
+
/** The round the driver stopped at — always `maxRounds + 1`. */
|
|
356
|
+
rounds: number,
|
|
357
|
+
/** Every Msg folded and Cmd dispatched before the driver gave up. */
|
|
358
|
+
trace: readonly DriveTraceEntry<M, C>[]);
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Raised when a Cmd reaches {@link drive} with no handler for its `type` in the
|
|
362
|
+
* `handlers` record. `Interpret`'s mapped type makes that a compile error at a
|
|
363
|
+
* well-typed call site; this is the runtime arm for a handler record assembled
|
|
364
|
+
* dynamically or cast.
|
|
365
|
+
*/
|
|
366
|
+
declare class DriveNoHandlerError<M, C> extends Error {
|
|
367
|
+
/** The Cmd `type` nothing in the handler record answered. */
|
|
368
|
+
readonly cmdType: string;
|
|
369
|
+
/** Every Msg folded and Cmd dispatched before the miss. */
|
|
370
|
+
readonly trace: readonly DriveTraceEntry<M, C>[];
|
|
371
|
+
readonly name = "DriveNoHandlerError";
|
|
372
|
+
readonly _tag: "DriveNoHandlerError";
|
|
373
|
+
constructor(
|
|
374
|
+
/** The Cmd `type` nothing in the handler record answered. */
|
|
375
|
+
cmdType: string,
|
|
376
|
+
/** Every Msg folded and Cmd dispatched before the miss. */
|
|
377
|
+
trace: readonly DriveTraceEntry<M, C>[]);
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Read back the partial trace `drive` attached to an error a handler rejected
|
|
381
|
+
* with. Returns `undefined` for anything `drive` did not annotate.
|
|
382
|
+
*
|
|
383
|
+
* A rejecting handler's error propagates out of `drive` UNSWALLOWED — same
|
|
384
|
+
* value, same `instanceof`, same `_tag` — so a test that already branches on
|
|
385
|
+
* the handler's own error type keeps doing so. The trace rides along on a
|
|
386
|
+
* non-enumerable property so it is recoverable without changing how the error
|
|
387
|
+
* prints or serializes.
|
|
388
|
+
*/
|
|
389
|
+
declare function driveTraceOf<M, C>(err: unknown): readonly DriveTraceEntry<M, C>[] | undefined;
|
|
390
|
+
/**
|
|
391
|
+
* Drive `machine` from `initial` through `msg` against the REAL interpret
|
|
392
|
+
* `handlers`, feeding every settle Msg back until the machine goes quiet, and
|
|
393
|
+
* hand back the settled state together with the whole history.
|
|
394
|
+
*
|
|
395
|
+
* `handlers` is the same table a host hands `run` as its `interpret` (e.g.
|
|
396
|
+
* a jev knob's `resilient_run` handler), so the test drives the real interpreter and
|
|
397
|
+
* mocks only the port beneath it.
|
|
398
|
+
*
|
|
399
|
+
* One round is: fold every pending Msg, then await a handler for every Cmd
|
|
400
|
+
* those folds emitted. A Msg a handler returns — or fires through its injected
|
|
401
|
+
* `dispatch` — is pending for the next round. A machine that emits no Cmd for
|
|
402
|
+
* its seed Msg therefore settles in ONE round and never awaits a handler at
|
|
403
|
+
* all.
|
|
404
|
+
*
|
|
405
|
+
* The `ctx` handed to each handler is `opts.ctx` augmented with a NO-OP `emit`,
|
|
406
|
+
* so a handler that emits to a `Port` runs without a live runtime; nothing here
|
|
407
|
+
* observes ports. Supply your own `emit` on `ctx` to capture them.
|
|
408
|
+
*
|
|
409
|
+
* @throws {DriveRoundsExceededError} when the machine is still emitting work
|
|
410
|
+
* after `opts.maxRounds` rounds. It never returns a half-driven state.
|
|
411
|
+
* @throws whatever a handler rejects with, unchanged — annotated with the
|
|
412
|
+
* partial trace, readable via {@link driveTraceOf}.
|
|
413
|
+
*/
|
|
414
|
+
declare function drive<S, M extends {
|
|
415
|
+
type: string;
|
|
416
|
+
}, C extends Cmd, U extends Sub, Ctx>(machine: Machine<S, M, C, U, Ctx>, initial: S, msg: M, handlers: Interpret<M, C, Ctx>, ...[opts]: Record<never, never> extends DriveOptions<Ctx> ? [opts?: DriveOptions<Ctx>] : [opts: DriveOptions<Ctx>]): Promise<DriveResult<S, M, C>>;
|
|
417
|
+
|
|
268
418
|
/**
|
|
269
419
|
* Construct an inert `Runtime<S, M>` value. Use at ctx sites that require
|
|
270
420
|
* a Runtime reference but where the test never invokes `interpret` (so
|
|
@@ -324,4 +474,4 @@ declare function stateFactory<S extends {
|
|
|
324
474
|
type: string;
|
|
325
475
|
}>(defaults: StateFactoryDefaults<S>): StateFactoryAPI<S>;
|
|
326
476
|
|
|
327
|
-
export { type AssertWrapperFaithfulOpts, type BoundMachine, type InterceptingOpt, type ReplayOpts, type StateFactoryAPI, type StateFactoryDefaults, type WrapperModel, assertWrapperFaithful, bindMachine, expectActiveSubs, expectCmdEmitted, expectCmdSequence, expectFinalState, noopRuntime, stateFactory, step };
|
|
477
|
+
export { type AssertWrapperFaithfulOpts, type BoundMachine, DEFAULT_MAX_ROUNDS, type DriveCtxArg, DriveNoHandlerError, type DriveOptions, type DriveResult, DriveRoundsExceededError, type DriveTraceEntry, type InterceptingOpt, type ReplayOpts, type StateFactoryAPI, type StateFactoryDefaults, type WrapperModel, assertWrapperFaithful, bindMachine, drive, driveTraceOf, expectActiveSubs, expectCmdEmitted, expectCmdSequence, expectFinalState, noopRuntime, stateFactory, step };
|
package/dist/testing/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import '../chunk-GOX2CYIM.js';
|
|
2
|
+
import { replay, cmdEdgeOver, Outcome, cmdEdge } from '../chunk-CH5KTOEZ.js';
|
|
2
3
|
import { expect, vi } from 'vitest';
|
|
3
4
|
|
|
4
5
|
function assertWrapperFaithful(base, makeWrapped, opts) {
|
|
@@ -116,7 +117,7 @@ function wrapperSliceKey(model) {
|
|
|
116
117
|
const dollarKeys = Object.keys(model).filter((k) => k.startsWith("$"));
|
|
117
118
|
if (dollarKeys.length !== 1) {
|
|
118
119
|
throw new Error(
|
|
119
|
-
`assertWrapperFaithful: expected exactly one "$"-prefixed wrapper slice on the composed Model, found ${dollarKeys.length} (${dollarKeys.join(", ") || "none"}). Every withX wrapper owns exactly one named slice (e.g. "$
|
|
120
|
+
`assertWrapperFaithful: expected exactly one "$"-prefixed wrapper slice on the composed Model, found ${dollarKeys.length} (${dollarKeys.join(", ") || "none"}). Every withX wrapper owns exactly one named slice (e.g. "$deadline").`
|
|
120
121
|
);
|
|
121
122
|
}
|
|
122
123
|
return dollarKeys[0];
|
|
@@ -223,6 +224,106 @@ function bindMachine(machine, ctx) {
|
|
|
223
224
|
};
|
|
224
225
|
}
|
|
225
226
|
|
|
227
|
+
// src/testing/drive.ts
|
|
228
|
+
var DEFAULT_MAX_ROUNDS = 100;
|
|
229
|
+
var DriveRoundsExceededError = class extends Error {
|
|
230
|
+
constructor(maxRounds, rounds, trace) {
|
|
231
|
+
super(
|
|
232
|
+
`@demlik/tea: drive did not settle within ${maxRounds} round(s) \u2014 the machine was still emitting work at round ${rounds}. The partial trace (${trace.length} entr${trace.length === 1 ? "y" : "ies"}) is on the error's \`trace\` field.`
|
|
233
|
+
);
|
|
234
|
+
this.maxRounds = maxRounds;
|
|
235
|
+
this.rounds = rounds;
|
|
236
|
+
this.trace = trace;
|
|
237
|
+
}
|
|
238
|
+
maxRounds;
|
|
239
|
+
rounds;
|
|
240
|
+
trace;
|
|
241
|
+
name = "DriveRoundsExceededError";
|
|
242
|
+
_tag = "DriveRoundsExceededError";
|
|
243
|
+
};
|
|
244
|
+
var DriveNoHandlerError = class extends Error {
|
|
245
|
+
constructor(cmdType, trace) {
|
|
246
|
+
super(
|
|
247
|
+
`@demlik/tea: drive found no interpret handler for Cmd type "${cmdType}" \u2014 the handlers record must answer every Cmd the machine emits.`
|
|
248
|
+
);
|
|
249
|
+
this.cmdType = cmdType;
|
|
250
|
+
this.trace = trace;
|
|
251
|
+
}
|
|
252
|
+
cmdType;
|
|
253
|
+
trace;
|
|
254
|
+
name = "DriveNoHandlerError";
|
|
255
|
+
_tag = "DriveNoHandlerError";
|
|
256
|
+
};
|
|
257
|
+
var TRACE_KEY = "driveTrace";
|
|
258
|
+
function driveTraceOf(err) {
|
|
259
|
+
if (typeof err !== "object" || err === null) return void 0;
|
|
260
|
+
const carried = err[TRACE_KEY];
|
|
261
|
+
return Array.isArray(carried) ? carried : void 0;
|
|
262
|
+
}
|
|
263
|
+
async function drive(machine, initial, msg, handlers, ...[opts]) {
|
|
264
|
+
const options = opts ?? {};
|
|
265
|
+
const maxRounds = options.maxRounds ?? DEFAULT_MAX_ROUNDS;
|
|
266
|
+
const bound = bindMachine(machine, options.ctx);
|
|
267
|
+
const settle = cmdEdgeOver(machine.cmds ?? [], options.clock ?? Date.now);
|
|
268
|
+
const noopEmit = { emit: () => {
|
|
269
|
+
} };
|
|
270
|
+
const handlerCtx = {
|
|
271
|
+
...noopEmit,
|
|
272
|
+
ok: Outcome.ok,
|
|
273
|
+
err: Outcome.err,
|
|
274
|
+
[cmdEdge]: settle,
|
|
275
|
+
...options.ctx
|
|
276
|
+
};
|
|
277
|
+
const cells = handlers;
|
|
278
|
+
const trace = [];
|
|
279
|
+
let state = initial;
|
|
280
|
+
let pending = [msg];
|
|
281
|
+
let round = 0;
|
|
282
|
+
while (pending.length > 0) {
|
|
283
|
+
round += 1;
|
|
284
|
+
if (round > maxRounds) {
|
|
285
|
+
throw new DriveRoundsExceededError(maxRounds, round, trace);
|
|
286
|
+
}
|
|
287
|
+
const folding = pending;
|
|
288
|
+
pending = [];
|
|
289
|
+
const emitted = [];
|
|
290
|
+
for (const next of folding) {
|
|
291
|
+
trace.push({ kind: "msg", msg: next });
|
|
292
|
+
const [advanced, cmds] = bound.step(state, next);
|
|
293
|
+
state = advanced;
|
|
294
|
+
emitted.push(...cmds);
|
|
295
|
+
}
|
|
296
|
+
for (const cmd of emitted) {
|
|
297
|
+
trace.push({ kind: "cmd", cmd });
|
|
298
|
+
const cell = cells[cmd.type];
|
|
299
|
+
if (cell === void 0) {
|
|
300
|
+
throw new DriveNoHandlerError(cmd.type, trace);
|
|
301
|
+
}
|
|
302
|
+
let settled;
|
|
303
|
+
try {
|
|
304
|
+
settled = settle(
|
|
305
|
+
cmd,
|
|
306
|
+
await cell(cmd, handlerCtx, (fired) => {
|
|
307
|
+
pending.push(fired);
|
|
308
|
+
})
|
|
309
|
+
);
|
|
310
|
+
} catch (err) {
|
|
311
|
+
if (typeof err === "object" && err !== null) {
|
|
312
|
+
Object.defineProperty(err, TRACE_KEY, {
|
|
313
|
+
value: [...trace],
|
|
314
|
+
enumerable: false,
|
|
315
|
+
configurable: true,
|
|
316
|
+
writable: true
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
throw err;
|
|
320
|
+
}
|
|
321
|
+
if (settled !== void 0) pending.push(settled);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return { state, trace };
|
|
325
|
+
}
|
|
326
|
+
|
|
226
327
|
// src/testing/noop-runtime.ts
|
|
227
328
|
function noopRuntime(opts) {
|
|
228
329
|
const initialState = opts?.initialState;
|
|
@@ -297,6 +398,6 @@ function stateFactory(defaults) {
|
|
|
297
398
|
return api;
|
|
298
399
|
}
|
|
299
400
|
|
|
300
|
-
export { assertWrapperFaithful, bindMachine, expectActiveSubs, expectCmdEmitted, expectCmdSequence, expectFinalState, noopRuntime, stateFactory, step };
|
|
401
|
+
export { DEFAULT_MAX_ROUNDS, DriveNoHandlerError, DriveRoundsExceededError, assertWrapperFaithful, bindMachine, drive, driveTraceOf, expectActiveSubs, expectCmdEmitted, expectCmdSequence, expectFinalState, noopRuntime, stateFactory, step };
|
|
301
402
|
//# sourceMappingURL=index.js.map
|
|
302
403
|
//# sourceMappingURL=index.js.map
|