@typeonce/effect-machine 0.31.2 → 0.33.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 (151) hide show
  1. package/README.md +168 -162
  2. package/dist/Machine.d.ts +495 -284
  3. package/dist/Machine.d.ts.map +1 -1
  4. package/dist/Machine.js +91 -111
  5. package/dist/Machine.js.map +1 -1
  6. package/dist/internal/machine/atom.d.ts +3 -4
  7. package/dist/internal/machine/atom.d.ts.map +1 -1
  8. package/dist/internal/machine/atom.js +0 -2
  9. package/dist/internal/machine/atom.js.map +1 -1
  10. package/dist/internal/machine/childRegistry.d.ts +52 -0
  11. package/dist/internal/machine/childRegistry.d.ts.map +1 -0
  12. package/dist/internal/machine/childRegistry.js +74 -0
  13. package/dist/internal/machine/childRegistry.js.map +1 -0
  14. package/dist/internal/machine/cluster.d.ts +2 -3
  15. package/dist/internal/machine/cluster.d.ts.map +1 -1
  16. package/dist/internal/machine/cluster.js.map +1 -1
  17. package/dist/internal/machine/configuration.d.ts.map +1 -1
  18. package/dist/internal/machine/configuration.js +14 -4
  19. package/dist/internal/machine/configuration.js.map +1 -1
  20. package/dist/internal/machine/executionPlan.d.ts +1 -0
  21. package/dist/internal/machine/executionPlan.d.ts.map +1 -1
  22. package/dist/internal/machine/executionPlan.js +97 -53
  23. package/dist/internal/machine/executionPlan.js.map +1 -1
  24. package/dist/internal/machine/invocation.d.ts.map +1 -1
  25. package/dist/internal/machine/invocation.js +4 -2
  26. package/dist/internal/machine/invocation.js.map +1 -1
  27. package/dist/internal/machine/invocationDefinition.d.ts +35 -0
  28. package/dist/internal/machine/invocationDefinition.d.ts.map +1 -0
  29. package/dist/internal/machine/invocationDefinition.js +21 -0
  30. package/dist/internal/machine/invocationDefinition.js.map +1 -0
  31. package/dist/internal/machine/invocationEvent.d.ts +0 -2
  32. package/dist/internal/machine/invocationEvent.d.ts.map +1 -1
  33. package/dist/internal/machine/invocationEvent.js +0 -8
  34. package/dist/internal/machine/invocationEvent.js.map +1 -1
  35. package/dist/internal/machine/machine.d.ts +21 -43
  36. package/dist/internal/machine/machine.d.ts.map +1 -1
  37. package/dist/internal/machine/machine.js +134 -403
  38. package/dist/internal/machine/machine.js.map +1 -1
  39. package/dist/internal/machine/planner.d.ts +13 -19
  40. package/dist/internal/machine/planner.d.ts.map +1 -1
  41. package/dist/internal/machine/planner.js +63 -35
  42. package/dist/internal/machine/planner.js.map +1 -1
  43. package/dist/internal/machine/process.d.ts +6 -8
  44. package/dist/internal/machine/process.d.ts.map +1 -1
  45. package/dist/internal/machine/process.js +1 -0
  46. package/dist/internal/machine/process.js.map +1 -1
  47. package/dist/internal/machine/protocol.d.ts +2 -2
  48. package/dist/internal/machine/protocol.d.ts.map +1 -1
  49. package/dist/internal/machine/protocol.js +4 -18
  50. package/dist/internal/machine/protocol.js.map +1 -1
  51. package/dist/internal/machine/readiness.d.ts +1 -1
  52. package/dist/internal/machine/readiness.d.ts.map +1 -1
  53. package/dist/internal/machine/requirements.d.ts +4 -0
  54. package/dist/internal/machine/requirements.d.ts.map +1 -0
  55. package/dist/internal/machine/requirements.js +2 -0
  56. package/dist/internal/machine/requirements.js.map +1 -0
  57. package/dist/internal/machine/runtime.d.ts +4 -58
  58. package/dist/internal/machine/runtime.d.ts.map +1 -1
  59. package/dist/internal/machine/runtime.js +1 -69
  60. package/dist/internal/machine/runtime.js.map +1 -1
  61. package/dist/internal/machine/serialization.d.ts.map +1 -1
  62. package/dist/internal/machine/serialization.js +16 -0
  63. package/dist/internal/machine/serialization.js.map +1 -1
  64. package/dist/internal/machine/stateDefinition.d.ts +3 -1
  65. package/dist/internal/machine/stateDefinition.d.ts.map +1 -1
  66. package/dist/internal/machine/stateDefinition.js +36 -2
  67. package/dist/internal/machine/stateDefinition.js.map +1 -1
  68. package/dist/internal/machine/targetBuilder.d.ts +16 -0
  69. package/dist/internal/machine/targetBuilder.d.ts.map +1 -0
  70. package/dist/internal/machine/targetBuilder.js +333 -0
  71. package/dist/internal/machine/targetBuilder.js.map +1 -0
  72. package/dist/internal/machine/topology.js +3 -3
  73. package/dist/internal/machine/topology.js.map +1 -1
  74. package/dist/internal/machine/transition.d.ts +16 -0
  75. package/dist/internal/machine/transition.d.ts.map +1 -0
  76. package/dist/internal/machine/transition.js +2 -0
  77. package/dist/internal/machine/transition.js.map +1 -0
  78. package/dist/internal/testing/machine/finiteModel.d.ts.map +1 -1
  79. package/dist/internal/testing/machine/finiteModel.js +11 -13
  80. package/dist/internal/testing/machine/finiteModel.js.map +1 -1
  81. package/dist/internal/testing/machine/format.d.ts +7 -0
  82. package/dist/internal/testing/machine/format.d.ts.map +1 -0
  83. package/dist/internal/testing/machine/format.js +104 -0
  84. package/dist/internal/testing/machine/format.js.map +1 -0
  85. package/dist/internal/testing/machine/probe.d.ts +1 -1
  86. package/dist/internal/testing/machine/probe.d.ts.map +1 -1
  87. package/dist/internal/testing/machine/probe.js +1 -1
  88. package/dist/internal/testing/machine/probe.js.map +1 -1
  89. package/dist/internal/testing/machine/referenceModel.d.ts.map +1 -1
  90. package/dist/internal/testing/machine/referenceModel.js +15 -19
  91. package/dist/internal/testing/machine/referenceModel.js.map +1 -1
  92. package/dist/internal/testing/machine/trace.d.ts +1 -1
  93. package/dist/internal/testing/machine/trace.d.ts.map +1 -1
  94. package/dist/internal/testing/machine/trace.js +3 -3
  95. package/dist/internal/testing/machine/trace.js.map +1 -1
  96. package/dist/internal/testing/machine/value.d.ts +8 -0
  97. package/dist/internal/testing/machine/value.d.ts.map +1 -0
  98. package/dist/internal/testing/machine/value.js +82 -0
  99. package/dist/internal/testing/machine/value.js.map +1 -0
  100. package/dist/internal/testing/machine/verification.d.ts +2 -13
  101. package/dist/internal/testing/machine/verification.d.ts.map +1 -1
  102. package/dist/internal/testing/machine/verification.js +21 -113
  103. package/dist/internal/testing/machine/verification.js.map +1 -1
  104. package/dist/testing/MachineTest.d.ts +89 -104
  105. package/dist/testing/MachineTest.d.ts.map +1 -1
  106. package/dist/testing/MachineTest.js +70 -84
  107. package/dist/testing/MachineTest.js.map +1 -1
  108. package/dist/unstable/cluster/ClusterMachine.d.ts +10 -13
  109. package/dist/unstable/cluster/ClusterMachine.d.ts.map +1 -1
  110. package/dist/unstable/cluster/ClusterMachine.js +5 -8
  111. package/dist/unstable/cluster/ClusterMachine.js.map +1 -1
  112. package/dist/unstable/reactivity/AtomMachine.d.ts +26 -61
  113. package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
  114. package/dist/unstable/reactivity/AtomMachine.js +17 -26
  115. package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
  116. package/docs/agent-guide.md +45 -45
  117. package/docs/effect-atom-react.md +35 -63
  118. package/docs/machine-review.md +7 -7
  119. package/docs/root-api.md +259 -0
  120. package/package.json +1 -1
  121. package/src/Machine.ts +1053 -538
  122. package/src/internal/machine/atom.ts +3 -13
  123. package/src/internal/machine/childRegistry.ts +141 -0
  124. package/src/internal/machine/cluster.ts +5 -14
  125. package/src/internal/machine/configuration.ts +20 -4
  126. package/src/internal/machine/executionPlan.ts +109 -52
  127. package/src/internal/machine/invocation.ts +10 -6
  128. package/src/internal/machine/invocationDefinition.ts +52 -0
  129. package/src/internal/machine/invocationEvent.ts +0 -8
  130. package/src/internal/machine/machine.ts +222 -716
  131. package/src/internal/machine/planner.ts +74 -62
  132. package/src/internal/machine/process.ts +14 -21
  133. package/src/internal/machine/protocol.ts +9 -32
  134. package/src/internal/machine/readiness.ts +1 -0
  135. package/src/internal/machine/requirements.ts +11 -0
  136. package/src/internal/machine/runtime.ts +17 -186
  137. package/src/internal/machine/serialization.ts +22 -0
  138. package/src/internal/machine/stateDefinition.ts +36 -3
  139. package/src/internal/machine/targetBuilder.ts +525 -0
  140. package/src/internal/machine/topology.ts +3 -3
  141. package/src/internal/machine/transition.ts +26 -0
  142. package/src/internal/testing/machine/finiteModel.ts +23 -24
  143. package/src/internal/testing/machine/format.ts +120 -0
  144. package/src/internal/testing/machine/probe.ts +4 -4
  145. package/src/internal/testing/machine/referenceModel.ts +25 -17
  146. package/src/internal/testing/machine/trace.ts +4 -4
  147. package/src/internal/testing/machine/value.ts +77 -0
  148. package/src/internal/testing/machine/verification.ts +904 -1109
  149. package/src/testing/MachineTest.ts +103 -114
  150. package/src/unstable/cluster/ClusterMachine.ts +10 -20
  151. package/src/unstable/reactivity/AtomMachine.ts +42 -79
@@ -40,6 +40,7 @@ import {
40
40
  } from "./configuration.js"
41
41
  import { InfiniteTransitionError, MachineSchemaDecodeError, StartupError, StoppedError } from "./errors.js"
42
42
  import { getStateInitializeValues, makeStateInitializeBuilder } from "./initialization.js"
43
+ import * as InvocationDefinition from "./invocationDefinition.js"
43
44
  import * as InvocationEvent from "./invocationEvent.js"
44
45
  import { decodeEventSync, decodeInputSync, decodeStateValueSync } from "./protocol.js"
45
46
  import { InitialEventTypeId } from "./symbols.js"
@@ -56,9 +57,15 @@ import {
56
57
  isStateUpdate,
57
58
  isTarget,
58
59
  makeChoiceTarget,
60
+ makeStateInput,
59
61
  makeTarget,
60
62
  TargetSnapshotTypeId
61
63
  } from "./topology.js"
64
+ import type {
65
+ EventTransition,
66
+ TransitionEvaluator,
67
+ TransitionHandler as CapturedTransitionHandler
68
+ } from "./transition.js"
62
69
 
63
70
  export type MicrostepPlan<State, Event, E, R> = {
64
71
  readonly next: State
@@ -104,21 +111,12 @@ export type MacrostepPlan<State, Event, E, R, Output> =
104
111
  }
105
112
  )
106
113
 
107
- export type TransitionHandler<States extends Machine.StateSchemas, E, R, Context> = (
108
- context: Context,
109
- enqueue: Enqueue<any, any>
110
- ) => Machine.HandlerResult<States, E, R> | Machine.Declined
111
-
112
- type TransitionEvaluation<States extends Machine.StateSchemas, E, R> = {
113
- readonly result: Machine.HandlerResult<States, E, R> | Machine.Declined
114
- readonly branchIndex: number
115
- readonly branchKey: string | undefined
116
- }
117
-
118
- type TransitionEvaluator<States extends Machine.StateSchemas, E, R, Context> = (
119
- context: Context,
120
- enqueue: Enqueue<any, any>
121
- ) => TransitionEvaluation<States, E, R>
114
+ export type TransitionHandler<States extends Machine.StateSchemas, E, R, Context> = CapturedTransitionHandler<
115
+ States,
116
+ E,
117
+ R,
118
+ Context
119
+ >
122
120
 
123
121
  type PlanningMachineReferences = {
124
122
  readonly self: MachineTarget<any>
@@ -170,16 +168,6 @@ const resolveMachineReferences = (
170
168
  return root
171
169
  }
172
170
 
173
- type EventTransition<States extends Machine.StateSchemas, E, R, Context> =
174
- | TransitionHandler<States, E, R, Context>
175
- | {
176
- readonly reenter?: boolean
177
- readonly declinable?: boolean
178
- readonly targets?: ReadonlyArray<string>
179
- readonly transition: TransitionHandler<States, E, R, Context>
180
- readonly evaluate?: TransitionEvaluator<States, E, R, Context>
181
- }
182
-
183
171
  export type MicrostepTransition<States extends Machine.StateSchemas, E, R, Context> = {
184
172
  readonly reenter: boolean
185
173
  readonly declinable: boolean
@@ -344,7 +332,9 @@ const completeHistoryConfiguration = (
344
332
  if (child.schema !== undefined) {
345
333
  const initializer = machine.handlers[path]?.initialize
346
334
  if (initializer === undefined) {
347
- throw new Error(`Machine shallow history requires an initial value implementation for state "${path}"`)
335
+ values.set(child.path, decodeStateValueSync(machine, child, makeStateInput({})))
336
+ changed = true
337
+ continue
348
338
  }
349
339
  const initialized = collectStateInitializer(machine, initializer, {
350
340
  ...resolveMachineReferences(machine, current),
@@ -374,9 +364,6 @@ const completeHistoryConfiguration = (
374
364
  machineReferences: configuration.machineReferences
375
365
  } as ActiveConfiguration
376
366
  const initializer = valuedMissing.length === 0 ? undefined : machine.handlers[path]?.initialize
377
- if (valuedMissing.length > 0 && initializer === undefined) {
378
- throw new Error(`Machine shallow history requires an initial value implementation for state "${path}"`)
379
- }
380
367
  const initialized = initializer === undefined ? undefined : collectStateInitializer(machine, initializer, {
381
368
  ...resolveMachineReferences(machine, current),
382
369
  state: current.values.get(path),
@@ -392,8 +379,11 @@ const completeHistoryConfiguration = (
392
379
  const child = getNode(machine, childPath)
393
380
  active.add(child.path)
394
381
  if (child.schema !== undefined) {
382
+ if (initialized === undefined) {
383
+ values.set(child.path, decodeStateValueSync(machine, child, makeStateInput({})))
384
+ continue
385
+ }
395
386
  if (
396
- initialized === undefined ||
397
387
  initializedValues === undefined || !Object.prototype.hasOwnProperty.call(initializedValues, child.key)
398
388
  ) {
399
389
  throw new Error(`Machine parallel state initializer for "${path}" must return region "${child.key}"`)
@@ -468,6 +458,7 @@ function resolveHistoryTarget(
468
458
  const completed = completeHistoryConfiguration(machine, restored, event)
469
459
  const snapshot = snapshotFromConfigurationAtPath(machine, completed.configuration, target.parent)
470
460
  const values = Object.fromEntries(completed.configuration.values)
461
+ if (target.parent !== "" && configuration.active.has("")) delete values[""]
471
462
  return {
472
463
  target: makeTarget(target.parent as any, snapshot.value as any, {
473
464
  snapshot: snapshot as any,
@@ -487,7 +478,7 @@ function resolveHistoryTarget(
487
478
  }
488
479
  const collected = collectTransition(machine, fallback, {
489
480
  event,
490
- target: getTargetBuilder(machine, target.parent).full,
481
+ target: getTargetBuilder(machine, target.parent).full[""],
491
482
  owner: target.parent
492
483
  })
493
484
  if (collected.state === undefined || isHistoryTarget(collected.state) || !isSnapshot(collected.state)) {
@@ -531,6 +522,7 @@ function resolveHistoryTarget(
531
522
  }
532
523
  const snapshot = snapshotFromConfigurationAtPath(machine, fallbackConfiguration, target.parent)
533
524
  const values = Object.fromEntries(fallbackConfiguration.values)
525
+ if (target.parent !== "" && configuration.active.has("")) delete values[""]
534
526
  return {
535
527
  target: makeTarget(target.parent as any, snapshot.value as any, {
536
528
  snapshot: snapshot as any,
@@ -765,7 +757,7 @@ const collectStateActions = <
765
757
  ) => {
766
758
  const commands: Array<RuntimeCommand> = []
767
759
  const raisedEvents: Array<Machine.EventOf<Events>> = []
768
- const emittedEvents: Array<Machine.EmitOf<Emits>> = []
760
+ const emittedEvents: Array<Machine.EmittedEventOf<Emits>> = []
769
761
  for (const path of paths) {
770
762
  const collected = collectStateAction<
771
763
  Machine.StateActionContext<States, Events, Emits, Machine.StateIdentifier<States>>,
@@ -784,7 +776,7 @@ const collectStateActions = <
784
776
  )
785
777
  commands.push(...collected.commands)
786
778
  raisedEvents.push(...collected.raisedEvents)
787
- emittedEvents.push(...collected.emittedEvents as ReadonlyArray<Machine.EmitOf<Emits>>)
779
+ emittedEvents.push(...collected.emittedEvents as ReadonlyArray<Machine.EmittedEventOf<Emits>>)
788
780
  }
789
781
  return { commands, emittedEvents, raisedEvents }
790
782
  }
@@ -1024,7 +1016,7 @@ const selectInvocationTransition = <
1024
1016
  ): ReadonlyArray<SelectedTransition<States, E, R, any>> => {
1025
1017
  if (!configuration.active.has(event.path)) return []
1026
1018
  const config = machine.handlers[event.path] as Machine.AnyStateConfig | undefined
1027
- const invoke = InvocationEvent.definitions(config?.invoke).find((definition) => {
1019
+ const invoke = InvocationDefinition.definitions(config?.invoke).find((definition) => {
1028
1020
  const id = "child" in definition ? definition.child?.id : definition.id
1029
1021
  return String(id) === event.id
1030
1022
  })
@@ -1096,7 +1088,7 @@ export const validateDeclaredTransitionTarget = (
1096
1088
  const actual = typeof target === "object" && target !== null && "path" in target
1097
1089
  ? String(target.path)
1098
1090
  : "<unknown>"
1099
- if (!declaredTargets.some((path) => actual === path || actual.startsWith(`${path}.`))) {
1091
+ if (!declaredTargets.some((path) => actual === path || (path === "" || actual.startsWith(`${path}.`)))) {
1100
1092
  const triggerLabel = trigger.type === "event" ? String(trigger.event) : trigger.type
1101
1093
  throw new Error(
1102
1094
  `Machine transition from "${sourcePath}" on "${triggerLabel}" returned target "${actual}" outside declared targets: ${
@@ -1386,10 +1378,9 @@ const collectEvaluatedTransition = <
1386
1378
  ? (() => {
1387
1379
  const node = getNode(machine, stateUpdate.path)
1388
1380
  if (
1389
- !state.active.has(node.path) || node.schema === undefined ||
1390
- (node.type !== "compound" && node.type !== "parallel")
1381
+ !state.active.has(node.path) || node.schema === undefined
1391
1382
  ) {
1392
- throw new Error(`Machine state update owner "${node.path}" must be an active valued compound or parallel state`)
1383
+ throw new Error(`Machine state update owner "${node.path}" must be an active valued state`)
1393
1384
  }
1394
1385
  return {
1395
1386
  path: node.path,
@@ -1707,13 +1698,17 @@ export const planInitialSync = <
1707
1698
  : args.length === 0
1708
1699
  ? (decodeInputSync(machine, machine.input, undefined), args)
1709
1700
  : [decodeInputSync(machine, machine.input, args[0])] as [...Machine.InputArgs<Input>]
1710
- const state = machine.initial(...inputArgs)
1701
+ const initial = machine.initial(...inputArgs)
1711
1702
  const emptyConfiguration: ActiveConfiguration = {
1712
1703
  active: new Set(),
1713
1704
  values: new Map(),
1714
1705
  outputs: new Map(),
1715
1706
  history: new Map()
1716
1707
  }
1708
+ const rootResolution = isInitialTarget(initial)
1709
+ ? resolveInitialTarget(machine, emptyConfiguration, initial, InitialEvent)
1710
+ : undefined
1711
+ const state = rootResolution?.target ?? initial
1717
1712
  const initialChoice = choiceFromTarget(state)
1718
1713
  const choiceResolution = initialChoice === undefined
1719
1714
  ? undefined
@@ -1729,9 +1724,11 @@ export const planInitialSync = <
1729
1724
  const initialHistoryChoiceTransitions: Array<ResolvedChoiceTransition> = []
1730
1725
  const resolvedInitialTargets: Array<unknown> = []
1731
1726
  for (
1732
- const target of choiceResolution === undefined
1727
+ const target of choiceResolution !== undefined
1728
+ ? [choiceResolution.target, ...choiceResolution.additionalTargets]
1729
+ : rootResolution === undefined
1733
1730
  ? []
1734
- : [choiceResolution.target, ...choiceResolution.additionalTargets]
1731
+ : [rootResolution.target]
1735
1732
  ) {
1736
1733
  if (!isHistoryTarget(target)) {
1737
1734
  resolvedInitialTargets.push(target)
@@ -1744,7 +1741,7 @@ export const planInitialSync = <
1744
1741
  initialHistoryEmittedEvents.push(...history.emittedEvents)
1745
1742
  initialHistoryChoiceTransitions.push(...history.transitions)
1746
1743
  }
1747
- let resolvedConfiguration = choiceResolution === undefined
1744
+ let resolvedConfiguration = resolvedInitialTargets.length === 0
1748
1745
  ? normalizeConfigurationSync<States>(machine, state as Machine.Snapshot<States>)
1749
1746
  : normalizeTargetConfigurationSync<States>(
1750
1747
  machine,
@@ -1761,18 +1758,21 @@ export const planInitialSync = <
1761
1758
  )
1762
1759
  }
1763
1760
  const configuration: ActiveConfiguration = resolvedConfiguration
1764
- validateInitialConfiguration(machine, configuration)
1761
+ if (machine.initialDefinition.selection.kind === "initial") validateInitialConfiguration(machine, configuration)
1765
1762
  const startingState = snapshotFromConfiguration<States>(machine, configuration)
1766
1763
  const initialEntryPaths = getInitialEntryPaths(machine, configuration)
1767
1764
  const commands = [
1765
+ ...(rootResolution?.commands ?? []),
1768
1766
  ...(choiceResolution?.commands ?? []),
1769
1767
  ...initialHistoryActions
1770
1768
  ]
1771
1769
  const raisedEvents = [
1770
+ ...(rootResolution?.raisedEvents ?? []),
1772
1771
  ...(choiceResolution?.raisedEvents ?? []),
1773
1772
  ...initialHistoryRaisedEvents
1774
1773
  ]
1775
1774
  const emittedEvents = [
1775
+ ...(rootResolution?.emittedEvents ?? []),
1776
1776
  ...(choiceResolution?.emittedEvents ?? []),
1777
1777
  ...initialHistoryEmittedEvents
1778
1778
  ]
@@ -1790,21 +1790,27 @@ export const planInitialSync = <
1790
1790
  [...entry.commands],
1791
1791
  [...raisedEvents, ...entry.raisedEvents] as Array<Machine.EventOf<Events>>,
1792
1792
  [...emittedEvents, ...entry.emittedEvents],
1793
- choiceResolution === undefined ? [] : [{
1794
- next: configuration,
1795
- event: InitialEvent,
1796
- transitions: [...choiceResolution.transitions, ...initialHistoryChoiceTransitions],
1797
- commands: [...choiceResolution.commands, ...initialHistoryActions],
1798
- raisedEvents: [
1799
- ...choiceResolution.raisedEvents,
1800
- ...initialHistoryRaisedEvents
1801
- ] as ReadonlyArray<Machine.EventOf<Events>>,
1802
- emittedEvents: [...choiceResolution.emittedEvents, ...initialHistoryEmittedEvents],
1803
- exitPaths: [],
1804
- entryPaths: [],
1805
- changed: false,
1806
- stabilize: false
1807
- }]
1793
+ choiceResolution === undefined && (rootResolution?.transitions.length ?? 0) === 0 &&
1794
+ initialHistoryChoiceTransitions.length === 0 ?
1795
+ [] :
1796
+ [{
1797
+ next: configuration,
1798
+ event: InitialEvent,
1799
+ transitions: [
1800
+ ...(rootResolution?.transitions ?? []),
1801
+ ...(choiceResolution?.transitions ?? []),
1802
+ ...initialHistoryChoiceTransitions
1803
+ ],
1804
+ commands,
1805
+ raisedEvents: [
1806
+ ...raisedEvents
1807
+ ] as ReadonlyArray<Machine.EventOf<Events>>,
1808
+ emittedEvents,
1809
+ exitPaths: [],
1810
+ entryPaths: [],
1811
+ changed: false,
1812
+ stabilize: false
1813
+ }]
1808
1814
  )
1809
1815
 
1810
1816
  const planned = {
@@ -1815,7 +1821,7 @@ export const planInitialSync = <
1815
1821
  ...commands,
1816
1822
  ...settled.commands
1817
1823
  ],
1818
- emittedEvents: settled.emittedEvents as ReadonlyArray<Machine.EmitOf<Emits>>,
1824
+ emittedEvents: settled.emittedEvents as ReadonlyArray<Machine.EmittedEventOf<Emits>>,
1819
1825
  microsteps: settled.microsteps.map((step) => ({
1820
1826
  next: snapshotFromConfiguration<States>(machine, step.next),
1821
1827
  event: step.event,
@@ -2208,6 +2214,7 @@ const macrostepConfiguration = <
2208
2214
  throw new Error("Machine reached a terminal configuration without a completed root output")
2209
2215
  }
2210
2216
  return {
2217
+ event: decodedEvent,
2211
2218
  next: completed.configuration,
2212
2219
  commands: [],
2213
2220
  emittedEvents: [],
@@ -2226,6 +2233,7 @@ const macrostepConfiguration = <
2226
2233
  )
2227
2234
  if (selections.length === 0) {
2228
2235
  return {
2236
+ event: decodedEvent,
2229
2237
  next: configuration,
2230
2238
  commands: [],
2231
2239
  emittedEvents: [],
@@ -2244,7 +2252,10 @@ const macrostepConfiguration = <
2244
2252
  const raisedEvents = [...step.raisedEvents]
2245
2253
  const emittedEvents = [...step.emittedEvents]
2246
2254
  const microsteps = [step]
2247
- return settle(machine, step.next, decodedEvent as any, commands, raisedEvents, emittedEvents, microsteps)
2255
+ return {
2256
+ ...settle(machine, step.next, decodedEvent as any, commands, raisedEvents, emittedEvents, microsteps),
2257
+ event: decodedEvent
2258
+ }
2248
2259
  }
2249
2260
 
2250
2261
  const snapshotMacrostep = <
@@ -2255,9 +2266,10 @@ const snapshotMacrostep = <
2255
2266
  Output
2256
2267
  >(
2257
2268
  machine: Machine.Any,
2258
- settled: MacrostepPlan<ActiveConfiguration, Event, E, R, Output>
2259
- ): MacrostepPlan<Machine.Snapshot<States>, Event, E, R, Output> => {
2269
+ settled: MacrostepPlan<ActiveConfiguration, Event, E, R, Output> & { readonly event: unknown }
2270
+ ): MacrostepPlan<Machine.Snapshot<States>, Event, E, R, Output> & { readonly event: unknown } => {
2260
2271
  const planned = {
2272
+ event: settled.event,
2261
2273
  next: snapshotFromConfiguration<States>(machine, settled.next),
2262
2274
  commands: settled.commands,
2263
2275
  emittedEvents: settled.emittedEvents,
@@ -16,19 +16,10 @@ import type { StoppedError } from "./errors.js"
16
16
  import * as ExecutionPlan from "./executionPlan.js"
17
17
  import * as Invocation from "./invocation.js"
18
18
  import * as internalPlanner from "./planner.js"
19
+ import type { ExcludeCompatibleRuntime } from "./requirements.js"
19
20
  import * as internalRuntime from "./runtime.js"
20
21
  import * as Serialization from "./serialization.js"
21
22
 
22
- type IsAny<A> = 0 extends (1 & A) ? true : false
23
-
24
- type ExcludeCompatibleRuntime<Requirements, Events, Emits> = Requirements extends Runtime.Requirement<
25
- infer RequiredEvents,
26
- infer RequiredEmits
27
- > ? IsAny<Requirements> extends true ? Requirements
28
- : [RequiredEvents] extends [Events] ? [RequiredEmits] extends [Emits] ? never : Requirements
29
- : Requirements
30
- : Requirements
31
-
32
23
  type ProcessEntry<States extends Machine.StateSchemas, Input extends Schema.Top> =
33
24
  | {
34
25
  readonly _tag: "Initial"
@@ -50,6 +41,7 @@ const runSequentialDiscard = <E, R>(
50
41
 
51
42
  const acknowledgedPlan = (
52
43
  planned: {
44
+ readonly event: unknown
53
45
  readonly next: unknown
54
46
  readonly commands: ReadonlyArray<unknown>
55
47
  readonly emittedEvents: ReadonlyArray<unknown>
@@ -69,6 +61,7 @@ const acknowledgedPlan = (
69
61
  },
70
62
  snapshot: (state: unknown) => unknown
71
63
  ): unknown => ({
64
+ event: planned.event,
72
65
  next: snapshot(planned.next),
73
66
  commands: planned.commands,
74
67
  emittedEvents: planned.emittedEvents,
@@ -397,7 +390,7 @@ const makeProcessLogic: <
397
390
  ExcludeCompatibleRuntime<
398
391
  Exclude<ExecutionServices<InitialR | R>, internalRuntime.MachineRuntime>,
399
392
  Machine.EventOf<Events>,
400
- Machine.EmitOf<Emits>
393
+ Machine.EmittedEventOf<Emits>
401
394
  >,
402
395
  Output,
403
396
  | InitialE
@@ -469,7 +462,7 @@ const makeProcessLogic: <
469
462
  ? undefined
470
463
  : CommandRuntime.runEmittedEvents(
471
464
  planned.emittedEvents,
472
- CommandRuntime.makeLiveRuntime<Machine.EventOf<Events>, Machine.EmitOf<Emits>>(machine, scope)
465
+ CommandRuntime.makeLiveRuntime<Machine.EventOf<Events>, Machine.EmittedEventOf<Emits>>(machine, scope)
473
466
  )
474
467
  const result = Effect.succeed({
475
468
  state: planned.state,
@@ -531,7 +524,7 @@ const makeProcessLogic: <
531
524
  // so the Effect scheduler remains responsible for cooperative yield.
532
525
  let configuration: Configuration.ActiveConfiguration | undefined
533
526
  let pendingMessage: Option.Option<internalRuntime.ProcessMessage<Machine.EventOf<Events>>> = Option.none()
534
- let liveRuntime: Runtime<Machine.EventOf<Events>, Machine.EmitOf<Emits>> | undefined
527
+ let liveRuntime: Runtime<Machine.EventOf<Events>, Machine.EmittedEventOf<Emits>> | undefined
535
528
  while (terminal === undefined) {
536
529
  const message = Option.isSome(pendingMessage) ? pendingMessage.value : yield* receiveMessage
537
530
  pendingMessage = Option.none()
@@ -563,7 +556,7 @@ const makeProcessLogic: <
563
556
  current = next
564
557
  if (planned.emittedEvents.length > 0) {
565
558
  yield* CommandRuntime.runEmittedEvents(
566
- planned.emittedEvents as ReadonlyArray<Machine.EmitOf<Emits>>,
559
+ planned.emittedEvents as ReadonlyArray<Machine.EmittedEventOf<Emits>>,
567
560
  liveRuntime ??= CommandRuntime.makeLiveRuntime(machine, context)
568
561
  )
569
562
  }
@@ -639,7 +632,7 @@ const makeProcessLogic: <
639
632
  // worker can continue draining an already queued batch.
640
633
  configuration = undefined
641
634
  let pendingMessage: Option.Option<internalRuntime.ProcessMessage<Machine.EventOf<Events>>> = Option.none()
642
- let liveRuntime: Runtime<Machine.EventOf<Events>, Machine.EmitOf<Emits>> | undefined
635
+ let liveRuntime: Runtime<Machine.EventOf<Events>, Machine.EmittedEventOf<Emits>> | undefined
643
636
 
644
637
  // Match the compact non-invoke loop while retaining state-scoped
645
638
  // child lifecycle work at the same ordered Effect boundaries.
@@ -687,7 +680,7 @@ const makeProcessLogic: <
687
680
  current = next
688
681
  if (planned.emittedEvents.length > 0) {
689
682
  yield* CommandRuntime.runEmittedEvents(
690
- planned.emittedEvents as ReadonlyArray<Machine.EmitOf<Emits>>,
683
+ planned.emittedEvents as ReadonlyArray<Machine.EmittedEventOf<Emits>>,
691
684
  liveRuntime ??= CommandRuntime.makeLiveRuntime(machine, context)
692
685
  )
693
686
  }
@@ -741,7 +734,7 @@ const makeProcessLogic: <
741
734
  ExcludeCompatibleRuntime<
742
735
  Exclude<ExecutionServices<InitialR | R>, internalRuntime.MachineRuntime>,
743
736
  Machine.EventOf<Events>,
744
- Machine.EmitOf<Emits>
737
+ Machine.EmittedEventOf<Emits>
745
738
  >,
746
739
  Output,
747
740
  | InitialE
@@ -781,7 +774,7 @@ export const toProcessLogic: <
781
774
  ExcludeCompatibleRuntime<
782
775
  Exclude<ExecutionServices<InitialR | R>, internalRuntime.MachineRuntime>,
783
776
  Machine.EventOf<Events>,
784
- Machine.EmitOf<Emits>
777
+ Machine.EmittedEventOf<Emits>
785
778
  >,
786
779
  Output,
787
780
  | InitialE
@@ -887,7 +880,7 @@ export const start: <
887
880
  ExcludeCompatibleRuntime<
888
881
  Exclude<ExecutionServices<InitialR | R>, internalRuntime.MachineRuntime>,
889
882
  Machine.EventOf<Events>,
890
- Machine.EmitOf<Emits>
883
+ Machine.EmittedEventOf<Emits>
891
884
  >
892
885
  > = (machine, ...args) =>
893
886
  internalRuntime.startProcess(
@@ -931,7 +924,7 @@ export const prepare: <
931
924
  ExcludeCompatibleRuntime<
932
925
  Exclude<ExecutionServices<InitialR | R>, internalRuntime.MachineRuntime>,
933
926
  Machine.EventOf<Events>,
934
- Machine.EmitOf<Emits>
927
+ Machine.EmittedEventOf<Emits>
935
928
  >
936
929
  >
937
930
  > = (machine, ...args) =>
@@ -966,7 +959,7 @@ export const resume: <
966
959
  ExcludeCompatibleRuntime<
967
960
  Exclude<ExecutionServices<R>, internalRuntime.MachineRuntime>,
968
961
  Machine.EventOf<Events>,
969
- Machine.EmitOf<Emits>
962
+ Machine.EmittedEventOf<Emits>
970
963
  >
971
964
  > = (machine, snapshot) =>
972
965
  internalRuntime.startProcess(
@@ -24,9 +24,7 @@ interface MachineProtocolSchemas {
24
24
  readonly event: Schema.Top
25
25
  readonly emit: Schema.Top
26
26
  readonly eventConstructors: ReadonlySet<object>
27
- readonly trustedEvents: WeakSet<object>
28
27
  readonly emissionConstructors: ReadonlySet<object>
29
- readonly trustedEmissions: WeakSet<object>
30
28
  }
31
29
 
32
30
  interface EventProtocolDefinition {
@@ -171,9 +169,7 @@ export const setProtocol = (machine: Machine.Any): void => {
171
169
  event: Schema.Union(events),
172
170
  emit: Schema.Union(emittedEvents),
173
171
  eventConstructors: collectEventConstructors(events),
174
- trustedEvents: new WeakSet(),
175
- emissionConstructors: collectEventConstructors(emittedEvents),
176
- trustedEmissions: new WeakSet()
172
+ emissionConstructors: collectEventConstructors(emittedEvents)
177
173
  })
178
174
  }
179
175
 
@@ -419,11 +415,6 @@ const decodeEventConstruction = (
419
415
  })
420
416
  )
421
417
  )
422
- ),
423
- Effect.tap((event) =>
424
- Effect.sync(() =>
425
- (boundary === "event" ? protocol.trustedEvents : protocol.trustedEmissions).add(event as object)
426
- )
427
418
  )
428
419
  )
429
420
  }
@@ -453,13 +444,9 @@ const decodeEventConstructionSync = (
453
444
  boundary,
454
445
  event: String(construction._tag)
455
446
  })
456
- ;(boundary === "event" ? protocol.trustedEvents : protocol.trustedEmissions).add(event as object)
457
447
  return event
458
448
  }
459
449
 
460
- const isTrustedEvent = (protocol: MachineProtocolSchemas, event: unknown): boolean =>
461
- typeof event === "object" && event !== null && protocol.trustedEvents.has(event)
462
-
463
450
  export const decodeInput = <Input extends Schema.Top>(
464
451
  machine: Machine.Any,
465
452
  schema: Input,
@@ -478,10 +465,9 @@ export const decodeEvent = <const Events extends ReadonlyArray<Machine.TaggedSch
478
465
  MachineSchemaDecodeError
479
466
  >
480
467
  }
481
- if (isTrustedEvent(protocol, event)) {
482
- return Effect.succeed(event as Machine.EventOf<Events>)
483
- }
484
468
  const eventName = getEventName(event)
469
+ // Decoded objects can escape to user code and be mutated. Validation is local
470
+ // to this delivery; object identity is never evidence of continued validity.
485
471
  return decodeBoundary<Machine.EventOf<Events>>(
486
472
  machine,
487
473
  protocol.event,
@@ -498,9 +484,6 @@ export const decodeEventSync = <const Events extends ReadonlyArray<Machine.Tagge
498
484
  if (isEventConstruction(event)) {
499
485
  return decodeEventConstructionSync(machine, protocol, event, "event") as Machine.EventOf<Events>
500
486
  }
501
- if (isTrustedEvent(protocol, event)) {
502
- return event as Machine.EventOf<Events>
503
- }
504
487
  const eventName = getEventName(event)
505
488
  return decodeBoundarySync<Machine.EventOf<Events>>(
506
489
  machine,
@@ -513,19 +496,16 @@ export const decodeEventSync = <const Events extends ReadonlyArray<Machine.Tagge
513
496
  export const decodeEmit = <const Emits extends ReadonlyArray<Machine.TaggedSchema>>(
514
497
  machine: Machine.Any,
515
498
  event: unknown
516
- ): Effect.Effect<Machine.EmitOf<Emits>, MachineSchemaDecodeError> => {
499
+ ): Effect.Effect<Machine.EmittedEventOf<Emits>, MachineSchemaDecodeError> => {
517
500
  const protocol = getProtocolSchemas(machine)
518
501
  if (isEventConstruction(event)) {
519
502
  return decodeEventConstruction(machine, protocol, event, "emission") as Effect.Effect<
520
- Machine.EmitOf<Emits>,
503
+ Machine.EmittedEventOf<Emits>,
521
504
  MachineSchemaDecodeError
522
505
  >
523
506
  }
524
- if (typeof event === "object" && event !== null && protocol.trustedEmissions.has(event)) {
525
- return Effect.succeed(event as Machine.EmitOf<Emits>)
526
- }
527
507
  const eventName = getEventName(event)
528
- return decodeBoundary<Machine.EmitOf<Emits>>(
508
+ return decodeBoundary<Machine.EmittedEventOf<Emits>>(
529
509
  machine,
530
510
  protocol.emit,
531
511
  event,
@@ -536,16 +516,13 @@ export const decodeEmit = <const Emits extends ReadonlyArray<Machine.TaggedSchem
536
516
  export const decodeEmitSync = <const Emits extends ReadonlyArray<Machine.TaggedSchema>>(
537
517
  machine: Machine.Any,
538
518
  event: unknown
539
- ): Machine.EmitOf<Emits> => {
519
+ ): Machine.EmittedEventOf<Emits> => {
540
520
  const protocol = getProtocolSchemas(machine)
541
521
  if (isEventConstruction(event)) {
542
- return decodeEventConstructionSync(machine, protocol, event, "emission") as Machine.EmitOf<Emits>
543
- }
544
- if (typeof event === "object" && event !== null && protocol.trustedEmissions.has(event)) {
545
- return event as Machine.EmitOf<Emits>
522
+ return decodeEventConstructionSync(machine, protocol, event, "emission") as Machine.EmittedEventOf<Emits>
546
523
  }
547
524
  const eventName = getEventName(event)
548
- return decodeBoundarySync<Machine.EmitOf<Emits>>(
525
+ return decodeBoundarySync<Machine.EmittedEventOf<Emits>>(
549
526
  machine,
550
527
  protocol.emit,
551
528
  event,
@@ -8,3 +8,4 @@ export type EnsureExecutable<
8
8
  > =
9
9
  & Machine.Machine.EnsureOutputImplementations<States, OutputStates>
10
10
  & Machine.Machine.EnsureHistoryImplementations<States, UnhandledStates>
11
+ & Machine.Machine.EnsureInitialImplementations<States, UnhandledStates>
@@ -0,0 +1,11 @@
1
+ import type { Runtime } from "../../Machine.js"
2
+
3
+ export type IsAny<A> = 0 extends (1 & A) ? true : false
4
+
5
+ export type ExcludeCompatibleRuntime<Requirements, Events, Emits> = Requirements extends Runtime.Requirement<
6
+ infer RequiredEvents,
7
+ infer RequiredEmits
8
+ > ? IsAny<Requirements> extends true ? Requirements
9
+ : [RequiredEvents] extends [Events] ? [RequiredEmits] extends [Emits] ? never : Requirements
10
+ : Requirements
11
+ : Requirements