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