|
4 | 4 | * @since 4.0.0 |
5 | 5 | */ |
6 | 6 |
|
| 7 | +import * as Cause from "effect/Cause" |
7 | 8 | import * as Effect from "effect/Effect" |
8 | 9 | import * as Exit from "effect/Exit" |
9 | 10 | import * as Option from "effect/Option" |
10 | 11 | import * as Queue from "effect/Queue" |
11 | 12 | import type * as Schema from "effect/Schema" |
12 | 13 | import type { ActionError, ExecutionServices, Machine, Runtime } from "../Machine.js" |
13 | | -import { ChildAlreadyExistsError, InfiniteTransitionError, MachineSchemaDecodeError } from "./machineErrors.js" |
14 | | -import type { StartupError, StoppedError } from "./machineErrors.js" |
| 14 | +import { |
| 15 | + ChildAlreadyExistsError, |
| 16 | + InfiniteTransitionError, |
| 17 | + MachineSchemaDecodeError, |
| 18 | + StartupError |
| 19 | +} from "./machineErrors.js" |
| 20 | +import type { StoppedError } from "./machineErrors.js" |
15 | 21 | import * as Model from "./machineModel.js" |
16 | 22 | import * as internalPlanner from "./machinePlanner.js" |
17 | 23 | import * as internalRuntime from "./machineRuntime.js" |
@@ -247,9 +253,21 @@ const makeChildlessCompiledDrain = ( |
247 | 253 | class InvokeExecutionKernel { |
248 | 254 | readonly sessions: Map<string, InvokeSession> |
249 | 255 | initialized = false |
| 256 | + initial: |
| 257 | + | { |
| 258 | + readonly configuration: unknown |
| 259 | + readonly activeConfiguration: Model.ActiveConfiguration |
| 260 | + readonly entryPaths: ReadonlyArray<string> |
| 261 | + } |
| 262 | + | undefined |
250 | 263 |
|
251 | | - constructor() { |
| 264 | + constructor(initial?: { |
| 265 | + readonly configuration: unknown |
| 266 | + readonly activeConfiguration: Model.ActiveConfiguration |
| 267 | + readonly entryPaths: ReadonlyArray<string> |
| 268 | + }) { |
252 | 269 | this.sessions = new Map() |
| 270 | + this.initial = initial |
253 | 271 | } |
254 | 272 |
|
255 | 273 | private makeSessionKey(path: string, id: string): string { |
@@ -499,15 +517,17 @@ const makeInvokingCompiledDrain = ( |
499 | 517 | if (execution.initialized) { |
500 | 518 | return loop |
501 | 519 | } |
502 | | - const initialConfiguration = Model.normalizeConfigurationSync(machine, current) |
503 | | - configuration = executionPlan.fromConfiguration(initialConfiguration) |
| 520 | + const seeded = execution.initial |
| 521 | + const initialConfiguration = seeded?.activeConfiguration ?? Model.normalizeConfigurationSync(machine, current) |
| 522 | + configuration = seeded?.configuration ?? executionPlan.fromConfiguration(initialConfiguration) |
504 | 523 | const starting = execution.startAll( |
505 | 524 | machine, |
506 | 525 | context, |
507 | 526 | initialConfiguration, |
508 | | - Model.getInitialEntryPaths(machine, initialConfiguration), |
| 527 | + seeded?.entryPaths ?? Model.getInitialEntryPaths(machine, initialConfiguration), |
509 | 528 | internalPlanner.InitialEvent |
510 | 529 | ) |
| 530 | + execution.initial = undefined |
511 | 531 | execution.initialized = true |
512 | 532 | return starting === undefined ? loop : starting.pipe(Effect.andThen(loop)) |
513 | 533 | } |
@@ -564,36 +584,63 @@ const makeProcessLogic: < |
564 | 584 | entry: ProcessEntry<States, Input> |
565 | 585 | ) => { |
566 | 586 | const hasInvokes = hasInvokeCapability(machine) |
| 587 | + const executionPlan = internalPlanner.compileExecutionPlan(machine) |
567 | 588 | const initialArgs = entry._tag === "Initial" ? entry.args : [] |
| 589 | + const compiledInitial = entry._tag === "Initial" ? executionPlan.initial : undefined |
568 | 590 | const makeInitial = ( |
569 | 591 | scope: internalRuntime.ProcessScope<Machine.EventOf<Events>> |
570 | 592 | ) => |
571 | | - internalRuntime.provideMachineRuntime( |
572 | | - internalPlanner.planInitial(machine, ...initialArgs).pipe( |
573 | | - Effect.flatMap((planned) => { |
574 | | - const commands = planned.commands.length === 0 |
575 | | - ? undefined |
576 | | - : internalPlanner.runCommands(planned.commands, scope) |
577 | | - const emitted = planned.emittedEvents.length === 0 |
578 | | - ? undefined |
579 | | - : internalPlanner.runEmittedEvents( |
580 | | - planned.emittedEvents, |
581 | | - internalPlanner.makeLiveRuntime<Machine.EventOf<Events>, Machine.EmitOf<Emits>>(machine, scope) |
582 | | - ) |
583 | | - const result = Effect.succeed({ |
584 | | - state: planned.state, |
585 | | - done: planned.done, |
586 | | - output: planned.output |
| 593 | + compiledInitial === undefined |
| 594 | + ? internalRuntime.provideMachineRuntime( |
| 595 | + internalPlanner.planInitial(machine, ...initialArgs).pipe( |
| 596 | + Effect.flatMap((planned) => { |
| 597 | + const commands = planned.commands.length === 0 |
| 598 | + ? undefined |
| 599 | + : internalPlanner.runCommands(planned.commands, scope) |
| 600 | + const emitted = planned.emittedEvents.length === 0 |
| 601 | + ? undefined |
| 602 | + : internalPlanner.runEmittedEvents( |
| 603 | + planned.emittedEvents, |
| 604 | + internalPlanner.makeLiveRuntime<Machine.EventOf<Events>, Machine.EmitOf<Emits>>(machine, scope) |
| 605 | + ) |
| 606 | + const result = Effect.succeed({ |
| 607 | + state: planned.state, |
| 608 | + done: planned.done, |
| 609 | + output: planned.output |
| 610 | + }) |
| 611 | + return commands === undefined |
| 612 | + ? emitted === undefined ? result : emitted.pipe(Effect.andThen(result)) |
| 613 | + : emitted === undefined |
| 614 | + ? commands.pipe(Effect.andThen(result)) |
| 615 | + : commands.pipe(Effect.andThen(emitted), Effect.andThen(result)) |
587 | 616 | }) |
588 | | - return commands === undefined |
589 | | - ? emitted === undefined ? result : emitted.pipe(Effect.andThen(result)) |
590 | | - : emitted === undefined |
591 | | - ? commands.pipe(Effect.andThen(result)) |
592 | | - : commands.pipe(Effect.andThen(emitted), Effect.andThen(result)) |
593 | | - }) |
594 | | - ), |
595 | | - scope |
596 | | - ) |
| 617 | + ), |
| 618 | + scope |
| 619 | + ) |
| 620 | + : Effect.try({ |
| 621 | + try: () => { |
| 622 | + const planned = compiledInitial(initialArgs) |
| 623 | + const result = { |
| 624 | + state: planned.state as Machine.Snapshot<States>, |
| 625 | + done: planned.done, |
| 626 | + output: planned.output as Output | undefined |
| 627 | + } |
| 628 | + return hasInvokes |
| 629 | + ? { |
| 630 | + ...result, |
| 631 | + executionState: new InvokeExecutionKernel({ |
| 632 | + configuration: planned.configuration, |
| 633 | + activeConfiguration: planned.activeConfiguration, |
| 634 | + entryPaths: planned.initialEntryPaths |
| 635 | + }) |
| 636 | + } |
| 637 | + : result |
| 638 | + }, |
| 639 | + catch: (error) => |
| 640 | + error instanceof InfiniteTransitionError || error instanceof MachineSchemaDecodeError |
| 641 | + ? error |
| 642 | + : new StartupError({ cause: Cause.die(error) }) |
| 643 | + }) |
597 | 644 | return ({ |
598 | 645 | [internalRuntime.childlessProcess]: hasInvokes ? undefined : true, |
599 | 646 | [internalRuntime.compiledProcess]: true, |
|
0 commit comments