xstate 6.0.0-alpha.49 → 6.0.0-alpha.50

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-0adb3a70.cjs.js → StateMachine-1e6ee14a.cjs.js} +18 -6
  2. package/dist/{StateMachine-29450e6d.development.cjs.js → StateMachine-70df737c.development.cjs.js} +18 -6
  3. package/dist/{StateMachine-2af31c11.esm.js → StateMachine-8cea8974.esm.js} +18 -6
  4. package/dist/{StateMachine-faf50c5c.development.esm.js → StateMachine-bc28e207.development.esm.js} +18 -6
  5. package/dist/{createActor-b4dd05ae.cjs.js → createActor-27fd819f.cjs.js} +80 -10
  6. package/dist/{createActor-88709f74.development.esm.js → createActor-74e185ee.development.esm.js} +80 -11
  7. package/dist/{createActor-268165d4.esm.js → createActor-ad3a1abe.esm.js} +80 -11
  8. package/dist/{createActor-a1e0dffb.development.cjs.js → createActor-ea9a560c.development.cjs.js} +80 -10
  9. package/dist/declarations/src/effectDescriptor.d.ts +9 -0
  10. package/dist/declarations/src/index.d.ts +1 -1
  11. package/dist/declarations/src/inspection.d.ts +24 -7
  12. package/dist/declarations/src/runtimeHelpers.d.ts +6 -3
  13. package/dist/declarations/src/system.d.ts +38 -3
  14. package/dist/declarations/src/types.d.ts +35 -2
  15. package/dist/{effectDescriptor-7ff6802f.development.cjs.js → effectDescriptor-16b6f3b4.cjs.js} +12 -1
  16. package/dist/{effectDescriptor-39d22100.development.esm.js → effectDescriptor-38598bd3.development.esm.js} +12 -1
  17. package/dist/{effectDescriptor-be348e50.cjs.js → effectDescriptor-40ca302f.development.cjs.js} +12 -1
  18. package/dist/{effectDescriptor-30c9a744.esm.js → effectDescriptor-7dac431a.esm.js} +12 -1
  19. package/dist/{fsm-e18a7cb4.development.esm.js → fsm-25f10f50.development.esm.js} +1 -1
  20. package/dist/{fsm-c1316948.development.cjs.js → fsm-697ffd89.development.cjs.js} +1 -1
  21. package/dist/{fsm-7a2e9697.cjs.js → fsm-7adaf0ea.cjs.js} +1 -1
  22. package/dist/{fsm-b804b3e9.esm.js → fsm-dc1bb88b.esm.js} +1 -1
  23. package/dist/{types-fbabaeee.cjs.js → types-a14db10c.development.cjs.js} +6 -1
  24. package/dist/{types-3c3455f7.esm.js → types-a313e7e2.esm.js} +6 -1
  25. package/dist/{types-b3fea5bd.development.cjs.js → types-bc22b358.cjs.js} +6 -1
  26. package/dist/{types-adda3842.development.esm.js → types-c37714eb.development.esm.js} +6 -1
  27. package/dist/xstate-actors.cjs.js +12 -3
  28. package/dist/xstate-actors.development.cjs.js +12 -3
  29. package/dist/xstate-actors.development.esm.js +13 -4
  30. package/dist/xstate-actors.esm.js +13 -4
  31. package/dist/xstate-actors.umd.min.js +1 -1
  32. package/dist/xstate-actors.umd.min.js.map +1 -1
  33. package/dist/xstate-durable.cjs.js +2 -2
  34. package/dist/xstate-durable.development.cjs.js +2 -2
  35. package/dist/xstate-durable.development.esm.js +2 -2
  36. package/dist/xstate-durable.esm.js +2 -2
  37. package/dist/xstate-durable.umd.min.js +1 -1
  38. package/dist/xstate-durable.umd.min.js.map +1 -1
  39. package/dist/xstate-fsm.cjs.js +2 -2
  40. package/dist/xstate-fsm.development.cjs.js +2 -2
  41. package/dist/xstate-fsm.development.esm.js +2 -2
  42. package/dist/xstate-fsm.esm.js +2 -2
  43. package/dist/xstate-graph.cjs.js +2 -2
  44. package/dist/xstate-graph.development.cjs.js +2 -2
  45. package/dist/xstate-graph.development.esm.js +2 -2
  46. package/dist/xstate-graph.esm.js +2 -2
  47. package/dist/xstate-graph.umd.min.js +1 -1
  48. package/dist/xstate-graph.umd.min.js.map +1 -1
  49. package/dist/xstate-scxml.cjs.js +3 -3
  50. package/dist/xstate-scxml.development.cjs.js +3 -3
  51. package/dist/xstate-scxml.development.esm.js +3 -3
  52. package/dist/xstate-scxml.esm.js +3 -3
  53. package/dist/xstate-scxml.umd.min.js +1 -1
  54. package/dist/xstate-scxml.umd.min.js.map +1 -1
  55. package/dist/xstate-validation.cjs.js +1 -1
  56. package/dist/xstate-validation.development.cjs.js +1 -1
  57. package/dist/xstate-validation.development.esm.js +1 -1
  58. package/dist/xstate-validation.esm.js +1 -1
  59. package/dist/xstate.cjs.js +5 -5
  60. package/dist/xstate.development.cjs.js +5 -5
  61. package/dist/xstate.development.esm.js +8 -8
  62. package/dist/xstate.esm.js +8 -8
  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
@@ -498,6 +498,25 @@ function createEmitEffect(actorScope, event) {
498
498
  args: []
499
499
  };
500
500
  }
501
+ function execDeadLetterEffect(runtime = this.target.system) {
502
+ return runtime.deadLetter(this.source, this.target, this.event, this.reason, this.detail);
503
+ }
504
+
505
+ /** @internal Creates a dead-letter effect for a boundary-rejected event. */
506
+ function createDeadLetterEffect(actorScope, source, event, reason, detail) {
507
+ return {
508
+ kind: 'builtin',
509
+ type: '@xstate.deadLetter',
510
+ exec: execDeadLetterEffect,
511
+ source,
512
+ target: actorScope.self,
513
+ event,
514
+ reason,
515
+ detail,
516
+ params: undefined,
517
+ args: []
518
+ };
519
+ }
501
520
 
502
521
  /** @internal Creates a directly executable user effect. */
503
522
  function createCustomEffect(type, action, params) {
@@ -4225,21 +4244,42 @@ async function runStep(actor, key, exec, sendSelf = event => void actor.system.s
4225
4244
  * @experimental
4226
4245
  */
4227
4246
  function deliverEvent(source, target, event) {
4228
- assertEventCanBeSent(source, target, event);
4247
+ if (rejectUndeliverableEvent(source, target, event)) {
4248
+ return;
4249
+ }
4229
4250
  const runtimeTarget = target;
4230
4251
  runtimeTarget._lastSourceRef = source;
4231
4252
  runtimeTarget._send(event);
4232
4253
  }
4233
4254
 
4234
4255
  /**
4235
- * Ensures internal events cannot cross an actor boundary from an external
4236
- * sender. Host runtimes must call this before taking ownership of delivery.
4256
+ * Returns the boundary error preventing this delivery, if any: an internal
4257
+ * event type cannot cross an actor boundary from an external sender.
4237
4258
  */
4238
- function assertEventCanBeSent(source, target, event) {
4259
+ function getEventBoundaryError(source, target, event) {
4239
4260
  const runtimeTarget = target;
4240
4261
  if (source !== target && runtimeTarget.logic?.isInternalEventType?.(event.type)) {
4241
- throw new Error(`Internal event "${event.type}" cannot be sent to actor "${target.id}" from outside.`);
4262
+ return new Error(`Internal event "${event.type}" cannot be sent to actor "${target.id}" from outside.`);
4263
+ }
4264
+ return undefined;
4265
+ }
4266
+
4267
+ /**
4268
+ * Rejects an event that must not cross the delivery boundary — an internal
4269
+ * event type sent from outside its owning actor — by reporting it as a dead
4270
+ * letter. Returns `true` when the event was rejected and must not be
4271
+ * delivered. Host runtimes must call this before taking ownership of
4272
+ * delivery.
4273
+ */
4274
+ function rejectUndeliverableEvent(source, target, event) {
4275
+ const error = getEventBoundaryError(source, target, event);
4276
+ if (error) {
4277
+ void target.system.deadLetter(source, target, event, 'internalEvent', {
4278
+ error
4279
+ });
4280
+ return true;
4242
4281
  }
4282
+ return false;
4243
4283
  }
4244
4284
 
4245
4285
  /**
@@ -4440,6 +4480,19 @@ function bookSessionId(system) {
4440
4480
  * other: install a different one via `system.runtime` (for durable hosts,
4441
4481
  * through `createDurable`'s adapter runtime operations).
4442
4482
  */
4483
+ /**
4484
+ * Why an event was not delivered: `'invalidEvent'` (payload failed its
4485
+ * declared schema), `'internalEvent'` (an internal event type sent from
4486
+ * outside its owning actor) or `'stopped'` (the target actor already
4487
+ * stopped). Hosts may report additional reasons.
4488
+ */
4489
+
4490
+ /** Extra detail attached to a dead letter. */
4491
+
4492
+ /**
4493
+ * Describes an event that was rejected at the delivery boundary instead of
4494
+ * being delivered to its target actor (a dead letter).
4495
+ */
4443
4496
 
4444
4497
  /** @internal Every operation of `ActorSystemRuntime`, for runtime wrappers. */
4445
4498
  const RUNTIME_OPERATIONS = ['spawnActor', 'startActor', 'stopActor', 'terminateActor', 'emitEvent', 'scheduleTimer', 'cancelTimer', 'cancelAllTimers', 'deadLetter'
@@ -4502,6 +4555,7 @@ class RuntimeSystem {
4502
4555
  this._clock = void 0;
4503
4556
  this._logger = void 0;
4504
4557
  this.createActorRef = void 0;
4558
+ this._onRejectedEvent = options.onRejectedEvent;
4505
4559
  const restoredSnapshot = typeof options.snapshot === 'object' && options.snapshot !== null ? options.snapshot : undefined;
4506
4560
  this._clock = options.clock;
4507
4561
  this._logger = options.logger;
@@ -4700,7 +4754,9 @@ class RuntimeSystem {
4700
4754
  terminateActor(actor, termination);
4701
4755
  }
4702
4756
  sendEvent(source, target, event) {
4703
- assertEventCanBeSent(source, target, event);
4757
+ if (rejectUndeliverableEvent(source, target, event)) {
4758
+ return;
4759
+ }
4704
4760
  // Record for the inspection `sent[]` facet regardless of which runtime
4705
4761
  // delivers, so host runtimes keep inspection parity.
4706
4762
  this._recordSent(source, target, event);
@@ -4717,17 +4773,29 @@ class RuntimeSystem {
4717
4773
  }
4718
4774
  source._emit(event);
4719
4775
  }
4720
- deadLetter(source, target, event, reason) {
4776
+ deadLetter(source, target, event, reason, detail) {
4721
4777
  this._sendInspectionEvent({
4722
4778
  type: '@xstate.deadletter',
4723
4779
  actorRef: target,
4724
4780
  sourceRef: source,
4725
4781
  event,
4726
- reason
4782
+ reason,
4783
+ issues: detail?.issues,
4784
+ error: detail?.error
4785
+ });
4786
+ this._onRejectedEvent?.({
4787
+ event,
4788
+ targetRef: target,
4789
+ targetId: target.id,
4790
+ sourceRef: source,
4791
+ eventOrigin: source ? 'actor' : 'external',
4792
+ reason,
4793
+ issues: detail?.issues,
4794
+ error: detail?.error
4727
4795
  });
4728
4796
  const override = this.runtime?.deadLetter;
4729
4797
  if (override) {
4730
- return override(source, target, event, reason);
4798
+ return override(source, target, event, reason, detail);
4731
4799
  }
4732
4800
  }
4733
4801
  runStep(actor, key, exec) {
@@ -4974,7 +5042,8 @@ class Actor {
4974
5042
  clock,
4975
5043
  logger,
4976
5044
  snapshot: resolvedOptions.snapshot ?? resolvedOptions.state,
4977
- createActorRef
5045
+ createActorRef,
5046
+ onRejectedEvent: resolvedOptions.onRejectedEvent
4978
5047
  });
4979
5048
  if (!parent && resolvedOptions._systemRef && !resolvedOptions._systemRef.current) {
4980
5049
  resolvedOptions._systemRef.current = this.system;
@@ -5755,4 +5824,4 @@ function createActor(logic, options) {
5755
5824
  return new Actor(logic, options);
5756
5825
  }
5757
5826
 
5758
- export { matchesActorSession as $, Actor as A, XSTATE_LOGIC_EFFECT_START as B, XSTATE_LOGIC_EFFECT_RESOLVE as C, XSTATE_LOGIC_EFFECT_REJECT as D, finalizeTransitionResult as E, createEmitEffect as F, createSendToEffect as G, XSTATE_INIT as H, withActorScope as I, XSTATE_TIMER as J, isLazyActorScope as K, resolveRegisteredActorSource as L, allocateChildId as M, assertChildIdFree as N, reserveChildId as O, mapValues as P, createInvokeId as Q, getDelayedTransitions as R, STATE_DELIMITER as S, getEventDescriptorKey as T, getCandidates as U, evaluateCandidate as V, formatTransition as W, XSTATE_STOP as X, NULL_EVENT as Y, toTransitionConfigArray as Z, createInvokeTimeoutEventId as _, createListenerLogic as a, formatRouteTransitions as a0, resolveStateValue as a1, getAllStateNodes as a2, createMachineSnapshot as a3, isInFinalState as a4, createInertActorScope as a5, setInertActorScopeSnapshot as a6, beginSpawnAllocation as a7, attachSnapshotActorRef as a8, macrostep as a9, getAllOwnEvents as aA, matchesEvent as aB, encodeAddressSegment as aC, getRootActorId as aD, RUNTIME_OPERATIONS as aE, withSystemInspector as aF, getSnapshotActorRef as aG, withExecutionIdentity as aH, isInertActorScope as aa, setSnapshotActorRef as ab, cloneMachineSnapshot as ac, transitionNode as ad, getTransitionResult as ae, hasEffect as af, createErrorPlatformEvent as ag, withActorSelf as ah, resolveActionsWithContext as ai, takeSpawnAllocationCounters as aj, mergeActorIdCounters as ak, createSpawnEffect as al, initialMicrostep as am, toStatePath as an, isStateId as ao, getStateNodeByPath as ap, getPersistedSnapshot as aq, createRemoteActorRef as ar, resolveReferencedActor as as, createInvokeTimeoutEvent as at, parseGeneratedActorId as au, ACTOR_REF_TYPE as av, hasAmbientInspector as aw, getProperAncestors as ax, isRemoteActorRef as ay, getActorIdPrefix as az, createSubscriptionLogic as b, createActor as c, getNextSnapshot as d, isMachineSnapshot as e, getStateNodes as f, getInitialSnapshot as g, getAllOwnEventDescriptors as h, isAtomicStateNode as i, matchesState as j, checkStateIn as k, listenerLogic as l, matchesEventDescriptor as m, pathToStateValue as n, toObserver as o, parseDelayToMilliseconds as p, executeEffects as q, isBuiltInExecutableAction as r, subscriptionLogic as s, toArray as t, deliverEvent as u, runStep as v, stopActor as w, terminateActor as x, createInitEvent as y, createCustomEffect as z };
5827
+ export { createInvokeTimeoutEventId as $, Actor as A, createCustomEffect as B, XSTATE_LOGIC_EFFECT_START as C, XSTATE_LOGIC_EFFECT_RESOLVE as D, XSTATE_LOGIC_EFFECT_REJECT as E, finalizeTransitionResult as F, createEmitEffect as G, createSendToEffect as H, XSTATE_INIT as I, withActorScope as J, XSTATE_TIMER as K, isLazyActorScope as L, resolveRegisteredActorSource as M, allocateChildId as N, assertChildIdFree as O, reserveChildId as P, mapValues as Q, createInvokeId as R, STATE_DELIMITER as S, getDelayedTransitions as T, getEventDescriptorKey as U, getCandidates as V, evaluateCandidate as W, XSTATE_STOP as X, formatTransition as Y, NULL_EVENT as Z, toTransitionConfigArray as _, createListenerLogic as a, matchesActorSession as a0, formatRouteTransitions as a1, resolveStateValue as a2, getAllStateNodes as a3, createMachineSnapshot as a4, isInFinalState as a5, createInertActorScope as a6, setInertActorScopeSnapshot as a7, beginSpawnAllocation as a8, attachSnapshotActorRef as a9, getActorIdPrefix as aA, getAllOwnEvents as aB, matchesEvent as aC, encodeAddressSegment as aD, getRootActorId as aE, RUNTIME_OPERATIONS as aF, withSystemInspector as aG, getSnapshotActorRef as aH, withExecutionIdentity as aI, macrostep as aa, isInertActorScope as ab, setSnapshotActorRef as ac, cloneMachineSnapshot as ad, transitionNode as ae, getTransitionResult as af, hasEffect as ag, createErrorPlatformEvent as ah, withActorSelf as ai, resolveActionsWithContext as aj, takeSpawnAllocationCounters as ak, mergeActorIdCounters as al, createSpawnEffect as am, initialMicrostep as an, toStatePath as ao, isStateId as ap, getStateNodeByPath as aq, getPersistedSnapshot as ar, createRemoteActorRef as as, resolveReferencedActor as at, createInvokeTimeoutEvent as au, parseGeneratedActorId as av, ACTOR_REF_TYPE as aw, hasAmbientInspector as ax, getProperAncestors as ay, isRemoteActorRef as az, createSubscriptionLogic as b, createActor as c, getNextSnapshot as d, isMachineSnapshot as e, getStateNodes as f, getInitialSnapshot as g, getAllOwnEventDescriptors as h, isAtomicStateNode as i, matchesState as j, checkStateIn as k, listenerLogic as l, matchesEventDescriptor as m, pathToStateValue as n, toObserver as o, parseDelayToMilliseconds as p, executeEffects as q, isBuiltInExecutableAction as r, subscriptionLogic as s, toArray as t, deliverEvent as u, runStep as v, stopActor as w, terminateActor as x, createInitEvent as y, createDeadLetterEffect as z };
@@ -501,6 +501,25 @@ function createEmitEffect(actorScope, event) {
501
501
  args: []
502
502
  };
503
503
  }
504
+ function execDeadLetterEffect(runtime = this.target.system) {
505
+ return runtime.deadLetter(this.source, this.target, this.event, this.reason, this.detail);
506
+ }
507
+
508
+ /** @internal Creates a dead-letter effect for a boundary-rejected event. */
509
+ function createDeadLetterEffect(actorScope, source, event, reason, detail) {
510
+ return {
511
+ kind: 'builtin',
512
+ type: '@xstate.deadLetter',
513
+ exec: execDeadLetterEffect,
514
+ source,
515
+ target: actorScope.self,
516
+ event,
517
+ reason,
518
+ detail,
519
+ params: undefined,
520
+ args: []
521
+ };
522
+ }
504
523
 
505
524
  /** @internal Creates a directly executable user effect. */
506
525
  function createCustomEffect(type, action, params) {
@@ -4257,21 +4276,42 @@ async function runStep(actor, key, exec, sendSelf = event => void actor.system.s
4257
4276
  * @experimental
4258
4277
  */
4259
4278
  function deliverEvent(source, target, event) {
4260
- assertEventCanBeSent(source, target, event);
4279
+ if (rejectUndeliverableEvent(source, target, event)) {
4280
+ return;
4281
+ }
4261
4282
  const runtimeTarget = target;
4262
4283
  runtimeTarget._lastSourceRef = source;
4263
4284
  runtimeTarget._send(event);
4264
4285
  }
4265
4286
 
4266
4287
  /**
4267
- * Ensures internal events cannot cross an actor boundary from an external
4268
- * sender. Host runtimes must call this before taking ownership of delivery.
4288
+ * Returns the boundary error preventing this delivery, if any: an internal
4289
+ * event type cannot cross an actor boundary from an external sender.
4269
4290
  */
4270
- function assertEventCanBeSent(source, target, event) {
4291
+ function getEventBoundaryError(source, target, event) {
4271
4292
  const runtimeTarget = target;
4272
4293
  if (source !== target && runtimeTarget.logic?.isInternalEventType?.(event.type)) {
4273
- throw new Error(`Internal event "${event.type}" cannot be sent to actor "${target.id}" from outside.`);
4294
+ return new Error(`Internal event "${event.type}" cannot be sent to actor "${target.id}" from outside.`);
4295
+ }
4296
+ return undefined;
4297
+ }
4298
+
4299
+ /**
4300
+ * Rejects an event that must not cross the delivery boundary — an internal
4301
+ * event type sent from outside its owning actor — by reporting it as a dead
4302
+ * letter. Returns `true` when the event was rejected and must not be
4303
+ * delivered. Host runtimes must call this before taking ownership of
4304
+ * delivery.
4305
+ */
4306
+ function rejectUndeliverableEvent(source, target, event) {
4307
+ const error = getEventBoundaryError(source, target, event);
4308
+ if (error) {
4309
+ void target.system.deadLetter(source, target, event, 'internalEvent', {
4310
+ error
4311
+ });
4312
+ return true;
4274
4313
  }
4314
+ return false;
4275
4315
  }
4276
4316
 
4277
4317
  /**
@@ -4472,6 +4512,19 @@ function bookSessionId(system) {
4472
4512
  * other: install a different one via `system.runtime` (for durable hosts,
4473
4513
  * through `createDurable`'s adapter runtime operations).
4474
4514
  */
4515
+ /**
4516
+ * Why an event was not delivered: `'invalidEvent'` (payload failed its
4517
+ * declared schema), `'internalEvent'` (an internal event type sent from
4518
+ * outside its owning actor) or `'stopped'` (the target actor already
4519
+ * stopped). Hosts may report additional reasons.
4520
+ */
4521
+
4522
+ /** Extra detail attached to a dead letter. */
4523
+
4524
+ /**
4525
+ * Describes an event that was rejected at the delivery boundary instead of
4526
+ * being delivered to its target actor (a dead letter).
4527
+ */
4475
4528
 
4476
4529
  /** @internal Every operation of `ActorSystemRuntime`, for runtime wrappers. */
4477
4530
  const RUNTIME_OPERATIONS = ['spawnActor', 'startActor', 'stopActor', 'terminateActor', 'emitEvent', 'scheduleTimer', 'cancelTimer', 'cancelAllTimers', 'deadLetter'
@@ -4534,6 +4587,7 @@ class RuntimeSystem {
4534
4587
  this._clock = void 0;
4535
4588
  this._logger = void 0;
4536
4589
  this.createActorRef = void 0;
4590
+ this._onRejectedEvent = options.onRejectedEvent;
4537
4591
  const restoredSnapshot = typeof options.snapshot === 'object' && options.snapshot !== null ? options.snapshot : undefined;
4538
4592
  this._clock = options.clock;
4539
4593
  this._logger = options.logger;
@@ -4732,7 +4786,9 @@ class RuntimeSystem {
4732
4786
  terminateActor(actor, termination);
4733
4787
  }
4734
4788
  sendEvent(source, target, event) {
4735
- assertEventCanBeSent(source, target, event);
4789
+ if (rejectUndeliverableEvent(source, target, event)) {
4790
+ return;
4791
+ }
4736
4792
  // Record for the inspection `sent[]` facet regardless of which runtime
4737
4793
  // delivers, so host runtimes keep inspection parity.
4738
4794
  this._recordSent(source, target, event);
@@ -4749,17 +4805,29 @@ class RuntimeSystem {
4749
4805
  }
4750
4806
  source._emit(event);
4751
4807
  }
4752
- deadLetter(source, target, event, reason) {
4808
+ deadLetter(source, target, event, reason, detail) {
4753
4809
  this._sendInspectionEvent({
4754
4810
  type: '@xstate.deadletter',
4755
4811
  actorRef: target,
4756
4812
  sourceRef: source,
4757
4813
  event,
4758
- reason
4814
+ reason,
4815
+ issues: detail?.issues,
4816
+ error: detail?.error
4817
+ });
4818
+ this._onRejectedEvent?.({
4819
+ event,
4820
+ targetRef: target,
4821
+ targetId: target.id,
4822
+ sourceRef: source,
4823
+ eventOrigin: source ? 'actor' : 'external',
4824
+ reason,
4825
+ issues: detail?.issues,
4826
+ error: detail?.error
4759
4827
  });
4760
4828
  const override = this.runtime?.deadLetter;
4761
4829
  if (override) {
4762
- return override(source, target, event, reason);
4830
+ return override(source, target, event, reason, detail);
4763
4831
  }
4764
4832
  {
4765
4833
  console.warn(`Event "${event.type}" to actor "${target.id}" was not delivered (${reason}).`);
@@ -5009,7 +5077,8 @@ class Actor {
5009
5077
  clock,
5010
5078
  logger,
5011
5079
  snapshot: resolvedOptions.snapshot ?? resolvedOptions.state,
5012
- createActorRef
5080
+ createActorRef,
5081
+ onRejectedEvent: resolvedOptions.onRejectedEvent
5013
5082
  });
5014
5083
  if (!parent && resolvedOptions._systemRef && !resolvedOptions._systemRef.current) {
5015
5084
  resolvedOptions._systemRef.current = this.system;
@@ -5815,6 +5884,7 @@ exports.checkStateIn = checkStateIn;
5815
5884
  exports.cloneMachineSnapshot = cloneMachineSnapshot;
5816
5885
  exports.createActor = createActor;
5817
5886
  exports.createCustomEffect = createCustomEffect;
5887
+ exports.createDeadLetterEffect = createDeadLetterEffect;
5818
5888
  exports.createEmitEffect = createEmitEffect;
5819
5889
  exports.createErrorPlatformEvent = createErrorPlatformEvent;
5820
5890
  exports.createInertActorScope = createInertActorScope;
@@ -60,6 +60,15 @@ export type EffectDescriptor = {
60
60
  status: 'done' | 'error';
61
61
  output: unknown;
62
62
  error: unknown;
63
+ } | {
64
+ kind: 'builtin';
65
+ type: '@xstate.deadLetter';
66
+ source: string | undefined;
67
+ target: string;
68
+ event: unknown;
69
+ reason: string;
70
+ issues: unknown;
71
+ error: unknown;
63
72
  } | {
64
73
  kind: 'emit';
65
74
  type: string;
@@ -20,7 +20,7 @@ export { isMachineSnapshot, type MachineSnapshot } from "./State.js";
20
20
  export { StateMachine } from "./StateMachine.js";
21
21
  export { StateNode } from "./StateNode.js";
22
22
  export { getStateNodes } from "./stateUtils.js";
23
- export type { ActorSystem, ActorSystemRuntime, AnyActorSystem } from "./system.js";
23
+ export type { ActorSystem, ActorSystemRuntime, AnyActorSystem, DeadLetterDetail, EventRejection, EventRejectionReason } from "./system.js";
24
24
  export { toPromise } from "./toPromise.js";
25
25
  export type * from "./types.js";
26
26
  export { SpecialTargets } from "./types.js";
@@ -1,4 +1,6 @@
1
1
  import { ActorRefLike, AnyActorLogic, AnyEventObject, AnyTransitionDefinition, Snapshot } from "./types.js";
2
+ import type { StandardSchemaV1 } from "./schema.types.js";
3
+ import type { EventRejectionReason } from "./system.js";
2
4
  /**
3
5
  * A record of a single action executed during a transition.
4
6
  *
@@ -89,21 +91,36 @@ export interface TransitionInspectionEvent extends BaseInspectionEventProperties
89
91
  sent: SentRecord[];
90
92
  }
91
93
  /**
92
- * A lossless, two-event inspection protocol:
94
+ * Emitted when an event could not be delivered to its target actor (a dead
95
+ * letter): a send to a stopped actor, an invalid external event payload, or
96
+ * an internal event type sent from outside its owning actor.
93
97
  *
94
- * - `@xstate.actor` — actor topology (identity + parent), drawable up front.
95
- * - `@xstate.transition` — every transition facet: event, snapshot, source,
96
- * microsteps, executed actions, and sent/scheduled events.
98
+ * A dead letter is not an actor error: the target actor's snapshot is
99
+ * unchanged.
97
100
  */
98
- /** Emitted when an event could not be delivered to its target actor. */
99
101
  export interface DeadLetterInspectionEvent extends BaseInspectionEventProperties {
100
102
  type: '@xstate.deadletter';
101
103
  /** The actor that sent the event, or `undefined` when sent externally. */
102
104
  sourceRef: ActorRefLike | undefined;
103
105
  /** The undelivered event. */
104
106
  event: AnyEventObject;
105
- /** Why the event was not delivered, such as `'stopped'`. */
106
- reason: string;
107
+ /**
108
+ * Why the event was not delivered: `'stopped'`, `'invalidEvent'` or
109
+ * `'internalEvent'`.
110
+ */
111
+ reason: EventRejectionReason;
112
+ /** Standard Schema issues for `'invalidEvent'` dead letters. */
113
+ issues?: readonly StandardSchemaV1.Issue[];
114
+ /** The underlying error describing a delivery-boundary rejection. */
115
+ error?: Error;
107
116
  }
117
+ /**
118
+ * A lossless inspection protocol:
119
+ *
120
+ * - `@xstate.actor` — actor topology (identity + parent), drawable up front.
121
+ * - `@xstate.transition` — every transition facet: event, snapshot, source,
122
+ * microsteps, executed actions, and sent/scheduled events.
123
+ * - `@xstate.deadletter` — events that could not be delivered.
124
+ */
108
125
  export type InspectionEvent = ActorInspectionEvent | TransitionInspectionEvent | DeadLetterInspectionEvent;
109
126
  export {};
@@ -18,10 +18,13 @@ export declare function runStep<TStepOutput>(actor: AnyActor, key: string, exec:
18
18
  */
19
19
  export declare function deliverEvent(source: AnyActor | undefined, target: AnyActor, event: AnyEventObject): void;
20
20
  /**
21
- * Ensures internal events cannot cross an actor boundary from an external
22
- * sender. Host runtimes must call this before taking ownership of delivery.
21
+ * Rejects an event that must not cross the delivery boundary — an internal
22
+ * event type sent from outside its owning actor — by reporting it as a dead
23
+ * letter. Returns `true` when the event was rejected and must not be
24
+ * delivered. Host runtimes must call this before taking ownership of
25
+ * delivery.
23
26
  */
24
- export declare function assertEventCanBeSent(source: AnyActor | undefined, target: AnyActor, event: AnyEventObject): void;
27
+ export declare function rejectUndeliverableEvent(source: AnyActor | undefined, target: AnyActor, event: AnyEventObject): boolean;
25
28
  /**
26
29
  * Publishes an actor's terminal result, notifying its parent and observers.
27
30
  * Custom runtimes use this for the default local behavior inside their own
@@ -1,4 +1,5 @@
1
1
  import type { InspectionEvent } from "./inspection.js";
2
+ import type { StandardSchemaV1 } from "./schema.types.js";
2
3
  import { AnyEventObject, ActorTermination, ActorSystemInfo, AnyActor, Observer, EventObject, Subscription } from "./types.js";
3
4
  interface ScheduledTimer {
4
5
  id: string;
@@ -40,6 +41,37 @@ export { hasAmbientInspector, withSystemInspector } from "./inspectionAmbient.js
40
41
  * other: install a different one via `system.runtime` (for durable hosts,
41
42
  * through `createDurable`'s adapter runtime operations).
42
43
  */
44
+ /**
45
+ * Why an event was not delivered: `'invalidEvent'` (payload failed its
46
+ * declared schema), `'internalEvent'` (an internal event type sent from
47
+ * outside its owning actor) or `'stopped'` (the target actor already
48
+ * stopped). Hosts may report additional reasons.
49
+ */
50
+ export type EventRejectionReason = 'invalidEvent' | 'internalEvent' | 'stopped' | (string & {});
51
+ /** Extra detail attached to a dead letter. */
52
+ export interface DeadLetterDetail {
53
+ /** Standard Schema issues for `invalidEvent` rejections. */
54
+ issues?: readonly StandardSchemaV1.Issue[];
55
+ /** The underlying error describing the rejection. */
56
+ error?: Error;
57
+ }
58
+ /**
59
+ * Describes an event that was rejected at the delivery boundary instead of
60
+ * being delivered to its target actor (a dead letter).
61
+ */
62
+ export interface EventRejection extends DeadLetterDetail {
63
+ /** The event that was rejected. */
64
+ event: AnyEventObject;
65
+ /** The actor the event was addressed to. */
66
+ targetRef: AnyActor | undefined;
67
+ /** The `id` of the target actor. */
68
+ targetId: string | undefined;
69
+ /** The actor that sent the event, or `undefined` for an external send. */
70
+ sourceRef: AnyActor | undefined;
71
+ /** Whether the event came from outside the system or from another actor. */
72
+ eventOrigin: 'external' | 'actor';
73
+ reason: EventRejectionReason;
74
+ }
43
75
  export interface ActorSystemRuntime {
44
76
  /** Publishes a newly created actor to the runtime. */
45
77
  spawnActor(source: AnyActor | undefined, actor: AnyActor): void | PromiseLike<void>;
@@ -82,10 +114,12 @@ export interface ActorSystemRuntime {
82
114
  runStep(actor: AnyActor, key: string, exec: () => unknown | PromiseLike<unknown>): unknown | PromiseLike<unknown>;
83
115
  /**
84
116
  * Reports an undeliverable event. Delivery stays at-most-once — this is
85
- * observability, not retry: the default logs in development and emits an
86
- * inspection event.
117
+ * observability, not retry: the default logs in development, emits an
118
+ * inspection event and calls the root actor's `onRejectedEvent` hook.
119
+ * `detail` carries validation issues and the underlying error for events
120
+ * rejected at the delivery boundary.
87
121
  */
88
- deadLetter(source: AnyActor | undefined, target: AnyActor, event: AnyEventObject, reason: string): void | PromiseLike<void>;
122
+ deadLetter(source: AnyActor | undefined, target: AnyActor, event: AnyEventObject, reason: EventRejectionReason, detail?: DeadLetterDetail): void | PromiseLike<void>;
89
123
  /** Cancels all logical timers owned by an actor. */
90
124
  cancelAllTimers(source: AnyActor): void | PromiseLike<void>;
91
125
  }
@@ -124,4 +158,5 @@ export declare function createRuntimeSystem<T extends ActorSystemInfo>(rootActor
124
158
  logger: (...args: any[]) => void;
125
159
  snapshot?: unknown;
126
160
  createActorRef: ActorSystem<T>['createActorRef'];
161
+ onRejectedEvent?: (rejection: EventRejection) => void;
127
162
  }): ActorSystem<T>;
@@ -5,7 +5,7 @@ import { AsyncActorLogic } from "./actors/promise.js";
5
5
  import type { Actor } from "./createActor.js";
6
6
  import { InspectionEvent } from "./inspection.js";
7
7
  import { Spawner } from "./spawn.js";
8
- import type { ActorSystemRuntime, AnyActorSystem, Clock } from "./system.js";
8
+ import type { ActorSystemRuntime, AnyActorSystem, Clock, DeadLetterDetail, EventRejection, EventRejectionReason } from "./system.js";
9
9
  import { Sources, Next_StateNodeConfig } from "./types.v6.js";
10
10
  import { StandardSchemaV1 } from "./schema.types.js";
11
11
  import { builtInActions } from "./actions.js";
@@ -628,7 +628,7 @@ export interface ActorOptions<TLogic extends AnyActorLogic> {
628
628
  *
629
629
  * @remarks
630
630
  * If a callback function is provided, it can accept an inspection event
631
- * argument. The inspection protocol has two event types:
631
+ * argument. The inspection protocol has three event types:
632
632
  *
633
633
  * - `@xstate.actor` - An actor ref was created in the system (announces actor
634
634
  * topology: identity + parent).
@@ -636,6 +636,11 @@ export interface ActorOptions<TLogic extends AnyActorLogic> {
636
636
  * transition with flat, always-present fields: `event`, `snapshot`,
637
637
  * `sourceRef`, `microsteps`, executed `actions`, and `sent`/scheduled
638
638
  * events.
639
+ * - `@xstate.deadletter` - An event could not be delivered: the target actor
640
+ * stopped, the payload failed its declared schema, or an internal event
641
+ * type was sent from outside its owning actor. Carries the `event`,
642
+ * `sourceRef`, `reason`, and — for boundary rejections — `issues` and
643
+ * `error`.
639
644
  *
640
645
  * @example
641
646
  *
@@ -705,6 +710,15 @@ export interface ActorOptions<TLogic extends AnyActorLogic> {
705
710
  * ```
706
711
  */
707
712
  inspect?: Observer<InspectionEvent> | ((inspectionEvent: InspectionEvent) => void);
713
+ /**
714
+ * A dead-letter hook called whenever an event is rejected at the delivery
715
+ * boundary of this actor system — an invalid external event payload or an
716
+ * internal event type sent from outside its owning actor. Rejected events
717
+ * are never delivered and never error the target actor.
718
+ *
719
+ * Only observed when this actor is the root of its system.
720
+ */
721
+ onRejectedEvent?: (rejection: EventRejection) => void;
708
722
  }
709
723
  export type AnyActor = ActorInstance<any, any, any, any>;
710
724
  /** @deprecated Use `AnyActor` instead. */
@@ -1185,6 +1199,24 @@ export type TerminateExecutableActionObject = BaseExecutableActionObject & {
1185
1199
  id: string;
1186
1200
  args: Parameters<(typeof builtInActions)['@xstate.terminate']>;
1187
1201
  } & ActorTermination;
1202
+ /**
1203
+ * An executable effect that reports an event rejected at the delivery boundary
1204
+ * (a dead letter). The snapshot paired with this effect is unchanged.
1205
+ */
1206
+ export interface DeadLetterExecutableActionObject extends BaseExecutableActionObject {
1207
+ kind: 'builtin';
1208
+ type: '@xstate.deadLetter';
1209
+ /** The actor that sent the event, or `undefined` for an external send. */
1210
+ source: AnyActor | undefined;
1211
+ /** The actor that rejected the event. */
1212
+ target: AnyActor;
1213
+ /** The rejected event. */
1214
+ event: AnyEventObject;
1215
+ /** Why the event was rejected, such as `'invalidEvent'`. */
1216
+ reason: EventRejectionReason;
1217
+ detail?: DeadLetterDetail;
1218
+ args: [];
1219
+ }
1188
1220
  export type BuiltInExecutableActionObject = Values<{
1189
1221
  '@xstate.spawn': SpawnExecutableActionObject;
1190
1222
  '@xstate.start': StartExecutableActionObject;
@@ -1193,6 +1225,7 @@ export type BuiltInExecutableActionObject = Values<{
1193
1225
  '@xstate.cancel': CancelExecutableActionObject;
1194
1226
  '@xstate.stop': StopExecutableActionObject;
1195
1227
  '@xstate.terminate': TerminateExecutableActionObject;
1228
+ '@xstate.deadLetter': DeadLetterExecutableActionObject;
1196
1229
  }>;
1197
1230
  export type SpecialExecutableAction = BuiltInExecutableActionObject;
1198
1231
  type TransitionExecutableActionObject<TType extends string = never> = BuiltInExecutableActionObject | EmitExecutableActionObject | CustomExecutableActionObject<TType | (string & {})>;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var createActor = require('./createActor-a1e0dffb.development.cjs.js');
3
+ var createActor = require('./createActor-27fd819f.cjs.js');
4
4
 
5
5
  function attachMicrostepActorRefs(microsteps, actorScope, inputSnapshot) {
6
6
  if (!microsteps.length) {
@@ -267,6 +267,17 @@ function getEffectDescriptor(effect) {
267
267
  output: effect.output,
268
268
  error: effect.error
269
269
  };
270
+ case '@xstate.deadLetter':
271
+ return {
272
+ kind: 'builtin',
273
+ type: '@xstate.deadLetter',
274
+ source: effect.source?.address,
275
+ target: effect.target.address,
276
+ event: effect.event,
277
+ reason: effect.reason,
278
+ issues: effect.detail?.issues,
279
+ error: effect.detail?.error
280
+ };
270
281
  }
271
282
  }
272
283
 
@@ -1,4 +1,4 @@
1
- import { a5 as createInertActorScope, a6 as setInertActorScopeSnapshot, E as finalizeTransitionResult, a8 as attachSnapshotActorRef, y as createInitEvent, aw as hasAmbientInspector, a7 as beginSpawnAllocation, a9 as macrostep, al as createSpawnEffect, am as initialMicrostep, i as isAtomicStateNode, ax as getProperAncestors, ay as isRemoteActorRef, az as getActorIdPrefix } from './createActor-88709f74.development.esm.js';
1
+ import { a6 as createInertActorScope, a7 as setInertActorScopeSnapshot, F as finalizeTransitionResult, a9 as attachSnapshotActorRef, y as createInitEvent, ax as hasAmbientInspector, a8 as beginSpawnAllocation, aa as macrostep, am as createSpawnEffect, an as initialMicrostep, i as isAtomicStateNode, ay as getProperAncestors, az as isRemoteActorRef, aA as getActorIdPrefix } from './createActor-74e185ee.development.esm.js';
2
2
 
3
3
  function attachMicrostepActorRefs(microsteps, actorScope, inputSnapshot) {
4
4
  if (!microsteps.length) {
@@ -265,6 +265,17 @@ function getEffectDescriptor(effect) {
265
265
  output: effect.output,
266
266
  error: effect.error
267
267
  };
268
+ case '@xstate.deadLetter':
269
+ return {
270
+ kind: 'builtin',
271
+ type: '@xstate.deadLetter',
272
+ source: effect.source?.address,
273
+ target: effect.target.address,
274
+ event: effect.event,
275
+ reason: effect.reason,
276
+ issues: effect.detail?.issues,
277
+ error: effect.detail?.error
278
+ };
268
279
  }
269
280
  }
270
281
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var createActor = require('./createActor-b4dd05ae.cjs.js');
3
+ var createActor = require('./createActor-ea9a560c.development.cjs.js');
4
4
 
5
5
  function attachMicrostepActorRefs(microsteps, actorScope, inputSnapshot) {
6
6
  if (!microsteps.length) {
@@ -267,6 +267,17 @@ function getEffectDescriptor(effect) {
267
267
  output: effect.output,
268
268
  error: effect.error
269
269
  };
270
+ case '@xstate.deadLetter':
271
+ return {
272
+ kind: 'builtin',
273
+ type: '@xstate.deadLetter',
274
+ source: effect.source?.address,
275
+ target: effect.target.address,
276
+ event: effect.event,
277
+ reason: effect.reason,
278
+ issues: effect.detail?.issues,
279
+ error: effect.detail?.error
280
+ };
270
281
  }
271
282
  }
272
283