@typeonce/effect-machine 0.9.0 → 0.11.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 +167 -28
- package/dist/Machine.d.ts +491 -283
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +74 -76
- package/dist/Machine.js.map +1 -1
- package/dist/internal/machine/atom.d.ts +7 -3
- package/dist/internal/machine/atom.d.ts.map +1 -1
- package/dist/internal/machine/atom.js +42 -6
- package/dist/internal/machine/atom.js.map +1 -1
- package/dist/internal/machine/cluster.d.ts.map +1 -1
- package/dist/internal/machine/cluster.js +2 -1
- package/dist/internal/machine/cluster.js.map +1 -1
- package/dist/internal/machine/command.js +2 -2
- package/dist/internal/machine/command.js.map +1 -1
- package/dist/internal/machine/commandRuntime.d.ts.map +1 -1
- package/dist/internal/machine/commandRuntime.js +6 -3
- package/dist/internal/machine/commandRuntime.js.map +1 -1
- package/dist/internal/machine/configuration.d.ts +8 -1
- package/dist/internal/machine/configuration.d.ts.map +1 -1
- package/dist/internal/machine/configuration.js +9 -4
- package/dist/internal/machine/configuration.js.map +1 -1
- package/dist/internal/machine/errors.d.ts +1 -1
- package/dist/internal/machine/errors.d.ts.map +1 -1
- package/dist/internal/machine/executionPlan.d.ts +3 -3
- package/dist/internal/machine/executionPlan.d.ts.map +1 -1
- package/dist/internal/machine/executionPlan.js +50 -25
- package/dist/internal/machine/executionPlan.js.map +1 -1
- package/dist/internal/machine/invocation.d.ts.map +1 -1
- package/dist/internal/machine/invocation.js +3 -2
- package/dist/internal/machine/invocation.js.map +1 -1
- package/dist/internal/machine/machine.d.ts +15 -19
- package/dist/internal/machine/machine.d.ts.map +1 -1
- package/dist/internal/machine/machine.js +16 -10
- package/dist/internal/machine/machine.js.map +1 -1
- package/dist/internal/machine/planner.d.ts +2 -1
- package/dist/internal/machine/planner.d.ts.map +1 -1
- package/dist/internal/machine/planner.js +61 -24
- package/dist/internal/machine/planner.js.map +1 -1
- package/dist/internal/machine/process.d.ts +3 -0
- package/dist/internal/machine/process.d.ts.map +1 -1
- package/dist/internal/machine/process.js +11 -8
- package/dist/internal/machine/process.js.map +1 -1
- package/dist/internal/machine/protocol.d.ts +7 -13
- package/dist/internal/machine/protocol.d.ts.map +1 -1
- package/dist/internal/machine/protocol.js +128 -50
- package/dist/internal/machine/protocol.js.map +1 -1
- package/dist/internal/machine/runtime.d.ts +22 -2
- package/dist/internal/machine/runtime.d.ts.map +1 -1
- package/dist/internal/machine/runtime.js +138 -10
- package/dist/internal/machine/runtime.js.map +1 -1
- package/dist/internal/machine/topology.d.ts +7 -0
- package/dist/internal/machine/topology.d.ts.map +1 -1
- package/dist/internal/machine/topology.js +6 -0
- package/dist/internal/machine/topology.js.map +1 -1
- package/dist/internal/testing/machine/finiteModel.js +1 -1
- package/dist/internal/testing/machine/finiteModel.js.map +1 -1
- package/dist/internal/testing/machine/runtime.d.ts.map +1 -1
- package/dist/internal/testing/machine/runtime.js +2 -1
- package/dist/internal/testing/machine/runtime.js.map +1 -1
- package/dist/internal/testing/machine/verification.d.ts.map +1 -1
- package/dist/internal/testing/machine/verification.js +5 -3
- package/dist/internal/testing/machine/verification.js.map +1 -1
- package/dist/testing/MachineTest.d.ts +7 -7
- package/dist/testing/MachineTest.js +7 -7
- package/dist/unstable/cluster/ClusterMachine.d.ts +1 -1
- package/dist/unstable/cluster/ClusterMachine.js +1 -1
- package/dist/unstable/reactivity/AtomMachine.d.ts +27 -8
- package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.js +20 -3
- package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
- package/docs/agent-guide.md +191 -54
- package/package.json +1 -1
- package/src/Machine.ts +1220 -360
- package/src/internal/machine/atom.ts +76 -53
- package/src/internal/machine/cluster.ts +2 -1
- package/src/internal/machine/command.ts +2 -2
- package/src/internal/machine/commandRuntime.ts +9 -4
- package/src/internal/machine/configuration.ts +23 -5
- package/src/internal/machine/errors.ts +1 -1
- package/src/internal/machine/executionPlan.ts +74 -29
- package/src/internal/machine/invocation.ts +3 -2
- package/src/internal/machine/machine.ts +74 -49
- package/src/internal/machine/planner.ts +68 -24
- package/src/internal/machine/process.ts +75 -8
- package/src/internal/machine/protocol.ts +207 -68
- package/src/internal/machine/runtime.ts +266 -11
- package/src/internal/machine/topology.ts +15 -0
- package/src/internal/testing/machine/finiteModel.ts +1 -1
- package/src/internal/testing/machine/runtime.ts +2 -1
- package/src/internal/testing/machine/verification.ts +5 -3
- package/src/testing/MachineTest.ts +7 -7
- package/src/unstable/cluster/ClusterMachine.ts +1 -1
- package/src/unstable/reactivity/AtomMachine.ts +44 -10
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
import * as Data from "effect/Data"
|
|
8
8
|
import * as Effect from "effect/Effect"
|
|
9
9
|
import * as Equal from "effect/Equal"
|
|
10
|
+
import * as Fiber from "effect/Fiber"
|
|
10
11
|
import * as Option from "effect/Option"
|
|
11
12
|
import type * as Schema from "effect/Schema"
|
|
12
13
|
import type * as Scope from "effect/Scope"
|
|
13
14
|
import * as Stream from "effect/Stream"
|
|
14
|
-
import { AsyncResult, Atom,
|
|
15
|
+
import { AsyncResult, Atom, AtomRegistry } from "effect/unstable/reactivity"
|
|
15
16
|
import type * as Machine from "../../Machine.js"
|
|
16
17
|
import type { Bound, ChildMachineAtom, MachineAtom } from "../../unstable/reactivity/AtomMachine.js"
|
|
17
18
|
import * as internalMachine from "./machine.js"
|
|
@@ -72,9 +73,14 @@ type MachineStartError<InitialE, E, InitialR, R, RuntimeError = never> =
|
|
|
72
73
|
| Machine.StoppedError
|
|
73
74
|
| RuntimeError
|
|
74
75
|
|
|
75
|
-
const
|
|
76
|
+
const preparedByMachineAtom = new WeakMap<
|
|
77
|
+
object,
|
|
78
|
+
Atom.Atom<AsyncResult.AsyncResult<Machine.Prepared<any, any, any, any, any, any, any>, any>>
|
|
79
|
+
>()
|
|
80
|
+
|
|
81
|
+
const runMachineAtomEffect = <State, Event, Error, Output, Emitted, StartError, Requirements>(
|
|
76
82
|
get: Atom.AtomContext,
|
|
77
|
-
start: Effect.Effect<Machine.MachineRef<State, Event, Error, Output>, StartError, Requirements>
|
|
83
|
+
start: Effect.Effect<Machine.MachineRef<State, Event, Error, Output, Emitted>, StartError, Requirements>
|
|
78
84
|
): Effect.Effect<never, StartError, Requirements> =>
|
|
79
85
|
Effect.scoped(
|
|
80
86
|
Effect.acquireRelease(start, (ref) => ref.stop).pipe(
|
|
@@ -83,50 +89,16 @@ const runMachineAtomEffect = <State, Event, Error, Output, StartError, Requireme
|
|
|
83
89
|
)
|
|
84
90
|
)
|
|
85
91
|
|
|
86
|
-
const
|
|
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
|
-
>(
|
|
92
|
+
const startPreparedMachineAtomEffect = <State, Event, Error, Output, Emitted, StartError, Requirements>(
|
|
101
93
|
get: Atom.AtomContext,
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
Input,
|
|
107
|
-
UnhandledStates,
|
|
108
|
-
E,
|
|
109
|
-
R,
|
|
110
|
-
InitialE,
|
|
111
|
-
InitialR,
|
|
112
|
-
FinalStates,
|
|
113
|
-
Output,
|
|
114
|
-
Emits,
|
|
115
|
-
OutputStates,
|
|
116
|
-
InputEvents
|
|
94
|
+
prepared: Atom.Atom<
|
|
95
|
+
AsyncResult.AsyncResult<
|
|
96
|
+
Machine.Prepared<State, Event, Error, Output, Emitted, StartError, Requirements>,
|
|
97
|
+
never
|
|
117
98
|
>
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
)
|
|
121
|
-
Machine.MachineRef<
|
|
122
|
-
Machine.Machine.Snapshot<States>,
|
|
123
|
-
Machine.Machine.EventInputOf<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))
|
|
99
|
+
>
|
|
100
|
+
): Effect.Effect<never, StartError, Requirements> =>
|
|
101
|
+
runMachineAtomEffect(get, get.result(prepared).pipe(Effect.flatMap((prepared) => prepared.start)))
|
|
130
102
|
|
|
131
103
|
const resumeMachineAtomEffect = (
|
|
132
104
|
get: Atom.AtomContext,
|
|
@@ -137,6 +109,47 @@ const resumeMachineAtomEffect = (
|
|
|
137
109
|
type RefState<Ref> = Ref extends Machine.MachineRef<infer State, any, any, any> ? State : never
|
|
138
110
|
type RefError<Ref> = Ref extends Machine.MachineRef<any, any, infer Error, any> ? Error : never
|
|
139
111
|
type RefOutput<Ref> = Ref extends Machine.MachineRef<any, any, any, infer Output> ? Output : never
|
|
112
|
+
type RefEmitted<Ref> = Ref extends Machine.MachineRef<any, any, any, any, infer Emitted> ? Emitted : never
|
|
113
|
+
|
|
114
|
+
export const emissions = <State, Event, Error, Output, StartError, Emitted>(
|
|
115
|
+
self: MachineAtom<State, Event, Error, Output, StartError, Emitted>
|
|
116
|
+
): Stream.Stream<Emitted, StartError, AtomRegistry.AtomRegistry> => {
|
|
117
|
+
const prepared = preparedByMachineAtom.get(self as object)
|
|
118
|
+
if (prepared === undefined) {
|
|
119
|
+
return Atom.toStreamResult(self.ref).pipe(Stream.flatMap((ref) => ref.emissions))
|
|
120
|
+
}
|
|
121
|
+
return Stream.unwrap(
|
|
122
|
+
Effect.gen(function*() {
|
|
123
|
+
const registry = yield* AtomRegistry.AtomRegistry
|
|
124
|
+
const releasePrepared = yield* Effect.sync(() => registry.mount(prepared))
|
|
125
|
+
yield* Effect.addFinalizer(() => Effect.sync(releasePrepared))
|
|
126
|
+
const machine = yield* Atom.getResult(prepared)
|
|
127
|
+
const pull = yield* Stream.toPull(machine.emissions as Stream.Stream<Emitted>)
|
|
128
|
+
const firstPull = yield* pull.pipe(Effect.forkScoped({ startImmediately: true }))
|
|
129
|
+
const releaseRef = yield* Effect.sync(() => registry.mount(self.ref))
|
|
130
|
+
yield* Effect.addFinalizer(() => Effect.sync(releaseRef))
|
|
131
|
+
yield* Atom.getResult(self.ref)
|
|
132
|
+
let first = true
|
|
133
|
+
return Stream.fromPull(Effect.succeed(Effect.suspend(() => {
|
|
134
|
+
if (!first) return pull
|
|
135
|
+
first = false
|
|
136
|
+
return Fiber.join(firstPull)
|
|
137
|
+
})))
|
|
138
|
+
})
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const childEmissions = <Child extends Machine.ChildMachine.Any, StartError>(
|
|
143
|
+
self: ChildMachineAtom<Child, StartError>
|
|
144
|
+
): Stream.Stream<RefEmitted<Machine.ChildMachine.Ref<Child>>, StartError, AtomRegistry.AtomRegistry> =>
|
|
145
|
+
Atom.toStreamResult(self.ref).pipe(
|
|
146
|
+
Stream.flatMap(
|
|
147
|
+
Option.match({
|
|
148
|
+
onNone: () => Stream.empty,
|
|
149
|
+
onSome: (ref) => ref.emissions
|
|
150
|
+
})
|
|
151
|
+
)
|
|
152
|
+
)
|
|
140
153
|
|
|
141
154
|
const makeRuntimeResultAtom = <State, Error, Output, StartError>(
|
|
142
155
|
snapshot: Atom.Atom<AsyncResult.AsyncResult<Machine.RuntimeSnapshot<State, Error, Output>, StartError>>
|
|
@@ -588,7 +601,8 @@ type ResumedMachineAtomOf<M extends Machine.Machine.Any, RuntimeError> = Machine
|
|
|
588
601
|
Machine.Machine.EventInput<Machine.Machine.InputEvent<M>>,
|
|
589
602
|
MachineRuntimeError<Machine.Machine.Error<M>, Machine.Machine.Services<M>>,
|
|
590
603
|
Machine.Machine.Output<M>,
|
|
591
|
-
Machine.MachineSchemaDecodeError | RuntimeError
|
|
604
|
+
Machine.MachineSchemaDecodeError | RuntimeError,
|
|
605
|
+
Machine.Machine.EmittedEvent<M>
|
|
592
606
|
>
|
|
593
607
|
|
|
594
608
|
export const make: {
|
|
@@ -605,7 +619,8 @@ export const make: {
|
|
|
605
619
|
FinalStates extends Machine.Machine.StateIdentifier<States> = never,
|
|
606
620
|
Output = never,
|
|
607
621
|
OutputStates extends Machine.Machine.StateIdentifier<States> = never,
|
|
608
|
-
InputEvents extends ReadonlyArray<Machine.Machine.TaggedSchema> = Events
|
|
622
|
+
InputEvents extends ReadonlyArray<Machine.Machine.TaggedSchema> = Events,
|
|
623
|
+
ParentEvents extends ReadonlyArray<Machine.Machine.TaggedSchema> = readonly []
|
|
609
624
|
>(
|
|
610
625
|
machine:
|
|
611
626
|
& Machine.Machine<
|
|
@@ -621,7 +636,8 @@ export const make: {
|
|
|
621
636
|
Output,
|
|
622
637
|
Emits,
|
|
623
638
|
OutputStates,
|
|
624
|
-
InputEvents
|
|
639
|
+
InputEvents,
|
|
640
|
+
ParentEvents
|
|
625
641
|
>
|
|
626
642
|
& EnsureNoExternalRequirements<
|
|
627
643
|
MachineRequirements<
|
|
@@ -638,11 +654,15 @@ export const make: {
|
|
|
638
654
|
Machine.Machine.EventInputOf<InputEvents>,
|
|
639
655
|
MachineRuntimeError<E, R>,
|
|
640
656
|
Output,
|
|
641
|
-
MachineStartError<InitialE, E, InitialR, R
|
|
657
|
+
MachineStartError<InitialE, E, InitialR, R>,
|
|
658
|
+
Machine.Machine.EmittedEventOf<Emits>
|
|
642
659
|
>
|
|
643
660
|
} = ((machine: Machine.Machine.Any, ...args: ReadonlyArray<unknown>) => {
|
|
644
|
-
const
|
|
645
|
-
|
|
661
|
+
const prepared = Atom.make(() => internalMachine.prepare(machine as any, ...(args as [])))
|
|
662
|
+
const ref = Atom.make((get) => startPreparedMachineAtomEffect(get, prepared as any))
|
|
663
|
+
const result = makeFromRefAtom(ref as any)
|
|
664
|
+
preparedByMachineAtom.set(result, prepared as any)
|
|
665
|
+
return result
|
|
646
666
|
}) as any
|
|
647
667
|
|
|
648
668
|
export const resume: {
|
|
@@ -663,8 +683,11 @@ const makeWithRuntime = (
|
|
|
663
683
|
machine: Machine.Machine.Any,
|
|
664
684
|
args: ReadonlyArray<unknown>
|
|
665
685
|
): MachineAtom<any, any, any, any, any> => {
|
|
666
|
-
const
|
|
667
|
-
|
|
686
|
+
const prepared = runtime.atom(() => internalMachine.prepare(machine as any, ...(args as [])))
|
|
687
|
+
const ref = runtime.atom((get) => startPreparedMachineAtomEffect(get, prepared as any))
|
|
688
|
+
const result = makeFromRefAtom(ref as any)
|
|
689
|
+
preparedByMachineAtom.set(result, prepared as any)
|
|
690
|
+
return result
|
|
668
691
|
}
|
|
669
692
|
|
|
670
693
|
const resumeWithRuntime = (
|
|
@@ -14,6 +14,7 @@ import { Rpc } from "effect/unstable/rpc"
|
|
|
14
14
|
import type * as Machine from "../../Machine.js"
|
|
15
15
|
import type { Checkpoint, ClusterMachine, LoadResult } from "../../unstable/cluster/ClusterMachine.js"
|
|
16
16
|
import * as internalMachine from "./machine.js"
|
|
17
|
+
import * as Protocol from "./protocol.js"
|
|
17
18
|
import type { EnsureExecutable } from "./readiness.js"
|
|
18
19
|
|
|
19
20
|
type EntityAddress = EntityAddress.EntityAddress
|
|
@@ -248,7 +249,7 @@ export const make = <
|
|
|
248
249
|
OutputStates,
|
|
249
250
|
InputEvents
|
|
250
251
|
>
|
|
251
|
-
const eventSchema = Schema.Union(machine
|
|
252
|
+
const eventSchema = Schema.Union(Protocol.inputEventSchemas(machine) as MachineEvents<M>)
|
|
252
253
|
const rpc = Rpc.make("send", {
|
|
253
254
|
payload: eventSchema,
|
|
254
255
|
success: SendResult
|
|
@@ -47,8 +47,8 @@ export const makeCollector = <Event>(machine: Machine.Any): Collected<Event> =>
|
|
|
47
47
|
emit: (event) => {
|
|
48
48
|
emittedEvents.push(decodeEmitSync(machine, event))
|
|
49
49
|
},
|
|
50
|
-
sendTo: (
|
|
51
|
-
commands.push({ _tag: "SendTo",
|
|
50
|
+
sendTo: (target: unknown, event: unknown) => {
|
|
51
|
+
commands.push({ _tag: "SendTo", target: target as any, event })
|
|
52
52
|
},
|
|
53
53
|
stop: (child: unknown) => {
|
|
54
54
|
commands.push({ _tag: "Stop", child: child as any })
|
|
@@ -10,6 +10,9 @@ import type { RuntimeCommand } from "./command.js"
|
|
|
10
10
|
import { decodeEmit, decodeEvent } from "./protocol.js"
|
|
11
11
|
import type { ProcessScope } from "./runtime.js"
|
|
12
12
|
|
|
13
|
+
const isActorRef = (target: unknown): target is { readonly send: (event: unknown) => Effect.Effect<void, unknown> } =>
|
|
14
|
+
typeof target === "object" && target !== null && "send" in target && typeof target.send === "function"
|
|
15
|
+
|
|
13
16
|
export const makeLiveRuntime = <Events, Emits>(
|
|
14
17
|
machine: Machine.Any,
|
|
15
18
|
scope: ProcessScope<Events>
|
|
@@ -18,9 +21,9 @@ export const makeLiveRuntime = <Events, Emits>(
|
|
|
18
21
|
decodeEvent(machine, event).pipe(
|
|
19
22
|
Effect.flatMap((event) => scope.self.send(event as Events))
|
|
20
23
|
),
|
|
21
|
-
|
|
24
|
+
emit: (event) =>
|
|
22
25
|
decodeEmit(machine, event).pipe(
|
|
23
|
-
Effect.flatMap((event) => scope.
|
|
26
|
+
Effect.flatMap((event) => scope.emit(event))
|
|
24
27
|
)
|
|
25
28
|
})
|
|
26
29
|
|
|
@@ -30,7 +33,9 @@ export const runCommands = <Event>(
|
|
|
30
33
|
) =>
|
|
31
34
|
Effect.forEach(commands, (command) =>
|
|
32
35
|
command._tag === "SendTo"
|
|
33
|
-
?
|
|
36
|
+
? isActorRef(command.target)
|
|
37
|
+
? command.target.send(command.event)
|
|
38
|
+
: scope.sendTo(command.target as never, command.event)
|
|
34
39
|
: scope.stopChild(command.child as never), { discard: true })
|
|
35
40
|
|
|
36
41
|
export const runEmittedEvents = <Events, Emits>(
|
|
@@ -38,6 +43,6 @@ export const runEmittedEvents = <Events, Emits>(
|
|
|
38
43
|
runtime: Runtime<Events, Emits>
|
|
39
44
|
) =>
|
|
40
45
|
Effect.all(
|
|
41
|
-
Array.from(events, (event) => runtime.
|
|
46
|
+
Array.from(events, (event) => runtime.emit(event)),
|
|
42
47
|
{ discard: true }
|
|
43
48
|
)
|
|
@@ -8,7 +8,7 @@ import * as Cause from "effect/Cause"
|
|
|
8
8
|
import * as Effect from "effect/Effect"
|
|
9
9
|
import * as Option from "effect/Option"
|
|
10
10
|
import { hasProperty } from "effect/Predicate"
|
|
11
|
-
import type { Machine } from "../../Machine.js"
|
|
11
|
+
import type { ActorRef, Machine } from "../../Machine.js"
|
|
12
12
|
import { MachineSchemaDecodeError } from "./errors.js"
|
|
13
13
|
import {
|
|
14
14
|
decodeBoundary,
|
|
@@ -252,8 +252,26 @@ export interface ActiveConfiguration {
|
|
|
252
252
|
readonly values: ReadonlyMap<string, unknown>
|
|
253
253
|
readonly outputs: ReadonlyMap<string, unknown>
|
|
254
254
|
readonly history: ReadonlyMap<string, HistoryRecord>
|
|
255
|
+
readonly actorScope?: PlanningActorScope
|
|
255
256
|
}
|
|
256
257
|
|
|
258
|
+
export interface PlanningActorScope {
|
|
259
|
+
readonly self: ActorRef<any>
|
|
260
|
+
readonly parent: ActorRef<any> | undefined
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export const withActorScope = (
|
|
264
|
+
configuration: ActiveConfiguration,
|
|
265
|
+
actorScope: PlanningActorScope
|
|
266
|
+
): ActiveConfiguration => ({
|
|
267
|
+
...configuration,
|
|
268
|
+
actorScope: { self: actorScope.self, parent: actorScope.parent }
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
export const getActorScope = (
|
|
272
|
+
configuration: ActiveConfiguration
|
|
273
|
+
): PlanningActorScope | undefined => configuration.actorScope
|
|
274
|
+
|
|
257
275
|
export interface FinalCompletion {
|
|
258
276
|
readonly path: string
|
|
259
277
|
readonly output: unknown
|
|
@@ -1178,8 +1196,8 @@ export const resolveFinalOutputEffect: <
|
|
|
1178
1196
|
const node = getNode(machine, path)
|
|
1179
1197
|
const output = getStateConfigByPath(machine, path)?.output?.({
|
|
1180
1198
|
state: configuration.values.get(path),
|
|
1181
|
-
|
|
1182
|
-
|
|
1199
|
+
containingState: getParentValue(machine, configuration, path),
|
|
1200
|
+
ancestors: getParentValues(machine, configuration, path),
|
|
1183
1201
|
event,
|
|
1184
1202
|
outputs
|
|
1185
1203
|
} as any)
|
|
@@ -1331,8 +1349,8 @@ const resolveFinalOutputSync = <const Events extends ReadonlyArray<Machine.Tagge
|
|
|
1331
1349
|
const node = getNode(machine, path)
|
|
1332
1350
|
const output = getStateConfigByPath(machine, path)?.output?.({
|
|
1333
1351
|
state: configuration.values.get(path),
|
|
1334
|
-
|
|
1335
|
-
|
|
1352
|
+
containingState: getParentValue(machine, configuration, path),
|
|
1353
|
+
ancestors: getParentValues(machine, configuration, path),
|
|
1336
1354
|
event,
|
|
1337
1355
|
outputs
|
|
1338
1356
|
} as any)
|
|
@@ -25,7 +25,7 @@ export class MachineSchemaEncodeError extends Data.TaggedError("MachineSchemaEnc
|
|
|
25
25
|
*/
|
|
26
26
|
export class MachineSchemaDecodeError extends Data.TaggedError("MachineSchemaDecodeError")<{
|
|
27
27
|
readonly machineId: string | undefined
|
|
28
|
-
readonly boundary: "input" | "event" | "
|
|
28
|
+
readonly boundary: "input" | "event" | "emission" | "state" | "output" | "history" | "configuration"
|
|
29
29
|
readonly state?: string
|
|
30
30
|
readonly event?: string
|
|
31
31
|
readonly cause: Schema.SchemaError | Cause.Cause<unknown>
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* @since 0.4.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import * as Effect from "effect/Effect"
|
|
8
|
+
import type { ActorRef, Machine } from "../../Machine.js"
|
|
8
9
|
import { getTargetBuilder, type RuntimeCommand } from "./command.js"
|
|
9
10
|
import {
|
|
10
11
|
type ActiveConfiguration,
|
|
@@ -17,10 +18,12 @@ import {
|
|
|
17
18
|
isDescendantOf,
|
|
18
19
|
normalizeConfigurationSync,
|
|
19
20
|
normalizeTargetConfigurationSync,
|
|
21
|
+
type PlanningActorScope,
|
|
20
22
|
snapshotFromConfiguration,
|
|
21
|
-
validateInitialConfiguration
|
|
23
|
+
validateInitialConfiguration,
|
|
24
|
+
withActorScope
|
|
22
25
|
} from "./configuration.js"
|
|
23
|
-
import { InfiniteTransitionError } from "./errors.js"
|
|
26
|
+
import { InfiniteTransitionError, StoppedError } from "./errors.js"
|
|
24
27
|
import * as InvocationEvent from "./invocationEvent.js"
|
|
25
28
|
import {
|
|
26
29
|
broadenTransitionBoundary,
|
|
@@ -43,7 +46,7 @@ import {
|
|
|
43
46
|
validateDeclaredTransitionTarget
|
|
44
47
|
} from "./planner.js"
|
|
45
48
|
import { decodeEmitSync, decodeEventSync, decodeInputSync, decodeStateValueSync } from "./protocol.js"
|
|
46
|
-
import { isSnapshot, isTarget, TargetSnapshotTypeId } from "./topology.js"
|
|
49
|
+
import { isNoTarget, isSnapshot, isTarget, TargetSnapshotTypeId } from "./topology.js"
|
|
47
50
|
|
|
48
51
|
interface IndexedExecutionDescriptor {
|
|
49
52
|
readonly flat: boolean
|
|
@@ -64,6 +67,29 @@ interface IndexedExecutionDescriptor {
|
|
|
64
67
|
>
|
|
65
68
|
}
|
|
66
69
|
|
|
70
|
+
const planningActorScopes = new WeakMap<Machine.Any, PlanningActorScope>()
|
|
71
|
+
|
|
72
|
+
const getPlanningActorScope = (machine: Machine.Any): PlanningActorScope => {
|
|
73
|
+
const cached = planningActorScopes.get(machine)
|
|
74
|
+
if (cached !== undefined) return cached
|
|
75
|
+
const self: ActorRef<unknown> = {
|
|
76
|
+
id: machine.id ?? "Machine",
|
|
77
|
+
sessionId: "Machine.plan",
|
|
78
|
+
send: () => Effect.fail(new StoppedError())
|
|
79
|
+
}
|
|
80
|
+
const scope = { self, parent: undefined }
|
|
81
|
+
planningActorScopes.set(machine, scope)
|
|
82
|
+
return scope
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const getActorContext = (
|
|
86
|
+
machine: Machine.Any,
|
|
87
|
+
actorScope: PlanningActorScope | undefined
|
|
88
|
+
): PlanningActorScope =>
|
|
89
|
+
actorScope === undefined
|
|
90
|
+
? getPlanningActorScope(machine)
|
|
91
|
+
: { self: actorScope.self, parent: actorScope.parent }
|
|
92
|
+
|
|
67
93
|
const indexedStateConfigKeys: ReadonlySet<PropertyKey> = new Set([
|
|
68
94
|
"initial",
|
|
69
95
|
"invoke",
|
|
@@ -336,18 +362,20 @@ const makeIndexedTransitionContext = (
|
|
|
336
362
|
descriptor: IndexedExecutionDescriptor,
|
|
337
363
|
configuration: OwnedIndexedState,
|
|
338
364
|
sourceIndex: number,
|
|
339
|
-
event: any
|
|
365
|
+
event: any,
|
|
366
|
+
actorScope?: PlanningActorScope
|
|
340
367
|
): any => {
|
|
341
368
|
const source = descriptor.nodes[sourceIndex]!
|
|
342
369
|
const parentIndex = descriptor.parentIndices[sourceIndex]!
|
|
343
|
-
const
|
|
370
|
+
const ancestors: Record<string, unknown> = {}
|
|
344
371
|
for (const ancestorIndex of descriptor.ancestorIndices[sourceIndex]!) {
|
|
345
|
-
|
|
372
|
+
ancestors[descriptor.nodes[ancestorIndex]!.path] = configuration.values[ancestorIndex]
|
|
346
373
|
}
|
|
347
374
|
return {
|
|
375
|
+
...getActorContext(machine, actorScope),
|
|
348
376
|
state: configuration.values[sourceIndex],
|
|
349
|
-
|
|
350
|
-
|
|
377
|
+
containingState: parentIndex < 0 ? undefined : configuration.values[parentIndex],
|
|
378
|
+
ancestors,
|
|
351
379
|
event,
|
|
352
380
|
snapshot: snapshotFromIndexedState(descriptor, configuration),
|
|
353
381
|
target: getTargetBuilder(machine, source.path)
|
|
@@ -399,7 +427,7 @@ const collectIndexedTransition = (
|
|
|
399
427
|
let commands: Array<RuntimeCommand> | undefined
|
|
400
428
|
let raisedEvents: Array<any> | undefined
|
|
401
429
|
let emittedEvents: Array<unknown> | undefined
|
|
402
|
-
const
|
|
430
|
+
const result = transition(context, {
|
|
403
431
|
raise: (event: unknown) => {
|
|
404
432
|
;(raisedEvents ??= []).push(decodeEventSync(machine, event))
|
|
405
433
|
},
|
|
@@ -407,14 +435,14 @@ const collectIndexedTransition = (
|
|
|
407
435
|
;(emittedEvents ??= []).push(decodeEmitSync(machine, event))
|
|
408
436
|
},
|
|
409
437
|
sendTo: (child: unknown, event: unknown) => {
|
|
410
|
-
;(commands ??= []).push({ _tag: "SendTo",
|
|
438
|
+
;(commands ??= []).push({ _tag: "SendTo", target: child as any, event })
|
|
411
439
|
},
|
|
412
440
|
stop: (child: unknown) => {
|
|
413
441
|
;(commands ??= []).push({ _tag: "Stop", child: child as any })
|
|
414
442
|
}
|
|
415
443
|
})
|
|
416
444
|
return {
|
|
417
|
-
state,
|
|
445
|
+
state: isNoTarget(result) ? undefined : result,
|
|
418
446
|
commands: commands ?? emptyExecutionValues,
|
|
419
447
|
raisedEvents: raisedEvents ?? emptyExecutionValues,
|
|
420
448
|
emittedEvents: emittedEvents ?? emptyExecutionValues
|
|
@@ -425,7 +453,8 @@ const selectIndexedEventTransitions = (
|
|
|
425
453
|
machine: Machine.Any,
|
|
426
454
|
descriptor: IndexedExecutionDescriptor,
|
|
427
455
|
configuration: OwnedIndexedState,
|
|
428
|
-
event: any
|
|
456
|
+
event: any,
|
|
457
|
+
actorScope?: PlanningActorScope
|
|
429
458
|
): ReadonlyArray<IndexedSelectedTransition> => {
|
|
430
459
|
const selected: Array<IndexedSelectedTransition> = []
|
|
431
460
|
for (const leafIndex of configuration.activeLeaves) {
|
|
@@ -446,7 +475,8 @@ const selectIndexedEventTransitions = (
|
|
|
446
475
|
descriptor,
|
|
447
476
|
configuration,
|
|
448
477
|
sourceIndex,
|
|
449
|
-
event
|
|
478
|
+
event,
|
|
479
|
+
actorScope
|
|
450
480
|
)
|
|
451
481
|
})
|
|
452
482
|
}
|
|
@@ -629,7 +659,8 @@ const planIndexedFlatState = (
|
|
|
629
659
|
descriptor: IndexedExecutionDescriptor,
|
|
630
660
|
configuration: OwnedIndexedState,
|
|
631
661
|
decoded: { readonly _tag: PropertyKey },
|
|
632
|
-
retainMicrosteps: boolean
|
|
662
|
+
retainMicrosteps: boolean,
|
|
663
|
+
actorScope?: PlanningActorScope
|
|
633
664
|
): ExecutionMacrostep<OwnedIndexedState> => {
|
|
634
665
|
let current = configuration
|
|
635
666
|
let event: any = decoded
|
|
@@ -681,9 +712,10 @@ const planIndexedFlatState = (
|
|
|
681
712
|
machine,
|
|
682
713
|
transition.transition,
|
|
683
714
|
{
|
|
715
|
+
...getActorContext(machine, actorScope),
|
|
684
716
|
state: current.values[sourceIndex],
|
|
685
|
-
|
|
686
|
-
|
|
717
|
+
containingState: undefined,
|
|
718
|
+
ancestors: {},
|
|
687
719
|
event,
|
|
688
720
|
snapshot: snapshotFromIndexedState(descriptor, current),
|
|
689
721
|
target: getTargetBuilder(machine, sourcePath)
|
|
@@ -774,7 +806,8 @@ const planIndexedState = (
|
|
|
774
806
|
descriptor: IndexedExecutionDescriptor,
|
|
775
807
|
configuration: OwnedIndexedState,
|
|
776
808
|
input: unknown,
|
|
777
|
-
retainMicrosteps: boolean
|
|
809
|
+
retainMicrosteps: boolean,
|
|
810
|
+
actorScope?: PlanningActorScope
|
|
778
811
|
): ExecutionMacrostep<OwnedIndexedState> => {
|
|
779
812
|
if (InvocationEvent.isInvocationEvent(input)) {
|
|
780
813
|
// Invocation lifecycle transitions retain the generic planner as their
|
|
@@ -783,7 +816,9 @@ const planIndexedState = (
|
|
|
783
816
|
// the representation boundary.
|
|
784
817
|
const planned = planConfiguration(
|
|
785
818
|
machine as any,
|
|
786
|
-
|
|
819
|
+
actorScope === undefined
|
|
820
|
+
? activeConfigurationFromIndexedState(descriptor, configuration)
|
|
821
|
+
: withActorScope(activeConfigurationFromIndexedState(descriptor, configuration), actorScope),
|
|
787
822
|
input
|
|
788
823
|
)
|
|
789
824
|
return {
|
|
@@ -806,7 +841,7 @@ const planIndexedState = (
|
|
|
806
841
|
}
|
|
807
842
|
const decoded = decodeEventSync(machine, input)
|
|
808
843
|
if (descriptor.flat) {
|
|
809
|
-
return planIndexedFlatState(machine, descriptor, configuration, decoded, retainMicrosteps)
|
|
844
|
+
return planIndexedFlatState(machine, descriptor, configuration, decoded, retainMicrosteps, actorScope)
|
|
810
845
|
}
|
|
811
846
|
if (descriptor.finalIndices.some((index) => configuration.active[index] === 1)) {
|
|
812
847
|
const active = activeConfigurationFromIndexedState(descriptor, configuration)
|
|
@@ -827,7 +862,7 @@ const planIndexedState = (
|
|
|
827
862
|
}
|
|
828
863
|
}
|
|
829
864
|
|
|
830
|
-
const selections = selectIndexedEventTransitions(machine, descriptor, configuration, decoded)
|
|
865
|
+
const selections = selectIndexedEventTransitions(machine, descriptor, configuration, decoded, actorScope)
|
|
831
866
|
if (selections.length === 0) {
|
|
832
867
|
return {
|
|
833
868
|
next: configuration,
|
|
@@ -895,7 +930,7 @@ const planIndexedState = (
|
|
|
895
930
|
}
|
|
896
931
|
raisedIndex += 1
|
|
897
932
|
currentEvent = raised
|
|
898
|
-
const raisedSelections = selectIndexedEventTransitions(machine, descriptor, current, raised)
|
|
933
|
+
const raisedSelections = selectIndexedEventTransitions(machine, descriptor, current, raised, actorScope)
|
|
899
934
|
if (raisedSelections.length === 0) continue
|
|
900
935
|
const step = indexedMicrostep(machine, descriptor, current, raised, raisedSelections)
|
|
901
936
|
current = step.next
|
|
@@ -913,10 +948,12 @@ export interface CompiledExecutionPlan {
|
|
|
913
948
|
readonly plan: (
|
|
914
949
|
state: unknown,
|
|
915
950
|
event: unknown,
|
|
916
|
-
retainMicrosteps?: boolean
|
|
951
|
+
retainMicrosteps?: boolean,
|
|
952
|
+
actorScope?: PlanningActorScope
|
|
917
953
|
) => ExecutionMacrostep
|
|
918
954
|
readonly initial?: (
|
|
919
|
-
args: ReadonlyArray<unknown
|
|
955
|
+
args: ReadonlyArray<unknown>,
|
|
956
|
+
actorScope?: PlanningActorScope
|
|
920
957
|
) => {
|
|
921
958
|
readonly state: Machine.Snapshot<any>
|
|
922
959
|
readonly configuration: unknown
|
|
@@ -933,7 +970,14 @@ const makeActiveExecutionPlan = (machine: Machine.Any): CompiledExecutionPlan =>
|
|
|
933
970
|
fromConfiguration: (configuration) => configuration,
|
|
934
971
|
toConfiguration: (state) => state as ActiveConfiguration,
|
|
935
972
|
snapshot: (state) => snapshotFromConfiguration(machine, state as ActiveConfiguration),
|
|
936
|
-
plan: (state, event
|
|
973
|
+
plan: (state, event, _retainMicrosteps, actorScope) =>
|
|
974
|
+
planConfiguration(
|
|
975
|
+
machine as any,
|
|
976
|
+
actorScope === undefined
|
|
977
|
+
? state as ActiveConfiguration
|
|
978
|
+
: withActorScope(state as ActiveConfiguration, actorScope),
|
|
979
|
+
event as any
|
|
980
|
+
)
|
|
937
981
|
})
|
|
938
982
|
|
|
939
983
|
const makeIndexedExecutionPlan = (
|
|
@@ -943,16 +987,17 @@ const makeIndexedExecutionPlan = (
|
|
|
943
987
|
fromConfiguration: (configuration) => ownedIndexedStateFromActive(indexed, configuration),
|
|
944
988
|
toConfiguration: (state) => activeConfigurationFromIndexedState(indexed, state as OwnedIndexedState),
|
|
945
989
|
snapshot: (state) => snapshotFromIndexedState(indexed, state as OwnedIndexedState),
|
|
946
|
-
plan: (state, event, retainMicrosteps = false) =>
|
|
947
|
-
planIndexedState(machine, indexed, state as OwnedIndexedState, event, retainMicrosteps),
|
|
948
|
-
initial: (args) => {
|
|
990
|
+
plan: (state, event, retainMicrosteps = false, actorScope) =>
|
|
991
|
+
planIndexedState(machine, indexed, state as OwnedIndexedState, event, retainMicrosteps, actorScope),
|
|
992
|
+
initial: (args, actorScope) => {
|
|
949
993
|
const inputArgs = machine.input === undefined
|
|
950
994
|
? args
|
|
951
995
|
: args.length === 0
|
|
952
996
|
? (decodeInputSync(machine, machine.input, undefined), args)
|
|
953
997
|
: [decodeInputSync(machine, machine.input, args[0])]
|
|
954
998
|
const initial = machine.initial(...inputArgs as any)
|
|
955
|
-
const
|
|
999
|
+
const normalized = normalizeConfigurationSync(machine, initial as Machine.Snapshot<any>)
|
|
1000
|
+
const active = actorScope === undefined ? normalized : withActorScope(normalized, actorScope)
|
|
956
1001
|
validateInitialConfiguration(machine, active)
|
|
957
1002
|
const completed = completeConfigurationSync(machine, active, InitialEvent).configuration
|
|
958
1003
|
const configuration = ownedIndexedStateFromActive(indexed, completed)
|
|
@@ -235,9 +235,10 @@ export const startAll = (
|
|
|
235
235
|
.filter((path) => configuration.active.has(path))
|
|
236
236
|
.flatMap((path) => {
|
|
237
237
|
const context = {
|
|
238
|
+
...(Configuration.getActorScope(configuration) ?? { self: scope.self, parent: scope.parent }),
|
|
238
239
|
state: configuration.values.get(path),
|
|
239
|
-
|
|
240
|
-
|
|
240
|
+
containingState: Configuration.getParentValue(machine, configuration, path),
|
|
241
|
+
ancestors: Configuration.getParentValues(machine, configuration, path),
|
|
241
242
|
event
|
|
242
243
|
}
|
|
243
244
|
return InvocationEvent.definitions(Configuration.getStateConfigByPath(machine, path)?.invoke).map((definition) =>
|