@typeonce/effect-machine 0.6.0 → 0.7.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.
Files changed (54) hide show
  1. package/README.md +4 -3
  2. package/dist/Machine.d.ts +24 -6
  3. package/dist/Machine.d.ts.map +1 -1
  4. package/dist/Machine.js.map +1 -1
  5. package/dist/internal/machine/atom.d.ts +5 -0
  6. package/dist/internal/machine/atom.d.ts.map +1 -1
  7. package/dist/internal/machine/atom.js +6 -3
  8. package/dist/internal/machine/atom.js.map +1 -1
  9. package/dist/internal/machine/machine.d.ts.map +1 -1
  10. package/dist/internal/machine/machine.js +1 -1
  11. package/dist/internal/machine/machine.js.map +1 -1
  12. package/dist/unstable/reactivity/AtomMachine.d.ts +26 -0
  13. package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
  14. package/dist/unstable/reactivity/AtomMachine.js +23 -0
  15. package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
  16. package/docs/agent-guide.md +14 -0
  17. package/package.json +5 -5
  18. package/src/Machine.ts +6909 -0
  19. package/src/index.ts +1 -0
  20. package/src/internal/machine/activities.ts +108 -0
  21. package/src/internal/machine/atom.ts +684 -0
  22. package/src/internal/machine/cluster.ts +394 -0
  23. package/src/internal/machine/command.ts +58 -0
  24. package/src/internal/machine/commandRuntime.ts +43 -0
  25. package/src/internal/machine/configuration.ts +1331 -0
  26. package/src/internal/machine/errors.ts +87 -0
  27. package/src/internal/machine/executionPlan.ts +996 -0
  28. package/src/internal/machine/invocation.ts +119 -0
  29. package/src/internal/machine/machine.ts +1750 -0
  30. package/src/internal/machine/planner.ts +1933 -0
  31. package/src/internal/machine/process.ts +906 -0
  32. package/src/internal/machine/protocol.ts +322 -0
  33. package/src/internal/machine/readiness.ts +10 -0
  34. package/src/internal/machine/runtime.ts +2512 -0
  35. package/src/internal/machine/serialization.ts +498 -0
  36. package/src/internal/machine/stateDefinition.ts +270 -0
  37. package/src/internal/machine/symbols.ts +2 -0
  38. package/src/internal/machine/topology.ts +479 -0
  39. package/src/internal/testing/machine/arbitrary.ts +102 -0
  40. package/src/internal/testing/machine/exploration.ts +331 -0
  41. package/src/internal/testing/machine/finiteModel.ts +1498 -0
  42. package/src/internal/testing/machine/invariant.ts +372 -0
  43. package/src/internal/testing/machine/probe.ts +79 -0
  44. package/src/internal/testing/machine/referenceModel.ts +1505 -0
  45. package/src/internal/testing/machine/runtime.ts +1710 -0
  46. package/src/internal/testing/machine/runtimeInvariant.ts +486 -0
  47. package/src/internal/testing/machine/trace.ts +150 -0
  48. package/src/internal/testing/machine/verification.ts +1890 -0
  49. package/src/testing/MachineTest.ts +2067 -0
  50. package/src/testing/index.ts +7 -0
  51. package/src/unstable/cluster/ClusterMachine.ts +390 -0
  52. package/src/unstable/cluster/index.ts +1 -0
  53. package/src/unstable/reactivity/AtomMachine.ts +696 -0
  54. package/src/unstable/reactivity/index.ts +1 -0
@@ -0,0 +1,696 @@
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 SnapshotByIdentifier<State, Path extends SnapshotIdentifier<State>> = SnapshotNode<State> extends infer Node ?
299
+ Node extends { readonly path: Path } ? Node : never
300
+ : never
301
+
302
+ type ChildState<Child extends Machine.ChildMachine.Any> = RefState<Machine.ChildMachine.Ref<Child>>
303
+
304
+ /**
305
+ * Selects the typed value for an active state path.
306
+ *
307
+ * Valid paths and their selected value types are inferred from the bridge.
308
+ * The derived atom suppresses structurally equal updates. Keep the returned
309
+ * atom stable when constructing it inside a component.
310
+ *
311
+ * **Example**
312
+ *
313
+ * ```ts
314
+ * import { Schema } from "effect"
315
+ * import { Machine } from "@typeonce/effect-machine"
316
+ * import { AtomMachine } from "@typeonce/effect-machine/reactivity"
317
+ *
318
+ * class Count extends Schema.TaggedClass<Count>("Count")("Count", {
319
+ * value: Schema.Number
320
+ * }) {}
321
+ * const States = Machine.defineStates({ Count })
322
+ * const machine = Machine.make({
323
+ * states: States.states,
324
+ * events: [],
325
+ * initial: () => States.initial.Count(new Count({ value: 0 }))
326
+ * }).handle({ Count: {} })
327
+ * const machineAtom = AtomMachine.make(machine)
328
+ *
329
+ * const countAtom = AtomMachine.select(machineAtom, "Count")
330
+ * ```
331
+ *
332
+ * @category combinators
333
+ * @since 0.4.0
334
+ */
335
+ export const select: <
336
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
337
+ Event,
338
+ Error,
339
+ Output,
340
+ StartError,
341
+ const Path extends SnapshotIdentifier<State>
342
+ >(self: MachineAtom<State, Event, Error, Output, StartError>, path: Path) => Atom.Atom<
343
+ AsyncResult.AsyncResult<Option.Option<SnapshotValueByIdentifier<State, Path>>, StartError | Error>
344
+ > = internal.select
345
+
346
+ /**
347
+ * Selects the typed logical snapshot for an active state path.
348
+ *
349
+ * Unlike {@link select}, the selected value retains its child snapshot
350
+ * topology. The derived atom suppresses structurally equal updates. Keep the
351
+ * returned atom stable when constructing it inside a component.
352
+ *
353
+ * @category combinators
354
+ * @since 0.7.0
355
+ */
356
+ export const selectSnapshot: <
357
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
358
+ Event,
359
+ Error,
360
+ Output,
361
+ StartError,
362
+ const Path extends SnapshotIdentifier<State>
363
+ >(self: MachineAtom<State, Event, Error, Output, StartError>, path: Path) => Atom.Atom<
364
+ AsyncResult.AsyncResult<Option.Option<SnapshotByIdentifier<State, Path>>, StartError | Error>
365
+ > = internal.selectSnapshot
366
+
367
+ /**
368
+ * Selects the typed value for an active state path in an invoked child.
369
+ *
370
+ * Valid paths and their selected value types are inferred from the child
371
+ * bridge. An inactive child produces `Option.none()`. Keep the returned atom
372
+ * stable when constructing it inside a component.
373
+ *
374
+ * **Example**
375
+ *
376
+ * ```ts
377
+ * const editingAtom = AtomMachine.selectChild(editorAtom, "Editing")
378
+ * // Atom<AsyncResult<Option<Editing>, StartError | ChildRuntimeError>>
379
+ * ```
380
+ *
381
+ * @category combinators
382
+ * @since 0.4.0
383
+ */
384
+ export const selectChild: <
385
+ Child extends Machine.ChildMachine.Any,
386
+ StartError,
387
+ const Path extends SnapshotIdentifier<ChildState<Child>>
388
+ >(self: ChildMachineAtom<Child, StartError>, path: Path) => Atom.Atom<
389
+ AsyncResult.AsyncResult<
390
+ Option.Option<SnapshotValueByIdentifier<ChildState<Child>, Path>>,
391
+ StartError | RefError<Machine.ChildMachine.Ref<Child>>
392
+ >
393
+ > = internal.selectChild
394
+
395
+ /**
396
+ * Selects the typed logical snapshot for an active state path in an invoked
397
+ * child.
398
+ *
399
+ * An inactive child or state path produces `Option.none()`. Unlike
400
+ * {@link selectChild}, the selected value retains its child snapshot topology.
401
+ * The derived atom suppresses structurally equal updates.
402
+ *
403
+ * @category combinators
404
+ * @since 0.7.0
405
+ */
406
+ export const selectSnapshotChild: <
407
+ Child extends Machine.ChildMachine.Any,
408
+ StartError,
409
+ const Path extends SnapshotIdentifier<ChildState<Child>>
410
+ >(self: ChildMachineAtom<Child, StartError>, path: Path) => Atom.Atom<
411
+ AsyncResult.AsyncResult<
412
+ Option.Option<SnapshotByIdentifier<ChildState<Child>, Path>>,
413
+ StartError | RefError<Machine.ChildMachine.Ref<Child>>
414
+ >
415
+ > = internal.selectSnapshotChild
416
+
417
+ /**
418
+ * Returns whether a state path is active.
419
+ *
420
+ * Valid paths are inferred from the bridge snapshot.
421
+ * The derived atom suppresses equal updates. Runtime failures remain in the
422
+ * typed failure channel.
423
+ *
424
+ * **Example**
425
+ *
426
+ * ```ts
427
+ * import { Schema } from "effect"
428
+ * import { Machine } from "@typeonce/effect-machine"
429
+ * import { AtomMachine } from "@typeonce/effect-machine/reactivity"
430
+ *
431
+ * class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
432
+ * const States = Machine.defineStates({ Idle })
433
+ * const machine = Machine.make({
434
+ * states: States.states,
435
+ * events: [],
436
+ * initial: () => States.initial.Idle.from()
437
+ * }).handle({ Idle: {} })
438
+ * const machineAtom = AtomMachine.make(machine)
439
+ *
440
+ * const isIdleAtom = AtomMachine.matches(machineAtom, "Idle")
441
+ * ```
442
+ *
443
+ * @category combinators
444
+ * @since 0.4.0
445
+ */
446
+ export const matches: <
447
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
448
+ Event,
449
+ Error,
450
+ Output,
451
+ StartError,
452
+ const Path extends SnapshotIdentifier<State>
453
+ >(
454
+ self: MachineAtom<State, Event, Error, Output, StartError>,
455
+ path: Path
456
+ ) => Atom.Atom<AsyncResult.AsyncResult<boolean, StartError | Error>> = internal.matches
457
+
458
+ /**
459
+ * Returns whether a state path is active in an invoked child.
460
+ *
461
+ * Valid paths are inferred from the child bridge snapshot.
462
+ * An inactive child produces `false`. Keep the returned atom stable when
463
+ * constructing it inside a component.
464
+ *
465
+ * @category combinators
466
+ * @since 0.4.0
467
+ */
468
+ export const matchesChild: <
469
+ Child extends Machine.ChildMachine.Any,
470
+ StartError,
471
+ const Path extends SnapshotIdentifier<ChildState<Child>>
472
+ >(self: ChildMachineAtom<Child, StartError>, path: Path) => Atom.Atom<
473
+ AsyncResult.AsyncResult<boolean, StartError | RefError<Machine.ChildMachine.Ref<Child>>>
474
+ > = internal.matchesChild
475
+
476
+ const BoundRequirementsTypeId = "~effect/reactivity/AtomMachine/BoundRequirements"
477
+
478
+ type MachineRequirementsOf<M extends Machine.Machine.Any> = MachineRequirements<
479
+ Machine.Machine.InitialServices<M>,
480
+ Machine.Machine.Services<M>,
481
+ Machine.Machine.Event<M>,
482
+ Machine.Machine.Emit<M>
483
+ >
484
+
485
+ type MissingBoundRequirements<Services, M extends Machine.Machine.Any> = Exclude<
486
+ ExternalRequirements<MachineRequirementsOf<M>>,
487
+ Services
488
+ >
489
+
490
+ type EnsureBoundRequirements<Services, M extends Machine.Machine.Any> = IsAny<MachineRequirementsOf<M>> extends true ? {
491
+ readonly [BoundRequirementsTypeId]: MachineRequirementsOf<M>
492
+ }
493
+ : [MissingBoundRequirements<Services, M>] extends [never] ? unknown
494
+ : {
495
+ readonly [BoundRequirementsTypeId]: MissingBoundRequirements<Services, M>
496
+ }
497
+
498
+ type MachineResumeRequirementsOf<M extends Machine.Machine.Any> = MachineResumeRequirements<
499
+ Machine.Machine.Services<M>,
500
+ Machine.Machine.Event<M>,
501
+ Machine.Machine.Emit<M>
502
+ >
503
+
504
+ type MissingBoundResumeRequirements<Services, M extends Machine.Machine.Any> = Exclude<
505
+ ExternalRequirements<MachineResumeRequirementsOf<M>>,
506
+ Services
507
+ >
508
+
509
+ type EnsureBoundResumeRequirements<Services, M extends Machine.Machine.Any> =
510
+ IsAny<MachineResumeRequirementsOf<M>> extends true ? {
511
+ readonly [BoundRequirementsTypeId]: MachineResumeRequirementsOf<M>
512
+ }
513
+ : [MissingBoundResumeRequirements<Services, M>] extends [never] ? unknown
514
+ : {
515
+ readonly [BoundRequirementsTypeId]: MissingBoundResumeRequirements<Services, M>
516
+ }
517
+
518
+ type EnsureMachineExecutable<M extends Machine.Machine.Any> = IsAny<Machine.Machine.States<M>> extends true ? {
519
+ readonly "~effect/reactivity/AtomMachine/ConcreteMachineRequired": M
520
+ }
521
+ : EnsureExecutable<
522
+ Machine.Machine.States<M>,
523
+ Machine.Machine.UnhandledStates<M>,
524
+ Machine.Machine.OutputStates<M>
525
+ >
526
+
527
+ type MachineInputArgsOf<M extends Machine.Machine.Any> = [
528
+ ...Machine.Machine.InputArgs<Machine.Machine.Input<M>>
529
+ ]
530
+
531
+ type MachineAtomOf<M extends Machine.Machine.Any, RuntimeError> = MachineAtom<
532
+ Machine.Machine.Snapshot<Machine.Machine.States<M>>,
533
+ Machine.Machine.InputEvent<M>,
534
+ MachineRuntimeError<Machine.Machine.Error<M>, Machine.Machine.Services<M>>,
535
+ Machine.Machine.Output<M>,
536
+ MachineStartError<
537
+ Machine.Machine.InitialError<M>,
538
+ Machine.Machine.Error<M>,
539
+ Machine.Machine.InitialServices<M>,
540
+ Machine.Machine.Services<M>,
541
+ RuntimeError
542
+ >
543
+ >
544
+
545
+ type ResumedMachineAtomOf<M extends Machine.Machine.Any, RuntimeError> = MachineAtom<
546
+ Machine.Machine.Snapshot<Machine.Machine.States<M>>,
547
+ Machine.Machine.InputEvent<M>,
548
+ MachineRuntimeError<Machine.Machine.Error<M>, Machine.Machine.Services<M>>,
549
+ Machine.Machine.Output<M>,
550
+ Machine.MachineSchemaDecodeError | RuntimeError
551
+ >
552
+
553
+ /**
554
+ * An `AtomMachine` factory with one owned Effect runtime.
555
+ *
556
+ * @category models
557
+ * @since 0.4.0
558
+ */
559
+ export interface Bound<Services, RuntimeError = never> {
560
+ /**
561
+ * Creates an independent machine bridge using the bound runtime.
562
+ *
563
+ * The machine's external service requirements must be provided by the
564
+ * runtime. Machine-native runtime requirements are supplied automatically.
565
+ *
566
+ * @since 0.4.0
567
+ */
568
+ readonly make: <M extends Machine.Machine.Any>(
569
+ machine:
570
+ & M
571
+ & EnsureBoundRequirements<Services, NoInfer<M>>
572
+ & EnsureMachineExecutable<NoInfer<M>>,
573
+ ...args: MachineInputArgsOf<M>
574
+ ) => MachineAtomOf<M, RuntimeError>
575
+
576
+ /** Creates a lazy bridge from a decoded logical snapshot. */
577
+ readonly resume: <M extends Machine.Machine.Any>(
578
+ machine:
579
+ & M
580
+ & EnsureBoundResumeRequirements<Services, NoInfer<M>>
581
+ & EnsureMachineExecutable<NoInfer<M>>,
582
+ snapshot: Machine.Machine.Snapshot<Machine.Machine.States<M>>
583
+ ) => ResumedMachineAtomOf<M, RuntimeError>
584
+ }
585
+
586
+ /**
587
+ * Creates atoms backed by a running machine.
588
+ *
589
+ * Use `bind(runtime).make(machine)` when the machine requires external
590
+ * services.
591
+ *
592
+ * **Example**
593
+ *
594
+ * ```ts
595
+ * import { Schema } from "effect"
596
+ * import { Machine } from "@typeonce/effect-machine"
597
+ * import { AtomMachine } from "@typeonce/effect-machine/reactivity"
598
+ *
599
+ * class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
600
+ * const States = Machine.defineStates({ Idle })
601
+ * const machine = Machine.make({
602
+ * states: States.states,
603
+ * events: [],
604
+ * initial: () => States.initial.Idle.from()
605
+ * }).handle({ Idle: {} })
606
+ *
607
+ * const machineAtom = AtomMachine.make(machine)
608
+ * ```
609
+ *
610
+ * @category constructors
611
+ * @since 0.4.0
612
+ */
613
+ export const make: {
614
+ <
615
+ const States extends Machine.Machine.StateSchemas,
616
+ const Events extends ReadonlyArray<Machine.Machine.TaggedSchema>,
617
+ const Emits extends ReadonlyArray<Machine.Machine.TaggedSchema> = any,
618
+ const Input extends Schema.Top = typeof Schema.Void,
619
+ UnhandledStates extends Machine.Machine.StateIdentifier<States> = Machine.Machine.StateIdentifier<States>,
620
+ E = never,
621
+ R = never,
622
+ InitialE = never,
623
+ InitialR = never,
624
+ FinalStates extends Machine.Machine.StateIdentifier<States> = never,
625
+ Output = never,
626
+ OutputStates extends Machine.Machine.StateIdentifier<States> = never,
627
+ InputEvents extends ReadonlyArray<Machine.Machine.TaggedSchema> = Events
628
+ >(
629
+ machine:
630
+ & Machine.Machine<
631
+ States,
632
+ Events,
633
+ Input,
634
+ UnhandledStates,
635
+ E,
636
+ R,
637
+ InitialE,
638
+ InitialR,
639
+ FinalStates,
640
+ Output,
641
+ Emits,
642
+ OutputStates,
643
+ InputEvents
644
+ >
645
+ & EnsureNoExternalRequirements<
646
+ MachineRequirements<
647
+ InitialR,
648
+ R,
649
+ Machine.Machine.EventOf<Events>,
650
+ Machine.Machine.EmitOf<Emits>
651
+ >
652
+ >
653
+ & EnsureExecutable<States, UnhandledStates, OutputStates>,
654
+ ...args: [...Machine.Machine.InputArgs<Input>]
655
+ ): MachineAtom<
656
+ Machine.Machine.Snapshot<States>,
657
+ Machine.Machine.EventOf<InputEvents>,
658
+ MachineRuntimeError<E, R>,
659
+ Output,
660
+ MachineStartError<InitialE, E, InitialR, R>
661
+ >
662
+ } = internal.make
663
+
664
+ /**
665
+ * Creates a lazy atom bridge from a decoded logical snapshot.
666
+ *
667
+ * The bridge owns one freshly resumed runtime per `AtomRegistry`, with the same
668
+ * lazy start and disposal semantics as {@link make}. The machine initial
669
+ * function and its input, errors, and services are not involved.
670
+ *
671
+ * @category constructors
672
+ * @since 0.4.0
673
+ */
674
+ export const resume: {
675
+ <M extends Machine.Machine.Any>(
676
+ machine:
677
+ & M
678
+ & EnsureNoExternalRequirements<MachineResumeRequirementsOf<NoInfer<M>>>
679
+ & EnsureMachineExecutable<NoInfer<M>>,
680
+ snapshot: Machine.Machine.Snapshot<Machine.Machine.States<M>>
681
+ ): ResumedMachineAtomOf<M, never>
682
+ } = internal.resume
683
+
684
+ /**
685
+ * Creates an `AtomMachine` factory that owns a shared Effect runtime.
686
+ *
687
+ * Use this when an application runs many machines from the same service layer.
688
+ * The returned factory keeps runtime provisioning at the composition boundary,
689
+ * while every call to `make` still creates an independent machine bridge.
690
+ *
691
+ * @category constructors
692
+ * @since 0.4.0
693
+ */
694
+ export const bind: <Services, RuntimeError>(
695
+ runtime: Atom.AtomRuntime<Services, RuntimeError>
696
+ ) => Bound<Services, RuntimeError> = internal.bind
@@ -0,0 +1 @@
1
+ export * as AtomMachine from "./AtomMachine.js"