@typeonce/effect-machine 0.10.0 → 0.12.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 +76 -13
- package/dist/Machine.d.ts +202 -90
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +38 -9
- package/dist/Machine.js.map +1 -1
- package/dist/internal/machine/atom.d.ts +1 -1
- package/dist/internal/machine/atom.d.ts.map +1 -1
- package/dist/internal/machine/atom.js +38 -7
- package/dist/internal/machine/atom.js.map +1 -1
- package/dist/internal/machine/cluster.js +2 -2
- package/dist/internal/machine/cluster.js.map +1 -1
- package/dist/internal/machine/commandRuntime.d.ts.map +1 -1
- package/dist/internal/machine/commandRuntime.js +2 -2
- package/dist/internal/machine/commandRuntime.js.map +1 -1
- package/dist/internal/machine/configuration.d.ts +7 -7
- package/dist/internal/machine/configuration.d.ts.map +1 -1
- package/dist/internal/machine/configuration.js +3 -3
- package/dist/internal/machine/configuration.js.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 +25 -25
- package/dist/internal/machine/executionPlan.js.map +1 -1
- package/dist/internal/machine/invocation.js +1 -1
- package/dist/internal/machine/invocation.js.map +1 -1
- package/dist/internal/machine/machine.d.ts +1 -0
- package/dist/internal/machine/machine.d.ts.map +1 -1
- package/dist/internal/machine/machine.js +4 -0
- package/dist/internal/machine/machine.js.map +1 -1
- package/dist/internal/machine/planner.d.ts +2 -2
- package/dist/internal/machine/planner.d.ts.map +1 -1
- package/dist/internal/machine/planner.js +20 -20
- 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 +6 -3
- package/dist/internal/machine/process.js.map +1 -1
- package/dist/internal/machine/runtime.d.ts +17 -3
- package/dist/internal/machine/runtime.d.ts.map +1 -1
- package/dist/internal/machine/runtime.js +82 -32
- package/dist/internal/machine/runtime.js.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.d.ts +4 -2
- package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.js +4 -2
- package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
- package/docs/agent-guide.md +78 -19
- package/package.json +1 -1
- package/src/Machine.ts +704 -96
- package/src/internal/machine/atom.ts +50 -52
- package/src/internal/machine/cluster.ts +2 -2
- package/src/internal/machine/commandRuntime.ts +4 -2
- package/src/internal/machine/configuration.ts +10 -10
- package/src/internal/machine/executionPlan.ts +35 -35
- package/src/internal/machine/invocation.ts +1 -1
- package/src/internal/machine/machine.ts +6 -0
- package/src/internal/machine/planner.ts +30 -24
- package/src/internal/machine/process.ts +60 -3
- package/src/internal/machine/runtime.ts +176 -47
- package/src/unstable/reactivity/AtomMachine.ts +4 -2
|
@@ -459,7 +459,7 @@ const makeProcessLogic: <
|
|
|
459
459
|
) =>
|
|
460
460
|
compiledInitial === undefined
|
|
461
461
|
? internalRuntime.provideMachineRuntime(
|
|
462
|
-
internalPlanner.planInitial(internalPlanner.
|
|
462
|
+
internalPlanner.planInitial(internalPlanner.withMachineReferences(machine, scope), ...initialArgs).pipe(
|
|
463
463
|
Effect.flatMap((planned) => {
|
|
464
464
|
const commands = planned.commands.length === 0
|
|
465
465
|
? undefined
|
|
@@ -540,7 +540,7 @@ const makeProcessLogic: <
|
|
|
540
540
|
try {
|
|
541
541
|
planned = internalPlanner.planConfiguration(
|
|
542
542
|
machine,
|
|
543
|
-
Configuration.
|
|
543
|
+
Configuration.withMachineReferences(
|
|
544
544
|
configuration ?? Configuration.normalizeConfigurationSync(machine, current),
|
|
545
545
|
context
|
|
546
546
|
),
|
|
@@ -651,7 +651,7 @@ const makeProcessLogic: <
|
|
|
651
651
|
try {
|
|
652
652
|
planned = internalPlanner.planConfiguration(
|
|
653
653
|
machine,
|
|
654
|
-
Configuration.
|
|
654
|
+
Configuration.withMachineReferences(
|
|
655
655
|
configuration ?? Configuration.normalizeConfigurationSync(machine, current),
|
|
656
656
|
context
|
|
657
657
|
),
|
|
@@ -825,6 +825,18 @@ export const startWithRuntimeStrategyForTesting = (
|
|
|
825
825
|
machine.id === undefined ? undefined : { id: machine.id }
|
|
826
826
|
)
|
|
827
827
|
|
|
828
|
+
/** @internal Test-only prepared startup strategy selection for a fresh machine. */
|
|
829
|
+
export const prepareWithRuntimeStrategyForTesting = (
|
|
830
|
+
machine: Machine.Any,
|
|
831
|
+
strategy: internalRuntime.ProcessRuntimeStrategy,
|
|
832
|
+
...args: ReadonlyArray<unknown>
|
|
833
|
+
): Effect.Effect<internalRuntime.PreparedProcess<any, any, any, any, any, any, any>, any, any> =>
|
|
834
|
+
internalRuntime.prepareProcessWithStrategyForTesting(
|
|
835
|
+
(toProcessLogic as any)(machine, ...args),
|
|
836
|
+
strategy,
|
|
837
|
+
machine.id === undefined ? undefined : { id: machine.id }
|
|
838
|
+
)
|
|
839
|
+
|
|
828
840
|
/** @internal Test-only runtime strategy selection for a resumed machine. */
|
|
829
841
|
export const resumeWithRuntimeStrategyForTesting = (
|
|
830
842
|
machine: Machine.Any,
|
|
@@ -881,6 +893,51 @@ export const start: <
|
|
|
881
893
|
machine.id === undefined ? undefined : { id: machine.id }
|
|
882
894
|
) as any
|
|
883
895
|
|
|
896
|
+
export const prepare: <
|
|
897
|
+
const States extends Machine.StateSchemas,
|
|
898
|
+
const Events extends ReadonlyArray<Machine.TaggedSchema>,
|
|
899
|
+
const Emits extends ReadonlyArray<Machine.TaggedSchema> = readonly [],
|
|
900
|
+
const Input extends Schema.Top = typeof Schema.Void,
|
|
901
|
+
UnhandledStates extends Machine.StateIdentifier<States> = Machine.StateIdentifier<States>,
|
|
902
|
+
E = never,
|
|
903
|
+
R = never,
|
|
904
|
+
InitialE = never,
|
|
905
|
+
InitialR = never,
|
|
906
|
+
FinalStates extends Machine.StateIdentifier<States> = never,
|
|
907
|
+
Output = never
|
|
908
|
+
>(
|
|
909
|
+
machine: Machine<States, Events, Input, UnhandledStates, E, R, InitialE, InitialR, FinalStates, Output, Emits>,
|
|
910
|
+
...args: [...Machine.InputArgs<Input>]
|
|
911
|
+
) => Effect.Effect<
|
|
912
|
+
internalRuntime.PreparedProcess<
|
|
913
|
+
Machine.Snapshot<States>,
|
|
914
|
+
Machine.EventOf<Events>,
|
|
915
|
+
| E
|
|
916
|
+
| ActionError<R>
|
|
917
|
+
| InfiniteTransitionError
|
|
918
|
+
| MachineSchemaDecodeError
|
|
919
|
+
| StoppedError,
|
|
920
|
+
Output,
|
|
921
|
+
Machine.EmittedEventOf<Emits>,
|
|
922
|
+
| InitialE
|
|
923
|
+
| E
|
|
924
|
+
| ActionError<InitialR | R>
|
|
925
|
+
| InfiniteTransitionError
|
|
926
|
+
| MachineSchemaDecodeError
|
|
927
|
+
| StartupError
|
|
928
|
+
| StoppedError,
|
|
929
|
+
ExcludeCompatibleRuntime<
|
|
930
|
+
Exclude<ExecutionServices<InitialR | R>, internalRuntime.MachineRuntime>,
|
|
931
|
+
Machine.EventOf<Events>,
|
|
932
|
+
Machine.EmitOf<Emits>
|
|
933
|
+
>
|
|
934
|
+
>
|
|
935
|
+
> = (machine, ...args) =>
|
|
936
|
+
internalRuntime.prepareProcess(
|
|
937
|
+
toProcessLogic(machine, ...args),
|
|
938
|
+
machine.id === undefined ? undefined : { id: machine.id }
|
|
939
|
+
) as any
|
|
940
|
+
|
|
884
941
|
export const resume: <
|
|
885
942
|
const States extends Machine.StateSchemas,
|
|
886
943
|
const Events extends ReadonlyArray<Machine.TaggedSchema>,
|
|
@@ -18,7 +18,7 @@ import * as Scope from "effect/Scope"
|
|
|
18
18
|
import * as Stream from "effect/Stream"
|
|
19
19
|
import * as SynchronizedRef from "effect/SynchronizedRef"
|
|
20
20
|
import type * as Take from "effect/Take"
|
|
21
|
-
import type {
|
|
21
|
+
import type { MachineTarget } from "../../Machine.js"
|
|
22
22
|
import { ChildAlreadyExistsError, StoppedError } from "./errors.js"
|
|
23
23
|
|
|
24
24
|
type ChildDescriptor = {
|
|
@@ -302,6 +302,22 @@ export interface MachineRef<out State, in Event, out Error = never, out Output =
|
|
|
302
302
|
readonly childChanges: (child: any) => Stream.Stream<Option.Option<any>>
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
+
export interface PreparedProcess<
|
|
306
|
+
out State,
|
|
307
|
+
in Event,
|
|
308
|
+
out Error,
|
|
309
|
+
out Output,
|
|
310
|
+
out Emitted,
|
|
311
|
+
out StartError,
|
|
312
|
+
StartRequirements
|
|
313
|
+
> {
|
|
314
|
+
readonly id: string
|
|
315
|
+
readonly sessionId: string
|
|
316
|
+
readonly changes: Stream.Stream<RuntimeSnapshot<State, Error, Output>, StartError>
|
|
317
|
+
readonly emissions: Stream.Stream<Emitted>
|
|
318
|
+
readonly start: Effect.Effect<MachineRef<State, Event, Error, Output, Emitted>, StartError, StartRequirements>
|
|
319
|
+
}
|
|
320
|
+
|
|
305
321
|
interface ProcessAddress<in Event> {
|
|
306
322
|
readonly id: string
|
|
307
323
|
readonly sessionId: string
|
|
@@ -309,7 +325,7 @@ interface ProcessAddress<in Event> {
|
|
|
309
325
|
readonly send: (event: Event) => Effect.Effect<void, StoppedError>
|
|
310
326
|
}
|
|
311
327
|
|
|
312
|
-
const isProcessAddress = (value: unknown): value is
|
|
328
|
+
const isProcessAddress = (value: unknown): value is MachineTarget<unknown> =>
|
|
313
329
|
typeof value === "object" && value !== null && "send" in value && typeof value.send === "function"
|
|
314
330
|
|
|
315
331
|
export interface ProcessScope<Event> {
|
|
@@ -319,7 +335,7 @@ export interface ProcessScope<Event> {
|
|
|
319
335
|
readonly sendParent: (event: unknown) => Effect.Effect<void, StoppedError>
|
|
320
336
|
readonly emit: (event: unknown) => Effect.Effect<void>
|
|
321
337
|
readonly sendTo: {
|
|
322
|
-
<TargetEvent>(target:
|
|
338
|
+
<TargetEvent>(target: MachineTarget<TargetEvent>, event: TargetEvent): Effect.Effect<void, StoppedError>
|
|
323
339
|
(child: ChildSelector, event: unknown): Effect.Effect<void, StoppedError>
|
|
324
340
|
}
|
|
325
341
|
readonly stopChild: (child: ChildSelector) => Effect.Effect<void>
|
|
@@ -351,7 +367,7 @@ export interface ProcessContext<State, Event> extends ProcessScope<Event> {
|
|
|
351
367
|
*
|
|
352
368
|
* Unlike `ProcessContext`, synchronous mailbox and state operations do not
|
|
353
369
|
* introduce an Effect boundary. The compiled drain still returns an Effect so
|
|
354
|
-
*
|
|
370
|
+
* machine commands, invokes, observation callbacks, interruption, and the Effect
|
|
355
371
|
* scheduler remain explicit at their actual boundaries.
|
|
356
372
|
*
|
|
357
373
|
* @internal
|
|
@@ -609,6 +625,8 @@ const makeProcessRuntime: Effect.Effect<ProcessRuntime> = Effect.sync(() => {
|
|
|
609
625
|
interface StartInternalOptions {
|
|
610
626
|
readonly detached?: boolean
|
|
611
627
|
readonly id?: string
|
|
628
|
+
readonly sessionId?: string
|
|
629
|
+
readonly emissions?: EmissionRuntime
|
|
612
630
|
readonly onOutcome?: (outcome: RuntimeOutcome<any, any, any>) => Effect.Effect<void>
|
|
613
631
|
readonly onSnapshot?: (
|
|
614
632
|
snapshot: Extract<RuntimeSnapshot<any, any, any>, { readonly status: "active" }>
|
|
@@ -802,6 +820,54 @@ const EmissionsClosed: unique symbol = Symbol("effect/Machine/EmissionsClosed")
|
|
|
802
820
|
|
|
803
821
|
type LazyEmissions = PubSub.PubSub<unknown> | typeof EmissionsClosed | undefined
|
|
804
822
|
|
|
823
|
+
interface EmissionRuntime {
|
|
824
|
+
readonly emit: (event: unknown) => Effect.Effect<void>
|
|
825
|
+
readonly close: () => Effect.Effect<void>
|
|
826
|
+
readonly stream: Stream.Stream<unknown>
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
const makeEmissionRuntime = (): EmissionRuntime => {
|
|
830
|
+
let emissions: LazyEmissions
|
|
831
|
+
const getOrCreate: Effect.Effect<PubSub.PubSub<unknown> | undefined> = Effect.suspend(() => {
|
|
832
|
+
const observed = emissions
|
|
833
|
+
if (observed === EmissionsClosed) return Effect.succeed(undefined)
|
|
834
|
+
if (observed !== undefined) return Effect.succeed(observed)
|
|
835
|
+
return PubSub.unbounded<unknown>().pipe(
|
|
836
|
+
Effect.flatMap((candidate) =>
|
|
837
|
+
Effect.sync(() => {
|
|
838
|
+
const latest = emissions
|
|
839
|
+
if (latest === EmissionsClosed) return [undefined, true] as const
|
|
840
|
+
if (latest !== undefined) return [latest, true] as const
|
|
841
|
+
emissions = candidate
|
|
842
|
+
return [candidate, false] as const
|
|
843
|
+
}).pipe(
|
|
844
|
+
Effect.flatMap(([selected, discard]) =>
|
|
845
|
+
discard ? PubSub.shutdown(candidate).pipe(Effect.as(selected)) : Effect.succeed(selected)
|
|
846
|
+
)
|
|
847
|
+
)
|
|
848
|
+
)
|
|
849
|
+
)
|
|
850
|
+
})
|
|
851
|
+
return {
|
|
852
|
+
emit: (event) =>
|
|
853
|
+
Effect.suspend(() =>
|
|
854
|
+
emissions === undefined || emissions === EmissionsClosed
|
|
855
|
+
? Effect.void
|
|
856
|
+
: PubSub.publish(emissions, event).pipe(Effect.asVoid)
|
|
857
|
+
),
|
|
858
|
+
close: () => {
|
|
859
|
+
const observed = emissions
|
|
860
|
+
emissions = EmissionsClosed
|
|
861
|
+
return observed === undefined || observed === EmissionsClosed ? Effect.void : PubSub.shutdown(observed)
|
|
862
|
+
},
|
|
863
|
+
stream: Stream.unwrap(
|
|
864
|
+
getOrCreate.pipe(
|
|
865
|
+
Effect.map((emissions) => emissions === undefined ? Stream.empty : Stream.fromPubSub(emissions))
|
|
866
|
+
)
|
|
867
|
+
)
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
805
871
|
const childlessRuntime: ChildRuntime = {
|
|
806
872
|
close: () => Effect.void,
|
|
807
873
|
spawn: (() => Effect.die(new Error("Childless machine logic cannot spawn a process"))) as ProcessSpawn,
|
|
@@ -1104,41 +1170,10 @@ const startGenericInternal: <
|
|
|
1104
1170
|
| { readonly _tag: "Done"; readonly output: Output }
|
|
1105
1171
|
| { readonly _tag: "Failure"; readonly cause: Cause.Cause<Error> }
|
|
1106
1172
|
|
|
1107
|
-
const sessionId = yield* runtime.nextSessionId
|
|
1173
|
+
const sessionId = options.sessionId ?? (yield* runtime.nextSessionId)
|
|
1108
1174
|
const id = requestedId ?? sessionId
|
|
1109
1175
|
const queue = yield* Queue.unbounded<ProcessMessage<Event>>()
|
|
1110
|
-
|
|
1111
|
-
const getOrCreateEmissions: Effect.Effect<PubSub.PubSub<unknown> | undefined> = Effect.suspend(() => {
|
|
1112
|
-
const observed = emissions
|
|
1113
|
-
if (observed === EmissionsClosed) return Effect.succeed(undefined)
|
|
1114
|
-
if (observed !== undefined) return Effect.succeed(observed)
|
|
1115
|
-
return PubSub.unbounded<unknown>().pipe(
|
|
1116
|
-
Effect.flatMap((candidate) =>
|
|
1117
|
-
Effect.sync(() => {
|
|
1118
|
-
const latest = emissions
|
|
1119
|
-
if (latest === EmissionsClosed) return [undefined, true] as const
|
|
1120
|
-
if (latest !== undefined) return [latest, true] as const
|
|
1121
|
-
emissions = candidate
|
|
1122
|
-
return [candidate, false] as const
|
|
1123
|
-
}).pipe(
|
|
1124
|
-
Effect.flatMap(([selected, discard]) =>
|
|
1125
|
-
discard ? PubSub.shutdown(candidate).pipe(Effect.as(selected)) : Effect.succeed(selected)
|
|
1126
|
-
)
|
|
1127
|
-
)
|
|
1128
|
-
)
|
|
1129
|
-
)
|
|
1130
|
-
})
|
|
1131
|
-
const closeEmissions = (): Effect.Effect<void> => {
|
|
1132
|
-
const observed = emissions
|
|
1133
|
-
emissions = EmissionsClosed
|
|
1134
|
-
return observed === undefined || observed === EmissionsClosed ? Effect.void : PubSub.shutdown(observed)
|
|
1135
|
-
}
|
|
1136
|
-
const emit = (event: unknown): Effect.Effect<void> =>
|
|
1137
|
-
Effect.suspend(() =>
|
|
1138
|
-
emissions === undefined || emissions === EmissionsClosed
|
|
1139
|
-
? Effect.void
|
|
1140
|
-
: PubSub.publish(emissions, event).pipe(Effect.asVoid)
|
|
1141
|
-
)
|
|
1176
|
+
const emissions = options.emissions ?? makeEmissionRuntime()
|
|
1142
1177
|
const termination = yield* Deferred.make<ProcessTermination>()
|
|
1143
1178
|
const done = yield* Deferred.make<Output, Error | StoppedError>()
|
|
1144
1179
|
const awaitCompletion = Deferred.await(done).pipe(Effect.exit, Effect.asVoid)
|
|
@@ -1209,7 +1244,7 @@ const startGenericInternal: <
|
|
|
1209
1244
|
}
|
|
1210
1245
|
const cleanupStartupFailure = <A, E>(exit: Exit.Exit<A, E>): Effect.Effect<void> =>
|
|
1211
1246
|
Exit.isFailure(exit)
|
|
1212
|
-
? closeChildren(exit).pipe(Effect.andThen(
|
|
1247
|
+
? closeChildren(exit).pipe(Effect.andThen(emissions.close()))
|
|
1213
1248
|
: Effect.void
|
|
1214
1249
|
const cleanup = onStopSync === undefined ? onStop ?? Effect.void : Effect.sync(onStopSync)
|
|
1215
1250
|
const sendParent = overrideSendParent ?? (parent === undefined ? noParentSend : parent.send)
|
|
@@ -1219,7 +1254,7 @@ const startGenericInternal: <
|
|
|
1219
1254
|
parent,
|
|
1220
1255
|
spawn,
|
|
1221
1256
|
sendParent,
|
|
1222
|
-
emit,
|
|
1257
|
+
emit: emissions.emit,
|
|
1223
1258
|
sendTo: ((target: unknown, event: unknown) =>
|
|
1224
1259
|
isProcessAddress(target) ? target.send(event) : sendTo(target as ChildSelector, event)) as ProcessScope<
|
|
1225
1260
|
Event
|
|
@@ -1402,7 +1437,7 @@ const startGenericInternal: <
|
|
|
1402
1437
|
Effect.andThen(Queue.shutdown(queue)),
|
|
1403
1438
|
Effect.andThen(closeChildren(exit)),
|
|
1404
1439
|
Effect.andThen(setAndPublishSnapshot(snapshot)),
|
|
1405
|
-
Effect.andThen(
|
|
1440
|
+
Effect.andThen(emissions.close()),
|
|
1406
1441
|
Effect.andThen(Effect.sync(() => {
|
|
1407
1442
|
if (Exit.isFailure(exit)) {
|
|
1408
1443
|
failAcknowledgedMessage(inFlightMessage, exit.cause)
|
|
@@ -1559,11 +1594,7 @@ const startGenericInternal: <
|
|
|
1559
1594
|
state: SynchronizedRef.get(current).pipe(Effect.map((current) => current.snapshot.state)),
|
|
1560
1595
|
snapshot: SynchronizedRef.get(current).pipe(Effect.map((current) => current.snapshot)),
|
|
1561
1596
|
changes: changesStream,
|
|
1562
|
-
emissions: Stream.
|
|
1563
|
-
getOrCreateEmissions.pipe(
|
|
1564
|
-
Effect.map((emissions) => emissions === undefined ? Stream.empty : Stream.fromPubSub(emissions))
|
|
1565
|
-
)
|
|
1566
|
-
) as Stream.Stream<never>,
|
|
1597
|
+
emissions: emissions.stream as Stream.Stream<never>,
|
|
1567
1598
|
join: Deferred.await(done),
|
|
1568
1599
|
stop,
|
|
1569
1600
|
send: self.send,
|
|
@@ -1717,6 +1748,7 @@ class CompiledProcess implements MachineRef<any, any, any, any> {
|
|
|
1717
1748
|
private interruptRequested = false
|
|
1718
1749
|
private offerRevision = 0
|
|
1719
1750
|
private inFlightMessage: ProcessMessage<unknown> | undefined
|
|
1751
|
+
private readonly externalEmissions: EmissionRuntime | undefined
|
|
1720
1752
|
private emissionsPubSub: LazyEmissions
|
|
1721
1753
|
|
|
1722
1754
|
constructor(
|
|
@@ -1727,6 +1759,7 @@ class CompiledProcess implements MachineRef<any, any, any, any> {
|
|
|
1727
1759
|
) {
|
|
1728
1760
|
this.sessionId = sessionId
|
|
1729
1761
|
this.id = options.id ?? sessionId
|
|
1762
|
+
this.externalEmissions = options.emissions
|
|
1730
1763
|
this.send = (event) => this.offerMessage(event)
|
|
1731
1764
|
this.address = {
|
|
1732
1765
|
id: this.id,
|
|
@@ -1908,7 +1941,7 @@ class CompiledProcess implements MachineRef<any, any, any, any> {
|
|
|
1908
1941
|
}
|
|
1909
1942
|
|
|
1910
1943
|
get emissions(): Stream.Stream<never> {
|
|
1911
|
-
return this.emissionsStream() as Stream.Stream<never>
|
|
1944
|
+
return (this.externalEmissions?.stream ?? this.emissionsStream()) as Stream.Stream<never>
|
|
1912
1945
|
}
|
|
1913
1946
|
|
|
1914
1947
|
get join(): Effect.Effect<unknown, unknown> {
|
|
@@ -2268,6 +2301,7 @@ class CompiledProcess implements MachineRef<any, any, any, any> {
|
|
|
2268
2301
|
}
|
|
2269
2302
|
|
|
2270
2303
|
private emitEvent(event: unknown): Effect.Effect<void> {
|
|
2304
|
+
if (this.externalEmissions !== undefined) return this.externalEmissions.emit(event)
|
|
2271
2305
|
return Effect.suspend(() =>
|
|
2272
2306
|
this.emissionsPubSub === undefined || this.emissionsPubSub === EmissionsClosed
|
|
2273
2307
|
? Effect.void
|
|
@@ -2280,6 +2314,7 @@ class CompiledProcess implements MachineRef<any, any, any, any> {
|
|
|
2280
2314
|
}
|
|
2281
2315
|
|
|
2282
2316
|
private closeEmissions(): Effect.Effect<void> {
|
|
2317
|
+
if (this.externalEmissions !== undefined) return this.externalEmissions.close()
|
|
2283
2318
|
const observed = this.emissionsPubSub
|
|
2284
2319
|
this.emissionsPubSub = EmissionsClosed
|
|
2285
2320
|
return observed === undefined || observed === EmissionsClosed ? Effect.void : PubSub.shutdown(observed)
|
|
@@ -2523,7 +2558,7 @@ const startCompactCompiledInternal: typeof startGenericInternal = Effect.fnUntra
|
|
|
2523
2558
|
logic: ProcessLogic<any, any, any, any, any, any>,
|
|
2524
2559
|
options: StartInternalOptions
|
|
2525
2560
|
) {
|
|
2526
|
-
const sessionId = yield* options.runtime.nextSessionId
|
|
2561
|
+
const sessionId = options.sessionId ?? (yield* options.runtime.nextSessionId)
|
|
2527
2562
|
const services = yield* Effect.context<any>()
|
|
2528
2563
|
const execution = logic.execution as CompiledProcessExecution<any, any, any, any, any, any>
|
|
2529
2564
|
const process = new CompiledProcess(logic, options, services, sessionId)
|
|
@@ -2636,3 +2671,97 @@ export const startProcess: <
|
|
|
2636
2671
|
}
|
|
2637
2672
|
)
|
|
2638
2673
|
})
|
|
2674
|
+
|
|
2675
|
+
const prepareProcessWithStrategy = Effect.fnUntraced(function*<
|
|
2676
|
+
State,
|
|
2677
|
+
Event,
|
|
2678
|
+
Error,
|
|
2679
|
+
Requirements,
|
|
2680
|
+
Output,
|
|
2681
|
+
InitialError,
|
|
2682
|
+
Emitted
|
|
2683
|
+
>(
|
|
2684
|
+
logic: ProcessLogic<State, Event, Error, Requirements, Output, InitialError>,
|
|
2685
|
+
strategy: ProcessRuntimeStrategy,
|
|
2686
|
+
options?: {
|
|
2687
|
+
readonly id?: string
|
|
2688
|
+
}
|
|
2689
|
+
) {
|
|
2690
|
+
const runtime = yield* makeProcessRuntime
|
|
2691
|
+
const sessionId = yield* runtime.nextSessionId
|
|
2692
|
+
const emissions = makeEmissionRuntime()
|
|
2693
|
+
const started = yield* Deferred.make<MachineRef<State, Event, Error, Output, Emitted>, InitialError>()
|
|
2694
|
+
const internalOptions: StartInternalOptions = options === undefined
|
|
2695
|
+
? {
|
|
2696
|
+
detached: true,
|
|
2697
|
+
emissions,
|
|
2698
|
+
runtime,
|
|
2699
|
+
sessionId
|
|
2700
|
+
}
|
|
2701
|
+
: {
|
|
2702
|
+
...options,
|
|
2703
|
+
detached: true,
|
|
2704
|
+
emissions,
|
|
2705
|
+
runtime,
|
|
2706
|
+
sessionId
|
|
2707
|
+
}
|
|
2708
|
+
const initialize = strategy === "generic"
|
|
2709
|
+
? startGenericInternal(logic, internalOptions)
|
|
2710
|
+
: strategy === "compiled"
|
|
2711
|
+
? logic.execution?._tag === "Compiled"
|
|
2712
|
+
? startCompactCompiledInternal(logic, internalOptions)
|
|
2713
|
+
: Effect.die(new Error("Machine cannot force the compiled runtime for generic process logic"))
|
|
2714
|
+
: startLogicInternal(logic, internalOptions)
|
|
2715
|
+
const start = yield* Effect.cached(
|
|
2716
|
+
initialize.pipe(
|
|
2717
|
+
Effect.onExit((exit) => Deferred.done(started, exit))
|
|
2718
|
+
) as Effect.Effect<MachineRef<State, Event, Error, Output, Emitted>, InitialError, Requirements>
|
|
2719
|
+
)
|
|
2720
|
+
return {
|
|
2721
|
+
id: options?.id ?? sessionId,
|
|
2722
|
+
sessionId,
|
|
2723
|
+
changes: Stream.unwrap(
|
|
2724
|
+
Deferred.await(started).pipe(Effect.map((ref) => ref.changes))
|
|
2725
|
+
),
|
|
2726
|
+
emissions: emissions.stream as Stream.Stream<Emitted>,
|
|
2727
|
+
start
|
|
2728
|
+
}
|
|
2729
|
+
})
|
|
2730
|
+
|
|
2731
|
+
export const prepareProcess: <
|
|
2732
|
+
State,
|
|
2733
|
+
Event,
|
|
2734
|
+
Error = never,
|
|
2735
|
+
Requirements = never,
|
|
2736
|
+
Output = never,
|
|
2737
|
+
InitialError = never,
|
|
2738
|
+
Emitted = never
|
|
2739
|
+
>(
|
|
2740
|
+
logic: ProcessLogic<State, Event, Error, Requirements, Output, InitialError>,
|
|
2741
|
+
options?: {
|
|
2742
|
+
readonly id?: string
|
|
2743
|
+
}
|
|
2744
|
+
) => Effect.Effect<
|
|
2745
|
+
PreparedProcess<State, Event, Error, Output, Emitted, InitialError, Requirements>
|
|
2746
|
+
> =
|
|
2747
|
+
((logic: ProcessLogic<any, any, any, any, any, any>, options?: { readonly id?: string }) =>
|
|
2748
|
+
prepareProcessWithStrategy(logic, "auto", options)) as any
|
|
2749
|
+
|
|
2750
|
+
/** @internal Test-only prepared startup strategy selection. */
|
|
2751
|
+
export const prepareProcessWithStrategyForTesting = <
|
|
2752
|
+
State,
|
|
2753
|
+
Event,
|
|
2754
|
+
Error = never,
|
|
2755
|
+
Requirements = never,
|
|
2756
|
+
Output = never,
|
|
2757
|
+
InitialError = never,
|
|
2758
|
+
Emitted = never
|
|
2759
|
+
>(
|
|
2760
|
+
logic: ProcessLogic<State, Event, Error, Requirements, Output, InitialError>,
|
|
2761
|
+
strategy: ProcessRuntimeStrategy,
|
|
2762
|
+
options?: {
|
|
2763
|
+
readonly id?: string
|
|
2764
|
+
}
|
|
2765
|
+
): Effect.Effect<
|
|
2766
|
+
PreparedProcess<State, Event, Error, Output, Emitted, InitialError, Requirements>
|
|
2767
|
+
> => prepareProcessWithStrategy(logic, strategy, options) as any
|
|
@@ -167,8 +167,10 @@ type RefOutput<Ref> = Ref extends Machine.MachineRef<any, any, any, infer Output
|
|
|
167
167
|
type RefEmitted<Ref> = Ref extends Machine.MachineRef<any, any, any, any, infer Emitted> ? Emitted : never
|
|
168
168
|
|
|
169
169
|
/**
|
|
170
|
-
* Observes ephemeral notifications from the
|
|
171
|
-
*
|
|
170
|
+
* Observes ephemeral notifications from the running machine owned by a machine
|
|
171
|
+
* atom. When this stream activates a fresh bridge, it subscribes before machine
|
|
172
|
+
* initialization and observes initial-entry emissions. It never replays
|
|
173
|
+
* emissions from a machine that was already running.
|
|
172
174
|
*
|
|
173
175
|
* @category getters
|
|
174
176
|
* @since 0.10.0
|