@typeonce/effect-machine 0.5.1 → 0.6.1
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 +1 -1
- package/package.json +8 -8
- package/src/Machine.ts +6873 -0
- package/src/index.ts +1 -0
- package/src/internal/machine/activities.ts +108 -0
- package/src/internal/machine/atom.ts +636 -0
- package/src/internal/machine/cluster.ts +394 -0
- package/src/internal/machine/command.ts +58 -0
- package/src/internal/machine/commandRuntime.ts +43 -0
- package/src/internal/machine/configuration.ts +1331 -0
- package/src/internal/machine/errors.ts +87 -0
- package/src/internal/machine/executionPlan.ts +996 -0
- package/src/internal/machine/invocation.ts +119 -0
- package/src/internal/machine/machine.ts +1747 -0
- package/src/internal/machine/planner.ts +1933 -0
- package/src/internal/machine/process.ts +906 -0
- package/src/internal/machine/protocol.ts +322 -0
- package/src/internal/machine/readiness.ts +10 -0
- package/src/internal/machine/runtime.ts +2512 -0
- package/src/internal/machine/serialization.ts +498 -0
- package/src/internal/machine/stateDefinition.ts +270 -0
- package/src/internal/machine/symbols.ts +2 -0
- package/src/internal/machine/topology.ts +479 -0
- package/src/internal/testing/machine/arbitrary.ts +102 -0
- package/src/internal/testing/machine/exploration.ts +331 -0
- package/src/internal/testing/machine/finiteModel.ts +1498 -0
- package/src/internal/testing/machine/invariant.ts +372 -0
- package/src/internal/testing/machine/probe.ts +79 -0
- package/src/internal/testing/machine/referenceModel.ts +1505 -0
- package/src/internal/testing/machine/runtime.ts +1710 -0
- package/src/internal/testing/machine/runtimeInvariant.ts +486 -0
- package/src/internal/testing/machine/trace.ts +150 -0
- package/src/internal/testing/machine/verification.ts +1890 -0
- package/src/testing/MachineTest.ts +2067 -0
- package/src/testing/index.ts +7 -0
- package/src/unstable/cluster/ClusterMachine.ts +390 -0
- package/src/unstable/cluster/index.ts +1 -0
- package/src/unstable/reactivity/AtomMachine.ts +649 -0
- package/src/unstable/reactivity/index.ts +1 -0
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atom bridge for running machines.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.4.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type * as Option from "effect/Option"
|
|
8
|
+
import type * as Schema from "effect/Schema"
|
|
9
|
+
import type * as Scope from "effect/Scope"
|
|
10
|
+
import type { AsyncResult, Atom, AtomRegistry } from "effect/unstable/reactivity"
|
|
11
|
+
import * as internal from "../../internal/machine/atom.js"
|
|
12
|
+
import type { ChildNotActiveError, NotReadyError } from "../../internal/machine/atom.js"
|
|
13
|
+
import type { EnsureExecutable } from "../../internal/machine/readiness.js"
|
|
14
|
+
import type * as Machine from "../../Machine.js"
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Error returned when a machine command is issued before startup completes.
|
|
18
|
+
*
|
|
19
|
+
* @category errors
|
|
20
|
+
* @since 0.4.0
|
|
21
|
+
*/
|
|
22
|
+
export { NotReadyError } from "../../internal/machine/atom.js"
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Error returned when a command targets a child machine that is not active.
|
|
26
|
+
*
|
|
27
|
+
* @category errors
|
|
28
|
+
* @since 0.4.0
|
|
29
|
+
*/
|
|
30
|
+
export { ChildNotActiveError } from "../../internal/machine/atom.js"
|
|
31
|
+
|
|
32
|
+
type AtomSupportedRequirements = Scope.Scope | AtomRegistry.AtomRegistry
|
|
33
|
+
|
|
34
|
+
type ExternalRequirements<Requirements> = Exclude<Requirements, AtomSupportedRequirements>
|
|
35
|
+
|
|
36
|
+
const ExternalRequirementsTypeId = "~effect/reactivity/AtomMachine/ExternalRequirements"
|
|
37
|
+
|
|
38
|
+
type EnsureNoExternalRequirements<Requirements> = [ExternalRequirements<Requirements>] extends [never] ? unknown : {
|
|
39
|
+
readonly [ExternalRequirementsTypeId]: ExternalRequirements<Requirements>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type IsAny<A> = 0 extends (1 & A) ? true : false
|
|
43
|
+
|
|
44
|
+
type ExcludeCompatibleMachineRuntime<Requirements, Events, Emits> = Requirements extends
|
|
45
|
+
Machine.Runtime.Requirement<infer RequiredEvents, infer RequiredEmits> ?
|
|
46
|
+
IsAny<Requirements> extends true ? Requirements
|
|
47
|
+
: [RequiredEvents] extends [Events] ? [RequiredEmits] extends [Emits] ? never : Requirements
|
|
48
|
+
: Requirements
|
|
49
|
+
: Requirements
|
|
50
|
+
|
|
51
|
+
type MachineRequirements<InitialR, R, Events, Emits> = ExcludeCompatibleMachineRuntime<
|
|
52
|
+
Machine.ExecutionServices<InitialR | R>,
|
|
53
|
+
Events,
|
|
54
|
+
Emits
|
|
55
|
+
>
|
|
56
|
+
|
|
57
|
+
type MachineResumeRequirements<R, Events, Emits> = ExcludeCompatibleMachineRuntime<
|
|
58
|
+
Machine.ExecutionServices<R>,
|
|
59
|
+
Events,
|
|
60
|
+
Emits
|
|
61
|
+
>
|
|
62
|
+
|
|
63
|
+
type MachineRuntimeError<E, R> =
|
|
64
|
+
| E
|
|
65
|
+
| Machine.ActionError<R>
|
|
66
|
+
| Machine.InfiniteTransitionError
|
|
67
|
+
| Machine.MachineSchemaDecodeError
|
|
68
|
+
| Machine.StoppedError
|
|
69
|
+
|
|
70
|
+
type MachineStartError<InitialE, E, InitialR, R, RuntimeError = never> =
|
|
71
|
+
| InitialE
|
|
72
|
+
| E
|
|
73
|
+
| Machine.ActionError<InitialR | R>
|
|
74
|
+
| Machine.InfiniteTransitionError
|
|
75
|
+
| Machine.MachineSchemaDecodeError
|
|
76
|
+
| Machine.StartupError
|
|
77
|
+
| Machine.StoppedError
|
|
78
|
+
| RuntimeError
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Atoms backed by one running machine instance in an `AtomRegistry`.
|
|
82
|
+
*
|
|
83
|
+
* **Details**
|
|
84
|
+
*
|
|
85
|
+
* The machine starts when one of the returned atoms is mounted or read in
|
|
86
|
+
* a registry, and it is stopped when the registry disposes the ref atom. The
|
|
87
|
+
* same atom values share one running machine per registry.
|
|
88
|
+
*
|
|
89
|
+
* @category models
|
|
90
|
+
* @since 0.4.0
|
|
91
|
+
*/
|
|
92
|
+
export interface MachineAtom<State, Event, Error = never, Output = never, StartError = never> {
|
|
93
|
+
/**
|
|
94
|
+
* Atom containing the running machine handle once startup succeeds.
|
|
95
|
+
*
|
|
96
|
+
* @since 0.4.0
|
|
97
|
+
*/
|
|
98
|
+
readonly ref: Atom.Atom<
|
|
99
|
+
AsyncResult.AsyncResult<Machine.MachineRef<State, Event, Error, Output>, StartError>
|
|
100
|
+
>
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Atom containing the latest machine lifecycle snapshot.
|
|
104
|
+
*
|
|
105
|
+
* @since 0.4.0
|
|
106
|
+
*/
|
|
107
|
+
readonly snapshot: Atom.Atom<
|
|
108
|
+
AsyncResult.AsyncResult<Machine.RuntimeSnapshot<State, Error, Output>, StartError>
|
|
109
|
+
>
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Atom containing the state value from the latest runtime snapshot.
|
|
113
|
+
*
|
|
114
|
+
* This preserves the historical behavior of exposing a state even when the
|
|
115
|
+
* runtime snapshot reports a terminal error. Use `result` when runtime
|
|
116
|
+
* failures must be represented in the atom failure channel.
|
|
117
|
+
*
|
|
118
|
+
* @since 0.4.0
|
|
119
|
+
*/
|
|
120
|
+
readonly state: Atom.Atom<AsyncResult.AsyncResult<State, StartError>>
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Atom containing the current state, with startup and runtime failures in
|
|
124
|
+
* one typed failure channel.
|
|
125
|
+
*
|
|
126
|
+
* @since 0.4.0
|
|
127
|
+
*/
|
|
128
|
+
readonly result: Atom.Atom<AsyncResult.AsyncResult<State, StartError | Error>>
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Writable atom that sends events to the machine. Writes before startup
|
|
132
|
+
* completes fail with `NotReadyError`.
|
|
133
|
+
*
|
|
134
|
+
* @since 0.4.0
|
|
135
|
+
*/
|
|
136
|
+
readonly send: Atom.Writable<
|
|
137
|
+
AsyncResult.AsyncResult<void, StartError | NotReadyError | Machine.StoppedError>,
|
|
138
|
+
Event
|
|
139
|
+
>
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Writable atom that stops the machine. Writes before startup completes fail
|
|
143
|
+
* with `NotReadyError`.
|
|
144
|
+
*
|
|
145
|
+
* @since 0.4.0
|
|
146
|
+
*/
|
|
147
|
+
readonly stop: Atom.Writable<AsyncResult.AsyncResult<void, StartError | NotReadyError>, void>
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Creates a reactive bridge for a directly invoked child machine.
|
|
151
|
+
* Reusing the same descriptor returns the same live bridge while it remains
|
|
152
|
+
* referenced.
|
|
153
|
+
*
|
|
154
|
+
* @since 0.4.0
|
|
155
|
+
*/
|
|
156
|
+
readonly child: <Child extends Machine.ChildMachine.Any>(
|
|
157
|
+
child: Child
|
|
158
|
+
) => ChildMachineAtom<Child, StartError>
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
type RefState<Ref> = Ref extends Machine.MachineRef<infer State, any, any, any> ? State : never
|
|
162
|
+
|
|
163
|
+
type RefError<Ref> = Ref extends Machine.MachineRef<any, any, infer Error, any> ? Error : never
|
|
164
|
+
|
|
165
|
+
type RefOutput<Ref> = Ref extends Machine.MachineRef<any, any, any, infer Output> ? Output : never
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Reactive access to one invoked child machine selected by its descriptor.
|
|
169
|
+
*
|
|
170
|
+
* **Details**
|
|
171
|
+
*
|
|
172
|
+
* Each atom contains `Option.none()` while the state that owns the invocation
|
|
173
|
+
* is inactive or while the child is starting. It contains `Option.some(...)`
|
|
174
|
+
* for the current child instance and follows replacements after re-entry.
|
|
175
|
+
*
|
|
176
|
+
* **Gotchas**
|
|
177
|
+
*
|
|
178
|
+
* Lookup is direct-child scoped. Use `child` again on this bridge to reach a
|
|
179
|
+
* machine invoked by the selected child.
|
|
180
|
+
*
|
|
181
|
+
* @category models
|
|
182
|
+
* @since 0.4.0
|
|
183
|
+
*/
|
|
184
|
+
export interface ChildMachineAtom<Child extends Machine.ChildMachine.Any, StartError = unknown> {
|
|
185
|
+
/**
|
|
186
|
+
* Atom containing the current child reference when the child is active.
|
|
187
|
+
*
|
|
188
|
+
* @since 0.4.0
|
|
189
|
+
*/
|
|
190
|
+
readonly ref: Atom.Atom<
|
|
191
|
+
AsyncResult.AsyncResult<Option.Option<Machine.ChildMachine.Ref<Child>>, StartError>
|
|
192
|
+
>
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Atom containing the current child lifecycle snapshot when active.
|
|
196
|
+
*
|
|
197
|
+
* @since 0.4.0
|
|
198
|
+
*/
|
|
199
|
+
readonly snapshot: Atom.Atom<
|
|
200
|
+
AsyncResult.AsyncResult<
|
|
201
|
+
Option.Option<
|
|
202
|
+
Machine.RuntimeSnapshot<
|
|
203
|
+
RefState<Machine.ChildMachine.Ref<Child>>,
|
|
204
|
+
RefError<Machine.ChildMachine.Ref<Child>>,
|
|
205
|
+
RefOutput<Machine.ChildMachine.Ref<Child>>
|
|
206
|
+
>
|
|
207
|
+
>,
|
|
208
|
+
StartError
|
|
209
|
+
>
|
|
210
|
+
>
|
|
211
|
+
/**
|
|
212
|
+
* Atom containing the current child state when active.
|
|
213
|
+
*
|
|
214
|
+
* Runtime failures retain the last successful state. Use `result` when they
|
|
215
|
+
* must be represented in the atom failure channel.
|
|
216
|
+
*
|
|
217
|
+
* @since 0.4.0
|
|
218
|
+
*/
|
|
219
|
+
readonly state: Atom.Atom<
|
|
220
|
+
AsyncResult.AsyncResult<Option.Option<RefState<Machine.ChildMachine.Ref<Child>>>, StartError>
|
|
221
|
+
>
|
|
222
|
+
/**
|
|
223
|
+
* Atom containing the current child state when active, with startup and
|
|
224
|
+
* runtime failures in one typed failure channel.
|
|
225
|
+
*
|
|
226
|
+
* @since 0.4.0
|
|
227
|
+
*/
|
|
228
|
+
readonly result: Atom.Atom<
|
|
229
|
+
AsyncResult.AsyncResult<
|
|
230
|
+
Option.Option<RefState<Machine.ChildMachine.Ref<Child>>>,
|
|
231
|
+
StartError | RefError<Machine.ChildMachine.Ref<Child>>
|
|
232
|
+
>
|
|
233
|
+
>
|
|
234
|
+
/**
|
|
235
|
+
* Writable atom that sends events to the active child.
|
|
236
|
+
*
|
|
237
|
+
* Writes fail with `ChildNotActiveError` while the child is inactive.
|
|
238
|
+
*
|
|
239
|
+
* @since 0.4.0
|
|
240
|
+
*/
|
|
241
|
+
readonly send: Atom.Writable<
|
|
242
|
+
AsyncResult.AsyncResult<void, StartError | NotReadyError | ChildNotActiveError | Machine.StoppedError>,
|
|
243
|
+
Machine.ChildMachine.Event<Child>
|
|
244
|
+
>
|
|
245
|
+
/**
|
|
246
|
+
* Writable atom that stops the active child.
|
|
247
|
+
*
|
|
248
|
+
* Writes fail with `ChildNotActiveError` while the child is inactive.
|
|
249
|
+
*
|
|
250
|
+
* @since 0.4.0
|
|
251
|
+
*/
|
|
252
|
+
readonly stop: Atom.Writable<
|
|
253
|
+
AsyncResult.AsyncResult<void, StartError | NotReadyError | ChildNotActiveError>,
|
|
254
|
+
void
|
|
255
|
+
>
|
|
256
|
+
/**
|
|
257
|
+
* Creates a reactive bridge for a directly owned nested child. Reusing the
|
|
258
|
+
* same descriptor returns the same live bridge while it remains referenced.
|
|
259
|
+
*
|
|
260
|
+
* @since 0.4.0
|
|
261
|
+
*/
|
|
262
|
+
readonly child: <Nested extends Machine.ChildMachine.Any>(
|
|
263
|
+
child: Nested
|
|
264
|
+
) => ChildMachineAtom<Nested, StartError>
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
type BridgeStartError<Bridge> = Bridge extends MachineAtom<any, any, any, any, infer StartError> ? StartError
|
|
268
|
+
: Bridge extends ChildMachineAtom<any, infer StartError> ? StartError
|
|
269
|
+
: never
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Derives the exact child bridge type from a parent bridge and child
|
|
273
|
+
* descriptor.
|
|
274
|
+
*
|
|
275
|
+
* @category utility types
|
|
276
|
+
* @since 0.4.0
|
|
277
|
+
*/
|
|
278
|
+
export type ChildOf<
|
|
279
|
+
Parent extends MachineAtom<any, any, any, any, any> | ChildMachineAtom<any, any>,
|
|
280
|
+
Child extends Machine.ChildMachine.Any
|
|
281
|
+
> = ChildMachineAtom<Child, BridgeStartError<Parent>>
|
|
282
|
+
|
|
283
|
+
type SnapshotNode<State> = State extends Machine.Machine.AtomicSnapshot<string, unknown> ?
|
|
284
|
+
| State
|
|
285
|
+
| (State extends { readonly state: infer Child } ? SnapshotNode<Child>
|
|
286
|
+
: State extends { readonly states: infer Regions } ? SnapshotNode<Regions[keyof Regions]>
|
|
287
|
+
: never)
|
|
288
|
+
: never
|
|
289
|
+
|
|
290
|
+
type SnapshotIdentifier<State> = SnapshotNode<State> extends infer Node ?
|
|
291
|
+
Node extends { readonly path: infer Path extends string } ? Path : never
|
|
292
|
+
: never
|
|
293
|
+
|
|
294
|
+
type SnapshotValueByIdentifier<State, Path extends SnapshotIdentifier<State>> = SnapshotNode<State> extends infer Node ?
|
|
295
|
+
Node extends { readonly path: Path; readonly value: infer Value } ? Value : never
|
|
296
|
+
: never
|
|
297
|
+
|
|
298
|
+
type ChildState<Child extends Machine.ChildMachine.Any> = RefState<Machine.ChildMachine.Ref<Child>>
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Selects the typed value for an active state path.
|
|
302
|
+
*
|
|
303
|
+
* Valid paths and their selected value types are inferred from the bridge.
|
|
304
|
+
* The derived atom suppresses structurally equal updates. Keep the returned
|
|
305
|
+
* atom stable when constructing it inside a component.
|
|
306
|
+
*
|
|
307
|
+
* **Example**
|
|
308
|
+
*
|
|
309
|
+
* ```ts
|
|
310
|
+
* import { Schema } from "effect"
|
|
311
|
+
* import { Machine } from "@typeonce/effect-machine"
|
|
312
|
+
* import { AtomMachine } from "@typeonce/effect-machine/reactivity"
|
|
313
|
+
*
|
|
314
|
+
* class Count extends Schema.TaggedClass<Count>("Count")("Count", {
|
|
315
|
+
* value: Schema.Number
|
|
316
|
+
* }) {}
|
|
317
|
+
* const States = Machine.defineStates({ Count })
|
|
318
|
+
* const machine = Machine.make({
|
|
319
|
+
* states: States.states,
|
|
320
|
+
* events: [],
|
|
321
|
+
* initial: () => States.initial.Count(new Count({ value: 0 }))
|
|
322
|
+
* }).handle({ Count: {} })
|
|
323
|
+
* const machineAtom = AtomMachine.make(machine)
|
|
324
|
+
*
|
|
325
|
+
* const countAtom = AtomMachine.select(machineAtom, "Count")
|
|
326
|
+
* ```
|
|
327
|
+
*
|
|
328
|
+
* @category combinators
|
|
329
|
+
* @since 0.4.0
|
|
330
|
+
*/
|
|
331
|
+
export const select: <
|
|
332
|
+
State extends Machine.Machine.AtomicSnapshot<string, unknown>,
|
|
333
|
+
Event,
|
|
334
|
+
Error,
|
|
335
|
+
Output,
|
|
336
|
+
StartError,
|
|
337
|
+
const Path extends SnapshotIdentifier<State>
|
|
338
|
+
>(self: MachineAtom<State, Event, Error, Output, StartError>, path: Path) => Atom.Atom<
|
|
339
|
+
AsyncResult.AsyncResult<Option.Option<SnapshotValueByIdentifier<State, Path>>, StartError | Error>
|
|
340
|
+
> = internal.select
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Selects the typed value for an active state path in an invoked child.
|
|
344
|
+
*
|
|
345
|
+
* Valid paths and their selected value types are inferred from the child
|
|
346
|
+
* bridge. An inactive child produces `Option.none()`. Keep the returned atom
|
|
347
|
+
* stable when constructing it inside a component.
|
|
348
|
+
*
|
|
349
|
+
* **Example**
|
|
350
|
+
*
|
|
351
|
+
* ```ts
|
|
352
|
+
* const editingAtom = AtomMachine.selectChild(editorAtom, "Editing")
|
|
353
|
+
* // Atom<AsyncResult<Option<Editing>, StartError | ChildRuntimeError>>
|
|
354
|
+
* ```
|
|
355
|
+
*
|
|
356
|
+
* @category combinators
|
|
357
|
+
* @since 0.4.0
|
|
358
|
+
*/
|
|
359
|
+
export const selectChild: <
|
|
360
|
+
Child extends Machine.ChildMachine.Any,
|
|
361
|
+
StartError,
|
|
362
|
+
const Path extends SnapshotIdentifier<ChildState<Child>>
|
|
363
|
+
>(self: ChildMachineAtom<Child, StartError>, path: Path) => Atom.Atom<
|
|
364
|
+
AsyncResult.AsyncResult<
|
|
365
|
+
Option.Option<SnapshotValueByIdentifier<ChildState<Child>, Path>>,
|
|
366
|
+
StartError | RefError<Machine.ChildMachine.Ref<Child>>
|
|
367
|
+
>
|
|
368
|
+
> = internal.selectChild
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Returns whether a state path is active.
|
|
372
|
+
*
|
|
373
|
+
* Valid paths are inferred from the bridge snapshot.
|
|
374
|
+
* The derived atom suppresses equal updates. Runtime failures remain in the
|
|
375
|
+
* typed failure channel.
|
|
376
|
+
*
|
|
377
|
+
* **Example**
|
|
378
|
+
*
|
|
379
|
+
* ```ts
|
|
380
|
+
* import { Schema } from "effect"
|
|
381
|
+
* import { Machine } from "@typeonce/effect-machine"
|
|
382
|
+
* import { AtomMachine } from "@typeonce/effect-machine/reactivity"
|
|
383
|
+
*
|
|
384
|
+
* class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
|
|
385
|
+
* const States = Machine.defineStates({ Idle })
|
|
386
|
+
* const machine = Machine.make({
|
|
387
|
+
* states: States.states,
|
|
388
|
+
* events: [],
|
|
389
|
+
* initial: () => States.initial.Idle.from()
|
|
390
|
+
* }).handle({ Idle: {} })
|
|
391
|
+
* const machineAtom = AtomMachine.make(machine)
|
|
392
|
+
*
|
|
393
|
+
* const isIdleAtom = AtomMachine.matches(machineAtom, "Idle")
|
|
394
|
+
* ```
|
|
395
|
+
*
|
|
396
|
+
* @category combinators
|
|
397
|
+
* @since 0.4.0
|
|
398
|
+
*/
|
|
399
|
+
export const matches: <
|
|
400
|
+
State extends Machine.Machine.AtomicSnapshot<string, unknown>,
|
|
401
|
+
Event,
|
|
402
|
+
Error,
|
|
403
|
+
Output,
|
|
404
|
+
StartError,
|
|
405
|
+
const Path extends SnapshotIdentifier<State>
|
|
406
|
+
>(
|
|
407
|
+
self: MachineAtom<State, Event, Error, Output, StartError>,
|
|
408
|
+
path: Path
|
|
409
|
+
) => Atom.Atom<AsyncResult.AsyncResult<boolean, StartError | Error>> = internal.matches
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Returns whether a state path is active in an invoked child.
|
|
413
|
+
*
|
|
414
|
+
* Valid paths are inferred from the child bridge snapshot.
|
|
415
|
+
* An inactive child produces `false`. Keep the returned atom stable when
|
|
416
|
+
* constructing it inside a component.
|
|
417
|
+
*
|
|
418
|
+
* @category combinators
|
|
419
|
+
* @since 0.4.0
|
|
420
|
+
*/
|
|
421
|
+
export const matchesChild: <
|
|
422
|
+
Child extends Machine.ChildMachine.Any,
|
|
423
|
+
StartError,
|
|
424
|
+
const Path extends SnapshotIdentifier<ChildState<Child>>
|
|
425
|
+
>(self: ChildMachineAtom<Child, StartError>, path: Path) => Atom.Atom<
|
|
426
|
+
AsyncResult.AsyncResult<boolean, StartError | RefError<Machine.ChildMachine.Ref<Child>>>
|
|
427
|
+
> = internal.matchesChild
|
|
428
|
+
|
|
429
|
+
const BoundRequirementsTypeId = "~effect/reactivity/AtomMachine/BoundRequirements"
|
|
430
|
+
|
|
431
|
+
type MachineRequirementsOf<M extends Machine.Machine.Any> = MachineRequirements<
|
|
432
|
+
Machine.Machine.InitialServices<M>,
|
|
433
|
+
Machine.Machine.Services<M>,
|
|
434
|
+
Machine.Machine.Event<M>,
|
|
435
|
+
Machine.Machine.Emit<M>
|
|
436
|
+
>
|
|
437
|
+
|
|
438
|
+
type MissingBoundRequirements<Services, M extends Machine.Machine.Any> = Exclude<
|
|
439
|
+
ExternalRequirements<MachineRequirementsOf<M>>,
|
|
440
|
+
Services
|
|
441
|
+
>
|
|
442
|
+
|
|
443
|
+
type EnsureBoundRequirements<Services, M extends Machine.Machine.Any> = IsAny<MachineRequirementsOf<M>> extends true ? {
|
|
444
|
+
readonly [BoundRequirementsTypeId]: MachineRequirementsOf<M>
|
|
445
|
+
}
|
|
446
|
+
: [MissingBoundRequirements<Services, M>] extends [never] ? unknown
|
|
447
|
+
: {
|
|
448
|
+
readonly [BoundRequirementsTypeId]: MissingBoundRequirements<Services, M>
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
type MachineResumeRequirementsOf<M extends Machine.Machine.Any> = MachineResumeRequirements<
|
|
452
|
+
Machine.Machine.Services<M>,
|
|
453
|
+
Machine.Machine.Event<M>,
|
|
454
|
+
Machine.Machine.Emit<M>
|
|
455
|
+
>
|
|
456
|
+
|
|
457
|
+
type MissingBoundResumeRequirements<Services, M extends Machine.Machine.Any> = Exclude<
|
|
458
|
+
ExternalRequirements<MachineResumeRequirementsOf<M>>,
|
|
459
|
+
Services
|
|
460
|
+
>
|
|
461
|
+
|
|
462
|
+
type EnsureBoundResumeRequirements<Services, M extends Machine.Machine.Any> =
|
|
463
|
+
IsAny<MachineResumeRequirementsOf<M>> extends true ? {
|
|
464
|
+
readonly [BoundRequirementsTypeId]: MachineResumeRequirementsOf<M>
|
|
465
|
+
}
|
|
466
|
+
: [MissingBoundResumeRequirements<Services, M>] extends [never] ? unknown
|
|
467
|
+
: {
|
|
468
|
+
readonly [BoundRequirementsTypeId]: MissingBoundResumeRequirements<Services, M>
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
type EnsureMachineExecutable<M extends Machine.Machine.Any> = IsAny<Machine.Machine.States<M>> extends true ? {
|
|
472
|
+
readonly "~effect/reactivity/AtomMachine/ConcreteMachineRequired": M
|
|
473
|
+
}
|
|
474
|
+
: EnsureExecutable<
|
|
475
|
+
Machine.Machine.States<M>,
|
|
476
|
+
Machine.Machine.UnhandledStates<M>,
|
|
477
|
+
Machine.Machine.OutputStates<M>
|
|
478
|
+
>
|
|
479
|
+
|
|
480
|
+
type MachineInputArgsOf<M extends Machine.Machine.Any> = [
|
|
481
|
+
...Machine.Machine.InputArgs<Machine.Machine.Input<M>>
|
|
482
|
+
]
|
|
483
|
+
|
|
484
|
+
type MachineAtomOf<M extends Machine.Machine.Any, RuntimeError> = MachineAtom<
|
|
485
|
+
Machine.Machine.Snapshot<Machine.Machine.States<M>>,
|
|
486
|
+
Machine.Machine.InputEvent<M>,
|
|
487
|
+
MachineRuntimeError<Machine.Machine.Error<M>, Machine.Machine.Services<M>>,
|
|
488
|
+
Machine.Machine.Output<M>,
|
|
489
|
+
MachineStartError<
|
|
490
|
+
Machine.Machine.InitialError<M>,
|
|
491
|
+
Machine.Machine.Error<M>,
|
|
492
|
+
Machine.Machine.InitialServices<M>,
|
|
493
|
+
Machine.Machine.Services<M>,
|
|
494
|
+
RuntimeError
|
|
495
|
+
>
|
|
496
|
+
>
|
|
497
|
+
|
|
498
|
+
type ResumedMachineAtomOf<M extends Machine.Machine.Any, RuntimeError> = MachineAtom<
|
|
499
|
+
Machine.Machine.Snapshot<Machine.Machine.States<M>>,
|
|
500
|
+
Machine.Machine.InputEvent<M>,
|
|
501
|
+
MachineRuntimeError<Machine.Machine.Error<M>, Machine.Machine.Services<M>>,
|
|
502
|
+
Machine.Machine.Output<M>,
|
|
503
|
+
Machine.MachineSchemaDecodeError | RuntimeError
|
|
504
|
+
>
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* An `AtomMachine` factory with one owned Effect runtime.
|
|
508
|
+
*
|
|
509
|
+
* @category models
|
|
510
|
+
* @since 0.4.0
|
|
511
|
+
*/
|
|
512
|
+
export interface Bound<Services, RuntimeError = never> {
|
|
513
|
+
/**
|
|
514
|
+
* Creates an independent machine bridge using the bound runtime.
|
|
515
|
+
*
|
|
516
|
+
* The machine's external service requirements must be provided by the
|
|
517
|
+
* runtime. Machine-native runtime requirements are supplied automatically.
|
|
518
|
+
*
|
|
519
|
+
* @since 0.4.0
|
|
520
|
+
*/
|
|
521
|
+
readonly make: <M extends Machine.Machine.Any>(
|
|
522
|
+
machine:
|
|
523
|
+
& M
|
|
524
|
+
& EnsureBoundRequirements<Services, NoInfer<M>>
|
|
525
|
+
& EnsureMachineExecutable<NoInfer<M>>,
|
|
526
|
+
...args: MachineInputArgsOf<M>
|
|
527
|
+
) => MachineAtomOf<M, RuntimeError>
|
|
528
|
+
|
|
529
|
+
/** Creates a lazy bridge from a decoded logical snapshot. */
|
|
530
|
+
readonly resume: <M extends Machine.Machine.Any>(
|
|
531
|
+
machine:
|
|
532
|
+
& M
|
|
533
|
+
& EnsureBoundResumeRequirements<Services, NoInfer<M>>
|
|
534
|
+
& EnsureMachineExecutable<NoInfer<M>>,
|
|
535
|
+
snapshot: Machine.Machine.Snapshot<Machine.Machine.States<M>>
|
|
536
|
+
) => ResumedMachineAtomOf<M, RuntimeError>
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Creates atoms backed by a running machine.
|
|
541
|
+
*
|
|
542
|
+
* Use `bind(runtime).make(machine)` when the machine requires external
|
|
543
|
+
* services.
|
|
544
|
+
*
|
|
545
|
+
* **Example**
|
|
546
|
+
*
|
|
547
|
+
* ```ts
|
|
548
|
+
* import { Schema } from "effect"
|
|
549
|
+
* import { Machine } from "@typeonce/effect-machine"
|
|
550
|
+
* import { AtomMachine } from "@typeonce/effect-machine/reactivity"
|
|
551
|
+
*
|
|
552
|
+
* class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
|
|
553
|
+
* const States = Machine.defineStates({ Idle })
|
|
554
|
+
* const machine = Machine.make({
|
|
555
|
+
* states: States.states,
|
|
556
|
+
* events: [],
|
|
557
|
+
* initial: () => States.initial.Idle.from()
|
|
558
|
+
* }).handle({ Idle: {} })
|
|
559
|
+
*
|
|
560
|
+
* const machineAtom = AtomMachine.make(machine)
|
|
561
|
+
* ```
|
|
562
|
+
*
|
|
563
|
+
* @category constructors
|
|
564
|
+
* @since 0.4.0
|
|
565
|
+
*/
|
|
566
|
+
export const make: {
|
|
567
|
+
<
|
|
568
|
+
const States extends Machine.Machine.StateSchemas,
|
|
569
|
+
const Events extends ReadonlyArray<Machine.Machine.TaggedSchema>,
|
|
570
|
+
const Emits extends ReadonlyArray<Machine.Machine.TaggedSchema> = any,
|
|
571
|
+
const Input extends Schema.Top = typeof Schema.Void,
|
|
572
|
+
UnhandledStates extends Machine.Machine.StateIdentifier<States> = Machine.Machine.StateIdentifier<States>,
|
|
573
|
+
E = never,
|
|
574
|
+
R = never,
|
|
575
|
+
InitialE = never,
|
|
576
|
+
InitialR = never,
|
|
577
|
+
FinalStates extends Machine.Machine.StateIdentifier<States> = never,
|
|
578
|
+
Output = never,
|
|
579
|
+
OutputStates extends Machine.Machine.StateIdentifier<States> = never,
|
|
580
|
+
InputEvents extends ReadonlyArray<Machine.Machine.TaggedSchema> = Events
|
|
581
|
+
>(
|
|
582
|
+
machine:
|
|
583
|
+
& Machine.Machine<
|
|
584
|
+
States,
|
|
585
|
+
Events,
|
|
586
|
+
Input,
|
|
587
|
+
UnhandledStates,
|
|
588
|
+
E,
|
|
589
|
+
R,
|
|
590
|
+
InitialE,
|
|
591
|
+
InitialR,
|
|
592
|
+
FinalStates,
|
|
593
|
+
Output,
|
|
594
|
+
Emits,
|
|
595
|
+
OutputStates,
|
|
596
|
+
InputEvents
|
|
597
|
+
>
|
|
598
|
+
& EnsureNoExternalRequirements<
|
|
599
|
+
MachineRequirements<
|
|
600
|
+
InitialR,
|
|
601
|
+
R,
|
|
602
|
+
Machine.Machine.EventOf<Events>,
|
|
603
|
+
Machine.Machine.EmitOf<Emits>
|
|
604
|
+
>
|
|
605
|
+
>
|
|
606
|
+
& EnsureExecutable<States, UnhandledStates, OutputStates>,
|
|
607
|
+
...args: [...Machine.Machine.InputArgs<Input>]
|
|
608
|
+
): MachineAtom<
|
|
609
|
+
Machine.Machine.Snapshot<States>,
|
|
610
|
+
Machine.Machine.EventOf<InputEvents>,
|
|
611
|
+
MachineRuntimeError<E, R>,
|
|
612
|
+
Output,
|
|
613
|
+
MachineStartError<InitialE, E, InitialR, R>
|
|
614
|
+
>
|
|
615
|
+
} = internal.make
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Creates a lazy atom bridge from a decoded logical snapshot.
|
|
619
|
+
*
|
|
620
|
+
* The bridge owns one freshly resumed runtime per `AtomRegistry`, with the same
|
|
621
|
+
* lazy start and disposal semantics as {@link make}. The machine initial
|
|
622
|
+
* function and its input, errors, and services are not involved.
|
|
623
|
+
*
|
|
624
|
+
* @category constructors
|
|
625
|
+
* @since 0.4.0
|
|
626
|
+
*/
|
|
627
|
+
export const resume: {
|
|
628
|
+
<M extends Machine.Machine.Any>(
|
|
629
|
+
machine:
|
|
630
|
+
& M
|
|
631
|
+
& EnsureNoExternalRequirements<MachineResumeRequirementsOf<NoInfer<M>>>
|
|
632
|
+
& EnsureMachineExecutable<NoInfer<M>>,
|
|
633
|
+
snapshot: Machine.Machine.Snapshot<Machine.Machine.States<M>>
|
|
634
|
+
): ResumedMachineAtomOf<M, never>
|
|
635
|
+
} = internal.resume
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Creates an `AtomMachine` factory that owns a shared Effect runtime.
|
|
639
|
+
*
|
|
640
|
+
* Use this when an application runs many machines from the same service layer.
|
|
641
|
+
* The returned factory keeps runtime provisioning at the composition boundary,
|
|
642
|
+
* while every call to `make` still creates an independent machine bridge.
|
|
643
|
+
*
|
|
644
|
+
* @category constructors
|
|
645
|
+
* @since 0.4.0
|
|
646
|
+
*/
|
|
647
|
+
export const bind: <Services, RuntimeError>(
|
|
648
|
+
runtime: Atom.AtomRuntime<Services, RuntimeError>
|
|
649
|
+
) => Bound<Services, RuntimeError> = internal.bind
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * as AtomMachine from "./AtomMachine.js"
|