xstate 5.0.0-alpha.6 → 5.0.0-beta.11

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 (94) hide show
  1. package/actions/dist/xstate-actions.cjs.d.mts +2 -0
  2. package/actions/dist/xstate-actions.cjs.d.mts.map +1 -0
  3. package/actions/dist/xstate-actions.cjs.d.ts +1 -0
  4. package/actions/dist/xstate-actions.cjs.d.ts.map +1 -0
  5. package/actions/dist/xstate-actions.cjs.js +29 -5
  6. package/actions/dist/xstate-actions.cjs.mjs +24 -0
  7. package/actions/dist/{xstate-actions.cjs.dev.js → xstate-actions.development.cjs.js} +3 -3
  8. package/actions/dist/xstate-actions.development.esm.js +2 -0
  9. package/actions/dist/xstate-actions.esm.js +2 -2
  10. package/actions/dist/xstate-actions.umd.min.js +1 -1
  11. package/actions/dist/xstate-actions.umd.min.js.map +1 -1
  12. package/actors/dist/xstate-actors.cjs.d.mts +2 -0
  13. package/actors/dist/xstate-actors.cjs.d.mts.map +1 -0
  14. package/actors/dist/xstate-actors.cjs.d.ts +1 -0
  15. package/actors/dist/xstate-actors.cjs.d.ts.map +1 -0
  16. package/actors/dist/xstate-actors.cjs.js +20 -5
  17. package/actors/dist/xstate-actors.cjs.mjs +15 -0
  18. package/actors/dist/{xstate-actors.cjs.dev.js → xstate-actors.development.cjs.js} +3 -2
  19. package/actors/dist/xstate-actors.development.esm.js +2 -0
  20. package/actors/dist/xstate-actors.esm.js +2 -2
  21. package/actors/dist/xstate-actors.umd.min.js +1 -1
  22. package/actors/dist/xstate-actors.umd.min.js.map +1 -1
  23. package/dev/dist/xstate-dev.cjs.d.mts +2 -0
  24. package/dev/dist/xstate-dev.cjs.d.mts.map +1 -0
  25. package/dev/dist/xstate-dev.cjs.d.ts +1 -0
  26. package/dev/dist/xstate-dev.cjs.d.ts.map +1 -0
  27. package/dev/dist/xstate-dev.cjs.js +45 -4
  28. package/dev/dist/xstate-dev.cjs.mjs +5 -0
  29. package/{dist/index-ebaab3c9.cjs.dev.js → dev/dist/xstate-dev.development.cjs.js} +6 -7
  30. package/{dist/index-50bd0aff.esm.js → dev/dist/xstate-dev.development.esm.js} +6 -8
  31. package/dev/dist/xstate-dev.esm.js +42 -1
  32. package/dev/dist/xstate-dev.umd.min.js +1 -1
  33. package/dev/dist/xstate-dev.umd.min.js.map +1 -1
  34. package/dist/actions-26f9aa9d.cjs.js +3388 -0
  35. package/dist/actions-acbe7aa1.development.cjs.js +3423 -0
  36. package/dist/actions-b82e841e.esm.js +3306 -0
  37. package/dist/actions-cff79077.development.esm.js +3341 -0
  38. package/dist/declarations/src/State.d.ts +2 -3
  39. package/dist/declarations/src/StateMachine.d.ts +6 -6
  40. package/dist/declarations/src/StateNode.d.ts +3 -9
  41. package/dist/declarations/src/actions/send.d.ts +0 -7
  42. package/dist/declarations/src/actions.d.ts +9 -8
  43. package/dist/declarations/src/actors/index.d.ts +2 -1
  44. package/dist/declarations/src/actors/observable.d.ts +1 -2
  45. package/dist/declarations/src/actors/promise.d.ts +1 -2
  46. package/dist/declarations/src/guards.d.ts +2 -2
  47. package/dist/declarations/src/index.d.ts +13 -29
  48. package/dist/declarations/src/interpreter.d.ts +5 -4
  49. package/dist/declarations/src/stateUtils.d.ts +9 -14
  50. package/dist/declarations/src/typegenTypes.d.ts +7 -1
  51. package/dist/declarations/src/types.d.ts +18 -92
  52. package/dist/declarations/src/utils.d.ts +3 -6
  53. package/dist/declarations/src/waitFor.d.ts +33 -0
  54. package/dist/xstate.cjs.d.mts +2 -0
  55. package/dist/xstate.cjs.d.mts.map +1 -0
  56. package/dist/xstate.cjs.d.ts +1 -0
  57. package/dist/xstate.cjs.d.ts.map +1 -0
  58. package/dist/xstate.cjs.js +802 -4
  59. package/dist/xstate.cjs.mjs +38 -0
  60. package/dist/xstate.development.cjs.js +808 -0
  61. package/dist/xstate.development.esm.js +770 -0
  62. package/dist/xstate.esm.js +594 -706
  63. package/dist/xstate.umd.min.js +1 -1
  64. package/dist/xstate.umd.min.js.map +1 -1
  65. package/guards/dist/xstate-guards.cjs.d.mts +2 -0
  66. package/guards/dist/xstate-guards.cjs.d.mts.map +1 -0
  67. package/guards/dist/xstate-guards.cjs.d.ts +1 -0
  68. package/guards/dist/xstate-guards.cjs.d.ts.map +1 -0
  69. package/guards/dist/xstate-guards.cjs.js +13 -5
  70. package/guards/dist/xstate-guards.cjs.mjs +8 -0
  71. package/guards/dist/{xstate-guards.cjs.dev.js → xstate-guards.development.cjs.js} +2 -2
  72. package/guards/dist/xstate-guards.development.esm.js +2 -0
  73. package/guards/dist/xstate-guards.esm.js +2 -2
  74. package/guards/dist/xstate-guards.umd.min.js +1 -1
  75. package/guards/dist/xstate-guards.umd.min.js.map +1 -1
  76. package/package.json +58 -1
  77. package/actions/dist/xstate-actions.cjs.prod.js +0 -31
  78. package/actors/dist/xstate-actors.cjs.prod.js +0 -21
  79. package/dev/dist/xstate-dev.cjs.dev.js +0 -11
  80. package/dev/dist/xstate-dev.cjs.prod.js +0 -48
  81. package/dist/actions-41b74cdc.esm.js +0 -4287
  82. package/dist/actions-bf7bb1c5.cjs.dev.js +0 -4342
  83. package/dist/actions-c46e4911.cjs.prod.js +0 -4304
  84. package/dist/declarations/actions/dynamicAction.d.ts +0 -5
  85. package/dist/declarations/src/Mailbox.d.ts +0 -12
  86. package/dist/declarations/src/actions/invoke.d.ts +0 -3
  87. package/dist/declarations/src/environment.d.ts +0 -1
  88. package/dist/declarations/src/memo.d.ts +0 -2
  89. package/dist/declarations/src/schema.d.ts +0 -2
  90. package/dist/declarations/src/spawn.d.ts +0 -2
  91. package/dist/declarations/src/system.d.ts +0 -2
  92. package/dist/xstate.cjs.dev.js +0 -921
  93. package/dist/xstate.cjs.prod.js +0 -921
  94. package/guards/dist/xstate-guards.cjs.prod.js +0 -15
@@ -0,0 +1,3341 @@
1
+ import { devToolsAdapter } from '../dev/dist/xstate-dev.development.esm.js';
2
+
3
+ // https://github.com/microsoft/TypeScript/issues/23182#issuecomment-379091887
4
+
5
+ // TODO: replace in v5 with:
6
+ // export type IndexByType<T extends { type: string }> = { [E in T as E['type']]: E; };
7
+
8
+ /**
9
+ * The full definition of an event, with a string `type`.
10
+ */
11
+
12
+ // TODO: do not accept machines without all implementations
13
+ // we should also accept a raw machine as a behavior here
14
+ // or just make machine a behavior
15
+
16
+ // TODO: narrow this to behaviors from machine
17
+
18
+ // TODO: fix last param
19
+
20
+ /**
21
+ * Extracts action objects that have no extra properties.
22
+ */
23
+
24
+ /**
25
+ * The string or object representing the state value relative to the parent state node.
26
+ *
27
+ * - For a child atomic state node, this is a string, e.g., `"pending"`.
28
+ * - For complex state nodes, this is an object, e.g., `{ success: "someChildState" }`.
29
+ */
30
+
31
+ // TODO: remove once TS fixes this type-widening issue
32
+
33
+ // TODO: possibly refactor this somehow, use even a simpler type, and maybe even make `machine.options` private or something
34
+
35
+ let ActionTypes = /*#__PURE__*/function (ActionTypes) {
36
+ ActionTypes["Stop"] = "xstate.stop";
37
+ ActionTypes["Raise"] = "xstate.raise";
38
+ ActionTypes["Send"] = "xstate.send";
39
+ ActionTypes["Cancel"] = "xstate.cancel";
40
+ ActionTypes["Assign"] = "xstate.assign";
41
+ ActionTypes["After"] = "xstate.after";
42
+ ActionTypes["DoneState"] = "done.state";
43
+ ActionTypes["DoneInvoke"] = "done.invoke";
44
+ ActionTypes["Log"] = "xstate.log";
45
+ ActionTypes["Init"] = "xstate.init";
46
+ ActionTypes["Invoke"] = "xstate.invoke";
47
+ ActionTypes["ErrorExecution"] = "error.execution";
48
+ ActionTypes["ErrorCommunication"] = "error.communication";
49
+ ActionTypes["ErrorPlatform"] = "error.platform";
50
+ ActionTypes["ErrorCustom"] = "xstate.error";
51
+ ActionTypes["Pure"] = "xstate.pure";
52
+ ActionTypes["Choose"] = "xstate.choose";
53
+ return ActionTypes;
54
+ }({});
55
+ let SpecialTargets = /*#__PURE__*/function (SpecialTargets) {
56
+ SpecialTargets["Parent"] = "#_parent";
57
+ SpecialTargets["Internal"] = "#_internal";
58
+ return SpecialTargets;
59
+ }({});
60
+
61
+ // xstate-specific action types
62
+ const stop$1 = ActionTypes.Stop;
63
+ const raise$1 = ActionTypes.Raise;
64
+ const send$1 = ActionTypes.Send;
65
+ const cancel$1 = ActionTypes.Cancel;
66
+ const assign$1 = ActionTypes.Assign;
67
+ const after$1 = ActionTypes.After;
68
+ const doneState = ActionTypes.DoneState;
69
+ const log$1 = ActionTypes.Log;
70
+ const init = ActionTypes.Init;
71
+ const invoke$1 = ActionTypes.Invoke;
72
+ const errorExecution = ActionTypes.ErrorExecution;
73
+ const errorPlatform = ActionTypes.ErrorPlatform;
74
+ const error$1 = ActionTypes.ErrorCustom;
75
+ const choose$1 = ActionTypes.Choose;
76
+ const pure$1 = ActionTypes.Pure;
77
+
78
+ var actionTypes = /*#__PURE__*/Object.freeze({
79
+ __proto__: null,
80
+ stop: stop$1,
81
+ raise: raise$1,
82
+ send: send$1,
83
+ cancel: cancel$1,
84
+ assign: assign$1,
85
+ after: after$1,
86
+ doneState: doneState,
87
+ log: log$1,
88
+ init: init,
89
+ invoke: invoke$1,
90
+ errorExecution: errorExecution,
91
+ errorPlatform: errorPlatform,
92
+ error: error$1,
93
+ choose: choose$1,
94
+ pure: pure$1
95
+ });
96
+
97
+ const STATE_DELIMITER = '.';
98
+ const TARGETLESS_KEY = '';
99
+ const NULL_EVENT = '';
100
+ const STATE_IDENTIFIER = '#';
101
+ const WILDCARD = '*';
102
+
103
+ function matchesState(parentStateId, childStateId, delimiter = STATE_DELIMITER) {
104
+ const parentStateValue = toStateValue(parentStateId, delimiter);
105
+ const childStateValue = toStateValue(childStateId, delimiter);
106
+ if (isString(childStateValue)) {
107
+ if (isString(parentStateValue)) {
108
+ return childStateValue === parentStateValue;
109
+ }
110
+
111
+ // Parent more specific than child
112
+ return false;
113
+ }
114
+ if (isString(parentStateValue)) {
115
+ return parentStateValue in childStateValue;
116
+ }
117
+ return Object.keys(parentStateValue).every(key => {
118
+ if (!(key in childStateValue)) {
119
+ return false;
120
+ }
121
+ return matchesState(parentStateValue[key], childStateValue[key]);
122
+ });
123
+ }
124
+ function toStatePath(stateId, delimiter) {
125
+ try {
126
+ if (isArray(stateId)) {
127
+ return stateId;
128
+ }
129
+ return stateId.toString().split(delimiter);
130
+ } catch (e) {
131
+ throw new Error(`'${stateId}' is not a valid state path.`);
132
+ }
133
+ }
134
+ function isStateLike(state) {
135
+ return typeof state === 'object' && 'value' in state && 'context' in state && 'event' in state;
136
+ }
137
+ function toStateValue(stateValue, delimiter) {
138
+ if (isStateLike(stateValue)) {
139
+ return stateValue.value;
140
+ }
141
+ if (isArray(stateValue)) {
142
+ return pathToStateValue(stateValue);
143
+ }
144
+ if (typeof stateValue !== 'string') {
145
+ return stateValue;
146
+ }
147
+ const statePath = toStatePath(stateValue, delimiter);
148
+ return pathToStateValue(statePath);
149
+ }
150
+ function pathToStateValue(statePath) {
151
+ if (statePath.length === 1) {
152
+ return statePath[0];
153
+ }
154
+ const value = {};
155
+ let marker = value;
156
+ for (let i = 0; i < statePath.length - 1; i++) {
157
+ if (i === statePath.length - 2) {
158
+ marker[statePath[i]] = statePath[i + 1];
159
+ } else {
160
+ marker[statePath[i]] = {};
161
+ marker = marker[statePath[i]];
162
+ }
163
+ }
164
+ return value;
165
+ }
166
+ function mapValues(collection, iteratee) {
167
+ const result = {};
168
+ const collectionKeys = Object.keys(collection);
169
+ for (let i = 0; i < collectionKeys.length; i++) {
170
+ const key = collectionKeys[i];
171
+ result[key] = iteratee(collection[key], key, collection, i);
172
+ }
173
+ return result;
174
+ }
175
+ function flatten(array) {
176
+ return [].concat(...array);
177
+ }
178
+ function toArrayStrict(value) {
179
+ if (isArray(value)) {
180
+ return value;
181
+ }
182
+ return [value];
183
+ }
184
+ function toArray(value) {
185
+ if (value === undefined) {
186
+ return [];
187
+ }
188
+ return toArrayStrict(value);
189
+ }
190
+ function mapContext(mapper, context, event) {
191
+ if (isFunction(mapper)) {
192
+ return mapper({
193
+ context,
194
+ event
195
+ });
196
+ }
197
+ const result = {};
198
+ const args = {
199
+ context,
200
+ event
201
+ };
202
+ for (const key of Object.keys(mapper)) {
203
+ const subMapper = mapper[key];
204
+ if (isFunction(subMapper)) {
205
+ result[key] = subMapper(args);
206
+ } else {
207
+ result[key] = subMapper;
208
+ }
209
+ }
210
+ return result;
211
+ }
212
+ function isPromiseLike(value) {
213
+ if (value instanceof Promise) {
214
+ return true;
215
+ }
216
+ // Check if shape matches the Promise/A+ specification for a "thenable".
217
+ if (value !== null && (isFunction(value) || typeof value === 'object') && isFunction(value.then)) {
218
+ return true;
219
+ }
220
+ return false;
221
+ }
222
+ function isArray(value) {
223
+ return Array.isArray(value);
224
+ }
225
+
226
+ // tslint:disable-next-line:ban-types
227
+ function isFunction(value) {
228
+ return typeof value === 'function';
229
+ }
230
+ function isString(value) {
231
+ return typeof value === 'string';
232
+ }
233
+ function isErrorEvent(event) {
234
+ return typeof event.type === 'string' && (event.type === errorExecution || event.type.startsWith(errorPlatform));
235
+ }
236
+ function toTransitionConfigArray(event, configLike) {
237
+ const transitions = toArrayStrict(configLike).map(transitionLike => {
238
+ if (typeof transitionLike === 'undefined' || typeof transitionLike === 'string') {
239
+ return {
240
+ target: transitionLike,
241
+ event
242
+ };
243
+ }
244
+ return {
245
+ ...transitionLike,
246
+ event
247
+ };
248
+ });
249
+ return transitions;
250
+ }
251
+ function normalizeTarget(target) {
252
+ if (target === undefined || target === TARGETLESS_KEY) {
253
+ return undefined;
254
+ }
255
+ return toArray(target);
256
+ }
257
+ function toInvokeConfig(invocable, id) {
258
+ if (typeof invocable === 'object') {
259
+ if ('src' in invocable) {
260
+ return invocable;
261
+ }
262
+ if ('transition' in invocable) {
263
+ return {
264
+ id,
265
+ src: invocable
266
+ };
267
+ }
268
+ }
269
+ return {
270
+ id,
271
+ src: invocable
272
+ };
273
+ }
274
+ function toObserver(nextHandler, errorHandler, completionHandler) {
275
+ const noop = () => {};
276
+ const isObserver = typeof nextHandler === 'object';
277
+ const self = isObserver ? nextHandler : null;
278
+ return {
279
+ next: ((isObserver ? nextHandler.next : nextHandler) || noop).bind(self),
280
+ error: ((isObserver ? nextHandler.error : errorHandler) || noop).bind(self),
281
+ complete: ((isObserver ? nextHandler.complete : completionHandler) || noop).bind(self)
282
+ };
283
+ }
284
+ function createInvokeId(stateNodeId, index) {
285
+ return `${stateNodeId}:invocation[${index}]`;
286
+ }
287
+ function resolveReferencedActor(referenced) {
288
+ return referenced ? 'transition' in referenced ? {
289
+ src: referenced,
290
+ input: undefined
291
+ } : referenced : undefined;
292
+ }
293
+
294
+ function createDynamicAction(action, resolve) {
295
+ return {
296
+ type: action.type,
297
+ params: action.params,
298
+ resolve
299
+ };
300
+ }
301
+ function isDynamicAction(action) {
302
+ return typeof action === 'object' && action !== null && 'resolve' in action;
303
+ }
304
+
305
+ /**
306
+ * Sends an event. This returns an action that will be read by an interpreter to
307
+ * send the event in the next step, after the current step is finished executing.
308
+ *
309
+ * @deprecated Use the `sendTo(...)` action creator instead.
310
+ *
311
+ * @param eventOrExpr The event to send.
312
+ * @param options Options to pass into the send event:
313
+ * - `id` - The unique send event identifier (used with `cancel()`).
314
+ * - `delay` - The number of milliseconds to delay the sending of the event.
315
+ * - `to` - The target of this event (by default, the machine the event was sent from).
316
+ */
317
+ function send(eventOrExpr, options) {
318
+ return createDynamicAction({
319
+ type: send$1,
320
+ params: {
321
+ to: options ? options.to : undefined,
322
+ delay: options ? options.delay : undefined,
323
+ event: eventOrExpr,
324
+ id: options && options.id !== undefined ? options.id : isFunction(eventOrExpr) ? eventOrExpr.name : eventOrExpr.type
325
+ }
326
+ }, (event, {
327
+ actorContext,
328
+ state
329
+ }) => {
330
+ const params = {
331
+ to: options ? options.to : undefined,
332
+ delay: options ? options.delay : undefined,
333
+ event: eventOrExpr,
334
+ // TODO: don't auto-generate IDs here like that
335
+ // there is too big chance of the ID collision
336
+ id: options && options.id !== undefined ? options.id : isFunction(eventOrExpr) ? eventOrExpr.name : eventOrExpr.type
337
+ };
338
+ const args = {
339
+ context: state.context,
340
+ event,
341
+ self: actorContext?.self ?? null,
342
+ system: actorContext?.system
343
+ };
344
+ const delaysMap = state.machine.options.delays;
345
+
346
+ // TODO: helper function for resolving Expr
347
+ if (typeof eventOrExpr === 'string') {
348
+ throw new Error(`Only event objects may be used with sendTo; use sendTo({ type: "${eventOrExpr}" }) instead`);
349
+ }
350
+ const resolvedEvent = isFunction(eventOrExpr) ? eventOrExpr(args) : eventOrExpr;
351
+ let resolvedDelay;
352
+ if (isString(params.delay)) {
353
+ const configDelay = delaysMap && delaysMap[params.delay];
354
+ resolvedDelay = isFunction(configDelay) ? configDelay(args) : configDelay;
355
+ } else {
356
+ resolvedDelay = isFunction(params.delay) ? params.delay(args) : params.delay;
357
+ }
358
+ const resolvedTarget = isFunction(params.to) ? params.to(args) : params.to;
359
+ let targetActorRef;
360
+ if (typeof resolvedTarget === 'string') {
361
+ if (resolvedTarget === SpecialTargets.Parent) {
362
+ targetActorRef = actorContext?.self._parent;
363
+ } else if (resolvedTarget === SpecialTargets.Internal) {
364
+ targetActorRef = actorContext?.self;
365
+ } else if (resolvedTarget.startsWith('#_')) {
366
+ // SCXML compatibility: https://www.w3.org/TR/scxml/#SCXMLEventProcessor
367
+ // #_invokeid. If the target is the special term '#_invokeid', where invokeid is the invokeid of an SCXML session that the sending session has created by <invoke>, the Processor must add the event to the external queue of that session.
368
+ targetActorRef = state.children[resolvedTarget.slice(2)];
369
+ } else {
370
+ targetActorRef = state.children[resolvedTarget];
371
+ }
372
+ if (!targetActorRef) {
373
+ throw new Error(`Unable to send event to actor '${resolvedTarget}' from machine '${state.machine.id}'.`);
374
+ }
375
+ } else {
376
+ targetActorRef = resolvedTarget || actorContext?.self;
377
+ }
378
+ const resolvedAction = {
379
+ type: send$1,
380
+ params: {
381
+ ...params,
382
+ to: targetActorRef,
383
+ event: resolvedEvent,
384
+ delay: resolvedDelay,
385
+ internal: resolvedTarget === SpecialTargets.Internal
386
+ },
387
+ execute: actorCtx => {
388
+ const sendAction = resolvedAction;
389
+ if (typeof sendAction.params.delay === 'number') {
390
+ actorCtx.self.delaySend(sendAction);
391
+ return;
392
+ } else {
393
+ const target = sendAction.params.to;
394
+ const sentEvent = sendAction.params.event;
395
+ actorCtx.defer(() => {
396
+ target.send(sentEvent.type === error$1 ? {
397
+ type: `${error(actorCtx.self.id)}`,
398
+ data: sentEvent.data
399
+ } : sendAction.params.event);
400
+ });
401
+ }
402
+ }
403
+ };
404
+ return [state, resolvedAction];
405
+ });
406
+ }
407
+
408
+ /**
409
+ * Sends an event to this machine's parent.
410
+ *
411
+ * @param event The event to send to the parent machine.
412
+ * @param options Options to pass into the send event.
413
+ */
414
+ function sendParent(event, options) {
415
+ return send(event, {
416
+ ...options,
417
+ to: SpecialTargets.Parent
418
+ });
419
+ }
420
+
421
+ /**
422
+ * Forwards (sends) an event to a specified service.
423
+ *
424
+ * @param target The target service to forward the event to.
425
+ * @param options Options to pass into the send action creator.
426
+ */
427
+ function forwardTo(target, options) {
428
+ if ((!target || typeof target === 'function')) {
429
+ const originalTarget = target;
430
+ target = (...args) => {
431
+ const resolvedTarget = typeof originalTarget === 'function' ? originalTarget(...args) : originalTarget;
432
+ if (!resolvedTarget) {
433
+ throw new Error(`Attempted to forward event to undefined actor. This risks an infinite loop in the sender.`);
434
+ }
435
+ return resolvedTarget;
436
+ };
437
+ }
438
+ return send(({
439
+ event
440
+ }) => event, {
441
+ ...options,
442
+ to: target
443
+ });
444
+ }
445
+
446
+ /**
447
+ * Escalates an error by sending it as an event to this machine's parent.
448
+ *
449
+ * @param errorData The error data to send, or the expression function that
450
+ * takes in the `context`, `event`, and `meta`, and returns the error data to send.
451
+ * @param options Options to pass into the send action creator.
452
+ */
453
+ function escalate(errorData, options) {
454
+ return sendParent(arg => {
455
+ return {
456
+ type: error$1,
457
+ data: isFunction(errorData) ? errorData(arg) : errorData
458
+ };
459
+ }, {
460
+ ...options,
461
+ to: SpecialTargets.Parent
462
+ });
463
+ }
464
+
465
+ /**
466
+ * Sends an event to an actor.
467
+ *
468
+ * @param actor The `ActorRef` to send the event to.
469
+ * @param event The event to send, or an expression that evaluates to the event to send
470
+ * @param options Send action options
471
+ * @returns An XState send action object
472
+ */
473
+ function sendTo(actor, event, options) {
474
+ return send(event, {
475
+ ...options,
476
+ to: actor
477
+ });
478
+ }
479
+
480
+ class Mailbox {
481
+ constructor(_process) {
482
+ this._process = _process;
483
+ this._active = false;
484
+ this._current = null;
485
+ this._last = null;
486
+ }
487
+ start() {
488
+ this._active = true;
489
+ this.flush();
490
+ }
491
+ clear() {
492
+ // we can't set _current to null because we might be currently processing
493
+ // and enqueue following clear shouldnt start processing the enqueued item immediately
494
+ if (this._current) {
495
+ this._current.next = null;
496
+ this._last = this._current;
497
+ }
498
+ }
499
+
500
+ // TODO: rethink this design
501
+ prepend(event) {
502
+ if (!this._current) {
503
+ this.enqueue(event);
504
+ return;
505
+ }
506
+
507
+ // we know that something is already queued up
508
+ // so the mailbox is already flushing or it's inactive
509
+ // therefore the only thing that we need to do is to reassign `this._current`
510
+ this._current = {
511
+ value: event,
512
+ next: this._current
513
+ };
514
+ }
515
+ enqueue(event) {
516
+ const enqueued = {
517
+ value: event,
518
+ next: null
519
+ };
520
+ if (this._current) {
521
+ this._last.next = enqueued;
522
+ this._last = enqueued;
523
+ return;
524
+ }
525
+ this._current = enqueued;
526
+ this._last = enqueued;
527
+ if (this._active) {
528
+ this.flush();
529
+ }
530
+ }
531
+ flush() {
532
+ while (this._current) {
533
+ // atm the given _process is responsible for implementing proper try/catch handling
534
+ // we assume here that this won't throw in a way that can affect this mailbox
535
+ const consumed = this._current;
536
+ this._process(consumed.value);
537
+ // something could have been prepended in the meantime
538
+ // so we need to be defensive here to avoid skipping over a prepended item
539
+ if (consumed === this._current) {
540
+ this._current = this._current.next;
541
+ }
542
+ }
543
+ this._last = null;
544
+ }
545
+ }
546
+
547
+ const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
548
+
549
+ /**
550
+ * Returns an actor behavior from a transition function and its initial state.
551
+ *
552
+ * A transition function is a function that takes the current state and an event and returns the next state.
553
+ *
554
+ * @param transition The transition function that returns the next state given the current state and event.
555
+ * @param initialState The initial state of the transition function.
556
+ * @returns An actor behavior
557
+ */
558
+ function fromTransition(transition, initialState) {
559
+ const behavior = {
560
+ config: transition,
561
+ transition: (state, event, actorContext) => {
562
+ return transition(state, event, actorContext);
563
+ },
564
+ getInitialState: (_, input) => {
565
+ return typeof initialState === 'function' ? initialState({
566
+ input
567
+ }) : initialState;
568
+ },
569
+ getSnapshot: state => state,
570
+ getPersistedState: state => state,
571
+ restoreState: state => state
572
+ };
573
+ return behavior;
574
+ }
575
+
576
+ function fromPromise(
577
+ // TODO: add types
578
+ promiseCreator) {
579
+ const resolveEventType = '$$xstate.resolve';
580
+ const rejectEventType = '$$xstate.reject';
581
+
582
+ // TODO: add event types
583
+ const behavior = {
584
+ config: promiseCreator,
585
+ transition: (state, event) => {
586
+ if (state.status !== 'active') {
587
+ return state;
588
+ }
589
+ switch (event.type) {
590
+ case resolveEventType:
591
+ return {
592
+ ...state,
593
+ status: 'done',
594
+ data: event.data,
595
+ input: undefined
596
+ };
597
+ case rejectEventType:
598
+ return {
599
+ ...state,
600
+ status: 'error',
601
+ data: event.data,
602
+ input: undefined
603
+ };
604
+ case stopSignalType:
605
+ return {
606
+ ...state,
607
+ status: 'canceled',
608
+ input: undefined
609
+ };
610
+ default:
611
+ return state;
612
+ }
613
+ },
614
+ start: (state, {
615
+ self
616
+ }) => {
617
+ // TODO: determine how to allow customizing this so that promises
618
+ // can be restarted if necessary
619
+ if (state.status !== 'active') {
620
+ return;
621
+ }
622
+ const resolvedPromise = Promise.resolve(promiseCreator({
623
+ input: state.input
624
+ }));
625
+ resolvedPromise.then(response => {
626
+ // TODO: remove this condition once dead letter queue lands
627
+ if (self._state.status !== 'active') {
628
+ return;
629
+ }
630
+ self.send({
631
+ type: resolveEventType,
632
+ data: response
633
+ });
634
+ }, errorData => {
635
+ // TODO: remove this condition once dead letter queue lands
636
+ if (self._state.status !== 'active') {
637
+ return;
638
+ }
639
+ self.send({
640
+ type: rejectEventType,
641
+ data: errorData
642
+ });
643
+ });
644
+ },
645
+ getInitialState: (_, input) => {
646
+ return {
647
+ status: 'active',
648
+ data: undefined,
649
+ input
650
+ };
651
+ },
652
+ getSnapshot: state => state.data,
653
+ getStatus: state => state,
654
+ getPersistedState: state => state,
655
+ restoreState: state => state
656
+ };
657
+ return behavior;
658
+ }
659
+
660
+ // TODO: this likely shouldn't accept TEvent, observable actor doesn't accept external events
661
+ function fromObservable(observableCreator) {
662
+ const nextEventType = '$$xstate.next';
663
+ const errorEventType = '$$xstate.error';
664
+ const completeEventType = '$$xstate.complete';
665
+
666
+ // TODO: add event types
667
+ const behavior = {
668
+ config: observableCreator,
669
+ transition: (state, event, {
670
+ self,
671
+ id,
672
+ defer
673
+ }) => {
674
+ if (state.status !== 'active') {
675
+ return state;
676
+ }
677
+ switch (event.type) {
678
+ case nextEventType:
679
+ // match the exact timing of events sent by machines
680
+ // send actions are not executed immediately
681
+ defer(() => {
682
+ self._parent?.send({
683
+ type: `xstate.snapshot.${id}`,
684
+ data: event.data
685
+ });
686
+ });
687
+ return {
688
+ ...state,
689
+ data: event.data
690
+ };
691
+ case errorEventType:
692
+ return {
693
+ ...state,
694
+ status: 'error',
695
+ input: undefined,
696
+ data: event.data,
697
+ subscription: undefined
698
+ };
699
+ case completeEventType:
700
+ return {
701
+ ...state,
702
+ status: 'done',
703
+ input: undefined,
704
+ subscription: undefined
705
+ };
706
+ case stopSignalType:
707
+ state.subscription.unsubscribe();
708
+ return {
709
+ ...state,
710
+ status: 'canceled',
711
+ input: undefined,
712
+ subscription: undefined
713
+ };
714
+ default:
715
+ return state;
716
+ }
717
+ },
718
+ getInitialState: (_, input) => {
719
+ return {
720
+ subscription: undefined,
721
+ status: 'active',
722
+ data: undefined,
723
+ input
724
+ };
725
+ },
726
+ start: (state, {
727
+ self
728
+ }) => {
729
+ if (state.status === 'done') {
730
+ // Do not restart a completed observable
731
+ return;
732
+ }
733
+ state.subscription = observableCreator({
734
+ input: state.input
735
+ }).subscribe({
736
+ next: value => {
737
+ self.send({
738
+ type: nextEventType,
739
+ data: value
740
+ });
741
+ },
742
+ error: err => {
743
+ self.send({
744
+ type: errorEventType,
745
+ data: err
746
+ });
747
+ },
748
+ complete: () => {
749
+ self.send({
750
+ type: completeEventType
751
+ });
752
+ }
753
+ });
754
+ },
755
+ getSnapshot: state => state.data,
756
+ getPersistedState: ({
757
+ status,
758
+ data,
759
+ input
760
+ }) => ({
761
+ status,
762
+ data,
763
+ input
764
+ }),
765
+ getStatus: state => state,
766
+ restoreState: state => ({
767
+ ...state,
768
+ subscription: undefined
769
+ })
770
+ };
771
+ return behavior;
772
+ }
773
+
774
+ /**
775
+ * Creates an event observable behavior that listens to an observable
776
+ * that delivers event objects.
777
+ *
778
+ *
779
+ * @param lazyObservable A function that creates an observable
780
+ * @returns An event observable behavior
781
+ */
782
+
783
+ function fromEventObservable(lazyObservable) {
784
+ const errorEventType = '$$xstate.error';
785
+ const completeEventType = '$$xstate.complete';
786
+
787
+ // TODO: event types
788
+ const behavior = {
789
+ config: lazyObservable,
790
+ transition: (state, event) => {
791
+ if (state.status !== 'active') {
792
+ return state;
793
+ }
794
+ switch (event.type) {
795
+ case errorEventType:
796
+ return {
797
+ ...state,
798
+ status: 'error',
799
+ input: undefined,
800
+ data: event.data,
801
+ subscription: undefined
802
+ };
803
+ case completeEventType:
804
+ return {
805
+ ...state,
806
+ status: 'done',
807
+ input: undefined,
808
+ subscription: undefined
809
+ };
810
+ case stopSignalType:
811
+ state.subscription.unsubscribe();
812
+ return {
813
+ ...state,
814
+ status: 'canceled',
815
+ input: undefined,
816
+ subscription: undefined
817
+ };
818
+ default:
819
+ return state;
820
+ }
821
+ },
822
+ getInitialState: (_, input) => {
823
+ return {
824
+ subscription: undefined,
825
+ status: 'active',
826
+ data: undefined,
827
+ input
828
+ };
829
+ },
830
+ start: (state, {
831
+ self
832
+ }) => {
833
+ if (state.status === 'done') {
834
+ // Do not restart a completed observable
835
+ return;
836
+ }
837
+ state.subscription = lazyObservable({
838
+ input: state.input
839
+ }).subscribe({
840
+ next: value => {
841
+ self._parent?.send(value);
842
+ },
843
+ error: err => {
844
+ self.send({
845
+ type: errorEventType,
846
+ data: err
847
+ });
848
+ },
849
+ complete: () => {
850
+ self.send({
851
+ type: completeEventType
852
+ });
853
+ }
854
+ });
855
+ },
856
+ getSnapshot: _ => undefined,
857
+ getPersistedState: ({
858
+ status,
859
+ data,
860
+ input
861
+ }) => ({
862
+ status,
863
+ data,
864
+ input
865
+ }),
866
+ getStatus: state => state,
867
+ restoreState: state => ({
868
+ ...state,
869
+ subscription: undefined
870
+ })
871
+ };
872
+ return behavior;
873
+ }
874
+
875
+ function fromCallback(invokeCallback) {
876
+ const behavior = {
877
+ config: invokeCallback,
878
+ start: (_state, {
879
+ self
880
+ }) => {
881
+ self.send({
882
+ type: startSignalType
883
+ });
884
+ },
885
+ transition: (state, event, {
886
+ self,
887
+ id
888
+ }) => {
889
+ if (event.type === startSignalType) {
890
+ const sender = eventForParent => {
891
+ if (state.canceled) {
892
+ return;
893
+ }
894
+ self._parent?.send(eventForParent);
895
+ };
896
+ const receiver = newListener => {
897
+ state.receivers.add(newListener);
898
+ };
899
+ state.dispose = invokeCallback(sender, receiver, {
900
+ input: state.input
901
+ });
902
+ if (isPromiseLike(state.dispose)) {
903
+ state.dispose.then(resolved => {
904
+ self._parent?.send(doneInvoke(id, resolved));
905
+ state.canceled = true;
906
+ }, errorData => {
907
+ state.canceled = true;
908
+ self._parent?.send(error(id, errorData));
909
+ });
910
+ }
911
+ return state;
912
+ }
913
+ if (event.type === stopSignalType) {
914
+ state.canceled = true;
915
+ if (isFunction(state.dispose)) {
916
+ state.dispose();
917
+ }
918
+ return state;
919
+ }
920
+ if (isSignal(event.type)) {
921
+ // TODO: unrecognized signal
922
+ return state;
923
+ }
924
+ if (!isSignal(event.type)) {
925
+ state.receivers.forEach(receiver => receiver(event));
926
+ }
927
+ return state;
928
+ },
929
+ getInitialState: (_, input) => {
930
+ return {
931
+ canceled: false,
932
+ receivers: new Set(),
933
+ dispose: undefined,
934
+ input
935
+ };
936
+ },
937
+ getSnapshot: () => undefined,
938
+ getPersistedState: ({
939
+ input
940
+ }) => input
941
+ };
942
+ return behavior;
943
+ }
944
+
945
+ const startSignalType = 'xstate.init';
946
+ const stopSignalType = 'xstate.stop';
947
+ const startSignal = {
948
+ type: 'xstate.init'
949
+ };
950
+ const stopSignal = {
951
+ type: 'xstate.stop'
952
+ };
953
+ /**
954
+ * An object that expresses the behavior of an actor in reaction to received events,
955
+ * as well as an optionally emitted stream of values.
956
+ *
957
+ * @template TReceived The received event
958
+ * @template TSnapshot The emitted value
959
+ */
960
+
961
+ function isSignal(eventType) {
962
+ return eventType === startSignalType || eventType === stopSignalType;
963
+ }
964
+ function isActorRef(item) {
965
+ return !!item && typeof item === 'object' && typeof item.send === 'function';
966
+ }
967
+
968
+ // TODO: refactor the return type, this could be written in a better way
969
+ // but it's best to avoid unneccessary breaking changes now
970
+ // @deprecated use `interpret(behavior)` instead
971
+ function toActorRef(actorRefLike) {
972
+ return {
973
+ subscribe: () => ({
974
+ unsubscribe: () => void 0
975
+ }),
976
+ id: 'anonymous',
977
+ sessionId: '',
978
+ getSnapshot: () => undefined,
979
+ [symbolObservable]: function () {
980
+ return this;
981
+ },
982
+ status: ActorStatus.Running,
983
+ stop: () => void 0,
984
+ ...actorRefLike
985
+ };
986
+ }
987
+ const emptyBehavior = fromTransition(_ => undefined, undefined);
988
+ function createEmptyActor() {
989
+ return interpret(emptyBehavior);
990
+ }
991
+
992
+ function createSystem() {
993
+ let sessionIdCounter = 0;
994
+ const children = new Map();
995
+ const keyedActors = new Map();
996
+ const reverseKeyedActors = new WeakMap();
997
+ const system = {
998
+ _bookId: () => `x:${sessionIdCounter++}`,
999
+ _register: (sessionId, actorRef) => {
1000
+ children.set(sessionId, actorRef);
1001
+ return sessionId;
1002
+ },
1003
+ _unregister: actorRef => {
1004
+ children.delete(actorRef.sessionId);
1005
+ const systemId = reverseKeyedActors.get(actorRef);
1006
+ if (systemId !== undefined) {
1007
+ keyedActors.delete(systemId);
1008
+ reverseKeyedActors.delete(actorRef);
1009
+ }
1010
+ },
1011
+ get: systemId => {
1012
+ return keyedActors.get(systemId);
1013
+ },
1014
+ _set: (systemId, actorRef) => {
1015
+ const existing = keyedActors.get(systemId);
1016
+ if (existing && existing !== actorRef) {
1017
+ throw new Error(`Actor with system ID '${systemId}' already exists.`);
1018
+ }
1019
+ keyedActors.set(systemId, actorRef);
1020
+ reverseKeyedActors.set(actorRef, systemId);
1021
+ }
1022
+ };
1023
+ return system;
1024
+ }
1025
+
1026
+ let ActorStatus = /*#__PURE__*/function (ActorStatus) {
1027
+ ActorStatus[ActorStatus["NotStarted"] = 0] = "NotStarted";
1028
+ ActorStatus[ActorStatus["Running"] = 1] = "Running";
1029
+ ActorStatus[ActorStatus["Stopped"] = 2] = "Stopped";
1030
+ return ActorStatus;
1031
+ }({});
1032
+ const defaultOptions = {
1033
+ deferEvents: true,
1034
+ clock: {
1035
+ setTimeout: (fn, ms) => {
1036
+ return setTimeout(fn, ms);
1037
+ },
1038
+ clearTimeout: id => {
1039
+ return clearTimeout(id);
1040
+ }
1041
+ },
1042
+ logger: console.log.bind(console),
1043
+ devTools: false
1044
+ };
1045
+ class Interpreter {
1046
+ /**
1047
+ * The current state of the interpreted behavior.
1048
+ */
1049
+
1050
+ /**
1051
+ * The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions.
1052
+ */
1053
+
1054
+ /**
1055
+ * The unique identifier for this actor relative to its parent.
1056
+ */
1057
+
1058
+ /**
1059
+ * Whether the service is started.
1060
+ */
1061
+
1062
+ // Actor Ref
1063
+
1064
+ // TODO: add typings for system
1065
+
1066
+ /**
1067
+ * The globally unique process ID for this invocation.
1068
+ */
1069
+
1070
+ /**
1071
+ * Creates a new Interpreter instance (i.e., service) for the given behavior with the provided options, if any.
1072
+ *
1073
+ * @param behavior The behavior to be interpreted
1074
+ * @param options Interpreter options
1075
+ */
1076
+ constructor(behavior, options) {
1077
+ this.behavior = behavior;
1078
+ this._state = void 0;
1079
+ this.clock = void 0;
1080
+ this.options = void 0;
1081
+ this.id = void 0;
1082
+ this.mailbox = new Mailbox(this._process.bind(this));
1083
+ this.delayedEventsMap = {};
1084
+ this.observers = new Set();
1085
+ this.logger = void 0;
1086
+ this.status = ActorStatus.NotStarted;
1087
+ this._parent = void 0;
1088
+ this.ref = void 0;
1089
+ this._actorContext = void 0;
1090
+ this._systemId = void 0;
1091
+ this.sessionId = void 0;
1092
+ this.system = void 0;
1093
+ this._doneEvent = void 0;
1094
+ this.src = void 0;
1095
+ this._deferred = [];
1096
+ const resolvedOptions = {
1097
+ ...defaultOptions,
1098
+ ...options
1099
+ };
1100
+ const {
1101
+ clock,
1102
+ logger,
1103
+ parent,
1104
+ id,
1105
+ systemId
1106
+ } = resolvedOptions;
1107
+ const self = this;
1108
+ this.system = parent?.system ?? createSystem();
1109
+ if (systemId) {
1110
+ this._systemId = systemId;
1111
+ this.system._set(systemId, this);
1112
+ }
1113
+ this.sessionId = this.system._bookId();
1114
+ this.id = id ?? this.sessionId;
1115
+ this.logger = logger;
1116
+ this.clock = clock;
1117
+ this._parent = parent;
1118
+ this.options = resolvedOptions;
1119
+ this.src = resolvedOptions.src;
1120
+ this.ref = this;
1121
+ this._actorContext = {
1122
+ self,
1123
+ id: this.id,
1124
+ sessionId: this.sessionId,
1125
+ logger: this.logger,
1126
+ defer: fn => {
1127
+ this._deferred.push(fn);
1128
+ },
1129
+ system: this.system,
1130
+ stopChild: child => {
1131
+ if (child._parent !== this) {
1132
+ throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`);
1133
+ }
1134
+ child._stop();
1135
+ }
1136
+ };
1137
+
1138
+ // Ensure that the send method is bound to this interpreter instance
1139
+ // if destructured
1140
+ this.send = this.send.bind(this);
1141
+ this._initState();
1142
+ }
1143
+ _initState() {
1144
+ this._state = this.options.state ? this.behavior.restoreState ? this.behavior.restoreState(this.options.state, this._actorContext) : this.options.state : this.behavior.getInitialState(this._actorContext, this.options?.input);
1145
+ }
1146
+
1147
+ // array of functions to defer
1148
+
1149
+ update(state) {
1150
+ // Update state
1151
+ this._state = state;
1152
+ const snapshot = this.getSnapshot();
1153
+
1154
+ // Execute deferred effects
1155
+ let deferredFn;
1156
+ while (deferredFn = this._deferred.shift()) {
1157
+ deferredFn(state);
1158
+ }
1159
+ for (const observer of this.observers) {
1160
+ observer.next?.(snapshot);
1161
+ }
1162
+ const status = this.behavior.getStatus?.(state);
1163
+ switch (status?.status) {
1164
+ case 'done':
1165
+ this._stopProcedure();
1166
+ this._doneEvent = doneInvoke(this.id, status.data);
1167
+ this._parent?.send(this._doneEvent);
1168
+ this._complete();
1169
+ break;
1170
+ case 'error':
1171
+ this._stopProcedure();
1172
+ this._parent?.send(error(this.id, status.data));
1173
+ this._error(status.data);
1174
+ break;
1175
+ }
1176
+ }
1177
+ subscribe(nextListenerOrObserver, errorListener, completeListener) {
1178
+ const observer = toObserver(nextListenerOrObserver, errorListener, completeListener);
1179
+ this.observers.add(observer);
1180
+ if (this.status === ActorStatus.Stopped) {
1181
+ observer.complete?.();
1182
+ this.observers.delete(observer);
1183
+ }
1184
+ return {
1185
+ unsubscribe: () => {
1186
+ this.observers.delete(observer);
1187
+ }
1188
+ };
1189
+ }
1190
+
1191
+ /**
1192
+ * Adds a state listener that is notified when the statechart has reached its final state.
1193
+ * @param listener The state listener
1194
+ */
1195
+ onDone(listener) {
1196
+ if (this.status === ActorStatus.Stopped && this._doneEvent) {
1197
+ listener(this._doneEvent);
1198
+ } else {
1199
+ this.observers.add({
1200
+ complete: () => {
1201
+ if (this._doneEvent) {
1202
+ listener(this._doneEvent);
1203
+ }
1204
+ }
1205
+ });
1206
+ }
1207
+ return this;
1208
+ }
1209
+
1210
+ /**
1211
+ * Starts the interpreter from the initial state
1212
+ */
1213
+ start() {
1214
+ if (this.status === ActorStatus.Running) {
1215
+ // Do not restart the service if it is already started
1216
+ return this;
1217
+ }
1218
+ this.system._register(this.sessionId, this);
1219
+ if (this._systemId) {
1220
+ this.system._set(this._systemId, this);
1221
+ }
1222
+ this.status = ActorStatus.Running;
1223
+ if (this.behavior.start) {
1224
+ this.behavior.start(this._state, this._actorContext);
1225
+ }
1226
+
1227
+ // TODO: this notifies all subscribers but usually this is redundant
1228
+ // there is no real change happening here
1229
+ // we need to rethink if this needs to be refactored
1230
+ this.update(this._state);
1231
+ if (this.options.devTools) {
1232
+ this.attachDevTools();
1233
+ }
1234
+ this.mailbox.start();
1235
+ return this;
1236
+ }
1237
+ _process(event) {
1238
+ try {
1239
+ const nextState = this.behavior.transition(this._state, event, this._actorContext);
1240
+ this.update(nextState);
1241
+ if (event.type === stopSignalType) {
1242
+ this._stopProcedure();
1243
+ this._complete();
1244
+ }
1245
+ } catch (err) {
1246
+ // TODO: properly handle errors
1247
+ if (this.observers.size > 0) {
1248
+ this.observers.forEach(observer => {
1249
+ observer.error?.(err);
1250
+ });
1251
+ this.stop();
1252
+ } else {
1253
+ throw err;
1254
+ }
1255
+ }
1256
+ }
1257
+ _stop() {
1258
+ if (this.status === ActorStatus.Stopped) {
1259
+ return this;
1260
+ }
1261
+ this.mailbox.clear();
1262
+ if (this.status === ActorStatus.NotStarted) {
1263
+ this.status = ActorStatus.Stopped;
1264
+ return this;
1265
+ }
1266
+ this.mailbox.enqueue({
1267
+ type: stopSignalType
1268
+ });
1269
+ return this;
1270
+ }
1271
+
1272
+ /**
1273
+ * Stops the interpreter and unsubscribe all listeners.
1274
+ */
1275
+ stop() {
1276
+ if (this._parent) {
1277
+ throw new Error('A non-root actor cannot be stopped directly.');
1278
+ }
1279
+ return this._stop();
1280
+ }
1281
+ _complete() {
1282
+ for (const observer of this.observers) {
1283
+ observer.complete?.();
1284
+ }
1285
+ this.observers.clear();
1286
+ }
1287
+ _error(data) {
1288
+ for (const observer of this.observers) {
1289
+ observer.error?.(data);
1290
+ }
1291
+ this.observers.clear();
1292
+ }
1293
+ _stopProcedure() {
1294
+ if (this.status !== ActorStatus.Running) {
1295
+ // Interpreter already stopped; do nothing
1296
+ return this;
1297
+ }
1298
+
1299
+ // Cancel all delayed events
1300
+ for (const key of Object.keys(this.delayedEventsMap)) {
1301
+ this.clock.clearTimeout(this.delayedEventsMap[key]);
1302
+ }
1303
+
1304
+ // TODO: mailbox.reset
1305
+ this.mailbox.clear();
1306
+ // TODO: after `stop` we must prepare ourselves for receiving events again
1307
+ // events sent *after* stop signal must be queued
1308
+ // it seems like this should be the common behavior for all of our consumers
1309
+ // so perhaps this should be unified somehow for all of them
1310
+ this.mailbox = new Mailbox(this._process.bind(this));
1311
+ this.status = ActorStatus.Stopped;
1312
+ this.system._unregister(this);
1313
+ return this;
1314
+ }
1315
+
1316
+ /**
1317
+ * Sends an event to the running interpreter to trigger a transition.
1318
+ *
1319
+ * @param event The event to send
1320
+ */
1321
+ send(event) {
1322
+ if (typeof event === 'string') {
1323
+ throw new Error(`Only event objects may be sent to actors; use .send({ type: "${event}" }) instead`);
1324
+ }
1325
+ if (this.status === ActorStatus.Stopped) {
1326
+ // do nothing
1327
+ {
1328
+ const eventString = JSON.stringify(event);
1329
+ console.warn(`Event "${event.type.toString()}" was sent to stopped actor "${this.id} (${this.sessionId})". This actor has already reached its final state, and will not transition.\nEvent: ${eventString}`);
1330
+ }
1331
+ return;
1332
+ }
1333
+ if (this.status !== ActorStatus.Running && !this.options.deferEvents) {
1334
+ throw new Error(`Event "${event.type}" was sent to uninitialized actor "${this.id
1335
+ // tslint:disable-next-line:max-line-length
1336
+ }". Make sure .start() is called for this actor, or set { deferEvents: true } in the actor options.\nEvent: ${JSON.stringify(event)}`);
1337
+ }
1338
+ this.mailbox.enqueue(event);
1339
+ }
1340
+
1341
+ // TODO: make private (and figure out a way to do this within the machine)
1342
+ delaySend(sendAction) {
1343
+ this.delayedEventsMap[sendAction.params.id] = this.clock.setTimeout(() => {
1344
+ if ('to' in sendAction.params && sendAction.params.to) {
1345
+ sendAction.params.to.send(sendAction.params.event);
1346
+ } else {
1347
+ this.send(sendAction.params.event);
1348
+ }
1349
+ }, sendAction.params.delay);
1350
+ }
1351
+
1352
+ // TODO: make private (and figure out a way to do this within the machine)
1353
+ cancel(sendId) {
1354
+ this.clock.clearTimeout(this.delayedEventsMap[sendId]);
1355
+ delete this.delayedEventsMap[sendId];
1356
+ }
1357
+ attachDevTools() {
1358
+ const {
1359
+ devTools
1360
+ } = this.options;
1361
+ if (devTools) {
1362
+ const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : devToolsAdapter;
1363
+ resolvedDevToolsAdapter(this);
1364
+ }
1365
+ }
1366
+ toJSON() {
1367
+ return {
1368
+ id: this.id
1369
+ };
1370
+ }
1371
+ getPersistedState() {
1372
+ return this.behavior.getPersistedState?.(this._state);
1373
+ }
1374
+ [symbolObservable]() {
1375
+ return this;
1376
+ }
1377
+ getSnapshot() {
1378
+ return this.behavior.getSnapshot ? this.behavior.getSnapshot(this._state) : this._state;
1379
+ }
1380
+ }
1381
+
1382
+ /**
1383
+ * Creates a new Interpreter instance for the given machine with the provided options, if any.
1384
+ *
1385
+ * @param machine The machine to interpret
1386
+ * @param options Interpreter options
1387
+ */
1388
+
1389
+ function interpret(behavior, options) {
1390
+ const interpreter = new Interpreter(behavior, options);
1391
+ return interpreter;
1392
+ }
1393
+
1394
+ /**
1395
+ * Stops an actor.
1396
+ *
1397
+ * @param actorRef The actor to stop.
1398
+ */
1399
+
1400
+ function stop(actorRef) {
1401
+ const actor = actorRef;
1402
+ return createDynamicAction({
1403
+ type: stop$1,
1404
+ params: {
1405
+ actor
1406
+ }
1407
+ }, (event, {
1408
+ state
1409
+ }) => {
1410
+ const actorRefOrString = isFunction(actor) ? actor({
1411
+ context: state.context,
1412
+ event
1413
+ }) : actor;
1414
+ const actorRef = typeof actorRefOrString === 'string' ? state.children[actorRefOrString] : actorRefOrString;
1415
+ return [state, {
1416
+ type: 'xstate.stop',
1417
+ params: {
1418
+ actor: actorRef
1419
+ },
1420
+ execute: actorCtx => {
1421
+ if (!actorRef) {
1422
+ return;
1423
+ }
1424
+ if (actorRef.status !== ActorStatus.Running) {
1425
+ actorCtx.stopChild(actorRef);
1426
+ return;
1427
+ }
1428
+ actorCtx.defer(() => {
1429
+ actorCtx.stopChild(actorRef);
1430
+ });
1431
+ }
1432
+ }];
1433
+ });
1434
+ }
1435
+
1436
+ const defaultLogExpr = ({
1437
+ context,
1438
+ event
1439
+ }) => ({
1440
+ context,
1441
+ event
1442
+ });
1443
+
1444
+ /**
1445
+ *
1446
+ * @param expr The expression function to evaluate which will be logged.
1447
+ * Takes in 2 arguments:
1448
+ * - `ctx` - the current state context
1449
+ * - `event` - the event that caused this action to be executed.
1450
+ * @param label The label to give to the logged expression.
1451
+ */
1452
+
1453
+ function log(expr = defaultLogExpr, label) {
1454
+ return createDynamicAction({
1455
+ type: log$1,
1456
+ params: {
1457
+ label,
1458
+ expr
1459
+ }
1460
+ }, (event, {
1461
+ state,
1462
+ actorContext
1463
+ }) => {
1464
+ const resolvedValue = typeof expr === 'function' ? expr({
1465
+ context: state.context,
1466
+ event,
1467
+ self: actorContext?.self ?? {},
1468
+ system: actorContext?.system
1469
+ }) : expr;
1470
+ return [state, {
1471
+ type: 'xstate.log',
1472
+ params: {
1473
+ label,
1474
+ value: resolvedValue
1475
+ },
1476
+ execute: actorCtx => {
1477
+ if (label) {
1478
+ actorCtx.logger?.(label, resolvedValue);
1479
+ } else {
1480
+ actorCtx.logger?.(resolvedValue);
1481
+ }
1482
+ }
1483
+ }];
1484
+ });
1485
+ }
1486
+
1487
+ /**
1488
+ * Cancels an in-flight `send(...)` action. A canceled sent action will not
1489
+ * be executed, nor will its event be sent, unless it has already been sent
1490
+ * (e.g., if `cancel(...)` is called after the `send(...)` action's `delay`).
1491
+ *
1492
+ * @param sendId The `id` of the `send(...)` action to cancel.
1493
+ */
1494
+
1495
+ function cancel(sendId) {
1496
+ return createDynamicAction({
1497
+ type: cancel$1,
1498
+ params: {
1499
+ sendId
1500
+ }
1501
+ }, (event, {
1502
+ state,
1503
+ actorContext
1504
+ }) => {
1505
+ const resolvedSendId = isFunction(sendId) ? sendId({
1506
+ context: state.context,
1507
+ event,
1508
+ self: actorContext?.self ?? {},
1509
+ system: actorContext?.system
1510
+ }) : sendId;
1511
+ return [state, {
1512
+ type: 'xstate.cancel',
1513
+ params: {
1514
+ sendId: resolvedSendId
1515
+ },
1516
+ execute: actorCtx => {
1517
+ const interpreter = actorCtx.self;
1518
+ interpreter.cancel(resolvedSendId);
1519
+ }
1520
+ }];
1521
+ });
1522
+ }
1523
+
1524
+ const cache = new WeakMap();
1525
+ function memo(object, key, fn) {
1526
+ let memoizedData = cache.get(object);
1527
+ if (!memoizedData) {
1528
+ memoizedData = {
1529
+ [key]: fn()
1530
+ };
1531
+ cache.set(object, memoizedData);
1532
+ } else if (!(key in memoizedData)) {
1533
+ memoizedData[key] = fn();
1534
+ }
1535
+ return memoizedData[key];
1536
+ }
1537
+
1538
+ function stateIn(stateValue) {
1539
+ return {
1540
+ type: 'xstate.guard:in',
1541
+ params: {
1542
+ stateValue
1543
+ },
1544
+ predicate: ({
1545
+ state
1546
+ }) => {
1547
+ if (isString(stateValue) && isStateId(stateValue)) {
1548
+ return state.configuration.some(sn => sn.id === stateValue.slice(1));
1549
+ }
1550
+ return state.matches(stateValue);
1551
+ }
1552
+ };
1553
+ }
1554
+ function not(guard) {
1555
+ return {
1556
+ type: 'xstate.boolean',
1557
+ params: {
1558
+ op: 'not'
1559
+ },
1560
+ children: [toGuardDefinition(guard)],
1561
+ predicate: ({
1562
+ evaluate,
1563
+ guard,
1564
+ context,
1565
+ event,
1566
+ state
1567
+ }) => {
1568
+ return !evaluate(guard.children[0], context, event, state);
1569
+ }
1570
+ };
1571
+ }
1572
+ function and(guards) {
1573
+ return {
1574
+ type: 'xstate.boolean',
1575
+ params: {
1576
+ op: 'and'
1577
+ },
1578
+ children: guards.map(guard => toGuardDefinition(guard)),
1579
+ predicate: ({
1580
+ evaluate,
1581
+ guard,
1582
+ context,
1583
+ event,
1584
+ state
1585
+ }) => {
1586
+ return guard.children.every(childGuard => {
1587
+ return evaluate(childGuard, context, event, state);
1588
+ });
1589
+ }
1590
+ };
1591
+ }
1592
+ function or(guards) {
1593
+ return {
1594
+ type: 'xstate.boolean',
1595
+ params: {
1596
+ op: 'or'
1597
+ },
1598
+ children: guards.map(guard => toGuardDefinition(guard)),
1599
+ predicate: ({
1600
+ evaluate,
1601
+ guard,
1602
+ context,
1603
+ event,
1604
+ state
1605
+ }) => {
1606
+ return guard.children.some(childGuard => {
1607
+ return evaluate(childGuard, context, event, state);
1608
+ });
1609
+ }
1610
+ };
1611
+ }
1612
+ function evaluateGuard(guard, context, event, state) {
1613
+ const {
1614
+ machine
1615
+ } = state;
1616
+ const predicate = machine?.options?.guards?.[guard.type] ?? guard.predicate;
1617
+ if (!predicate) {
1618
+ throw new Error(`Guard '${guard.type}' is not implemented.'.`);
1619
+ }
1620
+ return predicate({
1621
+ context,
1622
+ event,
1623
+ state,
1624
+ guard,
1625
+ evaluate: evaluateGuard
1626
+ });
1627
+ }
1628
+ function toGuardDefinition(guardConfig, getPredicate) {
1629
+ if (isString(guardConfig)) {
1630
+ return {
1631
+ type: guardConfig,
1632
+ predicate: getPredicate?.(guardConfig) || undefined,
1633
+ params: {
1634
+ type: guardConfig
1635
+ }
1636
+ };
1637
+ }
1638
+ if (isFunction(guardConfig)) {
1639
+ return {
1640
+ type: guardConfig.name,
1641
+ predicate: guardConfig,
1642
+ params: {
1643
+ type: guardConfig.name,
1644
+ name: guardConfig.name
1645
+ }
1646
+ };
1647
+ }
1648
+ return {
1649
+ type: guardConfig.type,
1650
+ params: guardConfig.params || guardConfig,
1651
+ children: guardConfig.children?.map(childGuard => toGuardDefinition(childGuard, getPredicate)),
1652
+ predicate: getPredicate?.(guardConfig.type) || guardConfig.predicate
1653
+ };
1654
+ }
1655
+
1656
+ function getOutput(configuration, context, event) {
1657
+ const machine = configuration[0].machine;
1658
+ const finalChildStateNode = configuration.find(stateNode => stateNode.type === 'final' && stateNode.parent === machine.root);
1659
+ return finalChildStateNode && finalChildStateNode.output ? mapContext(finalChildStateNode.output, context, event) : undefined;
1660
+ }
1661
+ const isAtomicStateNode = stateNode => stateNode.type === 'atomic' || stateNode.type === 'final';
1662
+ function getChildren(stateNode) {
1663
+ return Object.values(stateNode.states).filter(sn => sn.type !== 'history');
1664
+ }
1665
+ function getProperAncestors(stateNode, toStateNode) {
1666
+ const ancestors = [];
1667
+
1668
+ // add all ancestors
1669
+ let m = stateNode.parent;
1670
+ while (m && m !== toStateNode) {
1671
+ ancestors.push(m);
1672
+ m = m.parent;
1673
+ }
1674
+ return ancestors;
1675
+ }
1676
+ function getConfiguration(stateNodes) {
1677
+ const configuration = new Set(stateNodes);
1678
+ const configurationSet = new Set(stateNodes);
1679
+ const adjList = getAdjList(configurationSet);
1680
+
1681
+ // add descendants
1682
+ for (const s of configuration) {
1683
+ // if previously active, add existing child nodes
1684
+ if (s.type === 'compound' && (!adjList.get(s) || !adjList.get(s).length)) {
1685
+ getInitialStateNodes(s).forEach(sn => configurationSet.add(sn));
1686
+ } else {
1687
+ if (s.type === 'parallel') {
1688
+ for (const child of getChildren(s)) {
1689
+ if (child.type === 'history') {
1690
+ continue;
1691
+ }
1692
+ if (!configurationSet.has(child)) {
1693
+ for (const initialStateNode of getInitialStateNodes(child)) {
1694
+ configurationSet.add(initialStateNode);
1695
+ }
1696
+ }
1697
+ }
1698
+ }
1699
+ }
1700
+ }
1701
+
1702
+ // add all ancestors
1703
+ for (const s of configurationSet) {
1704
+ let m = s.parent;
1705
+ while (m) {
1706
+ configurationSet.add(m);
1707
+ m = m.parent;
1708
+ }
1709
+ }
1710
+ return configurationSet;
1711
+ }
1712
+ function getValueFromAdj(baseNode, adjList) {
1713
+ const childStateNodes = adjList.get(baseNode);
1714
+ if (!childStateNodes) {
1715
+ return {}; // todo: fix?
1716
+ }
1717
+
1718
+ if (baseNode.type === 'compound') {
1719
+ const childStateNode = childStateNodes[0];
1720
+ if (childStateNode) {
1721
+ if (isAtomicStateNode(childStateNode)) {
1722
+ return childStateNode.key;
1723
+ }
1724
+ } else {
1725
+ return {};
1726
+ }
1727
+ }
1728
+ const stateValue = {};
1729
+ for (const childStateNode of childStateNodes) {
1730
+ stateValue[childStateNode.key] = getValueFromAdj(childStateNode, adjList);
1731
+ }
1732
+ return stateValue;
1733
+ }
1734
+ function getAdjList(configuration) {
1735
+ const adjList = new Map();
1736
+ for (const s of configuration) {
1737
+ if (!adjList.has(s)) {
1738
+ adjList.set(s, []);
1739
+ }
1740
+ if (s.parent) {
1741
+ if (!adjList.has(s.parent)) {
1742
+ adjList.set(s.parent, []);
1743
+ }
1744
+ adjList.get(s.parent).push(s);
1745
+ }
1746
+ }
1747
+ return adjList;
1748
+ }
1749
+ function getStateValue(rootNode, configuration) {
1750
+ const config = getConfiguration(configuration);
1751
+ return getValueFromAdj(rootNode, getAdjList(config));
1752
+ }
1753
+ function isInFinalState(configuration, stateNode = configuration[0].machine.root) {
1754
+ if (stateNode.type === 'compound') {
1755
+ return getChildren(stateNode).some(s => s.type === 'final' && configuration.includes(s));
1756
+ }
1757
+ if (stateNode.type === 'parallel') {
1758
+ return getChildren(stateNode).every(sn => isInFinalState(configuration, sn));
1759
+ }
1760
+ return false;
1761
+ }
1762
+ const isStateId = str => str[0] === STATE_IDENTIFIER;
1763
+ function getCandidates(stateNode, receivedEventType) {
1764
+ const candidates = stateNode.transitions.filter(transition => {
1765
+ const {
1766
+ eventType
1767
+ } = transition;
1768
+ // First, check the trivial case: event names are exactly equal
1769
+ if (eventType === receivedEventType) {
1770
+ return true;
1771
+ }
1772
+
1773
+ // Then, check if transition is a wildcard transition,
1774
+ // which matches any non-transient events
1775
+ if (eventType === WILDCARD) {
1776
+ return true;
1777
+ }
1778
+ if (!eventType.endsWith('.*')) {
1779
+ return false;
1780
+ }
1781
+ if (/.*\*.+/.test(eventType)) {
1782
+ console.warn(`Wildcards can only be the last token of an event descriptor (e.g., "event.*") or the entire event descriptor ("*"). Check the "${eventType}" event.`);
1783
+ }
1784
+ const partialEventTokens = eventType.split('.');
1785
+ const eventTokens = receivedEventType.split('.');
1786
+ for (let tokenIndex = 0; tokenIndex < partialEventTokens.length; tokenIndex++) {
1787
+ const partialEventToken = partialEventTokens[tokenIndex];
1788
+ const eventToken = eventTokens[tokenIndex];
1789
+ if (partialEventToken === '*') {
1790
+ const isLastToken = tokenIndex === partialEventTokens.length - 1;
1791
+ if (!isLastToken) {
1792
+ console.warn(`Infix wildcards in transition events are not allowed. Check the "${eventType}" event.`);
1793
+ }
1794
+ return isLastToken;
1795
+ }
1796
+ if (partialEventToken !== eventToken) {
1797
+ return false;
1798
+ }
1799
+ }
1800
+ return true;
1801
+ });
1802
+ return candidates;
1803
+ }
1804
+
1805
+ /**
1806
+ * All delayed transitions from the config.
1807
+ */
1808
+ function getDelayedTransitions(stateNode) {
1809
+ const afterConfig = stateNode.config.after;
1810
+ if (!afterConfig) {
1811
+ return [];
1812
+ }
1813
+ const mutateEntryExit = (delay, i) => {
1814
+ const delayRef = isFunction(delay) ? `${stateNode.id}:delay[${i}]` : delay;
1815
+ const eventType = after(delayRef, stateNode.id);
1816
+ stateNode.entry.push(raise({
1817
+ type: eventType
1818
+ }, {
1819
+ delay
1820
+ }));
1821
+ stateNode.exit.push(cancel(eventType));
1822
+ return eventType;
1823
+ };
1824
+ const delayedTransitions = isArray(afterConfig) ? afterConfig.map((transition, i) => {
1825
+ const eventType = mutateEntryExit(transition.delay, i);
1826
+ return {
1827
+ ...transition,
1828
+ event: eventType
1829
+ };
1830
+ }) : Object.keys(afterConfig).flatMap((delay, i) => {
1831
+ const configTransition = afterConfig[delay];
1832
+ const resolvedTransition = isString(configTransition) ? {
1833
+ target: configTransition
1834
+ } : configTransition;
1835
+ const resolvedDelay = !isNaN(+delay) ? +delay : delay;
1836
+ const eventType = mutateEntryExit(resolvedDelay, i);
1837
+ return toArray(resolvedTransition).map(transition => ({
1838
+ ...transition,
1839
+ event: eventType,
1840
+ delay: resolvedDelay
1841
+ }));
1842
+ });
1843
+ return delayedTransitions.map(delayedTransition => {
1844
+ const {
1845
+ delay
1846
+ } = delayedTransition;
1847
+ return {
1848
+ ...formatTransition(stateNode, delayedTransition),
1849
+ delay
1850
+ };
1851
+ });
1852
+ }
1853
+ function formatTransition(stateNode, transitionConfig) {
1854
+ const normalizedTarget = normalizeTarget(transitionConfig.target);
1855
+ const reenter = transitionConfig.reenter ?? false;
1856
+ const {
1857
+ guards
1858
+ } = stateNode.machine.options;
1859
+ const target = resolveTarget(stateNode, normalizedTarget);
1860
+
1861
+ // TODO: should this be part of a lint rule instead?
1862
+ if (transitionConfig.cond) {
1863
+ throw new Error(`State "${stateNode.id}" has declared \`cond\` for one of its transitions. This property has been renamed to \`guard\`. Please update your code.`);
1864
+ }
1865
+ const transition = {
1866
+ ...transitionConfig,
1867
+ actions: toActionObjects(toArray(transitionConfig.actions)),
1868
+ guard: transitionConfig.guard ? toGuardDefinition(transitionConfig.guard, guardType => guards[guardType]) : undefined,
1869
+ target,
1870
+ source: stateNode,
1871
+ reenter,
1872
+ eventType: transitionConfig.event,
1873
+ toJSON: () => ({
1874
+ ...transition,
1875
+ source: `#${stateNode.id}`,
1876
+ target: target ? target.map(t => `#${t.id}`) : undefined
1877
+ })
1878
+ };
1879
+ return transition;
1880
+ }
1881
+ function formatTransitions(stateNode) {
1882
+ const transitionConfigs = [];
1883
+ if (Array.isArray(stateNode.config.on)) {
1884
+ transitionConfigs.push(...stateNode.config.on);
1885
+ } else if (stateNode.config.on) {
1886
+ const {
1887
+ [WILDCARD]: wildcardConfigs = [],
1888
+ ...namedTransitionConfigs
1889
+ } = stateNode.config.on;
1890
+ for (const eventType of Object.keys(namedTransitionConfigs)) {
1891
+ if (eventType === NULL_EVENT) {
1892
+ throw new Error('Null events ("") cannot be specified as a transition key. Use `always: { ... }` instead.');
1893
+ }
1894
+ const eventTransitionConfigs = toTransitionConfigArray(eventType, namedTransitionConfigs[eventType]);
1895
+ transitionConfigs.push(...eventTransitionConfigs);
1896
+ // TODO: add dev-mode validation for unreachable transitions
1897
+ }
1898
+
1899
+ transitionConfigs.push(...toTransitionConfigArray(WILDCARD, wildcardConfigs));
1900
+ }
1901
+ const doneConfig = stateNode.config.onDone ? toTransitionConfigArray(String(done(stateNode.id)), stateNode.config.onDone) : [];
1902
+ const invokeConfig = stateNode.invoke.flatMap(invokeDef => {
1903
+ const settleTransitions = [];
1904
+ if (invokeDef.onDone) {
1905
+ settleTransitions.push(...toTransitionConfigArray(`done.invoke.${invokeDef.id}`, invokeDef.onDone));
1906
+ }
1907
+ if (invokeDef.onError) {
1908
+ settleTransitions.push(...toTransitionConfigArray(`error.platform.${invokeDef.id}`, invokeDef.onError));
1909
+ }
1910
+ if (invokeDef.onSnapshot) {
1911
+ settleTransitions.push(...toTransitionConfigArray(`xstate.snapshot.${invokeDef.id}`, invokeDef.onSnapshot));
1912
+ }
1913
+ return settleTransitions;
1914
+ });
1915
+ const delayedTransitions = stateNode.after;
1916
+ const formattedTransitions = [...doneConfig, ...invokeConfig, ...transitionConfigs].flatMap(transitionConfig => toArray(transitionConfig).map(transition => formatTransition(stateNode, transition)));
1917
+ for (const delayedTransition of delayedTransitions) {
1918
+ formattedTransitions.push(delayedTransition);
1919
+ }
1920
+ return formattedTransitions;
1921
+ }
1922
+ function formatInitialTransition(stateNode, _target) {
1923
+ if (isString(_target) || isArray(_target)) {
1924
+ const targets = toArray(_target).map(t => {
1925
+ // Resolve state string keys (which represent children)
1926
+ // to their state node
1927
+ const descStateNode = isString(t) ? isStateId(t) ? stateNode.machine.getStateNodeById(t) : stateNode.states[t] : t;
1928
+ if (!descStateNode) {
1929
+ throw new Error(`Initial state node "${t}" not found on parent state node #${stateNode.id}`);
1930
+ }
1931
+ if (!isDescendant(descStateNode, stateNode)) {
1932
+ throw new Error(`Invalid initial target: state node #${descStateNode.id} is not a descendant of #${stateNode.id}`);
1933
+ }
1934
+ return descStateNode;
1935
+ });
1936
+ const resolvedTarget = resolveTarget(stateNode, targets);
1937
+ const transition = {
1938
+ source: stateNode,
1939
+ actions: [],
1940
+ eventType: null,
1941
+ reenter: false,
1942
+ target: resolvedTarget,
1943
+ toJSON: () => ({
1944
+ ...transition,
1945
+ source: `#${stateNode.id}`,
1946
+ target: resolvedTarget ? resolvedTarget.map(t => `#${t.id}`) : undefined
1947
+ })
1948
+ };
1949
+ return transition;
1950
+ }
1951
+ return formatTransition(stateNode, {
1952
+ target: toArray(_target.target).map(t => {
1953
+ if (isString(t)) {
1954
+ return isStateId(t) ? t : `${stateNode.machine.delimiter}${t}`;
1955
+ }
1956
+ return t;
1957
+ }),
1958
+ actions: _target.actions,
1959
+ event: null
1960
+ });
1961
+ }
1962
+ function resolveTarget(stateNode, targets) {
1963
+ if (targets === undefined) {
1964
+ // an undefined target signals that the state node should not transition from that state when receiving that event
1965
+ return undefined;
1966
+ }
1967
+ return targets.map(target => {
1968
+ if (!isString(target)) {
1969
+ return target;
1970
+ }
1971
+ if (isStateId(target)) {
1972
+ return stateNode.machine.getStateNodeById(target);
1973
+ }
1974
+ const isInternalTarget = target[0] === stateNode.machine.delimiter;
1975
+ // If internal target is defined on machine,
1976
+ // do not include machine key on target
1977
+ if (isInternalTarget && !stateNode.parent) {
1978
+ return getStateNodeByPath(stateNode, target.slice(1));
1979
+ }
1980
+ const resolvedTarget = isInternalTarget ? stateNode.key + target : target;
1981
+ if (stateNode.parent) {
1982
+ try {
1983
+ const targetStateNode = getStateNodeByPath(stateNode.parent, resolvedTarget);
1984
+ return targetStateNode;
1985
+ } catch (err) {
1986
+ throw new Error(`Invalid transition definition for state node '${stateNode.id}':\n${err.message}`);
1987
+ }
1988
+ } else {
1989
+ throw new Error(`Invalid target: "${target}" is not a valid target from the root node. Did you mean ".${target}"?`);
1990
+ }
1991
+ });
1992
+ }
1993
+ function resolveHistoryTarget(stateNode) {
1994
+ const normalizedTarget = normalizeTarget(stateNode.target);
1995
+ if (!normalizedTarget) {
1996
+ return stateNode.parent.initial.target;
1997
+ }
1998
+ return normalizedTarget.map(t => typeof t === 'string' ? getStateNodeByPath(stateNode.parent, t) : t);
1999
+ }
2000
+ function isHistoryNode(stateNode) {
2001
+ return stateNode.type === 'history';
2002
+ }
2003
+ function getInitialStateNodes(stateNode) {
2004
+ const set = new Set();
2005
+ function iter(descStateNode) {
2006
+ if (set.has(descStateNode)) {
2007
+ return;
2008
+ }
2009
+ set.add(descStateNode);
2010
+ if (descStateNode.type === 'compound') {
2011
+ for (const targetStateNode of descStateNode.initial.target) {
2012
+ for (const a of getProperAncestors(targetStateNode, stateNode)) {
2013
+ set.add(a);
2014
+ }
2015
+ iter(targetStateNode);
2016
+ }
2017
+ } else if (descStateNode.type === 'parallel') {
2018
+ for (const child of getChildren(descStateNode)) {
2019
+ iter(child);
2020
+ }
2021
+ }
2022
+ }
2023
+ iter(stateNode);
2024
+ return [...set];
2025
+ }
2026
+ /**
2027
+ * Returns the child state node from its relative `stateKey`, or throws.
2028
+ */
2029
+ function getStateNode(stateNode, stateKey) {
2030
+ if (isStateId(stateKey)) {
2031
+ return stateNode.machine.getStateNodeById(stateKey);
2032
+ }
2033
+ if (!stateNode.states) {
2034
+ throw new Error(`Unable to retrieve child state '${stateKey}' from '${stateNode.id}'; no child states exist.`);
2035
+ }
2036
+ const result = stateNode.states[stateKey];
2037
+ if (!result) {
2038
+ throw new Error(`Child state '${stateKey}' does not exist on '${stateNode.id}'`);
2039
+ }
2040
+ return result;
2041
+ }
2042
+
2043
+ /**
2044
+ * Returns the relative state node from the given `statePath`, or throws.
2045
+ *
2046
+ * @param statePath The string or string array relative path to the state node.
2047
+ */
2048
+ function getStateNodeByPath(stateNode, statePath) {
2049
+ if (typeof statePath === 'string' && isStateId(statePath)) {
2050
+ try {
2051
+ return stateNode.machine.getStateNodeById(statePath);
2052
+ } catch (e) {
2053
+ // try individual paths
2054
+ // throw e;
2055
+ }
2056
+ }
2057
+ const arrayStatePath = toStatePath(statePath, stateNode.machine.delimiter).slice();
2058
+ let currentStateNode = stateNode;
2059
+ while (arrayStatePath.length) {
2060
+ const key = arrayStatePath.shift();
2061
+ if (!key.length) {
2062
+ break;
2063
+ }
2064
+ currentStateNode = getStateNode(currentStateNode, key);
2065
+ }
2066
+ return currentStateNode;
2067
+ }
2068
+
2069
+ /**
2070
+ * Returns the state nodes represented by the current state value.
2071
+ *
2072
+ * @param state The state value or State instance
2073
+ */
2074
+ function getStateNodes(stateNode, state) {
2075
+ const stateValue = state instanceof State ? state.value : toStateValue(state, stateNode.machine.delimiter);
2076
+ if (isString(stateValue)) {
2077
+ return [stateNode, stateNode.states[stateValue]];
2078
+ }
2079
+ const childStateKeys = Object.keys(stateValue);
2080
+ const childStateNodes = childStateKeys.map(subStateKey => getStateNode(stateNode, subStateKey)).filter(Boolean);
2081
+ return [stateNode.machine.root, stateNode].concat(childStateNodes, childStateKeys.reduce((allSubStateNodes, subStateKey) => {
2082
+ const subStateNode = getStateNode(stateNode, subStateKey);
2083
+ if (!subStateNode) {
2084
+ return allSubStateNodes;
2085
+ }
2086
+ const subStateNodes = getStateNodes(subStateNode, stateValue[subStateKey]);
2087
+ return allSubStateNodes.concat(subStateNodes);
2088
+ }, []));
2089
+ }
2090
+ function transitionAtomicNode(stateNode, stateValue, state, event) {
2091
+ const childStateNode = getStateNode(stateNode, stateValue);
2092
+ const next = childStateNode.next(state, event);
2093
+ if (!next || !next.length) {
2094
+ return stateNode.next(state, event);
2095
+ }
2096
+ return next;
2097
+ }
2098
+ function transitionCompoundNode(stateNode, stateValue, state, event) {
2099
+ const subStateKeys = Object.keys(stateValue);
2100
+ const childStateNode = getStateNode(stateNode, subStateKeys[0]);
2101
+ const next = transitionNode(childStateNode, stateValue[subStateKeys[0]], state, event);
2102
+ if (!next || !next.length) {
2103
+ return stateNode.next(state, event);
2104
+ }
2105
+ return next;
2106
+ }
2107
+ function transitionParallelNode(stateNode, stateValue, state, event) {
2108
+ const allInnerTransitions = [];
2109
+ for (const subStateKey of Object.keys(stateValue)) {
2110
+ const subStateValue = stateValue[subStateKey];
2111
+ if (!subStateValue) {
2112
+ continue;
2113
+ }
2114
+ const subStateNode = getStateNode(stateNode, subStateKey);
2115
+ const innerTransitions = transitionNode(subStateNode, subStateValue, state, event);
2116
+ if (innerTransitions) {
2117
+ allInnerTransitions.push(...innerTransitions);
2118
+ }
2119
+ }
2120
+ if (!allInnerTransitions.length) {
2121
+ return stateNode.next(state, event);
2122
+ }
2123
+ return allInnerTransitions;
2124
+ }
2125
+ function transitionNode(stateNode, stateValue, state, event) {
2126
+ // leaf node
2127
+ if (isString(stateValue)) {
2128
+ return transitionAtomicNode(stateNode, stateValue, state, event);
2129
+ }
2130
+
2131
+ // compound node
2132
+ if (Object.keys(stateValue).length === 1) {
2133
+ return transitionCompoundNode(stateNode, stateValue, state, event);
2134
+ }
2135
+
2136
+ // parallel node
2137
+ return transitionParallelNode(stateNode, stateValue, state, event);
2138
+ }
2139
+ function getHistoryNodes(stateNode) {
2140
+ return Object.keys(stateNode.states).map(key => stateNode.states[key]).filter(sn => sn.type === 'history');
2141
+ }
2142
+ function isDescendant(childStateNode, parentStateNode) {
2143
+ let marker = childStateNode;
2144
+ while (marker.parent && marker.parent !== parentStateNode) {
2145
+ marker = marker.parent;
2146
+ }
2147
+ return marker.parent === parentStateNode;
2148
+ }
2149
+ function getPathFromRootToNode(stateNode) {
2150
+ const path = [];
2151
+ let marker = stateNode.parent;
2152
+ while (marker) {
2153
+ path.unshift(marker);
2154
+ marker = marker.parent;
2155
+ }
2156
+ return path;
2157
+ }
2158
+ function hasIntersection(s1, s2) {
2159
+ const set1 = new Set(s1);
2160
+ const set2 = new Set(s2);
2161
+ for (const item of set1) {
2162
+ if (set2.has(item)) {
2163
+ return true;
2164
+ }
2165
+ }
2166
+ for (const item of set2) {
2167
+ if (set1.has(item)) {
2168
+ return true;
2169
+ }
2170
+ }
2171
+ return false;
2172
+ }
2173
+ function removeConflictingTransitions(enabledTransitions, configuration, historyValue) {
2174
+ const filteredTransitions = new Set();
2175
+ for (const t1 of enabledTransitions) {
2176
+ let t1Preempted = false;
2177
+ const transitionsToRemove = new Set();
2178
+ for (const t2 of filteredTransitions) {
2179
+ if (hasIntersection(computeExitSet([t1], configuration, historyValue), computeExitSet([t2], configuration, historyValue))) {
2180
+ if (isDescendant(t1.source, t2.source)) {
2181
+ transitionsToRemove.add(t2);
2182
+ } else {
2183
+ t1Preempted = true;
2184
+ break;
2185
+ }
2186
+ }
2187
+ }
2188
+ if (!t1Preempted) {
2189
+ for (const t3 of transitionsToRemove) {
2190
+ filteredTransitions.delete(t3);
2191
+ }
2192
+ filteredTransitions.add(t1);
2193
+ }
2194
+ }
2195
+ return Array.from(filteredTransitions);
2196
+ }
2197
+ function findLCCA(stateNodes) {
2198
+ const [head] = stateNodes;
2199
+ let current = getPathFromRootToNode(head);
2200
+ let candidates = [];
2201
+ for (const stateNode of stateNodes) {
2202
+ const path = getPathFromRootToNode(stateNode);
2203
+ candidates = current.filter(sn => path.includes(sn));
2204
+ current = candidates;
2205
+ candidates = [];
2206
+ }
2207
+ return current[current.length - 1];
2208
+ }
2209
+ function getEffectiveTargetStates(transition, historyValue) {
2210
+ if (!transition.target) {
2211
+ return [];
2212
+ }
2213
+ const targets = new Set();
2214
+ for (const targetNode of transition.target) {
2215
+ if (isHistoryNode(targetNode)) {
2216
+ if (historyValue[targetNode.id]) {
2217
+ for (const node of historyValue[targetNode.id]) {
2218
+ targets.add(node);
2219
+ }
2220
+ } else {
2221
+ for (const node of getEffectiveTargetStates({
2222
+ target: resolveHistoryTarget(targetNode)
2223
+ }, historyValue)) {
2224
+ targets.add(node);
2225
+ }
2226
+ }
2227
+ } else {
2228
+ targets.add(targetNode);
2229
+ }
2230
+ }
2231
+ return [...targets];
2232
+ }
2233
+ function getTransitionDomain(transition, historyValue) {
2234
+ const targetStates = getEffectiveTargetStates(transition, historyValue);
2235
+ if (!targetStates) {
2236
+ return null;
2237
+ }
2238
+ if (!transition.reenter && transition.source.type !== 'parallel' && targetStates.every(targetStateNode => isDescendant(targetStateNode, transition.source))) {
2239
+ return transition.source;
2240
+ }
2241
+ const lcca = findLCCA(targetStates.concat(transition.source));
2242
+ return lcca;
2243
+ }
2244
+ function computeExitSet(transitions, configuration, historyValue) {
2245
+ const statesToExit = new Set();
2246
+ for (const t of transitions) {
2247
+ if (t.target?.length) {
2248
+ const domain = getTransitionDomain(t, historyValue);
2249
+ for (const stateNode of configuration) {
2250
+ if (isDescendant(stateNode, domain)) {
2251
+ statesToExit.add(stateNode);
2252
+ }
2253
+ }
2254
+ }
2255
+ }
2256
+ return [...statesToExit];
2257
+ }
2258
+
2259
+ /**
2260
+ * https://www.w3.org/TR/scxml/#microstepProcedure
2261
+ *
2262
+ * @private
2263
+ * @param transitions
2264
+ * @param currentState
2265
+ * @param mutConfiguration
2266
+ */
2267
+
2268
+ function microstep(transitions, currentState, actorCtx, event) {
2269
+ const {
2270
+ machine
2271
+ } = currentState;
2272
+ // Transition will "apply" if:
2273
+ // - the state node is the initial state (there is no current state)
2274
+ // - OR there are transitions
2275
+ const willTransition = currentState._initial || transitions.length > 0;
2276
+ const mutConfiguration = new Set(currentState.configuration);
2277
+ if (!currentState._initial && !willTransition) {
2278
+ const inertState = cloneState(currentState, {
2279
+ event,
2280
+ actions: [],
2281
+ transitions: []
2282
+ });
2283
+ inertState.changed = false;
2284
+ return inertState;
2285
+ }
2286
+ const microstate = microstepProcedure(currentState._initial ? [{
2287
+ target: [...currentState.configuration].filter(isAtomicStateNode),
2288
+ source: machine.root,
2289
+ reenter: true,
2290
+ actions: [],
2291
+ eventType: null,
2292
+ toJSON: null // TODO: fix
2293
+ }] : transitions, currentState, mutConfiguration, event, actorCtx);
2294
+ const {
2295
+ context,
2296
+ actions: nonRaisedActions
2297
+ } = microstate;
2298
+ const children = setChildren(currentState, nonRaisedActions);
2299
+ const nextState = cloneState(microstate, {
2300
+ value: {},
2301
+ // TODO: make optional
2302
+ transitions,
2303
+ children
2304
+ });
2305
+ nextState.changed = currentState._initial ? undefined : !stateValuesEqual(nextState.value, currentState.value) || nextState.actions.length > 0 || context !== currentState.context;
2306
+ return nextState;
2307
+ }
2308
+ function setChildren(currentState, nonRaisedActions) {
2309
+ const children = {
2310
+ ...currentState.children
2311
+ };
2312
+ for (const action of nonRaisedActions) {
2313
+ if (action.type === invoke$1 && action.params.ref) {
2314
+ const ref = action.params.ref;
2315
+ if (ref) {
2316
+ children[ref.id] = ref;
2317
+ }
2318
+ } else if (action.type === stop$1) {
2319
+ const ref = action.params.actor;
2320
+ if (ref) {
2321
+ delete children[ref.id];
2322
+ }
2323
+ }
2324
+ }
2325
+ return children;
2326
+ }
2327
+ function microstepProcedure(transitions, currentState, mutConfiguration, event, actorCtx) {
2328
+ const actions = [];
2329
+ const historyValue = {
2330
+ ...currentState.historyValue
2331
+ };
2332
+ const filteredTransitions = removeConflictingTransitions(transitions, mutConfiguration, historyValue);
2333
+ const internalQueue = [...currentState._internalQueue];
2334
+
2335
+ // Exit states
2336
+ if (!currentState._initial) {
2337
+ exitStates(filteredTransitions, mutConfiguration, historyValue, actions);
2338
+ }
2339
+
2340
+ // Execute transition content
2341
+ actions.push(...filteredTransitions.flatMap(t => t.actions));
2342
+
2343
+ // Enter states
2344
+ enterStates(filteredTransitions, mutConfiguration, actions, internalQueue, currentState, historyValue);
2345
+ const nextConfiguration = [...mutConfiguration];
2346
+ const done = isInFinalState(nextConfiguration);
2347
+ if (done) {
2348
+ const finalActions = nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit);
2349
+ actions.push(...finalActions);
2350
+ }
2351
+ try {
2352
+ const {
2353
+ nextState
2354
+ } = resolveActionsAndContext(actions, event, currentState, actorCtx);
2355
+ const output = done ? getOutput(nextConfiguration, nextState.context, event) : undefined;
2356
+ internalQueue.push(...nextState._internalQueue);
2357
+ return cloneState(currentState, {
2358
+ actions: nextState.actions,
2359
+ configuration: nextConfiguration,
2360
+ historyValue,
2361
+ _internalQueue: internalQueue,
2362
+ context: nextState.context,
2363
+ event,
2364
+ done,
2365
+ output,
2366
+ children: nextState.children
2367
+ });
2368
+ } catch (e) {
2369
+ // TODO: Refactor this once proper error handling is implemented.
2370
+ // See https://github.com/statelyai/rfcs/pull/4
2371
+ throw e;
2372
+ }
2373
+ }
2374
+ function enterStates(filteredTransitions, mutConfiguration, actions, internalQueue, currentState, historyValue) {
2375
+ const statesToEnter = new Set();
2376
+ const statesForDefaultEntry = new Set();
2377
+ computeEntrySet(filteredTransitions, historyValue, statesForDefaultEntry, statesToEnter);
2378
+
2379
+ // In the initial state, the root state node is "entered".
2380
+ if (currentState._initial) {
2381
+ statesForDefaultEntry.add(currentState.machine.root);
2382
+ }
2383
+ for (const stateNodeToEnter of [...statesToEnter].sort((a, b) => a.order - b.order)) {
2384
+ mutConfiguration.add(stateNodeToEnter);
2385
+ for (const invokeDef of stateNodeToEnter.invoke) {
2386
+ actions.push(invoke(invokeDef));
2387
+ }
2388
+
2389
+ // Add entry actions
2390
+ actions.push(...stateNodeToEnter.entry);
2391
+ if (statesForDefaultEntry.has(stateNodeToEnter)) {
2392
+ for (const stateNode of statesForDefaultEntry) {
2393
+ const initialActions = stateNode.initial.actions;
2394
+ actions.push(...initialActions);
2395
+ }
2396
+ }
2397
+ if (stateNodeToEnter.type === 'final') {
2398
+ const parent = stateNodeToEnter.parent;
2399
+ if (!parent.parent) {
2400
+ continue;
2401
+ }
2402
+ internalQueue.push(done(parent.id, stateNodeToEnter.output ? mapContext(stateNodeToEnter.output, currentState.context, currentState.event) : undefined));
2403
+ if (parent.parent) {
2404
+ const grandparent = parent.parent;
2405
+ if (grandparent.type === 'parallel') {
2406
+ if (getChildren(grandparent).every(parentNode => isInFinalState([...mutConfiguration], parentNode))) {
2407
+ internalQueue.push(done(grandparent.id));
2408
+ }
2409
+ }
2410
+ }
2411
+ }
2412
+ }
2413
+ }
2414
+ function computeEntrySet(transitions, historyValue, statesForDefaultEntry, statesToEnter) {
2415
+ for (const t of transitions) {
2416
+ for (const s of t.target || []) {
2417
+ addDescendantStatesToEnter(s, historyValue, statesForDefaultEntry, statesToEnter);
2418
+ }
2419
+ const ancestor = getTransitionDomain(t, historyValue);
2420
+ const targetStates = getEffectiveTargetStates(t, historyValue);
2421
+ for (const s of targetStates) {
2422
+ addAncestorStatesToEnter(s, ancestor, statesToEnter, historyValue, statesForDefaultEntry);
2423
+ }
2424
+ }
2425
+ }
2426
+ function addDescendantStatesToEnter(stateNode, historyValue, statesForDefaultEntry, statesToEnter) {
2427
+ if (isHistoryNode(stateNode)) {
2428
+ if (historyValue[stateNode.id]) {
2429
+ const historyStateNodes = historyValue[stateNode.id];
2430
+ for (const s of historyStateNodes) {
2431
+ addDescendantStatesToEnter(s, historyValue, statesForDefaultEntry, statesToEnter);
2432
+ }
2433
+ for (const s of historyStateNodes) {
2434
+ addAncestorStatesToEnter(s, stateNode.parent, statesToEnter, historyValue, statesForDefaultEntry);
2435
+ for (const stateForDefaultEntry of statesForDefaultEntry) {
2436
+ statesForDefaultEntry.add(stateForDefaultEntry);
2437
+ }
2438
+ }
2439
+ } else {
2440
+ const targets = resolveHistoryTarget(stateNode);
2441
+ for (const s of targets) {
2442
+ addDescendantStatesToEnter(s, historyValue, statesForDefaultEntry, statesToEnter);
2443
+ }
2444
+ for (const s of targets) {
2445
+ addAncestorStatesToEnter(s, stateNode, statesToEnter, historyValue, statesForDefaultEntry);
2446
+ for (const stateForDefaultEntry of statesForDefaultEntry) {
2447
+ statesForDefaultEntry.add(stateForDefaultEntry);
2448
+ }
2449
+ }
2450
+ }
2451
+ } else {
2452
+ statesToEnter.add(stateNode);
2453
+ if (stateNode.type === 'compound') {
2454
+ statesForDefaultEntry.add(stateNode);
2455
+ const initialStates = stateNode.initial.target;
2456
+ for (const initialState of initialStates) {
2457
+ addDescendantStatesToEnter(initialState, historyValue, statesForDefaultEntry, statesToEnter);
2458
+ }
2459
+ for (const initialState of initialStates) {
2460
+ addAncestorStatesToEnter(initialState, stateNode, statesToEnter, historyValue, statesForDefaultEntry);
2461
+ }
2462
+ } else {
2463
+ if (stateNode.type === 'parallel') {
2464
+ for (const child of getChildren(stateNode).filter(sn => !isHistoryNode(sn))) {
2465
+ if (![...statesToEnter].some(s => isDescendant(s, child))) {
2466
+ addDescendantStatesToEnter(child, historyValue, statesForDefaultEntry, statesToEnter);
2467
+ }
2468
+ }
2469
+ }
2470
+ }
2471
+ }
2472
+ }
2473
+ function addAncestorStatesToEnter(stateNode, toStateNode, statesToEnter, historyValue, statesForDefaultEntry) {
2474
+ const properAncestors = getProperAncestors(stateNode, toStateNode);
2475
+ for (const anc of properAncestors) {
2476
+ statesToEnter.add(anc);
2477
+ if (anc.type === 'parallel') {
2478
+ for (const child of getChildren(anc).filter(sn => !isHistoryNode(sn))) {
2479
+ if (![...statesToEnter].some(s => isDescendant(s, child))) {
2480
+ addDescendantStatesToEnter(child, historyValue, statesForDefaultEntry, statesToEnter);
2481
+ }
2482
+ }
2483
+ }
2484
+ }
2485
+ }
2486
+ function exitStates(transitions, mutConfiguration, historyValue, actions) {
2487
+ const statesToExit = computeExitSet(transitions, mutConfiguration, historyValue);
2488
+ statesToExit.sort((a, b) => b.order - a.order);
2489
+
2490
+ // From SCXML algorithm: https://www.w3.org/TR/scxml/#exitStates
2491
+ for (const exitStateNode of statesToExit) {
2492
+ for (const historyNode of getHistoryNodes(exitStateNode)) {
2493
+ let predicate;
2494
+ if (historyNode.history === 'deep') {
2495
+ predicate = sn => isAtomicStateNode(sn) && isDescendant(sn, exitStateNode);
2496
+ } else {
2497
+ predicate = sn => {
2498
+ return sn.parent === exitStateNode;
2499
+ };
2500
+ }
2501
+ historyValue[historyNode.id] = Array.from(mutConfiguration).filter(predicate);
2502
+ }
2503
+ }
2504
+ for (const s of statesToExit) {
2505
+ actions.push(...s.exit.flat(), ...s.invoke.map(def => stop(def.id)));
2506
+ mutConfiguration.delete(s);
2507
+ }
2508
+ }
2509
+ function resolveActionsAndContext(actions, event, currentState, actorCtx) {
2510
+ const {
2511
+ machine
2512
+ } = currentState;
2513
+ const resolvedActions = [];
2514
+ const raiseActions = [];
2515
+ let intermediateState = currentState;
2516
+ function handleAction(action) {
2517
+ resolvedActions.push(action);
2518
+ if (actorCtx?.self.status === ActorStatus.Running) {
2519
+ action.execute?.(actorCtx);
2520
+ // TODO: this is hacky; re-evaluate
2521
+ delete action.execute;
2522
+ }
2523
+ }
2524
+ function resolveAction(actionObject) {
2525
+ const executableActionObject = resolveActionObject(actionObject, machine.options.actions);
2526
+ if (isDynamicAction(executableActionObject)) {
2527
+ const [nextState, resolvedAction] = executableActionObject.resolve(event, {
2528
+ state: intermediateState,
2529
+ action: actionObject,
2530
+ actorContext: actorCtx
2531
+ });
2532
+ const matchedActions = resolvedAction.params?.actions;
2533
+ intermediateState = nextState;
2534
+ if ((resolvedAction.type === raise$1 || resolvedAction.type === send$1 && resolvedAction.params.internal) && typeof resolvedAction.params.delay !== 'number') {
2535
+ raiseActions.push(resolvedAction);
2536
+ }
2537
+
2538
+ // TODO: remove the check; just handleAction
2539
+ if (resolvedAction.type !== pure$1) {
2540
+ handleAction(resolvedAction);
2541
+ }
2542
+ toActionObjects(matchedActions).forEach(resolveAction);
2543
+ return;
2544
+ }
2545
+ handleAction(executableActionObject);
2546
+ }
2547
+ for (const actionObject of actions) {
2548
+ resolveAction(actionObject);
2549
+ }
2550
+ return {
2551
+ nextState: cloneState(intermediateState, {
2552
+ actions: resolvedActions,
2553
+ _internalQueue: raiseActions.map(a => a.params.event)
2554
+ })
2555
+ };
2556
+ }
2557
+ function macrostep(state, event, actorCtx) {
2558
+ if (event.type === WILDCARD) {
2559
+ throw new Error(`An event cannot have the wildcard type ('${WILDCARD}')`);
2560
+ }
2561
+ let nextState = state;
2562
+ const states = [];
2563
+
2564
+ // Handle stop event
2565
+ if (event.type === stopSignalType) {
2566
+ nextState = stopStep(event, nextState, actorCtx);
2567
+ states.push(nextState);
2568
+ return {
2569
+ state: nextState,
2570
+ microstates: states
2571
+ };
2572
+ }
2573
+
2574
+ // Assume the state is at rest (no raised events)
2575
+ // Determine the next state based on the next microstep
2576
+ if (event.type !== init) {
2577
+ const transitions = selectTransitions(event, nextState);
2578
+ nextState = microstep(transitions, state, actorCtx, event);
2579
+ states.push(nextState);
2580
+ }
2581
+ while (!nextState.done) {
2582
+ let enabledTransitions = selectEventlessTransitions(nextState);
2583
+ if (enabledTransitions.length === 0) {
2584
+ // TODO: this is a bit of a hack, we need to review this
2585
+ // this matches the behavior from v4 for eventless transitions
2586
+ // where for `hasAlwaysTransitions` we were always trying to resolve with a NULL event
2587
+ // and if a transition was not selected the `state.transitions` stayed empty
2588
+ // without this we get into an infinite loop in the dieHard test in `@xstate/test` for the `simplePathsTo`
2589
+ if (nextState.configuration.some(state => state.always)) {
2590
+ nextState.transitions = [];
2591
+ }
2592
+ if (!nextState._internalQueue.length) {
2593
+ break;
2594
+ } else {
2595
+ const currentActions = nextState.actions;
2596
+ const nextEvent = nextState._internalQueue[0];
2597
+ const transitions = selectTransitions(nextEvent, nextState);
2598
+ nextState = microstep(transitions, nextState, actorCtx, nextEvent);
2599
+ nextState._internalQueue.shift();
2600
+ nextState.actions.unshift(...currentActions);
2601
+ states.push(nextState);
2602
+ }
2603
+ }
2604
+ if (enabledTransitions.length) {
2605
+ const currentActions = nextState.actions;
2606
+ nextState = microstep(enabledTransitions, nextState, actorCtx, nextState.event);
2607
+ nextState.actions.unshift(...currentActions);
2608
+ states.push(nextState);
2609
+ }
2610
+ }
2611
+ if (nextState.done) {
2612
+ // Perform the stop step to ensure that child actors are stopped
2613
+ stopStep(nextState.event, nextState, actorCtx);
2614
+ }
2615
+ return {
2616
+ state: nextState,
2617
+ microstates: states
2618
+ };
2619
+ }
2620
+ function stopStep(event, nextState, actorCtx) {
2621
+ const actions = [];
2622
+ for (const stateNode of nextState.configuration.sort((a, b) => b.order - a.order)) {
2623
+ actions.push(...stateNode.exit);
2624
+ }
2625
+ for (const child of Object.values(nextState.children)) {
2626
+ actions.push(stop(child));
2627
+ }
2628
+ const {
2629
+ nextState: stoppedState
2630
+ } = resolveActionsAndContext(actions, event, nextState, actorCtx);
2631
+ return stoppedState;
2632
+ }
2633
+ function selectTransitions(event, nextState) {
2634
+ return nextState.machine.getTransitionData(nextState, event);
2635
+ }
2636
+ function selectEventlessTransitions(nextState) {
2637
+ const enabledTransitionSet = new Set();
2638
+ const atomicStates = nextState.configuration.filter(isAtomicStateNode);
2639
+ for (const stateNode of atomicStates) {
2640
+ loop: for (const s of [stateNode].concat(getProperAncestors(stateNode, null))) {
2641
+ if (!s.always) {
2642
+ continue;
2643
+ }
2644
+ for (const transition of s.always) {
2645
+ if (transition.guard === undefined || evaluateGuard(transition.guard, nextState.context, nextState.event, nextState)) {
2646
+ enabledTransitionSet.add(transition);
2647
+ break loop;
2648
+ }
2649
+ }
2650
+ }
2651
+ }
2652
+ return removeConflictingTransitions(Array.from(enabledTransitionSet), new Set(nextState.configuration), nextState.historyValue);
2653
+ }
2654
+
2655
+ /**
2656
+ * Resolves a partial state value with its full representation in the state node's machine.
2657
+ *
2658
+ * @param stateValue The partial state value to resolve.
2659
+ */
2660
+ function resolveStateValue(rootNode, stateValue) {
2661
+ const configuration = getConfiguration(getStateNodes(rootNode, stateValue));
2662
+ return getStateValue(rootNode, [...configuration]);
2663
+ }
2664
+ function stateValuesEqual(a, b) {
2665
+ if (a === b) {
2666
+ return true;
2667
+ }
2668
+ if (a === undefined || b === undefined) {
2669
+ return false;
2670
+ }
2671
+ if (isString(a) || isString(b)) {
2672
+ return a === b;
2673
+ }
2674
+ const aKeys = Object.keys(a);
2675
+ const bKeys = Object.keys(b);
2676
+ return aKeys.length === bKeys.length && aKeys.every(key => stateValuesEqual(a[key], b[key]));
2677
+ }
2678
+ function getInitialConfiguration(rootNode) {
2679
+ const configuration = [];
2680
+ const initialTransition = rootNode.initial;
2681
+ const statesToEnter = new Set();
2682
+ const statesForDefaultEntry = new Set([rootNode]);
2683
+ computeEntrySet([initialTransition], {}, statesForDefaultEntry, statesToEnter);
2684
+ for (const stateNodeToEnter of [...statesToEnter].sort((a, b) => a.order - b.order)) {
2685
+ configuration.push(stateNodeToEnter);
2686
+ }
2687
+ return configuration;
2688
+ }
2689
+
2690
+ class State {
2691
+ /**
2692
+ * Indicates whether the state is a final state.
2693
+ */
2694
+
2695
+ /**
2696
+ * The done data of the top-level finite state.
2697
+ */
2698
+ // TODO: add an explicit type for `output`
2699
+
2700
+ /**
2701
+ * Indicates whether the state has changed from the previous state. A state is considered "changed" if:
2702
+ *
2703
+ * - Its value is not equal to its previous value, or:
2704
+ * - It has any new actions (side-effects) to execute.
2705
+ *
2706
+ * An initial state (with no history) will return `undefined`.
2707
+ */
2708
+
2709
+ /**
2710
+ * The enabled state nodes representative of the state value.
2711
+ */
2712
+
2713
+ /**
2714
+ * The transition definitions that resulted in this state.
2715
+ */
2716
+
2717
+ /**
2718
+ * An object mapping actor names to spawned/invoked actors.
2719
+ */
2720
+
2721
+ /**
2722
+ * Creates a new State instance for the given `stateValue` and `context`.
2723
+ * @param stateValue
2724
+ * @param context
2725
+ */
2726
+ static from(stateValue, context = {}, machine) {
2727
+ if (stateValue instanceof State) {
2728
+ if (stateValue.context !== context) {
2729
+ return new State({
2730
+ value: stateValue.value,
2731
+ context,
2732
+ event: stateValue.event,
2733
+ actions: [],
2734
+ meta: {},
2735
+ configuration: [],
2736
+ // TODO: fix,
2737
+ transitions: [],
2738
+ children: {}
2739
+ }, machine);
2740
+ }
2741
+ return stateValue;
2742
+ }
2743
+ const event = createInitEvent({}); // TODO: fix
2744
+
2745
+ const configuration = getConfiguration(getStateNodes(machine.root, stateValue));
2746
+ return new State({
2747
+ value: stateValue,
2748
+ context,
2749
+ event,
2750
+ actions: [],
2751
+ meta: undefined,
2752
+ configuration: Array.from(configuration),
2753
+ transitions: [],
2754
+ children: {}
2755
+ }, machine);
2756
+ }
2757
+
2758
+ /**
2759
+ * Creates a new `State` instance that represents the current state of a running machine.
2760
+ *
2761
+ * @param config
2762
+ */
2763
+ constructor(config, machine) {
2764
+ this.machine = machine;
2765
+ this.tags = void 0;
2766
+ this.value = void 0;
2767
+ this.done = void 0;
2768
+ this.output = void 0;
2769
+ this.context = void 0;
2770
+ this.historyValue = {};
2771
+ this.actions = [];
2772
+ this.event = void 0;
2773
+ this._internalQueue = void 0;
2774
+ this._initial = false;
2775
+ this.changed = void 0;
2776
+ this.configuration = void 0;
2777
+ this.transitions = void 0;
2778
+ this.children = void 0;
2779
+ this.context = config.context;
2780
+ this._internalQueue = config._internalQueue ?? [];
2781
+ this.event = config.event;
2782
+ this.historyValue = config.historyValue || {};
2783
+ this.actions = config.actions ?? [];
2784
+ this.matches = this.matches.bind(this);
2785
+ this.toStrings = this.toStrings.bind(this);
2786
+ this.configuration = config.configuration ?? Array.from(getConfiguration(getStateNodes(machine.root, config.value)));
2787
+ this.transitions = config.transitions;
2788
+ this.children = config.children;
2789
+ this.value = getStateValue(machine.root, this.configuration);
2790
+ this.tags = new Set(flatten(this.configuration.map(sn => sn.tags)));
2791
+ this.done = config.done ?? false;
2792
+ this.output = config.output;
2793
+ }
2794
+
2795
+ /**
2796
+ * Returns an array of all the string leaf state node paths.
2797
+ * @param stateValue
2798
+ * @param delimiter The character(s) that separate each subpath in the string state node path.
2799
+ */
2800
+ toStrings(stateValue = this.value, delimiter = '.') {
2801
+ if (isString(stateValue)) {
2802
+ return [stateValue];
2803
+ }
2804
+ const valueKeys = Object.keys(stateValue);
2805
+ return valueKeys.concat(...valueKeys.map(key => this.toStrings(stateValue[key], delimiter).map(s => key + delimiter + s)));
2806
+ }
2807
+ toJSON() {
2808
+ const {
2809
+ configuration,
2810
+ transitions,
2811
+ tags,
2812
+ machine,
2813
+ ...jsonValues
2814
+ } = this;
2815
+ return {
2816
+ ...jsonValues,
2817
+ tags: Array.from(tags),
2818
+ meta: this.meta
2819
+ };
2820
+ }
2821
+
2822
+ /**
2823
+ * Whether the current state value is a subset of the given parent state value.
2824
+ * @param parentStateValue
2825
+ */
2826
+ matches(parentStateValue) {
2827
+ return matchesState(parentStateValue, this.value);
2828
+ }
2829
+
2830
+ /**
2831
+ * Whether the current state configuration has a state node with the specified `tag`.
2832
+ * @param tag
2833
+ */
2834
+ hasTag(tag) {
2835
+ return this.tags.has(tag);
2836
+ }
2837
+
2838
+ /**
2839
+ * Determines whether sending the `event` will cause a non-forbidden transition
2840
+ * to be selected, even if the transitions have no actions nor
2841
+ * change the state value.
2842
+ *
2843
+ * @param event The event to test
2844
+ * @returns Whether the event will cause a transition
2845
+ */
2846
+ can(event) {
2847
+ if (!this.machine) {
2848
+ console.warn(`state.can(...) used outside of a machine-created State object; this will always return false.`);
2849
+ }
2850
+ const transitionData = this.machine.getTransitionData(this, event);
2851
+ return !!transitionData?.length &&
2852
+ // Check that at least one transition is not forbidden
2853
+ transitionData.some(t => t.target !== undefined || t.actions.length);
2854
+ }
2855
+
2856
+ /**
2857
+ * The next events that will cause a transition from the current state.
2858
+ */
2859
+ get nextEvents() {
2860
+ return memo(this, 'nextEvents', () => {
2861
+ return [...new Set(flatten([...this.configuration.map(sn => sn.ownEvents)]))];
2862
+ });
2863
+ }
2864
+ get meta() {
2865
+ return this.configuration.reduce((acc, stateNode) => {
2866
+ if (stateNode.meta !== undefined) {
2867
+ acc[stateNode.id] = stateNode.meta;
2868
+ }
2869
+ return acc;
2870
+ }, {});
2871
+ }
2872
+ }
2873
+ function cloneState(state, config = {}) {
2874
+ return new State({
2875
+ ...state,
2876
+ ...config
2877
+ }, state.machine);
2878
+ }
2879
+ function getPersistedState(state) {
2880
+ const {
2881
+ configuration,
2882
+ transitions,
2883
+ tags,
2884
+ machine,
2885
+ children,
2886
+ ...jsonValues
2887
+ } = state;
2888
+ const childrenJson = {};
2889
+ for (const id in children) {
2890
+ childrenJson[id] = {
2891
+ state: children[id].getPersistedState?.(),
2892
+ src: children[id].src
2893
+ };
2894
+ }
2895
+ return {
2896
+ ...jsonValues,
2897
+ children: childrenJson
2898
+ };
2899
+ }
2900
+
2901
+ function invoke(invokeDef) {
2902
+ return createDynamicAction({
2903
+ type: invoke$1,
2904
+ params: invokeDef
2905
+ }, (event, {
2906
+ state,
2907
+ actorContext
2908
+ }) => {
2909
+ const type = invoke$1;
2910
+ const {
2911
+ id,
2912
+ src
2913
+ } = invokeDef;
2914
+ let resolvedInvokeAction;
2915
+ if (isActorRef(src)) {
2916
+ resolvedInvokeAction = {
2917
+ type,
2918
+ params: {
2919
+ ...invokeDef,
2920
+ ref: src
2921
+ }
2922
+ };
2923
+ } else {
2924
+ const referenced = resolveReferencedActor(state.machine.options.actors[src]);
2925
+ if (!referenced) {
2926
+ resolvedInvokeAction = {
2927
+ type,
2928
+ params: invokeDef
2929
+ };
2930
+ } else {
2931
+ const input = 'input' in invokeDef ? invokeDef.input : referenced.input;
2932
+ const ref = interpret(referenced.src, {
2933
+ id,
2934
+ src,
2935
+ parent: actorContext?.self,
2936
+ systemId: invokeDef.systemId,
2937
+ input: typeof input === 'function' ? input({
2938
+ context: state.context,
2939
+ event,
2940
+ self: actorContext?.self
2941
+ }) : input
2942
+ });
2943
+ resolvedInvokeAction = {
2944
+ type,
2945
+ params: {
2946
+ ...invokeDef,
2947
+ ref
2948
+ }
2949
+ };
2950
+ }
2951
+ }
2952
+ const actorRef = resolvedInvokeAction.params.ref;
2953
+ const invokedState = cloneState(state, {
2954
+ children: {
2955
+ ...state.children,
2956
+ [id]: actorRef
2957
+ }
2958
+ });
2959
+ resolvedInvokeAction.execute = actorCtx => {
2960
+ const parent = actorCtx.self;
2961
+ const {
2962
+ id,
2963
+ ref
2964
+ } = resolvedInvokeAction.params;
2965
+ if (!ref) {
2966
+ {
2967
+ console.warn(`Actor type '${resolvedInvokeAction.params.src}' not found in machine '${actorCtx.id}'.`);
2968
+ }
2969
+ return;
2970
+ }
2971
+ actorCtx.defer(() => {
2972
+ if (actorRef.status === ActorStatus.Stopped) {
2973
+ return;
2974
+ }
2975
+ try {
2976
+ actorRef.start?.();
2977
+ } catch (err) {
2978
+ parent.send(error(id, err));
2979
+ return;
2980
+ }
2981
+ });
2982
+ };
2983
+ return [invokedState, resolvedInvokeAction];
2984
+ });
2985
+ }
2986
+
2987
+ function createSpawner(self, machine, context, event, mutCapturedActions) {
2988
+ return (src, options = {}) => {
2989
+ if (isString(src)) {
2990
+ const referenced = resolveReferencedActor(machine.options.actors[src]);
2991
+ if (referenced) {
2992
+ const resolvedName = options.id ?? 'anon'; // TODO: better name
2993
+ const input = 'input' in options ? options.input : referenced.input;
2994
+
2995
+ // TODO: this should also receive `src`
2996
+ const actorRef = interpret(referenced.src, {
2997
+ id: resolvedName,
2998
+ parent: self,
2999
+ input: typeof input === 'function' ? input({
3000
+ context,
3001
+ event,
3002
+ self
3003
+ }) : input
3004
+ });
3005
+ mutCapturedActions.push(invoke({
3006
+ id: actorRef.id,
3007
+ // @ts-ignore TODO: fix types
3008
+ src: actorRef,
3009
+ // TODO
3010
+ ref: actorRef,
3011
+ meta: undefined,
3012
+ input
3013
+ }));
3014
+ return actorRef; // TODO: fix types
3015
+ }
3016
+
3017
+ throw new Error(`Behavior '${src}' not implemented in machine '${machine.id}'`);
3018
+ } else {
3019
+ // TODO: this should also receive `src`
3020
+ // TODO: instead of anonymous, it should be a unique stable ID
3021
+ const actorRef = interpret(src, {
3022
+ id: options.id || 'anonymous',
3023
+ parent: self,
3024
+ input: options.input
3025
+ });
3026
+ mutCapturedActions.push(invoke({
3027
+ // @ts-ignore TODO: fix types
3028
+ src: actorRef,
3029
+ ref: actorRef,
3030
+ id: actorRef.id,
3031
+ meta: undefined,
3032
+ input: options.input
3033
+ }));
3034
+ return actorRef; // TODO: fix types
3035
+ }
3036
+ };
3037
+ }
3038
+
3039
+ /**
3040
+ * Updates the current context of the machine.
3041
+ *
3042
+ * @param assignment An object that represents the partial context to update.
3043
+ */
3044
+ function assign(assignment) {
3045
+ return createDynamicAction({
3046
+ type: assign$1,
3047
+ params: {
3048
+ assignment
3049
+ }
3050
+ }, (event, {
3051
+ state,
3052
+ action,
3053
+ actorContext
3054
+ }) => {
3055
+ const capturedActions = [];
3056
+ if (!state.context) {
3057
+ throw new Error('Cannot assign to undefined `context`. Ensure that `context` is defined in the machine config.');
3058
+ }
3059
+ const args = {
3060
+ context: state.context,
3061
+ event,
3062
+ action,
3063
+ spawn: createSpawner(actorContext?.self, state.machine, state.context, event, capturedActions),
3064
+ self: actorContext?.self ?? {},
3065
+ system: actorContext?.system
3066
+ };
3067
+ let partialUpdate = {};
3068
+ if (isFunction(assignment)) {
3069
+ partialUpdate = assignment(args);
3070
+ } else {
3071
+ for (const key of Object.keys(assignment)) {
3072
+ const propAssignment = assignment[key];
3073
+ partialUpdate[key] = isFunction(propAssignment) ? propAssignment(args) : propAssignment;
3074
+ }
3075
+ }
3076
+ const updatedContext = Object.assign({}, state.context, partialUpdate);
3077
+ return [cloneState(state, {
3078
+ context: updatedContext
3079
+ }), {
3080
+ type: assign$1,
3081
+ params: {
3082
+ context: updatedContext,
3083
+ actions: capturedActions
3084
+ }
3085
+ }];
3086
+ });
3087
+ }
3088
+
3089
+ /**
3090
+ * Raises an event. This places the event in the internal event queue, so that
3091
+ * the event is immediately consumed by the machine in the current step.
3092
+ *
3093
+ * @param eventType The event to raise.
3094
+ */
3095
+
3096
+ function raise(eventOrExpr, options) {
3097
+ return createDynamicAction({
3098
+ type: raise$1,
3099
+ params: {
3100
+ delay: options ? options.delay : undefined,
3101
+ event: eventOrExpr,
3102
+ id: options && options.id !== undefined ? options.id : typeof eventOrExpr === 'function' ? eventOrExpr.name : eventOrExpr.type
3103
+ }
3104
+ }, (event, {
3105
+ state,
3106
+ actorContext
3107
+ }) => {
3108
+ const params = {
3109
+ delay: options ? options.delay : undefined,
3110
+ event: eventOrExpr,
3111
+ id: options && options.id !== undefined ? options.id : typeof eventOrExpr === 'function' ? eventOrExpr.name : eventOrExpr.type
3112
+ };
3113
+ const args = {
3114
+ context: state.context,
3115
+ event,
3116
+ self: actorContext?.self ?? {},
3117
+ system: actorContext?.system
3118
+ };
3119
+ const delaysMap = state.machine.options.delays;
3120
+
3121
+ // TODO: helper function for resolving Expr
3122
+ if (typeof eventOrExpr === 'string') {
3123
+ throw new Error(`Only event objects may be used with raise; use raise({ type: "${eventOrExpr}" }) instead`);
3124
+ }
3125
+ const resolvedEvent = typeof eventOrExpr === 'function' ? eventOrExpr(args) : eventOrExpr;
3126
+ let resolvedDelay;
3127
+ if (typeof params.delay === 'string') {
3128
+ const configDelay = delaysMap && delaysMap[params.delay];
3129
+ resolvedDelay = typeof configDelay === 'function' ? configDelay(args) : configDelay;
3130
+ } else {
3131
+ resolvedDelay = typeof params.delay === 'function' ? params.delay(args) : params.delay;
3132
+ }
3133
+ const resolvedAction = {
3134
+ type: raise$1,
3135
+ params: {
3136
+ ...params,
3137
+ event: resolvedEvent,
3138
+ delay: resolvedDelay
3139
+ },
3140
+ execute: actorCtx => {
3141
+ if (typeof resolvedAction.params.delay === 'number') {
3142
+ actorCtx.self.delaySend(resolvedAction);
3143
+ return;
3144
+ }
3145
+ }
3146
+ };
3147
+ return [state, resolvedAction];
3148
+ });
3149
+ }
3150
+
3151
+ function choose(guards) {
3152
+ return createDynamicAction({
3153
+ type: choose$1,
3154
+ params: {
3155
+ guards
3156
+ }
3157
+ }, (event, {
3158
+ state
3159
+ }) => {
3160
+ const matchedActions = guards.find(condition => {
3161
+ const guard = condition.guard && toGuardDefinition(condition.guard, guardType => state.machine.options.guards[guardType]);
3162
+ return !guard || evaluateGuard(guard, state.context, event, state);
3163
+ })?.actions;
3164
+ return [state, {
3165
+ type: choose$1,
3166
+ params: {
3167
+ actions: toActionObjects(matchedActions)
3168
+ }
3169
+ }];
3170
+ });
3171
+ }
3172
+
3173
+ function pure(getActions) {
3174
+ return createDynamicAction({
3175
+ type: pure$1,
3176
+ params: {
3177
+ get: getActions
3178
+ }
3179
+ }, (event, {
3180
+ state
3181
+ }) => {
3182
+ return [state, {
3183
+ type: pure$1,
3184
+ params: {
3185
+ actions: toArray(toActionObjects(getActions({
3186
+ context: state.context,
3187
+ event
3188
+ }))) ?? []
3189
+ }
3190
+ }];
3191
+ });
3192
+ }
3193
+
3194
+ const initEvent = {
3195
+ type: init
3196
+ };
3197
+ function resolveActionObject(actionObject, actionFunctionMap) {
3198
+ if (isDynamicAction(actionObject)) {
3199
+ return actionObject;
3200
+ }
3201
+ const dereferencedAction = actionFunctionMap[actionObject.type];
3202
+ if (typeof dereferencedAction === 'function') {
3203
+ return createDynamicAction({
3204
+ type: 'xstate.function',
3205
+ params: actionObject.params ?? {}
3206
+ }, (event, {
3207
+ state
3208
+ }) => {
3209
+ const a = {
3210
+ type: actionObject.type,
3211
+ params: actionObject.params,
3212
+ execute: actorCtx => {
3213
+ return dereferencedAction({
3214
+ context: state.context,
3215
+ event,
3216
+ action: a,
3217
+ system: actorCtx.system,
3218
+ self: actorCtx.self
3219
+ });
3220
+ }
3221
+ };
3222
+ return [state, a];
3223
+ });
3224
+ } else if (dereferencedAction) {
3225
+ return dereferencedAction;
3226
+ } else {
3227
+ return actionObject;
3228
+ }
3229
+ }
3230
+ function toActionObject(action) {
3231
+ if (isDynamicAction(action)) {
3232
+ return action;
3233
+ }
3234
+ if (typeof action === 'string') {
3235
+ return {
3236
+ type: action,
3237
+ params: {}
3238
+ };
3239
+ }
3240
+ if (typeof action === 'function') {
3241
+ const type = 'xstate.function';
3242
+ return createDynamicAction({
3243
+ type,
3244
+ params: {}
3245
+ }, (event, {
3246
+ state
3247
+ }) => {
3248
+ const actionObject = {
3249
+ type,
3250
+ params: {
3251
+ function: action
3252
+ },
3253
+ execute: actorCtx => {
3254
+ return action({
3255
+ context: state.context,
3256
+ event: event,
3257
+ action: actionObject,
3258
+ self: actorCtx.self,
3259
+ system: actorCtx.system
3260
+ });
3261
+ }
3262
+ };
3263
+ return [state, actionObject];
3264
+ });
3265
+ }
3266
+
3267
+ // action is already a BaseActionObject
3268
+ return action;
3269
+ }
3270
+ const toActionObjects = action => {
3271
+ if (!action) {
3272
+ return [];
3273
+ }
3274
+ const actions = isArray(action) ? action : [action];
3275
+ return actions.map(toActionObject);
3276
+ };
3277
+
3278
+ /**
3279
+ * Returns an event type that represents an implicit event that
3280
+ * is sent after the specified `delay`.
3281
+ *
3282
+ * @param delayRef The delay in milliseconds
3283
+ * @param id The state node ID where this event is handled
3284
+ */
3285
+ function after(delayRef, id) {
3286
+ const idSuffix = id ? `#${id}` : '';
3287
+ return `${ActionTypes.After}(${delayRef})${idSuffix}`;
3288
+ }
3289
+
3290
+ /**
3291
+ * Returns an event that represents that a final state node
3292
+ * has been reached in the parent state node.
3293
+ *
3294
+ * @param id The final state node's parent state node `id`
3295
+ * @param output The data to pass into the event
3296
+ */
3297
+ function done(id, output) {
3298
+ const type = `${ActionTypes.DoneState}.${id}`;
3299
+ const eventObject = {
3300
+ type,
3301
+ output
3302
+ };
3303
+ eventObject.toString = () => type;
3304
+ return eventObject;
3305
+ }
3306
+
3307
+ /**
3308
+ * Returns an event that represents that an invoked service has terminated.
3309
+ *
3310
+ * An invoked service is terminated when it has reached a top-level final state node,
3311
+ * but not when it is canceled.
3312
+ *
3313
+ * @param invokeId The invoked service ID
3314
+ * @param output The data to pass into the event
3315
+ */
3316
+ function doneInvoke(invokeId, output) {
3317
+ const type = `${ActionTypes.DoneInvoke}.${invokeId}`;
3318
+ const eventObject = {
3319
+ type,
3320
+ output
3321
+ };
3322
+ eventObject.toString = () => type;
3323
+ return eventObject;
3324
+ }
3325
+ function error(id, data) {
3326
+ const type = `${ActionTypes.ErrorPlatform}.${id}`;
3327
+ const eventObject = {
3328
+ type,
3329
+ data
3330
+ };
3331
+ eventObject.toString = () => type;
3332
+ return eventObject;
3333
+ }
3334
+ function createInitEvent(input) {
3335
+ return {
3336
+ type: init,
3337
+ input
3338
+ };
3339
+ }
3340
+
3341
+ export { toObserver as $, createInitEvent as A, resolveActionsAndContext as B, microstep as C, error as D, isStateId as E, getStateNodeByPath as F, getPersistedState as G, resolveReferencedActor as H, interpret as I, initEvent as J, matchesState as K, sendTo as L, sendParent as M, NULL_EVENT as N, forwardTo as O, Interpreter as P, ActorStatus as Q, doneInvoke as R, STATE_DELIMITER as S, assign as T, cancel as U, choose as V, log as W, pure as X, raise as Y, stop as Z, pathToStateValue as _, toArray as a, fromPromise as a0, fromObservable as a1, fromCallback as a2, fromEventObservable as a3, fromTransition as a4, stateIn as a5, not as a6, and as a7, or as a8, ActionTypes as a9, SpecialTargets as aa, startSignalType as ab, stopSignalType as ac, startSignal as ad, stopSignal as ae, isSignal as af, isActorRef as ag, toActorRef as ah, createEmptyActor as ai, toGuardDefinition as aj, actionTypes as ak, resolveActionObject as al, toActionObject as am, after as an, done as ao, send as ap, escalate as aq, toTransitionConfigArray as b, formatTransition as c, memo as d, evaluateGuard as e, formatTransitions as f, flatten as g, createInvokeId as h, isString as i, invoke$1 as j, getDelayedTransitions as k, formatInitialTransition as l, mapValues as m, getCandidates as n, toInvokeConfig as o, createSpawner as p, getConfiguration as q, getStateNodes as r, resolveStateValue as s, toActionObjects as t, isInFinalState as u, State as v, isErrorEvent as w, macrostep as x, transitionNode as y, getInitialConfiguration as z };