@demlik/tea 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -18
- package/dist/agent/index.d.ts +44 -13
- package/dist/agent/index.js +10 -10
- package/dist/{chunk-PCJA2HTZ.js → chunk-2774I242.js} +7 -7
- package/dist/chunk-2774I242.js.map +1 -0
- package/dist/{chunk-YIMOFXST.js → chunk-2R62Q5UK.js} +3 -3
- package/dist/chunk-2R62Q5UK.js.map +1 -0
- package/dist/{chunk-PQSDUX6B.js → chunk-5HVKDHY6.js} +3 -3
- package/dist/{chunk-PQSDUX6B.js.map → chunk-5HVKDHY6.js.map} +1 -1
- package/dist/{chunk-WTSOW2MD.js → chunk-72CN3VPY.js} +5 -5
- package/dist/{chunk-WTSOW2MD.js.map → chunk-72CN3VPY.js.map} +1 -1
- package/dist/{chunk-JVE2LBFJ.js → chunk-A73IJ27X.js} +3 -3
- package/dist/{chunk-JVE2LBFJ.js.map → chunk-A73IJ27X.js.map} +1 -1
- package/dist/{chunk-I7E7AD2S.js → chunk-AIXC33SE.js} +4 -4
- package/dist/chunk-AIXC33SE.js.map +1 -0
- package/dist/{chunk-FNGZMVIT.js → chunk-DVNXEB7V.js} +3 -3
- package/dist/chunk-DVNXEB7V.js.map +1 -0
- package/dist/{chunk-XVIKSRCK.js → chunk-EA47MI5Q.js} +4 -4
- package/dist/{chunk-XVIKSRCK.js.map → chunk-EA47MI5Q.js.map} +1 -1
- package/dist/{chunk-IHUNKHDX.js → chunk-FTCYY2DO.js} +3 -3
- package/dist/{chunk-IHUNKHDX.js.map → chunk-FTCYY2DO.js.map} +1 -1
- package/dist/{chunk-JVKU2UQC.js → chunk-HX3C6LDK.js} +3 -3
- package/dist/{chunk-JVKU2UQC.js.map → chunk-HX3C6LDK.js.map} +1 -1
- package/dist/{chunk-H2ELKHI6.js → chunk-JAKM53JF.js} +4 -4
- package/dist/chunk-JAKM53JF.js.map +1 -0
- package/dist/{chunk-JYNYG5SF.js → chunk-NGYFBD5G.js} +3 -3
- package/dist/chunk-NGYFBD5G.js.map +1 -0
- package/dist/{chunk-AIIXV4XB.js → chunk-RKVUVALV.js} +2 -2
- package/dist/chunk-RKVUVALV.js.map +1 -0
- package/dist/{chunk-C3G2QFEZ.js → chunk-TAKPC6SD.js} +4 -4
- package/dist/{chunk-C3G2QFEZ.js.map → chunk-TAKPC6SD.js.map} +1 -1
- package/dist/{chunk-BRX3243I.js → chunk-TGJLXZAU.js} +3 -3
- package/dist/{chunk-BRX3243I.js.map → chunk-TGJLXZAU.js.map} +1 -1
- package/dist/{chunk-AHW2CLPT.js → chunk-UHAQ4PI6.js} +4 -4
- package/dist/{chunk-AHW2CLPT.js.map → chunk-UHAQ4PI6.js.map} +1 -1
- package/dist/{chunk-H3MWNH7A.js → chunk-XWIE5V7R.js} +4 -4
- package/dist/{chunk-H3MWNH7A.js.map → chunk-XWIE5V7R.js.map} +1 -1
- package/dist/{core-Ce9ncpuv.d.ts → core-CtvAyPpH.d.ts} +153 -1
- package/dist/devtools/index.d.ts +17 -0
- package/dist/devtools/index.js.map +1 -1
- package/dist/do/index.d.ts +12 -12
- package/dist/do/index.js +11 -11
- package/dist/{drive-loop-CsUsW3Wo.d.ts → drive-loop-Dw1sGSsW.d.ts} +1 -1
- package/dist/{durable-effects-BmUrRA-h.d.ts → durable-effects-Ump5lSdO.d.ts} +1 -1
- package/dist/effect/index.d.ts +124 -5
- package/dist/effect/index.js +33 -4
- package/dist/effect/index.js.map +1 -1
- package/dist/extension/index.d.ts +84 -3
- package/dist/extension/index.js +2 -2
- package/dist/extension/index.js.map +1 -1
- package/dist/flow/index.d.ts +29 -13
- package/dist/flow/index.js +11 -11
- package/dist/flow/index.js.map +1 -1
- package/dist/idempotency/index.d.ts +11 -3
- package/dist/idempotency/index.js +3 -3
- package/dist/{index-D8sYVzCI.d.ts → index-Bk2hBUdK.d.ts} +6 -1
- package/dist/{index-2kNxy6az.d.ts → index-CKtEKGyp.d.ts} +15 -3
- package/dist/{index-e36uEyl4.d.ts → index-CVU7SK3a.d.ts} +2 -2
- package/dist/{index-Dy3379ve.d.ts → index-CZZ3HI-Z.d.ts} +4 -4
- package/dist/{index-Ce5GYAuI.d.ts → index-CrcoVfd_.d.ts} +2 -2
- package/dist/{index-DWdg7R1l.d.ts → index-D3NY3VCN.d.ts} +5 -1
- package/dist/{index-B1Wzarkl.d.ts → index-Dl71V7kt.d.ts} +1 -1
- package/dist/{index-Bf9_bNql.d.ts → index-EIgfl83J.d.ts} +2 -2
- package/dist/index.d.ts +66 -5
- package/dist/index.js +2 -2
- package/dist/jev/index.d.ts +39 -27
- package/dist/jev/index.js +12 -8
- package/dist/jev/index.js.map +1 -1
- package/dist/{machine-CuojfZup.d.ts → machine-Dtre2TmN.d.ts} +9 -7
- package/dist/machine-viz/index.d.ts +2 -1
- package/dist/machine-viz/index.js +2 -2
- package/dist/machine-viz/index.js.map +1 -1
- package/dist/mem/index.d.ts +2 -2
- package/dist/mem/index.js +2 -2
- package/dist/node/index.d.ts +11 -2
- package/dist/node/index.js +2 -2
- package/dist/node/index.js.map +1 -1
- package/dist/otel/index.d.ts +10 -10
- package/dist/otel/index.js +10 -10
- package/dist/paginate/index.d.ts +5 -4
- package/dist/paginate/index.js +5 -5
- package/dist/parity/index.d.ts +3 -3
- package/dist/parity/index.js +3 -3
- package/dist/pbt/index.d.ts +1 -1
- package/dist/pbt/index.js +2 -2
- package/dist/persistence/index.d.ts +5 -5
- package/dist/persistence/index.js +4 -4
- package/dist/promise/index.d.ts +7 -2
- package/dist/promise/index.js +4 -4
- package/dist/react/index.d.ts +2 -2
- package/dist/resilience/index.d.ts +7 -6
- package/dist/resilience/index.js +5 -5
- package/dist/resilience/index.js.map +1 -1
- package/dist/{index-BnsAqn0-.d.ts → run-fiBe7pOG.d.ts} +8 -5
- package/dist/{runtime-types-BKg2CGMx.d.ts → runtime-types-DEluQgGO.d.ts} +74 -2
- package/dist/testing/effect/index.d.ts +5 -5
- package/dist/testing/effect/index.js +8 -8
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +3 -3
- package/dist/testing/promise/index.d.ts +4 -4
- package/dist/testing/promise/index.js +5 -5
- package/dist/timing/index.d.ts +4 -4
- package/dist/timing/index.js +4 -4
- package/dist/types-CXNzlbAg.d.ts +9 -0
- package/dist/work-queue/index.d.ts +4 -4
- package/dist/work-queue/index.js +2 -2
- package/dist/work-queue/index.js.map +1 -1
- package/package.json +3 -2
- package/dist/chunk-AIIXV4XB.js.map +0 -1
- package/dist/chunk-FNGZMVIT.js.map +0 -1
- package/dist/chunk-H2ELKHI6.js.map +0 -1
- package/dist/chunk-I7E7AD2S.js.map +0 -1
- package/dist/chunk-JYNYG5SF.js.map +0 -1
- package/dist/chunk-PCJA2HTZ.js.map +0 -1
- package/dist/chunk-YIMOFXST.js.map +0 -1
- package/dist/types-SzNSHKlV.d.ts +0 -5
|
@@ -130,6 +130,11 @@ type CmdInput = {
|
|
|
130
130
|
} & Record<string, unknown>;
|
|
131
131
|
/** The value `Cmd.define("fetch", …)` builds: `{ type: "fetch", ...input }`. */
|
|
132
132
|
type CmdValue<Name extends string, Input extends CmdInput, Ok, E extends Tagged> = Cmd<Name, Ok, E | MalformedResult> & Readonly<Input>;
|
|
133
|
+
/**
|
|
134
|
+
* The Msg the engine mints when a `Cmd.define`d Cmd's handler succeeds:
|
|
135
|
+
* `<name>_ok`, carrying the Cmd and its value. Handle it in `update` to fold
|
|
136
|
+
* the result into state.
|
|
137
|
+
*/
|
|
133
138
|
type SettledOk<Name extends string, C, Ok> = {
|
|
134
139
|
readonly type: `${Name}_ok`;
|
|
135
140
|
readonly cmd: C;
|
|
@@ -137,6 +142,11 @@ type SettledOk<Name extends string, C, Ok> = {
|
|
|
137
142
|
/** Stamped by the runtime at the interpret edge (`run`'s `clock`). */
|
|
138
143
|
readonly at: number;
|
|
139
144
|
};
|
|
145
|
+
/**
|
|
146
|
+
* The Msg the engine mints when a `Cmd.define`d Cmd's handler fails:
|
|
147
|
+
* `<name>_err`, carrying the Cmd and the tagged error. Handle it in `update` to
|
|
148
|
+
* decide what a failure means.
|
|
149
|
+
*/
|
|
140
150
|
type SettledErr<Name extends string, C, E extends Tagged> = {
|
|
141
151
|
readonly type: `${Name}_err`;
|
|
142
152
|
readonly cmd: C;
|
|
@@ -200,15 +210,41 @@ declare function defineCmd<const Name extends string, Input extends CmdInput, Ok
|
|
|
200
210
|
readonly ok: StandardSchemaV1<unknown, Ok>;
|
|
201
211
|
readonly err: Tags;
|
|
202
212
|
}): CmdDef<Name, Input, Ok, TaggedError<Tags[number]>>;
|
|
213
|
+
/**
|
|
214
|
+
* What an update cell returns: the `[nextState, cmds]` tuple, typed so that a
|
|
215
|
+
* Promise cannot stand in for it. An `async` cell fails to compile against it.
|
|
216
|
+
*/
|
|
203
217
|
type SyncReturn<S, C extends Cmd> = readonly [S, readonly C[]] & {
|
|
204
218
|
readonly then?: never;
|
|
205
219
|
};
|
|
220
|
+
/**
|
|
221
|
+
* Which of the two shapes a machine's `update` takes: a flat `reducer` keyed by
|
|
222
|
+
* Msg type, or a `transitions` table keyed by state type and then Msg type.
|
|
223
|
+
*/
|
|
206
224
|
type UpdateForm = "reducer" | "transitions";
|
|
225
|
+
/**
|
|
226
|
+
* Work out an `update` record's `UpdateForm` from its shape. For a machine, use
|
|
227
|
+
* `formOf`, which prefers the form `defineMachine` already recorded.
|
|
228
|
+
*
|
|
229
|
+
* A reducer's first own value is a function; a transitions table's is a record
|
|
230
|
+
* of functions. An empty record can never dispatch a Msg, so it reads as
|
|
231
|
+
* `reducer`.
|
|
232
|
+
*/
|
|
207
233
|
declare function detectUpdateForm(update: object): UpdateForm;
|
|
234
|
+
/**
|
|
235
|
+
* Read a machine's `UpdateForm`. Reach for it when code has to treat reducer
|
|
236
|
+
* and transitions machines differently. It prefers the form `defineMachine`
|
|
237
|
+
* recorded, and works the form out from the shape only for a machine that
|
|
238
|
+
* never went through `defineMachine`.
|
|
239
|
+
*/
|
|
208
240
|
declare function formOf(machine: {
|
|
209
241
|
update: object;
|
|
210
242
|
__form?: UpdateForm;
|
|
211
243
|
}): UpdateForm;
|
|
244
|
+
/**
|
|
245
|
+
* Thrown when a Msg is dispatched to a state that has no update cell for it. It
|
|
246
|
+
* names the Msg type, the state, and the Msg types that state does accept.
|
|
247
|
+
*/
|
|
212
248
|
declare class NoCellError extends Error {
|
|
213
249
|
readonly msgType: string;
|
|
214
250
|
readonly stateName: string;
|
|
@@ -232,22 +268,39 @@ declare function acceptedTypes<S>(machine: {
|
|
|
232
268
|
update: object;
|
|
233
269
|
__form?: UpdateForm;
|
|
234
270
|
}, state: S): readonly string[];
|
|
271
|
+
/**
|
|
272
|
+
* Run the one update cell that matches `state` and `msg` and return its
|
|
273
|
+
* `[nextState, cmds]`. Use it to step a machine by hand; it throws
|
|
274
|
+
* `NoCellError` when no cell matches.
|
|
275
|
+
*/
|
|
235
276
|
declare function applyCell<S, M extends {
|
|
236
277
|
type: string;
|
|
237
278
|
}, C extends Cmd>(machine: {
|
|
238
279
|
update: object;
|
|
239
280
|
__form?: UpdateForm;
|
|
240
281
|
}, state: S, msg: M): readonly [S, readonly C[]];
|
|
282
|
+
/**
|
|
283
|
+
* `applyCell` with the development-mode checks that catch an impure cell: the
|
|
284
|
+
* input state is frozen and the result is asserted to be plain data.
|
|
285
|
+
*/
|
|
241
286
|
declare function applyCellChecked<S, M extends {
|
|
242
287
|
type: string;
|
|
243
288
|
}, C extends Cmd>(machine: {
|
|
244
289
|
update: object;
|
|
245
290
|
__form?: UpdateForm;
|
|
246
291
|
}, state: S, msg: M): readonly [S, readonly C[]];
|
|
292
|
+
/**
|
|
293
|
+
* List every Msg type a machine has an update cell for, across all of its
|
|
294
|
+
* states.
|
|
295
|
+
*/
|
|
247
296
|
declare function msgKeysOf(machine: {
|
|
248
297
|
update: object;
|
|
249
298
|
__form?: UpdateForm;
|
|
250
299
|
}): readonly string[];
|
|
300
|
+
/**
|
|
301
|
+
* What `describeMachine` returns: the Msg types a machine handles and, for a
|
|
302
|
+
* transitions machine, its states and the Msg types each one accepts.
|
|
303
|
+
*/
|
|
251
304
|
type MachineShape = {
|
|
252
305
|
readonly form: "reducer";
|
|
253
306
|
/** Every `Msg.type` the flat reducer has a cell for. */
|
|
@@ -261,14 +314,28 @@ type MachineShape = {
|
|
|
261
314
|
/** `state.type` → the `Msg.type`s that state has a cell for. */
|
|
262
315
|
readonly accepts: Readonly<Record<string, readonly string[]>>;
|
|
263
316
|
};
|
|
317
|
+
/**
|
|
318
|
+
* Describe a machine's update table as data: its form, its Msg types, and the
|
|
319
|
+
* per-state accept sets of a transitions machine. Use it to build tooling, or
|
|
320
|
+
* to ask what a machine handles without dispatching to it.
|
|
321
|
+
*/
|
|
264
322
|
declare function describeMachine(machine: {
|
|
265
323
|
update: object;
|
|
266
324
|
__form?: UpdateForm;
|
|
267
325
|
}): MachineShape;
|
|
326
|
+
/**
|
|
327
|
+
* List the Msg types a machine accepts in the state named `stateType`. A
|
|
328
|
+
* reducer machine accepts every one of its Msg types in every state, and a
|
|
329
|
+
* `stateType` with no row in a transitions table accepts none.
|
|
330
|
+
*/
|
|
268
331
|
declare function acceptsOf(machine: {
|
|
269
332
|
update: object;
|
|
270
333
|
__form?: UpdateForm;
|
|
271
334
|
}, stateType: string): readonly string[];
|
|
335
|
+
/**
|
|
336
|
+
* The flat form of `update`: a record with one handler per Msg type, each
|
|
337
|
+
* returning `[nextState, cmds]`. Leaving a Msg type out is a compile error.
|
|
338
|
+
*/
|
|
272
339
|
type Reducer<S, M extends {
|
|
273
340
|
type: string;
|
|
274
341
|
}, C extends Cmd> = {
|
|
@@ -323,6 +390,11 @@ type Cmd<T extends string = string, Ok = unknown, E = unknown> = {
|
|
|
323
390
|
/** Phantom — the `_tag` union this Cmd can settle with. Never assigned. */
|
|
324
391
|
readonly __e?: E;
|
|
325
392
|
};
|
|
393
|
+
/**
|
|
394
|
+
* The helpers for building Cmds: `Cmd.define` declares a typed Cmd constructor,
|
|
395
|
+
* and `Cmd.none`, `Cmd.batch`, `Cmd.when` and `Cmd.whenDefined` build the Cmd
|
|
396
|
+
* list an update cell returns.
|
|
397
|
+
*/
|
|
326
398
|
declare const Cmd: {
|
|
327
399
|
/**
|
|
328
400
|
* Declare a typed Cmd constructor (ADR 0014, 0021). Returns the builder —
|
|
@@ -407,6 +479,7 @@ declare const Cmd: {
|
|
|
407
479
|
*/
|
|
408
480
|
readonly whenDefined: <T, const C extends Cmd>(value: T | undefined, build: (value: T) => C) => readonly C[];
|
|
409
481
|
};
|
|
482
|
+
/** The branded string that identifies a running Sub. Build one with `subId`. */
|
|
410
483
|
type SubId = string & {
|
|
411
484
|
readonly __brand: "SubId";
|
|
412
485
|
};
|
|
@@ -420,11 +493,29 @@ type SubId = string & {
|
|
|
420
493
|
* Strengthens invariant 7 (identity is explicit).
|
|
421
494
|
*/
|
|
422
495
|
declare function subId(s: string): SubId;
|
|
496
|
+
/**
|
|
497
|
+
* A running subscription as its runner sees it: its `type`, the `deps` value
|
|
498
|
+
* the machine's `subs` entry returned, and an `id` derived from both. Use it to
|
|
499
|
+
* declare a machine's Sub union and to type the `sub` argument of a runner.
|
|
500
|
+
*
|
|
501
|
+
* A machine never builds one. It declares `{ type, deps(state) }` in `subs`
|
|
502
|
+
* (see `DepKeyedSub`) and the engine derives the rest. A runner reads its data
|
|
503
|
+
* off `sub.deps`. `id` is `structuralHash({ type, deps })`, so it changes
|
|
504
|
+
* exactly when the type or the deps value does, which is when the engine
|
|
505
|
+
* restarts the runner.
|
|
506
|
+
*/
|
|
423
507
|
type Sub<T extends string = string, D = unknown> = {
|
|
424
508
|
readonly id: SubId;
|
|
425
509
|
readonly type: T;
|
|
426
510
|
readonly deps: D;
|
|
427
511
|
};
|
|
512
|
+
/**
|
|
513
|
+
* The cleanup function a Sub runner returns. The runner opens a resource and
|
|
514
|
+
* returns the function that closes it. The engine calls it when the Sub's
|
|
515
|
+
* `deps` go null (turned off), when they change (restarted: the old `Dispose`,
|
|
516
|
+
* then a fresh runner), and when the runtime stops. A returned Promise is
|
|
517
|
+
* awaited by `stop()`, with a bound.
|
|
518
|
+
*/
|
|
428
519
|
type Dispose = () => void | Promise<void>;
|
|
429
520
|
/** The `deps` a `timer` Sub declares: fire `msg` once, `ms` after it starts. */
|
|
430
521
|
type TimerDeps<M> = {
|
|
@@ -442,7 +533,16 @@ type BuiltinSub<M> = TimerSub<M>;
|
|
|
442
533
|
* value. Same type and same deps → same id → the running Sub is left alone.
|
|
443
534
|
*/
|
|
444
535
|
declare function subIdOf(type: string, deps: unknown): SubId;
|
|
536
|
+
/**
|
|
537
|
+
* Turn a plain-data value into a stable string that does not depend on object
|
|
538
|
+
* key order. Use it wherever two values must compare equal by content, as the
|
|
539
|
+
* engine does for Sub ids.
|
|
540
|
+
*/
|
|
445
541
|
declare function structuralHash(deps: unknown): string;
|
|
542
|
+
/**
|
|
543
|
+
* One entry of a machine's `subs`: a Sub `type` plus `deps(state)`, which
|
|
544
|
+
* returns the data the runner needs, or `null` to keep the Sub off.
|
|
545
|
+
*/
|
|
446
546
|
type DepKeyedSub<S, U extends Sub = Sub> = U extends Sub<infer T, infer D> ? {
|
|
447
547
|
readonly type: T;
|
|
448
548
|
/**
|
|
@@ -454,6 +554,11 @@ type DepKeyedSub<S, U extends Sub = Sub> = U extends Sub<infer T, infer D> ? {
|
|
|
454
554
|
*/
|
|
455
555
|
readonly deps: (state: S) => D | null | undefined;
|
|
456
556
|
} : never;
|
|
557
|
+
/**
|
|
558
|
+
* A machine's optional message filter: `ofState` names the identity this
|
|
559
|
+
* instance owns, and `ofMsg` the identity a Msg is addressed to. The engine
|
|
560
|
+
* drops a Msg addressed to a different identity before `update` runs.
|
|
561
|
+
*/
|
|
457
562
|
interface Identity<S, M> {
|
|
458
563
|
/** The identity THIS instance owns. Pure (invariant 2); plain value. */
|
|
459
564
|
readonly ofState: (state: S) => unknown;
|
|
@@ -464,6 +569,11 @@ interface Identity<S, M> {
|
|
|
464
569
|
*/
|
|
465
570
|
readonly ofMsg: (msg: M) => unknown;
|
|
466
571
|
}
|
|
572
|
+
/**
|
|
573
|
+
* A named, typed channel for values leaving the runtime. A Cmd handler sends on
|
|
574
|
+
* it with `ctx.emit(port, value)` and a host listens with
|
|
575
|
+
* `runtime.subscribePort`; create one with `definePort`.
|
|
576
|
+
*/
|
|
467
577
|
interface Port<T> {
|
|
468
578
|
readonly __brand: "port";
|
|
469
579
|
readonly name: string;
|
|
@@ -480,10 +590,18 @@ interface Port<T> {
|
|
|
480
590
|
interface PortEmitter {
|
|
481
591
|
emit<T>(port: Port<T>, value: T): void;
|
|
482
592
|
}
|
|
593
|
+
/**
|
|
594
|
+
* The `Ctx` of a machine whose handlers read nothing from context. Use it in
|
|
595
|
+
* place of `unknown` to say so on purpose.
|
|
596
|
+
*/
|
|
483
597
|
type NoCtx = Readonly<Record<never, never>>;
|
|
484
598
|
type HandlerCtx<Ctx> = (0 extends 1 & Ctx ? Ctx : [
|
|
485
599
|
Ctx
|
|
486
600
|
] extends [void] ? unknown : Ctx) & PortEmitter;
|
|
601
|
+
/**
|
|
602
|
+
* The Cmd handler table an engine is handed: one async handler per Cmd type.
|
|
603
|
+
* Leaving a Cmd type out is a compile error.
|
|
604
|
+
*/
|
|
487
605
|
type Interpret<M extends {
|
|
488
606
|
type: string;
|
|
489
607
|
}, C extends Cmd, Ctx> = {
|
|
@@ -506,9 +624,28 @@ type OkOfCmd<C> = C extends {
|
|
|
506
624
|
} ? Ok : unknown;
|
|
507
625
|
/** The failures a `Cmd.define`d Cmd's handler may return: its declared tags. */
|
|
508
626
|
type DeclaredErrorsOf<C> = Exclude<ErrorsOf<C>, MalformedResult>;
|
|
627
|
+
/**
|
|
628
|
+
* A Cmd handler that reports back through a `dispatch` limited to the Msgs it
|
|
629
|
+
* is allowed to send. Use it for work that outlives the handler call, and adapt
|
|
630
|
+
* it into an `Interpret` cell with `wrapDetached`.
|
|
631
|
+
*
|
|
632
|
+
* Such a handler hands its long-running work to `ctx.waitUntil(...)` and cannot
|
|
633
|
+
* return its terminal Msg inline, because awaiting it would deadlock the serial
|
|
634
|
+
* dispatch tail. So it returns `Promise<void>` and dispatches instead.
|
|
635
|
+
* `Allowed` is the Cmd's declared result-Msg set (e.g.
|
|
636
|
+
* `GraphFinished | GraphFailed`), and `dispatch` takes only those, so a wrong
|
|
637
|
+
* or mistyped terminal Msg fails to compile.
|
|
638
|
+
*/
|
|
509
639
|
type InterpretDetached<C extends Cmd, Allowed extends {
|
|
510
640
|
type: string;
|
|
511
641
|
}, Ctx> = (cmd: C, ctx: HandlerCtx<Ctx>, dispatch: (msg: Allowed) => void) => Promise<void>;
|
|
642
|
+
/**
|
|
643
|
+
* The Sub runner table an engine is handed: one runner per Sub type. Leaving a
|
|
644
|
+
* Sub type out is a compile error. Each runner receives the running Sub
|
|
645
|
+
* (`{ id, type, deps }`), the Ctx and a `dispatch`. It opens its resource,
|
|
646
|
+
* dispatches Msgs from it, and returns the `Dispose` the engine calls when the
|
|
647
|
+
* Sub stops.
|
|
648
|
+
*/
|
|
512
649
|
type Subscribe<M extends {
|
|
513
650
|
type: string;
|
|
514
651
|
}, U extends Sub, Ctx> = {
|
|
@@ -564,6 +701,10 @@ type Wired<S, M extends {
|
|
|
564
701
|
}, C extends Cmd, U extends Sub, Ctx> = {
|
|
565
702
|
readonly machine: Machine<S, M, C, U, Ctx>;
|
|
566
703
|
} & RunHandlers<M, C, U, Ctx>;
|
|
704
|
+
/**
|
|
705
|
+
* A machine as plain data: `init`, `update`, and optionally `subs`, `cmds` and
|
|
706
|
+
* `identity`. Build one with `defineMachine` and hand it to an engine's `run`.
|
|
707
|
+
*/
|
|
567
708
|
type Machine<S, M extends {
|
|
568
709
|
type: string;
|
|
569
710
|
}, C extends Cmd, U extends Sub, Ctx> = {
|
|
@@ -643,6 +784,12 @@ type Machine<S, M extends {
|
|
|
643
784
|
*/
|
|
644
785
|
readonly __form?: UpdateForm;
|
|
645
786
|
};
|
|
787
|
+
/**
|
|
788
|
+
* Fold a machine's `update` over a list of Msgs from a starting state, and
|
|
789
|
+
* return the final state with every Cmd the cells emitted. `replay` and
|
|
790
|
+
* `foldMsgs` cover the common cases; use this when you need both the state and
|
|
791
|
+
* the Cmds from a state of your choosing.
|
|
792
|
+
*/
|
|
646
793
|
declare function foldUpdates<S, M extends {
|
|
647
794
|
type: string;
|
|
648
795
|
}, C extends Cmd>(machine: {
|
|
@@ -652,8 +799,13 @@ declare function foldUpdates<S, M extends {
|
|
|
652
799
|
state: S;
|
|
653
800
|
cmds: C[];
|
|
654
801
|
};
|
|
802
|
+
/**
|
|
803
|
+
* Fold a machine's `update` over a list of Msgs from a base state and return
|
|
804
|
+
* only the final state. Use it for client-side prediction: re-apply
|
|
805
|
+
* unacknowledged inputs on top of a server snapshot without running any effect.
|
|
806
|
+
*/
|
|
655
807
|
declare function foldMsgs<S, M extends {
|
|
656
808
|
type: string;
|
|
657
809
|
}, C extends Cmd, U extends Sub, Ctx>(machine: Machine<S, M, C, U, Ctx>, base: S, msgs: readonly M[]): S;
|
|
658
810
|
|
|
659
|
-
export { applyCell as $, type AnyCmdDef as A, type BuiltinSub as B, Cmd as C, type Dispose as D, type
|
|
811
|
+
export { applyCell as $, type AnyCmdDef as A, type BuiltinSub as B, Cmd as C, type Dispose as D, type ErrorsOf as E, type InterpretCell as F, type MachineShape as G, type HandlerCtx as H, type Interpret as I, type NoCtx as J, OutcomeContractError as K, type OutcomeHelpers as L, type Machine as M, NoCellError as N, Outcome as O, type Port as P, type PortEmitter as Q, type RunHandlers as R, type Sub as S, type TimerDeps as T, type UpdateForm as U, type SubscribeArg as V, type Wired as W, type SyncReturn as X, UndeclaredFailureError as Y, acceptedTypes as Z, acceptsOf as _, type CmdOf as a, applyCellChecked as a0, describeMachine as a1, detectUpdateForm as a2, foldMsgs as a3, foldUpdates as a4, formOf as a5, msgKeysOf as a6, structuralHash as a7, subId as a8, subIdOf as a9, type CmdDef as b, type Subscribe as c, type SettledOk as d, type SettledErr as e, type TaggedError as f, type Reducer as g, type Settled as h, type Transitions as i, type InterpretDetached as j, type SubId as k, type DepKeyedSub as l, type TimerSub as m, type MalformedResult as n, type OkOfCmd as o, type DeclaredErrorsOf as p, type BuiltinSubType as q, type Tagged as r, type OkOf as s, type ErrOf as t, type CmdValue as u, AsyncSchemaError as v, type CmdInput as w, type ExhaustiveTransitions as x, type Identity as y, type InterpretArg as z };
|
package/dist/devtools/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
|
|
3
|
+
/** One row of the `MsgLog`: a timestamp, a category and the text to show. */
|
|
3
4
|
type MsgLogEntry = {
|
|
4
5
|
/** Display timestamp (whatever format you produced). */
|
|
5
6
|
ts: string;
|
|
@@ -8,10 +9,14 @@ type MsgLogEntry = {
|
|
|
8
9
|
/** Row text — usually the Msg tag plus a short detail. */
|
|
9
10
|
text: string;
|
|
10
11
|
};
|
|
12
|
+
/** Props for `MsgLog`: the rows to render and an optional `className`. */
|
|
11
13
|
interface MsgLogProps {
|
|
12
14
|
history: readonly MsgLogEntry[];
|
|
13
15
|
className?: string;
|
|
14
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* React component that renders a list of `MsgLogEntry` rows as a message log.
|
|
19
|
+
*/
|
|
15
20
|
declare function MsgLog({ history, className }: MsgLogProps): react_jsx_runtime.JSX.Element;
|
|
16
21
|
|
|
17
22
|
/**
|
|
@@ -68,6 +73,10 @@ declare function diffState(expected: unknown, actual: unknown): StateChange[];
|
|
|
68
73
|
*/
|
|
69
74
|
declare function formatDiff(changes: StateChange[]): string;
|
|
70
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Props for `StateDiff`: the `expected` and `actual` states to compare, and an
|
|
78
|
+
* optional `className`.
|
|
79
|
+
*/
|
|
71
80
|
interface StateDiffProps {
|
|
72
81
|
/**
|
|
73
82
|
* The baseline / "before" state — what you expected. In a regression view
|
|
@@ -95,6 +104,10 @@ interface StateDiffProps {
|
|
|
95
104
|
*/
|
|
96
105
|
declare function StateDiff({ expected, actual, className }: StateDiffProps): react_jsx_runtime.JSX.Element;
|
|
97
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Props for `StateInspector`: the `state` to show, an optional `flashKey`, and
|
|
109
|
+
* an optional `className`.
|
|
110
|
+
*/
|
|
98
111
|
interface StateInspectorProps {
|
|
99
112
|
/**
|
|
100
113
|
* The machine state to display. Render-derived shape — pass whatever you
|
|
@@ -111,6 +124,10 @@ interface StateInspectorProps {
|
|
|
111
124
|
*/
|
|
112
125
|
className?: string;
|
|
113
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* React component that renders a state value as formatted JSON, and flashes
|
|
129
|
+
* when `flashKey` changes.
|
|
130
|
+
*/
|
|
114
131
|
declare function StateInspector({ state, flashKey, className, }: StateInspectorProps): react_jsx_runtime.JSX.Element;
|
|
115
132
|
|
|
116
133
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/devtools/msg-log.tsx","../../src/devtools/state-diff.ts","../../src/devtools/state-diff-view.tsx","../../src/devtools/state-inspector.tsx","../../src/devtools/use-msg-history.ts"],"names":["jsxs","jsx","useRef"],"mappings":"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","file":"index.js","sourcesContent":["export type MsgLogEntry = {\n /** Display timestamp (whatever format you produced). */\n ts: string;\n /** Visual category — drives the row icon. Defaults to \"msg\" via CSS. */\n kind?: \"msg\" | \"sub\" | \"cmd\" | \"ok\" | \"fail\";\n /** Row text — usually the Msg tag plus a short detail. */\n text: string;\n};\n\nexport interface MsgLogProps {\n history: readonly MsgLogEntry[];\n className?: string;\n}\n\nexport function MsgLog({ history, className }: MsgLogProps) {\n return (\n <div className={`tea-dt-log${className ? ` ${className}` : \"\"}`}>\n {history.map((r, i) => (\n <div\n key={`${r.ts}-${i}`}\n className={`tea-dt-row tea-dt-${r.kind ?? \"msg\"}`}\n >\n <span className=\"tea-dt-t\">{r.ts}</span>\n <span className=\"tea-dt-m\">{r.text}</span>\n </div>\n ))}\n </div>\n );\n}\n","// ---------------------------------------------------------------------------\n// state-diff — the RICHER cousin of trace-replay's first-divergence walk.\n//\n// `../trace-replay` answers \"did the state drift, and where FIRST?\" — it stops\n// at the first differing cell because a regression check only needs to point at\n// one. This module answers the fuller devtools question: \"show me EVERY cell\n// that differs,\" classified as added / removed / changed, ready to render.\n//\n// Same substrate, same path grammar (root `state`, `foo[2]` for arrays,\n// `foo.bar` for objects, sorted-union key order, `Object.is` leaf equality) so\n// a path printed here is the SAME string trace-replay would print for that\n// cell. The two tools are deliberately consistent: a `divergence.path` from a\n// replay result indexes straight into this module's `StateChange[]`.\n//\n// Pure + zero-dep on purpose — runs in Node, in tests, in a Worker. The React\n// view (`./state-diff.tsx`) is the only React-touching layer.\n// ---------------------------------------------------------------------------\n\nimport {\n indexPath,\n keyPath,\n typeOf,\n unionKeys,\n} from \"../internal/persistence/trace-replay/state-walk\";\n\n/**\n * A single differing leaf value between two states.\n *\n * - `kind: \"added\"` — the path exists in `actual` but not `expected`\n * (`expected` is `undefined`).\n * - `kind: \"removed\"` — the path exists in `expected` but not `actual`\n * (`actual` is `undefined`).\n * - `kind: \"changed\"` — the path exists on both sides with differing leaf\n * values (or differing kinds, e.g. object vs array).\n */\nexport interface StateChange {\n /** Access path from the state root, e.g. `state.items[1].status`. */\n path: string;\n /** How the cell differs between the two states. */\n kind: \"added\" | \"removed\" | \"changed\";\n /** The value on the `expected` side (`undefined` when `added`). */\n expected: unknown;\n /** The value on the `actual` side (`undefined` when `removed`). */\n actual: unknown;\n}\n\n/**\n * Deep-walk two states and return EVERY differing leaf value, in deterministic\n * pre-order (the node before its children; children in array-index order, then\n * sorted-union key order for objects). The empty array means the two states are\n * deeply equal.\n *\n * Equality + path grammar match `../trace-replay`'s `firstDivergence` exactly:\n * - `Object.is` leaf equality, so `NaN` equals `NaN` and `+0` ≠ `-0`.\n * - arrays index by `[i]`; a length mismatch is NOT reported at the array\n * node — instead each surplus/missing element surfaces as its own\n * added/removed child, which is what a devtools list wants to show.\n * - objects walk the sorted union of both sides' keys; a key on only one\n * side becomes an `added`/`removed` child.\n * - the root path is `\"state\"`.\n *\n * Scope is JSON-shaped state (the same substrate trace-replay targets):\n * primitives, null/undefined, arrays, plain objects. A differing kind at a node\n * (object vs array, number vs string) is reported as a single `changed` at that\n * node — the walk does not descend into mismatched kinds.\n */\nexport function diffState(expected: unknown, actual: unknown): StateChange[] {\n const out: StateChange[] = [];\n walk(expected, actual, \"state\", out);\n return out;\n}\n\nfunction walk(\n expected: unknown,\n actual: unknown,\n path: string,\n out: StateChange[],\n): void {\n // Identity / primitive fast path. Equal cells contribute nothing. `Object.is`\n // so NaN equals NaN and +0 ≠ -0 — same intent as trace-replay's leaf check.\n if (Object.is(expected, actual)) return;\n\n const te = typeOf(expected);\n const ta = typeOf(actual);\n\n // A present/absent pair at this node is an add or a remove — the structural\n // signal a viewer color-codes differently from a value change.\n if (te === \"undefined\") {\n out.push({ path, kind: \"added\", expected, actual });\n return;\n }\n if (ta === \"undefined\") {\n out.push({ path, kind: \"removed\", expected, actual });\n return;\n }\n\n // Different kinds at a present node (object vs array, number vs string,\n // value vs null) — one `changed` at the node; do not descend into mismatched\n // shapes, mirroring trace-replay's \"this node IS the divergence\".\n if (te !== ta) {\n out.push({ path, kind: \"changed\", expected, actual });\n return;\n }\n\n if (te === \"array\") {\n const ae = expected as unknown[];\n const aa = actual as unknown[];\n // Walk the union of indices so surplus elements on EITHER side surface as\n // their own added/removed children (vs trace-replay, which reports a length\n // mismatch at the array node and stops). A viewer wants the per-element\n // detail.\n const len = Math.max(ae.length, aa.length);\n for (let i = 0; i < len; i++) {\n walk(ae[i], aa[i], indexPath(path, i), out);\n }\n return;\n }\n\n if (te === \"object\") {\n const oe = expected as Record<string, unknown>;\n const oa = actual as Record<string, unknown>;\n // Sorted union of keys — deterministic regardless of insertion order, so\n // two states with the same data in different key order produce no changes,\n // and the reported order is reproducible run-to-run.\n for (const key of unionKeys(oe, oa)) {\n walk(oe[key], oa[key], keyPath(path, key), out);\n }\n return;\n }\n\n // Two present primitives (string/number/boolean/bigint/symbol) or two\n // differing nulls that failed the Object.is fast path — a leaf change.\n out.push({ path, kind: \"changed\", expected, actual });\n}\n\n/** Render a single value compactly for a diff cell. Strings get quotes so\n * `\"3\"` is visibly distinct from `3`; everything else is JSON-ish, with the\n * `undefined`/`NaN`/`BigInt` cases JSON.stringify mishandles spelled out.\n * Exported (though not re-exported from `./index`) so the React `<StateDiff>`\n * view renders each cell with this exact formatter rather than a copy. */\nexport function fmtValue(v: unknown): string {\n if (v === undefined) return \"undefined\";\n if (typeof v === \"number\" && Number.isNaN(v)) return \"NaN\";\n if (typeof v === \"bigint\") return `${v}n`;\n if (typeof v === \"string\") return JSON.stringify(v);\n if (typeof v === \"function\" || typeof v === \"symbol\") return String(v);\n try {\n return JSON.stringify(v) ?? String(v);\n } catch {\n // Circular / non-serializable — fall back to a coarse tag.\n return String(v);\n }\n}\n\n/**\n * Pretty multi-line text for a {@link diffState} result. One `±`-prefixed line\n * per change, in the array's (pre-order, deterministic) order:\n *\n * - `~ state.total: 121.5 → 135` (changed: old → new)\n * - `- state.coupon: \"X\"` (removed: only the old value)\n * - `+ state.tax: 8` (added: only the new value)\n *\n * Deterministic given a deterministic `changes` array. An empty array yields\n * the empty string.\n */\nexport function formatDiff(changes: StateChange[]): string {\n return changes.map(formatChange).join(\"\\n\");\n}\n\n/** One `±`-prefixed line for a single change. Split out so the `map` callback\n * is total (Biome's useIterableCallbackReturn) without a dead default branch. */\nfunction formatChange(c: StateChange): string {\n switch (c.kind) {\n case \"changed\":\n return `~ ${c.path}: ${fmtValue(c.expected)} → ${fmtValue(c.actual)}`;\n case \"removed\":\n return `- ${c.path}: ${fmtValue(c.expected)}`;\n case \"added\":\n return `+ ${c.path}: ${fmtValue(c.actual)}`;\n }\n}\n","import {\n diffState,\n fmtValue,\n formatDiff,\n type StateChange,\n} from \"./state-diff\";\n\nexport interface StateDiffProps {\n /**\n * The baseline / \"before\" state — what you expected. In a regression view\n * this is a trace's recorded `finalState`; in a time-travel view it's the\n * previous model.\n */\n expected: unknown;\n /**\n * The \"after\" state to compare against `expected` — the recomputed or\n * current model.\n */\n actual: unknown;\n /** Optional className appended to the container. Use to override layout. */\n className?: string;\n}\n\n/** Per-kind row glyph + value rendering. Lives here (not CSS ::before like the\n * MsgLog rows) because the diff prints the path AND the value(s), so the glyph\n * is part of structured content the screen reader should read in order. */\nfunction changeRow(c: StateChange) {\n // `path` is unique within one diff (each cell appears at most once), so it is\n // a stable React key without needing the array index.\n switch (c.kind) {\n case \"changed\":\n return (\n <div key={c.path} className=\"tea-dt-diff-row tea-dt-diff-changed\">\n <span className=\"tea-dt-diff-mark\">~</span>\n <span className=\"tea-dt-diff-path\">{c.path}</span>\n <span className=\"tea-dt-diff-old\">{fmtValue(c.expected)}</span>\n <span className=\"tea-dt-diff-arrow\">→</span>\n <span className=\"tea-dt-diff-new\">{fmtValue(c.actual)}</span>\n </div>\n );\n case \"removed\":\n return (\n <div key={c.path} className=\"tea-dt-diff-row tea-dt-diff-removed\">\n <span className=\"tea-dt-diff-mark\">-</span>\n <span className=\"tea-dt-diff-path\">{c.path}</span>\n <span className=\"tea-dt-diff-old\">{fmtValue(c.expected)}</span>\n </div>\n );\n case \"added\":\n return (\n <div key={c.path} className=\"tea-dt-diff-row tea-dt-diff-added\">\n <span className=\"tea-dt-diff-mark\">+</span>\n <span className=\"tea-dt-diff-path\">{c.path}</span>\n <span className=\"tea-dt-diff-new\">{fmtValue(c.actual)}</span>\n </div>\n );\n }\n}\n\n/**\n * Presentational diff of two states. Renders {@link diffState}'s output as a\n * color-coded list (added / removed / changed), reusing the devtools `tea-dt-*`\n * class convention so it inherits the same design tokens as `<StateInspector>`\n * and `<MsgLog>` (see ./styles.css). No state, no subscription — pass the two\n * states as props, exactly like the rest of /devtools.\n *\n * When the states are deeply equal the list is empty; a tiny \"no changes\" hint\n * renders so an operator can tell \"equal\" from \"not yet computed\".\n */\nexport function StateDiff({ expected, actual, className }: StateDiffProps) {\n const changes = diffState(expected, actual);\n return (\n <div\n className={`tea-dt-diff${className ? ` ${className}` : \"\"}`}\n // The plain-text diff is the accessible/copyable fallback for the\n // color-coded rows — same content `formatDiff` produces in Node/tests.\n title={changes.length === 0 ? \"no changes\" : formatDiff(changes)}\n >\n {changes.length === 0 ? (\n <div className=\"tea-dt-diff-empty\">no changes</div>\n ) : (\n changes.map(changeRow)\n )}\n </div>\n );\n}\n","import { useEffect, useRef } from \"react\";\n\nfunction escapeHtml(s: string): string {\n return s.replace(\n /[&<>\"]/g,\n (c) =>\n ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\" })[c] as string,\n );\n}\n\nfunction fmtJson(obj: unknown, indent = 0): string {\n if (obj === null) return '<span class=\"tea-dt-b\">null</span>';\n if (typeof obj === \"number\") return `<span class=\"tea-dt-n\">${obj}</span>`;\n if (typeof obj === \"boolean\") return `<span class=\"tea-dt-b\">${obj}</span>`;\n if (typeof obj === \"string\")\n return `<span class=\"tea-dt-s\">\"${escapeHtml(obj)}\"</span>`;\n if (Array.isArray(obj)) {\n if (obj.length === 0) return '<span class=\"tea-dt-br\">[]</span>';\n return (\n '<span class=\"tea-dt-br\">[</span>' +\n obj\n .map((v) => fmtJson(v, indent + 1))\n .join('<span class=\"tea-dt-br\">, </span>') +\n '<span class=\"tea-dt-br\">]</span>'\n );\n }\n if (typeof obj === \"object\") {\n const keys = Object.keys(obj as object);\n if (keys.length === 0) return '<span class=\"tea-dt-br\">{}</span>';\n const pad = \" \".repeat(indent + 1);\n const lines = keys.map((k, i) => {\n const v = (obj as Record<string, unknown>)[k];\n const comma =\n i < keys.length - 1 ? '<span class=\"tea-dt-br\">,</span>' : \"\";\n return `${pad}<span class=\"tea-dt-k\">${escapeHtml(k)}</span><span class=\"tea-dt-br\">:</span> ${fmtJson(v, indent + 1)}${comma}`;\n });\n return [\n '<span class=\"tea-dt-br\">{</span>',\n ...lines,\n `${\" \".repeat(indent)}<span class=\"tea-dt-br\">}</span>`,\n ].join(\"<br/>\");\n }\n return escapeHtml(String(obj));\n}\n\nexport interface StateInspectorProps {\n /**\n * The machine state to display. Render-derived shape — pass whatever you\n * want surfaced to the inspector (often a hand-picked subset of the model).\n */\n state: unknown;\n /**\n * When this number changes, the inspector flashes. Pass `model.msgCount` or\n * any other monotonic counter you already have. Omit to disable flashing.\n */\n flashKey?: number;\n /**\n * Optional className appended to the container. Use to override layout.\n */\n className?: string;\n}\n\nexport function StateInspector({\n state,\n flashKey,\n className,\n}: StateInspectorProps) {\n const boxRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n if (flashKey === undefined || !boxRef.current) return;\n boxRef.current.classList.remove(\"tea-dt-flash\");\n void boxRef.current.offsetWidth;\n boxRef.current.classList.add(\"tea-dt-flash\");\n }, [flashKey]);\n\n return (\n <div\n ref={boxRef}\n className={`tea-dt-state${className ? ` ${className}` : \"\"}`}\n >\n <div\n className=\"tea-dt-json\"\n // biome-ignore lint/security/noDangerouslySetInnerHtml: formatter output\n dangerouslySetInnerHTML={{ __html: fmtJson(state) }}\n />\n </div>\n );\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport type { MsgLogEntry } from \"./msg-log\";\n\nfunction nowTs(): string {\n return new Date().toLocaleTimeString(\"en-GB\", { hour12: false }).slice(3);\n}\n\n/**\n * Wrap a `dispatch` so every Msg it sees lands in a bounded history buffer.\n *\n * `derive` lets you map a Msg to a richer entry (e.g. assign `kind: \"sub\"` to\n * subscription-triggered messages). Default: every msg becomes a `\"msg\"` row\n * tagged with `msg.type` (or `String(msg)` if it has no `type`). The substrate\n * uses `type` as the Msg discriminant — using `_tag` here would render every\n * Msg as `[object Object]` in the inspector.\n *\n * `max` caps the buffer — oldest entries fall off (LIFO, newest first).\n *\n * `now` is the timestamp source for the default `derive`. Defaults to\n * `nowTs` (real wall-clock). Tests inject a deterministic shim so\n * snapshots don't drift; production code never sets it.\n */\nexport function useMsgHistory<M>(\n dispatch: (msg: M) => void | Promise<void>,\n opts: {\n max?: number;\n derive?: (msg: M) => MsgLogEntry;\n now?: () => string;\n } = {},\n): readonly [readonly MsgLogEntry[], (msg: M) => void, () => void] {\n const max = opts.max ?? 60;\n const now = opts.now ?? nowTs;\n const derive =\n opts.derive ??\n ((msg: M): MsgLogEntry => {\n const tag =\n msg && typeof msg === \"object\" && \"type\" in msg\n ? String((msg as { type: unknown }).type)\n : String(msg);\n return { ts: now(), kind: \"msg\", text: tag };\n });\n\n const [history, setHistory] = useState<readonly MsgLogEntry[]>([]);\n // Stable ref to `dispatch` so the wrapper identity stays stable across\n // renders — important when this is passed to keyboard handlers and the like.\n const dispatchRef = useRef(dispatch);\n dispatchRef.current = dispatch;\n const deriveRef = useRef(derive);\n deriveRef.current = derive;\n\n const wrapped = useCallback(\n (msg: M) => {\n const entry = deriveRef.current(msg);\n setHistory((prev) => [entry, ...prev].slice(0, max));\n // Fire-and-forget — `dispatch` may return a Promise; we don't await it\n // here because callers historically treat dispatch as void.\n void dispatchRef.current(msg);\n },\n [max],\n );\n\n const clear = useCallback(() => setHistory([]), []);\n\n return [history, wrapped, clear] as const;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/devtools/msg-log.tsx","../../src/devtools/state-diff.ts","../../src/devtools/state-diff-view.tsx","../../src/devtools/state-inspector.tsx","../../src/devtools/use-msg-history.ts"],"names":["jsxs","jsx","useRef"],"mappings":";;;;AAmBO,SAAS,MAAA,CAAO,EAAE,OAAA,EAAS,SAAA,EAAU,EAAgB;AAC1D,EAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,CAAA,UAAA,EAAa,YAAY,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,GAAK,EAAE,CAAA,CAAA,EAC1D,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,GAAG,CAAA,qBACf,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MAEC,SAAA,EAAW,CAAA,kBAAA,EAAqB,CAAA,CAAE,IAAA,IAAQ,KAAK,CAAA,CAAA;AAAA,MAE/C,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,UAAA,EAAY,QAAA,EAAA,CAAA,CAAE,EAAA,EAAG,CAAA;AAAA,wBACjC,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,UAAA,EAAY,YAAE,IAAA,EAAK;AAAA;AAAA,KAAA;AAAA,IAJ9B,CAAA,EAAG,CAAA,CAAE,EAAE,CAAA,CAAA,EAAI,CAAC,CAAA;AAAA,GAMpB,CAAA,EACH,CAAA;AAEJ;;;ACiCO,SAAS,SAAA,CAAU,UAAmB,MAAA,EAAgC;AAC3E,EAAA,MAAM,MAAqB,EAAC;AAC5B,EAAA,IAAA,CAAK,QAAA,EAAU,MAAA,EAAQ,OAAA,EAAS,GAAG,CAAA;AACnC,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,IAAA,CACP,QAAA,EACA,MAAA,EACA,IAAA,EACA,GAAA,EACM;AAGN,EAAA,IAAI,MAAA,CAAO,EAAA,CAAG,QAAA,EAAU,MAAM,CAAA,EAAG;AAEjC,EAAA,MAAM,EAAA,GAAK,OAAO,QAAQ,CAAA;AAC1B,EAAA,MAAM,EAAA,GAAK,OAAO,MAAM,CAAA;AAIxB,EAAA,IAAI,OAAO,WAAA,EAAa;AACtB,IAAA,GAAA,CAAI,KAAK,EAAE,IAAA,EAAM,MAAM,OAAA,EAAS,QAAA,EAAU,QAAQ,CAAA;AAClD,IAAA;AAAA,EACF;AACA,EAAA,IAAI,OAAO,WAAA,EAAa;AACtB,IAAA,GAAA,CAAI,KAAK,EAAE,IAAA,EAAM,MAAM,SAAA,EAAW,QAAA,EAAU,QAAQ,CAAA;AACpD,IAAA;AAAA,EACF;AAKA,EAAA,IAAI,OAAO,EAAA,EAAI;AACb,IAAA,GAAA,CAAI,KAAK,EAAE,IAAA,EAAM,MAAM,SAAA,EAAW,QAAA,EAAU,QAAQ,CAAA;AACpD,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,OAAO,OAAA,EAAS;AAClB,IAAA,MAAM,EAAA,GAAK,QAAA;AACX,IAAA,MAAM,EAAA,GAAK,MAAA;AAKX,IAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,EAAA,CAAG,MAAA,EAAQ,GAAG,MAAM,CAAA;AACzC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,CAAA,EAAA,EAAK;AAC5B,MAAA,IAAA,CAAK,EAAA,CAAG,CAAC,CAAA,EAAG,EAAA,CAAG,CAAC,GAAG,SAAA,CAAU,IAAA,EAAM,CAAC,CAAA,EAAG,GAAG,CAAA;AAAA,IAC5C;AACA,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,OAAO,QAAA,EAAU;AACnB,IAAA,MAAM,EAAA,GAAK,QAAA;AACX,IAAA,MAAM,EAAA,GAAK,MAAA;AAIX,IAAA,KAAA,MAAW,GAAA,IAAO,SAAA,CAAU,EAAA,EAAI,EAAE,CAAA,EAAG;AACnC,MAAA,IAAA,CAAK,EAAA,CAAG,GAAG,CAAA,EAAG,EAAA,CAAG,GAAG,GAAG,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA,EAAG,GAAG,CAAA;AAAA,IAChD;AACA,IAAA;AAAA,EACF;AAIA,EAAA,GAAA,CAAI,KAAK,EAAE,IAAA,EAAM,MAAM,SAAA,EAAW,QAAA,EAAU,QAAQ,CAAA;AACtD;AAOO,SAAS,SAAS,CAAA,EAAoB;AAC3C,EAAA,IAAI,CAAA,KAAM,QAAW,OAAO,WAAA;AAC5B,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,OAAO,KAAA,CAAM,CAAC,GAAG,OAAO,KAAA;AACrD,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,EAAU,OAAO,GAAG,CAAC,CAAA,CAAA,CAAA;AACtC,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,EAAU,OAAO,IAAA,CAAK,UAAU,CAAC,CAAA;AAClD,EAAA,IAAI,OAAO,MAAM,UAAA,IAAc,OAAO,MAAM,QAAA,EAAU,OAAO,OAAO,CAAC,CAAA;AACrE,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA,IAAK,OAAO,CAAC,CAAA;AAAA,EACtC,CAAA,CAAA,MAAQ;AAEN,IAAA,OAAO,OAAO,CAAC,CAAA;AAAA,EACjB;AACF;AAaO,SAAS,WAAW,OAAA,EAAgC;AACzD,EAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,YAAY,CAAA,CAAE,KAAK,IAAI,CAAA;AAC5C;AAIA,SAAS,aAAa,CAAA,EAAwB;AAC5C,EAAA,QAAQ,EAAE,IAAA;AAAM,IACd,KAAK,SAAA;AACH,MAAA,OAAO,CAAA,EAAA,EAAK,CAAA,CAAE,IAAI,CAAA,EAAA,EAAK,QAAA,CAAS,CAAA,CAAE,QAAQ,CAAC,CAAA,QAAA,EAAM,QAAA,CAAS,CAAA,CAAE,MAAM,CAAC,CAAA,CAAA;AAAA,IACrE,KAAK,SAAA;AACH,MAAA,OAAO,KAAK,CAAA,CAAE,IAAI,KAAK,QAAA,CAAS,CAAA,CAAE,QAAQ,CAAC,CAAA,CAAA;AAAA,IAC7C,KAAK,OAAA;AACH,MAAA,OAAO,KAAK,CAAA,CAAE,IAAI,KAAK,QAAA,CAAS,CAAA,CAAE,MAAM,CAAC,CAAA,CAAA;AAAA;AAE/C;ACtJA,SAAS,UAAU,CAAA,EAAgB;AAGjC,EAAA,QAAQ,EAAE,IAAA;AAAM,IACd,KAAK,SAAA;AACH,MAAA,uBACEA,IAAAA,CAAC,KAAA,EAAA,EAAiB,SAAA,EAAU,qCAAA,EAC1B,QAAA,EAAA;AAAA,wBAAAC,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kBAAA,EAAmB,QAAA,EAAA,GAAA,EAAC,CAAA;AAAA,wBACpCA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kBAAA,EAAoB,YAAE,IAAA,EAAK,CAAA;AAAA,wBAC3CA,IAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mBAAmB,QAAA,EAAA,QAAA,CAAS,CAAA,CAAE,QAAQ,CAAA,EAAE,CAAA;AAAA,wBACxDA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,qBAAoB,QAAA,EAAA,QAAA,EAAC,CAAA;AAAA,wBACrCA,IAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mBAAmB,QAAA,EAAA,QAAA,CAAS,CAAA,CAAE,MAAM,CAAA,EAAE;AAAA,OAAA,EAAA,EAL9C,EAAE,IAMZ,CAAA;AAAA,IAEJ,KAAK,SAAA;AACH,MAAA,uBACED,IAAAA,CAAC,KAAA,EAAA,EAAiB,SAAA,EAAU,qCAAA,EAC1B,QAAA,EAAA;AAAA,wBAAAC,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kBAAA,EAAmB,QAAA,EAAA,GAAA,EAAC,CAAA;AAAA,wBACpCA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kBAAA,EAAoB,YAAE,IAAA,EAAK,CAAA;AAAA,wBAC3CA,IAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mBAAmB,QAAA,EAAA,QAAA,CAAS,CAAA,CAAE,QAAQ,CAAA,EAAE;AAAA,OAAA,EAAA,EAHhD,EAAE,IAIZ,CAAA;AAAA,IAEJ,KAAK,OAAA;AACH,MAAA,uBACED,IAAAA,CAAC,KAAA,EAAA,EAAiB,SAAA,EAAU,mCAAA,EAC1B,QAAA,EAAA;AAAA,wBAAAC,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kBAAA,EAAmB,QAAA,EAAA,GAAA,EAAC,CAAA;AAAA,wBACpCA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kBAAA,EAAoB,YAAE,IAAA,EAAK,CAAA;AAAA,wBAC3CA,IAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mBAAmB,QAAA,EAAA,QAAA,CAAS,CAAA,CAAE,MAAM,CAAA,EAAE;AAAA,OAAA,EAAA,EAH9C,EAAE,IAIZ,CAAA;AAAA;AAGR;AAYO,SAAS,SAAA,CAAU,EAAE,QAAA,EAAU,MAAA,EAAQ,WAAU,EAAmB;AACzE,EAAA,MAAM,OAAA,GAAU,SAAA,CAAU,QAAA,EAAU,MAAM,CAAA;AAC1C,EAAA,uBACEA,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,WAAW,CAAA,WAAA,EAAc,SAAA,GAAY,CAAA,CAAA,EAAI,SAAS,KAAK,EAAE,CAAA,CAAA;AAAA,MAGzD,OAAO,OAAA,CAAQ,MAAA,KAAW,CAAA,GAAI,YAAA,GAAe,WAAW,OAAO,CAAA;AAAA,MAE9D,QAAA,EAAA,OAAA,CAAQ,MAAA,KAAW,CAAA,mBAClBA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mBAAA,EAAoB,QAAA,EAAA,YAAA,EAAU,CAAA,GAE7C,OAAA,CAAQ,GAAA,CAAI,SAAS;AAAA;AAAA,GAEzB;AAEJ;ACvFA,SAAS,WAAW,CAAA,EAAmB;AACrC,EAAA,OAAO,CAAA,CAAE,OAAA;AAAA,IACP,SAAA;AAAA,IACA,CAAC,CAAA,KAAA,CACE,EAAE,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,MAAA,EAAQ,GAAA,EAAK,MAAA,EAAQ,GAAA,EAAK,QAAA,EAAS,EAAG,CAAC;AAAA,GACjE;AACF;AAEA,SAAS,OAAA,CAAQ,GAAA,EAAc,MAAA,GAAS,CAAA,EAAW;AACjD,EAAA,IAAI,GAAA,KAAQ,MAAM,OAAO,oCAAA;AACzB,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,0BAA0B,GAAG,CAAA,OAAA,CAAA;AACjE,EAAA,IAAI,OAAO,GAAA,KAAQ,SAAA,EAAW,OAAO,0BAA0B,GAAG,CAAA,OAAA,CAAA;AAClE,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA;AACjB,IAAA,OAAO,CAAA,wBAAA,EAA2B,UAAA,CAAW,GAAG,CAAC,CAAA,QAAA,CAAA;AACnD,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtB,IAAA,IAAI,GAAA,CAAI,MAAA,KAAW,CAAA,EAAG,OAAO,mCAAA;AAC7B,IAAA,OACE,kCAAA,GACA,GAAA,CACG,GAAA,CAAI,CAAC,CAAA,KAAM,OAAA,CAAQ,CAAA,EAAG,MAAA,GAAS,CAAC,CAAC,CAAA,CACjC,IAAA,CAAK,mCAAmC,CAAA,GAC3C,kCAAA;AAAA,EAEJ;AACA,EAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,GAAa,CAAA;AACtC,IAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,mCAAA;AAC9B,IAAA,MAAM,GAAA,GAAM,cAAA,CAAe,MAAA,CAAO,MAAA,GAAS,CAAC,CAAA;AAC5C,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,CAAC,GAAG,CAAA,KAAM;AAC/B,MAAA,MAAM,CAAA,GAAK,IAAgC,CAAC,CAAA;AAC5C,MAAA,MAAM,KAAA,GACJ,CAAA,GAAI,IAAA,CAAK,MAAA,GAAS,IAAI,kCAAA,GAAqC,EAAA;AAC7D,MAAA,OAAO,CAAA,EAAG,GAAG,CAAA,uBAAA,EAA0B,UAAA,CAAW,CAAC,CAAC,CAAA,wCAAA,EAA2C,OAAA,CAAQ,CAAA,EAAG,MAAA,GAAS,CAAC,CAAC,GAAG,KAAK,CAAA,CAAA;AAAA,IAC/H,CAAC,CAAA;AACD,IAAA,OAAO;AAAA,MACL,kCAAA;AAAA,MACA,GAAG,KAAA;AAAA,MACH,CAAA,EAAG,cAAA,CAAe,MAAA,CAAO,MAAM,CAAC,CAAA,gCAAA;AAAA,KAClC,CAAE,KAAK,OAAO,CAAA;AAAA,EAChB;AACA,EAAA,OAAO,UAAA,CAAW,MAAA,CAAO,GAAG,CAAC,CAAA;AAC/B;AA2BO,SAAS,cAAA,CAAe;AAAA,EAC7B,KAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAAwB;AACtB,EAAA,MAAM,MAAA,GAAS,OAAuB,IAAI,CAAA;AAC1C,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,QAAA,KAAa,MAAA,IAAa,CAAC,MAAA,CAAO,OAAA,EAAS;AAC/C,IAAA,MAAA,CAAO,OAAA,CAAQ,SAAA,CAAU,MAAA,CAAO,cAAc,CAAA;AAC9C,IAAA,KAAK,OAAO,OAAA,CAAQ,WAAA;AACpB,IAAA,MAAA,CAAO,OAAA,CAAQ,SAAA,CAAU,GAAA,CAAI,cAAc,CAAA;AAAA,EAC7C,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAA,uBACEA,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,MAAA;AAAA,MACL,WAAW,CAAA,YAAA,EAAe,SAAA,GAAY,CAAA,CAAA,EAAI,SAAS,KAAK,EAAE,CAAA,CAAA;AAAA,MAE1D,QAAA,kBAAAA,GAAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAU,aAAA;AAAA,UAEV,uBAAA,EAAyB,EAAE,MAAA,EAAQ,OAAA,CAAQ,KAAK,CAAA;AAAE;AAAA;AACpD;AAAA,GACF;AAEJ;AC5FA,SAAS,KAAA,GAAgB;AACvB,EAAA,OAAA,iBAAO,IAAI,IAAA,EAAK,EAAE,kBAAA,CAAmB,OAAA,EAAS,EAAE,MAAA,EAAQ,KAAA,EAAO,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA;AAC1E;AAiBO,SAAS,aAAA,CACd,QAAA,EACA,IAAA,GAII,EAAC,EAC4D;AACjE,EAAA,MAAM,GAAA,GAAM,KAAK,GAAA,IAAO,EAAA;AACxB,EAAA,MAAM,GAAA,GAAM,KAAK,GAAA,IAAO,KAAA;AACxB,EAAA,MAAM,MAAA,GACJ,IAAA,CAAK,MAAA,KACJ,CAAC,GAAA,KAAwB;AACxB,IAAA,MAAM,GAAA,GACJ,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,IAAY,MAAA,IAAU,GAAA,GACxC,MAAA,CAAQ,GAAA,CAA0B,IAAI,CAAA,GACtC,MAAA,CAAO,GAAG,CAAA;AAChB,IAAA,OAAO,EAAE,EAAA,EAAI,GAAA,IAAO,IAAA,EAAM,KAAA,EAAO,MAAM,GAAA,EAAI;AAAA,EAC7C,CAAA,CAAA;AAEF,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,QAAA,CAAiC,EAAE,CAAA;AAGjE,EAAA,MAAM,WAAA,GAAcC,OAAO,QAAQ,CAAA;AACnC,EAAA,WAAA,CAAY,OAAA,GAAU,QAAA;AACtB,EAAA,MAAM,SAAA,GAAYA,OAAO,MAAM,CAAA;AAC/B,EAAA,SAAA,CAAU,OAAA,GAAU,MAAA;AAEpB,EAAA,MAAM,OAAA,GAAU,WAAA;AAAA,IACd,CAAC,GAAA,KAAW;AACV,MAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,OAAA,CAAQ,GAAG,CAAA;AACnC,MAAA,UAAA,CAAW,CAAC,IAAA,KAAS,CAAC,KAAA,EAAO,GAAG,IAAI,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,GAAG,CAAC,CAAA;AAGnD,MAAA,KAAK,WAAA,CAAY,QAAQ,GAAG,CAAA;AAAA,IAC9B,CAAA;AAAA,IACA,CAAC,GAAG;AAAA,GACN;AAEA,EAAA,MAAM,KAAA,GAAQ,YAAY,MAAM,UAAA,CAAW,EAAE,CAAA,EAAG,EAAE,CAAA;AAElD,EAAA,OAAO,CAAC,OAAA,EAAS,OAAA,EAAS,KAAK,CAAA;AACjC","file":"index.js","sourcesContent":["/** One row of the `MsgLog`: a timestamp, a category and the text to show. */\nexport type MsgLogEntry = {\n /** Display timestamp (whatever format you produced). */\n ts: string;\n /** Visual category — drives the row icon. Defaults to \"msg\" via CSS. */\n kind?: \"msg\" | \"sub\" | \"cmd\" | \"ok\" | \"fail\";\n /** Row text — usually the Msg tag plus a short detail. */\n text: string;\n};\n\n/** Props for `MsgLog`: the rows to render and an optional `className`. */\nexport interface MsgLogProps {\n history: readonly MsgLogEntry[];\n className?: string;\n}\n\n/**\n * React component that renders a list of `MsgLogEntry` rows as a message log.\n */\nexport function MsgLog({ history, className }: MsgLogProps) {\n return (\n <div className={`tea-dt-log${className ? ` ${className}` : \"\"}`}>\n {history.map((r, i) => (\n <div\n key={`${r.ts}-${i}`}\n className={`tea-dt-row tea-dt-${r.kind ?? \"msg\"}`}\n >\n <span className=\"tea-dt-t\">{r.ts}</span>\n <span className=\"tea-dt-m\">{r.text}</span>\n </div>\n ))}\n </div>\n );\n}\n","// ---------------------------------------------------------------------------\n// state-diff — the RICHER cousin of trace-replay's first-divergence walk.\n//\n// `../trace-replay` answers \"did the state drift, and where FIRST?\" — it stops\n// at the first differing cell because a regression check only needs to point at\n// one. This module answers the fuller devtools question: \"show me EVERY cell\n// that differs,\" classified as added / removed / changed, ready to render.\n//\n// Same substrate, same path grammar (root `state`, `foo[2]` for arrays,\n// `foo.bar` for objects, sorted-union key order, `Object.is` leaf equality) so\n// a path printed here is the SAME string trace-replay would print for that\n// cell. The two tools are deliberately consistent: a `divergence.path` from a\n// replay result indexes straight into this module's `StateChange[]`.\n//\n// Pure + zero-dep on purpose — runs in Node, in tests, in a Worker. The React\n// view (`./state-diff.tsx`) is the only React-touching layer.\n// ---------------------------------------------------------------------------\n\nimport {\n indexPath,\n keyPath,\n typeOf,\n unionKeys,\n} from \"../internal/persistence/trace-replay/state-walk\";\n\n/**\n * A single differing leaf value between two states.\n *\n * - `kind: \"added\"` — the path exists in `actual` but not `expected`\n * (`expected` is `undefined`).\n * - `kind: \"removed\"` — the path exists in `expected` but not `actual`\n * (`actual` is `undefined`).\n * - `kind: \"changed\"` — the path exists on both sides with differing leaf\n * values (or differing kinds, e.g. object vs array).\n */\nexport interface StateChange {\n /** Access path from the state root, e.g. `state.items[1].status`. */\n path: string;\n /** How the cell differs between the two states. */\n kind: \"added\" | \"removed\" | \"changed\";\n /** The value on the `expected` side (`undefined` when `added`). */\n expected: unknown;\n /** The value on the `actual` side (`undefined` when `removed`). */\n actual: unknown;\n}\n\n/**\n * Deep-walk two states and return EVERY differing leaf value, in deterministic\n * pre-order (the node before its children; children in array-index order, then\n * sorted-union key order for objects). The empty array means the two states are\n * deeply equal.\n *\n * Equality + path grammar match `../trace-replay`'s `firstDivergence` exactly:\n * - `Object.is` leaf equality, so `NaN` equals `NaN` and `+0` ≠ `-0`.\n * - arrays index by `[i]`; a length mismatch is NOT reported at the array\n * node — instead each surplus/missing element surfaces as its own\n * added/removed child, which is what a devtools list wants to show.\n * - objects walk the sorted union of both sides' keys; a key on only one\n * side becomes an `added`/`removed` child.\n * - the root path is `\"state\"`.\n *\n * Scope is JSON-shaped state (the same substrate trace-replay targets):\n * primitives, null/undefined, arrays, plain objects. A differing kind at a node\n * (object vs array, number vs string) is reported as a single `changed` at that\n * node — the walk does not descend into mismatched kinds.\n */\nexport function diffState(expected: unknown, actual: unknown): StateChange[] {\n const out: StateChange[] = [];\n walk(expected, actual, \"state\", out);\n return out;\n}\n\nfunction walk(\n expected: unknown,\n actual: unknown,\n path: string,\n out: StateChange[],\n): void {\n // Identity / primitive fast path. Equal cells contribute nothing. `Object.is`\n // so NaN equals NaN and +0 ≠ -0 — same intent as trace-replay's leaf check.\n if (Object.is(expected, actual)) return;\n\n const te = typeOf(expected);\n const ta = typeOf(actual);\n\n // A present/absent pair at this node is an add or a remove — the structural\n // signal a viewer color-codes differently from a value change.\n if (te === \"undefined\") {\n out.push({ path, kind: \"added\", expected, actual });\n return;\n }\n if (ta === \"undefined\") {\n out.push({ path, kind: \"removed\", expected, actual });\n return;\n }\n\n // Different kinds at a present node (object vs array, number vs string,\n // value vs null) — one `changed` at the node; do not descend into mismatched\n // shapes, mirroring trace-replay's \"this node IS the divergence\".\n if (te !== ta) {\n out.push({ path, kind: \"changed\", expected, actual });\n return;\n }\n\n if (te === \"array\") {\n const ae = expected as unknown[];\n const aa = actual as unknown[];\n // Walk the union of indices so surplus elements on EITHER side surface as\n // their own added/removed children (vs trace-replay, which reports a length\n // mismatch at the array node and stops). A viewer wants the per-element\n // detail.\n const len = Math.max(ae.length, aa.length);\n for (let i = 0; i < len; i++) {\n walk(ae[i], aa[i], indexPath(path, i), out);\n }\n return;\n }\n\n if (te === \"object\") {\n const oe = expected as Record<string, unknown>;\n const oa = actual as Record<string, unknown>;\n // Sorted union of keys — deterministic regardless of insertion order, so\n // two states with the same data in different key order produce no changes,\n // and the reported order is reproducible run-to-run.\n for (const key of unionKeys(oe, oa)) {\n walk(oe[key], oa[key], keyPath(path, key), out);\n }\n return;\n }\n\n // Two present primitives (string/number/boolean/bigint/symbol) or two\n // differing nulls that failed the Object.is fast path — a leaf change.\n out.push({ path, kind: \"changed\", expected, actual });\n}\n\n/** Render a single value compactly for a diff cell. Strings get quotes so\n * `\"3\"` is visibly distinct from `3`; everything else is JSON-ish, with the\n * `undefined`/`NaN`/`BigInt` cases JSON.stringify mishandles spelled out.\n * Exported (though not re-exported from `./index`) so the React `<StateDiff>`\n * view renders each cell with this exact formatter rather than a copy. */\nexport function fmtValue(v: unknown): string {\n if (v === undefined) return \"undefined\";\n if (typeof v === \"number\" && Number.isNaN(v)) return \"NaN\";\n if (typeof v === \"bigint\") return `${v}n`;\n if (typeof v === \"string\") return JSON.stringify(v);\n if (typeof v === \"function\" || typeof v === \"symbol\") return String(v);\n try {\n return JSON.stringify(v) ?? String(v);\n } catch {\n // Circular / non-serializable — fall back to a coarse tag.\n return String(v);\n }\n}\n\n/**\n * Pretty multi-line text for a {@link diffState} result. One `±`-prefixed line\n * per change, in the array's (pre-order, deterministic) order:\n *\n * - `~ state.total: 121.5 → 135` (changed: old → new)\n * - `- state.coupon: \"X\"` (removed: only the old value)\n * - `+ state.tax: 8` (added: only the new value)\n *\n * Deterministic given a deterministic `changes` array. An empty array yields\n * the empty string.\n */\nexport function formatDiff(changes: StateChange[]): string {\n return changes.map(formatChange).join(\"\\n\");\n}\n\n/** One `±`-prefixed line for a single change. Split out so the `map` callback\n * is total (Biome's useIterableCallbackReturn) without a dead default branch. */\nfunction formatChange(c: StateChange): string {\n switch (c.kind) {\n case \"changed\":\n return `~ ${c.path}: ${fmtValue(c.expected)} → ${fmtValue(c.actual)}`;\n case \"removed\":\n return `- ${c.path}: ${fmtValue(c.expected)}`;\n case \"added\":\n return `+ ${c.path}: ${fmtValue(c.actual)}`;\n }\n}\n","import {\n diffState,\n fmtValue,\n formatDiff,\n type StateChange,\n} from \"./state-diff\";\n\n/**\n * Props for `StateDiff`: the `expected` and `actual` states to compare, and an\n * optional `className`.\n */\nexport interface StateDiffProps {\n /**\n * The baseline / \"before\" state — what you expected. In a regression view\n * this is a trace's recorded `finalState`; in a time-travel view it's the\n * previous model.\n */\n expected: unknown;\n /**\n * The \"after\" state to compare against `expected` — the recomputed or\n * current model.\n */\n actual: unknown;\n /** Optional className appended to the container. Use to override layout. */\n className?: string;\n}\n\n/** Per-kind row glyph + value rendering. Lives here (not CSS ::before like the\n * MsgLog rows) because the diff prints the path AND the value(s), so the glyph\n * is part of structured content the screen reader should read in order. */\nfunction changeRow(c: StateChange) {\n // `path` is unique within one diff (each cell appears at most once), so it is\n // a stable React key without needing the array index.\n switch (c.kind) {\n case \"changed\":\n return (\n <div key={c.path} className=\"tea-dt-diff-row tea-dt-diff-changed\">\n <span className=\"tea-dt-diff-mark\">~</span>\n <span className=\"tea-dt-diff-path\">{c.path}</span>\n <span className=\"tea-dt-diff-old\">{fmtValue(c.expected)}</span>\n <span className=\"tea-dt-diff-arrow\">→</span>\n <span className=\"tea-dt-diff-new\">{fmtValue(c.actual)}</span>\n </div>\n );\n case \"removed\":\n return (\n <div key={c.path} className=\"tea-dt-diff-row tea-dt-diff-removed\">\n <span className=\"tea-dt-diff-mark\">-</span>\n <span className=\"tea-dt-diff-path\">{c.path}</span>\n <span className=\"tea-dt-diff-old\">{fmtValue(c.expected)}</span>\n </div>\n );\n case \"added\":\n return (\n <div key={c.path} className=\"tea-dt-diff-row tea-dt-diff-added\">\n <span className=\"tea-dt-diff-mark\">+</span>\n <span className=\"tea-dt-diff-path\">{c.path}</span>\n <span className=\"tea-dt-diff-new\">{fmtValue(c.actual)}</span>\n </div>\n );\n }\n}\n\n/**\n * Presentational diff of two states. Renders {@link diffState}'s output as a\n * color-coded list (added / removed / changed), reusing the devtools `tea-dt-*`\n * class convention so it inherits the same design tokens as `<StateInspector>`\n * and `<MsgLog>` (see ./styles.css). No state, no subscription — pass the two\n * states as props, exactly like the rest of /devtools.\n *\n * When the states are deeply equal the list is empty; a tiny \"no changes\" hint\n * renders so an operator can tell \"equal\" from \"not yet computed\".\n */\nexport function StateDiff({ expected, actual, className }: StateDiffProps) {\n const changes = diffState(expected, actual);\n return (\n <div\n className={`tea-dt-diff${className ? ` ${className}` : \"\"}`}\n // The plain-text diff is the accessible/copyable fallback for the\n // color-coded rows — same content `formatDiff` produces in Node/tests.\n title={changes.length === 0 ? \"no changes\" : formatDiff(changes)}\n >\n {changes.length === 0 ? (\n <div className=\"tea-dt-diff-empty\">no changes</div>\n ) : (\n changes.map(changeRow)\n )}\n </div>\n );\n}\n","import { useEffect, useRef } from \"react\";\n\nfunction escapeHtml(s: string): string {\n return s.replace(\n /[&<>\"]/g,\n (c) =>\n ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\" })[c] as string,\n );\n}\n\nfunction fmtJson(obj: unknown, indent = 0): string {\n if (obj === null) return '<span class=\"tea-dt-b\">null</span>';\n if (typeof obj === \"number\") return `<span class=\"tea-dt-n\">${obj}</span>`;\n if (typeof obj === \"boolean\") return `<span class=\"tea-dt-b\">${obj}</span>`;\n if (typeof obj === \"string\")\n return `<span class=\"tea-dt-s\">\"${escapeHtml(obj)}\"</span>`;\n if (Array.isArray(obj)) {\n if (obj.length === 0) return '<span class=\"tea-dt-br\">[]</span>';\n return (\n '<span class=\"tea-dt-br\">[</span>' +\n obj\n .map((v) => fmtJson(v, indent + 1))\n .join('<span class=\"tea-dt-br\">, </span>') +\n '<span class=\"tea-dt-br\">]</span>'\n );\n }\n if (typeof obj === \"object\") {\n const keys = Object.keys(obj as object);\n if (keys.length === 0) return '<span class=\"tea-dt-br\">{}</span>';\n const pad = \" \".repeat(indent + 1);\n const lines = keys.map((k, i) => {\n const v = (obj as Record<string, unknown>)[k];\n const comma =\n i < keys.length - 1 ? '<span class=\"tea-dt-br\">,</span>' : \"\";\n return `${pad}<span class=\"tea-dt-k\">${escapeHtml(k)}</span><span class=\"tea-dt-br\">:</span> ${fmtJson(v, indent + 1)}${comma}`;\n });\n return [\n '<span class=\"tea-dt-br\">{</span>',\n ...lines,\n `${\" \".repeat(indent)}<span class=\"tea-dt-br\">}</span>`,\n ].join(\"<br/>\");\n }\n return escapeHtml(String(obj));\n}\n\n/**\n * Props for `StateInspector`: the `state` to show, an optional `flashKey`, and\n * an optional `className`.\n */\nexport interface StateInspectorProps {\n /**\n * The machine state to display. Render-derived shape — pass whatever you\n * want surfaced to the inspector (often a hand-picked subset of the model).\n */\n state: unknown;\n /**\n * When this number changes, the inspector flashes. Pass `model.msgCount` or\n * any other monotonic counter you already have. Omit to disable flashing.\n */\n flashKey?: number;\n /**\n * Optional className appended to the container. Use to override layout.\n */\n className?: string;\n}\n\n/**\n * React component that renders a state value as formatted JSON, and flashes\n * when `flashKey` changes.\n */\nexport function StateInspector({\n state,\n flashKey,\n className,\n}: StateInspectorProps) {\n const boxRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n if (flashKey === undefined || !boxRef.current) return;\n boxRef.current.classList.remove(\"tea-dt-flash\");\n void boxRef.current.offsetWidth;\n boxRef.current.classList.add(\"tea-dt-flash\");\n }, [flashKey]);\n\n return (\n <div\n ref={boxRef}\n className={`tea-dt-state${className ? ` ${className}` : \"\"}`}\n >\n <div\n className=\"tea-dt-json\"\n // biome-ignore lint/security/noDangerouslySetInnerHtml: formatter output\n dangerouslySetInnerHTML={{ __html: fmtJson(state) }}\n />\n </div>\n );\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport type { MsgLogEntry } from \"./msg-log\";\n\nfunction nowTs(): string {\n return new Date().toLocaleTimeString(\"en-GB\", { hour12: false }).slice(3);\n}\n\n/**\n * Wrap a `dispatch` so every Msg it sees lands in a bounded history buffer.\n *\n * `derive` lets you map a Msg to a richer entry (e.g. assign `kind: \"sub\"` to\n * subscription-triggered messages). Default: every msg becomes a `\"msg\"` row\n * tagged with `msg.type` (or `String(msg)` if it has no `type`). The substrate\n * uses `type` as the Msg discriminant — using `_tag` here would render every\n * Msg as `[object Object]` in the inspector.\n *\n * `max` caps the buffer — oldest entries fall off (LIFO, newest first).\n *\n * `now` is the timestamp source for the default `derive`. Defaults to\n * `nowTs` (real wall-clock). Tests inject a deterministic shim so\n * snapshots don't drift; production code never sets it.\n */\nexport function useMsgHistory<M>(\n dispatch: (msg: M) => void | Promise<void>,\n opts: {\n max?: number;\n derive?: (msg: M) => MsgLogEntry;\n now?: () => string;\n } = {},\n): readonly [readonly MsgLogEntry[], (msg: M) => void, () => void] {\n const max = opts.max ?? 60;\n const now = opts.now ?? nowTs;\n const derive =\n opts.derive ??\n ((msg: M): MsgLogEntry => {\n const tag =\n msg && typeof msg === \"object\" && \"type\" in msg\n ? String((msg as { type: unknown }).type)\n : String(msg);\n return { ts: now(), kind: \"msg\", text: tag };\n });\n\n const [history, setHistory] = useState<readonly MsgLogEntry[]>([]);\n // Stable ref to `dispatch` so the wrapper identity stays stable across\n // renders — important when this is passed to keyboard handlers and the like.\n const dispatchRef = useRef(dispatch);\n dispatchRef.current = dispatch;\n const deriveRef = useRef(derive);\n deriveRef.current = derive;\n\n const wrapped = useCallback(\n (msg: M) => {\n const entry = deriveRef.current(msg);\n setHistory((prev) => [entry, ...prev].slice(0, max));\n // Fire-and-forget — `dispatch` may return a Promise; we don't await it\n // here because callers historically treat dispatch as void.\n void dispatchRef.current(msg);\n },\n [max],\n );\n\n const clear = useCallback(() => setHistory([]), []);\n\n return [history, wrapped, clear] as const;\n}\n"]}
|
package/dist/do/index.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { S as Store, b as BootedRunHandle, E as EngineRun,
|
|
2
|
-
import { P as PendingEffectsRecorder, b as EffectOwed, a as EffectConfirmed } from '../durable-effects-
|
|
3
|
-
export { D as DeliveryId, E as EffectLedgerEvent, O as OwedEffect, c as PendingEffectsLedger, d as applyEffectEvent, e as emptyLedger, f as foldLedger, i as isOwed, p as pendingEffectsLedger, s as survivingEffects } from '../durable-effects-
|
|
1
|
+
import { S as Store, b as BootedRunHandle, E as EngineRun, d as RunHandle, M as Migrated, F as FencedStore, D as DeletableStore } from '../runtime-types-DEluQgGO.js';
|
|
2
|
+
import { P as PendingEffectsRecorder, b as EffectOwed, a as EffectConfirmed } from '../durable-effects-Ump5lSdO.js';
|
|
3
|
+
export { D as DeliveryId, E as EffectLedgerEvent, O as OwedEffect, c as PendingEffectsLedger, d as applyEffectEvent, e as emptyLedger, f as foldLedger, i as isOwed, p as pendingEffectsLedger, s as survivingEffects } from '../durable-effects-Ump5lSdO.js';
|
|
4
4
|
import { RetryPolicy, Rng } from '../retry-backoff/index.js';
|
|
5
|
-
import { C as Cmd,
|
|
6
|
-
import { A as AgentEvent, f as AgentTurn, e as AgentState, i as AgentMachineMsg, K as AgentStatus } from '../machine-
|
|
5
|
+
import { C as Cmd, S as Sub, M as Machine, W as Wired } from '../core-CtvAyPpH.js';
|
|
6
|
+
import { A as AgentEvent, f as AgentTurn, e as AgentState, i as AgentMachineMsg, K as AgentStatus } from '../machine-Dtre2TmN.js';
|
|
7
7
|
import '@standard-schema/spec';
|
|
8
|
-
import '../index-
|
|
9
|
-
import '../index-
|
|
10
|
-
import '../index-
|
|
11
|
-
import '../types-
|
|
12
|
-
import '../index-
|
|
13
|
-
import '../index-
|
|
8
|
+
import '../index-CZZ3HI-Z.js';
|
|
9
|
+
import '../index-Bk2hBUdK.js';
|
|
10
|
+
import '../index-CVU7SK3a.js';
|
|
11
|
+
import '../types-CXNzlbAg.js';
|
|
12
|
+
import '../index-D3NY3VCN.js';
|
|
13
|
+
import '../index-CKtEKGyp.js';
|
|
14
14
|
import '../protocol-ClRZBhHQ.js';
|
|
15
|
-
import '../index-
|
|
15
|
+
import '../index-CrcoVfd_.js';
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* @demlik/tea/do — `stepHost`, the HTTP-PULL control carrier (#92).
|
package/dist/do/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { status, agentBootMsg, AGENT_EVENT_TYPES, agentEvents } from '../chunk-
|
|
2
|
-
import { createIntake } from '../chunk-
|
|
1
|
+
import { status, agentBootMsg, AGENT_EVENT_TYPES, agentEvents } from '../chunk-2774I242.js';
|
|
2
|
+
import { createIntake } from '../chunk-NGYFBD5G.js';
|
|
3
3
|
export { applyEffectEvent, emptyLedger, foldLedger, isOwed, pendingEffectsLedger, survivingEffects } from '../chunk-6IQPODUF.js';
|
|
4
|
-
import '../chunk-
|
|
5
|
-
import '../chunk-
|
|
4
|
+
import '../chunk-EA47MI5Q.js';
|
|
5
|
+
import '../chunk-2R62Q5UK.js';
|
|
6
6
|
import '../chunk-QNGYQMZB.js';
|
|
7
|
-
import '../chunk-
|
|
8
|
-
import '../chunk-
|
|
7
|
+
import '../chunk-72CN3VPY.js';
|
|
8
|
+
import '../chunk-TAKPC6SD.js';
|
|
9
9
|
import { defaultRetryPolicy, initRetry, recordFailure, shouldRetry, nextDelayMs } from '../chunk-VBDU4JL6.js';
|
|
10
10
|
import '../chunk-PR6TB3BL.js';
|
|
11
11
|
import '../chunk-4LPY67E4.js';
|
|
12
12
|
import '../chunk-TXN2KFHF.js';
|
|
13
|
-
import '../chunk-
|
|
14
|
-
import '../chunk-
|
|
15
|
-
import '../chunk-
|
|
16
|
-
import '../chunk-
|
|
17
|
-
import { StoreConflictError, replay } from '../chunk-
|
|
13
|
+
import '../chunk-JAKM53JF.js';
|
|
14
|
+
import '../chunk-UHAQ4PI6.js';
|
|
15
|
+
import '../chunk-A73IJ27X.js';
|
|
16
|
+
import '../chunk-DVNXEB7V.js';
|
|
17
|
+
import { StoreConflictError, replay } from '../chunk-RKVUVALV.js';
|
|
18
18
|
|
|
19
19
|
// src/do/durable-timer.ts
|
|
20
20
|
function durableTimer(config) {
|