@xstate/effect 0.1.0-alpha.6 → 1.0.0-alpha.10
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 +35 -18
- package/dist/declarations/src/actor.d.ts +4 -4
- package/dist/declarations/src/atom.d.ts +8 -9
- package/dist/declarations/src/createEffectActor.d.ts +16 -6
- package/dist/declarations/src/effectActor.d.ts +19 -13
- package/dist/declarations/src/{fromEffect.d.ts → effectLogic.d.ts} +28 -30
- package/dist/declarations/src/errors.d.ts +23 -6
- package/dist/declarations/src/index.d.ts +4 -3
- package/dist/declarations/src/oxlint.d.ts +2 -0
- package/dist/declarations/src/persistence.d.ts +39 -0
- package/dist/declarations/src/schema.d.ts +2 -2
- package/dist/declarations/src/setupEffect.d.ts +48 -13
- package/dist/declarations/src/state.d.ts +8 -7
- package/dist/declarations/src/test.d.ts +11 -0
- package/dist/declarations/src/types.d.ts +2 -3
- package/dist/{state-14a1fecf.js → state-a3f54e06.js} +236 -90
- package/dist/xstate-effect-atom.js +10 -8
- package/dist/xstate-effect-oxlint.d.ts +3 -0
- package/dist/xstate-effect-oxlint.js +124 -0
- package/dist/xstate-effect-test.d.ts +2 -0
- package/dist/xstate-effect-test.js +11 -0
- package/dist/xstate-effect.js +231 -54
- package/package.json +18 -5
- package/dist/declarations/src/brands.d.ts +0 -1
|
@@ -1,13 +1,79 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { stopActor, terminateActor, deliverEvent } from 'xstate';
|
|
1
|
+
import { Cause, Data, Queue, Effect, Exit, Fiber, Scope, Context, Clock, Duration } from 'effect';
|
|
2
|
+
import { StateMachine, stopActor, terminateActor, deliverEvent, isMachineSnapshot } from 'xstate';
|
|
3
3
|
import { createDurable } from 'xstate/durable';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
function _checkPrivateRedeclaration(e, t) {
|
|
6
|
+
if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function _classPrivateFieldInitSpec(e, t, a) {
|
|
10
|
+
_checkPrivateRedeclaration(e, t), t.set(e, a);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function _checkInRHS(e) {
|
|
14
|
+
if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null"));
|
|
15
|
+
return e;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function _assertClassBrand(e, t, n) {
|
|
19
|
+
if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
|
|
20
|
+
throw new TypeError("Private element is not present on this object");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function _classPrivateFieldGet2(s, a) {
|
|
24
|
+
return s.get(_assertClassBrand(s, a));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var _effectFailure = /*#__PURE__*/new WeakMap();
|
|
28
|
+
/** Preserves an Effect failure, defect or interruption through XState error routing. */
|
|
29
|
+
class EffectFailure extends Error {
|
|
30
|
+
static is(value) {
|
|
31
|
+
return typeof value === 'object' && value !== null && _effectFailure.has(_checkInRHS(value)) && _classPrivateFieldGet2(_effectFailure, value);
|
|
32
|
+
}
|
|
33
|
+
constructor(cause) {
|
|
34
|
+
super(Cause.pretty(cause));
|
|
35
|
+
this.cause = cause;
|
|
36
|
+
this._tag = 'EffectFailure';
|
|
37
|
+
_classPrivateFieldInitSpec(this, _effectFailure, true);
|
|
38
|
+
this.name = 'EffectFailure';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** @deprecated Inspect `EffectFailure.cause` for interruption instead. */
|
|
43
|
+
class EffectInterruptedError extends Data.TaggedError('EffectInterruptedError') {
|
|
44
|
+
get message() {
|
|
45
|
+
return 'Effect was interrupted before the actor completed';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Reported by `waitFor` when the actor stops or errors before a snapshot
|
|
51
|
+
* matches, and by `join` when the actor stops without output. `join` reports
|
|
52
|
+
* an errored actor's outcome instead, preserving an Effect failure's Cause.
|
|
53
|
+
*/
|
|
54
|
+
class ActorStoppedError extends Data.TaggedError('ActorStoppedError') {
|
|
55
|
+
get message() {
|
|
56
|
+
return `Actor "${this.actorId}" ${this.snapshot.status === 'error' ? 'errored' : 'stopped'} before completing`;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Reported by the `send` atom of `createActorAtoms` when an event is sent
|
|
62
|
+
* before the actor's runtime has finished building.
|
|
63
|
+
*/
|
|
64
|
+
class NotReadyError extends Data.TaggedError('NotReadyError') {
|
|
65
|
+
get message() {
|
|
66
|
+
return 'The actor is not ready yet';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
6
69
|
|
|
7
|
-
|
|
8
|
-
function
|
|
9
|
-
return
|
|
70
|
+
/** @internal */
|
|
71
|
+
function causeFromError(error) {
|
|
72
|
+
return error instanceof EffectFailure ? error.cause : Cause.fail(error);
|
|
10
73
|
}
|
|
74
|
+
/** An event rejected at the actor's delivery boundary. */
|
|
75
|
+
class EventRejectedError extends Data.TaggedError('EventRejectedError') {}
|
|
76
|
+
|
|
11
77
|
const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
|
|
12
78
|
|
|
13
79
|
/**
|
|
@@ -57,6 +123,7 @@ class EffectActor {
|
|
|
57
123
|
this._observers = new Set();
|
|
58
124
|
this._listeners = new Map();
|
|
59
125
|
this._settled = false;
|
|
126
|
+
this._pending = new Set();
|
|
60
127
|
this._root = root;
|
|
61
128
|
this.id = root.id;
|
|
62
129
|
this.address = root.address;
|
|
@@ -73,11 +140,69 @@ class EffectActor {
|
|
|
73
140
|
|
|
74
141
|
/** Sends an event; the actor processes it on its own fiber. */
|
|
75
142
|
send(event) {
|
|
143
|
+
if (this._deliveryError(event)) return;
|
|
144
|
+
Queue.offerUnsafe(this._mailbox, {
|
|
145
|
+
kind: 'event',
|
|
146
|
+
event
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** @internal */
|
|
151
|
+
_sendAndAwait(event) {
|
|
152
|
+
return Effect.callback(resume => {
|
|
153
|
+
const error = this._deliveryError(event);
|
|
154
|
+
if (error) {
|
|
155
|
+
resume(Effect.fail(error));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const receipt = {
|
|
159
|
+
resume: exit => resume(exit)
|
|
160
|
+
};
|
|
161
|
+
this._pending.add(receipt);
|
|
162
|
+
Queue.offerUnsafe(this._mailbox, {
|
|
163
|
+
kind: 'event',
|
|
164
|
+
event,
|
|
165
|
+
receipt
|
|
166
|
+
});
|
|
167
|
+
return Effect.sync(() => {
|
|
168
|
+
this._pending.delete(receipt);
|
|
169
|
+
receipt.resume = undefined;
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
_deliveryError(event) {
|
|
76
174
|
if (this._settled) {
|
|
77
175
|
this.system.deadLetter(undefined, this._root, event, 'stopped');
|
|
78
|
-
return;
|
|
176
|
+
return this._stoppedError();
|
|
79
177
|
}
|
|
80
|
-
|
|
178
|
+
if (this.logic instanceof StateMachine && this.logic.isInternalEventType(event.type)) {
|
|
179
|
+
this.system.deadLetter(undefined, this._root, event, 'internalEvent');
|
|
180
|
+
return new EventRejectedError({
|
|
181
|
+
actorId: this.id,
|
|
182
|
+
event,
|
|
183
|
+
reason: 'internalEvent'
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** @internal */
|
|
190
|
+
_rejectReceipts() {
|
|
191
|
+
for (const receipt of this._pending) this._completeReceipt(receipt, Exit.fail(this._stoppedError()));
|
|
192
|
+
}
|
|
193
|
+
_stoppedError() {
|
|
194
|
+
return new ActorStoppedError({
|
|
195
|
+
actorId: this.id,
|
|
196
|
+
snapshot: this._snapshot
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** @internal */
|
|
201
|
+
_completeReceipt(receipt, exit) {
|
|
202
|
+
if (!receipt || !this._pending.delete(receipt)) return;
|
|
203
|
+
const resume = receipt.resume;
|
|
204
|
+
receipt.resume = undefined;
|
|
205
|
+
resume?.(exit);
|
|
81
206
|
}
|
|
82
207
|
|
|
83
208
|
/** Stops the actor, its children and every Effect it hosts. */
|
|
@@ -146,13 +271,13 @@ class EffectActor {
|
|
|
146
271
|
}
|
|
147
272
|
toJSON() {
|
|
148
273
|
return {
|
|
149
|
-
|
|
150
|
-
id: this.id
|
|
274
|
+
$actor: this.address
|
|
151
275
|
};
|
|
152
276
|
}
|
|
153
277
|
|
|
154
278
|
/** @internal Publishes a snapshot produced by the execution loop. */
|
|
155
|
-
_publish(snapshot) {
|
|
279
|
+
_publish(snapshot, receipt) {
|
|
280
|
+
if (this._settled) return;
|
|
156
281
|
this._snapshot = snapshot;
|
|
157
282
|
const status = snapshot.status;
|
|
158
283
|
if (status === 'active') {
|
|
@@ -161,16 +286,19 @@ class EffectActor {
|
|
|
161
286
|
}
|
|
162
287
|
return;
|
|
163
288
|
}
|
|
164
|
-
this._settle(snapshot);
|
|
289
|
+
this._settle(snapshot, receipt);
|
|
165
290
|
}
|
|
166
291
|
|
|
167
292
|
/** @internal Marks the actor stopped and notifies observers. */
|
|
168
|
-
_settle(snapshot) {
|
|
293
|
+
_settle(snapshot, processing) {
|
|
169
294
|
if (this._settled) {
|
|
170
295
|
return;
|
|
171
296
|
}
|
|
172
297
|
this._snapshot = snapshot;
|
|
173
298
|
this._settled = true;
|
|
299
|
+
for (const receipt of this._pending) {
|
|
300
|
+
if (receipt !== processing) this._completeReceipt(receipt, Exit.fail(this._stoppedError()));
|
|
301
|
+
}
|
|
174
302
|
const observers = [...this._observers];
|
|
175
303
|
this._observers.clear();
|
|
176
304
|
const status = snapshot.status;
|
|
@@ -315,7 +443,7 @@ function trackEffect(actor, host, interrupt) {
|
|
|
315
443
|
* The fiber belongs to the host scope, so closing the owning actor also
|
|
316
444
|
* waits for asynchronous invocation finalizers.
|
|
317
445
|
*/
|
|
318
|
-
function startHostedEffect(actor, effect, spanName, onExit) {
|
|
446
|
+
function startHostedEffect(actor, effect, spanName, onExit, onCancel) {
|
|
319
447
|
const host = requireEffectHost(actor);
|
|
320
448
|
let active = true;
|
|
321
449
|
const traced = Effect.withSpan(spanName, {
|
|
@@ -332,11 +460,18 @@ function startHostedEffect(actor, effect, spanName, onExit) {
|
|
|
332
460
|
}
|
|
333
461
|
active = false;
|
|
334
462
|
untrackEffect(actor, host, cancel);
|
|
463
|
+
onCancel?.();
|
|
335
464
|
interrupt();
|
|
336
465
|
};
|
|
337
|
-
|
|
466
|
+
// Register the fiber before its body runs: the body can synchronously
|
|
467
|
+
// trigger the host's close, which only awaits registered fibers.
|
|
468
|
+
const registered = Effect.withFiber(fiber => {
|
|
469
|
+
Fiber.runIn(fiber, host.scope);
|
|
470
|
+
host.fibers.add(fiber);
|
|
471
|
+
return traced;
|
|
472
|
+
});
|
|
473
|
+
const fiber = Effect.runForkWith(host.context)(registered);
|
|
338
474
|
const interrupt = () => fiber.interruptUnsafe();
|
|
339
|
-
host.fibers.add(fiber);
|
|
340
475
|
fiber.addObserver(exit => {
|
|
341
476
|
host.fibers.delete(fiber);
|
|
342
477
|
if (!active) {
|
|
@@ -352,22 +487,16 @@ function startHostedEffect(actor, effect, spanName, onExit) {
|
|
|
352
487
|
return cancel;
|
|
353
488
|
}
|
|
354
489
|
|
|
355
|
-
/**
|
|
356
|
-
* Runs an Effect in the actor's host context and settles when it exits.
|
|
357
|
-
* Interruption settles without error; failures and defects reject with the
|
|
358
|
-
* squashed cause so the actor's error handling can observe them.
|
|
359
|
-
*/
|
|
490
|
+
/** @internal */
|
|
360
491
|
function runHostedEffect(actor, effect, spanName) {
|
|
361
492
|
return new Promise((resolve, reject) => {
|
|
362
493
|
startHostedEffect(actor, effect, spanName, exit => {
|
|
363
|
-
if (Exit.isSuccess(exit)
|
|
494
|
+
if (Exit.isSuccess(exit)) {
|
|
364
495
|
resolve();
|
|
365
496
|
} else {
|
|
366
|
-
|
|
367
|
-
// oxlint-disable-next-line typescript/prefer-promise-reject-errors
|
|
368
|
-
reject(Cause.squash(exit.cause));
|
|
497
|
+
reject(new EffectFailure(exit.cause));
|
|
369
498
|
}
|
|
370
|
-
});
|
|
499
|
+
}, resolve);
|
|
371
500
|
});
|
|
372
501
|
}
|
|
373
502
|
|
|
@@ -416,6 +545,7 @@ function withActorScope(effect) {
|
|
|
416
545
|
}
|
|
417
546
|
|
|
418
547
|
const XSTATE_TIMER = 'xstate.timer';
|
|
548
|
+
const XSTATE_INIT = 'xstate.init';
|
|
419
549
|
|
|
420
550
|
/** Options for {@link createEffectActor}. */
|
|
421
551
|
|
|
@@ -443,6 +573,8 @@ function createEffectActor(logic, ...[options]) {
|
|
|
443
573
|
const runFork = Effect.runForkWith(context);
|
|
444
574
|
const runPromise = Effect.runPromiseWith(context);
|
|
445
575
|
const mailbox = yield* Queue.unbounded();
|
|
576
|
+
let delivered;
|
|
577
|
+
const getDelivered = () => delivered;
|
|
446
578
|
const timers = new Map();
|
|
447
579
|
// `root` and `actor` are declared after the adapter below; its
|
|
448
580
|
// callbacks only run once they are initialized.
|
|
@@ -453,10 +585,14 @@ function createEffectActor(logic, ...[options]) {
|
|
|
453
585
|
Queue.offerUnsafe(mailbox, item);
|
|
454
586
|
}
|
|
455
587
|
};
|
|
456
|
-
const timerKey = (source,
|
|
588
|
+
const timerKey = (source, timer) => `${source.sessionId}:${JSON.stringify(timer)}`;
|
|
457
589
|
const inspectors = new Set();
|
|
458
590
|
let rootAnnounced = false;
|
|
591
|
+
const clock = Context.get(context, Clock.Clock);
|
|
459
592
|
const durable = createDurable(logic, {
|
|
593
|
+
// Timer deadlines are measured on the same clock the timers sleep
|
|
594
|
+
// on, so a restored timer resumes with its remaining delay.
|
|
595
|
+
now: () => clock.currentTimeMillisUnsafe(),
|
|
460
596
|
executeAction: (action, _metadata, runtime) => {
|
|
461
597
|
// Fire-and-forget: the action starts now and the loop continues.
|
|
462
598
|
// A rejection reaches the machine as an execution error.
|
|
@@ -465,14 +601,14 @@ function createEffectActor(logic, ...[options]) {
|
|
|
465
601
|
if (result && typeof result.then === 'function') {
|
|
466
602
|
void Promise.resolve(result).catch(error => {
|
|
467
603
|
offer({
|
|
468
|
-
|
|
604
|
+
kind: 'actionFailure',
|
|
469
605
|
error
|
|
470
606
|
});
|
|
471
607
|
});
|
|
472
608
|
}
|
|
473
609
|
} catch (error) {
|
|
474
610
|
offer({
|
|
475
|
-
|
|
611
|
+
kind: 'actionFailure',
|
|
476
612
|
error
|
|
477
613
|
});
|
|
478
614
|
}
|
|
@@ -496,7 +632,10 @@ function createEffectActor(logic, ...[options]) {
|
|
|
496
632
|
},
|
|
497
633
|
sendEvent: (source, target, event) => {
|
|
498
634
|
if (isRoot(target)) {
|
|
499
|
-
offer(
|
|
635
|
+
offer({
|
|
636
|
+
kind: 'event',
|
|
637
|
+
event: event
|
|
638
|
+
});
|
|
500
639
|
return;
|
|
501
640
|
}
|
|
502
641
|
deliverEvent(source, target, event);
|
|
@@ -508,25 +647,28 @@ function createEffectActor(logic, ...[options]) {
|
|
|
508
647
|
}
|
|
509
648
|
source._emit(event);
|
|
510
649
|
},
|
|
511
|
-
scheduleTimer: (source,
|
|
512
|
-
const key = timerKey(source,
|
|
650
|
+
scheduleTimer: (source, timer, delay) => {
|
|
651
|
+
const key = timerKey(source, timer);
|
|
513
652
|
timers.get(key)?.interruptUnsafe();
|
|
514
653
|
const fiber = Fiber.runIn(runFork(Effect.andThen(Effect.sleep(Duration.millis(delay)), Effect.sync(() => {
|
|
515
654
|
timers.delete(key);
|
|
516
655
|
const timerEvent = {
|
|
517
656
|
type: XSTATE_TIMER,
|
|
518
|
-
|
|
657
|
+
...timer
|
|
519
658
|
};
|
|
520
659
|
if (isRoot(source)) {
|
|
521
|
-
offer(
|
|
660
|
+
offer({
|
|
661
|
+
kind: 'event',
|
|
662
|
+
event: timerEvent
|
|
663
|
+
});
|
|
522
664
|
} else {
|
|
523
665
|
deliverEvent(source, source, timerEvent);
|
|
524
666
|
}
|
|
525
667
|
}))), actorScope);
|
|
526
668
|
timers.set(key, fiber);
|
|
527
669
|
},
|
|
528
|
-
cancelTimer: (source,
|
|
529
|
-
const key = timerKey(source,
|
|
670
|
+
cancelTimer: (source, timer) => {
|
|
671
|
+
const key = timerKey(source, timer);
|
|
530
672
|
timers.get(key)?.interruptUnsafe();
|
|
531
673
|
timers.delete(key);
|
|
532
674
|
},
|
|
@@ -538,7 +680,12 @@ function createEffectActor(logic, ...[options]) {
|
|
|
538
680
|
}
|
|
539
681
|
}
|
|
540
682
|
},
|
|
541
|
-
waitForEvent: () => runPromise(Queue.take(mailbox))
|
|
683
|
+
waitForEvent: () => runPromise(Queue.take(mailbox)).then(item => {
|
|
684
|
+
delivered = item;
|
|
685
|
+
return item.kind === 'event' ? item.event : {
|
|
686
|
+
type: 'xstate.effect.actionFailure'
|
|
687
|
+
};
|
|
688
|
+
})
|
|
542
689
|
}, {
|
|
543
690
|
inspect: event => {
|
|
544
691
|
// The pure step scope re-materializes the root ref per step and
|
|
@@ -587,13 +734,33 @@ function createEffectActor(logic, ...[options]) {
|
|
|
587
734
|
status: 'stopped'
|
|
588
735
|
});
|
|
589
736
|
}
|
|
737
|
+
actor._rejectReceipts();
|
|
590
738
|
closeEffectHost(host);
|
|
591
739
|
};
|
|
592
740
|
|
|
593
|
-
// The first transition runs here so the handle is
|
|
594
|
-
// Effect succeeds, and the initial actions start before
|
|
595
|
-
|
|
741
|
+
// The first transition (or the restore) runs here so the handle is
|
|
742
|
+
// ready when this Effect succeeds, and the initial actions start before
|
|
743
|
+
// any send. Restoring runs no entry actions; its effects resume
|
|
744
|
+
// machine children, restart running Effect children and re-arm pending
|
|
745
|
+
// timers.
|
|
746
|
+
let [snapshot, effects] = options?.snapshot ? durable.restore(options.snapshot) : durable.initialTransition(options?.input);
|
|
747
|
+
const initial = snapshot;
|
|
748
|
+
if (options?.snapshot && !isMachineSnapshot(initial) && initial.status === 'active') {
|
|
749
|
+
// A restored machine resumes through the effects above. Other logic
|
|
750
|
+
// (an Effect task or stream at the root) reattaches its active work by
|
|
751
|
+
// replaying its init event, as its restored `start` does under
|
|
752
|
+
// `createActor`.
|
|
753
|
+
const [started, startEffects] = durable.transition(snapshot, {
|
|
754
|
+
type: XSTATE_INIT,
|
|
755
|
+
input: 'input' in initial ? initial.input : undefined
|
|
756
|
+
});
|
|
757
|
+
snapshot = started;
|
|
758
|
+
effects = [...effects, ...startEffects];
|
|
759
|
+
}
|
|
596
760
|
const root = durable.getActorRef(snapshot);
|
|
761
|
+
// Restored children are created by the snapshot, not spawned through
|
|
762
|
+
// the adapter; they find this host through their parent chain.
|
|
763
|
+
bindEffectHost(root, host);
|
|
597
764
|
// The root exists from here on; later announcements are step
|
|
598
765
|
// re-materializations, not new actors.
|
|
599
766
|
rootAnnounced = true;
|
|
@@ -601,19 +768,23 @@ function createEffectActor(logic, ...[options]) {
|
|
|
601
768
|
bindEffectHost(actor, host);
|
|
602
769
|
const executeEffects = batch => Effect.promise(() => durable.executeEffects(batch).then(() => undefined, error => {
|
|
603
770
|
offer({
|
|
604
|
-
|
|
771
|
+
kind: 'actionFailure',
|
|
605
772
|
error
|
|
606
773
|
});
|
|
607
774
|
}));
|
|
608
775
|
const loop = Effect.gen(function* () {
|
|
609
776
|
yield* executeEffects(effects);
|
|
610
777
|
while (snapshot.status === 'active' && !stopped) {
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
778
|
+
delivered = undefined;
|
|
779
|
+
const received = yield* Effect.promise(() => durable.waitForEvent().catch(() => undefined));
|
|
780
|
+
if (received === undefined || stopped) break;
|
|
781
|
+
const item = getDelivered() ?? {
|
|
782
|
+
kind: 'event',
|
|
783
|
+
event: received
|
|
784
|
+
};
|
|
785
|
+
const receipt = item.kind === 'event' ? item.receipt : undefined;
|
|
615
786
|
let event;
|
|
616
|
-
if (
|
|
787
|
+
if (item.kind === 'actionFailure') {
|
|
617
788
|
const errorEvent = logic.getExecutionErrorEvent?.(snapshot, item.error);
|
|
618
789
|
if (!errorEvent) {
|
|
619
790
|
snapshot = errorSnapshot(snapshot, item.error);
|
|
@@ -621,16 +792,25 @@ function createEffectActor(logic, ...[options]) {
|
|
|
621
792
|
}
|
|
622
793
|
event = errorEvent;
|
|
623
794
|
} else {
|
|
624
|
-
event = item;
|
|
795
|
+
event = item.event;
|
|
625
796
|
}
|
|
626
797
|
try {
|
|
627
798
|
[snapshot, effects] = durable.transition(snapshot, event);
|
|
628
799
|
} catch (error) {
|
|
629
800
|
snapshot = errorSnapshot(snapshot, error);
|
|
801
|
+
actor._publish(snapshot, receipt);
|
|
802
|
+
actor._completeReceipt(receipt, Exit.succeed(snapshot));
|
|
630
803
|
break;
|
|
631
804
|
}
|
|
632
|
-
actor._publish(snapshot);
|
|
805
|
+
actor._publish(snapshot, receipt);
|
|
806
|
+
if (stopped) break;
|
|
807
|
+
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;
|
|
633
808
|
yield* executeEffects(effects);
|
|
809
|
+
actor._completeReceipt(receipt, rejectedReason !== undefined ? Exit.fail(new EventRejectedError({
|
|
810
|
+
actorId: actor.id,
|
|
811
|
+
event,
|
|
812
|
+
reason: rejectedReason
|
|
813
|
+
})) : Exit.succeed(snapshot));
|
|
634
814
|
}
|
|
635
815
|
if (!stopped) {
|
|
636
816
|
actor._publish(snapshot);
|
|
@@ -660,45 +840,11 @@ function createEffectActor(logic, ...[options]) {
|
|
|
660
840
|
}) => actor));
|
|
661
841
|
}
|
|
662
842
|
|
|
663
|
-
/**
|
|
664
|
-
* The failure an Effect-backed actor reports when its Effect was interrupted
|
|
665
|
-
* by something other than the actor being stopped, such as `Effect.interrupt`,
|
|
666
|
-
* losing an `Effect.race`, or an `Effect.timeout` that interrupts.
|
|
667
|
-
*/
|
|
668
|
-
class EffectInterruptedError extends Data.TaggedError('EffectInterruptedError') {
|
|
669
|
-
get message() {
|
|
670
|
-
return 'Effect was interrupted before the actor completed';
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
/**
|
|
675
|
-
* Reported by `waitFor` when the actor stops or errors before a snapshot
|
|
676
|
-
* matches, and by `join` when the actor stops without output. `join` reports
|
|
677
|
-
* an errored actor's own `snapshot.error` instead.
|
|
678
|
-
*/
|
|
679
|
-
class ActorStoppedError extends Data.TaggedError('ActorStoppedError') {
|
|
680
|
-
get message() {
|
|
681
|
-
return `Actor "${this.actorId}" ${this.snapshot.status === 'error' ? 'errored' : 'stopped'} before completing`;
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
/**
|
|
686
|
-
* Reported by the `send` atom of `createActorAtoms` when an event is sent
|
|
687
|
-
* before the actor's runtime has finished building.
|
|
688
|
-
*/
|
|
689
|
-
class NotReadyError extends Data.TaggedError('NotReadyError') {
|
|
690
|
-
get message() {
|
|
691
|
-
return 'The actor is not ready yet';
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
/** The tag of the machine itself, used when the root state is parallel. */
|
|
696
|
-
const MACHINE_TAG = '(machine)';
|
|
697
|
-
|
|
698
843
|
/**
|
|
699
844
|
* The dotted path of a state value: `'idle'`, `'form.editing'`. A parallel
|
|
700
|
-
* state has no single path, so its tag stops at the parallel state
|
|
701
|
-
*
|
|
845
|
+
* state has no single path, so its tag stops at the parallel state. When the
|
|
846
|
+
* machine itself is parallel, the tag is `TRootTag`: the machine id, or `''`
|
|
847
|
+
* for a machine without one.
|
|
702
848
|
*/
|
|
703
849
|
|
|
704
850
|
/**
|
|
@@ -710,16 +856,16 @@ const MACHINE_TAG = '(machine)';
|
|
|
710
856
|
/** The tagged state union of a machine. */
|
|
711
857
|
|
|
712
858
|
/** Computes the dotted path tag of a state value. */
|
|
713
|
-
function stateTag(value, prefix = '') {
|
|
859
|
+
function stateTag(value, rootTag, prefix = '') {
|
|
714
860
|
if (typeof value === 'string') {
|
|
715
861
|
return prefix ? `${prefix}.${value}` : value;
|
|
716
862
|
}
|
|
717
863
|
const keys = Object.keys(value);
|
|
718
864
|
if (keys.length !== 1) {
|
|
719
|
-
return prefix ||
|
|
865
|
+
return prefix || rootTag;
|
|
720
866
|
}
|
|
721
867
|
const key = keys[0];
|
|
722
|
-
return stateTag(value[key], prefix ? `${prefix}.${key}` : key);
|
|
868
|
+
return stateTag(value[key], rootTag, prefix ? `${prefix}.${key}` : key);
|
|
723
869
|
}
|
|
724
870
|
|
|
725
871
|
/**
|
|
@@ -739,11 +885,11 @@ function stateTag(value, prefix = '') {
|
|
|
739
885
|
*/
|
|
740
886
|
function taggedState(snapshot) {
|
|
741
887
|
return {
|
|
742
|
-
_tag: stateTag(snapshot.value),
|
|
888
|
+
_tag: stateTag(snapshot.value, snapshot.machine.id),
|
|
743
889
|
value: snapshot.value,
|
|
744
890
|
context: snapshot.context,
|
|
745
891
|
snapshot
|
|
746
892
|
};
|
|
747
893
|
}
|
|
748
894
|
|
|
749
|
-
export { ActorStoppedError as A,
|
|
895
|
+
export { ActorStoppedError as A, EffectFailure as E, NotReadyError as N, causeFromError as a, runHostedEffect as b, createEffectActor as c, EffectActor as d, ActorScope as e, EventRejectedError as f, EffectInterruptedError as g, 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
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import { StateMachine } from 'xstate';
|
|
4
|
+
import { c as createEffectActor, a as causeFromError, N as NotReadyError, t as taggedState } from './state-a3f54e06.js';
|
|
5
|
+
export { N as NotReadyError } from './state-a3f54e06.js';
|
|
6
6
|
import 'xstate/durable';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -55,7 +55,7 @@ function createActorAtoms(runtime, logic, ...[options]) {
|
|
|
55
55
|
}
|
|
56
56
|
const value = current.value;
|
|
57
57
|
if (value.status === 'error') {
|
|
58
|
-
return AsyncResult.failureWithPrevious(
|
|
58
|
+
return AsyncResult.failureWithPrevious(causeFromError(value.error), {
|
|
59
59
|
previous: get.self()
|
|
60
60
|
});
|
|
61
61
|
}
|
|
@@ -75,15 +75,17 @@ function createActorAtoms(runtime, logic, ...[options]) {
|
|
|
75
75
|
function select(selector) {
|
|
76
76
|
return Atom.map(snapshot, result => AsyncResult.map(result, selector));
|
|
77
77
|
}
|
|
78
|
-
const
|
|
79
|
-
return {
|
|
78
|
+
const base = {
|
|
80
79
|
actor,
|
|
81
80
|
snapshot,
|
|
82
81
|
result,
|
|
83
82
|
send: sendAtom,
|
|
84
|
-
select
|
|
85
|
-
state
|
|
83
|
+
select
|
|
86
84
|
};
|
|
85
|
+
return logic instanceof StateMachine ? {
|
|
86
|
+
...base,
|
|
87
|
+
state: select(current => taggedState(current))
|
|
88
|
+
} : base;
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
export { createActorAtoms };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export * from "./declarations/src/oxlint.js";
|
|
2
|
+
export { default } from "./declarations/src/oxlint.js";
|
|
3
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieHN0YXRlLWVmZmVjdC1veGxpbnQuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4vZGVjbGFyYXRpb25zL3NyYy9veGxpbnQuZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSJ9
|