@xstate/effect 0.1.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +611 -0
- package/dist/declarations/src/actor.d.ts +76 -0
- package/dist/declarations/src/atom.d.ts +56 -0
- package/dist/declarations/src/brands.d.ts +1 -0
- package/dist/declarations/src/createEffectActor.d.ts +30 -0
- package/dist/declarations/src/effectActor.d.ts +60 -0
- package/dist/declarations/src/errors.d.ts +40 -0
- package/dist/declarations/src/fromEffect.d.ts +176 -0
- package/dist/declarations/src/index.d.ts +10 -0
- package/dist/declarations/src/schema.d.ts +80 -0
- package/dist/declarations/src/setupEffect.d.ts +94 -0
- package/dist/declarations/src/state.d.ts +44 -0
- package/dist/declarations/src/types.d.ts +52 -0
- package/dist/state-9a718be3.js +733 -0
- package/dist/xstate-effect-atom.d.ts +2 -0
- package/dist/xstate-effect-atom.js +88 -0
- package/dist/xstate-effect.d.ts +2 -0
- package/dist/xstate-effect.js +702 -0
- package/package.json +46 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Cause, Duration, Effect, Stream } from 'effect';
|
|
2
|
+
import type { Actor, ActorRef, AnyActorRef, AnyEventObject, DeadLetterInspectionEvent, EmittedFrom, ErrorFrom, InspectionEvent, OutputFrom, SnapshotFrom } from 'xstate';
|
|
3
|
+
import type { EffectActor } from "./effectActor.js";
|
|
4
|
+
import { ActorStoppedError } from "./errors.js";
|
|
5
|
+
/** The event type accepted by an actor's `send` method. */
|
|
6
|
+
export type SendableEventFrom<TActor extends AnyActorRef> = Parameters<TActor['send']>[0];
|
|
7
|
+
/** The event type an actor emits through `actor.on(...)`. */
|
|
8
|
+
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}. */
|
|
10
|
+
export interface WaitForOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Fails with `Cause.TimeoutError` when no snapshot satisfies the predicate
|
|
13
|
+
* within this duration.
|
|
14
|
+
*/
|
|
15
|
+
readonly timeout: Duration.Input;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Sends an event to an actor. The returned Effect always succeeds: the event
|
|
19
|
+
* is enqueued, like `actor.send(event)`, and processed on the actor's own
|
|
20
|
+
* fiber. An event that cannot be delivered (for example to a stopped actor)
|
|
21
|
+
* is reported as a dead letter, observable with {@link deadLetters}.
|
|
22
|
+
*/
|
|
23
|
+
export declare const send: {
|
|
24
|
+
<TActor extends AnyActorRef>(event: SendableEventFrom<TActor>): (actor: TActor) => Effect.Effect<void>;
|
|
25
|
+
<TActor extends AnyActorRef>(actor: TActor, event: SendableEventFrom<TActor>): Effect.Effect<void>;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Streams an actor's snapshots, starting with the current one. The stream ends
|
|
29
|
+
* when the actor completes or stops, and emits the error snapshot before
|
|
30
|
+
* ending when the actor errors. Interrupting the stream unsubscribes from the
|
|
31
|
+
* actor.
|
|
32
|
+
*/
|
|
33
|
+
export declare function snapshots<TActor extends AnyActorRef>(actor: TActor): Stream.Stream<SnapshotFrom<TActor>>;
|
|
34
|
+
/**
|
|
35
|
+
* Streams every event an actor emits, as delivered to `actor.on('*', …)`. The
|
|
36
|
+
* stream ends when the actor completes, errors or stops. Interrupting the
|
|
37
|
+
* stream removes the listener.
|
|
38
|
+
*/
|
|
39
|
+
export declare function emitted<TActor extends AnyActorRef>(actor: TActor): Stream.Stream<EmittedEventFrom<TActor>>;
|
|
40
|
+
/**
|
|
41
|
+
* Waits for the first actor snapshot that satisfies `predicate`, succeeding
|
|
42
|
+
* immediately when the current snapshot already does. Fails with
|
|
43
|
+
* `ActorStoppedError` if the actor stops or errors first, and with
|
|
44
|
+
* `Cause.TimeoutError` when `options.timeout` elapses. Interrupting the Effect
|
|
45
|
+
* unsubscribes from the actor.
|
|
46
|
+
*/
|
|
47
|
+
export declare const waitFor: {
|
|
48
|
+
<TActor extends AnyActorRef, TNarrowed extends SnapshotFrom<TActor>>(predicate: (snapshot: SnapshotFrom<TActor>) => snapshot is TNarrowed): (actor: TActor) => Effect.Effect<TNarrowed, ActorStoppedError>;
|
|
49
|
+
<TActor extends AnyActorRef>(predicate: (snapshot: SnapshotFrom<TActor>) => boolean): (actor: TActor) => Effect.Effect<SnapshotFrom<TActor>, ActorStoppedError>;
|
|
50
|
+
<TActor extends AnyActorRef, TNarrowed extends SnapshotFrom<TActor>>(predicate: (snapshot: SnapshotFrom<TActor>) => snapshot is TNarrowed, options: WaitForOptions): (actor: TActor) => Effect.Effect<TNarrowed, ActorStoppedError | Cause.TimeoutError>;
|
|
51
|
+
<TActor extends AnyActorRef>(predicate: (snapshot: SnapshotFrom<TActor>) => boolean, options: WaitForOptions): (actor: TActor) => Effect.Effect<SnapshotFrom<TActor>, ActorStoppedError | Cause.TimeoutError>;
|
|
52
|
+
<TActor extends AnyActorRef, TNarrowed extends SnapshotFrom<TActor>>(actor: TActor, predicate: (snapshot: SnapshotFrom<TActor>) => snapshot is TNarrowed): Effect.Effect<TNarrowed, ActorStoppedError>;
|
|
53
|
+
<TActor extends AnyActorRef>(actor: TActor, predicate: (snapshot: SnapshotFrom<TActor>) => boolean): Effect.Effect<SnapshotFrom<TActor>, ActorStoppedError>;
|
|
54
|
+
<TActor extends AnyActorRef, TNarrowed extends SnapshotFrom<TActor>>(actor: TActor, predicate: (snapshot: SnapshotFrom<TActor>) => snapshot is TNarrowed, options: WaitForOptions): Effect.Effect<TNarrowed, ActorStoppedError | Cause.TimeoutError>;
|
|
55
|
+
<TActor extends AnyActorRef>(actor: TActor, predicate: (snapshot: SnapshotFrom<TActor>) => boolean, options: WaitForOptions): Effect.Effect<SnapshotFrom<TActor>, ActorStoppedError | Cause.TimeoutError>;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* 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
|
|
60
|
+
* `ActorStoppedError` when it stops without output. Waits for a still-active
|
|
61
|
+
* actor to settle.
|
|
62
|
+
*/
|
|
63
|
+
export declare function join<TActor extends AnyActorRef>(actor: TActor): Effect.Effect<OutputFrom<TActor>, ErrorFrom<TActor> | ActorStoppedError>;
|
|
64
|
+
/**
|
|
65
|
+
* Streams the inspection events of the actor's system, as delivered to
|
|
66
|
+
* `system.inspect(…)`. The stream runs until it is interrupted or its scope
|
|
67
|
+
* closes.
|
|
68
|
+
*/
|
|
69
|
+
export declare function inspect(actor: AnyActorRef): Stream.Stream<InspectionEvent>;
|
|
70
|
+
/**
|
|
71
|
+
* Streams the events the actor's system could not deliver: sends to a
|
|
72
|
+
* stopped actor, invalid external events and internal events sent from
|
|
73
|
+
* outside their owner. A dead letter is not an actor error. The stream runs
|
|
74
|
+
* until it is interrupted or its scope closes.
|
|
75
|
+
*/
|
|
76
|
+
export declare function deadLetters(actor: AnyActorRef): Stream.Stream<DeadLetterInspectionEvent>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { AsyncResult, Atom } from 'effect/unstable/reactivity';
|
|
2
|
+
import type { AnyActorLogic, ErrorFrom, EventFromLogic, SnapshotFrom } from 'xstate';
|
|
3
|
+
import { type EffectActorOptions } from "./createEffectActor.js";
|
|
4
|
+
import type { EffectActor } from "./effectActor.js";
|
|
5
|
+
import { NotReadyError } from "./errors.js";
|
|
6
|
+
import { type TaggedStateFrom } from "./state.js";
|
|
7
|
+
import type { RequirementsFrom } from "./types.js";
|
|
8
|
+
export { NotReadyError } from "./errors.js";
|
|
9
|
+
/**
|
|
10
|
+
* Atoms that expose one actor to a reactive UI through
|
|
11
|
+
* `effect/unstable/reactivity`. Read them with the atom bindings for your
|
|
12
|
+
* framework, such as `@effect/atom-react`.
|
|
13
|
+
*/
|
|
14
|
+
export interface ActorAtoms<TLogic extends AnyActorLogic, ER = never> {
|
|
15
|
+
/**
|
|
16
|
+
* The running actor. It starts when the atom is first read and stops when
|
|
17
|
+
* the atom is released, that is, when nothing reads or mounts it anymore.
|
|
18
|
+
*/
|
|
19
|
+
readonly actor: Atom.Atom<AsyncResult.AsyncResult<EffectActor<TLogic>, ER>>;
|
|
20
|
+
/** The actor's current snapshot, updated on every transition. */
|
|
21
|
+
readonly snapshot: Atom.Atom<AsyncResult.AsyncResult<SnapshotFrom<TLogic>, ER>>;
|
|
22
|
+
/**
|
|
23
|
+
* The snapshot as a result: a `Failure` carrying the actor's error once
|
|
24
|
+
* the actor's status is `error`, so an error boundary can handle it.
|
|
25
|
+
*/
|
|
26
|
+
readonly result: Atom.Atom<AsyncResult.AsyncResult<SnapshotFrom<TLogic>, ER | ErrorFrom<TLogic>>>;
|
|
27
|
+
/**
|
|
28
|
+
* Sends an event to the actor synchronously. Set it with the event, for
|
|
29
|
+
* example through `useAtomSet` in React. Its value reports the last send:
|
|
30
|
+
* a `NotReadyError` failure when the runtime is still building, otherwise
|
|
31
|
+
* success.
|
|
32
|
+
*/
|
|
33
|
+
readonly send: Atom.Writable<AsyncResult.AsyncResult<void, ER | NotReadyError>, EventFromLogic<TLogic>>;
|
|
34
|
+
/** Derives an atom of a value selected from the snapshot. */
|
|
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
|
+
}
|
|
42
|
+
interface MissingRequirements<T> {
|
|
43
|
+
readonly 'The runtime does not provide services the logic requires': T;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Creates atoms for an actor that runs in an `Atom.runtime`. The runtime's
|
|
47
|
+
* Layer must provide every service the logic requires; a missing service is
|
|
48
|
+
* a type error on the `runtime` argument.
|
|
49
|
+
*
|
|
50
|
+
* The actor is created with `createEffectActor` inside the `actor` atom's
|
|
51
|
+
* scope, so its lifetime follows the atom: it starts on first read and stops
|
|
52
|
+
* when the atom is released. Wrap the atoms with `Atom.keepAlive` to pin the
|
|
53
|
+
* actor for the registry's lifetime, or with `Atom.family` to create one
|
|
54
|
+
* actor per input.
|
|
55
|
+
*/
|
|
56
|
+
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?: EffectActorOptions<TLogic>): ActorAtoms<TLogic, ER>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const effectActionBrand: unique symbol;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Effect, Scope } from 'effect';
|
|
2
|
+
import { type AnyActorLogic, type InputFrom } from 'xstate';
|
|
3
|
+
import { EffectActor } from "./effectActor.js";
|
|
4
|
+
import type { RequirementsFrom } from "./types.js";
|
|
5
|
+
/** Options for {@link createEffectActor}. */
|
|
6
|
+
export interface EffectActorOptions<TLogic extends AnyActorLogic> {
|
|
7
|
+
/** The actor's input. */
|
|
8
|
+
readonly input?: InputFrom<TLogic>;
|
|
9
|
+
}
|
|
10
|
+
type RequiredInput<TLogic extends AnyActorLogic> = undefined extends InputFrom<TLogic> ? {
|
|
11
|
+
input?: InputFrom<TLogic>;
|
|
12
|
+
} : {
|
|
13
|
+
input: InputFrom<TLogic>;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Creates and starts an actor as an Effect interpreter over pure transitions.
|
|
17
|
+
*
|
|
18
|
+
* Each step is `transition(snapshot, event)`, a pure function that returns
|
|
19
|
+
* the next snapshot and the actions to run. An Effect fiber owns the loop:
|
|
20
|
+
* the mailbox is a `Queue`, timers are `Effect.sleep` fibers on the Effect
|
|
21
|
+
* `Clock`, and declared Effect actions run as forked Effects in the actor's
|
|
22
|
+
* `Scope` with the services captured here. Child actors are started as live
|
|
23
|
+
* XState actors whose Effects run in the same host.
|
|
24
|
+
*
|
|
25
|
+
* The actor is a scoped resource: it stops, and every Effect it hosts is
|
|
26
|
+
* interrupted, when the enclosing `Scope` closes. The returned Effect never
|
|
27
|
+
* fails; the actor's own outcome is its snapshot status, read with `join`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createEffectActor<TLogic extends AnyActorLogic>(logic: TLogic, ...[options]: undefined extends InputFrom<TLogic> ? [options?: EffectActorOptions<TLogic>] : [options: EffectActorOptions<TLogic> & RequiredInput<TLogic>]): Effect.Effect<EffectActor<TLogic>, never, RequirementsFrom<TLogic> | Scope.Scope>;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
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;
|
|
7
|
+
}
|
|
8
|
+
export declare const actionFailure: unique symbol;
|
|
9
|
+
export declare function isActionFailure(value: unknown): value is ActionFailure;
|
|
10
|
+
export type MailboxItem<TEvent> = TEvent | ActionFailure;
|
|
11
|
+
declare const symbolObservable: typeof Symbol.observable;
|
|
12
|
+
/**
|
|
13
|
+
* Calls a listener and reports an exception it throws without letting it
|
|
14
|
+
* escape into the interpreter, matching core's `safeCall`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function safeCall<T>(fn: ((arg: T) => void) | undefined, arg?: T): void;
|
|
17
|
+
/**
|
|
18
|
+
* The handle `createEffectActor` returns. It implements XState's `ActorRef`
|
|
19
|
+
* contract (`send`, `getSnapshot`, `subscribe`, `on`), so it works with
|
|
20
|
+
* `useSelector`, this package's actor functions and the inspection APIs, while
|
|
21
|
+
* the actor itself is driven by an Effect fiber over pure transitions.
|
|
22
|
+
*/
|
|
23
|
+
export declare class EffectActor<TLogic extends AnyActorLogic> implements ActorRef<SnapshotFrom<TLogic>, EventFromLogic<TLogic>, EmittedFrom<TLogic>> {
|
|
24
|
+
readonly logic: TLogic;
|
|
25
|
+
private readonly _mailbox;
|
|
26
|
+
private readonly _stopExecution;
|
|
27
|
+
private readonly _inspectors;
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly address: string;
|
|
30
|
+
readonly sessionId: string | undefined;
|
|
31
|
+
/** The actor system that hosts this actor and its children. */
|
|
32
|
+
readonly system: AnyActor['system'];
|
|
33
|
+
private _snapshot;
|
|
34
|
+
private readonly _observers;
|
|
35
|
+
private readonly _listeners;
|
|
36
|
+
private _settled;
|
|
37
|
+
constructor(logic: TLogic, root: AnyActor, snapshot: SnapshotFrom<TLogic>, _mailbox: Queue.Queue<MailboxItem<EventFromLogic<TLogic>>>, _stopExecution: () => void, _inspectors: Set<(event: InspectionEvent) => void>);
|
|
38
|
+
getSnapshot(): SnapshotFrom<TLogic>;
|
|
39
|
+
getPersistedSnapshot(): Snapshot<unknown>;
|
|
40
|
+
/** Sends an event; the actor processes it on its own fiber. */
|
|
41
|
+
send(event: EventFromLogic<TLogic>): void;
|
|
42
|
+
/** Stops the actor, its children and every Effect it hosts. */
|
|
43
|
+
stop(): this;
|
|
44
|
+
subscribe(observer: Observer<SnapshotFrom<TLogic>>): Subscription;
|
|
45
|
+
subscribe(nextListener?: (snapshot: SnapshotFrom<TLogic>) => void, errorListener?: (error: any) => void, completeListener?: () => void): Subscription;
|
|
46
|
+
on<TType extends EmittedFrom<TLogic>['type'] | '*'>(type: TType, handler: (emitted: EmittedFrom<TLogic> & (TType extends '*' ? unknown : {
|
|
47
|
+
type: TType;
|
|
48
|
+
})) => void): Subscription;
|
|
49
|
+
/**
|
|
50
|
+
* Observes the inspection events of this actor and its children: every
|
|
51
|
+
* transition, event delivery and dead letter of the execution.
|
|
52
|
+
*/
|
|
53
|
+
inspect(observer: Observer<InspectionEvent> | ((event: InspectionEvent) => void)): Subscription;
|
|
54
|
+
[symbolObservable](): this;
|
|
55
|
+
toJSON(): {
|
|
56
|
+
xstate$$type: number;
|
|
57
|
+
id: string;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Cause } from 'effect';
|
|
2
|
+
import type { Snapshot } from 'xstate';
|
|
3
|
+
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
|
+
readonly _tag: "EffectInterruptedError";
|
|
5
|
+
} & Readonly<A>;
|
|
6
|
+
/**
|
|
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.
|
|
10
|
+
*/
|
|
11
|
+
export declare class EffectInterruptedError extends EffectInterruptedError_base<{
|
|
12
|
+
readonly cause: Cause.Cause<never>;
|
|
13
|
+
}> {
|
|
14
|
+
get message(): string;
|
|
15
|
+
}
|
|
16
|
+
declare const ActorStoppedError_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 & {
|
|
17
|
+
readonly _tag: "ActorStoppedError";
|
|
18
|
+
} & Readonly<A>;
|
|
19
|
+
/**
|
|
20
|
+
* Reported by `waitFor` when the actor stops or errors before a snapshot
|
|
21
|
+
* matches, and by `join` when the actor stops without output. `join` reports
|
|
22
|
+
* an errored actor's own `snapshot.error` instead.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ActorStoppedError extends ActorStoppedError_base<{
|
|
25
|
+
readonly actorId: string;
|
|
26
|
+
readonly snapshot: Snapshot<unknown>;
|
|
27
|
+
}> {
|
|
28
|
+
get message(): string;
|
|
29
|
+
}
|
|
30
|
+
declare const NotReadyError_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 & {
|
|
31
|
+
readonly _tag: "NotReadyError";
|
|
32
|
+
} & Readonly<A>;
|
|
33
|
+
/**
|
|
34
|
+
* Reported by the `send` atom of `createActorAtoms` when an event is sent
|
|
35
|
+
* before the actor's runtime has finished building.
|
|
36
|
+
*/
|
|
37
|
+
export declare class NotReadyError extends NotReadyError_base {
|
|
38
|
+
get message(): string;
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { Effect, Stream } from 'effect';
|
|
2
|
+
import { type ActorLogicValidator, type ActorLogic, type AnyActorRef, type AnyActorSystem, type AnyEventObject, type EventObject, type Snapshot, type StandardSchemaV1 } from 'xstate';
|
|
3
|
+
import type { EffectRequirements } from "./types.js";
|
|
4
|
+
import { type EffectSchemaLike, type ToStandardSchema, type ValidateEffectActorSchemas } from "./schema.js";
|
|
5
|
+
declare const effectLogicBrand: unique symbol;
|
|
6
|
+
/**
|
|
7
|
+
* Type-level marker attached to logic created by `fromEffect`,
|
|
8
|
+
* `fromEffectStream` and `fromEffectEventStream`. It carries the logic's
|
|
9
|
+
* failure type and its Effect service requirements, which is how
|
|
10
|
+
* `RequirementsFrom` collects the `R` channel of `createEffectActor` without
|
|
11
|
+
* inspecting the logic at runtime.
|
|
12
|
+
*/
|
|
13
|
+
export interface EffectLogicBrand<TError, TRequirements> {
|
|
14
|
+
readonly [effectLogicBrand]: {
|
|
15
|
+
readonly error: TError;
|
|
16
|
+
readonly requirements: TRequirements;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Snapshot of a `fromEffect` actor. The actor holds no context of its own: it
|
|
21
|
+
* 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`.
|
|
24
|
+
*/
|
|
25
|
+
export type EffectSnapshot<TOutput, TError, TInput> = Snapshot<TOutput> & {
|
|
26
|
+
readonly context: undefined;
|
|
27
|
+
readonly input: TInput | undefined;
|
|
28
|
+
readonly error: TError | undefined;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Argument passed to the function form of an Effect source. It gives the
|
|
32
|
+
* source the actor's `input`, its own reference (`self`), the actor `system`,
|
|
33
|
+
* and `emit` for publishing events that `actor.on(...)` and `emitted(actor)`
|
|
34
|
+
* observe.
|
|
35
|
+
*/
|
|
36
|
+
export type EffectSourceArgs<TInput> = {
|
|
37
|
+
readonly input: TInput;
|
|
38
|
+
readonly self: AnyActorRef;
|
|
39
|
+
readonly system: AnyActorSystem;
|
|
40
|
+
/** Emits an event that can be observed with `actor.on(...)` or `emitted(actor)`. */
|
|
41
|
+
readonly emit: (event: AnyEventObject) => void;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* What `fromEffect` accepts as its Effect: either an Effect value, or a
|
|
45
|
+
* function of {@link EffectSourceArgs} returning one. The function form is
|
|
46
|
+
* called once per actor start, so it sees that actor's input.
|
|
47
|
+
*/
|
|
48
|
+
export type EffectSource<TOutput, TError, TInput, TRequirements> = Effect.Effect<TOutput, TError, TRequirements> | ((args: EffectSourceArgs<TInput>) => Effect.Effect<TOutput, TError, TRequirements>);
|
|
49
|
+
type EffectActorSchemas = {
|
|
50
|
+
readonly input?: EffectSchemaLike;
|
|
51
|
+
readonly output?: EffectSchemaLike;
|
|
52
|
+
};
|
|
53
|
+
type EffectSourceConfig<TOutput, TError, TInput, TRequirements, TSchemas extends EffectActorSchemas = EffectActorSchemas, TValidator extends ActorLogicValidator | undefined = ActorLogicValidator | undefined> = {
|
|
54
|
+
readonly id?: string;
|
|
55
|
+
readonly validator?: TValidator;
|
|
56
|
+
readonly schemas?: TSchemas & ([TValidator] extends [ActorLogicValidator] ? ValidateEffectActorSchemas<TSchemas> : unknown);
|
|
57
|
+
readonly effect: EffectSource<TOutput, TError, TInput, TRequirements>;
|
|
58
|
+
};
|
|
59
|
+
type SchemaOutput<TSchema extends EffectSchemaLike> = StandardSchemaV1.InferOutput<ToStandardSchema<TSchema>>;
|
|
60
|
+
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;
|
|
62
|
+
type EffectSchemaValidationConfig<TSchemas extends EffectActorSchemas> = {
|
|
63
|
+
readonly validator: ActorLogicValidator;
|
|
64
|
+
readonly schemas: TSchemas & ValidateEffectActorSchemas<TSchemas>;
|
|
65
|
+
} | {
|
|
66
|
+
readonly validator?: undefined;
|
|
67
|
+
readonly schemas: TSchemas;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Actor logic produced by `fromEffect` and `fromEffectEventStream`. It is
|
|
71
|
+
* ordinary XState actor logic carrying {@link EffectLogicBrand}, so a machine
|
|
72
|
+
* can invoke or spawn it, and `createEffectActor` can collect its
|
|
73
|
+
* requirements.
|
|
74
|
+
*/
|
|
75
|
+
export type EffectActorLogic<TOutput, TError, TInput, TRequirements> = ActorLogic<EffectSnapshot<TOutput, TError, TInput>, EventObject, TInput, AnyActorSystem> & {
|
|
76
|
+
readonly id?: string;
|
|
77
|
+
} & EffectLogicBrand<TError, TRequirements>;
|
|
78
|
+
/**
|
|
79
|
+
* Snapshot of a `fromEffectStream` actor. `context` holds the most recent
|
|
80
|
+
* stream item, or `undefined` before the first one. The actor reaches `done`
|
|
81
|
+
* with no output when the stream completes, and `error` when it fails.
|
|
82
|
+
*/
|
|
83
|
+
export type EffectStreamSnapshot<TItem, TError, TInput> = Snapshot<undefined> & {
|
|
84
|
+
readonly context: TItem | undefined;
|
|
85
|
+
readonly input: TInput | undefined;
|
|
86
|
+
readonly error: TError | undefined;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Actor logic produced by `fromEffectStream`. Its snapshot is an
|
|
90
|
+
* {@link EffectStreamSnapshot}, so the parent reads the latest item from the
|
|
91
|
+
* child's `context` rather than from events.
|
|
92
|
+
*/
|
|
93
|
+
export type EffectStreamActorLogic<TItem, TError, TInput, TRequirements> = ActorLogic<EffectStreamSnapshot<TItem, TError, TInput>, EventObject, TInput, AnyActorSystem> & {
|
|
94
|
+
readonly id?: string;
|
|
95
|
+
} & EffectLogicBrand<TError, TRequirements>;
|
|
96
|
+
/**
|
|
97
|
+
* 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
|
|
101
|
+
* an Effect, a function of {@link EffectSourceArgs} returning one, or a config
|
|
102
|
+
* object with `id`, `schemas`, `validator` and `effect`. The logic must be run
|
|
103
|
+
* under `createEffectActor`, which provides the Effect services it declares.
|
|
104
|
+
*/
|
|
105
|
+
export declare function fromEffect<const TInputSchema extends EffectSchemaLike, const TOutputSchema extends EffectSchemaLike, TError = unknown, TRequirements = never>(config: Omit<EffectSourceConfig<SchemaOutput<TOutputSchema>, TError, SchemaOutput<TInputSchema>, TRequirements>, 'schemas' | 'validator'> & EffectSchemaValidationConfig<{
|
|
106
|
+
input: TInputSchema;
|
|
107
|
+
output: TOutputSchema;
|
|
108
|
+
}>): EffectActorLogic<SchemaOutput<TOutputSchema>, TError, SchemaOutput<TInputSchema>, TRequirements>;
|
|
109
|
+
export declare function fromEffect<const TInputSchema extends EffectSchemaLike, TEffect extends Effect.Effect<any, any, any>>(config: Omit<EffectSourceConfig<EffectSuccess<TEffect>, EffectFailure<TEffect>, SchemaOutput<TInputSchema>, EffectRequirements<TEffect>, {
|
|
110
|
+
input: TInputSchema;
|
|
111
|
+
}>, 'effect' | 'schemas' | 'validator'> & EffectSchemaValidationConfig<{
|
|
112
|
+
input: TInputSchema;
|
|
113
|
+
output?: never;
|
|
114
|
+
}> & {
|
|
115
|
+
effect: TEffect | ((args: EffectSourceArgs<SchemaOutput<TInputSchema>>) => TEffect);
|
|
116
|
+
}): EffectActorLogic<EffectSuccess<TEffect>, EffectFailure<TEffect>, SchemaOutput<TInputSchema>, EffectRequirements<TEffect>>;
|
|
117
|
+
export declare function fromEffect<const TOutputSchema extends EffectSchemaLike, TError = unknown, TInput = undefined, TRequirements = never>(config: Omit<EffectSourceConfig<SchemaOutput<TOutputSchema>, TError, TInput, TRequirements>, 'schemas' | 'validator'> & EffectSchemaValidationConfig<{
|
|
118
|
+
input?: never;
|
|
119
|
+
output: TOutputSchema;
|
|
120
|
+
}>): EffectActorLogic<SchemaOutput<TOutputSchema>, TError, TInput, TRequirements>;
|
|
121
|
+
export declare function fromEffect<TOutput, TError = unknown, TInput = undefined, TRequirements = never>(config: EffectSourceConfig<TOutput, TError, TInput, TRequirements> & {
|
|
122
|
+
schemas?: undefined;
|
|
123
|
+
}): EffectActorLogic<TOutput, TError, TInput, TRequirements>;
|
|
124
|
+
export declare function fromEffect<TOutput, TError = unknown, TRequirements = never>(effect: Effect.Effect<TOutput, TError, TRequirements>): EffectActorLogic<TOutput, TError, undefined, TRequirements>;
|
|
125
|
+
export declare function fromEffect<TOutput, TError = unknown, TInput = undefined, TRequirements = never>(effect: (args: EffectSourceArgs<TInput>) => Effect.Effect<TOutput, TError, TRequirements>): EffectActorLogic<TOutput, TError, TInput, TRequirements>;
|
|
126
|
+
/**
|
|
127
|
+
* What `fromEffectStream` and `fromEffectEventStream` accept as their stream:
|
|
128
|
+
* either a Stream value, or a function of {@link EffectSourceArgs} returning
|
|
129
|
+
* one. The function form is called once per actor start.
|
|
130
|
+
*/
|
|
131
|
+
export type EffectStreamSource<TItem, TError, TInput, TRequirements> = Stream.Stream<TItem, TError, TRequirements> | ((args: EffectSourceArgs<TInput>) => Stream.Stream<TItem, TError, TRequirements>);
|
|
132
|
+
type EffectStreamConfig<TItem, TError, TInput, TRequirements, TSchemas extends {
|
|
133
|
+
readonly input?: EffectSchemaLike;
|
|
134
|
+
} = {
|
|
135
|
+
readonly input?: EffectSchemaLike;
|
|
136
|
+
}, TValidator extends ActorLogicValidator | undefined = ActorLogicValidator | undefined> = {
|
|
137
|
+
readonly id?: string;
|
|
138
|
+
readonly validator?: TValidator;
|
|
139
|
+
readonly schemas?: TSchemas & ([TValidator] extends [ActorLogicValidator] ? ValidateEffectActorSchemas<TSchemas> : unknown);
|
|
140
|
+
readonly stream: EffectStreamSource<TItem, TError, TInput, TRequirements>;
|
|
141
|
+
};
|
|
142
|
+
type StreamItem<T> = T extends Stream.Stream<infer A, any, any> ? A : never;
|
|
143
|
+
type StreamError<T> = T extends Stream.Stream<any, infer E, any> ? E : never;
|
|
144
|
+
type StreamRequirements<T> = T extends Stream.Stream<any, any, infer R> ? R : never;
|
|
145
|
+
/**
|
|
146
|
+
* Creates actor logic that runs a Stream and exposes its most recent item as
|
|
147
|
+
* the actor's `context`. The actor reaches `done` when the stream completes
|
|
148
|
+
* and `error` when it fails. Accepts a Stream, a function of
|
|
149
|
+
* {@link EffectSourceArgs} returning one, or a config object with `id`,
|
|
150
|
+
* `schemas`, `validator` and `stream`.
|
|
151
|
+
*/
|
|
152
|
+
export declare function fromEffectStream<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<{
|
|
153
|
+
input: TInputSchema;
|
|
154
|
+
}> & {
|
|
155
|
+
stream: TStream | ((args: EffectSourceArgs<SchemaOutput<TInputSchema>>) => TStream);
|
|
156
|
+
}): EffectStreamActorLogic<StreamItem<TStream>, StreamError<TStream>, SchemaOutput<TInputSchema>, StreamRequirements<TStream>>;
|
|
157
|
+
export declare function fromEffectStream<TItem, TError = unknown, TInput = undefined, TRequirements = never>(config: EffectStreamConfig<TItem, TError, TInput, TRequirements> & {
|
|
158
|
+
schemas?: undefined;
|
|
159
|
+
}): EffectStreamActorLogic<TItem, TError, TInput, TRequirements>;
|
|
160
|
+
export declare function fromEffectStream<TItem, TError = unknown, TInput = undefined, TRequirements = never>(stream: EffectStreamSource<TItem, TError, TInput, TRequirements>): EffectStreamActorLogic<TItem, TError, TInput, TRequirements>;
|
|
161
|
+
/**
|
|
162
|
+
* Creates actor logic that runs a Stream of events and relays each item to the
|
|
163
|
+
* parent machine as an event, the way `fromEventObservable` does. The actor
|
|
164
|
+
* has no output: it reaches `done` when the stream completes and `error` when
|
|
165
|
+
* it fails. Accepts the same forms as `fromEffectStream`.
|
|
166
|
+
*/
|
|
167
|
+
export declare function fromEffectEventStream<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<{
|
|
168
|
+
input: TInputSchema;
|
|
169
|
+
}> & {
|
|
170
|
+
stream: TStream | ((args: EffectSourceArgs<SchemaOutput<TInputSchema>>) => TStream);
|
|
171
|
+
}): EffectActorLogic<undefined, StreamError<TStream>, SchemaOutput<TInputSchema>, StreamRequirements<TStream>>;
|
|
172
|
+
export declare function fromEffectEventStream<TEvent extends EventObject, TError = unknown, TInput = undefined, TRequirements = never>(config: EffectStreamConfig<TEvent, TError, TInput, TRequirements> & {
|
|
173
|
+
schemas?: undefined;
|
|
174
|
+
}): EffectActorLogic<undefined, TError, TInput, TRequirements>;
|
|
175
|
+
export declare function fromEffectEventStream<TEvent extends EventObject, TError = unknown, TInput = undefined, TRequirements = never>(stream: EffectStreamSource<TEvent, TError, TInput, TRequirements>): EffectActorLogic<undefined, TError, TInput, TRequirements>;
|
|
176
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { fromEffect, fromEffectEventStream, fromEffectStream, type EffectActorLogic, type EffectLogicBrand, type EffectSnapshot, type EffectSource, type EffectSourceArgs, type EffectStreamSource, type EffectStreamActorLogic, type EffectStreamSnapshot } from "./fromEffect.js";
|
|
2
|
+
export { createEffectActor, type EffectActorOptions } from "./createEffectActor.js";
|
|
3
|
+
export { EffectActor } from "./effectActor.js";
|
|
4
|
+
export { deadLetters, emitted, inspect, join, send, snapshots, waitFor, type EmittedEventFrom, type SendableEventFrom, type WaitForOptions } from "./actor.js";
|
|
5
|
+
export { ActorStoppedError, EffectInterruptedError } from "./errors.js";
|
|
6
|
+
export { setupEffect, type EffectAction, type EffectActionArgs, type EffectSetupReturn } from "./setupEffect.js";
|
|
7
|
+
export { type RequirementsFrom } from "./types.js";
|
|
8
|
+
export { taggedState, type StateTag, type TaggedState, type TaggedStateFrom } from "./state.js";
|
|
9
|
+
export { type ErrorFrom } from 'xstate';
|
|
10
|
+
export { type EffectSchema, type EffectSchemaLike, type EffectSetupSchemas, type EffectSetupStateSchema } from "./schema.js";
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
|
+
import type { SetupSchemas, SetupStateSchema, SetupStateSchemas, StandardSchemaV1 } from 'xstate';
|
|
3
|
+
/**
|
|
4
|
+
* An Effect `Schema` accepted by this package. `setupEffect`, `fromEffect`,
|
|
5
|
+
* `fromEffectStream` and `fromEffectEventStream` convert it to a Standard
|
|
6
|
+
* Schema, so XState infers the decoded `Schema.Type` without an explicit call
|
|
7
|
+
* to `Schema.toStandardSchemaV1`.
|
|
8
|
+
*/
|
|
9
|
+
export type EffectSchema = Schema.ConstraintDecoder<unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* Either an Effect {@link EffectSchema} or a Standard Schema. Every schema
|
|
12
|
+
* position in this package accepts both, so Effect schemas and schemas from
|
|
13
|
+
* other libraries can be mixed in one machine.
|
|
14
|
+
*/
|
|
15
|
+
export type EffectSchemaLike = StandardSchemaV1 | EffectSchema;
|
|
16
|
+
interface RuntimeValidationDoesNotSupportTransformingSchemas {
|
|
17
|
+
readonly __xstate_effect_error: 'Runtime validation does not support schemas with different encoded and decoded types';
|
|
18
|
+
}
|
|
19
|
+
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
20
|
+
export type ToStandardSchema<TSchema> = TSchema extends StandardSchemaV1 ? TSchema : TSchema extends EffectSchema ? StandardSchemaV1<TSchema['Encoded'], TSchema['Type']> & TSchema : never;
|
|
21
|
+
type AssertNonTransformingSchema<TSchema> = TSchema extends EffectSchemaLike ? IsAny<StandardSchemaV1.InferInput<ToStandardSchema<TSchema>>> extends true ? TSchema : IsAny<StandardSchemaV1.InferOutput<ToStandardSchema<TSchema>>> extends true ? TSchema : [
|
|
22
|
+
StandardSchemaV1.InferInput<ToStandardSchema<TSchema>>,
|
|
23
|
+
StandardSchemaV1.InferOutput<ToStandardSchema<TSchema>>
|
|
24
|
+
] extends [
|
|
25
|
+
StandardSchemaV1.InferOutput<ToStandardSchema<TSchema>>,
|
|
26
|
+
StandardSchemaV1.InferInput<ToStandardSchema<TSchema>>
|
|
27
|
+
] ? TSchema : RuntimeValidationDoesNotSupportTransformingSchemas : TSchema;
|
|
28
|
+
type EffectSchemaShape<TValue> = TValue extends StandardSchemaV1 ? EffectSchemaLike : TValue extends Record<string, unknown> ? {
|
|
29
|
+
[K in keyof TValue]: EffectSchemaShape<TValue[K]>;
|
|
30
|
+
} : TValue;
|
|
31
|
+
type ToStandardSchemaShape<TValue> = TValue extends EffectSchemaLike ? ToStandardSchema<TValue> : TValue extends Record<string, unknown> ? {
|
|
32
|
+
[K in keyof TValue]: ToStandardSchemaShape<TValue[K]>;
|
|
33
|
+
} : TValue;
|
|
34
|
+
/**
|
|
35
|
+
* The `schemas` option of `setupEffect`: XState's `SetupSchemas` with every
|
|
36
|
+
* schema position widened to {@link EffectSchemaLike}. Covers `context`,
|
|
37
|
+
* `input`, `output` and the per-key records for `events`, `internalEvents`,
|
|
38
|
+
* `emitted` and `children`.
|
|
39
|
+
*/
|
|
40
|
+
export type EffectSetupSchemas = {
|
|
41
|
+
[K in keyof SetupSchemas]?: EffectSchemaShape<NonNullable<SetupSchemas[K]>>;
|
|
42
|
+
};
|
|
43
|
+
export type ValidateEffectActorSchemas<TSchemas> = {
|
|
44
|
+
[K in keyof TSchemas]: AssertNonTransformingSchema<TSchemas[K]>;
|
|
45
|
+
};
|
|
46
|
+
export type ValidateEffectSetupSchemas<TSchemas> = {
|
|
47
|
+
[K in keyof TSchemas]: K extends 'events' | 'internalEvents' | 'emitted' | 'children' ? {
|
|
48
|
+
[P in keyof TSchemas[K]]: AssertNonTransformingSchema<TSchemas[K][P]>;
|
|
49
|
+
} : K extends 'context' | 'input' | 'output' ? AssertNonTransformingSchema<TSchemas[K]> : TSchemas[K];
|
|
50
|
+
};
|
|
51
|
+
export type ToStandardSetupSchemas<TSchemas> = {
|
|
52
|
+
[K in keyof TSchemas]: ToStandardSchemaShape<TSchemas[K]>;
|
|
53
|
+
} extends infer TStandardSchemas extends SetupSchemas ? TStandardSchemas : never;
|
|
54
|
+
/**
|
|
55
|
+
* One node of the `states` option of `setupEffect`: the schemas declared for
|
|
56
|
+
* that state, and the same shape recursively for its child states. It is
|
|
57
|
+
* XState's `SetupStateSchema` with Effect schemas allowed in every schema
|
|
58
|
+
* position.
|
|
59
|
+
*/
|
|
60
|
+
export interface EffectSetupStateSchema {
|
|
61
|
+
schemas?: EffectSchemaShape<SetupStateSchemas>;
|
|
62
|
+
states?: Record<string, EffectSetupStateSchema>;
|
|
63
|
+
}
|
|
64
|
+
export type ValidateEffectSetupStates<TStates> = {
|
|
65
|
+
[K in keyof TStates]: TStates[K] extends EffectSetupStateSchema ? {
|
|
66
|
+
[P in keyof TStates[K]]: P extends 'schemas' ? TStates[K][P] extends Record<string, unknown> ? {
|
|
67
|
+
[S in keyof TStates[K][P]]: AssertNonTransformingSchema<TStates[K][P][S]>;
|
|
68
|
+
} : TStates[K][P] : P extends 'states' ? TStates[K][P] extends Record<string, EffectSetupStateSchema> ? ValidateEffectSetupStates<TStates[K][P]> : TStates[K][P] : TStates[K][P];
|
|
69
|
+
} : TStates[K];
|
|
70
|
+
};
|
|
71
|
+
type ToStandardSetupStateSchema<TStateSchema> = TStateSchema extends EffectSetupStateSchema ? {
|
|
72
|
+
[K in keyof TStateSchema]: K extends 'schemas' ? ToStandardSchemaShape<TStateSchema[K]> : K extends 'states' ? TStateSchema[K] extends Record<string, EffectSetupStateSchema> ? ToStandardSetupStates<TStateSchema[K]> : TStateSchema[K] : TStateSchema[K];
|
|
73
|
+
} extends infer TStandardStateSchema extends SetupStateSchema ? TStandardStateSchema : never : never;
|
|
74
|
+
export type ToStandardSetupStates<TStates> = {
|
|
75
|
+
[K in keyof TStates]: ToStandardSetupStateSchema<TStates[K]>;
|
|
76
|
+
};
|
|
77
|
+
export declare function toStandardSchema(schema: EffectSchemaLike): StandardSchemaV1;
|
|
78
|
+
export declare function toStandardSetupSchemas(schemas: EffectSetupSchemas | undefined): SetupSchemas | undefined;
|
|
79
|
+
export declare function toStandardSetupStates(states: Record<string, EffectSetupStateSchema> | undefined): Record<string, SetupStateSchema> | undefined;
|
|
80
|
+
export {};
|