@xstate/effect 1.0.0-alpha.9 → 1.0.0-beta.1

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 CHANGED
@@ -7,18 +7,20 @@ Combine XState's event-driven workflows with Effect services, scopes, clocks and
7
7
  - Provide services once for the actor and its child logic.
8
8
  - Keep actor lifetime inside your Effect application.
9
9
 
10
- This package is experimental. It targets XState v6 alpha and Effect 4.
10
+ This package is experimental. It targets XState v6 beta and Effect 4.
11
11
 
12
12
  In these docs, "transition effects" are the executable effect descriptors (`ExecutableEffect`) that an XState transition returns. "Effect" means an Effect.ts program.
13
13
 
14
14
  ## Installation
15
15
 
16
- <!-- package name and peer dependencies from package.json -->
16
+ <!-- package name, zero direct runtime dependencies and required versus optional peers from package.json -->
17
17
 
18
18
  ```bash
19
- npm install @xstate/effect@alpha xstate@alpha effect@^4
19
+ npm install @xstate/effect@beta xstate@beta effect@^4
20
20
  ```
21
21
 
22
+ `@xstate/effect` has zero direct runtime dependencies. Effect and XState are its only required peers. Lint tooling is opt-in and installed as development dependencies.
23
+
22
24
  ## XState Effect: Quick start
23
25
 
24
26
  <!-- public API from src/index.ts; actor lifetime from src/createEffectActor.ts -->
@@ -123,6 +125,10 @@ Start Effect-backed logic with `createEffectActor` inside an Effect scope.
123
125
 
124
126
  </details>
125
127
 
128
+ <!-- declared Effect action typing from src/setupEffect.ts -->
129
+
130
+ Declared Effect actions infer context and event types from `setupEffect({ schemas })`, including schemas inherited through `extend`. See [Action argument types](docs/schemas-and-actions.md#action-argument-types) for custom arguments and safe defaults.
131
+
126
132
  ## Guides
127
133
 
128
134
  | Guide | Examples |
@@ -185,7 +191,7 @@ The actor's later errors are observed through `join` or snapshots. Invalid input
185
191
 
186
192
  ## Effect actor logic
187
193
 
188
- <!-- createEffectLogic, createEffectStreamLogic, createEffectEventStreamLogic from src/createEffectLogic.ts -->
194
+ <!-- createEffectLogic, createEffectStreamLogic, createEffectEventStreamLogic from src/effectLogic.ts -->
189
195
 
190
196
  | Function | Behavior |
191
197
  | --- | --- |
@@ -240,11 +246,15 @@ See [Effect actor logic](docs/effect-logic.md) for tasks and a stream that drive
240
246
 
241
247
  See [schemas and actions](docs/schemas-and-actions.md) for a complete audit example, runtime schema constraints and inline-source pitfalls.
242
248
 
249
+ <!-- lint plugin export from package.json; rule from src/oxlint.ts -->
250
+
251
+ Enable `xstate-effect/no-inline-effect` with the compiled `@xstate/effect/oxlint` plugin to catch discarded inline Effects and unsupported inline spawned Effect logic. See [Oxlint configuration](docs/schemas-and-actions.md#declared-sources) for installation and the rule's syntactic limits.
252
+
243
253
  ## Atoms and React
244
254
 
245
255
  <!-- atom surface from src/atom.ts -->
246
256
 
247
- `createActorAtoms` from `@xstate/effect/atom` exposes `actor`, `snapshot`, `result`, `send`, `select` and `state`. Its `Atom.runtime` must provide the logic's services. Pass `{ input }` when the logic requires input; missing or mismatched input is a type error.
257
+ `createActorAtoms` from `@xstate/effect/atom` exposes `actor`, `snapshot`, `result`, `send` and `select`. Machine logic also exposes `state`; tasks and streams do not. Its `Atom.runtime` must provide the logic's services. Pass `{ input }` when the logic requires input; missing or mismatched input is a type error.
248
258
 
249
259
  - Read atoms with `@effect/atom-react` in React, or an `AtomRegistry` elsewhere.
250
260
  - The registry owns their lifetime; dispose it when its owner shuts down.
@@ -256,16 +266,17 @@ See [atoms and React](docs/atoms-and-react.md) for complete examples with import
256
266
 
257
267
  <!-- error types from src/errors.ts; timeout failure from src/actor.ts -->
258
268
 
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.
259
270
  - Use `TestClock` to drive deadlines without waiting for real time.
260
271
  - `ActorStoppedError` reports a stop before an awaited result.
261
- - `EffectInterruptedError` reports self-interruption inside Effect logic.
272
+ - `EffectFailure<E>` carries the original `Cause<E>` in task and stream error snapshots, including defects and self-interruption.
262
273
  - Timed waits fail with Effect's `Cause.TimeoutError`.
263
- - `join` preserves a task's typed failure. Unexpected machine errors have type `unknown`.
274
+ - `join` replays the original Cause and preserves a task's typed failure. Unexpected machine errors have type `unknown`.
264
275
 
265
- See [testing and errors](docs/testing-and-errors.md) for executable deadline, retry and failure examples. Persisted snapshots record actor state; pass one to `createEffectActor(logic, { snapshot })` to resume the actor. See [persisting and restoring](docs/actors.md#persisting-and-restoring).
276
+ See [testing and errors](docs/testing-and-errors.md) for executable deadline, retry and failure examples. Persisted snapshots record actor state; pass one to `createEffectActor(logic, { snapshot })` to resume the actor. Use `createSnapshotCodec` with a full bidirectional Effect schema for validated JSON persistence of versioned machines. See [persisting and restoring](docs/actors.md#persisting-and-restoring).
266
277
 
267
278
  ## Tracing
268
279
 
269
- <!-- span names and attributes from src/internal.ts and src/createEffectLogic.ts -->
280
+ <!-- span names and attributes from src/internal.ts and src/effectLogic.ts -->
270
281
 
271
282
  Hosted work uses spans named `createEffectLogic`, `createEffectStreamLogic`, `createEffectEventStreamLogic` and `action.<name>`. Each carries `xstate.actor.id` and `xstate.actor.address`. Provide a `Tracer` to record and export them.
@@ -1,12 +1,24 @@
1
1
  import { Cause, Duration, Effect, Stream } from 'effect';
2
2
  import type { Actor, ActorRef, AnyActorRef, AnyEventObject, EmittedFrom, EventRejection, ErrorFrom, InspectionEvent, OutputFrom, SnapshotFrom } from 'xstate';
3
3
  import type { EffectActor } from "./effectActor.js";
4
- import { ActorStoppedError } from "./errors.js";
5
- /** The event type accepted by an actor's `send` method. */
4
+ import { ActorStoppedError, type UnwrapEffectFailure } from "./errors.js";
5
+ /**
6
+ * The event type accepted by an actor's `send` method.
7
+ *
8
+ * @experimental
9
+ */
6
10
  export type SendableEventFrom<TActor extends AnyActorRef> = Parameters<TActor['send']>[0];
7
- /** The event type an actor emits through `actor.on(...)`. */
11
+ /**
12
+ * The event type an actor emits through `actor.on(...)`.
13
+ *
14
+ * @experimental
15
+ */
8
16
  export type EmittedEventFrom<TActor> = TActor extends EffectActor<infer TLogic> ? EmittedFrom<TLogic> : TActor extends Actor<infer TLogic> ? EmittedFrom<TLogic> : TActor extends ActorRef<any, any, infer TEmitted, any> ? TEmitted : AnyEventObject;
9
- /** Options for {@link waitFor}. */
17
+ /**
18
+ * Options for {@link waitFor}.
19
+ *
20
+ * @experimental
21
+ */
10
22
  export interface WaitForOptions {
11
23
  /**
12
24
  * Fails with `Cause.TimeoutError` when no snapshot satisfies the predicate
@@ -19,6 +31,8 @@ export interface WaitForOptions {
19
31
  * is enqueued, like `actor.send(event)`, and processed on the actor's own
20
32
  * fiber. An event that cannot be delivered (for example to a stopped actor)
21
33
  * is reported as a dead letter, observable with {@link deadLetters}.
34
+ *
35
+ * @experimental
22
36
  */
23
37
  export declare const send: {
24
38
  <TActor extends AnyActorRef>(event: SendableEventFrom<TActor>): (actor: TActor) => Effect.Effect<void>;
@@ -29,12 +43,16 @@ export declare const send: {
29
43
  * when the actor completes or stops, and emits the error snapshot before
30
44
  * ending when the actor errors. Interrupting the stream unsubscribes from the
31
45
  * actor.
46
+ *
47
+ * @experimental
32
48
  */
33
49
  export declare function snapshots<TActor extends AnyActorRef>(actor: TActor): Stream.Stream<SnapshotFrom<TActor>>;
34
50
  /**
35
51
  * Streams every event an actor emits, as delivered to `actor.on('*', …)`. The
36
52
  * stream ends when the actor completes, errors or stops. Interrupting the
37
53
  * stream removes the listener.
54
+ *
55
+ * @experimental
38
56
  */
39
57
  export declare function emitted<TActor extends AnyActorRef>(actor: TActor): Stream.Stream<EmittedEventFrom<TActor>>;
40
58
  /**
@@ -43,6 +61,8 @@ export declare function emitted<TActor extends AnyActorRef>(actor: TActor): Stre
43
61
  * `ActorStoppedError` if the actor stops or errors first, and with
44
62
  * `Cause.TimeoutError` when `options.timeout` elapses. Interrupting the Effect
45
63
  * unsubscribes from the actor.
64
+ *
65
+ * @experimental
46
66
  */
47
67
  export declare const waitFor: {
48
68
  <TActor extends AnyActorRef, TNarrowed extends SnapshotFrom<TActor>>(predicate: (snapshot: SnapshotFrom<TActor>) => snapshot is TNarrowed): (actor: TActor) => Effect.Effect<TNarrowed, ActorStoppedError>;
@@ -56,15 +76,19 @@ export declare const waitFor: {
56
76
  };
57
77
  /**
58
78
  * Joins an actor's final result, like `Fiber.join`: succeeds with its `output`
59
- * when it is done, fails with `snapshot.error` when it errors, and fails with
79
+ * when it is done, replays an Effect actor's original Cause when it errors, and fails with
60
80
  * `ActorStoppedError` when it stops without output. Waits for a still-active
61
- * actor to settle.
81
+ * actor to settle. Ordinary XState errors remain typed failures.
82
+ *
83
+ * @experimental
62
84
  */
63
- export declare function join<TActor extends AnyActorRef>(actor: TActor): Effect.Effect<OutputFrom<TActor>, ErrorFrom<TActor> | ActorStoppedError>;
85
+ export declare function join<TActor extends AnyActorRef>(actor: TActor): Effect.Effect<OutputFrom<TActor>, UnwrapEffectFailure<ErrorFrom<TActor>> | ActorStoppedError>;
64
86
  /**
65
87
  * Streams the inspection events of the actor's system, as delivered to
66
88
  * `system.inspect(…)`. The stream runs until it is interrupted or its scope
67
89
  * closes.
90
+ *
91
+ * @experimental
68
92
  */
69
93
  export declare function inspect(actor: AnyActorRef): Stream.Stream<InspectionEvent>;
70
94
  /**
@@ -73,5 +97,7 @@ export declare function inspect(actor: AnyActorRef): Stream.Stream<InspectionEve
73
97
  * events and internal events sent from outside their owner. A dead letter is
74
98
  * not an actor error. The stream runs until it is interrupted or its scope
75
99
  * closes.
100
+ *
101
+ * @experimental
76
102
  */
77
103
  export declare function deadLetters(actor: AnyActorRef): Stream.Stream<EventRejection>;
@@ -1,11 +1,17 @@
1
1
  import { Context, Effect, Scope } from 'effect';
2
2
  declare const ActorScope_base: Context.ServiceClass<ActorScope, "@xstate/effect/ActorScope", Scope.Scope>;
3
- /** The owning Effect actor's scope, supplied by `createEffectActor`. */
3
+ /**
4
+ * The owning Effect actor's scope, supplied by `createEffectActor`.
5
+ *
6
+ * @experimental
7
+ */
4
8
  export declare class ActorScope extends ActorScope_base {
5
9
  }
6
10
  /**
7
11
  * Acquires resources in the owning actor's scope. Their finalizers run when
8
12
  * that actor stops, even if the invoking task finishes or is cancelled first.
13
+ *
14
+ * @experimental
9
15
  */
10
16
  export declare function withActorScope<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, Exclude<R, Scope.Scope> | ActorScope>;
11
17
  export {};
@@ -1,8 +1,8 @@
1
1
  import { AsyncResult, Atom } from 'effect/reactivity';
2
- import type { AnyActorLogic, ErrorFrom, EventFromLogic, SnapshotFrom } from 'xstate';
2
+ import { type AnyStateMachine, type AnyActorLogic, type ErrorFrom, type EventFromLogic, type SnapshotFrom } from 'xstate';
3
3
  import { type EffectActorOptionsArgs } from "./createEffectActor.js";
4
4
  import type { EffectActor } from "./effectActor.js";
5
- import { NotReadyError } from "./errors.js";
5
+ import { NotReadyError, type UnwrapEffectFailure } from "./errors.js";
6
6
  import { type TaggedStateFrom } from "./state.js";
7
7
  import type { RequirementsFrom } from "./types.js";
8
8
  export { NotReadyError } from "./errors.js";
@@ -11,7 +11,7 @@ export { NotReadyError } from "./errors.js";
11
11
  * `effect/reactivity`. Read them with the atom bindings for your
12
12
  * framework, such as `@effect/atom-react`.
13
13
  */
14
- export interface ActorAtoms<TLogic extends AnyActorLogic, ER = never> {
14
+ interface BaseActorAtoms<TLogic extends AnyActorLogic, ER> {
15
15
  /**
16
16
  * The running actor. It starts when the atom is first read and stops when
17
17
  * the atom is released, that is, when nothing reads or mounts it anymore.
@@ -23,7 +23,7 @@ export interface ActorAtoms<TLogic extends AnyActorLogic, ER = never> {
23
23
  * The snapshot as a result: a `Failure` carrying the actor's error once
24
24
  * the actor's status is `error`, so an error boundary can handle it.
25
25
  */
26
- readonly result: Atom.Atom<AsyncResult.AsyncResult<SnapshotFrom<TLogic>, ER | ErrorFrom<TLogic>>>;
26
+ readonly result: Atom.Atom<AsyncResult.AsyncResult<SnapshotFrom<TLogic>, ER | UnwrapEffectFailure<ErrorFrom<TLogic>>>>;
27
27
  /**
28
28
  * Sends an event to the actor synchronously. Set it with the event, for
29
29
  * example through `useAtomSet` in React. Its value reports the last send:
@@ -33,12 +33,12 @@ export interface ActorAtoms<TLogic extends AnyActorLogic, ER = never> {
33
33
  readonly send: Atom.Writable<AsyncResult.AsyncResult<void, ER | NotReadyError>, EventFromLogic<TLogic>>;
34
34
  /** Derives an atom of a value selected from the snapshot. */
35
35
  readonly select: <T>(selector: (snapshot: SnapshotFrom<TLogic>) => T) => Atom.Atom<AsyncResult.AsyncResult<T, ER>>;
36
- /**
37
- * The snapshot as a tagged union over the machine's states, for
38
- * `Match.tag` or a `switch` on `_tag`. See `taggedState`.
39
- */
40
- readonly state: Atom.Atom<AsyncResult.AsyncResult<TaggedStateFrom<SnapshotFrom<TLogic>>, ER>>;
41
36
  }
37
+ /** @experimental */
38
+ export type ActorAtoms<TLogic extends AnyActorLogic, ER = never> = BaseActorAtoms<TLogic, ER> & ([TLogic] extends [AnyStateMachine] ? {
39
+ /** The machine snapshot as a tagged union over its states. */
40
+ readonly state: Atom.Atom<AsyncResult.AsyncResult<TaggedStateFrom<SnapshotFrom<TLogic>>, ER>>;
41
+ } : {});
42
42
  interface MissingRequirements<T> {
43
43
  readonly 'The runtime does not provide services the logic requires': T;
44
44
  }
@@ -53,5 +53,7 @@ interface MissingRequirements<T> {
53
53
  * when the atom is released. Wrap the atoms with `Atom.keepAlive` to pin the
54
54
  * actor for the registry's lifetime, or with `Atom.family` to create one
55
55
  * actor per input.
56
+ *
57
+ * @experimental
56
58
  */
57
59
  export declare function createActorAtoms<TLogic extends AnyActorLogic, R, ER = never>(runtime: Atom.AtomRuntime<R, ER> & ([RequirementsFrom<TLogic>] extends [R] ? unknown : MissingRequirements<Exclude<RequirementsFrom<TLogic>, R>>), logic: TLogic, ...[options]: EffectActorOptionsArgs<TLogic>): ActorAtoms<TLogic, ER>;
@@ -1,21 +1,30 @@
1
1
  import { Effect, Scope } from 'effect';
2
- import { type ActorOptions, type AnyActorLogic, type InputFrom, type RequiredActorOptionsFor, type RequiredActorOptionsKeys } from 'xstate';
2
+ import { type AnyActorLogic, type InputFrom, type RestorablePersistedSnapshotFor, type RequiredActorOptionsKeys, type Snapshot } from 'xstate';
3
3
  import { EffectActor } from "./effectActor.js";
4
4
  import type { RequirementsFrom } from "./types.js";
5
- /** Options for {@link createEffectActor}. */
5
+ /**
6
+ * Options for {@link createEffectActor}.
7
+ *
8
+ * @experimental
9
+ */
6
10
  export type EffectActorOptions<TLogic extends AnyActorLogic> = {
7
11
  readonly input?: InputFrom<TLogic>;
8
12
  /**
9
13
  * A snapshot from `actor.getPersistedSnapshot()`. The actor resumes in that
10
14
  * state without re-running entry actions, and pending timers keep their
11
- * original deadlines, as with XState's `createActor(logic, { snapshot })`.
15
+ * original deadlines, as with `restoreActor(logic, snapshot)` from
16
+ * `xstate/persist`.
12
17
  * State-machine children resume their persisted state and completed
13
18
  * children stay done. Effect tasks and streams that were running, at the
14
19
  * root or as children, start again from the beginning. A restored actor
15
20
  * does not need `input`.
16
21
  */
17
- readonly snapshot?: ActorOptions<TLogic>['snapshot'];
18
- } & RequiredActorOptionsFor<TLogic>;
22
+ readonly snapshot?: Snapshot<unknown> & Partial<RestorablePersistedSnapshotFor<TLogic>>;
23
+ } & ([RequiredActorOptionsKeys<TLogic>] extends [never] ? {} : {
24
+ [K in RequiredActorOptionsKeys<TLogic>]: unknown;
25
+ } | {
26
+ snapshot: Snapshot<unknown> & Partial<RestorablePersistedSnapshotFor<TLogic>>;
27
+ });
19
28
  export type EffectActorOptionsArgs<TLogic extends AnyActorLogic> = [
20
29
  RequiredActorOptionsKeys<TLogic>
21
30
  ] extends [never] ? [options?: EffectActorOptions<TLogic>] : [options: EffectActorOptions<TLogic>];
@@ -32,5 +41,7 @@ export type EffectActorOptionsArgs<TLogic extends AnyActorLogic> = [
32
41
  * The actor is a scoped resource: it stops, and every Effect it hosts is
33
42
  * interrupted, when the enclosing `Scope` closes. The returned Effect never
34
43
  * fails; the actor's own outcome is its snapshot status, read with `join`.
44
+ *
45
+ * @experimental
35
46
  */
36
47
  export declare function createEffectActor<TLogic extends AnyActorLogic>(logic: TLogic, ...[options]: EffectActorOptionsArgs<TLogic>): Effect.Effect<EffectActor<TLogic>, never, RequirementsFrom<TLogic> | Scope.Scope>;
@@ -1,13 +1,17 @@
1
- import { Queue } from 'effect';
2
- import type { ActorRef, AnyActor, AnyActorLogic, EmittedFrom, EventFromLogic, InspectionEvent, Observer, Snapshot, SnapshotFrom, Subscription } from 'xstate';
3
- /** A mailbox item that reports a failed fire-and-forget action. */
4
- export interface ActionFailure {
5
- readonly [actionFailure]: true;
6
- readonly error: unknown;
1
+ import { Exit, Queue } from 'effect';
2
+ import { ActorStoppedError, EventRejectedError } from "./errors.js";
3
+ import type { ActorRef, AnyActor, AnyActorLogic, EmittedFrom, EventFromLogic, InspectionEvent, Observer, PersistedSnapshotOf, SnapshotFrom, Subscription } from 'xstate';
4
+ export interface Receipt<TSnapshot> {
5
+ resume?: (exit: Exit.Exit<TSnapshot, ActorStoppedError | EventRejectedError>) => void;
7
6
  }
8
- export declare const actionFailure: unique symbol;
9
- export declare function isActionFailure(value: unknown): value is ActionFailure;
10
- export type MailboxItem<TEvent> = TEvent | ActionFailure;
7
+ export type MailboxItem<TEvent, TSnapshot> = {
8
+ readonly kind: 'event';
9
+ readonly event: TEvent;
10
+ readonly receipt?: Receipt<TSnapshot>;
11
+ } | {
12
+ readonly kind: 'actionFailure';
13
+ readonly error: unknown;
14
+ };
11
15
  declare const symbolObservable: typeof Symbol.observable;
12
16
  /**
13
17
  * Calls a listener and reports an exception it throws without letting it
@@ -19,6 +23,8 @@ export declare function safeCall<T>(fn: ((arg: T) => void) | undefined, arg?: T)
19
23
  * contract (`send`, `getSnapshot`, `subscribe`, `on`), so it works with
20
24
  * `useSelector`, this package's actor functions and the inspection APIs, while
21
25
  * the actor itself is driven by an Effect fiber over pure transitions.
26
+ *
27
+ * @experimental
22
28
  */
23
29
  export declare class EffectActor<TLogic extends AnyActorLogic> implements ActorRef<SnapshotFrom<TLogic>, EventFromLogic<TLogic>, EmittedFrom<TLogic>> {
24
30
  readonly logic: TLogic;
@@ -34,18 +40,29 @@ export declare class EffectActor<TLogic extends AnyActorLogic> implements ActorR
34
40
  private readonly _observers;
35
41
  private readonly _listeners;
36
42
  private _settled;
37
- constructor(logic: TLogic, root: AnyActor, snapshot: SnapshotFrom<TLogic>, _mailbox: Queue.Queue<MailboxItem<EventFromLogic<TLogic>>>, _stopExecution: () => void, _inspectors: Set<(event: InspectionEvent) => void>);
43
+ private readonly _pending;
44
+ private _inStep;
45
+ private _deliveryDepth;
46
+ private _stopHeld;
47
+ constructor(logic: TLogic, root: AnyActor, snapshot: SnapshotFrom<TLogic>, _mailbox: Queue.Queue<MailboxItem<EventFromLogic<TLogic>, SnapshotFrom<TLogic>>>, _stopExecution: () => void, _inspectors: Set<(event: InspectionEvent) => void>);
38
48
  getSnapshot(): SnapshotFrom<TLogic>;
39
- getPersistedSnapshot(): Snapshot<unknown>;
49
+ getPersistedSnapshot(): PersistedSnapshotOf<TLogic>;
40
50
  /** Sends an event; the actor processes it on its own fiber. */
41
51
  send(event: EventFromLogic<TLogic>): void;
42
- /** Stops the actor, its children and every Effect it hosts. */
52
+ private _deliveryError;
53
+ private _stoppedError;
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
+ */
43
59
  stop(): this;
44
60
  subscribe(observer: Observer<SnapshotFrom<TLogic>>): Subscription;
45
61
  subscribe(nextListener?: (snapshot: SnapshotFrom<TLogic>) => void, errorListener?: (error: any) => void, completeListener?: () => void): Subscription;
46
62
  on<TType extends EmittedFrom<TLogic>['type'] | '*'>(type: TType, handler: (emitted: EmittedFrom<TLogic> & (TType extends '*' ? unknown : {
47
63
  type: TType;
48
64
  })) => void): Subscription;
65
+ private _deliver;
49
66
  /**
50
67
  * Observes the inspection events of this actor and its children: every
51
68
  * actor creation and transition of the execution.
@@ -53,7 +70,7 @@ export declare class EffectActor<TLogic extends AnyActorLogic> implements ActorR
53
70
  inspect(observer: Observer<InspectionEvent> | ((event: InspectionEvent) => void)): Subscription;
54
71
  [symbolObservable](): this;
55
72
  toJSON(): {
56
- $actor: string;
73
+ '@actor': string;
57
74
  };
58
75
  }
59
76
  export {};
@@ -1,5 +1,6 @@
1
1
  import { Effect, Stream } from 'effect';
2
2
  import { type ActorLogicValidator, type ActorLogic, type AnyActorRef, type AnyActorSystem, type AnyEventObject, type EventObject, type Snapshot, type StandardSchemaV1 } from 'xstate';
3
+ import { EffectFailure } from "./errors.js";
3
4
  import type { EffectRequirements } from "./types.js";
4
5
  import { type EffectSchemaLike, type ToStandardSchema, type ValidateEffectActorSchemas } from "./schema.js";
5
6
  declare const effectLogicBrand: unique symbol;
@@ -9,6 +10,8 @@ declare const effectLogicBrand: unique symbol;
9
10
  * failure type and its Effect service requirements, which is how
10
11
  * `RequirementsFrom` collects the `R` channel of `createEffectActor` without
11
12
  * inspecting the logic at runtime.
13
+ *
14
+ * @experimental
12
15
  */
13
16
  export interface EffectLogicBrand<TError, TRequirements> {
14
17
  readonly [effectLogicBrand]: {
@@ -19,19 +22,22 @@ export interface EffectLogicBrand<TError, TRequirements> {
19
22
  /**
20
23
  * Snapshot of a `createEffectLogic` actor. The actor holds no context of its own: it
21
24
  * is `active` while the Effect runs, `done` with the Effect's success value as
22
- * `output`, or `error` with the Effect's failure, defect or
23
- * `EffectInterruptedError` as `error`.
25
+ * `output`, or `error` with the original `Cause` wrapped in `EffectFailure` as `error`.
26
+ *
27
+ * @experimental
24
28
  */
25
29
  export type EffectSnapshot<TOutput, TError, TInput> = Snapshot<TOutput> & {
26
30
  readonly context: undefined;
27
31
  readonly input: TInput | undefined;
28
- readonly error: TError | undefined;
32
+ readonly error: EffectFailure<TError> | undefined;
29
33
  };
30
34
  /**
31
35
  * Argument passed to the function form of an Effect source. It gives the
32
36
  * source the actor's `input`, its own reference (`self`), the actor `system`,
33
37
  * and `emit` for publishing events that `actor.on(...)` and `emitted(actor)`
34
38
  * observe.
39
+ *
40
+ * @experimental
35
41
  */
36
42
  export type EffectSourceArgs<TInput> = {
37
43
  readonly input: TInput;
@@ -44,6 +50,8 @@ export type EffectSourceArgs<TInput> = {
44
50
  * What `createEffectLogic` accepts as its Effect: either an Effect value, or a
45
51
  * function of {@link EffectSourceArgs} returning one. The function form is
46
52
  * called once per actor start, so it sees that actor's input.
53
+ *
54
+ * @experimental
47
55
  */
48
56
  export type EffectSource<TOutput, TError, TInput, TRequirements> = Effect.Effect<TOutput, TError, TRequirements> | ((args: EffectSourceArgs<TInput>) => Effect.Effect<TOutput, TError, TRequirements>);
49
57
  type EffectActorSchemas = {
@@ -58,7 +66,7 @@ type EffectSourceConfig<TOutput, TError, TInput, TRequirements, TSchemas extends
58
66
  };
59
67
  type SchemaOutput<TSchema extends EffectSchemaLike> = StandardSchemaV1.InferOutput<ToStandardSchema<TSchema>>;
60
68
  type EffectSuccess<T> = T extends Effect.Effect<infer A, any, any> ? A : never;
61
- type EffectFailure<T> = T extends Effect.Effect<any, infer E, any> ? E : never;
69
+ type EffectError<T> = T extends Effect.Effect<any, infer E, any> ? E : never;
62
70
  type EffectSchemaValidationConfig<TSchemas extends EffectActorSchemas> = {
63
71
  readonly validator: ActorLogicValidator;
64
72
  readonly schemas: TSchemas & ValidateEffectActorSchemas<TSchemas>;
@@ -71,6 +79,8 @@ type EffectSchemaValidationConfig<TSchemas extends EffectActorSchemas> = {
71
79
  * ordinary XState actor logic carrying {@link EffectLogicBrand}, so a machine
72
80
  * can invoke or spawn it, and `createEffectActor` can collect its
73
81
  * requirements.
82
+ *
83
+ * @experimental
74
84
  */
75
85
  export type EffectActorLogic<TOutput, TError, TInput, TRequirements> = ActorLogic<EffectSnapshot<TOutput, TError, TInput>, EventObject, TInput, AnyActorSystem> & {
76
86
  readonly id?: string;
@@ -79,44 +89,48 @@ export type EffectActorLogic<TOutput, TError, TInput, TRequirements> = ActorLogi
79
89
  * Snapshot of a `createEffectStreamLogic` actor. `context` holds the most recent
80
90
  * stream item, or `undefined` before the first one. The actor reaches `done`
81
91
  * with no output when the stream completes, and `error` when it fails.
92
+ *
93
+ * @experimental
82
94
  */
83
95
  export type EffectStreamSnapshot<TItem, TError, TInput> = Snapshot<undefined> & {
84
96
  readonly context: TItem | undefined;
85
97
  readonly input: TInput | undefined;
86
- readonly error: TError | undefined;
98
+ readonly error: EffectFailure<TError> | undefined;
87
99
  };
88
100
  /**
89
101
  * Actor logic produced by `createEffectStreamLogic`. Its snapshot is an
90
102
  * {@link EffectStreamSnapshot}, so the parent reads the latest item from the
91
103
  * child's `context` rather than from events.
104
+ *
105
+ * @experimental
92
106
  */
93
107
  export type EffectStreamActorLogic<TItem, TError, TInput, TRequirements> = ActorLogic<EffectStreamSnapshot<TItem, TError, TInput>, EventObject, TInput, AnyActorSystem> & {
94
108
  readonly id?: string;
95
109
  } & EffectLogicBrand<TError, TRequirements>;
96
110
  /**
97
111
  * Creates actor logic that runs an Effect. The actor completes with the
98
- * Effect's success value as its output and fails with the Effect's error, its
99
- * squashed defect, or an `EffectInterruptedError` when the Effect interrupts
100
- * itself. Stopping the actor interrupts the Effect without an error. Accepts
112
+ * Effect's success value as its output and fails with the original `Cause` wrapped in `EffectFailure`. Stopping the actor interrupts the Effect without an error. Accepts
101
113
  * an Effect, a function of {@link EffectSourceArgs} returning one, or a config
102
114
  * object with `id`, `schemas`, `validator` and `effect`. The logic must be run
103
115
  * under `createEffectActor`, which provides the Effect services it declares.
104
116
  * Resources belong to this task's scope and close on completion, failure or
105
117
  * interruption. Use `withActorScope` to retain a resource until the owning
106
118
  * Effect actor stops.
119
+ *
120
+ * @experimental
107
121
  */
108
122
  export declare function createEffectLogic<const TInputSchema extends EffectSchemaLike, const TOutputSchema extends EffectSchemaLike, TError = unknown, TRequirements = never>(config: Omit<EffectSourceConfig<SchemaOutput<TOutputSchema>, TError, SchemaOutput<TInputSchema>, TRequirements>, 'schemas' | 'validator'> & EffectSchemaValidationConfig<{
109
123
  input: TInputSchema;
110
124
  output: TOutputSchema;
111
125
  }>): EffectActorLogic<SchemaOutput<TOutputSchema>, TError, SchemaOutput<TInputSchema>, TRequirements>;
112
- export declare function createEffectLogic<const TInputSchema extends EffectSchemaLike, TEffect extends Effect.Effect<any, any, any>>(config: Omit<EffectSourceConfig<EffectSuccess<TEffect>, EffectFailure<TEffect>, SchemaOutput<TInputSchema>, EffectRequirements<TEffect>, {
126
+ export declare function createEffectLogic<const TInputSchema extends EffectSchemaLike, TEffect extends Effect.Effect<any, any, any>>(config: Omit<EffectSourceConfig<EffectSuccess<TEffect>, EffectError<TEffect>, SchemaOutput<TInputSchema>, EffectRequirements<TEffect>, {
113
127
  input: TInputSchema;
114
128
  }>, 'effect' | 'schemas' | 'validator'> & EffectSchemaValidationConfig<{
115
129
  input: TInputSchema;
116
130
  output?: never;
117
131
  }> & {
118
132
  effect: TEffect | ((args: EffectSourceArgs<SchemaOutput<TInputSchema>>) => TEffect);
119
- }): EffectActorLogic<EffectSuccess<TEffect>, EffectFailure<TEffect>, SchemaOutput<TInputSchema>, EffectRequirements<TEffect>>;
133
+ }): EffectActorLogic<EffectSuccess<TEffect>, EffectError<TEffect>, SchemaOutput<TInputSchema>, EffectRequirements<TEffect>>;
120
134
  export declare function createEffectLogic<const TOutputSchema extends EffectSchemaLike, TError = unknown, TInput = undefined, TRequirements = never>(config: Omit<EffectSourceConfig<SchemaOutput<TOutputSchema>, TError, TInput, TRequirements>, 'schemas' | 'validator'> & EffectSchemaValidationConfig<{
121
135
  input?: never;
122
136
  output: TOutputSchema;
@@ -130,6 +144,8 @@ export declare function createEffectLogic<TOutput, TError = unknown, TInput = un
130
144
  * What `createEffectStreamLogic` and `createEffectEventStreamLogic` accept as their stream:
131
145
  * either a Stream value, or a function of {@link EffectSourceArgs} returning
132
146
  * one. The function form is called once per actor start.
147
+ *
148
+ * @experimental
133
149
  */
134
150
  export type EffectStreamSource<TItem, TError, TInput, TRequirements> = Stream.Stream<TItem, TError, TRequirements> | ((args: EffectSourceArgs<TInput>) => Stream.Stream<TItem, TError, TRequirements>);
135
151
  type EffectStreamConfig<TItem, TError, TInput, TRequirements, TSchemas extends {
@@ -152,6 +168,8 @@ type StreamRequirements<T> = T extends Stream.Stream<any, any, infer R> ? R : ne
152
168
  * {@link EffectSourceArgs} returning one, or a config object with `id`,
153
169
  * `schemas`, `validator` and `stream`. Its resources close when the stream
154
170
  * completes, fails or is interrupted.
171
+ *
172
+ * @experimental
155
173
  */
156
174
  export declare function createEffectStreamLogic<const TInputSchema extends EffectSchemaLike, TStream extends Stream.Stream<any, any, any>>(config: Omit<EffectStreamConfig<StreamItem<TStream>, StreamError<TStream>, SchemaOutput<TInputSchema>, StreamRequirements<TStream>>, 'stream' | 'schemas' | 'validator'> & EffectSchemaValidationConfig<{
157
175
  input: TInputSchema;
@@ -168,6 +186,8 @@ export declare function createEffectStreamLogic<TItem, TError = unknown, TInput
168
186
  * has no output: it reaches `done` when the stream completes and `error` when
169
187
  * it fails. Accepts the same forms as `createEffectStreamLogic`. Its resources close
170
188
  * when the stream completes, fails or is interrupted.
189
+ *
190
+ * @experimental
171
191
  */
172
192
  export declare function createEffectEventStreamLogic<const TInputSchema extends EffectSchemaLike, TStream extends Stream.Stream<EventObject, any, any>>(config: Omit<EffectStreamConfig<StreamItem<TStream>, StreamError<TStream>, SchemaOutput<TInputSchema>, StreamRequirements<TStream>>, 'stream' | 'schemas' | 'validator'> & EffectSchemaValidationConfig<{
173
193
  input: TInputSchema;
@@ -1,12 +1,24 @@
1
1
  import { Cause } from 'effect';
2
2
  import type { Snapshot } from 'xstate';
3
+ /**
4
+ * Preserves an Effect failure, defect or interruption through XState error routing.
5
+ *
6
+ * @experimental
7
+ */
8
+ export declare class EffectFailure<E> extends Error {
9
+ #private;
10
+ readonly cause: Cause.Cause<E>;
11
+ readonly _tag = "EffectFailure";
12
+ static is(value: unknown): value is EffectFailure<unknown>;
13
+ constructor(cause: Cause.Cause<E>);
14
+ }
3
15
  declare const EffectInterruptedError_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 & {
4
16
  readonly _tag: "EffectInterruptedError";
5
17
  } & Readonly<A>;
6
18
  /**
7
- * The failure an Effect-backed actor reports when its Effect was interrupted
8
- * by something other than the actor being stopped, such as `Effect.interrupt`,
9
- * losing an `Effect.race`, or an `Effect.timeout` that interrupts.
19
+ * @deprecated Inspect `EffectFailure.cause` for interruption instead.
20
+ *
21
+ * @experimental
10
22
  */
11
23
  export declare class EffectInterruptedError extends EffectInterruptedError_base<{
12
24
  readonly cause: Cause.Cause<never>;
@@ -19,7 +31,9 @@ declare const ActorStoppedError_base: new <A extends Record<string, any> = {}>(a
19
31
  /**
20
32
  * Reported by `waitFor` when the actor stops or errors before a snapshot
21
33
  * matches, and by `join` when the actor stops without output. `join` reports
22
- * an errored actor's own `snapshot.error` instead.
34
+ * an errored actor's outcome instead, preserving an Effect failure's Cause.
35
+ *
36
+ * @experimental
23
37
  */
24
38
  export declare class ActorStoppedError extends ActorStoppedError_base<{
25
39
  readonly actorId: string;
@@ -33,8 +47,27 @@ declare const NotReadyError_base: new <A extends Record<string, any> = {}>(args:
33
47
  /**
34
48
  * Reported by the `send` atom of `createActorAtoms` when an event is sent
35
49
  * before the actor's runtime has finished building.
50
+ *
51
+ * @experimental
36
52
  */
37
53
  export declare class NotReadyError extends NotReadyError_base {
38
54
  get message(): string;
39
55
  }
56
+ export type UnwrapEffectFailure<E> = E extends EffectFailure<infer Failure> ? Failure : E;
57
+ 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
+ readonly _tag: "EventRejectedError";
59
+ } & Readonly<A>;
60
+ /**
61
+ * An event rejected at the actor's delivery boundary.
62
+ *
63
+ * @experimental
64
+ */
65
+ export declare class EventRejectedError extends EventRejectedError_base<{
66
+ readonly actorId: string;
67
+ readonly event: {
68
+ readonly type: string;
69
+ };
70
+ readonly reason: string;
71
+ }> {
72
+ }
40
73
  export {};
@@ -1,11 +1,13 @@
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, EffectInterruptedError } from "./errors.js";
7
+ export { ActorStoppedError, EventRejectedError, EffectFailure, EffectInterruptedError } 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";
10
11
  export { type ErrorFrom } from 'xstate';
11
- export { type EffectSchema, type EffectSchemaLike, type EffectSetupSchemas, type EffectSetupStateSchema } from "./schema.js";
12
+ export { type EffectSchema, type EffectSchemaLike, type EffectSetupSchemas, type EffectSetupStateSchema, type ToStandardSetupSchemas, type ToStandardSetupStates } from "./schema.js";
13
+ export { createSnapshotCodec, SnapshotCodecError } from "./persistence.js";
@@ -0,0 +1,3 @@
1
+ /** @experimental */
2
+ declare const _default: import("@oxlint/plugins").Plugin;
3
+ export default _default;