@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.
@@ -1,13 +1,79 @@
1
- import { Queue, Effect, Fiber, Scope, Exit, Cause, Context, Duration, Data } from 'effect';
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
- /** A mailbox item that reports a failed fire-and-forget action. */
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
- const actionFailure = Symbol.for('@xstate/effect/actionFailure');
8
- function isActionFailure(value) {
9
- return typeof value === 'object' && value !== null && actionFailure in value;
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
- Queue.offerUnsafe(this._mailbox, event);
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
- xstate$$type: 1,
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
- const fiber = Fiber.runIn(Effect.runForkWith(host.context)(traced), host.scope);
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) || Cause.hasInterruptsOnly(exit.cause)) {
494
+ if (Exit.isSuccess(exit)) {
364
495
  resolve();
365
496
  } else {
366
- // Effect failures are arbitrary values, not necessarily Errors.
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, id) => `${source.sessionId}:${id}`;
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
- [actionFailure]: true,
604
+ kind: 'actionFailure',
469
605
  error
470
606
  });
471
607
  });
472
608
  }
473
609
  } catch (error) {
474
610
  offer({
475
- [actionFailure]: true,
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(event);
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, id, delay) => {
512
- const key = timerKey(source, id);
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
- id
657
+ ...timer
519
658
  };
520
659
  if (isRoot(source)) {
521
- offer(timerEvent);
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, id) => {
529
- const key = timerKey(source, id);
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 ready when this
594
- // Effect succeeds, and the initial actions start before any send.
595
- let [snapshot, effects] = durable.initialTransition(options?.input);
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
- [actionFailure]: true,
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
- const item = yield* Effect.promise(() => durable.waitForEvent().then(event => event, () => undefined));
612
- if (item === undefined || stopped) {
613
- break;
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 (isActionFailure(item)) {
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, or is
701
- * `'(machine)'` when the machine itself is parallel.
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 || MACHINE_TAG;
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, EffectInterruptedError as E, NotReadyError as N, runHostedEffect as a, EffectActor as b, createEffectActor as c, ActorScope as d, relayToParent as r, startHostedEffect as s, taggedState as t, withActorScope as w };
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 { c as createEffectActor, N as NotReadyError, t as taggedState } from './state-14a1fecf.js';
4
- export { N as NotReadyError } from './state-14a1fecf.js';
5
- import 'xstate';
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(Cause.fail(value.error), {
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 state = select(current => taggedState(current));
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