xstate 6.0.0-alpha.40 → 6.0.0-alpha.43

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 (65) hide show
  1. package/dist/{StateMachine-76ee1d6e.development.cjs.js → StateMachine-16d7ee93.development.cjs.js} +85 -7
  2. package/dist/{StateMachine-f8c7feca.development.esm.js → StateMachine-1ea29688.development.esm.js} +85 -7
  3. package/dist/{StateMachine-6082c3cf.esm.js → StateMachine-b13b4b09.esm.js} +85 -7
  4. package/dist/{StateMachine-1464d5e4.cjs.js → StateMachine-fcc48e11.cjs.js} +85 -7
  5. package/dist/{createActor-c0f78b8a.development.cjs.js → createActor-1a3a1d14.development.cjs.js} +827 -63
  6. package/dist/{createActor-d5305cc9.cjs.js → createActor-9538c7f8.cjs.js} +817 -56
  7. package/dist/{createActor-a211c276.esm.js → createActor-973c72ad.esm.js} +795 -56
  8. package/dist/{createActor-2a03d4b2.development.esm.js → createActor-f9cc6590.development.esm.js} +805 -63
  9. package/dist/declarations/src/StateMachine.d.ts +3 -3
  10. package/dist/declarations/src/actors/logic.d.ts +0 -3
  11. package/dist/declarations/src/createActor.d.ts +41 -6
  12. package/dist/declarations/src/createMachine.d.ts +7 -7
  13. package/dist/declarations/src/durable/index.d.ts +85 -8
  14. package/dist/declarations/src/effectDescriptor.d.ts +81 -0
  15. package/dist/declarations/src/fsm.d.ts +1 -0
  16. package/dist/declarations/src/index.d.ts +3 -1
  17. package/dist/declarations/src/inspection.d.ts +11 -1
  18. package/dist/declarations/src/machineVersion.types.d.ts +1 -0
  19. package/dist/declarations/src/runtimeHelpers.d.ts +40 -0
  20. package/dist/declarations/src/setup.d.ts +16 -11
  21. package/dist/declarations/src/system.d.ts +63 -2
  22. package/dist/declarations/src/transitionActions.d.ts +1 -1
  23. package/dist/declarations/src/types.d.ts +27 -8
  24. package/dist/declarations/src/types.v6.d.ts +13 -8
  25. package/dist/{transition-e8a13c00.esm.js → effectDescriptor-416ca00a.esm.js} +110 -2
  26. package/dist/{transition-4ba58b71.development.cjs.js → effectDescriptor-7d6f945a.development.cjs.js} +110 -1
  27. package/dist/{transition-f581ffa6.development.esm.js → effectDescriptor-e6730c9a.development.esm.js} +110 -2
  28. package/dist/{transition-2dcabac8.cjs.js → effectDescriptor-f8c9337f.cjs.js} +110 -1
  29. package/dist/{index-7020402e.esm.js → index-b478f443.esm.js} +12 -51
  30. package/dist/{index-21d08fff.cjs.js → index-ba7170ba.cjs.js} +15 -54
  31. package/dist/{index-3d1368f7.development.cjs.js → index-e0ba4813.development.cjs.js} +15 -54
  32. package/dist/{index-17f889df.development.esm.js → index-f284cc7b.development.esm.js} +12 -51
  33. package/dist/xstate-actors.cjs.js +2 -2
  34. package/dist/xstate-actors.development.cjs.js +2 -2
  35. package/dist/xstate-actors.development.esm.js +2 -2
  36. package/dist/xstate-actors.esm.js +2 -2
  37. package/dist/xstate-actors.umd.min.js +1 -1
  38. package/dist/xstate-actors.umd.min.js.map +1 -1
  39. package/dist/xstate-durable.cjs.js +255 -24
  40. package/dist/xstate-durable.development.cjs.js +255 -24
  41. package/dist/xstate-durable.development.esm.js +255 -24
  42. package/dist/xstate-durable.esm.js +255 -24
  43. package/dist/xstate-durable.umd.min.js +1 -1
  44. package/dist/xstate-durable.umd.min.js.map +1 -1
  45. package/dist/xstate-graph.cjs.js +3 -3
  46. package/dist/xstate-graph.development.cjs.js +3 -3
  47. package/dist/xstate-graph.development.esm.js +3 -3
  48. package/dist/xstate-graph.esm.js +3 -3
  49. package/dist/xstate-graph.umd.min.js +1 -1
  50. package/dist/xstate-graph.umd.min.js.map +1 -1
  51. package/dist/xstate-validation.cjs.js +20 -2
  52. package/dist/xstate-validation.development.cjs.js +20 -2
  53. package/dist/xstate-validation.development.esm.js +20 -2
  54. package/dist/xstate-validation.esm.js +20 -2
  55. package/dist/xstate-validation.umd.min.js +1 -1
  56. package/dist/xstate-validation.umd.min.js.map +1 -1
  57. package/dist/xstate.cjs.js +21 -9
  58. package/dist/xstate.cjs.mjs +5 -0
  59. package/dist/xstate.development.cjs.js +21 -9
  60. package/dist/xstate.development.cjs.mjs +5 -0
  61. package/dist/xstate.development.esm.js +13 -6
  62. package/dist/xstate.esm.js +13 -6
  63. package/dist/xstate.umd.min.js +1 -1
  64. package/dist/xstate.umd.min.js.map +1 -1
  65. package/package.json +1 -1
@@ -1,13 +1,21 @@
1
1
  'use strict';
2
2
 
3
- var createActor = require('./createActor-c0f78b8a.development.cjs.js');
4
- var dist_xstateActors = require('./index-3d1368f7.development.cjs.js');
3
+ var createActor = require('./createActor-1a3a1d14.development.cjs.js');
4
+ var dist_xstateActors = require('./index-e0ba4813.development.cjs.js');
5
5
 
6
6
  function createSpawner(actorScope, actors, spawnedChildren) {
7
7
  return (src, options) => {
8
8
  const referencedSrc = Object.entries(actors).find(([, logic]) => logic === src)?.[0];
9
+ // Generated ids come from the same transaction allocator as `enq.spawn`,
10
+ // so context-factory allocations persist with the snapshot and never
11
+ // collide with later spawns.
12
+ const id = options?.id ?? createActor.allocateChildId(actorScope, referencedSrc ?? src).id;
13
+ if (options?.id !== undefined) {
14
+ createActor.assertChildIdFree(actorScope, options.id);
15
+ createActor.reserveChildId(actorScope, options.id);
16
+ }
9
17
  const actor = actorScope.system.createActorRef(src, {
10
- id: options?.id,
18
+ id,
11
19
  parent: actorScope.self,
12
20
  syncSnapshot: options?.syncSnapshot,
13
21
  input: options?.input,
@@ -410,6 +418,16 @@ function formatInitialTransition(stateNode, _target) {
410
418
  }
411
419
 
412
420
  const STATE_IDENTIFIER = '#';
421
+ function findEventSchema(schemas, eventType) {
422
+ if (!schemas) {
423
+ return undefined;
424
+ }
425
+ if (Object.hasOwn(schemas, eventType)) {
426
+ return schemas[eventType];
427
+ }
428
+ const descriptor = Object.keys(schemas).find(key => createActor.matchesEventDescriptor(eventType, key));
429
+ return descriptor === undefined ? undefined : schemas[descriptor];
430
+ }
413
431
  let emptyCanActor;
414
432
  let emptyCanActorScope;
415
433
  function getEmptyCanActor() {
@@ -454,6 +472,12 @@ class StateMachine {
454
472
  config, sources, validator) {
455
473
  this.config = config;
456
474
  this.validator = validator;
475
+ /**
476
+ * @internal Type-only marker for the actor's internal event protocol. Not
477
+ * `declare` (the build's babel pipeline rejects declare class fields); the
478
+ * one `undefined` property this emits per machine instance is inert.
479
+ */
480
+ this._internalEventType = void 0;
457
481
  /** The machine's own version. */
458
482
  this.version = void 0;
459
483
  this.schemas = void 0;
@@ -592,9 +616,10 @@ class StateMachine {
592
616
  }
593
617
  const event = value;
594
618
  const eventSchemas = this.schemas?.events;
619
+ const internalEventSchemas = this.schemas?.internalEvents;
595
620
  const isFrameworkEvent = event.type.startsWith('xstate.') || event.type.startsWith('@xstate.');
596
- const schema = eventSchemas && Object.hasOwn(eventSchemas, event.type) ? eventSchemas[event.type] : undefined;
597
- if (eventSchemas && !schema && !isFrameworkEvent) {
621
+ const schema = findEventSchema(internalEventSchemas, event.type) ?? findEventSchema(eventSchemas, event.type);
622
+ if ((eventSchemas || internalEventSchemas) && !schema && !isFrameworkEvent) {
598
623
  return {
599
624
  issues: [{
600
625
  message: `Unknown event '${event.type}' for machine '${this.id}' version '${this.version}'.`
@@ -630,7 +655,7 @@ class StateMachine {
630
655
  }
631
656
  }
632
657
  };
633
- this.internalEventDescriptors = this.config.internalEvents ?? [];
658
+ this.internalEventDescriptors = [...Object.keys(this.schemas?.internalEvents ?? {}), ...(this.config.internalEvents ?? [])];
634
659
  this.options = {
635
660
  maxIterations: Infinity,
636
661
  ...this.config.options
@@ -726,6 +751,7 @@ class StateMachine {
726
751
  if (usesInertScope) {
727
752
  createActor.setInertActorScopeSnapshot(resolvedActorScope, snapshot, false);
728
753
  }
754
+ createActor.beginSpawnAllocation(resolvedActorScope);
729
755
  const fastSnapshot = this._transitionFast(snapshot, event, resolvedActorScope);
730
756
  if (fastSnapshot) {
731
757
  if (usesInertScope) {
@@ -921,6 +947,14 @@ class StateMachine {
921
947
  ...nextState.children,
922
948
  ...children
923
949
  };
950
+ // Commit the transaction counters so context-factory allocations
951
+ // persist with the snapshot: a freed id is never handed out again
952
+ // after a restore or in a fresh replay process. (The spawner already
953
+ // registered each child for string-id resolution.)
954
+ const counters = createActor.takeSpawnAllocationCounters(actorScope);
955
+ if (counters) {
956
+ nextState._nextActorIds = createActor.mergeActorIdCounters(nextState._nextActorIds, counters);
957
+ }
924
958
  }
925
959
  return nextState;
926
960
  }
@@ -944,6 +978,7 @@ class StateMachine {
944
978
  }
945
979
  const usesInertScope = !actorScope;
946
980
  const resolvedActorScope = actorScope ?? createActor.createInertActorScope(this);
981
+ createActor.beginSpawnAllocation(resolvedActorScope);
947
982
  const initEvent = createActor.createInitEvent(input); // TODO: fix;
948
983
  const internalQueue = [];
949
984
  const preInitialState = this._getPreInitialState(resolvedActorScope, initEvent);
@@ -1035,6 +1070,31 @@ class StateMachine {
1035
1070
  const snapshotChildren = snapshotData.children;
1036
1071
  for (const actorId of Object.keys(snapshotChildren)) {
1037
1072
  const actorData = snapshotChildren[actorId];
1073
+ if (actorData.remote === true && actorData.address !== undefined) {
1074
+ if (typeof actorData.src !== 'string') {
1075
+ // Fail loudly instead of fabricating a source key that hosts would
1076
+ // route by.
1077
+ throw new Error(`Unable to restore remote child '${actorId}': a child referenced by address requires a registered source key.`);
1078
+ }
1079
+ // The child's state lives with another runtime; restore a
1080
+ // location-transparent handle constructed from its identity alone.
1081
+ // The handle keeps its persisted address verbatim: the owning
1082
+ // runtime's identity for the child wins over the local parent chain.
1083
+ const handle = createActor.createRemoteActorRef(resolvedActorScope.system, {
1084
+ id: actorId,
1085
+ address: actorData.address,
1086
+ src: actorData.src,
1087
+ parent: resolvedActorScope.self,
1088
+ registryKey: actorData.registryKey,
1089
+ syncSnapshot: actorData.syncSnapshot,
1090
+ incarnation: actorData.incarnation
1091
+ });
1092
+ if (actorData.registryKey) {
1093
+ resolvedActorScope.system._set(actorData.registryKey, handle);
1094
+ }
1095
+ children[actorId] = handle;
1096
+ continue;
1097
+ }
1038
1098
  const childState = actorData.snapshot;
1039
1099
  const src = actorData.src;
1040
1100
  const logic = typeof src === 'string' ? createActor.resolveReferencedActor(this, src) : src;
@@ -1130,12 +1190,30 @@ class StateMachine {
1130
1190
  const nodes = Array.from(createActor.getAllStateNodes(createActor.getStateNodes(this.root, snapshotData.value)));
1131
1191
  const {
1132
1192
  version: _persistedSnapshotVersion,
1193
+ // The legacy system-wide counter: superseded by per-snapshot
1194
+ // `_nextActorIds` plus the child-id fold below; dropped so old and new
1195
+ // snapshots round-trip to the same shape.
1196
+ _nextActorId: _legacyNextActorId,
1133
1197
  ...persistedRest
1134
1198
  } = snapshot;
1199
+ // Fold generated-shaped child ids into the counters as a floor: snapshots
1200
+ // persisted before per-actor counters (or hand-crafted ones) still must
1201
+ // never reuse a live child's id.
1202
+ let restoredCounters = persistedRest._nextActorIds;
1203
+ for (const childId of Object.keys(snapshotChildren)) {
1204
+ const generated = createActor.parseGeneratedActorId(childId);
1205
+ if (generated && (restoredCounters?.[generated.prefix] ?? 0) <= generated.index) {
1206
+ restoredCounters = {
1207
+ ...restoredCounters,
1208
+ [generated.prefix]: generated.index + 1
1209
+ };
1210
+ }
1211
+ }
1135
1212
  const restoredSnapshot = createActor.createMachineSnapshot({
1136
1213
  ...persistedRest,
1137
1214
  children,
1138
1215
  timers,
1216
+ _nextActorIds: restoredCounters,
1139
1217
  _nodes: nodes,
1140
1218
  value: snapshotData.value,
1141
1219
  historyValue: revivedHistoryValue,
@@ -1150,7 +1228,7 @@ class StateMachine {
1150
1228
  for (const key of Object.keys(contextPart)) {
1151
1229
  const value = contextPart[key];
1152
1230
  if (value && typeof value === 'object') {
1153
- if ('xstate$$type' in value && value.xstate$$type === createActor.$$ACTOR_TYPE) {
1231
+ if ('xstate$type' in value && value.xstate$type === createActor.ACTOR_REF_TYPE) {
1154
1232
  contextPart[key] = children[value.id];
1155
1233
  continue;
1156
1234
  }
@@ -1,11 +1,19 @@
1
- import { S as STATE_DELIMITER, I as mapValues, t as toArray, J as createInvokeId, K as getDelayedTransitions, L as getEventDescriptorKey, M as getCandidates, N as evaluateCandidate, O as formatTransition, P as NULL_EVENT, Q as toTransitionConfigArray, R as createInvokeTimeoutEventId, T as matchesActorSession, U as formatRouteTransitions, V as resolveStateValue, W as getAllStateNodes, v as getStateNodes, Y as createMachineSnapshot, Z as isInFinalState, _ as createInertActorScope, $ as setInertActorScopeSnapshot, a0 as attachSnapshotActorRef, a1 as macrostep, a2 as isInertActorScope, a3 as setSnapshotActorRef, a4 as cloneMachineSnapshot, a5 as transitionNode, e as XSTATE_TIMER, m as matchesEventDescriptor, a6 as getTransitionResult, a7 as hasEffect, a8 as createErrorPlatformEvent, a9 as withActorSelf, r as resolveActionsWithContext, F as createInitEvent, aa as createSpawnEffect, ab as initialMicrostep, ac as toStatePath, ad as isStateId, ae as getStateNodeByPath, af as getPersistedSnapshot, ag as resolveReferencedActor, ah as createInvokeTimeoutEvent, ai as $$ACTOR_TYPE, j as createActor } from './createActor-2a03d4b2.development.esm.js';
2
- import { g as assertValid } from './index-17f889df.development.esm.js';
1
+ import { Q as allocateChildId, R as assertChildIdFree, S as reserveChildId, T as STATE_DELIMITER, U as mapValues, t as toArray, V as createInvokeId, W as getDelayedTransitions, Y as getEventDescriptorKey, Z as getCandidates, _ as evaluateCandidate, $ as formatTransition, a0 as NULL_EVENT, a1 as toTransitionConfigArray, a2 as createInvokeTimeoutEventId, a3 as matchesActorSession, a4 as formatRouteTransitions, a5 as resolveStateValue, a6 as getAllStateNodes, x as getStateNodes, a7 as createMachineSnapshot, a8 as isInFinalState, a9 as createInertActorScope, aa as setInertActorScopeSnapshot, a as beginSpawnAllocation, ab as attachSnapshotActorRef, ac as macrostep, ad as isInertActorScope, ae as setSnapshotActorRef, af as cloneMachineSnapshot, ag as transitionNode, g as XSTATE_TIMER, m as matchesEventDescriptor, ah as getTransitionResult, ai as hasEffect, aj as createErrorPlatformEvent, ak as withActorSelf, r as resolveActionsWithContext, al as takeSpawnAllocationCounters, am as mergeActorIdCounters, K as createInitEvent, an as createSpawnEffect, ao as initialMicrostep, ap as toStatePath, aq as isStateId, ar as getStateNodeByPath, as as getPersistedSnapshot, at as createRemoteActorRef, au as resolveReferencedActor, av as createInvokeTimeoutEvent, aw as parseGeneratedActorId, ax as ACTOR_REF_TYPE, k as createActor } from './createActor-f9cc6590.development.esm.js';
2
+ import { g as assertValid } from './index-f284cc7b.development.esm.js';
3
3
 
4
4
  function createSpawner(actorScope, actors, spawnedChildren) {
5
5
  return (src, options) => {
6
6
  const referencedSrc = Object.entries(actors).find(([, logic]) => logic === src)?.[0];
7
+ // Generated ids come from the same transaction allocator as `enq.spawn`,
8
+ // so context-factory allocations persist with the snapshot and never
9
+ // collide with later spawns.
10
+ const id = options?.id ?? allocateChildId(actorScope, referencedSrc ?? src).id;
11
+ if (options?.id !== undefined) {
12
+ assertChildIdFree(actorScope, options.id);
13
+ reserveChildId(actorScope, options.id);
14
+ }
7
15
  const actor = actorScope.system.createActorRef(src, {
8
- id: options?.id,
16
+ id,
9
17
  parent: actorScope.self,
10
18
  syncSnapshot: options?.syncSnapshot,
11
19
  input: options?.input,
@@ -408,6 +416,16 @@ function formatInitialTransition(stateNode, _target) {
408
416
  }
409
417
 
410
418
  const STATE_IDENTIFIER = '#';
419
+ function findEventSchema(schemas, eventType) {
420
+ if (!schemas) {
421
+ return undefined;
422
+ }
423
+ if (Object.hasOwn(schemas, eventType)) {
424
+ return schemas[eventType];
425
+ }
426
+ const descriptor = Object.keys(schemas).find(key => matchesEventDescriptor(eventType, key));
427
+ return descriptor === undefined ? undefined : schemas[descriptor];
428
+ }
411
429
  let emptyCanActor;
412
430
  let emptyCanActorScope;
413
431
  function getEmptyCanActor() {
@@ -452,6 +470,12 @@ class StateMachine {
452
470
  config, sources, validator) {
453
471
  this.config = config;
454
472
  this.validator = validator;
473
+ /**
474
+ * @internal Type-only marker for the actor's internal event protocol. Not
475
+ * `declare` (the build's babel pipeline rejects declare class fields); the
476
+ * one `undefined` property this emits per machine instance is inert.
477
+ */
478
+ this._internalEventType = void 0;
455
479
  /** The machine's own version. */
456
480
  this.version = void 0;
457
481
  this.schemas = void 0;
@@ -590,9 +614,10 @@ class StateMachine {
590
614
  }
591
615
  const event = value;
592
616
  const eventSchemas = this.schemas?.events;
617
+ const internalEventSchemas = this.schemas?.internalEvents;
593
618
  const isFrameworkEvent = event.type.startsWith('xstate.') || event.type.startsWith('@xstate.');
594
- const schema = eventSchemas && Object.hasOwn(eventSchemas, event.type) ? eventSchemas[event.type] : undefined;
595
- if (eventSchemas && !schema && !isFrameworkEvent) {
619
+ const schema = findEventSchema(internalEventSchemas, event.type) ?? findEventSchema(eventSchemas, event.type);
620
+ if ((eventSchemas || internalEventSchemas) && !schema && !isFrameworkEvent) {
596
621
  return {
597
622
  issues: [{
598
623
  message: `Unknown event '${event.type}' for machine '${this.id}' version '${this.version}'.`
@@ -628,7 +653,7 @@ class StateMachine {
628
653
  }
629
654
  }
630
655
  };
631
- this.internalEventDescriptors = this.config.internalEvents ?? [];
656
+ this.internalEventDescriptors = [...Object.keys(this.schemas?.internalEvents ?? {}), ...(this.config.internalEvents ?? [])];
632
657
  this.options = {
633
658
  maxIterations: Infinity,
634
659
  ...this.config.options
@@ -724,6 +749,7 @@ class StateMachine {
724
749
  if (usesInertScope) {
725
750
  setInertActorScopeSnapshot(resolvedActorScope, snapshot, false);
726
751
  }
752
+ beginSpawnAllocation(resolvedActorScope);
727
753
  const fastSnapshot = this._transitionFast(snapshot, event, resolvedActorScope);
728
754
  if (fastSnapshot) {
729
755
  if (usesInertScope) {
@@ -919,6 +945,14 @@ class StateMachine {
919
945
  ...nextState.children,
920
946
  ...children
921
947
  };
948
+ // Commit the transaction counters so context-factory allocations
949
+ // persist with the snapshot: a freed id is never handed out again
950
+ // after a restore or in a fresh replay process. (The spawner already
951
+ // registered each child for string-id resolution.)
952
+ const counters = takeSpawnAllocationCounters(actorScope);
953
+ if (counters) {
954
+ nextState._nextActorIds = mergeActorIdCounters(nextState._nextActorIds, counters);
955
+ }
922
956
  }
923
957
  return nextState;
924
958
  }
@@ -942,6 +976,7 @@ class StateMachine {
942
976
  }
943
977
  const usesInertScope = !actorScope;
944
978
  const resolvedActorScope = actorScope ?? createInertActorScope(this);
979
+ beginSpawnAllocation(resolvedActorScope);
945
980
  const initEvent = createInitEvent(input); // TODO: fix;
946
981
  const internalQueue = [];
947
982
  const preInitialState = this._getPreInitialState(resolvedActorScope, initEvent);
@@ -1033,6 +1068,31 @@ class StateMachine {
1033
1068
  const snapshotChildren = snapshotData.children;
1034
1069
  for (const actorId of Object.keys(snapshotChildren)) {
1035
1070
  const actorData = snapshotChildren[actorId];
1071
+ if (actorData.remote === true && actorData.address !== undefined) {
1072
+ if (typeof actorData.src !== 'string') {
1073
+ // Fail loudly instead of fabricating a source key that hosts would
1074
+ // route by.
1075
+ throw new Error(`Unable to restore remote child '${actorId}': a child referenced by address requires a registered source key.`);
1076
+ }
1077
+ // The child's state lives with another runtime; restore a
1078
+ // location-transparent handle constructed from its identity alone.
1079
+ // The handle keeps its persisted address verbatim: the owning
1080
+ // runtime's identity for the child wins over the local parent chain.
1081
+ const handle = createRemoteActorRef(resolvedActorScope.system, {
1082
+ id: actorId,
1083
+ address: actorData.address,
1084
+ src: actorData.src,
1085
+ parent: resolvedActorScope.self,
1086
+ registryKey: actorData.registryKey,
1087
+ syncSnapshot: actorData.syncSnapshot,
1088
+ incarnation: actorData.incarnation
1089
+ });
1090
+ if (actorData.registryKey) {
1091
+ resolvedActorScope.system._set(actorData.registryKey, handle);
1092
+ }
1093
+ children[actorId] = handle;
1094
+ continue;
1095
+ }
1036
1096
  const childState = actorData.snapshot;
1037
1097
  const src = actorData.src;
1038
1098
  const logic = typeof src === 'string' ? resolveReferencedActor(this, src) : src;
@@ -1128,12 +1188,30 @@ class StateMachine {
1128
1188
  const nodes = Array.from(getAllStateNodes(getStateNodes(this.root, snapshotData.value)));
1129
1189
  const {
1130
1190
  version: _persistedSnapshotVersion,
1191
+ // The legacy system-wide counter: superseded by per-snapshot
1192
+ // `_nextActorIds` plus the child-id fold below; dropped so old and new
1193
+ // snapshots round-trip to the same shape.
1194
+ _nextActorId: _legacyNextActorId,
1131
1195
  ...persistedRest
1132
1196
  } = snapshot;
1197
+ // Fold generated-shaped child ids into the counters as a floor: snapshots
1198
+ // persisted before per-actor counters (or hand-crafted ones) still must
1199
+ // never reuse a live child's id.
1200
+ let restoredCounters = persistedRest._nextActorIds;
1201
+ for (const childId of Object.keys(snapshotChildren)) {
1202
+ const generated = parseGeneratedActorId(childId);
1203
+ if (generated && (restoredCounters?.[generated.prefix] ?? 0) <= generated.index) {
1204
+ restoredCounters = {
1205
+ ...restoredCounters,
1206
+ [generated.prefix]: generated.index + 1
1207
+ };
1208
+ }
1209
+ }
1133
1210
  const restoredSnapshot = createMachineSnapshot({
1134
1211
  ...persistedRest,
1135
1212
  children,
1136
1213
  timers,
1214
+ _nextActorIds: restoredCounters,
1137
1215
  _nodes: nodes,
1138
1216
  value: snapshotData.value,
1139
1217
  historyValue: revivedHistoryValue,
@@ -1148,7 +1226,7 @@ class StateMachine {
1148
1226
  for (const key of Object.keys(contextPart)) {
1149
1227
  const value = contextPart[key];
1150
1228
  if (value && typeof value === 'object') {
1151
- if ('xstate$$type' in value && value.xstate$$type === $$ACTOR_TYPE) {
1229
+ if ('xstate$type' in value && value.xstate$type === ACTOR_REF_TYPE) {
1152
1230
  contextPart[key] = children[value.id];
1153
1231
  continue;
1154
1232
  }
@@ -1,11 +1,19 @@
1
- import { S as STATE_DELIMITER, I as mapValues, t as toArray, J as createInvokeId, K as getDelayedTransitions, L as getEventDescriptorKey, M as getCandidates, N as evaluateCandidate, O as formatTransition, P as NULL_EVENT, Q as toTransitionConfigArray, R as createInvokeTimeoutEventId, T as matchesActorSession, U as formatRouteTransitions, V as resolveStateValue, W as getAllStateNodes, v as getStateNodes, Y as createMachineSnapshot, Z as isInFinalState, _ as createInertActorScope, $ as setInertActorScopeSnapshot, a0 as attachSnapshotActorRef, a1 as macrostep, a2 as isInertActorScope, a3 as setSnapshotActorRef, a4 as cloneMachineSnapshot, a5 as transitionNode, e as XSTATE_TIMER, m as matchesEventDescriptor, a6 as getTransitionResult, a7 as hasEffect, a8 as createErrorPlatformEvent, a9 as withActorSelf, r as resolveActionsWithContext, F as createInitEvent, aa as createSpawnEffect, ab as initialMicrostep, ac as toStatePath, ad as isStateId, ae as getStateNodeByPath, af as getPersistedSnapshot, ag as resolveReferencedActor, ah as createInvokeTimeoutEvent, ai as $$ACTOR_TYPE, j as createActor } from './createActor-a211c276.esm.js';
2
- import { g as assertValid } from './index-7020402e.esm.js';
1
+ import { Q as allocateChildId, R as assertChildIdFree, S as reserveChildId, T as STATE_DELIMITER, U as mapValues, t as toArray, V as createInvokeId, W as getDelayedTransitions, Y as getEventDescriptorKey, Z as getCandidates, _ as evaluateCandidate, $ as formatTransition, a0 as NULL_EVENT, a1 as toTransitionConfigArray, a2 as createInvokeTimeoutEventId, a3 as matchesActorSession, a4 as formatRouteTransitions, a5 as resolveStateValue, a6 as getAllStateNodes, x as getStateNodes, a7 as createMachineSnapshot, a8 as isInFinalState, a9 as createInertActorScope, aa as setInertActorScopeSnapshot, a as beginSpawnAllocation, ab as attachSnapshotActorRef, ac as macrostep, ad as isInertActorScope, ae as setSnapshotActorRef, af as cloneMachineSnapshot, ag as transitionNode, g as XSTATE_TIMER, m as matchesEventDescriptor, ah as getTransitionResult, ai as hasEffect, aj as createErrorPlatformEvent, ak as withActorSelf, r as resolveActionsWithContext, al as takeSpawnAllocationCounters, am as mergeActorIdCounters, K as createInitEvent, an as createSpawnEffect, ao as initialMicrostep, ap as toStatePath, aq as isStateId, ar as getStateNodeByPath, as as getPersistedSnapshot, at as createRemoteActorRef, au as resolveReferencedActor, av as createInvokeTimeoutEvent, aw as parseGeneratedActorId, ax as ACTOR_REF_TYPE, k as createActor } from './createActor-973c72ad.esm.js';
2
+ import { g as assertValid } from './index-b478f443.esm.js';
3
3
 
4
4
  function createSpawner(actorScope, actors, spawnedChildren) {
5
5
  return (src, options) => {
6
6
  const referencedSrc = Object.entries(actors).find(([, logic]) => logic === src)?.[0];
7
+ // Generated ids come from the same transaction allocator as `enq.spawn`,
8
+ // so context-factory allocations persist with the snapshot and never
9
+ // collide with later spawns.
10
+ const id = options?.id ?? allocateChildId(actorScope, referencedSrc ?? src).id;
11
+ if (options?.id !== undefined) {
12
+ assertChildIdFree(actorScope, options.id);
13
+ reserveChildId(actorScope, options.id);
14
+ }
7
15
  const actor = actorScope.system.createActorRef(src, {
8
- id: options?.id,
16
+ id,
9
17
  parent: actorScope.self,
10
18
  syncSnapshot: options?.syncSnapshot,
11
19
  input: options?.input,
@@ -390,6 +398,16 @@ function formatInitialTransition(stateNode, _target) {
390
398
  }
391
399
 
392
400
  const STATE_IDENTIFIER = '#';
401
+ function findEventSchema(schemas, eventType) {
402
+ if (!schemas) {
403
+ return undefined;
404
+ }
405
+ if (Object.hasOwn(schemas, eventType)) {
406
+ return schemas[eventType];
407
+ }
408
+ const descriptor = Object.keys(schemas).find(key => matchesEventDescriptor(eventType, key));
409
+ return descriptor === undefined ? undefined : schemas[descriptor];
410
+ }
393
411
  let emptyCanActor;
394
412
  let emptyCanActorScope;
395
413
  function getEmptyCanActor() {
@@ -434,6 +452,12 @@ class StateMachine {
434
452
  config, sources, validator) {
435
453
  this.config = config;
436
454
  this.validator = validator;
455
+ /**
456
+ * @internal Type-only marker for the actor's internal event protocol. Not
457
+ * `declare` (the build's babel pipeline rejects declare class fields); the
458
+ * one `undefined` property this emits per machine instance is inert.
459
+ */
460
+ this._internalEventType = void 0;
437
461
  /** The machine's own version. */
438
462
  this.version = void 0;
439
463
  this.schemas = void 0;
@@ -561,9 +585,10 @@ class StateMachine {
561
585
  }
562
586
  const event = value;
563
587
  const eventSchemas = this.schemas?.events;
588
+ const internalEventSchemas = this.schemas?.internalEvents;
564
589
  const isFrameworkEvent = event.type.startsWith('xstate.') || event.type.startsWith('@xstate.');
565
- const schema = eventSchemas && Object.hasOwn(eventSchemas, event.type) ? eventSchemas[event.type] : undefined;
566
- if (eventSchemas && !schema && !isFrameworkEvent) {
590
+ const schema = findEventSchema(internalEventSchemas, event.type) ?? findEventSchema(eventSchemas, event.type);
591
+ if ((eventSchemas || internalEventSchemas) && !schema && !isFrameworkEvent) {
567
592
  return {
568
593
  issues: [{
569
594
  message: `Unknown event '${event.type}' for machine '${this.id}' version '${this.version}'.`
@@ -599,7 +624,7 @@ class StateMachine {
599
624
  }
600
625
  }
601
626
  };
602
- this.internalEventDescriptors = this.config.internalEvents ?? [];
627
+ this.internalEventDescriptors = [...Object.keys(this.schemas?.internalEvents ?? {}), ...(this.config.internalEvents ?? [])];
603
628
  this.options = {
604
629
  maxIterations: Infinity,
605
630
  ...this.config.options
@@ -695,6 +720,7 @@ class StateMachine {
695
720
  if (usesInertScope) {
696
721
  setInertActorScopeSnapshot(resolvedActorScope, snapshot, false);
697
722
  }
723
+ beginSpawnAllocation(resolvedActorScope);
698
724
  const fastSnapshot = this._transitionFast(snapshot, event, resolvedActorScope);
699
725
  if (fastSnapshot) {
700
726
  if (usesInertScope) {
@@ -890,6 +916,14 @@ class StateMachine {
890
916
  ...nextState.children,
891
917
  ...children
892
918
  };
919
+ // Commit the transaction counters so context-factory allocations
920
+ // persist with the snapshot: a freed id is never handed out again
921
+ // after a restore or in a fresh replay process. (The spawner already
922
+ // registered each child for string-id resolution.)
923
+ const counters = takeSpawnAllocationCounters(actorScope);
924
+ if (counters) {
925
+ nextState._nextActorIds = mergeActorIdCounters(nextState._nextActorIds, counters);
926
+ }
893
927
  }
894
928
  return nextState;
895
929
  }
@@ -913,6 +947,7 @@ class StateMachine {
913
947
  }
914
948
  const usesInertScope = !actorScope;
915
949
  const resolvedActorScope = actorScope ?? createInertActorScope(this);
950
+ beginSpawnAllocation(resolvedActorScope);
916
951
  const initEvent = createInitEvent(input); // TODO: fix;
917
952
  const internalQueue = [];
918
953
  const preInitialState = this._getPreInitialState(resolvedActorScope, initEvent);
@@ -1004,6 +1039,31 @@ class StateMachine {
1004
1039
  const snapshotChildren = snapshotData.children;
1005
1040
  for (const actorId of Object.keys(snapshotChildren)) {
1006
1041
  const actorData = snapshotChildren[actorId];
1042
+ if (actorData.remote === true && actorData.address !== undefined) {
1043
+ if (typeof actorData.src !== 'string') {
1044
+ // Fail loudly instead of fabricating a source key that hosts would
1045
+ // route by.
1046
+ throw new Error(`Unable to restore remote child '${actorId}': a child referenced by address requires a registered source key.`);
1047
+ }
1048
+ // The child's state lives with another runtime; restore a
1049
+ // location-transparent handle constructed from its identity alone.
1050
+ // The handle keeps its persisted address verbatim: the owning
1051
+ // runtime's identity for the child wins over the local parent chain.
1052
+ const handle = createRemoteActorRef(resolvedActorScope.system, {
1053
+ id: actorId,
1054
+ address: actorData.address,
1055
+ src: actorData.src,
1056
+ parent: resolvedActorScope.self,
1057
+ registryKey: actorData.registryKey,
1058
+ syncSnapshot: actorData.syncSnapshot,
1059
+ incarnation: actorData.incarnation
1060
+ });
1061
+ if (actorData.registryKey) {
1062
+ resolvedActorScope.system._set(actorData.registryKey, handle);
1063
+ }
1064
+ children[actorId] = handle;
1065
+ continue;
1066
+ }
1007
1067
  const childState = actorData.snapshot;
1008
1068
  const src = actorData.src;
1009
1069
  const logic = typeof src === 'string' ? resolveReferencedActor(this, src) : src;
@@ -1096,12 +1156,30 @@ class StateMachine {
1096
1156
  const nodes = Array.from(getAllStateNodes(getStateNodes(this.root, snapshotData.value)));
1097
1157
  const {
1098
1158
  version: _persistedSnapshotVersion,
1159
+ // The legacy system-wide counter: superseded by per-snapshot
1160
+ // `_nextActorIds` plus the child-id fold below; dropped so old and new
1161
+ // snapshots round-trip to the same shape.
1162
+ _nextActorId: _legacyNextActorId,
1099
1163
  ...persistedRest
1100
1164
  } = snapshot;
1165
+ // Fold generated-shaped child ids into the counters as a floor: snapshots
1166
+ // persisted before per-actor counters (or hand-crafted ones) still must
1167
+ // never reuse a live child's id.
1168
+ let restoredCounters = persistedRest._nextActorIds;
1169
+ for (const childId of Object.keys(snapshotChildren)) {
1170
+ const generated = parseGeneratedActorId(childId);
1171
+ if (generated && (restoredCounters?.[generated.prefix] ?? 0) <= generated.index) {
1172
+ restoredCounters = {
1173
+ ...restoredCounters,
1174
+ [generated.prefix]: generated.index + 1
1175
+ };
1176
+ }
1177
+ }
1101
1178
  const restoredSnapshot = createMachineSnapshot({
1102
1179
  ...persistedRest,
1103
1180
  children,
1104
1181
  timers,
1182
+ _nextActorIds: restoredCounters,
1105
1183
  _nodes: nodes,
1106
1184
  value: snapshotData.value,
1107
1185
  historyValue: revivedHistoryValue,
@@ -1116,7 +1194,7 @@ class StateMachine {
1116
1194
  for (const key of Object.keys(contextPart)) {
1117
1195
  const value = contextPart[key];
1118
1196
  if (value && typeof value === 'object') {
1119
- if ('xstate$$type' in value && value.xstate$$type === $$ACTOR_TYPE) {
1197
+ if ('xstate$type' in value && value.xstate$type === ACTOR_REF_TYPE) {
1120
1198
  contextPart[key] = children[value.id];
1121
1199
  continue;
1122
1200
  }