xstate 6.0.0-alpha.64 → 6.0.0-alpha.65

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 (60) hide show
  1. package/README.md +27 -0
  2. package/dist/{createActor-521c8805.development.cjs.js → createActor-1df42c9e.development.cjs.js} +205 -31
  3. package/dist/{createActor-8493caa9.esm.js → createActor-4629a290.esm.js} +133 -28
  4. package/dist/{createActor-bd2527dc.development.esm.js → createActor-8f57b47b.development.esm.js} +205 -31
  5. package/dist/{createActor-29adb8a4.cjs.js → createActor-b987e971.cjs.js} +133 -28
  6. package/dist/declarations/src/State.d.ts +25 -3
  7. package/dist/declarations/src/StateMachine.d.ts +20 -7
  8. package/dist/declarations/src/actors/promise.d.ts +5 -5
  9. package/dist/declarations/src/createMachine.d.ts +5 -3
  10. package/dist/declarations/src/createMachineFromConfig.d.ts +13 -2
  11. package/dist/declarations/src/eventTypes.d.ts +8 -0
  12. package/dist/declarations/src/graph/index.d.ts +1 -0
  13. package/dist/declarations/src/graph/types.d.ts +20 -2
  14. package/dist/declarations/src/machineVersions.d.ts +2 -2
  15. package/dist/declarations/src/serialize.d.ts +7 -2
  16. package/dist/declarations/src/setup.d.ts +60 -19
  17. package/dist/declarations/src/types.d.ts +44 -23
  18. package/dist/declarations/src/types.v6.d.ts +9 -7
  19. package/dist/declarations/src/utils.d.ts +9 -0
  20. package/dist/{effectDescriptor-6dbc400a.cjs.js → effectDescriptor-4cf24593.cjs.js} +1 -1
  21. package/dist/{effectDescriptor-85ea06c9.esm.js → effectDescriptor-973fc1ba.esm.js} +1 -1
  22. package/dist/{effectDescriptor-62b53c6d.development.cjs.js → effectDescriptor-b2b7deaa.development.cjs.js} +1 -1
  23. package/dist/{effectDescriptor-f76948fc.development.esm.js → effectDescriptor-c4671afc.development.esm.js} +1 -1
  24. package/dist/{index-5587e13b.cjs.js → index-0cf33789.development.cjs.js} +29 -14
  25. package/dist/{index-b0dc2b39.esm.js → index-15382daf.development.esm.js} +29 -14
  26. package/dist/{index-90ebf5ae.development.esm.js → index-52ad3d45.esm.js} +29 -14
  27. package/dist/{index-2afc57c3.development.cjs.js → index-f201d440.cjs.js} +29 -14
  28. package/dist/xstate-actors.cjs.js +2 -2
  29. package/dist/xstate-actors.development.cjs.js +2 -2
  30. package/dist/xstate-actors.development.esm.js +2 -2
  31. package/dist/xstate-actors.esm.js +2 -2
  32. package/dist/xstate-actors.umd.min.js +1 -1
  33. package/dist/xstate-actors.umd.min.js.map +1 -1
  34. package/dist/xstate-durable.cjs.js +2 -2
  35. package/dist/xstate-durable.development.cjs.js +2 -2
  36. package/dist/xstate-durable.development.esm.js +2 -2
  37. package/dist/xstate-durable.esm.js +2 -2
  38. package/dist/xstate-durable.umd.min.js +1 -1
  39. package/dist/xstate-durable.umd.min.js.map +1 -1
  40. package/dist/xstate-graph.cjs.js +8 -4
  41. package/dist/xstate-graph.cjs.mjs +1 -0
  42. package/dist/xstate-graph.development.cjs.js +8 -4
  43. package/dist/xstate-graph.development.cjs.mjs +1 -0
  44. package/dist/xstate-graph.development.esm.js +8 -4
  45. package/dist/xstate-graph.esm.js +8 -4
  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-validation.cjs.js +24 -7
  49. package/dist/xstate-validation.development.cjs.js +24 -7
  50. package/dist/xstate-validation.development.esm.js +24 -7
  51. package/dist/xstate-validation.esm.js +24 -7
  52. package/dist/xstate-validation.umd.min.js +1 -1
  53. package/dist/xstate-validation.umd.min.js.map +1 -1
  54. package/dist/xstate.cjs.js +475 -257
  55. package/dist/xstate.development.cjs.js +497 -260
  56. package/dist/xstate.development.esm.js +499 -262
  57. package/dist/xstate.esm.js +477 -259
  58. package/dist/xstate.umd.min.js +1 -1
  59. package/dist/xstate.umd.min.js.map +1 -1
  60. package/package.json +1 -1
package/README.md CHANGED
@@ -33,6 +33,13 @@ timers without replaying entry actions. Await `executeEffects()` before persisti
33
33
  to retain accepted timer deadlines. The host handles root error snapshots;
34
34
  `run()` rejects with the root error. See [durable execution](../../docs/durable-execution.md).
35
35
 
36
+ <!-- state context refinements from packages/core/src/setup.ts and packages/core/src/State.ts -->
37
+
38
+ For [typestates](../../docs/typestates.md), declare state-level `schemas.context`
39
+ in `setup({ states })`. State functions receive narrowed context, transitions
40
+ check the target context requirements, and `snapshot.matches(...)` narrows
41
+ context when reading snapshots.
42
+
36
43
  <!-- typed inline invocation from packages/core/src/setup.ts -->
37
44
 
38
45
  Use `s.createInvoke({ src, input, onDone })` inline in `s.createMachine(...)` for an actor used in one state. It infers the actor's input and output and the enclosing state's narrowed context without registering that actor in `setup.actors`. See [typed inline invokes](../../docs/invoke.md#typed-inline-invokes).
@@ -41,6 +48,14 @@ Pass an async function directly as `src`, with `schemas.input`, `schemas.output`
41
48
 
42
49
  The helper requires input for actors whose input excludes `undefined`, and checks child IDs and source compatibility against `schemas.children` declared in the setup or machine.
43
50
 
51
+ <!-- graph traversal events from packages/core/src/graph/index.ts -->
52
+
53
+ `getAllOwnEvents(snapshot)` from `xstate/graph` includes invoke completions, errors, and delayed events. Compose it with custom traversal payloads: supplied `events` replace the defaults. See [model-based testing](../../docs/model-based-testing.md).
54
+
55
+ <!-- JSON loading and runtime validation from packages/core/src/createMachineFromConfig.ts -->
56
+
57
+ Revive JSON definitions with `createMachineFromConfig(json, { schemas, validator, ...sources })` to restore runtime validation. The loader validates structural keys and references and copies its input; serialized definitions are independent copies. See [serialization](../../docs/serialization.md).
58
+
44
59
  For flat finite state machines, `xstate/fsm` provides a tiny pure transition
45
60
  table with context and TypeScript support:
46
61
 
@@ -635,3 +650,15 @@ For these reasons, it is impractical for our team to be bound by decisions taken
635
650
  ### Packages
636
651
 
637
652
  Most of the packages in the XState family declare a peer dependency on XState itself. We’ll be cautious about maintaining compatibility with already-released packages when releasing a new version of XState, **but** each release of packages depending on XState will always adjust the declared peer dependency range to include the latest version of XState. For example, you should always be able to update `xstate` without `@xstate/react`. But when you update `@xstate/react`, we highly recommend updating `xstate` too.
653
+
654
+ <!-- public input validation contract from src/StateMachine.ts -->
655
+ Validate external input with `machine.eventSchema` before `actor.send()`.
656
+ It validates complete public events, excludes internal/runtime events, and allows
657
+ explicitly configured routes. Payload checks require runtime schemas;
658
+ `types<T>()` supplies types only. See [public input validation](../../docs/internal-events.md#validating-public-input).
659
+
660
+ <!-- entry effects and terminal transition behavior from packages/core/src/stateUtils.ts and transitionActions.ts -->
661
+
662
+ Functions passed to `enq(...)` run as effects; their returned context or child patches are ignored, with a development warning. Return a computed patch from the transition, entry, or exit function instead. Entry/exit functions using enqueue must declare exactly `(args, enq)`; default/rest parameter wrappers receive a development diagnostic. See [actions](../../docs/actions.md).
663
+
664
+ Pure transitions preserve terminal snapshots and return no effects. `snapshot.can(...)` returns `false` for terminal snapshots; active dry runs propagate evaluation errors. See [snapshots](../../docs/snapshots.md) and [states](../../docs/states.md).
@@ -530,7 +530,33 @@ function withActorScope(args, actorScope) {
530
530
  }
531
531
 
532
532
  function execCustomEffect() {
533
- return this.action?.(...this.args);
533
+ const result = this.action?.(...this.args);
534
+ {
535
+ warnOnIgnoredEffectResult(this, result);
536
+ }
537
+ return result;
538
+ }
539
+ const warnedEffectResults = new WeakSet();
540
+
541
+ /**
542
+ * A function passed to `enq(...)` runs as an effect after the transition is
543
+ * computed, so a `{ context }` or `{ children }` it returns is never applied.
544
+ * Development builds say so, once per function.
545
+ */
546
+ function warnOnIgnoredEffectResult(effect, result) {
547
+ if (!effect.action || result === null || typeof result !== 'object' || warnedEffectResults.has(effect.action)) {
548
+ return;
549
+ }
550
+ const prototype = Object.getPrototypeOf(result);
551
+ if (prototype !== Object.prototype && prototype !== null) {
552
+ return;
553
+ }
554
+ const keys = ['context', 'children'].filter(key => key in result);
555
+ if (!keys.length) {
556
+ return;
557
+ }
558
+ warnedEffectResults.add(effect.action);
559
+ console.warn(`Action "${effect.type || '(anonymous)'}" returned { ${keys.join(', ')} }, which is ignored: functions passed to enq(...) run as effects after the transition. Return the patch from the transition, entry or exit function instead; a named action can be called there directly and its result returned.`);
534
560
  }
535
561
  function execEmitEffect(runtime = this.source.system) {
536
562
  return runtime.emitEvent(this.source, this.event);
@@ -1059,6 +1085,16 @@ function createTransitionEnqueue(actorScope, actions, internalEvents, actorSubsc
1059
1085
  props[key] = guard(props[key]);
1060
1086
  }
1061
1087
  const enqueue = createEnqueueObject(props, guard((action, ...args) => {
1088
+ // A named action is `undefined` when it has no implementation. Skip it:
1089
+ // an `{ action, args }` record without a function would be emitted as
1090
+ // an event. Speculative passes (`can()`, conflict resolution) run with
1091
+ // `createActors: false`; warn only when the transition really runs.
1092
+ if (typeof action !== 'function') {
1093
+ if (createActors) {
1094
+ warnNotAFunction(action);
1095
+ }
1096
+ return;
1097
+ }
1062
1098
  pushBuiltInAction(actions, action, ...args);
1063
1099
  }));
1064
1100
  enqueueClosers.set(enqueue, () => {
@@ -1083,6 +1119,10 @@ function lateEnqueueCall() {
1083
1119
  throw new Error('enq.* called after the transition function returned');
1084
1120
  }
1085
1121
  }
1122
+ function warnNotAFunction(value) {
1123
+ const received = typeof value === 'string' ? `the string "${value}"` : value !== null && typeof value === 'object' ? 'an object' : String(value);
1124
+ console.warn(`enq(...) received ${received} instead of a function, so nothing was enqueued. A named action is undefined when it has no implementation: implement it in setup({ actions }) or the machine config, or pass it to machine.provide({ actions }).`);
1125
+ }
1086
1126
  function getBuiltInActionFields(action, args) {
1087
1127
  switch (action) {
1088
1128
  case builtInActions['@xstate.spawn']:
@@ -2288,6 +2328,10 @@ function getDelayedTransitions(stateNode) {
2288
2328
  }));
2289
2329
  }
2290
2330
  function formatTransition(stateNode, descriptor, transitionConfig) {
2331
+ const removedKey = getRemovedTransitionKey(transitionConfig);
2332
+ if (removedKey) {
2333
+ throw new Error(`Transition "${descriptor || 'always'}" in state "${stateNode.id}" uses ${removedKey}, which was removed in v6. Use a transition function.`);
2334
+ }
2291
2335
  const normalizedTarget = normalizeTarget(transitionConfig.target);
2292
2336
  const reenter = transitionConfig.reenter ?? false;
2293
2337
  const target = resolveTarget(stateNode, normalizedTarget);
@@ -2298,14 +2342,46 @@ function formatTransition(stateNode, descriptor, transitionConfig) {
2298
2342
  source: stateNode,
2299
2343
  reenter,
2300
2344
  eventType: descriptor,
2301
- toJSON: () => ({
2302
- ...transition,
2303
- source: `#${stateNode.id}`,
2304
- target: target ? target.map(t => `#${t.id}`) : undefined
2305
- })
2345
+ toJSON: () => transitionDefinitionToJSON(transition)
2306
2346
  };
2307
2347
  return transition;
2308
2348
  }
2349
+ function transitionDefinitionToJSON(transition) {
2350
+ const {
2351
+ definition: _,
2352
+ ...serializableTransition
2353
+ } = transition;
2354
+ return {
2355
+ ...serializableTransition,
2356
+ source: `#${transition.source.id}`,
2357
+ target: transition.target?.map(target => `#${target.id}`)
2358
+ };
2359
+ }
2360
+
2361
+ /**
2362
+ * Returns the v5 key of a transition object that v6 would misread, in every
2363
+ * build: `cond` is never read, so the transition would always be taken,
2364
+ * transition `actions` would not run as written, and only a function `guard`
2365
+ * can be called. Development builds explain each key earlier, in
2366
+ * `diagnoseAuthorConfig`. Compiled configs (JSON, SCXML) never set them.
2367
+ */
2368
+ function getRemovedTransitionKey(transitionConfig) {
2369
+ const {
2370
+ cond,
2371
+ actions,
2372
+ guard
2373
+ } = transitionConfig;
2374
+ if (cond !== undefined) {
2375
+ return '"cond"';
2376
+ }
2377
+ if (actions !== undefined) {
2378
+ return '"actions"';
2379
+ }
2380
+ if (guard !== undefined && typeof guard !== 'function') {
2381
+ return 'an object-form "guard"';
2382
+ }
2383
+ return undefined;
2384
+ }
2309
2385
  function isStateNodeDescendantOf(stateNode, ancestor) {
2310
2386
  for (let current = stateNode.parent; current; current = current.parent) {
2311
2387
  if (current === ancestor) {
@@ -2648,12 +2724,18 @@ function removeConflictingTransitions(enabledTransitions, stateNodeSet, snapshot
2648
2724
  }
2649
2725
  function createTransitionResultResolver(snapshot, event, actorScope, resolveActions, selectionResults) {
2650
2726
  let cache;
2651
- return transition => {
2652
- if (!transition.to) {
2653
- return getTransitionResult(transition, snapshot, event, actorScope, {
2654
- resolveActions,
2655
- selectionResult: selectionResults?.get(transition)
2656
- });
2727
+ return (transition, applied) => {
2728
+ if (!transition.to && !applied) {
2729
+ // An object transition's targets are static, so reading them must not
2730
+ // run its `context` and `input` mappers
2731
+ return {
2732
+ targets: transition.target,
2733
+ context: undefined,
2734
+ reenter: transition.reenter,
2735
+ actions: undefined,
2736
+ internalEvents: undefined,
2737
+ input: undefined
2738
+ };
2657
2739
  }
2658
2740
  let result = cache?.get(transition);
2659
2741
  if (!result) {
@@ -2881,13 +2963,20 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
2881
2963
  children: args.children,
2882
2964
  actions: args.actions,
2883
2965
  actors: args.actors,
2966
+ guards: currentSnapshot.machine.sources.guards,
2967
+ delays: currentSnapshot.machine.sources.delays,
2884
2968
  input,
2885
2969
  stateNode
2886
2970
  }, actorScope) : {
2887
2971
  ...args,
2972
+ guards: currentSnapshot.machine.sources.guards,
2973
+ delays: currentSnapshot.machine.sources.delays,
2888
2974
  input,
2889
2975
  stateNode
2890
- }, enqueue), '_special' in transitionFn ? {
2976
+ },
2977
+ // This function runs during action resolution, where enqueued
2978
+ // effects are no longer collected.
2979
+ createIgnoredEnqueue(transitionFn, kind, stateNode.id) ), '_special' in transitionFn ? {
2891
2980
  _special: true
2892
2981
  } : {});
2893
2982
  return [[wrappedAction], undefined, undefined];
@@ -2925,7 +3014,7 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
2925
3014
  }
2926
3015
  for (const exitStateNode of statesToExit) {
2927
3016
  const stateInput = getStateInput(currentSnapshot, exitStateNode.id);
2928
- const [exitActions, nextContext, internalEvents] = exitStateNode.exit ? getStateActionsAndContext(exitStateNode.exit, nextState.context, currentSnapshot.children, stateInput, 'exit', exitStateNode) : [[], undefined, undefined];
3017
+ const [exitActions, nextContext, internalEvents] = exitStateNode.exit ? getStateActionsAndContext(exitStateNode.exit, nextState.context, nextState.children, stateInput, 'exit', exitStateNode) : [[], undefined, undefined];
2929
3018
  if (internalEvents?.length) {
2930
3019
  internalQueue.push(...internalEvents);
2931
3020
  }
@@ -2955,11 +3044,20 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
2955
3044
  let context = nextState.context;
2956
3045
  const transitionActions = [];
2957
3046
  const internalEvents = [];
3047
+ const resolvedTransitions = [];
2958
3048
  for (const t of filteredTransitions) {
2959
- if (t.actions) {
2960
- transitionActions.push(...toArray(t.actions));
3049
+ const res = getCurrentTransitionResult(t, true);
3050
+ if (t.to) {
3051
+ const resolvedTransition = {
3052
+ ...t,
3053
+ target: res.targets,
3054
+ definition: t
3055
+ };
3056
+ resolvedTransition.toJSON = () => transitionDefinitionToJSON(resolvedTransition);
3057
+ resolvedTransitions.push(resolvedTransition);
3058
+ } else {
3059
+ resolvedTransitions.push(t);
2961
3060
  }
2962
- const res = getCurrentTransitionResult(t);
2963
3061
  if (res.context !== undefined) {
2964
3062
  context = mergeContextPatch(context, res.context);
2965
3063
  }
@@ -3115,7 +3213,7 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3115
3213
  const {
3116
3214
  targets,
3117
3215
  input
3118
- } = getCurrentTransitionResult(transition);
3216
+ } = getCurrentTransitionResult(transition, true);
3119
3217
  if (input && targets) {
3120
3218
  for (const targetNode of targets.filter(targetNode => enteredTargetsByTransition.get(transition)?.has(targetNode))) {
3121
3219
  stateInputMap[targetNode.id] = input;
@@ -3124,12 +3222,12 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3124
3222
  }
3125
3223
  }
3126
3224
  const completedNodes = new Set();
3127
- const children = {
3128
- ...nextState.children
3129
- };
3130
3225
  for (const stateNodeToEnter of [...statesToEnter].sort((a, b) => a.order - b.order)) {
3131
3226
  mutStateNodeSet.add(stateNodeToEnter);
3132
3227
  const actions = [];
3228
+ // Read the children for each state: the entry actions of the states
3229
+ // entered before this one may have spawned or stopped children.
3230
+ let children = nextState.children;
3133
3231
 
3134
3232
  // Final states are inert, so (as in SCXML) their invocations never
3135
3233
  // start.
@@ -3168,7 +3266,10 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3168
3266
  args: [actor]
3169
3267
  });
3170
3268
  if (invokeDef.id) {
3171
- children[invokeDef.id] = actor;
3269
+ children = {
3270
+ ...children,
3271
+ [invokeDef.id]: actor
3272
+ };
3172
3273
  }
3173
3274
  }
3174
3275
  if (invoked) {
@@ -3288,7 +3389,12 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3288
3389
  nextStateNodesToExit.forEach(stateNode => {
3289
3390
  if (stateNode.exit) {
3290
3391
  const stateInput = getStateInput(nextState, stateNode.id);
3291
- const [exitActions,, nextInternalEvents] = getStateActionsAndContext(stateNode.exit, nextState.context, nextState.children, stateInput, 'exit', stateNode);
3392
+ const [exitActions, nextContext, nextInternalEvents] = getStateActionsAndContext(stateNode.exit, nextState.context, nextState.children, stateInput, 'exit', stateNode);
3393
+ if (nextContext) {
3394
+ nextState = cloneMachineSnapshot(nextState, {
3395
+ context: nextContext
3396
+ });
3397
+ }
3292
3398
  allExitActions.push(...exitActions);
3293
3399
  if (nextInternalEvents?.length) {
3294
3400
  internalQueue.push(...nextInternalEvents);
@@ -3309,14 +3415,14 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3309
3415
  // If context was changed (e.g. by entry actions during self-transition),
3310
3416
  // clone to ensure reference inequality for eventless transition re-evaluation
3311
3417
  if (nextState.context !== originalContext) {
3312
- return [nextState === currentSnapshot ? cloneMachineSnapshot(nextState) : nextState, executableActions];
3418
+ return [nextState === currentSnapshot ? cloneMachineSnapshot(nextState) : nextState, executableActions, resolvedTransitions];
3313
3419
  }
3314
- return [nextState, executableActions];
3420
+ return [nextState, executableActions, resolvedTransitions];
3315
3421
  }
3316
3422
  return [cloneMachineSnapshot(nextState, {
3317
3423
  _nodes: nextStateNodes,
3318
3424
  historyValue
3319
- }), executableActions];
3425
+ }), executableActions, resolvedTransitions];
3320
3426
  }
3321
3427
  }
3322
3428
 
@@ -3426,6 +3532,15 @@ class InfiniteTransitionError extends Error {
3426
3532
  }
3427
3533
  }
3428
3534
  function macrostep(snapshot, event, actorScope, internalQueue, initialMicrosteps = []) {
3535
+ // A done, error or stopped snapshot processes no events, as in an actor:
3536
+ // every event is unhandled. The initial macrostep passes `initialMicrosteps`
3537
+ // and may start from a snapshot that is already done.
3538
+ if (snapshot.status !== 'active' && !initialMicrosteps.length) {
3539
+ return {
3540
+ snapshot,
3541
+ microsteps: [[snapshot, [], []]]
3542
+ };
3543
+ }
3429
3544
  let nextSnapshot = snapshot;
3430
3545
  const microsteps = initialMicrosteps.slice();
3431
3546
  // Whether a transition handled the external event. A handled event always
@@ -3494,6 +3609,7 @@ function macrostep(snapshot, event, actorScope, internalQueue, initialMicrosteps
3494
3609
  };
3495
3610
  }
3496
3611
  function addMicrostep(step, transitions) {
3612
+ transitions = step[2] ?? transitions;
3497
3613
  // collect microsteps; their transitions are surfaced on the enclosing
3498
3614
  // '@xstate.transition' event via its `microsteps[]` facet (there is no
3499
3615
  // standalone microstep event) and returned by `getMicrosteps()`
@@ -3649,6 +3765,42 @@ function assertSyncTransitionResult(res, event, sourceId, kind) {
3649
3765
  throw new Error(kind ? `${kind === 'entry' ? 'Entry' : 'Exit'} functions must be synchronous. The ${kind} function of state "${sourceId}" returned a promise (event "${event.type}"). Move async work into an invoked or spawned actor, or enq.effect.` : `Transition functions must be synchronous. Transition for event "${event.type}" in state "${sourceId}" returned a promise. Move async work into an invoked or spawned actor, or enq.effect.`);
3650
3766
  }
3651
3767
  }
3768
+ const ignoredEnqueues = new WeakMap();
3769
+
3770
+ /**
3771
+ * The enqueue object that an entry or exit function gets in development when it
3772
+ * is not declared with exactly two parameters. Such a function runs during
3773
+ * action resolution, where enqueued effects are no longer collected, so every
3774
+ * call is ignored. This one warns, once per function.
3775
+ */
3776
+ function createIgnoredEnqueue(fn, kind, stateNodeId) {
3777
+ let enqueue = ignoredEnqueues.get(fn);
3778
+ if (enqueue) {
3779
+ return enqueue;
3780
+ }
3781
+ let warned = false;
3782
+ const ignore = (method, result) => (..._args) => {
3783
+ if (!warned) {
3784
+ warned = true;
3785
+ console.warn(`The ${kind} function of state "${stateNodeId}" called ${method}(...), which was ignored. Only ${kind} functions declared with exactly two parameters, (args, enq) => ..., get a working enq. This one has fn.length ${fn.length}; fn.length stops counting at a default or rest parameter.`);
3786
+ }
3787
+ return result?.();
3788
+ };
3789
+ const emptyActor = () => ({});
3790
+ enqueue = createEnqueueObject({
3791
+ cancel: ignore('enq.cancel'),
3792
+ emit: ignore('enq.emit'),
3793
+ log: ignore('enq.log'),
3794
+ raise: ignore('enq.raise'),
3795
+ sendTo: ignore('enq.sendTo'),
3796
+ stop: ignore('enq.stop'),
3797
+ spawn: ignore('enq.spawn', emptyActor),
3798
+ listen: ignore('enq.listen', emptyActor),
3799
+ subscribeTo: ignore('enq.subscribeTo', emptyActor)
3800
+ }, ignore('enq'));
3801
+ ignoredEnqueues.set(fn, enqueue);
3802
+ return enqueue;
3803
+ }
3652
3804
  let transitionEffectEnqueue;
3653
3805
  function getTransitionEffectEnqueue() {
3654
3806
  return transitionEffectEnqueue ??= createEnqueueObject({
@@ -3978,6 +4130,17 @@ function isMachineSnapshot(value) {
3978
4130
  return !!value && typeof value === 'object' && 'machine' in value && 'value' in value;
3979
4131
  }
3980
4132
 
4133
+ /**
4134
+ * The values that `snapshot.matches(...)` accepts for a state value: a state
4135
+ * key, a dot-delimited path to a descendant state, or a partial state value.
4136
+ * Non-literal state values accept any value.
4137
+ */
4138
+
4139
+ /**
4140
+ * `unknown` if `matches(...)` accepts `TTestStateValue` for `TStateValue`,
4141
+ * otherwise `never`. Non-literal test values are always accepted.
4142
+ */
4143
+
3981
4144
  /** @public */
3982
4145
 
3983
4146
  const machineSnapshotMatches = function matches(testValue) {
@@ -4502,7 +4665,14 @@ function getAllOwnEventDescriptors(snapshot) {
4502
4665
  return [...new Set([...snapshot.nodes.flatMap(sn => sn.ownEvents)])];
4503
4666
  }
4504
4667
 
4505
- /** @internal Events synthesized from active transition descriptors. */
4668
+ /**
4669
+ * Returns one event per transition of the active state nodes of `snapshot`,
4670
+ * including the internal events for invoked actors (`xstate.done.actor`,
4671
+ * `xstate.error.actor`) and delayed transitions (`xstate.after`). Graph
4672
+ * traversal sends these when the `events` option is not given.
4673
+ *
4674
+ * @public
4675
+ */
4506
4676
  function getAllOwnEvents(snapshot) {
4507
4677
  const events = snapshot.nodes.flatMap(stateNode => [...stateNode.transitions.values()].flatMap(transitions => transitions.map(transition => {
4508
4678
  const event = {
@@ -6063,7 +6233,10 @@ class Actor {
6063
6233
  const [nextSnapshot, effects] = nextState;
6064
6234
  if (nextSnapshot === previousSnapshot && !effects.length &&
6065
6235
  // State machine snapshots only; other logic may ignore events freely.
6066
- 'machine' in previousSnapshot && !event.type.startsWith('xstate.')) {
6236
+ 'machine' in previousSnapshot && (
6237
+ // `xstate.route` is sent by users, so a route that matches nothing is
6238
+ // reported like any other unhandled event.
6239
+ !event.type.startsWith('xstate.') || event.type === 'xstate.route')) {
6067
6240
  this._reportUnhandledEvent(event);
6068
6241
  }
6069
6242
  snapshot = nextSnapshot;
@@ -6084,10 +6257,11 @@ class Actor {
6084
6257
  _reportUnhandledEvent(event) {
6085
6258
  safeCall(() => this.options.onUnhandledEvent?.(event, this._snapshot));
6086
6259
  {
6260
+ const to = event.type === 'xstate.route' ? ` to ${JSON.stringify(event.to)}` : '';
6087
6261
  const warned = this._warnedUnhandledTypes ??= new Set();
6088
- if (!warned.has(event.type)) {
6089
- warned.add(event.type);
6090
- console.warn(`Actor ${this.id} received event "${event.type}" in state ${JSON.stringify(this._snapshot.value)} with no matching transition`);
6262
+ if (!warned.has(event.type + to)) {
6263
+ warned.add(event.type + to);
6264
+ console.warn(`Actor ${this.id} received event "${event.type}"${to} in state ${JSON.stringify(this._snapshot.value)} with no matching transition`);
6091
6265
  }
6092
6266
  }
6093
6267
  }