@xstate/effect 0.1.0-alpha.2

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.
@@ -0,0 +1,702 @@
1
+ import { Schema, Effect, Stream, Exit, Cause, Queue } from 'effect';
2
+ import { createLogic, setup } from 'xstate';
3
+ import { s as startHostedEffect, r as relayToParent, E as EffectInterruptedError, A as ActorStoppedError, a as runHostedEffect } from './state-9a718be3.js';
4
+ export { A as ActorStoppedError, b as EffectActor, E as EffectInterruptedError, c as createEffectActor, t as taggedState } from './state-9a718be3.js';
5
+ import { dual } from 'effect/Function';
6
+ import 'xstate/durable';
7
+
8
+ /**
9
+ * An Effect `Schema` accepted by this package. `setupEffect`, `fromEffect`,
10
+ * `fromEffectStream` and `fromEffectEventStream` convert it to a Standard
11
+ * Schema, so XState infers the decoded `Schema.Type` without an explicit call
12
+ * to `Schema.toStandardSchemaV1`.
13
+ */
14
+
15
+ /**
16
+ * Either an Effect {@link EffectSchema} or a Standard Schema. Every schema
17
+ * position in this package accepts both, so Effect schemas and schemas from
18
+ * other libraries can be mixed in one machine.
19
+ */
20
+
21
+ /**
22
+ * The `schemas` option of `setupEffect`: XState's `SetupSchemas` with every
23
+ * schema position widened to {@link EffectSchemaLike}. Covers `context`,
24
+ * `input`, `output` and the per-key records for `events`, `internalEvents`,
25
+ * `emitted` and `children`.
26
+ */
27
+
28
+ /**
29
+ * One node of the `states` option of `setupEffect`: the schemas declared for
30
+ * that state, and the same shape recursively for its child states. It is
31
+ * XState's `SetupStateSchema` with Effect schemas allowed in every schema
32
+ * position.
33
+ */
34
+
35
+ function isStandardSchema(value) {
36
+ return !!value && (typeof value === 'object' || typeof value === 'function') && '~standard' in value;
37
+ }
38
+ function toStandardSchema(schema) {
39
+ if (Schema.isSchema(schema)) {
40
+ return Schema.toStandardSchemaV1(schema);
41
+ }
42
+ return schema;
43
+ }
44
+ function mapSchemaRecord(value) {
45
+ return Object.fromEntries(Object.keys(value).map(key => {
46
+ const entry = value[key];
47
+ if (Schema.isSchema(entry) || isStandardSchema(entry)) {
48
+ return [key, toStandardSchema(entry)];
49
+ }
50
+ if (entry && typeof entry === 'object' && !Array.isArray(entry)) {
51
+ return [key, mapSchemaRecord(entry)];
52
+ }
53
+ return [key, entry];
54
+ }));
55
+ }
56
+ function toStandardSetupSchemas(schemas) {
57
+ return schemas ? mapSchemaRecord(schemas) : undefined;
58
+ }
59
+ function toStandardSetupStates(states) {
60
+ if (!states) {
61
+ return undefined;
62
+ }
63
+ return Object.fromEntries(Object.keys(states).map(key => {
64
+ const state = states[key];
65
+ return [key, {
66
+ ...state,
67
+ ...(state.schemas ? {
68
+ schemas: mapSchemaRecord(state.schemas)
69
+ } : undefined),
70
+ ...(state.states ? {
71
+ states: toStandardSetupStates(state.states)
72
+ } : undefined)
73
+ }];
74
+ }));
75
+ }
76
+
77
+ const EFFECT_INIT = '@xstate.init';
78
+ const EFFECT_RESOLVE = 'xstate.effect.resolve';
79
+ const EFFECT_REJECT = 'xstate.effect.reject';
80
+ const EFFECT_NEXT = 'xstate.effect.next';
81
+ const EFFECT_COMPLETE = 'xstate.effect.complete';
82
+ const effectLogicBrand = Symbol.for('@xstate/effect/logic');
83
+
84
+ /**
85
+ * Type-level marker attached to logic created by `fromEffect`,
86
+ * `fromEffectStream` and `fromEffectEventStream`. It carries the logic's
87
+ * failure type and its Effect service requirements, which is how
88
+ * `RequirementsFrom` collects the `R` channel of `createEffectActor` without
89
+ * inspecting the logic at runtime.
90
+ */
91
+
92
+ /**
93
+ * Snapshot of a `fromEffect` actor. The actor holds no context of its own: it
94
+ * is `active` while the Effect runs, `done` with the Effect's success value as
95
+ * `output`, or `error` with the Effect's failure, defect or
96
+ * `EffectInterruptedError` as `error`.
97
+ */
98
+
99
+ /**
100
+ * Argument passed to the function form of an Effect source. It gives the
101
+ * source the actor's `input`, its own reference (`self`), the actor `system`,
102
+ * and `emit` for publishing events that `actor.on(...)` and `emitted(actor)`
103
+ * observe.
104
+ */
105
+
106
+ /**
107
+ * What `fromEffect` accepts as its Effect: either an Effect value, or a
108
+ * function of {@link EffectSourceArgs} returning one. The function form is
109
+ * called once per actor start, so it sees that actor's input.
110
+ */
111
+
112
+ /**
113
+ * Actor logic produced by `fromEffect` and `fromEffectEventStream`. It is
114
+ * ordinary XState actor logic carrying {@link EffectLogicBrand}, so a machine
115
+ * can invoke or spawn it, and `createEffectActor` can collect its
116
+ * requirements.
117
+ */
118
+
119
+ /**
120
+ * Snapshot of a `fromEffectStream` actor. `context` holds the most recent
121
+ * stream item, or `undefined` before the first one. The actor reaches `done`
122
+ * with no output when the stream completes, and `error` when it fails.
123
+ */
124
+
125
+ /**
126
+ * Actor logic produced by `fromEffectStream`. Its snapshot is an
127
+ * {@link EffectStreamSnapshot}, so the parent reads the latest item from the
128
+ * child's `context` rather than from events.
129
+ */
130
+
131
+ function toError(exit) {
132
+ if (Exit.isSuccess(exit)) {
133
+ return undefined;
134
+ }
135
+ if (Cause.hasInterruptsOnly(exit.cause)) {
136
+ return new EffectInterruptedError({
137
+ cause: exit.cause
138
+ });
139
+ }
140
+ return Cause.squash(exit.cause);
141
+ }
142
+ function createSourceArgs(input, self, system) {
143
+ return {
144
+ input,
145
+ self,
146
+ system,
147
+ emit: event => {
148
+ void system.emitEvent(self, event);
149
+ }
150
+ };
151
+ }
152
+ function brandLogic(logic, error, requirements) {
153
+ Object.defineProperty(logic, effectLogicBrand, {
154
+ configurable: false,
155
+ enumerable: false,
156
+ value: {
157
+ error,
158
+ requirements
159
+ }
160
+ });
161
+ return logic;
162
+ }
163
+
164
+ /**
165
+ * Creates actor logic that runs an Effect. The actor completes with the
166
+ * Effect's success value as its output and fails with the Effect's error, its
167
+ * squashed defect, or an `EffectInterruptedError` when the Effect interrupts
168
+ * itself. Stopping the actor interrupts the Effect without an error. Accepts
169
+ * an Effect, a function of {@link EffectSourceArgs} returning one, or a config
170
+ * object with `id`, `schemas`, `validator` and `effect`. The logic must be run
171
+ * under `createEffectActor`, which provides the Effect services it declares.
172
+ */
173
+
174
+ function fromEffect(sourceOrConfig) {
175
+ const config = typeof sourceOrConfig === 'function' || Effect.isEffect(sourceOrConfig) ? {
176
+ effect: sourceOrConfig
177
+ } : sourceOrConfig;
178
+ const source = config.effect;
179
+ const schemas = config.schemas ? {
180
+ ...(config.schemas.input ? {
181
+ input: toStandardSchema(config.schemas.input)
182
+ } : {}),
183
+ ...(config.schemas.output ? {
184
+ output: toStandardSchema(config.schemas.output)
185
+ } : {})
186
+ } : undefined;
187
+ const logic = createLogic({
188
+ id: config.id,
189
+ validator: config.validator,
190
+ schemas,
191
+ context: undefined,
192
+ run: ({
193
+ event,
194
+ input,
195
+ self,
196
+ system
197
+ }, enq) => {
198
+ if (event.type === EFFECT_RESOLVE) {
199
+ return {
200
+ status: 'done',
201
+ output: event.output,
202
+ input: undefined
203
+ };
204
+ }
205
+ if (event.type === EFFECT_REJECT) {
206
+ return {
207
+ status: 'error',
208
+ error: event.error,
209
+ input: undefined
210
+ };
211
+ }
212
+ if (event.type !== EFFECT_INIT) {
213
+ return;
214
+ }
215
+ const effect = typeof source === 'function' ? source(createSourceArgs(input, self, system)) : source;
216
+ enq.effect(() => startHostedEffect(self, effect, 'fromEffect', exit => {
217
+ if (self.getSnapshot().status !== 'active') {
218
+ return;
219
+ }
220
+ if (Exit.isSuccess(exit)) {
221
+ self.send({
222
+ type: EFFECT_RESOLVE,
223
+ output: exit.value
224
+ });
225
+ } else {
226
+ self.send({
227
+ type: EFFECT_REJECT,
228
+ error: toError(exit)
229
+ });
230
+ }
231
+ }));
232
+ }
233
+ });
234
+ return brandLogic(logic, undefined, undefined);
235
+ }
236
+
237
+ /**
238
+ * What `fromEffectStream` and `fromEffectEventStream` accept as their stream:
239
+ * either a Stream value, or a function of {@link EffectSourceArgs} returning
240
+ * one. The function form is called once per actor start.
241
+ */
242
+
243
+ function resolveStreamConfig(sourceOrConfig) {
244
+ return typeof sourceOrConfig === 'function' || Stream.isStream(sourceOrConfig) ? {
245
+ stream: sourceOrConfig
246
+ } : sourceOrConfig;
247
+ }
248
+ function toLogicSchemas(schemas) {
249
+ return schemas?.input ? {
250
+ input: toStandardSchema(schemas.input)
251
+ } : undefined;
252
+ }
253
+
254
+ /**
255
+ * Creates actor logic that runs a Stream and exposes its most recent item as
256
+ * the actor's `context`. The actor reaches `done` when the stream completes
257
+ * and `error` when it fails. Accepts a Stream, a function of
258
+ * {@link EffectSourceArgs} returning one, or a config object with `id`,
259
+ * `schemas`, `validator` and `stream`.
260
+ */
261
+
262
+ function fromEffectStream(sourceOrConfig) {
263
+ const config = resolveStreamConfig(sourceOrConfig);
264
+ const stream = config.stream;
265
+ const logic = createLogic({
266
+ id: config.id,
267
+ validator: config.validator,
268
+ schemas: toLogicSchemas(config.schemas),
269
+ context: undefined,
270
+ run: ({
271
+ event,
272
+ input,
273
+ self,
274
+ system
275
+ }, enq) => {
276
+ if (event.type === EFFECT_NEXT) {
277
+ return {
278
+ context: event.value
279
+ };
280
+ }
281
+ if (event.type === EFFECT_COMPLETE) {
282
+ return {
283
+ status: 'done',
284
+ input: undefined
285
+ };
286
+ }
287
+ if (event.type === EFFECT_REJECT) {
288
+ return {
289
+ status: 'error',
290
+ error: event.error,
291
+ input: undefined
292
+ };
293
+ }
294
+ if (event.type !== EFFECT_INIT) {
295
+ return;
296
+ }
297
+ const streamValue = typeof stream === 'function' ? stream(createSourceArgs(input, self, system)) : stream;
298
+ const consume = Stream.runForEach(streamValue, value => Effect.sync(() => {
299
+ if (self.getSnapshot().status === 'active') {
300
+ self.send({
301
+ type: EFFECT_NEXT,
302
+ value
303
+ });
304
+ }
305
+ }));
306
+ enq.effect(() => startHostedEffect(self, consume, 'fromEffectStream', exit => {
307
+ if (self.getSnapshot().status !== 'active') {
308
+ return;
309
+ }
310
+ if (Exit.isSuccess(exit)) {
311
+ self.send({
312
+ type: EFFECT_COMPLETE
313
+ });
314
+ } else {
315
+ self.send({
316
+ type: EFFECT_REJECT,
317
+ error: toError(exit)
318
+ });
319
+ }
320
+ }));
321
+ }
322
+ });
323
+ return brandLogic(logic, undefined, undefined);
324
+ }
325
+
326
+ /**
327
+ * Creates actor logic that runs a Stream of events and relays each item to the
328
+ * parent machine as an event, the way `fromEventObservable` does. The actor
329
+ * has no output: it reaches `done` when the stream completes and `error` when
330
+ * it fails. Accepts the same forms as `fromEffectStream`.
331
+ */
332
+
333
+ function fromEffectEventStream(sourceOrConfig) {
334
+ const config = resolveStreamConfig(sourceOrConfig);
335
+ const stream = config.stream;
336
+ const logic = createLogic({
337
+ id: config.id,
338
+ validator: config.validator,
339
+ schemas: toLogicSchemas(config.schemas),
340
+ context: undefined,
341
+ run: ({
342
+ event,
343
+ input,
344
+ self,
345
+ system
346
+ }, enq) => {
347
+ if (event.type === EFFECT_COMPLETE) {
348
+ return {
349
+ status: 'done',
350
+ input: undefined
351
+ };
352
+ }
353
+ if (event.type === EFFECT_REJECT) {
354
+ return {
355
+ status: 'error',
356
+ error: event.error,
357
+ input: undefined
358
+ };
359
+ }
360
+ if (event.type !== EFFECT_INIT) {
361
+ return;
362
+ }
363
+ const streamValue = typeof stream === 'function' ? stream(createSourceArgs(input, self, system)) : stream;
364
+ const consume = Stream.runForEach(streamValue, value => Effect.sync(() => relayToParent(self, value)));
365
+ enq.effect(() => startHostedEffect(self, consume, 'fromEffectEventStream', exit => {
366
+ if (self.getSnapshot().status !== 'active') {
367
+ return;
368
+ }
369
+ if (Exit.isSuccess(exit)) {
370
+ self.send({
371
+ type: EFFECT_COMPLETE
372
+ });
373
+ } else {
374
+ self.send({
375
+ type: EFFECT_REJECT,
376
+ error: toError(exit)
377
+ });
378
+ }
379
+ }));
380
+ }
381
+ });
382
+ return brandLogic(logic, undefined, undefined);
383
+ }
384
+
385
+ /** The event type accepted by an actor's `send` method. */
386
+
387
+ /** The event type an actor emits through `actor.on(...)`. */
388
+
389
+ /** Options for {@link waitFor}. */
390
+
391
+ const noopSubscription = {
392
+ unsubscribe: () => {}
393
+ };
394
+ function actorId(actor) {
395
+ return actor.id ?? '(unknown)';
396
+ }
397
+
398
+ /**
399
+ * Marks an already-errored actor's error as observed, so XState does not
400
+ * report it as unhandled: the caller consumes it as a typed failure.
401
+ */
402
+ function observeError(actor) {
403
+ actor.subscribe({
404
+ error: () => {}
405
+ }).unsubscribe();
406
+ }
407
+ function stoppedError(actor) {
408
+ return new ActorStoppedError({
409
+ actorId: actorId(actor),
410
+ snapshot: actor.getSnapshot()
411
+ });
412
+ }
413
+ function isActorRef(value) {
414
+ return typeof value === 'object' && value !== null && typeof value.send === 'function' && typeof value.getSnapshot === 'function';
415
+ }
416
+
417
+ /**
418
+ * Sends an event to an actor. The returned Effect always succeeds: the event
419
+ * is enqueued, like `actor.send(event)`, and processed on the actor's own
420
+ * fiber. An event that cannot be delivered (for example to a stopped actor)
421
+ * is reported as a dead letter, observable with {@link deadLetters}.
422
+ */
423
+ const send = dual(2, (actor, event) => Effect.sync(() => {
424
+ actor.send(event);
425
+ }));
426
+
427
+ /**
428
+ * Streams an actor's snapshots, starting with the current one. The stream ends
429
+ * when the actor completes or stops, and emits the error snapshot before
430
+ * ending when the actor errors. Interrupting the stream unsubscribes from the
431
+ * actor.
432
+ */
433
+ function snapshots(actor) {
434
+ return Stream.callback(queue => Effect.acquireRelease(Effect.sync(() => {
435
+ const current = actor.getSnapshot();
436
+ Queue.offerUnsafe(queue, current);
437
+ if (current.status !== 'active') {
438
+ observeError(actor);
439
+ Queue.endUnsafe(queue);
440
+ return noopSubscription;
441
+ }
442
+ return actor.subscribe({
443
+ next: snapshot => {
444
+ Queue.offerUnsafe(queue, snapshot);
445
+ },
446
+ error: () => {
447
+ Queue.offerUnsafe(queue, actor.getSnapshot());
448
+ Queue.endUnsafe(queue);
449
+ },
450
+ complete: () => {
451
+ Queue.endUnsafe(queue);
452
+ }
453
+ });
454
+ }), subscription => Effect.sync(() => {
455
+ subscription.unsubscribe();
456
+ })));
457
+ }
458
+
459
+ /**
460
+ * Streams every event an actor emits, as delivered to `actor.on('*', …)`. The
461
+ * stream ends when the actor completes, errors or stops. Interrupting the
462
+ * stream removes the listener.
463
+ */
464
+ function emitted(actor) {
465
+ return Stream.callback(queue => Effect.acquireRelease(Effect.sync(() => {
466
+ const listener = actor.on('*', event => {
467
+ Queue.offerUnsafe(queue, event);
468
+ });
469
+ if (actor.getSnapshot().status !== 'active') {
470
+ Queue.endUnsafe(queue);
471
+ return [listener, noopSubscription];
472
+ }
473
+ const subscription = actor.subscribe({
474
+ error: () => {
475
+ Queue.endUnsafe(queue);
476
+ },
477
+ complete: () => {
478
+ Queue.endUnsafe(queue);
479
+ }
480
+ });
481
+ return [listener, subscription];
482
+ }), ([listener, subscription]) => Effect.sync(() => {
483
+ listener.unsubscribe();
484
+ subscription.unsubscribe();
485
+ })));
486
+ }
487
+
488
+ /**
489
+ * Waits for the first actor snapshot that satisfies `predicate`, succeeding
490
+ * immediately when the current snapshot already does. Fails with
491
+ * `ActorStoppedError` if the actor stops or errors first, and with
492
+ * `Cause.TimeoutError` when `options.timeout` elapses. Interrupting the Effect
493
+ * unsubscribes from the actor.
494
+ */
495
+ const waitFor = dual(args => isActorRef(args[0]), (actor, predicate, options) => {
496
+ const waiting = Effect.callback(resume => {
497
+ const current = actor.getSnapshot();
498
+ if (predicate(current)) {
499
+ resume(Effect.succeed(current));
500
+ return;
501
+ }
502
+ if (current.status !== 'active') {
503
+ observeError(actor);
504
+ resume(Effect.fail(stoppedError(actor)));
505
+ return;
506
+ }
507
+ let settled = false;
508
+ // oxlint-disable-next-line prefer-const
509
+ let subscription; // avoid TDZ when settling synchronously
510
+ const dispose = () => {
511
+ settled = true;
512
+ subscription?.unsubscribe();
513
+ };
514
+ subscription = actor.subscribe({
515
+ next: snapshot => {
516
+ if (settled || !predicate(snapshot)) {
517
+ return;
518
+ }
519
+ dispose();
520
+ resume(Effect.succeed(snapshot));
521
+ },
522
+ error: () => {
523
+ if (settled) {
524
+ return;
525
+ }
526
+ dispose();
527
+ resume(Effect.fail(stoppedError(actor)));
528
+ },
529
+ complete: () => {
530
+ if (settled) {
531
+ return;
532
+ }
533
+ dispose();
534
+ resume(Effect.fail(stoppedError(actor)));
535
+ }
536
+ });
537
+ if (settled) {
538
+ subscription.unsubscribe();
539
+ }
540
+ return Effect.sync(dispose);
541
+ });
542
+ return options === undefined ? waiting : Effect.timeout(waiting, options.timeout);
543
+ });
544
+
545
+ /**
546
+ * Joins an actor's final result, like `Fiber.join`: succeeds with its `output`
547
+ * when it is done, fails with `snapshot.error` when it errors, and fails with
548
+ * `ActorStoppedError` when it stops without output. Waits for a still-active
549
+ * actor to settle.
550
+ */
551
+ function join(actor) {
552
+ return Effect.callback(resume => {
553
+ const settle = () => {
554
+ const snapshot = actor.getSnapshot();
555
+ if (snapshot.status === 'done') {
556
+ resume(Effect.succeed(snapshot.output));
557
+ } else if (snapshot.status === 'error') {
558
+ resume(Effect.fail(snapshot.error));
559
+ } else {
560
+ resume(Effect.fail(stoppedError(actor)));
561
+ }
562
+ };
563
+ if (actor.getSnapshot().status !== 'active') {
564
+ observeError(actor);
565
+ settle();
566
+ return;
567
+ }
568
+ let settled = false;
569
+ // oxlint-disable-next-line prefer-const
570
+ let subscription; // avoid TDZ when settling synchronously
571
+ const dispose = () => {
572
+ settled = true;
573
+ subscription?.unsubscribe();
574
+ };
575
+ const onSettled = () => {
576
+ if (settled) {
577
+ return;
578
+ }
579
+ dispose();
580
+ settle();
581
+ };
582
+ subscription = actor.subscribe({
583
+ error: onSettled,
584
+ complete: onSettled
585
+ });
586
+ if (settled) {
587
+ subscription.unsubscribe();
588
+ }
589
+ return Effect.sync(dispose);
590
+ });
591
+ }
592
+
593
+ /**
594
+ * Streams the inspection events of the actor's system, as delivered to
595
+ * `system.inspect(…)`. The stream runs until it is interrupted or its scope
596
+ * closes.
597
+ */
598
+ function inspect(actor) {
599
+ return Stream.callback(queue => Effect.acquireRelease(Effect.sync(() => {
600
+ const observer = inspectionEvent => {
601
+ Queue.offerUnsafe(queue, inspectionEvent);
602
+ };
603
+ const inspectable = actor;
604
+ return inspectable.inspect ? inspectable.inspect(observer) : actor.system.inspect(observer);
605
+ }), subscription => Effect.sync(() => {
606
+ subscription.unsubscribe();
607
+ })));
608
+ }
609
+
610
+ /**
611
+ * Streams the events the actor's system could not deliver: sends to a
612
+ * stopped actor, invalid external events and internal events sent from
613
+ * outside their owner. A dead letter is not an actor error. The stream runs
614
+ * until it is interrupted or its scope closes.
615
+ */
616
+ function deadLetters(actor) {
617
+ return Stream.filter(inspect(actor), event => event.type === '@xstate.deadletter');
618
+ }
619
+
620
+ /**
621
+ * Argument an Effect action receives. It mirrors the v6 action argument
622
+ * object: the machine's `context` and the `event` that caused the transition,
623
+ * the actor itself and its family (`self`, `parent`, `children`), the
624
+ * registered `actions`, `actors`, `guards` and `delays`, the actor `system`,
625
+ * and the `params` and `output` the transition passed along.
626
+ */
627
+
628
+ /**
629
+ * An action registered with `setupEffect({ actions })`. It is called
630
+ * synchronously during the transition with the arguments the transition
631
+ * enqueued, and returns an Effect that runs afterwards in the actor's Effect
632
+ * context. The Effect is interrupted when the actor stops; its failures and
633
+ * defects route to the state's `onError`.
634
+ */
635
+
636
+ /**
637
+ * What `setupEffect` returns: the XState `SetupReturn` with an `extend` method
638
+ * that also accepts Effect schemas and Effect-returning actions. Call
639
+ * `createMachine` on it to build a machine whose registered actions and actors
640
+ * contribute to `RequirementsFrom`.
641
+ */
642
+
643
+ function wrapActions(actions) {
644
+ if (!actions) {
645
+ return undefined;
646
+ }
647
+ const wrapped = {};
648
+ for (const key of Object.keys(actions)) {
649
+ const action = actions[key];
650
+ wrapped[key] = args => {
651
+ const result = action(args);
652
+ return Effect.isEffect(result) ? runHostedEffect(args.self, result, `action.${key}`) : result;
653
+ };
654
+ }
655
+ return wrapped;
656
+ }
657
+
658
+ /**
659
+ * Makes `machine.provide` host Effect-returning action overrides the same way
660
+ * `setupEffect` hosts declared actions.
661
+ */
662
+ function decorateMachine(machine) {
663
+ const provide = machine.provide.bind(machine);
664
+ machine.provide = sources => decorateMachine(provide({
665
+ ...sources,
666
+ actions: wrapActions(sources.actions)
667
+ }));
668
+ return machine;
669
+ }
670
+ function decorateEffectSetup(effectSetup) {
671
+ const createMachine = effectSetup.createMachine.bind(effectSetup);
672
+ effectSetup.createMachine = config => decorateMachine(createMachine(config));
673
+ const extend = effectSetup.extend;
674
+ const extendAny = extend;
675
+ effectSetup.extend = extension => decorateEffectSetup(extendAny({
676
+ ...extension,
677
+ schemas: toStandardSetupSchemas(extension.schemas),
678
+ states: toStandardSetupStates(extension.states),
679
+ actions: wrapActions(extension.actions)
680
+ }));
681
+ return effectSetup;
682
+ }
683
+
684
+ /**
685
+ * The Effect-aware form of XState's `setup`. It accepts Effect `Schema` values
686
+ * wherever `setup` accepts Standard Schemas, and actions that return an
687
+ * Effect, which it wraps so the transition stays synchronous while the Effect
688
+ * runs in the actor's Effect context. Everything else, including `actors`,
689
+ * `guards`, `delays` and `extend`, behaves as in `setup`. Machines built from
690
+ * it must be started with `createEffectActor`.
691
+ */
692
+
693
+ function setupEffect(config = {}) {
694
+ return decorateEffectSetup(setup({
695
+ ...config,
696
+ schemas: toStandardSetupSchemas(config.schemas),
697
+ states: toStandardSetupStates(config.states),
698
+ actions: wrapActions(config.actions)
699
+ }));
700
+ }
701
+
702
+ export { deadLetters, emitted, fromEffect, fromEffectEventStream, fromEffectStream, inspect, join, send, setupEffect, snapshots, waitFor };