@typeonce/effect-machine 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -64
- package/dist/Machine.d.ts +139 -272
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +3 -49
- package/dist/Machine.js.map +1 -1
- package/dist/internal/machine/invocation.d.ts.map +1 -1
- package/dist/internal/machine/invocation.js +1 -1
- package/dist/internal/machine/invocation.js.map +1 -1
- package/dist/internal/machine/machine.d.ts.map +1 -1
- package/dist/internal/machine/machine.js +48 -10
- package/dist/internal/machine/machine.js.map +1 -1
- package/dist/testing/MachineTest.d.ts +4 -4
- package/dist/testing/MachineTest.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.d.ts +1 -1
- package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
- package/docs/agent-guide.md +106 -67
- package/package.json +1 -1
- package/src/Machine.ts +552 -1040
- package/src/internal/machine/invocation.ts +1 -1
- package/src/internal/machine/machine.ts +64 -8
- package/src/internal/testing/machine/exploration.ts +1 -1
- package/src/internal/testing/machine/trace.ts +1 -1
- package/src/internal/testing/machine/verification.ts +1 -1
- package/src/testing/MachineTest.ts +4 -4
- package/src/unstable/reactivity/AtomMachine.ts +1 -1
package/README.md
CHANGED
|
@@ -122,7 +122,10 @@ Keep one-off topology inline in `Machine.states`. Use `Machine.state` only when
|
|
|
122
122
|
the same active state definition is mounted more than once; tagged schemas are
|
|
123
123
|
already reusable without it. For repeated finite regions, derive names with
|
|
124
124
|
`States.path(...)` so every literal in the path family is checked against the
|
|
125
|
-
complete tree. Type full-snapshot helpers as `Machine.Snapshot<typeof States
|
|
125
|
+
complete tree. Type full-snapshot helpers as `Machine.Snapshot<typeof States>`
|
|
126
|
+
or `Machine.Snapshot<typeof machine>`, schema-backed state payloads as
|
|
127
|
+
`Machine.Value<typeof States, Path>`, and path-rooted snapshots as
|
|
128
|
+
`Machine.SnapshotAt<typeof States, Path>`.
|
|
126
129
|
|
|
127
130
|
### Construct state through builders
|
|
128
131
|
|
|
@@ -437,37 +440,35 @@ arbitrary asynchronous Effects do not run inside planning.
|
|
|
437
440
|
State-scoped work starts on entry and is interrupted on exit:
|
|
438
441
|
|
|
439
442
|
```ts
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
onDone: (to) => to.full.Failed().resolve(({ target }) => target.from({ message: "Timed out" }))
|
|
454
|
-
})
|
|
455
|
-
}
|
|
443
|
+
machine.handle({
|
|
444
|
+
Loading: {
|
|
445
|
+
invoke: (from) =>
|
|
446
|
+
from.effect("save-document", () => saveDocument)
|
|
447
|
+
.onDone((to) => to.full.Saved().resolve(({ output, target }) => target.from({ id: output.id })))
|
|
448
|
+
.onFailure((to) => to.full.Failed().resolve(({ error, target }) => target.from({ message: String(error) })))
|
|
449
|
+
},
|
|
450
|
+
Waiting: {
|
|
451
|
+
invoke: (from) =>
|
|
452
|
+
from.timer("save-timeout", "3 seconds")
|
|
453
|
+
.onDone((to) => to.full.Failed().resolve(({ target }) => target.from({ message: "Timed out" })))
|
|
454
|
+
}
|
|
455
|
+
})
|
|
456
456
|
```
|
|
457
457
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
for state-dependent Effects:
|
|
458
|
+
The state-local `from` selector starts an `effect`, `stream`, `timer`, reusable
|
|
459
|
+
`logic`, or complete `child` statechart. The selected source determines which
|
|
460
|
+
lifecycle methods the chain requires and which methods are available. For
|
|
461
|
+
example, an Effect with non-`never` output and error channels must handle both;
|
|
462
|
+
the completed chain is the value returned by the callback:
|
|
464
463
|
|
|
465
464
|
```ts
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
465
|
+
machine.handle({
|
|
466
|
+
Loading: {
|
|
467
|
+
invoke: (from) =>
|
|
468
|
+
from.effect("load-document", ({ state }) => loadDocument(state.documentId))
|
|
469
|
+
.onDone((to) => to.full.Ready().resolve(({ output, target }) => target.from({ document: output })))
|
|
470
|
+
.onFailure((to) => to.full.Failed().resolve(({ error, target }) => target.from({ message: error.message })))
|
|
471
|
+
}
|
|
471
472
|
})
|
|
472
473
|
```
|
|
473
474
|
|
|
@@ -476,15 +477,18 @@ is mapped by `onElement`, and the next element is not pulled until that parent
|
|
|
476
477
|
macrostep commits:
|
|
477
478
|
|
|
478
479
|
```ts
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
480
|
+
machine.handle({
|
|
481
|
+
Listening: {
|
|
482
|
+
invoke: (from) =>
|
|
483
|
+
from.stream("channel", () => channelMessages)
|
|
484
|
+
.onElement((to) =>
|
|
485
|
+
to.none.resolve(({ element }, enqueue) => {
|
|
486
|
+
enqueue.raise(Events.MessageReceived({ message: element }))
|
|
487
|
+
})
|
|
488
|
+
)
|
|
489
|
+
.onDone((to) => to.none)
|
|
490
|
+
.onFailure((to) => to.full.Failed().resolve(({ error, target }) => target.from({ error })))
|
|
491
|
+
}
|
|
488
492
|
})
|
|
489
493
|
```
|
|
490
494
|
|
|
@@ -493,10 +497,10 @@ current configuration, or call `.resolve(...)` when the transition only needs
|
|
|
493
497
|
to enqueue commands. A block resolver may omit its return because it is
|
|
494
498
|
contextually typed to return `undefined`.
|
|
495
499
|
|
|
496
|
-
Inside `.handle(...)`, `
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
+
Inside `.handle(...)`, `from` receives the owning machine's public input and
|
|
501
|
+
declared parent protocol contextually. Source and lifecycle callbacks can send
|
|
502
|
+
through `self` and `parent` while retaining the invoked Effect's output and
|
|
503
|
+
error inference:
|
|
500
504
|
|
|
501
505
|
```ts
|
|
502
506
|
const machine = Machine.make({
|
|
@@ -506,36 +510,47 @@ const machine = Machine.make({
|
|
|
506
510
|
// ...
|
|
507
511
|
}).handle({
|
|
508
512
|
Saving: {
|
|
509
|
-
invoke:
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
})
|
|
513
|
+
invoke: (from) =>
|
|
514
|
+
from.effect("notify-parent", () => saveDocument)
|
|
515
|
+
.onDone((to) =>
|
|
516
|
+
to.none.resolve(({ parent, self }, enqueue) => {
|
|
517
|
+
enqueue.sendTo(self, Commands.Save())
|
|
518
|
+
enqueue.sendTo(parent, ParentEvents.ChildFinished({ id: "job-1" }))
|
|
519
|
+
})
|
|
520
|
+
)
|
|
521
|
+
.onFailure((to) => to.none)
|
|
519
522
|
}
|
|
520
523
|
})
|
|
521
524
|
```
|
|
522
525
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
+
Return an array of completed chains to compose multiple state-owned activities.
|
|
527
|
+
The source computation itself, process logic, or `Machine.child(id, machine)`
|
|
528
|
+
descriptor can be named and reused; the invocation chain stays local so its
|
|
529
|
+
transitions retain the exact owning state and machine protocols.
|
|
526
530
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
+
```ts
|
|
532
|
+
const refreshCache = Cache.refresh
|
|
533
|
+
|
|
534
|
+
machine.handle({
|
|
535
|
+
Active: {
|
|
536
|
+
invoke: (from) => [
|
|
537
|
+
from.effect("refresh-cache", () => refreshCache).onDone((to) => to.none).onFailure((to) => to.none),
|
|
538
|
+
from.timer("expire-session", "5 minutes").onDone((to) => to.full.Expired())
|
|
539
|
+
]
|
|
540
|
+
}
|
|
541
|
+
})
|
|
542
|
+
```
|
|
531
543
|
|
|
532
544
|
`onDone` is required for a non-`never` output, and `onFailure` is required for a
|
|
533
|
-
non-`never` typed error
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
545
|
+
non-`never` typed error. Streams additionally require `onElement` when their
|
|
546
|
+
element channel is non-`never` and always require `onDone`; logic and child
|
|
547
|
+
chains optionally expose `onSnapshot`. A handled method disappears from the
|
|
548
|
+
next builder step, so every reachable lifecycle channel is handled exactly
|
|
549
|
+
once. Defects, interruption, and source-construction failures terminate the
|
|
550
|
+
owning runtime. Effect sources are factories evaluated when their state is
|
|
551
|
+
entered. Use an Effect containing `Effect.sleep(...)` for generic work, while
|
|
552
|
+
`from.timer(...)` keeps timer intent explicit and makes static durations visible
|
|
553
|
+
through activity inspection.
|
|
539
554
|
|
|
540
555
|
## Reactivity
|
|
541
556
|
|