@typeonce/effect-machine 0.12.0 → 0.14.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 (103) hide show
  1. package/README.md +130 -30
  2. package/dist/Machine.d.ts +722 -262
  3. package/dist/Machine.d.ts.map +1 -1
  4. package/dist/Machine.js +130 -62
  5. package/dist/Machine.js.map +1 -1
  6. package/dist/internal/machine/atom.d.ts +1 -0
  7. package/dist/internal/machine/atom.d.ts.map +1 -1
  8. package/dist/internal/machine/atom.js +23 -0
  9. package/dist/internal/machine/atom.js.map +1 -1
  10. package/dist/internal/machine/commandRuntime.d.ts.map +1 -1
  11. package/dist/internal/machine/commandRuntime.js +2 -5
  12. package/dist/internal/machine/commandRuntime.js.map +1 -1
  13. package/dist/internal/machine/configuration.d.ts +5 -0
  14. package/dist/internal/machine/configuration.d.ts.map +1 -1
  15. package/dist/internal/machine/configuration.js +6 -2
  16. package/dist/internal/machine/configuration.js.map +1 -1
  17. package/dist/internal/machine/executionPlan.d.ts +1 -0
  18. package/dist/internal/machine/executionPlan.d.ts.map +1 -1
  19. package/dist/internal/machine/executionPlan.js +57 -24
  20. package/dist/internal/machine/executionPlan.js.map +1 -1
  21. package/dist/internal/machine/initialization.d.ts +5 -0
  22. package/dist/internal/machine/initialization.d.ts.map +1 -0
  23. package/dist/internal/machine/initialization.js +61 -0
  24. package/dist/internal/machine/initialization.js.map +1 -0
  25. package/dist/internal/machine/inspectionRuntime.d.ts +25 -0
  26. package/dist/internal/machine/inspectionRuntime.d.ts.map +1 -0
  27. package/dist/internal/machine/inspectionRuntime.js +79 -0
  28. package/dist/internal/machine/inspectionRuntime.js.map +1 -0
  29. package/dist/internal/machine/invocation.d.ts +2 -1
  30. package/dist/internal/machine/invocation.d.ts.map +1 -1
  31. package/dist/internal/machine/invocation.js +17 -10
  32. package/dist/internal/machine/invocation.js.map +1 -1
  33. package/dist/internal/machine/machine.d.ts +4 -3
  34. package/dist/internal/machine/machine.d.ts.map +1 -1
  35. package/dist/internal/machine/machine.js +327 -32
  36. package/dist/internal/machine/machine.js.map +1 -1
  37. package/dist/internal/machine/planner.d.ts +28 -0
  38. package/dist/internal/machine/planner.d.ts.map +1 -1
  39. package/dist/internal/machine/planner.js +132 -51
  40. package/dist/internal/machine/planner.js.map +1 -1
  41. package/dist/internal/machine/process.d.ts.map +1 -1
  42. package/dist/internal/machine/process.js +4 -2
  43. package/dist/internal/machine/process.js.map +1 -1
  44. package/dist/internal/machine/runtime.d.ts +27 -3
  45. package/dist/internal/machine/runtime.d.ts.map +1 -1
  46. package/dist/internal/machine/runtime.js +440 -64
  47. package/dist/internal/machine/runtime.js.map +1 -1
  48. package/dist/internal/machine/symbols.d.ts +2 -0
  49. package/dist/internal/machine/symbols.d.ts.map +1 -1
  50. package/dist/internal/machine/symbols.js +2 -0
  51. package/dist/internal/machine/symbols.js.map +1 -1
  52. package/dist/internal/machine/topology.d.ts +25 -0
  53. package/dist/internal/machine/topology.d.ts.map +1 -1
  54. package/dist/internal/machine/topology.js +26 -10
  55. package/dist/internal/machine/topology.js.map +1 -1
  56. package/dist/internal/testing/machine/exploration.d.ts.map +1 -1
  57. package/dist/internal/testing/machine/exploration.js +11 -2
  58. package/dist/internal/testing/machine/exploration.js.map +1 -1
  59. package/dist/internal/testing/machine/finiteModel.d.ts.map +1 -1
  60. package/dist/internal/testing/machine/finiteModel.js +75 -69
  61. package/dist/internal/testing/machine/finiteModel.js.map +1 -1
  62. package/dist/internal/testing/machine/transitionCoverage.d.ts +20 -0
  63. package/dist/internal/testing/machine/transitionCoverage.d.ts.map +1 -0
  64. package/dist/internal/testing/machine/transitionCoverage.js +80 -0
  65. package/dist/internal/testing/machine/transitionCoverage.js.map +1 -0
  66. package/dist/internal/testing/machine/verification.d.ts.map +1 -1
  67. package/dist/internal/testing/machine/verification.js +171 -33
  68. package/dist/internal/testing/machine/verification.js.map +1 -1
  69. package/dist/testing/MachineTest.d.ts +97 -22
  70. package/dist/testing/MachineTest.d.ts.map +1 -1
  71. package/dist/testing/MachineTest.js +58 -16
  72. package/dist/testing/MachineTest.js.map +1 -1
  73. package/dist/unstable/cluster/ClusterMachine.d.ts +4 -1
  74. package/dist/unstable/cluster/ClusterMachine.d.ts.map +1 -1
  75. package/dist/unstable/cluster/ClusterMachine.js +4 -1
  76. package/dist/unstable/cluster/ClusterMachine.js.map +1 -1
  77. package/dist/unstable/reactivity/AtomMachine.d.ts +21 -3
  78. package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
  79. package/dist/unstable/reactivity/AtomMachine.js +21 -3
  80. package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
  81. package/docs/agent-guide.md +240 -65
  82. package/package.json +5 -5
  83. package/src/Machine.ts +1240 -495
  84. package/src/internal/machine/atom.ts +26 -0
  85. package/src/internal/machine/commandRuntime.ts +2 -9
  86. package/src/internal/machine/configuration.ts +28 -3
  87. package/src/internal/machine/executionPlan.ts +72 -24
  88. package/src/internal/machine/initialization.ts +73 -0
  89. package/src/internal/machine/inspectionRuntime.ts +102 -0
  90. package/src/internal/machine/invocation.ts +37 -12
  91. package/src/internal/machine/machine.ts +438 -39
  92. package/src/internal/machine/planner.ts +180 -55
  93. package/src/internal/machine/process.ts +4 -2
  94. package/src/internal/machine/runtime.ts +661 -89
  95. package/src/internal/machine/symbols.ts +3 -0
  96. package/src/internal/machine/topology.ts +65 -12
  97. package/src/internal/testing/machine/exploration.ts +10 -2
  98. package/src/internal/testing/machine/finiteModel.ts +114 -80
  99. package/src/internal/testing/machine/transitionCoverage.ts +116 -0
  100. package/src/internal/testing/machine/verification.ts +216 -58
  101. package/src/testing/MachineTest.ts +118 -28
  102. package/src/unstable/cluster/ClusterMachine.ts +4 -1
  103. package/src/unstable/reactivity/AtomMachine.ts +24 -3
@@ -22,6 +22,7 @@ import {
22
22
  completeConfigurationEffect,
23
23
  completeConfigurationSync,
24
24
  configurationFromHistoryRecord,
25
+ configurationFromInitialTargetSync,
25
26
  getActiveLeafPathFrom,
26
27
  getActiveLeafPaths,
27
28
  getHistoryRecord,
@@ -44,13 +45,16 @@ import {
44
45
  validateInitialConfiguration
45
46
  } from "./configuration.js"
46
47
  import { InfiniteTransitionError, MachineSchemaDecodeError, StartupError, StoppedError } from "./errors.js"
48
+ import { getStateInitializeValues, makeStateInitializeBuilder } from "./initialization.js"
47
49
  import * as InvocationEvent from "./invocationEvent.js"
48
50
  import { decodeEventSync, decodeInputSync, decodeStateValueSync } from "./protocol.js"
49
51
  import { InitialEventTypeId } from "./symbols.js"
50
52
  import {
51
53
  getNode,
54
+ type InitialTarget as InitialTargetInstruction,
52
55
  isChoiceTarget,
53
56
  isHistoryTarget,
57
+ isInitialTarget,
54
58
  isNoTarget,
55
59
  isSnapshot,
56
60
  isTarget,
@@ -66,6 +70,7 @@ export type MicrostepPlan<State, Event, E, R> = {
66
70
  readonly source: string
67
71
  readonly trigger: Machine.TransitionTrigger
68
72
  readonly reenter: boolean
73
+ readonly branchIndex: number
69
74
  readonly target: string | undefined
70
75
  readonly resolvedTarget: string | undefined
71
76
  }>
@@ -100,6 +105,16 @@ export type TransitionHandler<States extends Machine.StateSchemas, E, R, Context
100
105
  enqueue: Enqueue<any, any>
101
106
  ) => Machine.HandlerResult<States, E, R>
102
107
 
108
+ type TransitionEvaluation<States extends Machine.StateSchemas, E, R> = {
109
+ readonly result: Machine.HandlerResult<States, E, R>
110
+ readonly branchIndex: number
111
+ }
112
+
113
+ type TransitionEvaluator<States extends Machine.StateSchemas, E, R, Context> = (
114
+ context: Context,
115
+ enqueue: Enqueue<any, any>
116
+ ) => TransitionEvaluation<States, E, R>
117
+
103
118
  const rootMachineReferences = new WeakMap<Machine.Any, MachineReferences<any, any>>()
104
119
  const scopedMachineReferences = new WeakMap<Machine.Any, MachineReferences<any, any>>()
105
120
 
@@ -138,12 +153,14 @@ type EventTransition<States extends Machine.StateSchemas, E, R, Context> =
138
153
  readonly reenter?: boolean
139
154
  readonly targets?: ReadonlyArray<string>
140
155
  readonly transition: TransitionHandler<States, E, R, Context>
156
+ readonly evaluate?: TransitionEvaluator<States, E, R, Context>
141
157
  }
142
158
 
143
159
  export type MicrostepTransition<States extends Machine.StateSchemas, E, R, Context> = {
144
160
  readonly reenter: boolean
145
161
  readonly targets: ReadonlyArray<string> | undefined
146
162
  readonly transition: TransitionHandler<States, E, R, Context>
163
+ readonly evaluate: TransitionEvaluator<States, E, R, Context> | undefined
147
164
  }
148
165
 
149
166
  export const normalizeTransition = <States extends Machine.StateSchemas, E, R, Context>(
@@ -153,11 +170,12 @@ export const normalizeTransition = <States extends Machine.StateSchemas, E, R, C
153
170
  return undefined
154
171
  }
155
172
  return typeof transition === "function"
156
- ? { reenter: false, targets: undefined, transition }
173
+ ? { reenter: false, targets: undefined, transition, evaluate: undefined }
157
174
  : {
158
175
  reenter: transition.reenter === true,
159
176
  targets: transition.targets,
160
- transition: transition.transition
177
+ transition: transition.transition,
178
+ evaluate: transition.evaluate
161
179
  }
162
180
  }
163
181
 
@@ -191,12 +209,16 @@ const collectTransition = <
191
209
  >(
192
210
  machine: Machine.Any,
193
211
  transition: TransitionHandler<States, E, R, Context>,
194
- context: Context
212
+ context: Context,
213
+ evaluate?: TransitionEvaluator<States, E, R, Context>
195
214
  ) => {
196
215
  const collected = makeCollector<Event>(machine)
197
- const result = transition(context, collected.enqueue)
216
+ const evaluated = evaluate === undefined
217
+ ? { result: transition(context, collected.enqueue), branchIndex: 0 }
218
+ : evaluate(context, collected.enqueue)
198
219
  return {
199
- state: isNoTarget(result) ? undefined : result,
220
+ state: isNoTarget(evaluated.result) ? undefined : evaluated.result,
221
+ branchIndex: evaluated.branchIndex,
200
222
  commands: collected.commands,
201
223
  raisedEvents: collected.raisedEvents,
202
224
  emittedEvents: collected.emittedEvents
@@ -230,6 +252,7 @@ const completeHistoryConfiguration = (
230
252
  const commands: Array<RuntimeCommand> = []
231
253
  const raisedEvents: Array<unknown> = []
232
254
  const emittedEvents: Array<unknown> = []
255
+ const transitions: Array<ResolvedChoiceTransition> = []
233
256
 
234
257
  let changed = true
235
258
  while (changed) {
@@ -248,9 +271,47 @@ const completeHistoryConfiguration = (
248
271
  history: configuration.history,
249
272
  machineReferences: configuration.machineReferences
250
273
  } as ActiveConfiguration
274
+ if (child.type === "choice") {
275
+ const choice = resolveChoiceTarget(
276
+ machine,
277
+ current,
278
+ makeChoiceTarget(child.path, path, Object.fromEntries(values)),
279
+ event
280
+ )
281
+ let next = current
282
+ for (const routed of [choice.target, ...choice.additionalTargets]) {
283
+ if (routed === undefined || isHistoryTarget(routed)) {
284
+ throw new Error(`Machine initial choice "${child.path}" must resolve to an active state target`)
285
+ }
286
+ const resolved = isInitialTarget(routed)
287
+ ? resolveInitialTarget(machine, next, routed, event)
288
+ : undefined
289
+ next = normalizeTargetConfigurationSync(
290
+ machine,
291
+ next,
292
+ (resolved?.target ?? routed) as Machine.Snapshot<any> | Machine.Target<any, any>
293
+ )
294
+ if (resolved !== undefined) {
295
+ commands.push(...resolved.commands)
296
+ raisedEvents.push(...resolved.raisedEvents)
297
+ emittedEvents.push(...resolved.emittedEvents)
298
+ transitions.push(...resolved.transitions)
299
+ }
300
+ }
301
+ active.clear()
302
+ values.clear()
303
+ for (const activePath of next.active) active.add(activePath)
304
+ for (const [valuePath, stateValue] of next.values) values.set(valuePath, stateValue)
305
+ commands.push(...choice.commands)
306
+ raisedEvents.push(...choice.raisedEvents)
307
+ emittedEvents.push(...choice.emittedEvents)
308
+ transitions.push(...choice.transitions)
309
+ changed = true
310
+ continue
311
+ }
251
312
  active.add(child.path)
252
313
  if (child.schema !== undefined) {
253
- const initializer = machine.handlers[path]?.initial
314
+ const initializer = machine.handlers[path]?.initialize
254
315
  if (initializer === undefined) {
255
316
  throw new Error(`Machine shallow history requires an initial value implementation for state "${path}"`)
256
317
  }
@@ -259,9 +320,11 @@ const completeHistoryConfiguration = (
259
320
  state: current.values.get(path),
260
321
  containingState: getParentValue(machine, current, path),
261
322
  ancestors: getParentValues(machine, current, path),
262
- event
323
+ event,
324
+ builder: makeStateInitializeBuilder(machine, path)
263
325
  })
264
- values.set(child.path, decodeStateValueSync(machine, child, initialized.value))
326
+ const initializedValues = getStateInitializeValues(path, initialized.value)
327
+ values.set(child.path, decodeStateValueSync(machine, child, initializedValues[child.key]))
265
328
  commands.push(...initialized.commands)
266
329
  raisedEvents.push(...initialized.raisedEvents)
267
330
  emittedEvents.push(...initialized.emittedEvents)
@@ -279,7 +342,7 @@ const completeHistoryConfiguration = (
279
342
  history: configuration.history,
280
343
  machineReferences: configuration.machineReferences
281
344
  } as ActiveConfiguration
282
- const initializer = valuedMissing.length === 0 ? undefined : machine.handlers[path]?.initial
345
+ const initializer = valuedMissing.length === 0 ? undefined : machine.handlers[path]?.initialize
283
346
  if (valuedMissing.length > 0 && initializer === undefined) {
284
347
  throw new Error(`Machine shallow history requires an initial value implementation for state "${path}"`)
285
348
  }
@@ -288,24 +351,25 @@ const completeHistoryConfiguration = (
288
351
  state: current.values.get(path),
289
352
  containingState: getParentValue(machine, current, path),
290
353
  ancestors: getParentValues(machine, current, path),
291
- event
354
+ event,
355
+ builder: makeStateInitializeBuilder(machine, path)
292
356
  })
293
- if (initialized !== undefined && (typeof initialized.value !== "object" || initialized.value === null)) {
294
- throw new Error(`Machine parallel state initializer for "${path}" must return its region values`)
295
- }
357
+ const initializedValues = initialized === undefined
358
+ ? undefined
359
+ : getStateInitializeValues(path, initialized.value)
296
360
  for (const childPath of missing) {
297
361
  const child = getNode(machine, childPath)
298
362
  active.add(child.path)
299
363
  if (child.schema !== undefined) {
300
364
  if (
301
365
  initialized === undefined ||
302
- !Object.prototype.hasOwnProperty.call(initialized.value as object, child.key)
366
+ initializedValues === undefined || !Object.prototype.hasOwnProperty.call(initializedValues, child.key)
303
367
  ) {
304
368
  throw new Error(`Machine parallel state initializer for "${path}" must return region "${child.key}"`)
305
369
  }
306
370
  values.set(
307
371
  child.path,
308
- decodeStateValueSync(machine, child, (initialized.value as Record<string, unknown>)[child.key])
372
+ decodeStateValueSync(machine, child, initializedValues[child.key])
309
373
  )
310
374
  }
311
375
  }
@@ -328,16 +392,38 @@ const completeHistoryConfiguration = (
328
392
  } as ActiveConfiguration,
329
393
  commands,
330
394
  raisedEvents,
331
- emittedEvents
395
+ emittedEvents,
396
+ transitions
397
+ }
398
+ }
399
+
400
+ export function resolveInitialTarget(
401
+ machine: Machine.Any,
402
+ configuration: ActiveConfiguration,
403
+ target: InitialTargetInstruction,
404
+ event: unknown
405
+ ) {
406
+ const partial = configurationFromInitialTargetSync(machine, configuration, target)
407
+ const completed = completeHistoryConfiguration(machine, partial, event)
408
+ const snapshot = snapshotFromConfigurationAtPath(machine, completed.configuration, target.path)
409
+ return {
410
+ target: makeTarget(target.path as any, snapshot.value as any, {
411
+ snapshot: snapshot as any,
412
+ values: Object.fromEntries(completed.configuration.values) as any
413
+ }),
414
+ commands: completed.commands,
415
+ raisedEvents: completed.raisedEvents,
416
+ emittedEvents: completed.emittedEvents,
417
+ transitions: completed.transitions
332
418
  }
333
419
  }
334
420
 
335
- const resolveHistoryTarget = (
421
+ function resolveHistoryTarget(
336
422
  machine: Machine.Any,
337
423
  configuration: ActiveConfiguration,
338
424
  target: { readonly path: string; readonly parent: string },
339
425
  event: unknown
340
- ) => {
426
+ ) {
341
427
  const node = getNode(machine, target.path)
342
428
  if (node.type !== "history" || node.parent !== target.parent) {
343
429
  throw new Error(`Machine expected history target "${target.path}" to resolve to its declared parent`)
@@ -359,7 +445,7 @@ const resolveHistoryTarget = (
359
445
  commands: completed.commands,
360
446
  raisedEvents: completed.raisedEvents,
361
447
  emittedEvents: completed.emittedEvents,
362
- transitions: []
448
+ transitions: completed.transitions
363
449
  }
364
450
  }
365
451
 
@@ -436,6 +522,7 @@ export type SelectedTransition<States extends Machine.StateSchemas, E, R, Contex
436
522
 
437
523
  export type EvaluatedTransition<States extends Machine.StateSchemas, Event, E, R, Context> = {
438
524
  readonly selection: SelectedTransition<States, E, R, Context>
525
+ readonly branchIndex: number
439
526
  readonly unresolvedTarget:
440
527
  | Machine.Snapshot<States>
441
528
  | Machine.Target<States, Machine.StateIdentifier<States>>
@@ -456,6 +543,7 @@ export type EvaluatedTransition<States extends Machine.StateSchemas, Event, E, R
456
543
  readonly source: string
457
544
  readonly trigger: Machine.TransitionTrigger
458
545
  readonly reenter: false
546
+ readonly branchIndex: number
459
547
  readonly target: string
460
548
  readonly resolvedTarget: string
461
549
  }>
@@ -1061,16 +1149,17 @@ interface ResolvedChoiceTransition {
1061
1149
  readonly source: string
1062
1150
  readonly trigger: Machine.TransitionTrigger
1063
1151
  readonly reenter: false
1152
+ readonly branchIndex: number
1064
1153
  readonly target: string
1065
1154
  readonly resolvedTarget: string
1066
1155
  }
1067
1156
 
1068
- const resolveChoiceTarget = (
1157
+ function resolveChoiceTarget(
1069
1158
  machine: Machine.Any,
1070
1159
  configuration: ActiveConfiguration,
1071
1160
  initialTarget: unknown,
1072
1161
  event: unknown
1073
- ) => {
1162
+ ) {
1074
1163
  const pending: Array<unknown> = [initialTarget]
1075
1164
  const resolvedTargets: Array<unknown> = []
1076
1165
  const commands: Array<RuntimeCommand> = []
@@ -1115,13 +1204,18 @@ const resolveChoiceTarget = (
1115
1204
  history: configuration.history,
1116
1205
  ...(configuration.machineReferences === undefined ? {} : { machineReferences: configuration.machineReferences })
1117
1206
  }
1118
- const collected = collectTransition(machine, choice.transition, {
1119
- ...resolveMachineReferences(machine, provisional),
1120
- containingState: getParentValue(machine, provisional, node.path),
1121
- ancestors: getParentValues(machine, provisional, node.path),
1122
- event,
1123
- target: getTargetBuilder(machine, node.path)
1124
- })
1207
+ const collected = collectTransition(
1208
+ machine,
1209
+ choice.transition,
1210
+ {
1211
+ ...resolveMachineReferences(machine, provisional),
1212
+ containingState: getParentValue(machine, provisional, node.path),
1213
+ ancestors: getParentValues(machine, provisional, node.path),
1214
+ event,
1215
+ target: getTargetBuilder(machine, node.path)
1216
+ },
1217
+ choice.evaluate
1218
+ )
1125
1219
  if (collected.state === undefined) {
1126
1220
  throw new Error(`Machine choice resolver for "${node.path}" must return a target`)
1127
1221
  }
@@ -1133,6 +1227,7 @@ const resolveChoiceTarget = (
1133
1227
  source: node.path,
1134
1228
  trigger: { type: "choice" },
1135
1229
  reenter: false,
1230
+ branchIndex: collected.branchIndex,
1136
1231
  target: returnedPath,
1137
1232
  resolvedTarget: nested?.target.path ?? returnedPath
1138
1233
  })
@@ -1141,7 +1236,7 @@ const resolveChoiceTarget = (
1141
1236
  emittedEvents.push(...collected.emittedEvents)
1142
1237
  }
1143
1238
 
1144
- if (!isTarget(current) && !isSnapshot(current) && !isHistoryTarget(current)) {
1239
+ if (!isTarget(current) && !isSnapshot(current) && !isHistoryTarget(current) && !isInitialTarget(current)) {
1145
1240
  throw new Error("Machine choice resolver must return a concrete typed target")
1146
1241
  }
1147
1242
  resolvedTargets.push(current)
@@ -1172,7 +1267,8 @@ const collectEvaluatedTransition = <
1172
1267
  const transitionResult = collectTransition<States, Event, E, R, Context>(
1173
1268
  machine,
1174
1269
  selection.transition.transition,
1175
- selection.context
1270
+ selection.context,
1271
+ selection.transition.evaluate
1176
1272
  )
1177
1273
  const unresolvedTarget = transitionResult.state === undefined
1178
1274
  ? undefined
@@ -1196,6 +1292,10 @@ const collectEvaluatedTransition = <
1196
1292
  (selection.context as any).event
1197
1293
  )
1198
1294
  const choiceResolvedTarget = choiceResolution?.target ?? unresolvedTarget
1295
+ const initialResolution = choiceResolvedTarget !== undefined && isInitialTarget(choiceResolvedTarget)
1296
+ ? resolveInitialTarget(machine, state, choiceResolvedTarget, (selection.context as any).event)
1297
+ : undefined
1298
+ const routedTarget = initialResolution?.target ?? choiceResolvedTarget
1199
1299
  let historyResolution: {
1200
1300
  readonly target: unknown
1201
1301
  readonly commands: ReadonlyArray<RuntimeCommand>
@@ -1203,50 +1303,64 @@ const collectEvaluatedTransition = <
1203
1303
  readonly emittedEvents: ReadonlyArray<unknown>
1204
1304
  readonly transitions: ReadonlyArray<ResolvedChoiceTransition>
1205
1305
  } | undefined
1206
- const reenteredHistoryTarget = isHistoryTarget(choiceResolvedTarget) && selection.transition.reenter &&
1207
- state.active.has(choiceResolvedTarget.parent)
1208
- ? choiceResolvedTarget
1306
+ const reenteredHistoryTarget = isHistoryTarget(routedTarget) && selection.transition.reenter &&
1307
+ state.active.has(routedTarget.parent)
1308
+ ? routedTarget
1209
1309
  : undefined
1210
- if (choiceResolvedTarget !== undefined && isHistoryTarget(choiceResolvedTarget)) {
1310
+ if (routedTarget !== undefined && isHistoryTarget(routedTarget)) {
1211
1311
  // A reentering transition may exit the history node's own parent. SCXML
1212
1312
  // history observes that same exit, so resolve against a provisional
1213
1313
  // capture rather than an older record (or the default).
1214
1314
  const provisionalBoundary = selection.transition.reenter
1215
1315
  ? getNode(machine, selection.sourcePath).parent
1216
- : getLeastCommonAncestor(machine, stateIdentifier, choiceResolvedTarget.parent)
1316
+ : getLeastCommonAncestor(machine, stateIdentifier, routedTarget.parent)
1217
1317
  const provisionalExitPaths = reenteredHistoryTarget !== undefined
1218
1318
  ? sortExitPaths(
1219
1319
  machine,
1220
- Array.from(state.active).filter((path) => isPathInSubtree(path, choiceResolvedTarget.parent))
1320
+ Array.from(state.active).filter((path) => isPathInSubtree(path, routedTarget.parent))
1221
1321
  )
1222
1322
  : getExitPaths(machine, state, provisionalBoundary)
1223
- const stateAtHistoryResolution = provisionalExitPaths.includes(choiceResolvedTarget.parent)
1323
+ const stateAtHistoryResolution = provisionalExitPaths.includes(routedTarget.parent)
1224
1324
  ? captureHistory(machine, state, state, provisionalExitPaths)
1225
1325
  : state
1226
1326
  historyResolution = resolveHistoryTarget(
1227
1327
  machine,
1228
1328
  stateAtHistoryResolution,
1229
- choiceResolvedTarget,
1329
+ routedTarget,
1230
1330
  (selection.context as any).event
1231
1331
  )
1232
1332
  }
1233
1333
  const target: Machine.Snapshot<States> | Machine.Target<States, Machine.StateIdentifier<States>> | undefined =
1234
1334
  historyResolution === undefined
1235
- ? choiceResolvedTarget as
1335
+ ? routedTarget as
1236
1336
  | Machine.Snapshot<States>
1237
1337
  | Machine.Target<States, Machine.StateIdentifier<States>>
1238
1338
  | undefined
1239
1339
  : historyResolution.target as
1240
1340
  | Machine.Snapshot<States>
1241
1341
  | Machine.Target<States, Machine.StateIdentifier<States>>
1242
- const additionalHistoryActions: Array<RuntimeCommand> = []
1243
- const additionalHistoryRaisedEvents: Array<unknown> = []
1244
- const additionalHistoryEmittedEvents: Array<unknown> = []
1245
- const additionalHistoryChoiceTransitions: Array<ResolvedChoiceTransition> = []
1342
+ const additionalTargetActions: Array<RuntimeCommand> = []
1343
+ const additionalTargetRaisedEvents: Array<unknown> = []
1344
+ const additionalTargetEmittedEvents: Array<unknown> = []
1345
+ const additionalTargetChoiceTransitions: Array<ResolvedChoiceTransition> = []
1246
1346
  const additionalChoiceTargets: Array<
1247
1347
  Machine.Snapshot<States> | Machine.Target<States, Machine.StateIdentifier<States>>
1248
1348
  > = []
1249
1349
  for (const additionalTarget of choiceResolution?.additionalTargets ?? []) {
1350
+ if (isInitialTarget(additionalTarget)) {
1351
+ const resolved = resolveInitialTarget(
1352
+ machine,
1353
+ state,
1354
+ additionalTarget,
1355
+ (selection.context as any).event
1356
+ )
1357
+ additionalChoiceTargets.push(resolved.target as any)
1358
+ additionalTargetActions.push(...resolved.commands)
1359
+ additionalTargetRaisedEvents.push(...resolved.raisedEvents)
1360
+ additionalTargetEmittedEvents.push(...resolved.emittedEvents)
1361
+ additionalTargetChoiceTransitions.push(...resolved.transitions)
1362
+ continue
1363
+ }
1250
1364
  if (!isHistoryTarget(additionalTarget)) {
1251
1365
  additionalChoiceTargets.push(additionalTarget as any)
1252
1366
  continue
@@ -1258,10 +1372,10 @@ const collectEvaluatedTransition = <
1258
1372
  (selection.context as any).event
1259
1373
  )
1260
1374
  additionalChoiceTargets.push(resolved.target as any)
1261
- additionalHistoryActions.push(...resolved.commands)
1262
- additionalHistoryRaisedEvents.push(...resolved.raisedEvents)
1263
- additionalHistoryEmittedEvents.push(...resolved.emittedEvents)
1264
- additionalHistoryChoiceTransitions.push(...resolved.transitions)
1375
+ additionalTargetActions.push(...resolved.commands)
1376
+ additionalTargetRaisedEvents.push(...resolved.raisedEvents)
1377
+ additionalTargetEmittedEvents.push(...resolved.emittedEvents)
1378
+ additionalTargetChoiceTransitions.push(...resolved.transitions)
1265
1379
  }
1266
1380
  const targetPath = target === undefined
1267
1381
  ? undefined
@@ -1283,33 +1397,38 @@ const collectEvaluatedTransition = <
1283
1397
  if (!changed) {
1284
1398
  return {
1285
1399
  selection,
1400
+ branchIndex: transitionResult.branchIndex,
1286
1401
  unresolvedTarget,
1287
1402
  target,
1288
1403
  commands: [
1289
1404
  ...transitionResult.commands,
1290
1405
  ...(choiceResolution?.commands ?? []),
1406
+ ...(initialResolution?.commands ?? []),
1291
1407
  ...(historyResolution?.commands ?? []),
1292
- ...additionalHistoryActions
1408
+ ...additionalTargetActions
1293
1409
  ],
1294
1410
  raisedEvents: [
1295
1411
  ...transitionResult.raisedEvents,
1296
1412
  ...(choiceResolution?.raisedEvents ?? []),
1413
+ ...(initialResolution?.raisedEvents ?? []),
1297
1414
  ...(historyResolution?.raisedEvents ?? []),
1298
- ...additionalHistoryRaisedEvents
1415
+ ...additionalTargetRaisedEvents
1299
1416
  ],
1300
1417
  emittedEvents: [
1301
1418
  ...transitionResult.emittedEvents,
1302
1419
  ...(choiceResolution?.emittedEvents ?? []),
1420
+ ...(initialResolution?.emittedEvents ?? []),
1303
1421
  ...(historyResolution?.emittedEvents ?? []),
1304
- ...additionalHistoryEmittedEvents
1422
+ ...additionalTargetEmittedEvents
1305
1423
  ],
1306
1424
  changed,
1307
1425
  exitPaths: [],
1308
1426
  entryPaths: [],
1309
1427
  choiceTransitions: [
1310
1428
  ...(choiceResolution?.transitions ?? []),
1429
+ ...(initialResolution?.transitions ?? []),
1311
1430
  ...(historyResolution?.transitions ?? []),
1312
- ...additionalHistoryChoiceTransitions
1431
+ ...additionalTargetChoiceTransitions
1313
1432
  ]
1314
1433
  } as EvaluatedTransition<States, Event, E, R, Context>
1315
1434
  }
@@ -1324,25 +1443,29 @@ const collectEvaluatedTransition = <
1324
1443
 
1325
1444
  return {
1326
1445
  selection,
1446
+ branchIndex: transitionResult.branchIndex,
1327
1447
  unresolvedTarget,
1328
1448
  target,
1329
1449
  commands: [
1330
1450
  ...transitionResult.commands,
1331
1451
  ...(choiceResolution?.commands ?? []),
1452
+ ...(initialResolution?.commands ?? []),
1332
1453
  ...(historyResolution?.commands ?? []),
1333
- ...additionalHistoryActions
1454
+ ...additionalTargetActions
1334
1455
  ],
1335
1456
  raisedEvents: [
1336
1457
  ...transitionResult.raisedEvents,
1337
1458
  ...(choiceResolution?.raisedEvents ?? []),
1459
+ ...(initialResolution?.raisedEvents ?? []),
1338
1460
  ...(historyResolution?.raisedEvents ?? []),
1339
- ...additionalHistoryRaisedEvents
1461
+ ...additionalTargetRaisedEvents
1340
1462
  ],
1341
1463
  emittedEvents: [
1342
1464
  ...transitionResult.emittedEvents,
1343
1465
  ...(choiceResolution?.emittedEvents ?? []),
1466
+ ...(initialResolution?.emittedEvents ?? []),
1344
1467
  ...(historyResolution?.emittedEvents ?? []),
1345
- ...additionalHistoryEmittedEvents
1468
+ ...additionalTargetEmittedEvents
1346
1469
  ],
1347
1470
  changed,
1348
1471
  exitPaths: reenteredHistoryTarget !== undefined
@@ -1359,8 +1482,9 @@ const collectEvaluatedTransition = <
1359
1482
  : getEntryPaths(machine, stateAfterTransition, boundary),
1360
1483
  choiceTransitions: [
1361
1484
  ...(choiceResolution?.transitions ?? []),
1485
+ ...(initialResolution?.transitions ?? []),
1362
1486
  ...(historyResolution?.transitions ?? []),
1363
- ...additionalHistoryChoiceTransitions
1487
+ ...additionalTargetChoiceTransitions
1364
1488
  ]
1365
1489
  } as EvaluatedTransition<States, Event, E, R, Context>
1366
1490
  }
@@ -1674,6 +1798,7 @@ const microstep = <
1674
1798
  source: transition.selection.sourcePath,
1675
1799
  trigger: transition.selection.trigger,
1676
1800
  reenter: transition.selection.transition.reenter,
1801
+ branchIndex: transition.branchIndex,
1677
1802
  target: transition.unresolvedTarget === undefined ? undefined : getTargetNodePath(transition.unresolvedTarget),
1678
1803
  resolvedTarget: transition.target === undefined ? undefined : getTargetNodePath(transition.target)
1679
1804
  },
@@ -73,8 +73,7 @@ const acknowledgedPlan = (
73
73
  commands: planned.commands,
74
74
  emittedEvents: planned.emittedEvents,
75
75
  microsteps: planned.microsteps.map((microstep) => {
76
- const { transitions: _, ...evidence } = microstep
77
- return { ...evidence, next: snapshot(microstep.next) }
76
+ return { ...microstep, transitions: microstep.transitions ?? [], next: snapshot(microstep.next) }
78
77
  }),
79
78
  done: planned.done,
80
79
  output: planned.output
@@ -433,6 +432,7 @@ const makeProcessLogic: <
433
432
  ) => {
434
433
  try {
435
434
  const planned = compiledInitial(initialArgs, scope)
435
+ scope.inspectInitial(planned.initialEntryPaths)
436
436
  const result = {
437
437
  state: planned.state as Machine.Snapshot<States>,
438
438
  done: planned.done,
@@ -461,6 +461,7 @@ const makeProcessLogic: <
461
461
  ? internalRuntime.provideMachineRuntime(
462
462
  internalPlanner.planInitial(internalPlanner.withMachineReferences(machine, scope), ...initialArgs).pipe(
463
463
  Effect.flatMap((planned) => {
464
+ scope.inspectInitial(planned.initialEntryPaths, planned.microsteps)
464
465
  const commands = planned.commands.length === 0
465
466
  ? undefined
466
467
  : CommandRuntime.runCommands(planned.commands, scope)
@@ -486,6 +487,7 @@ const makeProcessLogic: <
486
487
  )
487
488
  : Effect.try({ try: () => makeCompiledInitial!(scope), catch: (error) => error as any })
488
489
  return ({
490
+ inspection: { kind: "Machine", definition: machine },
489
491
  execution: {
490
492
  _tag: "Compiled",
491
493
  childless: !hasInvokes,