@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,684 @@
1
+ /**
2
+ * Atom bridge for running machines.
3
+ *
4
+ * @since 0.4.0
5
+ */
6
+
7
+ import * as Data from "effect/Data"
8
+ import * as Effect from "effect/Effect"
9
+ import * as Equal from "effect/Equal"
10
+ import * as Option from "effect/Option"
11
+ import type * as Schema from "effect/Schema"
12
+ import type * as Scope from "effect/Scope"
13
+ import * as Stream from "effect/Stream"
14
+ import { AsyncResult, Atom, type AtomRegistry } from "effect/unstable/reactivity"
15
+ import type * as Machine from "../../Machine.js"
16
+ import type { Bound, ChildMachineAtom, MachineAtom } from "../../unstable/reactivity/AtomMachine.js"
17
+ import * as internalMachine from "./machine.js"
18
+ import type { EnsureExecutable } from "./readiness.js"
19
+ import * as Topology from "./topology.js"
20
+
21
+ export class NotReadyError extends Data.TaggedError("NotReadyError") {}
22
+
23
+ export class ChildNotActiveError extends Data.TaggedError("ChildNotActiveError")<{
24
+ readonly id: string
25
+ }> {}
26
+
27
+ type AtomSupportedRequirements = Scope.Scope | AtomRegistry.AtomRegistry
28
+
29
+ type ExternalRequirements<Requirements> = Exclude<Requirements, AtomSupportedRequirements>
30
+
31
+ const ExternalRequirementsTypeId = "~effect/reactivity/AtomMachine/ExternalRequirements"
32
+
33
+ type EnsureNoExternalRequirements<Requirements> = [ExternalRequirements<Requirements>] extends [never] ? unknown : {
34
+ readonly [ExternalRequirementsTypeId]: ExternalRequirements<Requirements>
35
+ }
36
+
37
+ type IsAny<A> = 0 extends (1 & A) ? true : false
38
+
39
+ type ExcludeCompatibleMachineRuntime<Requirements, Events, Emits> = Requirements extends
40
+ Machine.Runtime.Requirement<infer RequiredEvents, infer RequiredEmits> ?
41
+ IsAny<Requirements> extends true ? Requirements
42
+ : [RequiredEvents] extends [Events] ? [RequiredEmits] extends [Emits] ? never : Requirements
43
+ : Requirements
44
+ : Requirements
45
+
46
+ type MachineRequirements<InitialR, R, Events, Emits> = ExcludeCompatibleMachineRuntime<
47
+ Machine.ExecutionServices<InitialR | R>,
48
+ Events,
49
+ Emits
50
+ >
51
+
52
+ type MachineResumeRequirements<R, Events, Emits> = ExcludeCompatibleMachineRuntime<
53
+ Machine.ExecutionServices<R>,
54
+ Events,
55
+ Emits
56
+ >
57
+
58
+ type MachineRuntimeError<E, R> =
59
+ | E
60
+ | Machine.ActionError<R>
61
+ | Machine.InfiniteTransitionError
62
+ | Machine.MachineSchemaDecodeError
63
+ | Machine.StoppedError
64
+
65
+ type MachineStartError<InitialE, E, InitialR, R, RuntimeError = never> =
66
+ | InitialE
67
+ | E
68
+ | Machine.ActionError<InitialR | R>
69
+ | Machine.InfiniteTransitionError
70
+ | Machine.MachineSchemaDecodeError
71
+ | Machine.StartupError
72
+ | Machine.StoppedError
73
+ | RuntimeError
74
+
75
+ const runMachineAtomEffect = <State, Event, Error, Output, StartError, Requirements>(
76
+ get: Atom.AtomContext,
77
+ start: Effect.Effect<Machine.MachineRef<State, Event, Error, Output>, StartError, Requirements>
78
+ ): Effect.Effect<never, StartError, Requirements> =>
79
+ Effect.scoped(
80
+ Effect.acquireRelease(start, (ref) => ref.stop).pipe(
81
+ Effect.tap((ref) => Effect.sync(() => get.setSelf(AsyncResult.success(ref)))),
82
+ Effect.flatMap(() => Effect.never)
83
+ )
84
+ )
85
+
86
+ const startMachineAtomEffect = <
87
+ const States extends Machine.Machine.StateSchemas,
88
+ const Events extends ReadonlyArray<Machine.Machine.TaggedSchema>,
89
+ const Emits extends ReadonlyArray<Machine.Machine.TaggedSchema> = any,
90
+ const Input extends Schema.Top = typeof Schema.Void,
91
+ UnhandledStates extends Machine.Machine.StateIdentifier<States> = Machine.Machine.StateIdentifier<States>,
92
+ E = never,
93
+ R = never,
94
+ InitialE = never,
95
+ InitialR = never,
96
+ FinalStates extends Machine.Machine.StateIdentifier<States> = never,
97
+ Output = never,
98
+ OutputStates extends Machine.Machine.StateIdentifier<States> = never,
99
+ InputEvents extends ReadonlyArray<Machine.Machine.TaggedSchema> = Events
100
+ >(
101
+ get: Atom.AtomContext,
102
+ machine:
103
+ & Machine.Machine<
104
+ States,
105
+ Events,
106
+ Input,
107
+ UnhandledStates,
108
+ E,
109
+ R,
110
+ InitialE,
111
+ InitialR,
112
+ FinalStates,
113
+ Output,
114
+ Emits,
115
+ OutputStates,
116
+ InputEvents
117
+ >
118
+ & EnsureExecutable<States, UnhandledStates, OutputStates>,
119
+ args: [...Machine.Machine.InputArgs<Input>]
120
+ ): Effect.Effect<
121
+ Machine.MachineRef<
122
+ Machine.Machine.Snapshot<States>,
123
+ Machine.Machine.EventOf<InputEvents>,
124
+ MachineRuntimeError<E, R>,
125
+ Output
126
+ >,
127
+ MachineStartError<InitialE, E, InitialR, R>,
128
+ MachineRequirements<InitialR, R, Machine.Machine.EventOf<Events>, Machine.Machine.EmitOf<Emits>>
129
+ > => runMachineAtomEffect(get, internalMachine.start(machine, ...args))
130
+
131
+ const resumeMachineAtomEffect = (
132
+ get: Atom.AtomContext,
133
+ machine: Machine.Machine.Any,
134
+ snapshot: Machine.Machine.Snapshot<any>
135
+ ) => runMachineAtomEffect(get, internalMachine.resume(machine as any, snapshot as any))
136
+
137
+ type RefState<Ref> = Ref extends Machine.MachineRef<infer State, any, any, any> ? State : never
138
+ type RefError<Ref> = Ref extends Machine.MachineRef<any, any, infer Error, any> ? Error : never
139
+ type RefOutput<Ref> = Ref extends Machine.MachineRef<any, any, any, infer Output> ? Output : never
140
+
141
+ const makeRuntimeResultAtom = <State, Error, Output, StartError>(
142
+ snapshot: Atom.Atom<AsyncResult.AsyncResult<Machine.RuntimeSnapshot<State, Error, Output>, StartError>>
143
+ ): Atom.Atom<AsyncResult.AsyncResult<State, StartError | Error>> =>
144
+ Atom.readable((get): AsyncResult.AsyncResult<State, StartError | Error> => {
145
+ const current = get(snapshot)
146
+ if (AsyncResult.isInitial(current)) {
147
+ return AsyncResult.initial(current.waiting)
148
+ } else if (AsyncResult.isFailure(current)) {
149
+ return AsyncResult.failureWithPrevious(current.cause, {
150
+ previous: get.self(),
151
+ waiting: current.waiting
152
+ })
153
+ } else if (current.value.status === "error") {
154
+ return AsyncResult.failureWithPrevious(current.value.cause, {
155
+ previous: get.self(),
156
+ waiting: current.waiting
157
+ })
158
+ }
159
+ return AsyncResult.success(current.value.state, {
160
+ waiting: current.waiting
161
+ })
162
+ }).pipe(Atom.withEquality(Equal.equals))
163
+
164
+ const makeChildRuntimeResultAtom = <State, Error, Output, StartError>(
165
+ snapshot: Atom.Atom<
166
+ AsyncResult.AsyncResult<Option.Option<Machine.RuntimeSnapshot<State, Error, Output>>, StartError>
167
+ >
168
+ ): Atom.Atom<AsyncResult.AsyncResult<Option.Option<State>, StartError | Error>> =>
169
+ Atom.readable((get): AsyncResult.AsyncResult<Option.Option<State>, StartError | Error> => {
170
+ const current = get(snapshot)
171
+ if (AsyncResult.isInitial(current)) {
172
+ return AsyncResult.initial(current.waiting)
173
+ } else if (AsyncResult.isFailure(current)) {
174
+ return AsyncResult.failureWithPrevious(current.cause, {
175
+ previous: get.self(),
176
+ waiting: current.waiting
177
+ })
178
+ } else if (Option.isNone(current.value)) {
179
+ const previous = get.self<AsyncResult.AsyncResult<Option.Option<State>, StartError | Error>>()
180
+ if (Option.isSome(previous) && AsyncResult.isFailure(previous.value)) {
181
+ return previous.value
182
+ }
183
+ return AsyncResult.success(Option.none(), {
184
+ waiting: current.waiting
185
+ })
186
+ } else if (current.value.value.status === "error") {
187
+ return AsyncResult.failureWithPrevious(current.value.value.cause, {
188
+ previous: get.self(),
189
+ waiting: current.waiting
190
+ })
191
+ }
192
+ return AsyncResult.success(Option.some(current.value.value.state), {
193
+ waiting: current.waiting
194
+ })
195
+ }).pipe(Atom.withEquality(Equal.equals))
196
+
197
+ const makeChildRefAtom = <Child extends Machine.ChildMachine.Any, StartError>(
198
+ parentRef: Atom.Atom<
199
+ AsyncResult.AsyncResult<Option.Option<Machine.MachineRef<any, any, any, any>>, StartError>
200
+ >,
201
+ child: Child
202
+ ): Atom.Atom<AsyncResult.AsyncResult<Option.Option<Machine.ChildMachine.Ref<Child>>, StartError>> =>
203
+ Atom.readable((get) => {
204
+ const parent = get(parentRef)
205
+ if (AsyncResult.isInitial(parent)) {
206
+ return AsyncResult.initial(parent.waiting)
207
+ } else if (AsyncResult.isFailure(parent)) {
208
+ return AsyncResult.failureWithPrevious(parent.cause, {
209
+ previous: get.self(),
210
+ waiting: parent.waiting
211
+ })
212
+ } else if (Option.isNone(parent.value)) {
213
+ return AsyncResult.success(Option.none())
214
+ }
215
+
216
+ const handle = parent.value.value
217
+ const current = Effect.runSync(handle.child(child))
218
+ const cancel = Effect.runCallback(
219
+ Effect.yieldNow.pipe(
220
+ Effect.andThen(
221
+ handle.childChanges(child).pipe(
222
+ Stream.runForEach((ref) => Effect.sync(() => get.setSelf(AsyncResult.success(ref))))
223
+ )
224
+ )
225
+ )
226
+ )
227
+ get.addFinalizer(cancel)
228
+ return AsyncResult.success(current)
229
+ })
230
+
231
+ const makeChildFromRefAtom = <Child extends Machine.ChildMachine.Any, StartError>(
232
+ ref: Atom.Atom<AsyncResult.AsyncResult<Option.Option<Machine.ChildMachine.Ref<Child>>, StartError>>,
233
+ descriptor: Child
234
+ ): ChildMachineAtom<Child, StartError> => {
235
+ type Ref = Machine.ChildMachine.Ref<Child>
236
+ type State = RefState<Ref>
237
+ type Error = RefError<Ref>
238
+ type Output = RefOutput<Ref>
239
+
240
+ const snapshot = Atom.readable((get): AsyncResult.AsyncResult<
241
+ Option.Option<Machine.RuntimeSnapshot<State, Error, Output>>,
242
+ StartError
243
+ > => {
244
+ const result = get(ref)
245
+ if (AsyncResult.isInitial(result)) {
246
+ return AsyncResult.initial(result.waiting)
247
+ } else if (AsyncResult.isFailure(result)) {
248
+ return AsyncResult.failureWithPrevious(result.cause, {
249
+ previous: get.self(),
250
+ waiting: result.waiting
251
+ })
252
+ } else if (Option.isNone(result.value)) {
253
+ return AsyncResult.success(Option.none())
254
+ }
255
+
256
+ const handle = result.value.value as unknown as Machine.MachineRef<State, any, Error, Output>
257
+ const cancel = Effect.runCallback(
258
+ handle.changes.pipe(
259
+ Stream.runForEach((snapshot) => Effect.sync(() => get.setSelf(AsyncResult.success(Option.some(snapshot)))))
260
+ )
261
+ )
262
+ get.addFinalizer(cancel)
263
+ return AsyncResult.success(Option.some(Effect.runSync(handle.snapshot)))
264
+ })
265
+
266
+ const send = Atom.writable<
267
+ AsyncResult.AsyncResult<void, StartError | NotReadyError | ChildNotActiveError | Machine.StoppedError>,
268
+ Machine.ChildMachine.Event<Child>
269
+ >(
270
+ (get) => AsyncResult.map(get(ref), () => undefined),
271
+ (ctx, event) => {
272
+ const result = ctx.get(ref)
273
+ if (AsyncResult.isInitial(result)) {
274
+ ctx.setSelf(AsyncResult.fail(new NotReadyError()))
275
+ } else if (AsyncResult.isFailure(result)) {
276
+ ctx.setSelf(AsyncResult.map(result, () => undefined))
277
+ } else if (Option.isNone(result.value)) {
278
+ ctx.setSelf(AsyncResult.fail(new ChildNotActiveError({ id: descriptor.id })))
279
+ } else {
280
+ Effect.runCallback(result.value.value.send(event as never), {
281
+ onExit: (exit) => ctx.setSelf(AsyncResult.fromExit(exit))
282
+ })
283
+ }
284
+ }
285
+ )
286
+
287
+ const stop = Atom.writable<
288
+ AsyncResult.AsyncResult<void, StartError | NotReadyError | ChildNotActiveError>,
289
+ void
290
+ >(
291
+ (get) => AsyncResult.map(get(ref), () => undefined),
292
+ (ctx) => {
293
+ const result = ctx.get(ref)
294
+ if (AsyncResult.isInitial(result)) {
295
+ ctx.setSelf(AsyncResult.fail(new NotReadyError()))
296
+ } else if (AsyncResult.isFailure(result)) {
297
+ ctx.setSelf(AsyncResult.map(result, () => undefined))
298
+ } else if (Option.isNone(result.value)) {
299
+ ctx.setSelf(AsyncResult.fail(new ChildNotActiveError({ id: descriptor.id })))
300
+ } else {
301
+ Effect.runCallback(result.value.value.stop)
302
+ }
303
+ }
304
+ )
305
+
306
+ const childFamily = Atom.family((nested: Machine.ChildMachine.Any) =>
307
+ makeChildFromRefAtom(
308
+ makeChildRefAtom(ref as any, nested),
309
+ nested
310
+ )
311
+ )
312
+ const child = <Nested extends Machine.ChildMachine.Any>(
313
+ nested: Nested
314
+ ): ChildMachineAtom<Nested, StartError> => childFamily(nested) as ChildMachineAtom<Nested, StartError>
315
+
316
+ return {
317
+ ref,
318
+ snapshot,
319
+ state: Atom.mapResult(snapshot, Option.map((snapshot) => snapshot.state)),
320
+ result: makeChildRuntimeResultAtom(snapshot),
321
+ send,
322
+ stop,
323
+ child
324
+ }
325
+ }
326
+
327
+ const makeFromRefAtom = <State, Event, Error, Output, StartError>(
328
+ ref: Atom.Atom<AsyncResult.AsyncResult<Machine.MachineRef<State, Event, Error, Output>, StartError>>
329
+ ): MachineAtom<State, Event, Error, Output, StartError> => {
330
+ const snapshot = Atom.readable((
331
+ get
332
+ ): AsyncResult.AsyncResult<Machine.RuntimeSnapshot<State, Error, Output>, StartError> => {
333
+ const result = get(ref)
334
+ if (AsyncResult.isInitial(result)) {
335
+ return AsyncResult.initial(result.waiting)
336
+ } else if (AsyncResult.isFailure(result)) {
337
+ return AsyncResult.failureWithPrevious(result.cause, {
338
+ previous: get.self<AsyncResult.AsyncResult<Machine.RuntimeSnapshot<State, Error, Output>, StartError>>(),
339
+ waiting: result.waiting
340
+ })
341
+ }
342
+
343
+ const handle = result.value
344
+ const cancel = Effect.runCallback(
345
+ handle.changes.pipe(
346
+ Stream.runForEach((snapshot) =>
347
+ Effect.sync(() =>
348
+ get.setSelf(
349
+ AsyncResult.success(snapshot, {
350
+ waiting: snapshot.status === "active"
351
+ })
352
+ )
353
+ )
354
+ )
355
+ )
356
+ )
357
+ get.addFinalizer(cancel)
358
+
359
+ const current = Effect.runSync(handle.snapshot)
360
+ return AsyncResult.success(current, {
361
+ waiting: current.status === "active"
362
+ })
363
+ })
364
+
365
+ const send = Atom.writable<
366
+ AsyncResult.AsyncResult<void, StartError | NotReadyError | Machine.StoppedError>,
367
+ Event
368
+ >(
369
+ (get) => AsyncResult.map(get(ref), () => undefined),
370
+ (ctx, event: Event) => {
371
+ const result = ctx.get(ref)
372
+ if (AsyncResult.isInitial(result)) {
373
+ ctx.setSelf(AsyncResult.fail(new NotReadyError()))
374
+ } else if (AsyncResult.isFailure(result)) {
375
+ ctx.setSelf(AsyncResult.map(result, () => undefined))
376
+ } else {
377
+ Effect.runCallback(result.value.send(event), {
378
+ onExit: (exit) =>
379
+ ctx.setSelf(
380
+ AsyncResult.fromExit(exit)
381
+ )
382
+ })
383
+ }
384
+ }
385
+ )
386
+
387
+ const stop = Atom.writable<AsyncResult.AsyncResult<void, StartError | NotReadyError>, void>(
388
+ (get) => AsyncResult.map(get(ref), () => undefined),
389
+ (ctx) => {
390
+ const result = ctx.get(ref)
391
+ if (AsyncResult.isInitial(result)) {
392
+ ctx.setSelf(AsyncResult.fail(new NotReadyError()))
393
+ } else if (AsyncResult.isFailure(result)) {
394
+ ctx.setSelf(AsyncResult.map(result, () => undefined))
395
+ } else {
396
+ Effect.runCallback(result.value.stop)
397
+ }
398
+ }
399
+ )
400
+
401
+ const optionalRef = Atom.mapResult(ref, Option.some)
402
+ const childFamily = Atom.family((descriptor: Machine.ChildMachine.Any) =>
403
+ makeChildFromRefAtom(
404
+ makeChildRefAtom(optionalRef as any, descriptor),
405
+ descriptor
406
+ )
407
+ )
408
+ const child = <Child extends Machine.ChildMachine.Any>(
409
+ descriptor: Child
410
+ ): ChildMachineAtom<Child, StartError> => childFamily(descriptor) as ChildMachineAtom<Child, StartError>
411
+
412
+ return {
413
+ ref,
414
+ snapshot,
415
+ state: Atom.mapResult(snapshot, (snapshot) => snapshot.state),
416
+ result: makeRuntimeResultAtom(snapshot),
417
+ send,
418
+ stop,
419
+ child
420
+ }
421
+ }
422
+
423
+ type SnapshotNode<State> = State extends Machine.Machine.AtomicSnapshot<string, unknown> ?
424
+ | State
425
+ | (State extends { readonly state: infer Child } ? SnapshotNode<Child>
426
+ : State extends { readonly states: infer Regions } ? SnapshotNode<Regions[keyof Regions]>
427
+ : never)
428
+ : never
429
+
430
+ type SnapshotIdentifier<State> = SnapshotNode<State> extends infer Node ?
431
+ Node extends { readonly path: infer Path extends string } ? Path : never
432
+ : never
433
+
434
+ type SnapshotValueByIdentifier<State, Path extends SnapshotIdentifier<State>> = SnapshotNode<State> extends infer Node ?
435
+ Node extends { readonly path: Path; readonly value: infer Value } ? Value : never
436
+ : never
437
+
438
+ type SnapshotByIdentifier<State, Path extends SnapshotIdentifier<State>> = SnapshotNode<State> extends infer Node ?
439
+ Node extends { readonly path: Path } ? Node : never
440
+ : never
441
+
442
+ type ChildState<Child extends Machine.ChildMachine.Any> = RefState<Machine.ChildMachine.Ref<Child>>
443
+
444
+ const selectValueByPath = <
445
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
446
+ Path extends SnapshotIdentifier<State>
447
+ >(
448
+ snapshot: State,
449
+ path: Path
450
+ ): Option.Option<SnapshotValueByIdentifier<State, Path>> =>
451
+ Topology.getSnapshotByPath(snapshot, path).pipe(
452
+ Option.map((snapshot) => snapshot.value)
453
+ ) as Option.Option<SnapshotValueByIdentifier<State, Path>>
454
+
455
+ const selectSnapshotByPath = <
456
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
457
+ Path extends SnapshotIdentifier<State>
458
+ >(
459
+ snapshot: State,
460
+ path: Path
461
+ ): Option.Option<SnapshotByIdentifier<State, Path>> =>
462
+ Topology.getSnapshotByPath(snapshot, path) as Option.Option<SnapshotByIdentifier<State, Path>>
463
+
464
+ export const select = <
465
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
466
+ Event,
467
+ Error,
468
+ Output,
469
+ StartError,
470
+ const Path extends SnapshotIdentifier<State>
471
+ >(
472
+ self: MachineAtom<State, Event, Error, Output, StartError>,
473
+ path: Path
474
+ ): Atom.Atom<
475
+ AsyncResult.AsyncResult<Option.Option<SnapshotValueByIdentifier<State, Path>>, StartError | Error>
476
+ > =>
477
+ Atom.mapResult(self.result, (snapshot) => selectValueByPath(snapshot, path)).pipe(
478
+ Atom.withEquality(Equal.equals)
479
+ )
480
+
481
+ export const selectSnapshot = <
482
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
483
+ Event,
484
+ Error,
485
+ Output,
486
+ StartError,
487
+ const Path extends SnapshotIdentifier<State>
488
+ >(
489
+ self: MachineAtom<State, Event, Error, Output, StartError>,
490
+ path: Path
491
+ ): Atom.Atom<
492
+ AsyncResult.AsyncResult<Option.Option<SnapshotByIdentifier<State, Path>>, StartError | Error>
493
+ > =>
494
+ Atom.mapResult(self.result, (snapshot) => selectSnapshotByPath(snapshot, path)).pipe(
495
+ Atom.withEquality(Equal.equals)
496
+ )
497
+
498
+ export const selectChild = <
499
+ Child extends Machine.ChildMachine.Any,
500
+ StartError,
501
+ const Path extends SnapshotIdentifier<ChildState<Child>>
502
+ >(
503
+ self: ChildMachineAtom<Child, StartError>,
504
+ path: Path
505
+ ): Atom.Atom<
506
+ AsyncResult.AsyncResult<
507
+ Option.Option<SnapshotValueByIdentifier<ChildState<Child>, Path>>,
508
+ StartError | RefError<Machine.ChildMachine.Ref<Child>>
509
+ >
510
+ > =>
511
+ Atom.mapResult(
512
+ self.result,
513
+ Option.flatMap((snapshot) => selectValueByPath(snapshot, path))
514
+ ).pipe(Atom.withEquality(Equal.equals))
515
+
516
+ export const selectSnapshotChild = <
517
+ Child extends Machine.ChildMachine.Any,
518
+ StartError,
519
+ const Path extends SnapshotIdentifier<ChildState<Child>>
520
+ >(
521
+ self: ChildMachineAtom<Child, StartError>,
522
+ path: Path
523
+ ): Atom.Atom<
524
+ AsyncResult.AsyncResult<
525
+ Option.Option<SnapshotByIdentifier<ChildState<Child>, Path>>,
526
+ StartError | RefError<Machine.ChildMachine.Ref<Child>>
527
+ >
528
+ > =>
529
+ Atom.mapResult(
530
+ self.result,
531
+ Option.flatMap((snapshot) => selectSnapshotByPath(snapshot, path))
532
+ ).pipe(Atom.withEquality(Equal.equals))
533
+
534
+ export const matches = <
535
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
536
+ Event,
537
+ Error,
538
+ Output,
539
+ StartError,
540
+ const Path extends SnapshotIdentifier<State>
541
+ >(
542
+ self: MachineAtom<State, Event, Error, Output, StartError>,
543
+ path: Path
544
+ ): Atom.Atom<AsyncResult.AsyncResult<boolean, StartError | Error>> =>
545
+ Atom.mapResult(self.result, (snapshot) => Option.isSome(Topology.getSnapshotByPath(snapshot, path))).pipe(
546
+ Atom.withEquality(Equal.equals)
547
+ )
548
+
549
+ export const matchesChild = <
550
+ Child extends Machine.ChildMachine.Any,
551
+ StartError,
552
+ const Path extends SnapshotIdentifier<ChildState<Child>>
553
+ >(
554
+ self: ChildMachineAtom<Child, StartError>,
555
+ path: Path
556
+ ): Atom.Atom<
557
+ AsyncResult.AsyncResult<boolean, StartError | RefError<Machine.ChildMachine.Ref<Child>>>
558
+ > =>
559
+ Atom.mapResult(
560
+ self.result,
561
+ Option.exists((snapshot) => Option.isSome(Topology.getSnapshotByPath(snapshot, path)))
562
+ ).pipe(Atom.withEquality(Equal.equals))
563
+
564
+ type MachineResumeRequirementsOf<M extends Machine.Machine.Any> = MachineResumeRequirements<
565
+ Machine.Machine.Services<M>,
566
+ Machine.Machine.Event<M>,
567
+ Machine.Machine.Emit<M>
568
+ >
569
+
570
+ type EnsureMachineExecutable<M extends Machine.Machine.Any> = IsAny<Machine.Machine.States<M>> extends true ? {
571
+ readonly "~effect/reactivity/AtomMachine/ConcreteMachineRequired": M
572
+ }
573
+ : EnsureExecutable<
574
+ Machine.Machine.States<M>,
575
+ Machine.Machine.UnhandledStates<M>,
576
+ Machine.Machine.OutputStates<M>
577
+ >
578
+
579
+ type ResumedMachineAtomOf<M extends Machine.Machine.Any, RuntimeError> = MachineAtom<
580
+ Machine.Machine.Snapshot<Machine.Machine.States<M>>,
581
+ Machine.Machine.InputEvent<M>,
582
+ MachineRuntimeError<Machine.Machine.Error<M>, Machine.Machine.Services<M>>,
583
+ Machine.Machine.Output<M>,
584
+ Machine.MachineSchemaDecodeError | RuntimeError
585
+ >
586
+
587
+ export const make: {
588
+ <
589
+ const States extends Machine.Machine.StateSchemas,
590
+ const Events extends ReadonlyArray<Machine.Machine.TaggedSchema>,
591
+ const Emits extends ReadonlyArray<Machine.Machine.TaggedSchema> = any,
592
+ const Input extends Schema.Top = typeof Schema.Void,
593
+ UnhandledStates extends Machine.Machine.StateIdentifier<States> = Machine.Machine.StateIdentifier<States>,
594
+ E = never,
595
+ R = never,
596
+ InitialE = never,
597
+ InitialR = never,
598
+ FinalStates extends Machine.Machine.StateIdentifier<States> = never,
599
+ Output = never,
600
+ OutputStates extends Machine.Machine.StateIdentifier<States> = never,
601
+ InputEvents extends ReadonlyArray<Machine.Machine.TaggedSchema> = Events
602
+ >(
603
+ machine:
604
+ & Machine.Machine<
605
+ States,
606
+ Events,
607
+ Input,
608
+ UnhandledStates,
609
+ E,
610
+ R,
611
+ InitialE,
612
+ InitialR,
613
+ FinalStates,
614
+ Output,
615
+ Emits,
616
+ OutputStates,
617
+ InputEvents
618
+ >
619
+ & EnsureNoExternalRequirements<
620
+ MachineRequirements<
621
+ InitialR,
622
+ R,
623
+ Machine.Machine.EventOf<Events>,
624
+ Machine.Machine.EmitOf<Emits>
625
+ >
626
+ >
627
+ & EnsureExecutable<States, UnhandledStates, OutputStates>,
628
+ ...args: [...Machine.Machine.InputArgs<Input>]
629
+ ): MachineAtom<
630
+ Machine.Machine.Snapshot<States>,
631
+ Machine.Machine.EventOf<InputEvents>,
632
+ MachineRuntimeError<E, R>,
633
+ Output,
634
+ MachineStartError<InitialE, E, InitialR, R>
635
+ >
636
+ } = ((machine: Machine.Machine.Any, ...args: ReadonlyArray<unknown>) => {
637
+ const ref = Atom.make((get) => startMachineAtomEffect(get, machine as any, args as []))
638
+ return makeFromRefAtom(ref as any)
639
+ }) as any
640
+
641
+ export const resume: {
642
+ <M extends Machine.Machine.Any>(
643
+ machine:
644
+ & M
645
+ & EnsureNoExternalRequirements<MachineResumeRequirementsOf<NoInfer<M>>>
646
+ & EnsureMachineExecutable<NoInfer<M>>,
647
+ snapshot: Machine.Machine.Snapshot<Machine.Machine.States<M>>
648
+ ): ResumedMachineAtomOf<M, never>
649
+ } = ((machine: Machine.Machine.Any, snapshot: Machine.Machine.Snapshot<any>) => {
650
+ const ref = Atom.make((get) => resumeMachineAtomEffect(get, machine, snapshot))
651
+ return makeFromRefAtom(ref as any)
652
+ }) as any
653
+
654
+ const makeWithRuntime = (
655
+ runtime: Atom.AtomRuntime<any, any>,
656
+ machine: Machine.Machine.Any,
657
+ args: ReadonlyArray<unknown>
658
+ ): MachineAtom<any, any, any, any, any> => {
659
+ const ref = runtime.atom((get) => startMachineAtomEffect(get, machine as any, args as []))
660
+ return makeFromRefAtom(ref as any)
661
+ }
662
+
663
+ const resumeWithRuntime = (
664
+ runtime: Atom.AtomRuntime<any, any>,
665
+ machine: Machine.Machine.Any,
666
+ snapshot: Machine.Machine.Snapshot<any>
667
+ ): MachineAtom<any, any, any, any, any> => {
668
+ const ref = runtime.atom((get) => resumeMachineAtomEffect(get, machine, snapshot))
669
+ return makeFromRefAtom(ref as any)
670
+ }
671
+
672
+ export const bind = <Services, RuntimeError>(
673
+ runtime: Atom.AtomRuntime<Services, RuntimeError>
674
+ ): Bound<Services, RuntimeError> => ({
675
+ make:
676
+ ((machine: Machine.Machine.Any, ...args: ReadonlyArray<unknown>) =>
677
+ makeWithRuntime(runtime, machine, args)) as Bound<
678
+ Services,
679
+ RuntimeError
680
+ >["make"],
681
+ resume:
682
+ ((machine: Machine.Machine.Any, snapshot: Machine.Machine.Snapshot<any>) =>
683
+ resumeWithRuntime(runtime, machine, snapshot)) as Bound<Services, RuntimeError>["resume"]
684
+ })