xstate 6.0.0-beta.1 → 6.0.0-beta.3

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 (87) hide show
  1. package/README.md +4 -2
  2. package/dist/{createActor-cbe3abac.esm.js → createActor-49ea55ba.esm.js} +259 -47
  3. package/dist/{createActor-25900f76.cjs.js → createActor-73aa92ba.cjs.js} +261 -46
  4. package/dist/{createActor-551369be.development.esm.js → createActor-a085b20b.development.esm.js} +260 -48
  5. package/dist/{createActor-a49ae0ce.development.cjs.js → createActor-dfb6b790.development.cjs.js} +262 -47
  6. package/dist/declarations/src/createActor.d.ts +3 -1
  7. package/dist/declarations/src/createMachine.d.ts +6 -3
  8. package/dist/declarations/src/durable/index.d.ts +43 -8
  9. package/dist/declarations/src/effectDescriptor.d.ts +2 -2
  10. package/dist/declarations/src/fsm.d.ts +7 -7
  11. package/dist/declarations/src/machineVersion.types.d.ts +2 -2
  12. package/dist/declarations/src/setup.d.ts +2 -2
  13. package/dist/declarations/src/systemTransition.d.ts +1 -1
  14. package/dist/declarations/src/types.d.ts +4 -2
  15. package/dist/declarations/src/types.v6.d.ts +37 -2
  16. package/dist/{effectDescriptor-2fa27c54.cjs.js → effectDescriptor-3402f63e.cjs.js} +5 -5
  17. package/dist/{effectDescriptor-d8b0f749.esm.js → effectDescriptor-65821048.development.esm.js} +5 -5
  18. package/dist/{effectDescriptor-321a8ce9.development.esm.js → effectDescriptor-72c62058.esm.js} +5 -5
  19. package/dist/{effectDescriptor-f73da4ec.development.cjs.js → effectDescriptor-d0ea44ad.development.cjs.js} +5 -5
  20. package/dist/{machineSchemas-b5736804.development.esm.js → legacySnapshot-11aba2d2.development.esm.js} +117 -3
  21. package/dist/{machineSchemas-6d96bef4.development.cjs.js → legacySnapshot-2e2c1d3b.development.cjs.js} +118 -2
  22. package/dist/{machineSchemas-88d01821.cjs.js → legacySnapshot-a85dfbe2.cjs.js} +117 -1
  23. package/dist/{machineSchemas-45c21bc2.esm.js → legacySnapshot-fffe81a0.esm.js} +116 -2
  24. package/dist/xstate-actors.cjs.js +30 -5
  25. package/dist/xstate-actors.development.cjs.js +30 -5
  26. package/dist/xstate-actors.development.esm.js +31 -6
  27. package/dist/xstate-actors.esm.js +31 -6
  28. package/dist/xstate-actors.umd.min.js +1 -1
  29. package/dist/xstate-actors.umd.min.js.map +1 -1
  30. package/dist/xstate-durable.cjs.js +120 -10
  31. package/dist/xstate-durable.development.cjs.js +120 -10
  32. package/dist/xstate-durable.development.esm.js +120 -10
  33. package/dist/xstate-durable.esm.js +120 -10
  34. package/dist/xstate-durable.umd.min.js +1 -1
  35. package/dist/xstate-durable.umd.min.js.map +1 -1
  36. package/dist/xstate-fsm.cjs.js +61 -31
  37. package/dist/xstate-fsm.development.cjs.js +61 -31
  38. package/dist/xstate-fsm.development.esm.js +61 -31
  39. package/dist/xstate-fsm.esm.js +61 -31
  40. package/dist/xstate-fsm.umd.min.js +1 -1
  41. package/dist/xstate-fsm.umd.min.js.map +1 -1
  42. package/dist/xstate-graph.cjs.js +1 -1
  43. package/dist/xstate-graph.development.cjs.js +1 -1
  44. package/dist/xstate-graph.development.esm.js +2 -2
  45. package/dist/xstate-graph.esm.js +2 -2
  46. package/dist/xstate-graph.umd.min.js +1 -1
  47. package/dist/xstate-graph.umd.min.js.map +1 -1
  48. package/dist/xstate-persist.cjs.js +23 -12
  49. package/dist/xstate-persist.development.cjs.js +23 -12
  50. package/dist/xstate-persist.development.esm.js +17 -6
  51. package/dist/xstate-persist.esm.js +17 -6
  52. package/dist/xstate-persist.umd.min.js +1 -1
  53. package/dist/xstate-persist.umd.min.js.map +1 -1
  54. package/dist/xstate-validation.cjs.js +1 -1
  55. package/dist/xstate-validation.development.cjs.js +1 -1
  56. package/dist/xstate-validation.development.esm.js +1 -1
  57. package/dist/xstate-validation.esm.js +1 -1
  58. package/dist/xstate.cjs.js +86 -56
  59. package/dist/xstate.development.cjs.js +86 -56
  60. package/dist/xstate.development.esm.js +76 -46
  61. package/dist/xstate.esm.js +76 -46
  62. package/dist/xstate.umd.min.js +1 -1
  63. package/dist/xstate.umd.min.js.map +1 -1
  64. package/docs/actor-logic.md +1 -1
  65. package/docs/api-stability.json +335 -305
  66. package/docs/backend-workflows.md +3 -3
  67. package/docs/durable-execution.md +72 -48
  68. package/docs/errors.md +2 -2
  69. package/docs/examples.md +34 -34
  70. package/docs/faq.md +1 -1
  71. package/docs/fsm.md +54 -10
  72. package/docs/guards.md +1 -1
  73. package/docs/index.md +2 -1
  74. package/docs/inspect-actor-systems.md +20 -3
  75. package/docs/inspection.md +5 -1
  76. package/docs/invoke.md +36 -4
  77. package/docs/migrate-inspector.md +141 -0
  78. package/docs/persistence.md +16 -10
  79. package/docs/serialization.md +1 -1
  80. package/docs/setup-and-provide.md +3 -3
  81. package/docs/spawn.md +1 -1
  82. package/docs/system-transitions.md +8 -6
  83. package/docs/transitions.md +5 -1
  84. package/docs/tutorial.md +5 -5
  85. package/docs/typescript.md +9 -0
  86. package/docs/xstate-v5-to-v6.md +23 -21
  87. package/package.json +1 -1
@@ -166,11 +166,11 @@ function isRemoteActorRef(actorRef) {
166
166
  * JSON (`actor.toJSON()`): plain data carrying an address, not an actor.
167
167
  */
168
168
  function isSerializedActorRef(target) {
169
- if (typeof target !== 'object' || target === null || Array.isArray(target) || typeof target.$actor !== 'string') {
169
+ if (typeof target !== 'object' || target === null || Array.isArray(target) || typeof target['@actor'] !== 'string') {
170
170
  return false;
171
171
  }
172
172
  for (const key in target) {
173
- if (key !== '$actor' && key !== 'incarnation') {
173
+ if (key !== '@actor' && key !== 'incarnation') {
174
174
  return false;
175
175
  }
176
176
  }
@@ -186,7 +186,7 @@ function getAddressId(address) {
186
186
 
187
187
  /** @internal The error reported when no live actor has a serialized address. */
188
188
  function createMissingAddressError(target) {
189
- return new Error(xstateError(50, ...(target.incarnation === undefined ? [target.$actor] : [target.$actor, target.incarnation])) );
189
+ return new Error(xstateError(50, ...(target.incarnation === undefined ? [target['@actor']] : [target['@actor'], target.incarnation])) );
190
190
  }
191
191
 
192
192
  /**
@@ -195,7 +195,7 @@ function createMissingAddressError(target) {
195
195
  * without one follows whichever actor is live at the address.
196
196
  */
197
197
  function resolveSerializedActorRef(system, target) {
198
- const live = system._getByAddress?.(target.$actor);
198
+ const live = system._getByAddress?.(target['@actor']);
199
199
  return live && (target.incarnation === undefined || live.sessionId === target.incarnation) ? live : undefined;
200
200
  }
201
201
 
@@ -248,7 +248,7 @@ function createInertActorRef(options) {
248
248
  throw new Error(xstateError(51, id));
249
249
  }
250
250
  return {
251
- $actor: address
251
+ '@actor': address
252
252
  };
253
253
  }
254
254
  };
@@ -334,7 +334,7 @@ function createRemoteActorRef(system, options) {
334
334
  // one actor-reference shape whether a child is co-located or remote.
335
335
  toJSON() {
336
336
  return {
337
- $actor: options.address
337
+ '@actor': options.address
338
338
  };
339
339
  }
340
340
  };
@@ -454,7 +454,7 @@ function deliverEvent(source, target, event) {
454
454
  throw error;
455
455
  }
456
456
  void system.deadLetter(source, undefined, event, 'missingTarget', {
457
- targetId: getAddressId(serialized.$actor),
457
+ targetId: getAddressId(serialized['@actor']),
458
458
  error
459
459
  });
460
460
  return;
@@ -907,6 +907,7 @@ function resolveRegisteredActorSource(actors, logic) {
907
907
  const systemLogicMetadata = Symbol('xstate.systemLogicMetadata');
908
908
 
909
909
  const subscriptions = /* #__PURE__ */new WeakMap();
910
+ const XSTATE_ATTACHED_FORWARD = 'xstate.attached.forward';
910
911
 
911
912
  /**
912
913
  * Internal factory for actor logic that attaches to another actor on start
@@ -969,9 +970,11 @@ id) {
969
970
  unsubscribe: teardown
970
971
  });
971
972
  },
972
- transition: (state, event, {
973
- self
974
- }) => {
973
+ transition: (state, event, scope) => {
974
+ const self = scope.self;
975
+ if (event.type === XSTATE_ATTACHED_FORWARD) {
976
+ return [state, state.status === 'active' && self._parent ? [createSendToEffect(scope, self._parent, event.event)] : []];
977
+ }
975
978
  if (event.type === XSTATE_STOP) {
976
979
  subscriptions.get(self)?.unsubscribe();
977
980
  subscriptions.delete(self);
@@ -986,7 +989,8 @@ id) {
986
989
  initialTransition,
987
990
  getInitialSnapshot: (actorScope, input) => initialTransition(input)[0],
988
991
  getPersistedSnapshot: snapshot => snapshot,
989
- restoreSnapshot: snapshot => snapshot
992
+ restoreSnapshot: snapshot => snapshot,
993
+ isInternalEventType: eventType => eventType === XSTATE_ATTACHED_FORWARD
990
994
  };
991
995
  Object.defineProperty(logic, systemLogicMetadata, {
992
996
  value: {
@@ -1004,7 +1008,10 @@ function relayMappedToParent(self, system, getEvent) {
1004
1008
  if (self.getSnapshot().status === 'stopped' || !self._parent) {
1005
1009
  return;
1006
1010
  }
1007
- system._relay(self, self._parent, getEvent());
1011
+ system._relay(self, self, {
1012
+ type: XSTATE_ATTACHED_FORWARD,
1013
+ event: getEvent()
1014
+ });
1008
1015
  }
1009
1016
 
1010
1017
  /** @public */
@@ -2114,6 +2121,18 @@ function withSystemInspector(inspect, fn) {
2114
2121
 
2115
2122
  /** Snapshot-scoped actor identity and system view. @internal */
2116
2123
 
2124
+ // Each view's execution system and whether it forwards inspection. Views
2125
+ // never chain: they all inherit from the execution system directly.
2126
+ const snapshotSystemViews = new WeakMap();
2127
+ // Facilities owned by the execution rather than by one snapshot's view. A view
2128
+ // reads and writes them on the execution system, so timers, listeners and the
2129
+ // runtime installed through any snapshot are visible through every other.
2130
+ const executionFacilities = ['runtime', '_timerMap', '_rejectionListeners', '_inspectionObservers', '_emissionListeners'];
2131
+ // The durable execution that owns each execution system.
2132
+ /** A durable execution, as the owner of the views its transitions create. @internal */
2133
+
2134
+ const executionOwners = new WeakMap();
2135
+ let ambientExecutionOwner;
2117
2136
  const snapshotActorRefs = new WeakMap();
2118
2137
  const lazySnapshotActorRefs = new WeakMap();
2119
2138
  const emptyKeyedActors = new Map();
@@ -2173,12 +2192,22 @@ function getSnapshotChildren(snapshot) {
2173
2192
  *
2174
2193
  * @internal
2175
2194
  */
2176
- function createSnapshotSystem(baseSystem, children, baseState) {
2177
- const forwardInspection = hasAmbientInspector();
2195
+ function createSnapshotSystem(baseSystem, children, baseState, owner) {
2196
+ const baseView = snapshotSystemViews.get(baseSystem);
2197
+ const baseExecutionSystem = baseView?.executionSystem ?? baseSystem;
2198
+ // The runtime system under every view. A view runs its methods against the
2199
+ // execution system's facilities.
2200
+ const rootSystem = baseView?.rootSystem ?? baseSystem;
2201
+ const forks = owner !== undefined && executionOwners.get(baseExecutionSystem) !== owner;
2202
+ // A view an execution owns reports to that execution's inspector.
2203
+ const forwardInspection = owner ? !!owner.inspect : hasAmbientInspector() && (baseView?.forwardInspection ?? true);
2178
2204
  const registeredActors = copyRegisteredActors(baseSystem, baseState);
2179
2205
  const keyedActors = new Map(baseState?.keyedActors ?? getKeyedActors(baseSystem));
2180
2206
  const reverseKeyedActors = new WeakMap();
2181
- const system = Object.assign(Object.create(baseSystem), {
2207
+ // The view's execution system; adoption can make the view its own.
2208
+ const execution = () => snapshotSystemViews.get(system).executionSystem;
2209
+ const forwards = () => snapshotSystemViews.get(system).forwardInspection;
2210
+ const system = Object.assign(Object.create(baseExecutionSystem), {
2182
2211
  children: registeredActors,
2183
2212
  keyedActors,
2184
2213
  reverseKeyedActors,
@@ -2213,15 +2242,38 @@ function createSnapshotSystem(baseSystem, children, baseState) {
2213
2242
  },
2214
2243
  get: registryKey => keyedActors.get(registryKey),
2215
2244
  getAll: () => Object.fromEntries(keyedActors),
2216
- onEmitted: listener => baseSystem.onEmitted(listener),
2217
- _notifyEmitted: (actorRef, event) => baseSystem._notifyEmitted(actorRef, event),
2245
+ onEmitted: listener => rootSystem.onEmitted.call(execution(), listener),
2246
+ _notifyEmitted: (actorRef, event) => rootSystem._notifyEmitted.call(execution(), actorRef, event),
2218
2247
  // Pure transition resolution must not leak topology inspection events
2219
2248
  // into a live runtime system — planning branches stay silent. The one
2220
2249
  // exception is a durable execution's own transitions (marked by the
2221
2250
  // ambient inspector at creation time): there the pure path IS the
2222
- // execution, so inspection forwards to the base system's observers.
2223
- _hasInspectionObservers: forwardInspection ? () => baseSystem._hasInspectionObservers?.() ?? false : () => false,
2224
- _sendInspectionEvent: forwardInspection ? event => baseSystem._sendInspectionEvent(event) : () => {}
2251
+ // execution, so inspection forwards to the execution system's observers.
2252
+ _hasInspectionObservers: () => forwards() && (rootSystem._hasInspectionObservers?.call(execution()) ?? false),
2253
+ _sendInspectionEvent: event => {
2254
+ if (forwards()) {
2255
+ rootSystem._sendInspectionEvent.call(execution(), event);
2256
+ }
2257
+ }
2258
+ });
2259
+ const executionSystem = forks ? system : baseExecutionSystem;
2260
+ if (forks) {
2261
+ forkFacilities(system, baseExecutionSystem, owner);
2262
+ } else {
2263
+ for (const key of executionFacilities) {
2264
+ Object.defineProperty(system, key, {
2265
+ configurable: true,
2266
+ get: () => execution()[key],
2267
+ set: value => {
2268
+ execution()[key] = value;
2269
+ }
2270
+ });
2271
+ }
2272
+ }
2273
+ snapshotSystemViews.set(system, {
2274
+ executionSystem,
2275
+ rootSystem,
2276
+ forwardInspection
2225
2277
  });
2226
2278
  for (const [registryKey, actor] of keyedActors) {
2227
2279
  if (!actor) {
@@ -2245,6 +2297,83 @@ function createSnapshotSystem(baseSystem, children, baseState) {
2245
2297
  return system;
2246
2298
  }
2247
2299
 
2300
+ /**
2301
+ * Makes `system` the execution system of `owner`, a new incarnation: it gets
2302
+ * the owner's runtime and the pending timers it saw, and starts with no
2303
+ * listeners or inspectors, so nothing registered on another execution
2304
+ * observes it.
2305
+ */
2306
+ function forkFacilities(system, from, owner) {
2307
+ const timers = from._timerMap;
2308
+ for (const key of executionFacilities) {
2309
+ Object.defineProperty(system, key, {
2310
+ configurable: true,
2311
+ writable: true,
2312
+ value: key === 'runtime' ? owner.runtime : key === '_timerMap' && timers ? {
2313
+ ...timers
2314
+ } : undefined
2315
+ });
2316
+ }
2317
+ executionOwners.set(system, owner);
2318
+ if (owner.inspect) {
2319
+ system.inspect(owner.inspect);
2320
+ }
2321
+ }
2322
+
2323
+ /**
2324
+ * Makes `owner` own `system` before it installs its runtime there, and
2325
+ * returns whether it does. An unowned view forks in place, so the install
2326
+ * never reaches the system it was derived from. A system another execution
2327
+ * owns is left alone.
2328
+ *
2329
+ * @internal
2330
+ */
2331
+ function adoptSystem(system, owner) {
2332
+ const view = snapshotSystemViews.get(system);
2333
+ const current = executionOwners.get(view?.executionSystem ?? system);
2334
+ if (current === owner) {
2335
+ if (view) {
2336
+ view.forwardInspection = !!owner.inspect;
2337
+ }
2338
+ return true;
2339
+ }
2340
+ // A system another execution owns stays with it.
2341
+ if (current) {
2342
+ return false;
2343
+ }
2344
+ if (!view) {
2345
+ executionOwners.set(system, owner);
2346
+ return true;
2347
+ }
2348
+ forkFacilities(system, view.executionSystem, owner);
2349
+ view.executionSystem = system;
2350
+ view.forwardInspection = !!owner.inspect;
2351
+ return true;
2352
+ }
2353
+
2354
+ /**
2355
+ * Runs `fn` as a transition of `owner`. A view it derives from a system the
2356
+ * owner does not own forks into the owner's own execution system.
2357
+ *
2358
+ * @internal
2359
+ */
2360
+ function withExecutionOwner(owner, fn) {
2361
+ const previous = ambientExecutionOwner;
2362
+ ambientExecutionOwner = owner;
2363
+ try {
2364
+ return fn();
2365
+ } finally {
2366
+ ambientExecutionOwner = previous;
2367
+ }
2368
+ }
2369
+
2370
+ /** Hands the ambient owner to the first scope that asks for it. @internal */
2371
+ function takeExecutionOwner() {
2372
+ const owner = ambientExecutionOwner;
2373
+ ambientExecutionOwner = undefined;
2374
+ return owner;
2375
+ }
2376
+
2248
2377
  /** Returns the actor identity associated with a transition snapshot. @internal */
2249
2378
  function getSnapshotActorRef(snapshot) {
2250
2379
  const existing = snapshotActorRefs.get(snapshot);
@@ -2438,8 +2567,9 @@ function setInertActorScopeSnapshot(actorScope, snapshot, attachActorRef = true)
2438
2567
  const lazyState = getLazyInertActorState(actorScope);
2439
2568
  if (lazyState) {
2440
2569
  lazyState.snapshot = snapshot;
2441
- if (lazyState.materialized) {
2442
- lazyState.materialized.self._snapshot = snapshot;
2570
+ const scope = lazyState.materialized ?? lazyState.identityScope;
2571
+ if (scope) {
2572
+ scope.self._snapshot = snapshot;
2443
2573
  }
2444
2574
  } else {
2445
2575
  actorScope.self._snapshot = snapshot;
@@ -2474,6 +2604,15 @@ function attachSnapshotActorRef(actorScope, snapshot) {
2474
2604
  setLazySnapshotActorRef(snapshot, create);
2475
2605
  return snapshot;
2476
2606
  }
2607
+ /** Records the materialized scope and releases its consumed source. */
2608
+ function commitMaterialization(state, scope) {
2609
+ // Dropping the consumed source keeps this scope from retaining earlier snapshots.
2610
+ state.sourceRef = undefined;
2611
+ state.sourceChildren = {};
2612
+ state.materialized = scope;
2613
+ state.materialize = () => scope;
2614
+ return scope;
2615
+ }
2477
2616
  const lazyInertActorState = Symbol();
2478
2617
  const snapshotActorScopes = new WeakMap();
2479
2618
  let inertActorMaterializationObserver;
@@ -2518,12 +2657,14 @@ const lazyInertActorScopePrototype = {
2518
2657
  return materializeInertActorScope(this).actionExecutor;
2519
2658
  }
2520
2659
  };
2521
- function createMaterializedInertActorScope(actorLogic, sourceRef, sourceChildren, currentSnapshot, sourceSelf) {
2660
+
2661
+ /** Creates a transactional planning scope backed by an inert actor. */
2662
+ function createMaterializedInertActorScope(actorLogic, sourceRef, sourceChildren, currentSnapshot, sourceSelf, owner) {
2522
2663
  inertActorMaterializationObserver?.();
2523
2664
  const snapshotRef = sourceRef?.();
2524
2665
  const previousSelf = sourceSelf ?? snapshotRef?.actor;
2525
2666
  const baseSystem = previousSelf?.system;
2526
- const system = previousSelf && baseSystem ? createSnapshotSystem(baseSystem, sourceChildren, sourceSelf ? undefined : snapshotRef?.systemState) : undefined;
2667
+ const system = previousSelf && baseSystem ? createSnapshotSystem(baseSystem, sourceChildren, sourceSelf ? undefined : snapshotRef?.systemState, owner) : undefined;
2527
2668
  const self = createActor(actorLogic, {
2528
2669
  _inert: true,
2529
2670
  ...(previousSelf ? {
@@ -2543,12 +2684,8 @@ function createMaterializedInertActorScope(actorLogic, sourceRef, sourceChildren
2543
2684
  // a future construction-time read cannot pin a root-shaped address.
2544
2685
  self._address = undefined;
2545
2686
  }
2546
- if (currentSnapshot) {
2547
- self._snapshot = currentSnapshot;
2548
- }
2549
-
2550
2687
  // Reuse the branch actor's scope while keeping planning transactional.
2551
- return Object.create(self._actorScope, {
2688
+ const scope = Object.create(self._actorScope, {
2552
2689
  defer: {
2553
2690
  value: () => {}
2554
2691
  },
@@ -2557,8 +2694,20 @@ function createMaterializedInertActorScope(actorLogic, sourceRef, sourceChildren
2557
2694
  },
2558
2695
  actionExecutor: {
2559
2696
  value: () => {}
2697
+ },
2698
+ _snapshot: {
2699
+ enumerable: true,
2700
+ configurable: true,
2701
+ get: () => self._snapshot,
2702
+ set: snapshot => {
2703
+ self._snapshot = snapshot;
2704
+ }
2560
2705
  }
2561
2706
  });
2707
+ if (currentSnapshot) {
2708
+ scope._snapshot = currentSnapshot;
2709
+ }
2710
+ return scope;
2562
2711
  }
2563
2712
 
2564
2713
  /** @internal */
@@ -2573,22 +2722,34 @@ function createInertActorScope(actorLogic, snapshot, sourceSelf, sourceActorScop
2573
2722
  sourceChildren: isMachineSnapshot(snapshot) ? snapshot.children : {},
2574
2723
  identityProvider: sourceState?.identityProvider ?? sourceRef,
2575
2724
  parent: sourceSelf?._parent ?? sourceState?.parent ?? eagerSourceRef?.actor._parent,
2725
+ // Only the outermost scope of an owned transition belongs to the owner;
2726
+ // scopes for its intermediate snapshots inherit it, and nested pure
2727
+ // transitions run unowned.
2728
+ owner: sourceActorScope ? sourceState?.owner : takeExecutionOwner(),
2576
2729
  parentKnown: !!sourceSelf || !!sourceState?.parentKnown || !!eagerSourceRef || !snapshot
2577
2730
  };
2578
- state.materialize = () => state.materialized ??= createMaterializedInertActorScope(actorLogic, state.sourceRef, state.sourceChildren, state.snapshot, sourceSelf);
2731
+ state.materialize = () => {
2732
+ const scope = createMaterializedInertActorScope(actorLogic, state.sourceRef, state.sourceChildren, state.snapshot, sourceSelf, state.owner);
2733
+ return commitMaterialization(state, scope);
2734
+ };
2579
2735
  if (!state.identityProvider && !snapshot) {
2580
2736
  const identitySnapshot = {};
2581
- const identitySourceRef = state.sourceRef;
2582
- const identitySourceChildren = state.sourceChildren;
2583
- let identityScope;
2584
2737
  let identityRef;
2585
- const getIdentityScope = () => identityScope ??= createMaterializedInertActorScope(actorLogic, identitySourceRef, identitySourceChildren, undefined, sourceSelf);
2738
+ const getIdentityScope = () => {
2739
+ if (!state.identityScope) {
2740
+ state.identityScope = createMaterializedInertActorScope(actorLogic, state.sourceRef, state.sourceChildren, undefined, sourceSelf, state.owner);
2741
+ if (state.snapshot !== undefined) {
2742
+ state.identityScope.self._snapshot = state.snapshot;
2743
+ }
2744
+ }
2745
+ return state.identityScope;
2746
+ };
2586
2747
  state.materialize = () => {
2587
2748
  const scope = getIdentityScope();
2588
2749
  if (state.snapshot !== undefined) {
2589
2750
  scope.self._snapshot = state.snapshot;
2590
2751
  }
2591
- return state.materialized = scope;
2752
+ return commitMaterialization(state, scope);
2592
2753
  };
2593
2754
  state.identityProvider = () => {
2594
2755
  if (identityRef) {
@@ -3716,7 +3877,7 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3716
3877
  }
3717
3878
  addAncestorStatesToEnter(ancestors, !transition.source.parent && reenter ? undefined : domain);
3718
3879
  }
3719
- if (reenter && domain === transition.source) {
3880
+ if (targets?.length && reenter && domain === transition.source) {
3720
3881
  // A reentering transition whose domain is its own source exits and
3721
3882
  // reenters the source, so the source must be entered explicitly —
3722
3883
  // it has no ancestor inside the domain to add it.
@@ -4265,7 +4426,9 @@ function macrostep(snapshot, event, actorScope, internalQueue, initialMicrosteps
4265
4426
  if (!internalQueue.length && snapshot.machine._hasEventlessTransitions === false) {
4266
4427
  return completeMacrostep();
4267
4428
  }
4268
- let shouldSelectEventlessTransitions = true;
4429
+
4430
+ // A timer notification must not run eventless transitions before delivery.
4431
+ let shouldSelectEventlessTransitions = event.type !== XSTATE_TIMER;
4269
4432
  const maxIterations = snapshot.machine.options?.maxIterations ?? Infinity;
4270
4433
  let iterationCount = 0;
4271
4434
  // The last few state values visited, for the infinite-loop error.
@@ -4561,6 +4724,8 @@ const machineSnapshotToJSON = function toJSON() {
4561
4724
  const {
4562
4725
  nodes,
4563
4726
  _stateInputs,
4727
+ _nextTimerId,
4728
+ _nextActorIds,
4564
4729
  tags,
4565
4730
  machine,
4566
4731
  getMeta,
@@ -4679,6 +4844,8 @@ function getPersistedSnapshot(snapshot, options) {
4679
4844
  const {
4680
4845
  nodes,
4681
4846
  _stateInputs,
4847
+ _nextTimerId,
4848
+ _nextActorIds,
4682
4849
  tags,
4683
4850
  machine,
4684
4851
  children,
@@ -4805,6 +4972,11 @@ function getPersistedSnapshot(snapshot, options) {
4805
4972
  if (_stateInputs && Object.keys(_stateInputs).length > 0) {
4806
4973
  persisted.stateInputs = _stateInputs;
4807
4974
  }
4975
+ // Stores such as Convex reject `_`-prefixed field names.
4976
+ persisted.nextTimerId = _nextTimerId;
4977
+ if (_nextActorIds && Object.keys(_nextActorIds).length > 0) {
4978
+ persisted.nextActorIds = _nextActorIds;
4979
+ }
4808
4980
  if (machine.version !== undefined) {
4809
4981
  persisted.machine = {
4810
4982
  id: machine.id,
@@ -4827,7 +4999,7 @@ function persistContext(contextPart, getActorId, path = 'context', ancestors = [
4827
4999
  };
4828
5000
  // The address lets refs to non-children still route after restore.
4829
5001
  copy[key] = {
4830
- $actor: value.address
5002
+ '@actor': value.address
4831
5003
  };
4832
5004
  } else {
4833
5005
  const valuePath = Array.isArray(contextPart) ? `${path}[${key}]` : `${path}.${key}`;
@@ -5460,11 +5632,18 @@ class RuntimeSystem {
5460
5632
  // Records a send on the *sender's* transition for the `sent[]` inspection
5461
5633
  // facet. Captures the send when it is initiated (including delayed sends that
5462
5634
  // may never deliver), keyed to the source actor's in-flight transition.
5635
+ // A send made with no transition in flight (a callback's `sendBack`, a value
5636
+ // an observable relays to its parent) is not recorded: no transition reports
5637
+ // it, so it would be held until the source's next transition, or for as long
5638
+ // as the source lives if it never makes one.
5463
5639
  _recordSent(source, target, event, delay, id) {
5464
5640
  if (!this._inspectionObservers?.size || !source) {
5465
5641
  return;
5466
5642
  }
5467
5643
  const inspectionSource = source;
5644
+ if (!inspectionSource._inTransition) {
5645
+ return;
5646
+ }
5468
5647
  const collected = inspectionSource._collectedSent ??= [];
5469
5648
  collected.push({
5470
5649
  targetRef: target,
@@ -5701,9 +5880,9 @@ class RuntimeSystem {
5701
5880
  } else if (
5702
5881
  // A live actor of another incarnation is stale locally; an
5703
5882
  // address this system cannot see may belong to a host runtime.
5704
- this._getByAddress(target.$actor) || !this.runtime?.sendEvent) {
5883
+ this._getByAddress(target['@actor']) || !this.runtime?.sendEvent) {
5705
5884
  return this.deadLetter(source, undefined, event, 'missingTarget', {
5706
- targetId: getAddressId(target.$actor),
5885
+ targetId: getAddressId(target['@actor']),
5707
5886
  error: createMissingAddressError(target)
5708
5887
  });
5709
5888
  }
@@ -5987,6 +6166,12 @@ class Actor {
5987
6166
  this._collectedActions = void 0;
5988
6167
  /** @internal Events relayed to other actors during the in-flight transition. */
5989
6168
  this._collectedSent = void 0;
6169
+ /**
6170
+ * @internal Whether a transition is in flight: while the actor starts,
6171
+ * processes an event, or recovers from an execution error. Sends are recorded
6172
+ * for `sent[]` only then.
6173
+ */
6174
+ this._inTransition = false;
5990
6175
  this._initialEffects = void 0;
5991
6176
  this.registryKey = void 0;
5992
6177
  /** The globally unique process ID for this invocation. */
@@ -6059,9 +6244,14 @@ class Actor {
6059
6244
  // transition functions; computing an initial snapshot here would run
6060
6245
  // init-time side effects (context factories, entry) a second time.
6061
6246
  } else {
6062
- const [snapshot, effects] = finalizeTransitionResult(this._actorScope, undefined, this.logic.initialTransition(this.options?.input, this._actorScope));
6063
- this._setSnapshot(snapshot);
6064
- this._initialEffects = effects.length ? effects : undefined;
6247
+ this._inTransition = true;
6248
+ try {
6249
+ const [snapshot, effects] = finalizeTransitionResult(this._actorScope, undefined, this.logic.initialTransition(this.options?.input, this._actorScope));
6250
+ this._setSnapshot(snapshot);
6251
+ this._initialEffects = effects.length ? effects : undefined;
6252
+ } finally {
6253
+ this._inTransition = false;
6254
+ }
6065
6255
  }
6066
6256
  } catch (err) {
6067
6257
  // Restored logic may keep its snapshot shape on restore failures (e.g.
@@ -6214,6 +6404,8 @@ class Actor {
6214
6404
  if (!errorEvent) {
6215
6405
  return false;
6216
6406
  }
6407
+ const inTransition = this._inTransition;
6408
+ this._inTransition = true;
6217
6409
  try {
6218
6410
  const [nextSnapshot, effects] = finalizeTransitionResult(this._actorScope, snapshot, this.logic.transition(snapshot, errorEvent, this._actorScope));
6219
6411
  this._setSnapshot(nextSnapshot);
@@ -6222,6 +6414,8 @@ class Actor {
6222
6414
  return true;
6223
6415
  } catch {
6224
6416
  return false;
6417
+ } finally {
6418
+ this._inTransition = inTransition;
6225
6419
  }
6226
6420
  }
6227
6421
  _next(snapshot) {
@@ -6433,6 +6627,15 @@ class Actor {
6433
6627
 
6434
6628
  /** Starts the Actor from the initial state */
6435
6629
  start() {
6630
+ const inTransition = this._inTransition;
6631
+ this._inTransition = true;
6632
+ try {
6633
+ return this._start();
6634
+ } finally {
6635
+ this._inTransition = inTransition;
6636
+ }
6637
+ }
6638
+ _start() {
6436
6639
  if (this._processingStatus === ProcessingStatus.Running) {
6437
6640
  // Do not restart the service if it is already started
6438
6641
  return this;
@@ -6548,7 +6751,16 @@ class Actor {
6548
6751
  this.mailbox?.start();
6549
6752
  return this;
6550
6753
  }
6551
- _process({
6754
+ _process(item) {
6755
+ const inTransition = this._inTransition;
6756
+ this._inTransition = true;
6757
+ try {
6758
+ this._processEvent(item);
6759
+ } finally {
6760
+ this._inTransition = inTransition;
6761
+ }
6762
+ }
6763
+ _processEvent({
6552
6764
  event,
6553
6765
  sourceRef
6554
6766
  }) {
@@ -6785,12 +6997,12 @@ class Actor {
6785
6997
  }
6786
6998
 
6787
6999
  /**
6788
- * Returns the actor's serializable logical identity: `{ $actor: address }`.
7000
+ * Returns the actor's serializable logical identity: `{ "@actor": address }`.
6789
7001
  * The result can be used as an `enq.sendTo(...)` target.
6790
7002
  */
6791
7003
  toJSON() {
6792
7004
  return {
6793
- $actor: this.address
7005
+ '@actor': this.address
6794
7006
  };
6795
7007
  }
6796
7008
 
@@ -6907,6 +7119,7 @@ exports.NULL_EVENT = NULL_EVENT;
6907
7119
  exports.ProcessingStatus = ProcessingStatus;
6908
7120
  exports.RUNTIME_OPERATIONS = RUNTIME_OPERATIONS;
6909
7121
  exports.STATE_DELIMITER = STATE_DELIMITER;
7122
+ exports.XSTATE_ATTACHED_FORWARD = XSTATE_ATTACHED_FORWARD;
6910
7123
  exports.XSTATE_INIT = XSTATE_INIT;
6911
7124
  exports.XSTATE_LOGIC_EFFECT_REJECT = XSTATE_LOGIC_EFFECT_REJECT;
6912
7125
  exports.XSTATE_LOGIC_EFFECT_RESOLVE = XSTATE_LOGIC_EFFECT_RESOLVE;
@@ -6914,6 +7127,7 @@ exports.XSTATE_LOGIC_EFFECT_START = XSTATE_LOGIC_EFFECT_START;
6914
7127
  exports.XSTATE_STOP = XSTATE_STOP;
6915
7128
  exports.XSTATE_STOP_EFFECT = XSTATE_STOP_EFFECT;
6916
7129
  exports.XSTATE_TIMER = XSTATE_TIMER;
7130
+ exports.adoptSystem = adoptSystem;
6917
7131
  exports.allocateChildId = allocateChildId;
6918
7132
  exports.assertChildIdFree = assertChildIdFree;
6919
7133
  exports.assertUnreservedSourceName = assertUnreservedSourceName;
@@ -7011,5 +7225,6 @@ exports.toTransitionConfigArray = toTransitionConfigArray;
7011
7225
  exports.transitionNode = transitionNode;
7012
7226
  exports.withActorSelf = withActorSelf;
7013
7227
  exports.withExecutionIdentity = withExecutionIdentity;
7228
+ exports.withExecutionOwner = withExecutionOwner;
7014
7229
  exports.withSystemInspector = withSystemInspector;
7015
7230
  exports.xstateError = xstateError;