xstate 6.0.0-alpha.47 → 6.0.0-alpha.49

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 (84) hide show
  1. package/README.md +30 -1
  2. package/dist/{StateMachine-7046f677.cjs.js → StateMachine-0adb3a70.cjs.js} +15 -12
  3. package/dist/{StateMachine-70c06bdd.development.cjs.js → StateMachine-29450e6d.development.cjs.js} +15 -12
  4. package/dist/{StateMachine-74929087.esm.js → StateMachine-2af31c11.esm.js} +10 -7
  5. package/dist/{StateMachine-ee10f67e.development.esm.js → StateMachine-faf50c5c.development.esm.js} +10 -7
  6. package/dist/{createActor-915ea40c.esm.js → createActor-268165d4.esm.js} +79 -23
  7. package/dist/{createActor-ff132afa.development.esm.js → createActor-88709f74.development.esm.js} +79 -23
  8. package/dist/{createActor-6736cbbe.development.cjs.js → createActor-a1e0dffb.development.cjs.js} +78 -25
  9. package/dist/{createActor-bfe8b6bd.cjs.js → createActor-b4dd05ae.cjs.js} +78 -25
  10. package/dist/declarations/src/createMachineFromConfig.d.ts +5 -77
  11. package/dist/declarations/src/fsm/createFSMActor.d.ts +67 -0
  12. package/dist/declarations/src/fsm/index.d.ts +2 -0
  13. package/dist/declarations/src/fsm.d.ts +5 -4
  14. package/dist/declarations/src/scxml/index.d.ts +1 -0
  15. package/dist/declarations/src/scxml/runtime.d.ts +251 -0
  16. package/dist/declarations/src/scxml/scxml.d.ts +19 -0
  17. package/dist/declarations/src/types.d.ts +1 -0
  18. package/dist/{effectDescriptor-8be60443.esm.js → effectDescriptor-30c9a744.esm.js} +1 -1
  19. package/dist/{effectDescriptor-fbe67d5a.development.esm.js → effectDescriptor-39d22100.development.esm.js} +1 -1
  20. package/dist/{effectDescriptor-3c699328.development.cjs.js → effectDescriptor-7ff6802f.development.cjs.js} +1 -1
  21. package/dist/{effectDescriptor-a7e2d4d1.cjs.js → effectDescriptor-be348e50.cjs.js} +1 -1
  22. package/dist/fsm-7a2e9697.cjs.js +777 -0
  23. package/dist/fsm-b804b3e9.esm.js +775 -0
  24. package/dist/fsm-c1316948.development.cjs.js +777 -0
  25. package/dist/fsm-e18a7cb4.development.esm.js +775 -0
  26. package/dist/types-3c3455f7.esm.js +185 -0
  27. package/dist/types-adda3842.development.esm.js +185 -0
  28. package/dist/types-b3fea5bd.development.cjs.js +189 -0
  29. package/dist/types-fbabaeee.cjs.js +189 -0
  30. package/dist/validation-05f1d517.esm.js +8 -0
  31. package/dist/validation-4561b43c.cjs.js +10 -0
  32. package/dist/validation-e69470ad.development.esm.js +8 -0
  33. package/dist/validation-f2714a35.development.cjs.js +10 -0
  34. package/dist/xstate-actors.cjs.js +934 -9
  35. package/dist/xstate-actors.development.cjs.js +934 -9
  36. package/dist/xstate-actors.development.esm.js +932 -2
  37. package/dist/xstate-actors.esm.js +932 -2
  38. package/dist/xstate-durable.cjs.js +2 -2
  39. package/dist/xstate-durable.development.cjs.js +2 -2
  40. package/dist/xstate-durable.development.esm.js +2 -2
  41. package/dist/xstate-durable.esm.js +2 -2
  42. package/dist/xstate-fsm.cjs.d.mts +2 -0
  43. package/dist/xstate-fsm.cjs.d.ts +2 -0
  44. package/dist/xstate-fsm.cjs.js +409 -0
  45. package/dist/xstate-fsm.cjs.mjs +5 -0
  46. package/dist/xstate-fsm.development.cjs.js +409 -0
  47. package/dist/xstate-fsm.development.cjs.mjs +5 -0
  48. package/dist/xstate-fsm.development.esm.js +403 -0
  49. package/dist/xstate-fsm.esm.js +403 -0
  50. package/dist/xstate-fsm.umd.min.js +2 -0
  51. package/dist/xstate-fsm.umd.min.js.map +1 -0
  52. package/dist/xstate-graph.cjs.js +4 -3
  53. package/dist/xstate-graph.development.cjs.js +4 -3
  54. package/dist/xstate-graph.development.esm.js +4 -3
  55. package/dist/xstate-graph.esm.js +4 -3
  56. package/dist/xstate-graph.umd.min.js +1 -1
  57. package/dist/xstate-graph.umd.min.js.map +1 -1
  58. package/dist/xstate-scxml.cjs.d.mts +2 -0
  59. package/dist/xstate-scxml.cjs.d.ts +2 -0
  60. package/dist/xstate-scxml.cjs.js +2387 -0
  61. package/dist/xstate-scxml.cjs.mjs +3 -0
  62. package/dist/xstate-scxml.development.cjs.js +2387 -0
  63. package/dist/xstate-scxml.development.cjs.mjs +3 -0
  64. package/dist/xstate-scxml.development.esm.js +2383 -0
  65. package/dist/xstate-scxml.esm.js +2383 -0
  66. package/dist/xstate-scxml.umd.min.js +26 -0
  67. package/dist/xstate-scxml.umd.min.js.map +1 -0
  68. package/dist/xstate-validation.cjs.js +1 -1
  69. package/dist/xstate-validation.development.cjs.js +1 -1
  70. package/dist/xstate-validation.development.esm.js +1 -1
  71. package/dist/xstate-validation.esm.js +1 -1
  72. package/dist/xstate.cjs.js +143 -1412
  73. package/dist/xstate.development.cjs.js +143 -1412
  74. package/dist/xstate.development.esm.js +143 -1411
  75. package/dist/xstate.esm.js +143 -1411
  76. package/dist/xstate.umd.min.js +1 -1
  77. package/dist/xstate.umd.min.js.map +1 -1
  78. package/fsm/package.json +8 -0
  79. package/package.json +37 -3
  80. package/scxml/package.json +8 -0
  81. package/dist/index-0f498ef2.development.cjs.js +0 -946
  82. package/dist/index-70d56425.development.esm.js +0 -937
  83. package/dist/index-b051c924.esm.js +0 -937
  84. package/dist/index-b3fe59bc.cjs.js +0 -946
@@ -1,946 +0,0 @@
1
- 'use strict';
2
-
3
- var createActor = require('./createActor-bfe8b6bd.cjs.js');
4
-
5
- function assertValid(validator, request) {
6
- const error = validator.check(request);
7
- if (error) {
8
- throw error;
9
- }
10
- }
11
-
12
- const effectStates = new WeakMap();
13
- function getEffectState(self) {
14
- let state = effectStates.get(self);
15
- if (!state) {
16
- state = new Map();
17
- effectStates.set(self, state);
18
- }
19
- return state;
20
- }
21
- function executeLogicEffect(self, key, effect) {
22
- const state = getEffectState(self);
23
- if (key !== undefined && state.has(key)) {
24
- return;
25
- }
26
- const cleanup = effect();
27
- state.set(key ?? Symbol(), {
28
- cleanup: typeof cleanup === 'function' ? cleanup : undefined
29
- });
30
- }
31
- function cleanupLogicEffects(self) {
32
- const state = effectStates.get(self);
33
- if (!state) {
34
- return;
35
- }
36
- for (const {
37
- cleanup
38
- } of state.values()) {
39
- cleanup?.();
40
- }
41
- effectStates.delete(self);
42
- }
43
- function resolveContext(context, input) {
44
- return typeof context === 'function' ? context({
45
- input
46
- }) : context;
47
- }
48
- function createLogic(config) {
49
- const calculateTransition = (snapshot, event, actorScope) => {
50
- if (snapshot.status !== 'active') {
51
- return [snapshot, []];
52
- }
53
- if (event.type === createActor.XSTATE_STOP) {
54
- return [{
55
- ...snapshot,
56
- status: 'stopped',
57
- input: undefined
58
- }, [createActor.createCustomEffect('xstate.logic.cleanup', () => cleanupLogicEffects(actorScope.self))]];
59
- }
60
- if (event.type === createActor.XSTATE_LOGIC_EFFECT_START) {
61
- return [{
62
- ...snapshot,
63
- effects: {
64
- ...snapshot.effects,
65
- [event.key]: {
66
- status: 'active'
67
- }
68
- }
69
- }, []];
70
- }
71
- if (event.type === createActor.XSTATE_LOGIC_EFFECT_RESOLVE) {
72
- return [{
73
- ...snapshot,
74
- effects: {
75
- ...snapshot.effects,
76
- [event.key]: {
77
- status: 'done',
78
- output: event.output
79
- }
80
- }
81
- }, []];
82
- }
83
- if (event.type === createActor.XSTATE_LOGIC_EFFECT_REJECT) {
84
- return [{
85
- ...snapshot,
86
- effects: {
87
- ...snapshot.effects,
88
- [event.key]: {
89
- status: 'error',
90
- error: event.error
91
- }
92
- }
93
- }, []];
94
- }
95
- const effects = [];
96
- const trackedEffects = {};
97
- const enqueueEffect = (key, exec) => {
98
- if (snapshot.effects?.[key]) {
99
- return;
100
- }
101
- effects.push(createActor.createCustomEffect('xstate.logic.effect', (runtime = actorScope.self.system) => executeLogicEffect(actorScope.self, key, () => exec(runtime)), {
102
- key
103
- }));
104
- trackedEffects[key] = {
105
- status: 'active'
106
- };
107
- };
108
- const enq = {
109
- emit: emitted => {
110
- effects.push(createActor.createEmitEffect(actorScope, emitted));
111
- },
112
- sendBack: sentEvent => {
113
- const parent = actorScope.self._parent;
114
- if (parent) {
115
- effects.push(createActor.createSendToEffect(actorScope, parent, sentEvent));
116
- }
117
- },
118
- raise: raisedEvent => {
119
- effects.push(createActor.createSendToEffect(actorScope, actorScope.self, raisedEvent));
120
- },
121
- effect: (keyOrExec, maybeExec) => {
122
- if (typeof keyOrExec === 'string') {
123
- enqueueEffect(keyOrExec, maybeExec);
124
- return;
125
- }
126
- const exec = keyOrExec;
127
- effects.push(createActor.createCustomEffect('xstate.logic.effect', (runtime = actorScope.self.system) => executeLogicEffect(actorScope.self, undefined, () => exec(runtime))));
128
- }
129
- };
130
- const patch = config.run({
131
- context: snapshot.context,
132
- event,
133
- input: snapshot.input,
134
- system: actorScope.system,
135
- self: actorScope.self,
136
- emit: actorScope.emit
137
- }, enq);
138
- const nextSnapshot = {
139
- ...snapshot,
140
- ...(patch || {})
141
- };
142
- if ('context' in snapshot || patch?.context !== undefined) {
143
- nextSnapshot.context = patch?.context ?? snapshot.context;
144
- }
145
- if (patch?.effects || Object.keys(trackedEffects).length) {
146
- nextSnapshot.effects = {
147
- ...snapshot.effects,
148
- ...patch?.effects,
149
- ...trackedEffects
150
- };
151
- }
152
- return createActor.finalizeTransitionResult(actorScope, snapshot, [nextSnapshot, effects]);
153
- };
154
- const transition = (snapshot, event, actorScope) => {
155
- if (config.validator) {
156
- assertValid(config.validator, {
157
- kind: 'event',
158
- logic,
159
- event,
160
- eventOrigin: actorScope.self._lastSourceRef ? 'actor' : 'external'
161
- });
162
- }
163
- const result = calculateTransition(snapshot, event, actorScope);
164
- if (config.validator) {
165
- assertValid(config.validator, {
166
- kind: 'result',
167
- logic,
168
- snapshot: result[0],
169
- effects: result[1]
170
- });
171
- }
172
- return result;
173
- };
174
- const logic = {
175
- id: config.id,
176
- config,
177
- validator: config.validator,
178
- transition,
179
- start: (snapshot, actorScope, options) => {
180
- if (!options?.restored) {
181
- return;
182
- }
183
- const [nextSnapshot, effects] = transition(snapshot, createActor.createInitEvent(snapshot.input), actorScope);
184
- Object.assign(snapshot, nextSnapshot);
185
- for (const effect of effects) {
186
- actorScope.actionExecutor(effect);
187
- }
188
- },
189
- initialTransition: (input, actorScope) => {
190
- if (config.validator) {
191
- assertValid(config.validator, {
192
- kind: 'input',
193
- logic,
194
- input
195
- });
196
- }
197
- const context = resolveContext(config.context, input);
198
- const snapshot = {
199
- status: 'active',
200
- output: undefined,
201
- error: undefined,
202
- input
203
- };
204
- if (context !== undefined) {
205
- snapshot.context = context;
206
- }
207
- return transition({
208
- ...snapshot
209
- }, createActor.createInitEvent(input), actorScope);
210
- },
211
- getInitialSnapshot: (actorScope, input) => logic.initialTransition(input, actorScope)[0],
212
- getPersistedSnapshot: snapshot => snapshot,
213
- restoreSnapshot: snapshot => snapshot
214
- };
215
- return logic;
216
- }
217
-
218
- const instanceStates = /* #__PURE__ */new WeakMap();
219
-
220
- /**
221
- * Represents an actor created by `createCallbackLogic`.
222
- *
223
- * The type of `self` within the actor's logic.
224
- *
225
- * @example
226
- *
227
- * ```ts
228
- * import { createCallbackLogic, createActor } from 'xstate';
229
- *
230
- * // The events the actor receives.
231
- * type Event = { type: 'someEvent' };
232
- * // The actor's input.
233
- * type Input = { name: string };
234
- *
235
- * // Actor logic that logs whenever it receives an event of type `someEvent`.
236
- * const logic = createCallbackLogic<Event, Input>(
237
- * ({ self, input, receive }) => {
238
- * self;
239
- * // ^? CallbackActorRef<Event, Input>
240
- *
241
- * receive((event) => {
242
- * if (event.type === 'someEvent') {
243
- * console.log(`${input.name}: received "someEvent" event`);
244
- * // logs 'myActor: received "someEvent" event'
245
- * }
246
- * });
247
- * }
248
- * );
249
- *
250
- * const actor = createActor(logic, { input: { name: 'myActor' } });
251
- * // ^? CallbackActorRef<Event, Input>
252
- * ```
253
- *
254
- * @see {@link createCallbackLogic}
255
- */
256
-
257
- /**
258
- * An actor logic creator which returns callback logic as defined by a callback
259
- * function.
260
- *
261
- * @remarks
262
- * Useful for subscription-based or other free-form logic that can send events
263
- * back to the parent actor.
264
- *
265
- * Actors created from callback logic (“callback actors”) can:
266
- *
267
- * - Receive events via the `receive` function
268
- * - Send events to the parent actor via the `sendBack` function
269
- *
270
- * Callback actors are a bit different from other actors in that they:
271
- *
272
- * - Do not work with `onDone`
273
- * - Do not produce a snapshot using `.getSnapshot()`
274
- * - Do not emit values when used with `.subscribe()`
275
- * - Can not be stopped with `.stop()`
276
- *
277
- * @example
278
- *
279
- * ```typescript
280
- * const callbackLogic = createCallbackLogic(({ sendBack, receive }) => {
281
- * let lockStatus = 'unlocked';
282
- *
283
- * const handler = (event) => {
284
- * if (lockStatus === 'locked') {
285
- * return;
286
- * }
287
- * sendBack(event);
288
- * };
289
- *
290
- * receive((event) => {
291
- * if (event.type === 'lock') {
292
- * lockStatus = 'locked';
293
- * } else if (event.type === 'unlock') {
294
- * lockStatus = 'unlocked';
295
- * }
296
- * });
297
- *
298
- * document.body.addEventListener('click', handler);
299
- *
300
- * return () => {
301
- * document.body.removeEventListener('click', handler);
302
- * };
303
- * });
304
- * ```
305
- *
306
- * @param callback - The callback function used to describe the callback logic
307
- * The callback function is passed an object with the following properties:
308
- *
309
- * - `receive` - A function that can send events back to the parent actor; the
310
- * listener is then called whenever events are received by the callback
311
- * actor
312
- * - `sendBack` - A function that can send events back to the parent actor
313
- * - `input` - Data that was provided to the callback actor
314
- * - `self` - The parent actor of the callback actor
315
- * - `system` - The actor system to which the callback actor belongs The callback
316
- * function can (optionally) return a cleanup function, which is called
317
- * when the actor is stopped.
318
- *
319
- * @returns Callback logic
320
- * @see {@link CallbackLogicFunction} for more information about the callback function and its object argument
321
- * @see {@link https://stately.ai/docs/input | Input docs} for more information about how input is passed
322
- */
323
-
324
- function createCallbackLogic(callbackOrConfig) {
325
- const callback = typeof callbackOrConfig === 'function' ? callbackOrConfig : callbackOrConfig.run;
326
- const schemas = typeof callbackOrConfig === 'function' ? undefined : callbackOrConfig.schemas;
327
- const validator = typeof callbackOrConfig === 'function' ? undefined : callbackOrConfig.validator;
328
- return createLogic({
329
- validator,
330
- schemas,
331
- context: undefined,
332
- run: (args, enq) => {
333
- const {
334
- event,
335
- input,
336
- self,
337
- system
338
- } = args;
339
- const emit = args.emit;
340
- const callbackState = instanceStates.get(self);
341
- callbackState?.receivers?.forEach(receiver => receiver(event));
342
- enq.effect('callback', () => {
343
- const callbackState = {
344
- receivers: undefined,
345
- dispose: undefined
346
- };
347
- instanceStates.set(self, callbackState);
348
- callbackState.dispose = callback({
349
- input,
350
- system,
351
- self: self,
352
- sendBack: event => {
353
- if (self.getSnapshot().status === 'stopped') {
354
- return;
355
- }
356
- const parent = self._parent;
357
- if (parent) {
358
- system._relay(self, parent, event);
359
- }
360
- },
361
- receive: listener => {
362
- callbackState.receivers ??= new Set();
363
- callbackState.receivers.add(listener);
364
- },
365
- emit: emit
366
- });
367
- return () => {
368
- instanceStates.delete(self);
369
- callbackState.receivers?.clear();
370
- callbackState.dispose?.();
371
- };
372
- });
373
- }
374
- });
375
- }
376
-
377
- const XSTATE_OBSERVABLE_NEXT = 'xstate.observable.next';
378
- const XSTATE_OBSERVABLE_ERROR = 'xstate.observable.error';
379
- const XSTATE_OBSERVABLE_COMPLETE = 'xstate.observable.complete';
380
-
381
- /**
382
- * Represents an actor created by `createObservableLogic` or
383
- * `createEventObservableLogic`.
384
- *
385
- * The type of `self` within the actor's logic.
386
- *
387
- * @example
388
- *
389
- * ```ts
390
- * import { createObservableLogic, createActor } from 'xstate';
391
- * import { interval } from 'rxjs';
392
- *
393
- * // The type of the value observed by the actor's logic.
394
- * type Context = number;
395
- * // The actor's input.
396
- * type Input = { period?: number };
397
- *
398
- * // Actor logic that observes a number incremented every `input.period`
399
- * // milliseconds (default: 1_000).
400
- * const logic = createObservableLogic<Context, Input>(
401
- * ({ input, self }) => {
402
- * self;
403
- * // ^? ObservableActor<Event, Input>
404
- *
405
- * return interval(input.period ?? 1_000);
406
- * }
407
- * );
408
- *
409
- * const actor = createActor(logic, { input: { period: 2_000 } });
410
- * // ^? ObservableActor<Event, Input>
411
- * ```
412
- *
413
- * @see {@link createObservableLogic}
414
- * @see {@link createEventObservableLogic}
415
- */
416
-
417
- /**
418
- * Observable actor logic is described by an observable stream of values. Actors
419
- * created from observable logic (“observable actors”) can:
420
- *
421
- * - Emit snapshots of the observable’s emitted value
422
- *
423
- * The observable’s emitted value is used as its observable actor’s `context`.
424
- *
425
- * Sending events to observable actors will have no effect.
426
- *
427
- * @example
428
- *
429
- * ```ts
430
- * import { createObservableLogic, createActor } from 'xstate';
431
- * import { interval } from 'rxjs';
432
- *
433
- * const logic = createObservableLogic((obj) => interval(1000));
434
- *
435
- * const actor = createActor(logic);
436
- *
437
- * actor.subscribe((snapshot) => {
438
- * console.log(snapshot.context);
439
- * });
440
- *
441
- * actor.start();
442
- * // At every second:
443
- * // Logs 0
444
- * // Logs 1
445
- * // Logs 2
446
- * // ...
447
- * ```
448
- *
449
- * @param observableCreator A function that creates an observable. It receives
450
- * one argument, an object with the following properties:
451
- *
452
- * - `input` - Data that was provided to the observable actor
453
- * - `self` - The parent actor
454
- * - `system` - The actor system to which the observable actor belongs
455
- *
456
- * It should return a {@link Subscribable}, which is compatible with an RxJS
457
- * Observable, although RxJS is not required to create them.
458
- * @see {@link https://rxjs.dev} for documentation on RxJS Observable and observable creators.
459
- * @see {@link Subscribable} interface in XState, which is based on and compatible with RxJS Observable.
460
- */
461
-
462
- function createObservableLogic(observableCreatorOrConfig) {
463
- const observableCreator = typeof observableCreatorOrConfig === 'function' ? observableCreatorOrConfig : observableCreatorOrConfig.run;
464
- const schemas = typeof observableCreatorOrConfig === 'function' ? undefined : observableCreatorOrConfig.schemas;
465
- const validator = typeof observableCreatorOrConfig === 'function' ? undefined : observableCreatorOrConfig.validator;
466
- return createLogic({
467
- validator,
468
- schemas,
469
- context: undefined,
470
- run: (args, enq) => {
471
- const {
472
- event,
473
- input,
474
- self,
475
- system
476
- } = args;
477
- switch (event.type) {
478
- case XSTATE_OBSERVABLE_NEXT:
479
- {
480
- return {
481
- context: event.data
482
- };
483
- }
484
- case XSTATE_OBSERVABLE_ERROR:
485
- return {
486
- status: 'error',
487
- error: event.data,
488
- input: undefined,
489
- effects: {
490
- observable: {
491
- status: 'error',
492
- error: event.data
493
- }
494
- }
495
- };
496
- case XSTATE_OBSERVABLE_COMPLETE:
497
- return {
498
- status: 'done',
499
- input: undefined,
500
- effects: {
501
- observable: {
502
- status: 'done'
503
- }
504
- }
505
- };
506
- }
507
- if (event.type !== createActor.XSTATE_INIT) {
508
- return;
509
- }
510
- enq.effect((runtime = system) => {
511
- const actorSelf = self;
512
- const sendSelf = event => void runtime.sendEvent(actorSelf, actorSelf, event);
513
- const subscription = observableCreator({
514
- input,
515
- system,
516
- self: self,
517
- emit: event => void runtime.emitEvent(actorSelf, event)
518
- }).subscribe({
519
- next: value => {
520
- sendSelf({
521
- type: XSTATE_OBSERVABLE_NEXT,
522
- data: value
523
- });
524
- },
525
- error: err => {
526
- sendSelf({
527
- type: XSTATE_OBSERVABLE_ERROR,
528
- data: err
529
- });
530
- },
531
- complete: () => {
532
- sendSelf({
533
- type: XSTATE_OBSERVABLE_COMPLETE
534
- });
535
- }
536
- });
537
- return () => subscription.unsubscribe();
538
- });
539
- }
540
- });
541
- }
542
-
543
- /**
544
- * Creates event observable logic that listens to an observable that delivers
545
- * event objects.
546
- *
547
- * Event observable actor logic is described by an observable stream of
548
- * {@link https://stately.ai/docs/transitions#event-objects | event objects}.
549
- * Actors created from event observable logic (“event observable actors”) can:
550
- *
551
- * - Implicitly send events to its parent actor
552
- * - Emit snapshots of its emitted event objects
553
- *
554
- * Sending events to event observable actors will have no effect.
555
- *
556
- * @example
557
- *
558
- * ```ts
559
- * import {
560
- * createEventObservableLogic,
561
- * Subscribable,
562
- * EventObject,
563
- * createMachine,
564
- * createActor
565
- * } from 'xstate';
566
- * import { fromEvent } from 'rxjs';
567
- *
568
- * const mouseClickLogic = createEventObservableLogic(
569
- * () => fromEvent(document.body, 'click') as Subscribable<EventObject>
570
- * );
571
- *
572
- * const canvasMachine = createMachine({
573
- * invoke: {
574
- * // Will send mouse `click` events to the canvas actor
575
- * src: mouseClickLogic
576
- * }
577
- * });
578
- *
579
- * const canvasActor = createActor(canvasMachine);
580
- * canvasActor.start();
581
- * ```
582
- *
583
- * @param lazyObservable A function that creates an observable that delivers
584
- * event objects. It receives one argument, an object with the following
585
- * properties:
586
- *
587
- * - `input` - Data that was provided to the event observable actor
588
- * - `self` - The parent actor
589
- * - `system` - The actor system to which the event observable actor belongs.
590
- *
591
- * It should return a {@link Subscribable}, which is compatible with an RxJS
592
- * Observable, although RxJS is not required to create them.
593
- */
594
-
595
- function createEventObservableLogic(lazyObservableOrConfig) {
596
- const lazyObservable = typeof lazyObservableOrConfig === 'function' ? lazyObservableOrConfig : lazyObservableOrConfig.run;
597
- const validator = typeof lazyObservableOrConfig === 'function' ? undefined : lazyObservableOrConfig.validator;
598
-
599
- // TODO: event types
600
- const logic = {
601
- config: lazyObservableOrConfig,
602
- validator,
603
- transition: (state, event, actorScope) => {
604
- if (state.status !== 'active') {
605
- return [state, []];
606
- }
607
- switch (event.type) {
608
- case XSTATE_OBSERVABLE_ERROR:
609
- return createActor.finalizeTransitionResult(actorScope, state, [{
610
- ...state,
611
- status: 'error',
612
- error: event.data,
613
- input: undefined,
614
- _subscription: undefined
615
- }, []]);
616
- case XSTATE_OBSERVABLE_COMPLETE:
617
- return createActor.finalizeTransitionResult(actorScope, state, [{
618
- ...state,
619
- status: 'done',
620
- input: undefined,
621
- _subscription: undefined
622
- }, []]);
623
- case createActor.XSTATE_STOP:
624
- state._subscription.unsubscribe();
625
- return [{
626
- ...state,
627
- status: 'stopped',
628
- input: undefined,
629
- _subscription: undefined
630
- }, []];
631
- default:
632
- return [state, []];
633
- }
634
- },
635
- initialTransition: (input, _) => {
636
- if (validator) {
637
- assertValid(validator, {
638
- kind: 'input',
639
- logic,
640
- input
641
- });
642
- }
643
- const snapshot = {
644
- status: 'active',
645
- output: undefined,
646
- error: undefined,
647
- context: undefined,
648
- input,
649
- _subscription: undefined
650
- };
651
- return [snapshot, []];
652
- },
653
- getInitialSnapshot: (actorScope, input) => logic.initialTransition(input, actorScope)[0],
654
- start: (state, {
655
- self,
656
- system,
657
- emit
658
- }) => {
659
- if (state.status === 'done') {
660
- // Do not restart a completed observable
661
- return;
662
- }
663
- state._subscription = lazyObservable({
664
- input: state.input,
665
- system,
666
- self,
667
- emit: event => {
668
- void emit(event);
669
- }
670
- }).subscribe({
671
- next: value => {
672
- if (self._parent) {
673
- system._relay(self, self._parent, value);
674
- }
675
- },
676
- error: err => {
677
- system._relay(self, self, {
678
- type: XSTATE_OBSERVABLE_ERROR,
679
- data: err
680
- });
681
- },
682
- complete: () => {
683
- system._relay(self, self, {
684
- type: XSTATE_OBSERVABLE_COMPLETE
685
- });
686
- }
687
- });
688
- },
689
- getPersistedSnapshot: ({
690
- _subscription,
691
- ...snapshot
692
- }) => snapshot,
693
- restoreSnapshot: snapshot => ({
694
- ...snapshot,
695
- _subscription: undefined
696
- })
697
- };
698
- return logic;
699
- }
700
-
701
- const XSTATE_ASYNC_RESOLVE = 'xstate.async.resolve';
702
- const XSTATE_ASYNC_REJECT = 'xstate.async.reject';
703
- class TimeoutError extends Error {
704
- constructor(timeout) {
705
- super(`Async logic timed out after ${timeout}.`);
706
- this.name = 'TimeoutError';
707
- }
708
- }
709
-
710
- /**
711
- * Represents an actor created by `createAsyncLogic`.
712
- *
713
- * The type of `self` within the actor's logic.
714
- *
715
- * @example
716
- *
717
- * ```ts
718
- * import { createAsyncLogic, createActor } from 'xstate';
719
- *
720
- * // The actor's resolved output
721
- * type Output = string;
722
- * // The actor's input.
723
- * type Input = { message: string };
724
- *
725
- * // Actor logic that fetches the url of an image of a cat saying `input.message`.
726
- * const logic = createAsyncLogic<Output, Input>({
727
- * run: async ({ input, self }, enq) => {
728
- * self;
729
- * // ^? AsyncActor<Output, Input>
730
- * enq.emit({ type: 'request.start' });
731
- *
732
- * const data = await fetch(
733
- * `https://cataas.com/cat/says/${input.message}`
734
- * );
735
- * const url = await data.json();
736
- * return url;
737
- * }
738
- * });
739
- *
740
- * const actor = createActor(logic, { input: { message: 'hello world' } });
741
- * // ^? AsyncActor<Output, Input>
742
- * ```
743
- *
744
- * @see {@link createAsyncLogic}
745
- */
746
-
747
- /**
748
- * An actor logic creator which returns async logic as defined by an async
749
- * process that resolves or rejects after some time.
750
- *
751
- * Actors created from async actor logic can:
752
- *
753
- * - Output the resolved value of the async process
754
- * - Error with the rejected value of the async process
755
- * - Abort when stopped or timed out
756
- *
757
- * Sending events to async actors will have no effect.
758
- *
759
- * @example
760
- *
761
- * ```ts
762
- * const asyncLogic = createAsyncLogic({
763
- * id: 'fetch-user',
764
- * timeout: '30s',
765
- * run: async ({ signal }, enq) => {
766
- * enq.emit({ type: 'request.start' });
767
- * const result = await fetch('https://example.com/...', {
768
- * signal
769
- * }).then((data) => data.json());
770
- *
771
- * return result;
772
- * }
773
- * });
774
- *
775
- * const asyncActor = createActor(asyncLogic);
776
- * asyncActor.subscribe((snapshot) => {
777
- * console.log(snapshot);
778
- * });
779
- * asyncActor.start();
780
- * // => {
781
- * // output: undefined,
782
- * // status: 'active'
783
- * // ...
784
- * // }
785
- *
786
- * // After promise resolves
787
- * // => {
788
- * // output: { ... },
789
- * // status: 'done',
790
- * // ...
791
- * // }
792
- * ```
793
- *
794
- * @param asyncLogic A config object with a `run` function which returns a
795
- * Promise, and accepts an object with the following properties:
796
- *
797
- * - `input` - Data that was provided to the async actor
798
- * - `self` - The async actor ref
799
- * - `system` - The actor system to which the async actor belongs
800
- * - `signal` - An abort signal for cancellation
801
- *
802
- * `run` also receives an `enq` object with the following properties:
803
- *
804
- * - `emit` - Emits an event that can be observed with `actor.on(...)`
805
- *
806
- * @see {@link https://stately.ai/docs/input | Input docs} for more information about how input is passed
807
- */
808
-
809
- function createAsyncLogic(asyncLogic) {
810
- const config = asyncLogic;
811
- return createLogic({
812
- id: config.id,
813
- validator: config.validator,
814
- schemas: config.schemas,
815
- context: undefined,
816
- run: ({
817
- event,
818
- input,
819
- self,
820
- system
821
- }, enq) => {
822
- switch (event.type) {
823
- case XSTATE_ASYNC_RESOLVE:
824
- {
825
- const resolvedValue = event.data ?? event.output;
826
- return {
827
- status: 'done',
828
- output: resolvedValue,
829
- input: undefined,
830
- effects: {
831
- async: {
832
- status: 'done',
833
- output: resolvedValue
834
- }
835
- }
836
- };
837
- }
838
- case XSTATE_ASYNC_REJECT:
839
- {
840
- const error = event.data ?? event.error;
841
- return {
842
- status: 'error',
843
- error,
844
- input: undefined,
845
- effects: {
846
- async: {
847
- status: 'error',
848
- error
849
- }
850
- }
851
- };
852
- }
853
- }
854
- if (event.type !== createActor.XSTATE_INIT) {
855
- return;
856
- }
857
- enq.effect((runtime = system) => {
858
- const actorSelf = self;
859
- const sendSelf = event => void runtime.sendEvent(actorSelf, actorSelf, event);
860
- const controller = new AbortController();
861
- const timeout = config.timeout;
862
- const timeoutMs = createActor.parseDelayToMilliseconds(timeout);
863
- const timeoutId = timeoutMs === undefined ? undefined : system._clock.setTimeout(() => {
864
- if (self.getSnapshot().status !== 'active') {
865
- return;
866
- }
867
- controller.abort();
868
- sendSelf({
869
- type: XSTATE_ASYNC_REJECT,
870
- data: new TimeoutError(timeout)
871
- });
872
- }, timeoutMs);
873
- const clearTimeout = () => {
874
- if (timeoutId !== undefined) {
875
- system._clock.clearTimeout(timeoutId);
876
- }
877
- };
878
- const runBody = () => Promise.resolve(config.run({
879
- input,
880
- system,
881
- self: self,
882
- signal: controller.signal
883
- }, {
884
- emit: event => void runtime.emitEvent(actorSelf, event),
885
- // Steps route through the runtime: a durable host that
886
- // implements `runStep` owns the step journal; otherwise the
887
- // built-in behavior memoizes into this actor's own snapshot,
888
- // self-sending through the same runtime as the other effects.
889
- step: (key, exec) => runtime.runStep ? Promise.resolve(runtime.runStep(actorSelf, key, exec)) : createActor.runStep(actorSelf, key, exec, sendSelf)
890
- }));
891
- // The whole body is one durable unit: a host that implements
892
- // `runLogic` journals it by the actor's address — or re-runs the
893
- // registered logic from (src, input) on a remote executor, ignoring
894
- // the closure. The default runs it here, unjournaled.
895
- const resolvedPromise = runtime.runLogic ? Promise.resolve(runtime.runLogic(actorSelf, runBody)) : runBody();
896
- resolvedPromise.then(response => {
897
- clearTimeout();
898
- if (self.getSnapshot().status !== 'active') {
899
- return;
900
- }
901
- sendSelf({
902
- type: XSTATE_ASYNC_RESOLVE,
903
- data: response
904
- });
905
- }, errorData => {
906
- clearTimeout();
907
- if (self.getSnapshot().status !== 'active') {
908
- return;
909
- }
910
- sendSelf({
911
- type: XSTATE_ASYNC_REJECT,
912
- data: errorData
913
- });
914
- });
915
- return () => {
916
- controller.abort();
917
- clearTimeout();
918
- };
919
- });
920
- return {
921
- effects: {
922
- async: {
923
- status: 'active'
924
- }
925
- }
926
- };
927
- }
928
- });
929
- }
930
-
931
- const emptyLogic = /* #__PURE__ */createLogic({
932
- context: undefined,
933
- run: () => undefined
934
- });
935
- function createEmptyActor() {
936
- return createActor.createActor(emptyLogic);
937
- }
938
-
939
- exports.TimeoutError = TimeoutError;
940
- exports.assertValid = assertValid;
941
- exports.createAsyncLogic = createAsyncLogic;
942
- exports.createCallbackLogic = createCallbackLogic;
943
- exports.createEmptyActor = createEmptyActor;
944
- exports.createEventObservableLogic = createEventObservableLogic;
945
- exports.createLogic = createLogic;
946
- exports.createObservableLogic = createObservableLogic;