@xstate/effect 1.0.0-beta.0 → 1.0.0-beta.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.
- package/README.md +3 -2
- package/dist/declarations/src/effectActor.d.ts +10 -2
- package/dist/declarations/src/errors.d.ts +12 -0
- package/dist/declarations/src/index.d.ts +2 -1
- package/dist/declarations/src/sendAndAwait.d.ts +14 -0
- package/dist/declarations/src/test.d.ts +1 -13
- package/dist/sendAndAwait-bf1d4117.js +14 -0
- package/dist/{state-a2154dce.js → state-54c1cda0.js} +126 -60
- package/dist/xstate-effect-atom.js +2 -2
- package/dist/xstate-effect-test.js +1 -13
- package/dist/xstate-effect.js +19 -3
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -264,12 +264,13 @@ See [atoms and React](docs/atoms-and-react.md) for complete examples with import
|
|
|
264
264
|
|
|
265
265
|
## Testing and errors
|
|
266
266
|
|
|
267
|
-
<!-- error types from src/errors.ts; timeout failure from src/actor.ts -->
|
|
267
|
+
<!-- error types and causeFromError from src/errors.ts; timeout failure from src/actor.ts -->
|
|
268
268
|
|
|
269
|
-
- Use `sendAndAwait` from `@xstate/effect
|
|
269
|
+
- Use `sendAndAwait` from `@xstate/effect` to acknowledge one event after its transition and immediate effects. It does not wait for child replies, invoked work, background actions or future timers.
|
|
270
270
|
- Use `TestClock` to drive deadlines without waiting for real time.
|
|
271
271
|
- `ActorStoppedError` reports a stop before an awaited result.
|
|
272
272
|
- `EffectFailure<E>` carries the original `Cause<E>` in task and stream error snapshots, including defects and self-interruption.
|
|
273
|
+
- Use `causeFromError(error)` to obtain the original Cause from `EffectFailure` or wrap an ordinary error. Use `Cause.findErrorOption` to inspect its typed failure.
|
|
273
274
|
- Timed waits fail with Effect's `Cause.TimeoutError`.
|
|
274
275
|
- `join` replays the original Cause and preserves a task's typed failure. Unexpected machine errors have type `unknown`.
|
|
275
276
|
|
|
@@ -41,6 +41,9 @@ export declare class EffectActor<TLogic extends AnyActorLogic> implements ActorR
|
|
|
41
41
|
private readonly _listeners;
|
|
42
42
|
private _settled;
|
|
43
43
|
private readonly _pending;
|
|
44
|
+
private _inStep;
|
|
45
|
+
private _deliveryDepth;
|
|
46
|
+
private _stopHeld;
|
|
44
47
|
constructor(logic: TLogic, root: AnyActor, snapshot: SnapshotFrom<TLogic>, _mailbox: Queue.Queue<MailboxItem<EventFromLogic<TLogic>, SnapshotFrom<TLogic>>>, _stopExecution: () => void, _inspectors: Set<(event: InspectionEvent) => void>);
|
|
45
48
|
getSnapshot(): SnapshotFrom<TLogic>;
|
|
46
49
|
getPersistedSnapshot(): PersistedSnapshotOf<TLogic>;
|
|
@@ -48,13 +51,18 @@ export declare class EffectActor<TLogic extends AnyActorLogic> implements ActorR
|
|
|
48
51
|
send(event: EventFromLogic<TLogic>): void;
|
|
49
52
|
private _deliveryError;
|
|
50
53
|
private _stoppedError;
|
|
51
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Stops the actor, its children and every Effect it hosts. If a listener or
|
|
56
|
+
* an observer calls `stop()` while the actor delivers a macrostep to it, the
|
|
57
|
+
* actor stops when that macrostep ends. `createActor` does the same.
|
|
58
|
+
*/
|
|
52
59
|
stop(): this;
|
|
53
60
|
subscribe(observer: Observer<SnapshotFrom<TLogic>>): Subscription;
|
|
54
61
|
subscribe(nextListener?: (snapshot: SnapshotFrom<TLogic>) => void, errorListener?: (error: any) => void, completeListener?: () => void): Subscription;
|
|
55
62
|
on<TType extends EmittedFrom<TLogic>['type'] | '*'>(type: TType, handler: (emitted: EmittedFrom<TLogic> & (TType extends '*' ? unknown : {
|
|
56
63
|
type: TType;
|
|
57
64
|
})) => void): Subscription;
|
|
65
|
+
private _deliver;
|
|
58
66
|
/**
|
|
59
67
|
* Observes the inspection events of this actor and its children: every
|
|
60
68
|
* actor creation and transition of the execution.
|
|
@@ -62,7 +70,7 @@ export declare class EffectActor<TLogic extends AnyActorLogic> implements ActorR
|
|
|
62
70
|
inspect(observer: Observer<InspectionEvent> | ((event: InspectionEvent) => void)): Subscription;
|
|
63
71
|
[symbolObservable](): this;
|
|
64
72
|
toJSON(): {
|
|
65
|
-
|
|
73
|
+
'@actor': string;
|
|
66
74
|
};
|
|
67
75
|
}
|
|
68
76
|
export {};
|
|
@@ -53,6 +53,18 @@ declare const NotReadyError_base: new <A extends Record<string, any> = {}>(args:
|
|
|
53
53
|
export declare class NotReadyError extends NotReadyError_base {
|
|
54
54
|
get message(): string;
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Returns an EffectFailure's original Cause, or wraps an ordinary error with
|
|
58
|
+
* Cause.fail. Defects and interruption in an existing Cause are preserved.
|
|
59
|
+
*
|
|
60
|
+
* @experimental
|
|
61
|
+
*/
|
|
62
|
+
export declare function causeFromError<E>(error: E): Cause.Cause<UnwrapEffectFailure<E>>;
|
|
63
|
+
/**
|
|
64
|
+
* Extracts the typed failure from EffectFailure while retaining ordinary errors.
|
|
65
|
+
*
|
|
66
|
+
* @experimental
|
|
67
|
+
*/
|
|
56
68
|
export type UnwrapEffectFailure<E> = E extends EffectFailure<infer Failure> ? Failure : E;
|
|
57
69
|
declare const EventRejectedError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => Cause.YieldableError & {
|
|
58
70
|
readonly _tag: "EventRejectedError";
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export { createEffectLogic, createEffectEventStreamLogic, createEffectStreamLogic, type EffectActorLogic, type EffectLogicBrand, type EffectSnapshot, type EffectSource, type EffectSourceArgs, type EffectStreamSource, type EffectStreamActorLogic, type EffectStreamSnapshot } from "./effectLogic.js";
|
|
2
2
|
export { createEffectActor, type EffectActorOptions } from "./createEffectActor.js";
|
|
3
3
|
export { EffectActor } from "./effectActor.js";
|
|
4
|
+
export { sendAndAwait } from "./sendAndAwait.js";
|
|
4
5
|
export { ActorScope, withActorScope } from "./actorScope.js";
|
|
5
6
|
export { deadLetters, emitted, inspect, join, send, snapshots, waitFor, type EmittedEventFrom, type SendableEventFrom, type WaitForOptions } from "./actor.js";
|
|
6
|
-
export { ActorStoppedError, EventRejectedError, EffectFailure, EffectInterruptedError } from "./errors.js";
|
|
7
|
+
export { ActorStoppedError, EventRejectedError, EffectFailure, EffectInterruptedError, causeFromError, type UnwrapEffectFailure } from "./errors.js";
|
|
7
8
|
export { setupEffect, type EffectAction, type EffectActionArgs, type EffectSetupReturn } from "./setupEffect.js";
|
|
8
9
|
export { type RequirementsFrom } from "./types.js";
|
|
9
10
|
export { taggedState, type StateTag, type TaggedState, type TaggedStateFrom } from "./state.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Effect } from 'effect';
|
|
2
|
+
import type { AnyActorLogic, EventFromLogic, SnapshotFrom } from 'xstate';
|
|
3
|
+
import type { EffectActor } from "./effectActor.js";
|
|
4
|
+
import type { ActorStoppedError, EventRejectedError } from "./errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* Sends one event and acknowledges its transition and immediate effects.
|
|
7
|
+
* Ignored events are acknowledged too, as are events whose actions fail; the
|
|
8
|
+
* failure is processed afterwards. Child replies, invoked work, background
|
|
9
|
+
* action bodies and future timers are not awaited. Interrupting the waiter
|
|
10
|
+
* detaches its receipt without retracting the event.
|
|
11
|
+
*
|
|
12
|
+
* @experimental
|
|
13
|
+
*/
|
|
14
|
+
export declare function sendAndAwait<TLogic extends AnyActorLogic>(actor: EffectActor<TLogic>, event: EventFromLogic<TLogic>): Effect.Effect<SnapshotFrom<TLogic>, ActorStoppedError | EventRejectedError>;
|
|
@@ -1,13 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type { AnyActorLogic, EventFromLogic, SnapshotFrom } from 'xstate';
|
|
3
|
-
import type { EffectActor } from "./effectActor.js";
|
|
4
|
-
import type { ActorStoppedError, EventRejectedError } from "./errors.js";
|
|
5
|
-
/**
|
|
6
|
-
* Sends one mailbox item and awaits its macrostep publication and immediate
|
|
7
|
-
* effect scheduling. Ignored events are acknowledged too. Does not await
|
|
8
|
-
* invoked work, background actions or future timers. Interrupting the waiter
|
|
9
|
-
* detaches its receipt without retracting the event.
|
|
10
|
-
*
|
|
11
|
-
* @experimental
|
|
12
|
-
*/
|
|
13
|
-
export declare function sendAndAwait<TLogic extends AnyActorLogic>(actor: EffectActor<TLogic>, event: EventFromLogic<TLogic>): Effect.Effect<SnapshotFrom<TLogic>, ActorStoppedError | EventRejectedError>;
|
|
1
|
+
export { sendAndAwait } from "./sendAndAwait.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sends one event and acknowledges its transition and immediate effects.
|
|
3
|
+
* Ignored events are acknowledged too, as are events whose actions fail; the
|
|
4
|
+
* failure is processed afterwards. Child replies, invoked work, background
|
|
5
|
+
* action bodies and future timers are not awaited. Interrupting the waiter
|
|
6
|
+
* detaches its receipt without retracting the event.
|
|
7
|
+
*
|
|
8
|
+
* @experimental
|
|
9
|
+
*/
|
|
10
|
+
function sendAndAwait(actor, event) {
|
|
11
|
+
return actor._sendAndAwait(event);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { sendAndAwait as s };
|
|
@@ -79,10 +79,22 @@ class NotReadyError extends Data.TaggedError('NotReadyError') {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
/**
|
|
82
|
+
/**
|
|
83
|
+
* Returns an EffectFailure's original Cause, or wraps an ordinary error with
|
|
84
|
+
* Cause.fail. Defects and interruption in an existing Cause are preserved.
|
|
85
|
+
*
|
|
86
|
+
* @experimental
|
|
87
|
+
*/
|
|
83
88
|
function causeFromError(error) {
|
|
84
89
|
return error instanceof EffectFailure ? error.cause : Cause.fail(error);
|
|
85
90
|
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Extracts the typed failure from EffectFailure while retaining ordinary errors.
|
|
94
|
+
*
|
|
95
|
+
* @experimental
|
|
96
|
+
*/
|
|
97
|
+
|
|
86
98
|
/**
|
|
87
99
|
* An event rejected at the actor's delivery boundary.
|
|
88
100
|
*
|
|
@@ -90,6 +102,8 @@ function causeFromError(error) {
|
|
|
90
102
|
*/
|
|
91
103
|
class EventRejectedError extends Data.TaggedError('EventRejectedError') {}
|
|
92
104
|
|
|
105
|
+
/** @internal */
|
|
106
|
+
|
|
93
107
|
const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
|
|
94
108
|
|
|
95
109
|
/**
|
|
@@ -142,6 +156,9 @@ class EffectActor {
|
|
|
142
156
|
this._listeners = new Map();
|
|
143
157
|
this._settled = false;
|
|
144
158
|
this._pending = new Set();
|
|
159
|
+
this._inStep = false;
|
|
160
|
+
this._deliveryDepth = 0;
|
|
161
|
+
this._stopHeld = false;
|
|
145
162
|
this._root = root;
|
|
146
163
|
this.id = root.id;
|
|
147
164
|
this.address = root.address;
|
|
@@ -203,11 +220,6 @@ class EffectActor {
|
|
|
203
220
|
}
|
|
204
221
|
return undefined;
|
|
205
222
|
}
|
|
206
|
-
|
|
207
|
-
/** @internal */
|
|
208
|
-
_rejectReceipts() {
|
|
209
|
-
for (const receipt of this._pending) this._completeReceipt(receipt, Exit.fail(this._stoppedError()));
|
|
210
|
-
}
|
|
211
223
|
_stoppedError() {
|
|
212
224
|
return new ActorStoppedError({
|
|
213
225
|
actorId: this.id,
|
|
@@ -223,8 +235,16 @@ class EffectActor {
|
|
|
223
235
|
resume?.(exit);
|
|
224
236
|
}
|
|
225
237
|
|
|
226
|
-
/**
|
|
238
|
+
/**
|
|
239
|
+
* Stops the actor, its children and every Effect it hosts. If a listener or
|
|
240
|
+
* an observer calls `stop()` while the actor delivers a macrostep to it, the
|
|
241
|
+
* actor stops when that macrostep ends. `createActor` does the same.
|
|
242
|
+
*/
|
|
227
243
|
stop() {
|
|
244
|
+
if (this._inStep && this._deliveryDepth > 0) {
|
|
245
|
+
this._stopHeld = true;
|
|
246
|
+
return this;
|
|
247
|
+
}
|
|
228
248
|
this._stopExecution();
|
|
229
249
|
return this;
|
|
230
250
|
}
|
|
@@ -265,9 +285,20 @@ class EffectActor {
|
|
|
265
285
|
|
|
266
286
|
/** @internal Delivers an emitted event to `on` listeners. */
|
|
267
287
|
_emit(event) {
|
|
288
|
+
if (this._settled) return;
|
|
268
289
|
const listeners = [...(this._listeners.get(event.type) ?? []), ...(this._listeners.get('*') ?? [])];
|
|
269
|
-
|
|
270
|
-
|
|
290
|
+
this._deliver(() => {
|
|
291
|
+
for (const listener of listeners) {
|
|
292
|
+
safeCall(listener, event);
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
_deliver(notify) {
|
|
297
|
+
this._deliveryDepth++;
|
|
298
|
+
try {
|
|
299
|
+
notify();
|
|
300
|
+
} finally {
|
|
301
|
+
this._deliveryDepth--;
|
|
271
302
|
}
|
|
272
303
|
}
|
|
273
304
|
|
|
@@ -289,48 +320,66 @@ class EffectActor {
|
|
|
289
320
|
}
|
|
290
321
|
toJSON() {
|
|
291
322
|
return {
|
|
292
|
-
|
|
323
|
+
'@actor': this.address
|
|
293
324
|
};
|
|
294
325
|
}
|
|
295
326
|
|
|
296
|
-
/** @internal
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
327
|
+
/** @internal */
|
|
328
|
+
_runStep(step) {
|
|
329
|
+
return Effect.gen({
|
|
330
|
+
self: this
|
|
331
|
+
}, function* () {
|
|
332
|
+
if (this._settled) return;
|
|
333
|
+
this._snapshot = step.snapshot;
|
|
334
|
+
this._inStep = true;
|
|
335
|
+
yield* step.effects;
|
|
336
|
+
if (this._settled) return;
|
|
337
|
+
if (this._snapshot.status !== 'active') {
|
|
338
|
+
this._settle(this._snapshot, step.kind === 'transition' ? step.receipt : undefined);
|
|
339
|
+
} else if (step.kind === 'transition') {
|
|
340
|
+
this._deliver(() => {
|
|
341
|
+
for (const observer of this._observers) {
|
|
342
|
+
safeCall(observer.next, this._snapshot);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
304
345
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
346
|
+
}).pipe(Effect.onExit(exit => Effect.sync(() => {
|
|
347
|
+
this._inStep = false;
|
|
348
|
+
if (this._stopHeld) {
|
|
349
|
+
this._stopExecution();
|
|
350
|
+
} else if (step.kind === 'transition' && Exit.isSuccess(exit)) {
|
|
351
|
+
this._completeReceipt(step.receipt, step.rejection ? Exit.fail(step.rejection) : Exit.succeed(step.snapshot));
|
|
352
|
+
}
|
|
353
|
+
})));
|
|
308
354
|
}
|
|
309
355
|
|
|
310
|
-
/** @internal
|
|
356
|
+
/** @internal Settles the actor and notifies its observers. */
|
|
311
357
|
_settle(snapshot, processing) {
|
|
312
358
|
if (this._settled) {
|
|
313
359
|
return;
|
|
314
360
|
}
|
|
315
361
|
this._snapshot = snapshot;
|
|
316
362
|
this._settled = true;
|
|
317
|
-
for (const receipt of this._pending) {
|
|
318
|
-
if (receipt !== processing) this._completeReceipt(receipt, Exit.fail(this._stoppedError()));
|
|
319
|
-
}
|
|
320
363
|
const observers = [...this._observers];
|
|
321
364
|
this._observers.clear();
|
|
322
365
|
const status = snapshot.status;
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
366
|
+
this._deliver(() => {
|
|
367
|
+
if (status === 'done') {
|
|
368
|
+
for (const observer of observers) {
|
|
369
|
+
safeCall(observer.next, snapshot);
|
|
370
|
+
}
|
|
326
371
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
372
|
+
for (const observer of observers) {
|
|
373
|
+
if (status === 'error') {
|
|
374
|
+
safeCall(observer.error, snapshot.error);
|
|
375
|
+
} else {
|
|
376
|
+
safeCall(observer.complete);
|
|
377
|
+
}
|
|
333
378
|
}
|
|
379
|
+
});
|
|
380
|
+
this._completeReceipt(processing, Exit.succeed(snapshot));
|
|
381
|
+
for (const receipt of this._pending) {
|
|
382
|
+
this._completeReceipt(receipt, Exit.fail(this._stoppedError()));
|
|
334
383
|
}
|
|
335
384
|
}
|
|
336
385
|
|
|
@@ -539,15 +588,16 @@ function closeEffectHost(host) {
|
|
|
539
588
|
discard: true
|
|
540
589
|
}).pipe(Effect.andThen(Scope.close(host.scope, Exit.void))));
|
|
541
590
|
}
|
|
591
|
+
const EFFECT_FORWARD = 'xstate.effect.forward';
|
|
542
592
|
|
|
543
|
-
/**
|
|
544
|
-
* Delivers a stream item to the parent as an event. This runs outside a
|
|
545
|
-
* transition, so it uses the system relay like core's observable logic does.
|
|
546
|
-
*/
|
|
593
|
+
/** Queues a stream item for the source actor to forward in its transition. */
|
|
547
594
|
function relayToParent(actor, event) {
|
|
548
595
|
const actorWithParent = actor;
|
|
549
596
|
if (actorWithParent._parent) {
|
|
550
|
-
actor.system._relay(actorWithParent, actorWithParent
|
|
597
|
+
actor.system._relay(actorWithParent, actorWithParent, {
|
|
598
|
+
type: EFFECT_FORWARD,
|
|
599
|
+
event
|
|
600
|
+
});
|
|
551
601
|
}
|
|
552
602
|
}
|
|
553
603
|
|
|
@@ -761,12 +811,12 @@ function createEffectActor(logic, ...[options]) {
|
|
|
761
811
|
}
|
|
762
812
|
runFork(Queue.shutdown(mailbox));
|
|
763
813
|
if (!actor._isSettled) {
|
|
764
|
-
actor.
|
|
765
|
-
|
|
814
|
+
const current = actor.getSnapshot();
|
|
815
|
+
actor._settle(current.status === 'active' ? {
|
|
816
|
+
...current,
|
|
766
817
|
status: 'stopped'
|
|
767
|
-
});
|
|
818
|
+
} : current);
|
|
768
819
|
}
|
|
769
|
-
actor._rejectReceipts();
|
|
770
820
|
closeEffectHost(host);
|
|
771
821
|
};
|
|
772
822
|
|
|
@@ -805,7 +855,11 @@ function createEffectActor(logic, ...[options]) {
|
|
|
805
855
|
});
|
|
806
856
|
}));
|
|
807
857
|
const loop = Effect.gen(function* () {
|
|
808
|
-
yield*
|
|
858
|
+
yield* actor._runStep({
|
|
859
|
+
kind: 'start',
|
|
860
|
+
snapshot,
|
|
861
|
+
effects: executeEffects(effects)
|
|
862
|
+
});
|
|
809
863
|
while (snapshot.status === 'active' && !stopped) {
|
|
810
864
|
delivered = undefined;
|
|
811
865
|
const received = yield* Effect.promise(() => durable.waitForEvent().catch(() => undefined));
|
|
@@ -820,6 +874,11 @@ function createEffectActor(logic, ...[options]) {
|
|
|
820
874
|
const errorEvent = logic.getExecutionErrorEvent?.(snapshot, item.error);
|
|
821
875
|
if (!errorEvent) {
|
|
822
876
|
snapshot = errorSnapshot(snapshot, item.error);
|
|
877
|
+
yield* actor._runStep({
|
|
878
|
+
kind: 'transition',
|
|
879
|
+
snapshot,
|
|
880
|
+
effects: Effect.void
|
|
881
|
+
});
|
|
823
882
|
break;
|
|
824
883
|
}
|
|
825
884
|
event = errorEvent;
|
|
@@ -830,22 +889,28 @@ function createEffectActor(logic, ...[options]) {
|
|
|
830
889
|
[snapshot, effects] = durable.transition(snapshot, event);
|
|
831
890
|
} catch (error) {
|
|
832
891
|
snapshot = errorSnapshot(snapshot, error);
|
|
833
|
-
actor.
|
|
834
|
-
|
|
892
|
+
yield* actor._runStep({
|
|
893
|
+
kind: 'transition',
|
|
894
|
+
snapshot,
|
|
895
|
+
effects: Effect.void,
|
|
896
|
+
receipt
|
|
897
|
+
});
|
|
835
898
|
break;
|
|
836
899
|
}
|
|
837
|
-
actor._publish(snapshot, receipt);
|
|
838
|
-
if (stopped) break;
|
|
839
900
|
const rejectedReason = effects.length === 1 && effects[0].effect.type === '@xstate.deadLetter' && 'reason' in effects[0].effect && effects[0].effect.reason === 'invalidEvent' ? effects[0].effect.reason : undefined;
|
|
840
|
-
yield*
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
901
|
+
yield* actor._runStep({
|
|
902
|
+
kind: 'transition',
|
|
903
|
+
snapshot,
|
|
904
|
+
effects: executeEffects(effects),
|
|
905
|
+
receipt,
|
|
906
|
+
rejection: rejectedReason !== undefined ? new EventRejectedError({
|
|
907
|
+
actorId: actor.id,
|
|
908
|
+
event,
|
|
909
|
+
reason: rejectedReason
|
|
910
|
+
}) : undefined
|
|
911
|
+
});
|
|
846
912
|
}
|
|
847
913
|
if (!stopped) {
|
|
848
|
-
actor._publish(snapshot);
|
|
849
914
|
if (snapshot.status !== 'active') {
|
|
850
915
|
stopChildren(snapshot);
|
|
851
916
|
closeEffectHost(host);
|
|
@@ -855,13 +920,14 @@ function createEffectActor(logic, ...[options]) {
|
|
|
855
920
|
yield* Effect.forkIn(loop, actorScope);
|
|
856
921
|
return {
|
|
857
922
|
actor,
|
|
858
|
-
host
|
|
923
|
+
host,
|
|
924
|
+
stopNow: stop
|
|
859
925
|
};
|
|
860
926
|
}), ({
|
|
861
|
-
|
|
862
|
-
|
|
927
|
+
host,
|
|
928
|
+
stopNow
|
|
863
929
|
}) => Effect.gen(function* () {
|
|
864
|
-
|
|
930
|
+
stopNow();
|
|
865
931
|
if (host.closing) {
|
|
866
932
|
yield* Fiber.join(host.closing);
|
|
867
933
|
} else {
|
|
@@ -934,4 +1000,4 @@ function taggedState(snapshot) {
|
|
|
934
1000
|
};
|
|
935
1001
|
}
|
|
936
1002
|
|
|
937
|
-
export { ActorStoppedError as A,
|
|
1003
|
+
export { ActorStoppedError as A, EFFECT_FORWARD as E, NotReadyError as N, causeFromError as a, EffectFailure as b, createEffectActor as c, runHostedEffect as d, EffectActor as e, ActorScope as f, EventRejectedError as g, EffectInterruptedError as h, relayToParent as r, startHostedEffect as s, taggedState as t, withActorScope as w };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Cause } from 'effect';
|
|
2
2
|
import { Atom, AsyncResult } from 'effect/reactivity';
|
|
3
3
|
import { StateMachine } from 'xstate';
|
|
4
|
-
import { c as createEffectActor, a as causeFromError, N as NotReadyError, t as taggedState } from './state-
|
|
5
|
-
export { N as NotReadyError } from './state-
|
|
4
|
+
import { c as createEffectActor, a as causeFromError, N as NotReadyError, t as taggedState } from './state-54c1cda0.js';
|
|
5
|
+
export { N as NotReadyError } from './state-54c1cda0.js';
|
|
6
6
|
import 'xstate/durable';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -1,13 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Sends one mailbox item and awaits its macrostep publication and immediate
|
|
3
|
-
* effect scheduling. Ignored events are acknowledged too. Does not await
|
|
4
|
-
* invoked work, background actions or future timers. Interrupting the waiter
|
|
5
|
-
* detaches its receipt without retracting the event.
|
|
6
|
-
*
|
|
7
|
-
* @experimental
|
|
8
|
-
*/
|
|
9
|
-
function sendAndAwait(actor, event) {
|
|
10
|
-
return actor._sendAndAwait(event);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export { sendAndAwait };
|
|
1
|
+
export { s as sendAndAwait } from './sendAndAwait-bf1d4117.js';
|
package/dist/xstate-effect.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Schema, Effect, Stream, Cause, Exit, Queue, Data } from 'effect';
|
|
2
2
|
import { createStepLogic, setup } from 'xstate';
|
|
3
|
-
import { s as startHostedEffect, r as relayToParent,
|
|
4
|
-
export {
|
|
3
|
+
import { s as startHostedEffect, E as EFFECT_FORWARD, r as relayToParent, b as EffectFailure, A as ActorStoppedError, a as causeFromError, d as runHostedEffect } from './state-54c1cda0.js';
|
|
4
|
+
export { f as ActorScope, A as ActorStoppedError, e as EffectActor, b as EffectFailure, h as EffectInterruptedError, g as EventRejectedError, a as causeFromError, c as createEffectActor, t as taggedState, w as withActorScope } from './state-54c1cda0.js';
|
|
5
|
+
export { s as sendAndAwait } from './sendAndAwait-bf1d4117.js';
|
|
5
6
|
import { dual } from 'effect/Function';
|
|
6
7
|
import 'xstate/durable';
|
|
7
8
|
|
|
@@ -389,7 +390,9 @@ function createEffectEventStreamLogic(sourceOrConfig) {
|
|
|
389
390
|
const stream = config.stream;
|
|
390
391
|
const logic = createStepLogic({
|
|
391
392
|
id: config.id,
|
|
392
|
-
validator: config.validator
|
|
393
|
+
validator: config.validator && {
|
|
394
|
+
check: request => request.kind === 'event' && request.event.type === EFFECT_FORWARD ? undefined : config.validator.check(request)
|
|
395
|
+
},
|
|
393
396
|
schemas: toLogicSchemas(config.schemas),
|
|
394
397
|
context: undefined,
|
|
395
398
|
run: ({
|
|
@@ -398,6 +401,10 @@ function createEffectEventStreamLogic(sourceOrConfig) {
|
|
|
398
401
|
self,
|
|
399
402
|
system
|
|
400
403
|
}, enq) => {
|
|
404
|
+
if (event.type === EFFECT_FORWARD) {
|
|
405
|
+
enq.sendBack(event.event);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
401
408
|
if (event.type === EFFECT_COMPLETE) {
|
|
402
409
|
return {
|
|
403
410
|
status: 'done',
|
|
@@ -433,6 +440,9 @@ function createEffectEventStreamLogic(sourceOrConfig) {
|
|
|
433
440
|
}));
|
|
434
441
|
}
|
|
435
442
|
});
|
|
443
|
+
Object.assign(logic, {
|
|
444
|
+
isInternalEventType: eventType => eventType === EFFECT_FORWARD
|
|
445
|
+
});
|
|
436
446
|
return brandLogic(logic, undefined, undefined);
|
|
437
447
|
}
|
|
438
448
|
|
|
@@ -748,6 +758,12 @@ function wrapActions(actions) {
|
|
|
748
758
|
}
|
|
749
759
|
return Effect.isEffect(result) ? runHostedEffect(args.self, result, `action.${key}`) : result;
|
|
750
760
|
};
|
|
761
|
+
// Built-in effect descriptors use these reserved prefixes.
|
|
762
|
+
if (!key.startsWith('xstate.') && !key.startsWith('@xstate.')) {
|
|
763
|
+
Object.defineProperty(wrapped[key], 'name', {
|
|
764
|
+
value: key
|
|
765
|
+
});
|
|
766
|
+
}
|
|
751
767
|
}
|
|
752
768
|
return wrapped;
|
|
753
769
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xstate/effect",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Effect integration for XState",
|
|
6
6
|
"keywords": [
|
|
@@ -33,14 +33,14 @@
|
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@oxlint/plugins": "^1.76.0",
|
|
35
35
|
"effect": "^4.0.0",
|
|
36
|
-
"xstate": "^6.0.0-beta.
|
|
36
|
+
"xstate": "^6.0.0-beta.3"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@oxlint/plugins": "^1.76.0",
|
|
40
40
|
"effect": "4.0.6",
|
|
41
41
|
"fast-check": "4.10.2",
|
|
42
|
-
"@xstate/test": "^2.0.0-beta.
|
|
43
|
-
"xstate": "^6.0.0-beta.
|
|
42
|
+
"@xstate/test": "^2.0.0-beta.1",
|
|
43
|
+
"xstate": "^6.0.0-beta.3"
|
|
44
44
|
},
|
|
45
45
|
"preconstruct": {
|
|
46
46
|
"entrypoints": [
|