effect-machine 0.9.0 → 0.11.0
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 +118 -55
- package/dist/actor.d.ts +77 -179
- package/dist/actor.js +161 -113
- package/dist/cluster/entity-machine.js +5 -3
- package/dist/errors.d.ts +12 -1
- package/dist/errors.js +8 -1
- package/dist/index.d.ts +4 -8
- package/dist/index.js +2 -7
- package/dist/internal/transition.d.ts +27 -3
- package/dist/internal/transition.js +38 -9
- package/dist/internal/utils.d.ts +7 -2
- package/dist/internal/utils.js +1 -5
- package/dist/machine.d.ts +94 -35
- package/dist/machine.js +128 -13
- package/dist/testing.js +57 -3
- package/package.json +10 -9
- package/v3/dist/actor.d.ts +210 -0
- package/{dist-v3 → v3/dist}/actor.js +198 -117
- package/{dist-v3 → v3/dist}/cluster/entity-machine.d.ts +1 -1
- package/{dist-v3 → v3/dist}/cluster/entity-machine.js +8 -6
- package/{dist-v3 → v3/dist}/cluster/to-entity.d.ts +1 -1
- package/{dist-v3 → v3/dist}/cluster/to-entity.js +1 -1
- package/v3/dist/errors.d.ts +76 -0
- package/{dist-v3 → v3/dist}/errors.js +9 -2
- package/v3/dist/index.d.ts +9 -0
- package/v3/dist/index.js +8 -0
- package/{dist-v3 → v3/dist}/inspection.d.ts +53 -8
- package/v3/dist/inspection.js +156 -0
- package/{dist-v3 → v3/dist}/internal/brands.d.ts +1 -1
- package/{dist-v3 → v3/dist}/internal/inspection.d.ts +1 -1
- package/v3/dist/internal/inspection.js +20 -0
- package/{dist-v3 → v3/dist}/internal/transition.d.ts +35 -11
- package/{dist-v3 → v3/dist}/internal/transition.js +47 -15
- package/{dist-v3 → v3/dist}/internal/utils.d.ts +9 -4
- package/{dist-v3 → v3/dist}/internal/utils.js +2 -6
- package/{dist-v3 → v3/dist}/machine.d.ts +113 -40
- package/{dist-v3 → v3/dist}/machine.js +191 -15
- package/{dist-v3 → v3/dist}/schema.d.ts +1 -1
- package/{dist-v3 → v3/dist}/schema.js +5 -2
- package/{dist-v3 → v3/dist}/slot.d.ts +4 -3
- package/{dist-v3 → v3/dist}/slot.js +1 -1
- package/{dist-v3 → v3/dist}/testing.d.ts +14 -8
- package/{dist-v3 → v3/dist}/testing.js +60 -6
- package/dist/persistence/adapter.d.ts +0 -135
- package/dist/persistence/adapter.js +0 -25
- package/dist/persistence/adapters/in-memory.d.ts +0 -32
- package/dist/persistence/adapters/in-memory.js +0 -174
- package/dist/persistence/index.d.ts +0 -5
- package/dist/persistence/index.js +0 -5
- package/dist/persistence/persistent-actor.d.ts +0 -50
- package/dist/persistence/persistent-actor.js +0 -368
- package/dist/persistence/persistent-machine.d.ts +0 -105
- package/dist/persistence/persistent-machine.js +0 -22
- package/dist-v3/actor.d.ts +0 -291
- package/dist-v3/errors.d.ts +0 -27
- package/dist-v3/index.d.ts +0 -12
- package/dist-v3/index.js +0 -13
- package/dist-v3/inspection.js +0 -48
- package/dist-v3/internal/inspection.js +0 -13
- package/dist-v3/persistence/adapter.d.ts +0 -125
- package/dist-v3/persistence/adapter.js +0 -25
- package/dist-v3/persistence/adapters/in-memory.d.ts +0 -32
- package/dist-v3/persistence/adapters/in-memory.js +0 -174
- package/dist-v3/persistence/index.d.ts +0 -5
- package/dist-v3/persistence/index.js +0 -5
- package/dist-v3/persistence/persistent-actor.d.ts +0 -49
- package/dist-v3/persistence/persistent-actor.js +0 -365
- package/dist-v3/persistence/persistent-machine.d.ts +0 -105
- package/dist-v3/persistence/persistent-machine.js +0 -22
- /package/{dist-v3 → v3/dist}/_virtual/_rolldown/runtime.js +0 -0
- /package/{dist-v3 → v3/dist}/cluster/index.d.ts +0 -0
- /package/{dist-v3 → v3/dist}/cluster/index.js +0 -0
- /package/{dist-v3 → v3/dist}/internal/brands.js +0 -0
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-machine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/cevr/effect-machine.git"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
9
|
"dist",
|
|
10
|
-
"dist
|
|
10
|
+
"v3/dist"
|
|
11
11
|
],
|
|
12
12
|
"type": "module",
|
|
13
13
|
"exports": {
|
|
@@ -25,14 +25,14 @@
|
|
|
25
25
|
},
|
|
26
26
|
"./v3": {
|
|
27
27
|
"import": {
|
|
28
|
-
"types": "./
|
|
29
|
-
"default": "./
|
|
28
|
+
"types": "./v3/dist/index.d.ts",
|
|
29
|
+
"default": "./v3/dist/index.js"
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
32
|
"./v3/cluster": {
|
|
33
33
|
"import": {
|
|
34
|
-
"types": "./
|
|
35
|
-
"default": "./
|
|
34
|
+
"types": "./v3/dist/cluster/index.d.ts",
|
|
35
|
+
"default": "./v3/dist/cluster/index.js"
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
},
|
|
@@ -41,17 +41,18 @@
|
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"typecheck": "tsc --noEmit",
|
|
44
|
-
"typecheck:v3": "tsc --noEmit -p tsconfig.
|
|
44
|
+
"typecheck:v3": "tsc --noEmit -p v3/tsconfig.json",
|
|
45
45
|
"lint": "oxlint",
|
|
46
46
|
"lint:fix": "oxlint --fix",
|
|
47
47
|
"fmt": "oxfmt",
|
|
48
48
|
"fmt:check": "oxfmt --check",
|
|
49
49
|
"test": "bun test",
|
|
50
|
+
"test:v3": "bun test --tsconfig-override=v3/tsconfig.json v3/test/",
|
|
50
51
|
"test:watch": "bun test --watch",
|
|
51
52
|
"gate": "concurrently -n type,lint,fmt,test,build -c blue,yellow,magenta,green,cyan \"bun run typecheck\" \"bun run lint:fix\" \"bun run fmt\" \"bun run test\" \"bun run build\"",
|
|
52
53
|
"prepare": "lefthook install || true && effect-language-service patch",
|
|
53
54
|
"version": "changeset version",
|
|
54
|
-
"build": "tsdown && tsdown --config tsdown.
|
|
55
|
+
"build": "tsdown && tsdown --config v3/tsdown.config.ts",
|
|
55
56
|
"release": "bun run build && changeset publish"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
@@ -63,7 +64,7 @@
|
|
|
63
64
|
"@effect/language-service": "^0.82.0",
|
|
64
65
|
"@types/bun": "1.3.11",
|
|
65
66
|
"concurrently": "^9.2.1",
|
|
66
|
-
"effect-bun-test": "0.
|
|
67
|
+
"effect-bun-test": "0.3.0",
|
|
67
68
|
"effect-v3": "npm:effect@^3.21.0",
|
|
68
69
|
"lefthook": "^2.1.4",
|
|
69
70
|
"oxfmt": "^0.41.0",
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { EffectsDef, GuardsDef, MachineContext } from "./slot.js";
|
|
2
|
+
import { ActorStoppedError, DuplicateActorError, NoReplyError } from "./errors.js";
|
|
3
|
+
import { ProcessEventError, ProcessEventHooks, ProcessEventResult, processEventCore, resolveTransition, runSpawnEffects } from "./internal/transition.js";
|
|
4
|
+
import { BuiltMachine, Machine, MachineRef } from "./machine.js";
|
|
5
|
+
import { Context, Deferred, Effect, Layer, Option, PubSub, Queue, Ref, Scope, Stream, SubscriptionRef } from "effect";
|
|
6
|
+
import * as effect_dist_dts_Tracer_js0 from "effect/dist/dts/Tracer.js";
|
|
7
|
+
|
|
8
|
+
//#region src/actor.d.ts
|
|
9
|
+
/** Discriminated mailbox request */
|
|
10
|
+
type QueuedEvent<E> = {
|
|
11
|
+
readonly _tag: "send";
|
|
12
|
+
readonly event: E;
|
|
13
|
+
} | {
|
|
14
|
+
readonly _tag: "call";
|
|
15
|
+
readonly event: E;
|
|
16
|
+
readonly reply: Deferred.Deferred<ProcessEventResult<{
|
|
17
|
+
readonly _tag: string;
|
|
18
|
+
}>, ActorStoppedError>;
|
|
19
|
+
} | {
|
|
20
|
+
readonly _tag: "ask";
|
|
21
|
+
readonly event: E;
|
|
22
|
+
readonly reply: Deferred.Deferred<unknown, NoReplyError | ActorStoppedError>;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Reference to a running actor.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Sync projection of ActorRef for non-Effect boundaries (React hooks, framework callbacks).
|
|
29
|
+
*/
|
|
30
|
+
interface ActorRefSync<State extends {
|
|
31
|
+
readonly _tag: string;
|
|
32
|
+
}, Event> {
|
|
33
|
+
readonly send: (event: Event) => void;
|
|
34
|
+
readonly stop: () => void;
|
|
35
|
+
readonly snapshot: () => State;
|
|
36
|
+
readonly matches: (tag: State["_tag"]) => boolean;
|
|
37
|
+
readonly can: (event: Event) => boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Information about a successful transition.
|
|
41
|
+
* Emitted on the `transitions` stream after each accepted event.
|
|
42
|
+
*/
|
|
43
|
+
interface TransitionInfo<State, Event> {
|
|
44
|
+
readonly fromState: State;
|
|
45
|
+
readonly toState: State;
|
|
46
|
+
readonly event: Event;
|
|
47
|
+
}
|
|
48
|
+
interface ActorRef<State extends {
|
|
49
|
+
readonly _tag: string;
|
|
50
|
+
}, Event> {
|
|
51
|
+
readonly id: string;
|
|
52
|
+
/** Send an event (fire-and-forget). */
|
|
53
|
+
readonly send: (event: Event) => Effect.Effect<void>;
|
|
54
|
+
/** Fire-and-forget alias for send (OTP gen_server:cast). */
|
|
55
|
+
readonly cast: (event: Event) => Effect.Effect<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Serialized request-reply (OTP gen_server:call).
|
|
58
|
+
* Event is processed through the queue; caller gets ProcessEventResult back.
|
|
59
|
+
*/
|
|
60
|
+
readonly call: (event: Event) => Effect.Effect<ProcessEventResult<State>>;
|
|
61
|
+
/**
|
|
62
|
+
* Typed request-reply. Event is processed through the queue; caller gets
|
|
63
|
+
* the domain value returned by the handler's `reply` field.
|
|
64
|
+
* Fails with NoReplyError if the handler doesn't provide a reply.
|
|
65
|
+
*/
|
|
66
|
+
readonly ask: <R>(event: Event) => Effect.Effect<R, NoReplyError | ActorStoppedError>;
|
|
67
|
+
/** Observable state. */
|
|
68
|
+
readonly state: SubscriptionRef.SubscriptionRef<State>;
|
|
69
|
+
/** Stop the actor gracefully. */
|
|
70
|
+
readonly stop: Effect.Effect<void>;
|
|
71
|
+
/** Get current state snapshot. */
|
|
72
|
+
readonly snapshot: Effect.Effect<State>;
|
|
73
|
+
/** Check if current state matches tag. */
|
|
74
|
+
readonly matches: (tag: State["_tag"]) => Effect.Effect<boolean>;
|
|
75
|
+
/** Check if event can be handled in current state. */
|
|
76
|
+
readonly can: (event: Event) => Effect.Effect<boolean>;
|
|
77
|
+
/** Stream of state changes. */
|
|
78
|
+
readonly changes: Stream.Stream<State>;
|
|
79
|
+
/**
|
|
80
|
+
* Stream of accepted transitions (edge stream).
|
|
81
|
+
*
|
|
82
|
+
* Emits `{ fromState, toState, event }` on every successful transition,
|
|
83
|
+
* including same-state reenters. PubSub-backed — late subscribers miss
|
|
84
|
+
* past edges. This is observational, not a durability guarantee.
|
|
85
|
+
*/
|
|
86
|
+
readonly transitions: Stream.Stream<TransitionInfo<State, Event>>;
|
|
87
|
+
/** Wait for a state matching predicate or variant (includes current snapshot). */
|
|
88
|
+
readonly waitFor: {
|
|
89
|
+
(predicate: (state: State) => boolean): Effect.Effect<State>;
|
|
90
|
+
(state: {
|
|
91
|
+
readonly _tag: State["_tag"];
|
|
92
|
+
}): Effect.Effect<State>;
|
|
93
|
+
};
|
|
94
|
+
/** Wait for a final state (includes current snapshot). */
|
|
95
|
+
readonly awaitFinal: Effect.Effect<State>;
|
|
96
|
+
/** Send event and wait for predicate, state variant, or final state. */
|
|
97
|
+
readonly sendAndWait: {
|
|
98
|
+
(event: Event, predicate: (state: State) => boolean): Effect.Effect<State>;
|
|
99
|
+
(event: Event, state: {
|
|
100
|
+
readonly _tag: State["_tag"];
|
|
101
|
+
}): Effect.Effect<State>;
|
|
102
|
+
(event: Event): Effect.Effect<State>;
|
|
103
|
+
};
|
|
104
|
+
/** Subscribe to state changes (sync callback). Returns unsubscribe function. */
|
|
105
|
+
readonly subscribe: (fn: (state: State) => void) => () => void;
|
|
106
|
+
/** Sync helpers for non-Effect boundaries. */
|
|
107
|
+
readonly sync: ActorRefSync<State, Event>;
|
|
108
|
+
/** The actor system this actor belongs to. */
|
|
109
|
+
readonly system: ActorSystem;
|
|
110
|
+
/** Child actors spawned via `self.spawn` in this actor's handlers. */
|
|
111
|
+
readonly children: ReadonlyMap<string, ActorRef<AnyState, unknown>>;
|
|
112
|
+
}
|
|
113
|
+
/** Base type for stored actors (internal) */
|
|
114
|
+
type AnyState = {
|
|
115
|
+
readonly _tag: string;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Events emitted by the ActorSystem when actors are spawned or stopped.
|
|
119
|
+
*/
|
|
120
|
+
type SystemEvent = {
|
|
121
|
+
readonly _tag: "ActorSpawned";
|
|
122
|
+
readonly id: string;
|
|
123
|
+
readonly actor: ActorRef<AnyState, unknown>;
|
|
124
|
+
} | {
|
|
125
|
+
readonly _tag: "ActorStopped";
|
|
126
|
+
readonly id: string;
|
|
127
|
+
readonly actor: ActorRef<AnyState, unknown>;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Listener callback for system events.
|
|
131
|
+
*/
|
|
132
|
+
type SystemEventListener = (event: SystemEvent) => void;
|
|
133
|
+
/**
|
|
134
|
+
* Actor system for managing actor lifecycles
|
|
135
|
+
*/
|
|
136
|
+
interface ActorSystem {
|
|
137
|
+
/**
|
|
138
|
+
* Spawn a new actor with the given machine.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* const built = machine.build({ fetchData: ... })
|
|
143
|
+
* const actor = yield* system.spawn("my-actor", built);
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
readonly spawn: <S extends {
|
|
147
|
+
readonly _tag: string;
|
|
148
|
+
}, E extends {
|
|
149
|
+
readonly _tag: string;
|
|
150
|
+
}, R>(id: string, machine: BuiltMachine<S, E, R>) => Effect.Effect<ActorRef<S, E>, DuplicateActorError, R>;
|
|
151
|
+
/**
|
|
152
|
+
* Get an existing actor by ID
|
|
153
|
+
*/
|
|
154
|
+
readonly get: (id: string) => Effect.Effect<Option.Option<ActorRef<AnyState, unknown>>>;
|
|
155
|
+
/**
|
|
156
|
+
* Stop an actor by ID
|
|
157
|
+
*/
|
|
158
|
+
readonly stop: (id: string) => Effect.Effect<boolean>;
|
|
159
|
+
/**
|
|
160
|
+
* Async stream of system events (actor spawned/stopped).
|
|
161
|
+
* Each subscriber gets their own queue — late subscribers miss prior events.
|
|
162
|
+
*/
|
|
163
|
+
readonly events: Stream.Stream<SystemEvent>;
|
|
164
|
+
/**
|
|
165
|
+
* Sync snapshot of all currently registered actors.
|
|
166
|
+
* Returns a new Map on each access (not live).
|
|
167
|
+
*/
|
|
168
|
+
readonly actors: ReadonlyMap<string, ActorRef<AnyState, unknown>>;
|
|
169
|
+
/**
|
|
170
|
+
* Subscribe to system events synchronously.
|
|
171
|
+
* Returns an unsubscribe function.
|
|
172
|
+
*/
|
|
173
|
+
readonly subscribe: (fn: SystemEventListener) => () => void;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* ActorSystem service tag
|
|
177
|
+
*/
|
|
178
|
+
declare const ActorSystem: Context.Tag<ActorSystem, ActorSystem>;
|
|
179
|
+
/** Listener set for sync subscriptions */
|
|
180
|
+
type Listeners<S> = Set<(state: S) => void>;
|
|
181
|
+
/**
|
|
182
|
+
* Notify all listeners of state change.
|
|
183
|
+
*/
|
|
184
|
+
declare const notifyListeners: <S>(listeners: Listeners<S>, state: S) => void;
|
|
185
|
+
/**
|
|
186
|
+
* Build core ActorRef methods shared between regular and persistent actors.
|
|
187
|
+
*/
|
|
188
|
+
declare const buildActorRefCore: <S extends {
|
|
189
|
+
readonly _tag: string;
|
|
190
|
+
}, E extends {
|
|
191
|
+
readonly _tag: string;
|
|
192
|
+
}, R, GD extends GuardsDef, EFD extends EffectsDef>(id: string, machine: Machine<S, E, R, any, any, GD, EFD>, stateRef: SubscriptionRef.SubscriptionRef<S>, eventQueue: Queue.Queue<QueuedEvent<E>>, stoppedRef: Ref.Ref<boolean>, listeners: Listeners<S>, stop: Effect.Effect<void>, system: ActorSystem, childrenMap: ReadonlyMap<string, ActorRef<AnyState, unknown>>, pendingReplies: Set<Deferred.Deferred<unknown, unknown>>, transitionsPubSub?: PubSub.PubSub<TransitionInfo<S, E>>) => ActorRef<S, E>;
|
|
193
|
+
/**
|
|
194
|
+
* Create and start an actor for a machine
|
|
195
|
+
*/
|
|
196
|
+
declare const createActor: <S extends {
|
|
197
|
+
readonly _tag: string;
|
|
198
|
+
}, E extends {
|
|
199
|
+
readonly _tag: string;
|
|
200
|
+
}, R, GD extends GuardsDef, EFD extends EffectsDef>(id: string, machine: Machine<S, E, R, Record<string, never>, Record<string, never>, GD, EFD>, options?: {
|
|
201
|
+
initialState?: S;
|
|
202
|
+
} | undefined) => Effect.Effect<ActorRef<S, E>, never, Exclude<R, MachineContext<S, E, MachineRef<E>>> | Exclude<Exclude<R, MachineContext<S, E, MachineRef<E>>>, effect_dist_dts_Tracer_js0.ParentSpan> | Exclude<Exclude<R, MachineContext<S, E, MachineRef<E>>>, Scope.Scope> | Exclude<Exclude<Exclude<R, MachineContext<S, E, MachineRef<E>>>, Scope.Scope>, effect_dist_dts_Tracer_js0.ParentSpan>>;
|
|
203
|
+
/** Fail all pending call/ask Deferreds with ActorStoppedError. Safe to call multiple times. */
|
|
204
|
+
declare const settlePendingReplies: (pendingReplies: Set<Deferred.Deferred<unknown, unknown>>, actorId: string) => Effect.Effect<void, never, never>;
|
|
205
|
+
/**
|
|
206
|
+
* Default ActorSystem layer
|
|
207
|
+
*/
|
|
208
|
+
declare const Default: Layer.Layer<ActorSystem, never, never>;
|
|
209
|
+
//#endregion
|
|
210
|
+
export { ActorRef, ActorRefSync, ActorSystem, Default, Listeners, type ProcessEventError, type ProcessEventHooks, type ProcessEventResult, QueuedEvent, SystemEvent, SystemEventListener, TransitionInfo, buildActorRefCore, createActor, notifyListeners, processEventCore, resolveTransition, runSpawnEffects, settlePendingReplies };
|