effect-machine 0.20.0 → 0.21.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/dist/actor.d.ts CHANGED
@@ -144,6 +144,20 @@ interface ActorRef<State extends {
144
144
  type AnyState = {
145
145
  readonly _tag: string;
146
146
  };
147
+ declare const ActorSystemKeyTypeId: unique symbol;
148
+ /** A typed identity for an actor stored in an ActorSystem. */
149
+ declare class ActorSystemKey<State extends AnyState, Event, Output = State> {
150
+ readonly id: string;
151
+ readonly [ActorSystemKeyTypeId]: {
152
+ readonly state: State;
153
+ readonly event: Event;
154
+ readonly output: Output;
155
+ };
156
+ constructor(id: string);
157
+ }
158
+ /** Create a typed ActorSystem identity. */
159
+ declare const actorSystemKey: <State extends AnyState, Event, Output = State>(id: string) => ActorSystemKey<State, Event, Output>;
160
+ type AnyActorSystemKey = ActorSystemKey<AnyState, unknown, unknown>;
147
161
  /**
148
162
  * Events emitted by the ActorSystem when actors are spawned or stopped.
149
163
  */
@@ -180,9 +194,15 @@ interface ActorSystemService {
180
194
  * ```
181
195
  */
182
196
  readonly spawn: {
197
+ <S extends AnyState, E extends {
198
+ readonly _tag: string;
199
+ }, R, Output>(key: ActorSystemKey<S, E, Output>, machine: Machine<S, E, R, any, any, void, Output>, options?: SystemSpawnOptions<S, E, void>): Effect.Effect<ActorRef<S, E, Output>, DuplicateActorError, R>;
183
200
  <S extends AnyState, E extends {
184
201
  readonly _tag: string;
185
202
  }, R, Output>(id: string, machine: Machine<S, E, R, any, any, void, Output>, options?: SystemSpawnOptions<S, E, void>): Effect.Effect<ActorRef<S, E, Output>, DuplicateActorError, R>;
203
+ <S extends AnyState, E extends {
204
+ readonly _tag: string;
205
+ }, R, Input, Output>(key: ActorSystemKey<S, E, Output>, machine: Machine<S, E, R, any, any, Input, Output>, options: SystemSpawnOptions<S, E, Input>): Effect.Effect<ActorRef<S, E, Output>, DuplicateActorError, R>;
186
206
  <S extends AnyState, E extends {
187
207
  readonly _tag: string;
188
208
  }, R, Input, Output>(id: string, machine: Machine<S, E, R, any, any, Input, Output>, options: SystemSpawnOptions<S, E, Input>): Effect.Effect<ActorRef<S, E, Output>, DuplicateActorError, R>;
@@ -190,11 +210,19 @@ interface ActorSystemService {
190
210
  /**
191
211
  * Get an existing actor by ID
192
212
  */
193
- readonly get: (id: string) => Effect.Effect<Option.Option<ActorRef<AnyState, unknown>>>;
213
+ readonly get: {
214
+ <S extends AnyState, E, Output>(key: ActorSystemKey<S, E, Output>): Effect.Effect<Option.Option<ActorRef<S, E, Output>>>;
215
+ (id: string): Effect.Effect<Option.Option<ActorRef<AnyState, unknown>>>;
216
+ };
217
+ /** Observe the current actor for one ID across actor generations. */
218
+ readonly watch: {
219
+ <S extends AnyState, E, Output>(key: ActorSystemKey<S, E, Output>): Stream.Stream<Option.Option<ActorRef<S, E, Output>>>;
220
+ (id: string): Stream.Stream<Option.Option<ActorRef<AnyState, unknown>>>;
221
+ };
194
222
  /**
195
223
  * Stop an actor by ID
196
224
  */
197
- readonly stop: (id: string) => Effect.Effect<boolean>;
225
+ readonly stop: (id: string | AnyActorSystemKey) => Effect.Effect<boolean>;
198
226
  /**
199
227
  * Async stream of system events (actor spawned/stopped).
200
228
  * Each subscriber gets their own queue — late subscribers miss prior events.
@@ -258,4 +286,4 @@ declare const createActor: <S extends {
258
286
  */
259
287
  declare const Default: Layer.Layer<ActorSystem, never, never>;
260
288
  //#endregion
261
- export { ActorClient, ActorLifecycle, ActorRef, ActorRefSync, ActorScope, ActorSystem, ActorSystemService, Default, type ProcessEventResult, SystemEvent, SystemEventListener, SystemSpawnOptions, TransitionInfo, createActor };
289
+ export { ActorClient, ActorLifecycle, ActorRef, ActorRefSync, ActorScope, ActorSystem, ActorSystemKey, ActorSystemService, Default, type ProcessEventResult, SystemEvent, SystemEventListener, SystemSpawnOptions, TransitionInfo, actorSystemKey, createActor };
package/dist/actor.js CHANGED
@@ -14,6 +14,19 @@ import { Cause, Context, Deferred, Effect, Exit, Fiber, Layer, MutableHashMap, O
14
14
  * - ActorSystem service (spawn/stop/get actors)
15
15
  * - Actor creation and event loop
16
16
  */
17
+ /** A typed identity for an actor stored in an ActorSystem. */
18
+ var ActorSystemKey = class {
19
+ id;
20
+ constructor(id) {
21
+ this.id = id;
22
+ }
23
+ };
24
+ /** Create a typed ActorSystem identity. */
25
+ const actorSystemKey = (id) => new ActorSystemKey(id);
26
+ const actorSystemId = (id) => {
27
+ if (typeof id === "string") return id;
28
+ return id.id;
29
+ };
17
30
  /**
18
31
  * ActorSystem service tag
19
32
  */
@@ -552,11 +565,34 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
552
565
  yield* actor.start.pipe(Effect.catchCause((cause) => actor.stop.pipe(Effect.andThen(Effect.failCause(cause)))));
553
566
  return actor;
554
567
  });
555
- const spawn = (id, machine, options) => withSpawnGate(spawnRegular(id, machine, options));
556
- const get = Effect.fn("effect-machine.actorSystem.get")(function* (id) {
557
- return yield* Effect.sync(() => MutableHashMap.get(actorsMap, id));
558
- });
559
- const stop = Effect.fn("effect-machine.actorSystem.stop")(function* (id) {
568
+ const spawn = (idOrKey, machine, options) => {
569
+ const id = actorSystemId(idOrKey);
570
+ return withSpawnGate(spawnRegular(id, machine, options));
571
+ };
572
+ function get(idOrKey) {
573
+ return Effect.sync(() => MutableHashMap.get(actorsMap, actorSystemId(idOrKey)));
574
+ }
575
+ const sameActor = (left, right) => {
576
+ if (Option.isNone(left)) return Option.isNone(right);
577
+ return Option.isSome(right) && Object.is(left.value, right.value);
578
+ };
579
+ function watch(idOrKey) {
580
+ const id = actorSystemId(idOrKey);
581
+ return Stream.callback((queue) => Effect.acquireRelease(Effect.sync(() => {
582
+ const unsubscribe = (event) => {
583
+ if (event.id !== id) return;
584
+ if (event._tag === "ActorSpawned") Queue.offerUnsafe(queue, Option.some(event.actor));
585
+ else if (event._tag === "ActorStopped") Queue.offerUnsafe(queue, Option.none());
586
+ };
587
+ eventListeners.add(unsubscribe);
588
+ Queue.offerUnsafe(queue, MutableHashMap.get(actorsMap, id));
589
+ return () => {
590
+ eventListeners.delete(unsubscribe);
591
+ };
592
+ }), (unsubscribe) => Effect.sync(unsubscribe))).pipe(Stream.changesWith(sameActor));
593
+ }
594
+ const stop = Effect.fn("effect-machine.actorSystem.stop")(function* (idOrKey) {
595
+ const id = actorSystemId(idOrKey);
560
596
  const maybeActor = MutableHashMap.get(actorsMap, id);
561
597
  if (Option.isNone(maybeActor)) return false;
562
598
  const actor = maybeActor.value;
@@ -573,6 +609,7 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
573
609
  return ActorSystem.of({
574
610
  spawn,
575
611
  get,
612
+ watch,
576
613
  stop,
577
614
  events: Stream.fromPubSub(eventPubSub),
578
615
  get actors() {
@@ -600,4 +637,4 @@ const makeSystem = make;
600
637
  */
601
638
  const Default = Layer.effect(ActorSystem, make());
602
639
  //#endregion
603
- export { ActorScope, ActorSystem, Default, createActor, makeSystem };
640
+ export { ActorScope, ActorSystem, ActorSystemKey, Default, actorSystemKey, createActor, makeSystem };
package/dist/atom.d.ts CHANGED
@@ -1,6 +1,8 @@
1
- import { ActorLifecycle, ActorRef, TransitionInfo } from "./actor.js";
1
+ import { ActorLifecycle, ActorRef, ActorSystemKey, ActorSystemService, TransitionInfo } from "./actor.js";
2
+ import * as Option from "effect/Option";
2
3
  import * as Atom from "effect/unstable/reactivity/Atom";
3
4
  import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
5
+ import * as Cause from "effect/Cause";
4
6
  //#region src/atom.d.ts
5
7
  /**
6
8
  * A writable Atom projection of an actor.
@@ -8,6 +10,32 @@ import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
8
10
  * The Atom value is the current actor state. Atom writes send actor events.
9
11
  */
10
12
  type ActorAtom<State, Event> = Atom.Writable<State, Event>;
13
+ /** A reactive ActorSystem lookup for one typed actor identity. */
14
+ type ActorLookupAtom<State extends {
15
+ readonly _tag: string;
16
+ }, Event, Output> = Atom.Atom<AsyncResult.AsyncResult<Option.Option<ActorRef<State, Event, Output>>, Cause.NoSuchElementError>>;
17
+ /** A Suspense-ready actor acquisition that follows later actor generations. */
18
+ type ActorAcquireAtom<State extends {
19
+ readonly _tag: string;
20
+ }, Event, Output> = Atom.Atom<AsyncResult.AsyncResult<ActorRef<State, Event, Output>, Cause.NoSuchElementError>>;
21
+ /** Observe the current ActorRef for one ActorSystem key. */
22
+ declare const fromSystem: {
23
+ <State extends {
24
+ readonly _tag: string;
25
+ }, Event, Output>(key: ActorSystemKey<State, Event, Output>): (system: ActorSystemService) => ActorLookupAtom<State, Event, Output>;
26
+ <State extends {
27
+ readonly _tag: string;
28
+ }, Event, Output>(system: ActorSystemService, key: ActorSystemKey<State, Event, Output>): ActorLookupAtom<State, Event, Output>;
29
+ };
30
+ /** Suspend while an ActorSystem key is absent and follow later generations. */
31
+ declare const acquire: {
32
+ <State extends {
33
+ readonly _tag: string;
34
+ }, Event, Output>(key: ActorSystemKey<State, Event, Output>): (system: ActorSystemService) => ActorAcquireAtom<State, Event, Output>;
35
+ <State extends {
36
+ readonly _tag: string;
37
+ }, Event, Output>(system: ActorSystemService, key: ActorSystemKey<State, Event, Output>): ActorAcquireAtom<State, Event, Output>;
38
+ };
11
39
  /**
12
40
  * Make a writable Atom from an actor.
13
41
  *
@@ -53,4 +81,4 @@ declare const can: {
53
81
  }, Event, Output>(actor: ActorRef<State, Event, Output>, event: Event): CanAtom;
54
82
  };
55
83
  //#endregion
56
- export { ActorAtom, CanAtom, can, latestTransition, lifecycle, make, select };
84
+ export { ActorAcquireAtom, ActorAtom, ActorLookupAtom, CanAtom, acquire, can, fromSystem, latestTransition, lifecycle, make, select };
package/dist/atom.js CHANGED
@@ -1,4 +1,6 @@
1
+ import { Match } from "effect";
1
2
  import { dual } from "effect/Function";
3
+ import * as Option$1 from "effect/Option";
2
4
  import * as Atom from "effect/unstable/reactivity/Atom";
3
5
  import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
4
6
  //#region src/atom.ts
@@ -8,6 +10,17 @@ import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
8
10
  * The adapter keeps the actor as the state owner. Atom registries observe the
9
11
  * actor's SubscriptionRef and write events through its synchronous boundary.
10
12
  */
13
+ /** Observe the current ActorRef for one ActorSystem key. */
14
+ const fromSystem = dual(2, (system, key) => Atom.make(system.watch(key), { initialValue: Option$1.none() }));
15
+ /** Suspend while an ActorSystem key is absent and follow later generations. */
16
+ const acquire = dual(2, (system, key) => Atom.map(fromSystem(system, key), (result) => Match.value(result).pipe(Match.tagsExhaustive({
17
+ Initial: (initial) => AsyncResult.initial(initial.waiting),
18
+ Failure: (failure) => AsyncResult.failure(failure.cause, { waiting: failure.waiting }),
19
+ Success: (success) => Option$1.match(success.value, {
20
+ onNone: () => AsyncResult.initial(true),
21
+ onSome: (actor) => AsyncResult.success(actor, success)
22
+ })
23
+ }))));
11
24
  /**
12
25
  * Make a writable Atom from an actor.
13
26
  *
@@ -44,4 +57,4 @@ const can = dual(2, (actor, event) => {
44
57
  }).pipe(Atom.withEquality((value, next) => AsyncResult.isSuccess(value) && AsyncResult.isSuccess(next) && Object.is(value.value, next.value)));
45
58
  });
46
59
  //#endregion
47
- export { can, latestTransition, lifecycle, make, select };
60
+ export { acquire, can, fromSystem, latestTransition, lifecycle, make, select };
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaEr
4
4
  import { ActorExit, DefectPhase, Supervision } from "./supervision.js";
5
5
  import { Durability, DurabilityCommit, FinalContext, GuardPredicate, HandlerContext, InputMakeConfig, Lifecycle, Machine, MachineRef, MakeConfig, Recovery, RecoveryContext, ReplayOptions, SpawnOptions, StateHandlerContext, TaskOptions, TimeoutConfig, machine_d_exports } from "./machine.js";
6
6
  import { ProcessEventResult } from "./internal/transition.js";
7
- import { ActorClient, ActorLifecycle, ActorRef, ActorRefSync, ActorScope, ActorSystem, ActorSystemService, Default, SystemEvent, SystemEventListener, SystemSpawnOptions, TransitionInfo } from "./actor.js";
7
+ import { ActorClient, ActorLifecycle, ActorRef, ActorRefSync, ActorScope, ActorSystem, ActorSystemKey, ActorSystemService, Default, SystemEvent, SystemEventListener, SystemSpawnOptions, TransitionInfo, actorSystemKey } from "./actor.js";
8
8
  import { InputTestHarnessOptions, SimulationOptions, SimulationResult, TestHarness, TestHarnessOptions, assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
9
9
  import { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, GuardEvent, InspectionEvent, Inspector, InspectorHandler, InspectorService, OperationEvent, SpawnEvent, StopEvent, TaskEvent, TracingInspectorOptions, TransitionEvent, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector } from "./inspection.js";
10
- export { type ActorClient, ActorExit, type ActorExit as ActorExitType, type ActorLifecycle, type ActorRef, type ActorRefSync, ActorScope, ActorStoppedError, type ActorSystemService as ActorSystem, Default as ActorSystemDefault, ActorSystem as ActorSystemService, type AnyInspectionEvent, AssertionError, type DefectPhase, type DeferReplyResult, DuplicateActorError, type Durability, type DurabilityCommit, type EffectEvent, type ErrorEvent, Event, type EventReceivedEvent, type FinalContext, type GuardEvent, type GuardPredicate, type HandlerContext, type InputMakeConfig, type InputTestHarnessOptions, type InspectionEvent, type InspectorService as Inspector, type InspectorHandler, Inspector as InspectorService, InvalidSchemaError, type Lifecycle, machine_d_exports as Machine, type MachineEventSchema, type MachineRef, type MachineStateSchema, type Machine as MachineType, type MakeConfig, MissingMatchHandlerError, NoReplyError, type OperationEvent, PersistenceError, type ProcessEventResult, type Recovery, type RecoveryContext, type ReplayOptions, type ReplyFields, type ReplyResult, type SimulationOptions, type SimulationResult, type SpawnEvent, type SpawnOptions, State, type StateHandlerContext, type StopEvent, Supervision, type SystemEvent, type SystemEventListener, type SystemSpawnOptions, type TaskEvent, type TaskOptions, type TestHarness, type TestHarnessOptions, type TimeoutConfig, type TracingInspectorOptions, type TransitionEvent, type TransitionInfo, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createTestHarness, makeInspector, makeInspectorEffect, simulate, tracingInspector };
10
+ export { type ActorClient, ActorExit, type ActorExit as ActorExitType, type ActorLifecycle, type ActorRef, type ActorRefSync, ActorScope, ActorStoppedError, type ActorSystemService as ActorSystem, Default as ActorSystemDefault, ActorSystemKey, ActorSystem as ActorSystemService, type AnyInspectionEvent, AssertionError, type DefectPhase, type DeferReplyResult, DuplicateActorError, type Durability, type DurabilityCommit, type EffectEvent, type ErrorEvent, Event, type EventReceivedEvent, type FinalContext, type GuardEvent, type GuardPredicate, type HandlerContext, type InputMakeConfig, type InputTestHarnessOptions, type InspectionEvent, type InspectorService as Inspector, type InspectorHandler, Inspector as InspectorService, InvalidSchemaError, type Lifecycle, machine_d_exports as Machine, type MachineEventSchema, type MachineRef, type MachineStateSchema, type Machine as MachineType, type MakeConfig, MissingMatchHandlerError, NoReplyError, type OperationEvent, PersistenceError, type ProcessEventResult, type Recovery, type RecoveryContext, type ReplayOptions, type ReplyFields, type ReplyResult, type SimulationOptions, type SimulationResult, type SpawnEvent, type SpawnOptions, State, type StateHandlerContext, type StopEvent, Supervision, type SystemEvent, type SystemEventListener, type SystemSpawnOptions, type TaskEvent, type TaskOptions, type TestHarness, type TestHarnessOptions, type TimeoutConfig, type TracingInspectorOptions, type TransitionEvent, type TransitionInfo, VersionConflictError, actorSystemKey, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createTestHarness, makeInspector, makeInspectorEffect, simulate, tracingInspector };
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaEr
2
2
  import { Event, State } from "./schema.js";
3
3
  import { Inspector, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector } from "./inspection.js";
4
4
  import { ActorExit, Supervision } from "./supervision.js";
5
- import { ActorScope, ActorSystem, Default } from "./actor.js";
5
+ import { ActorScope, ActorSystem, ActorSystemKey, Default, actorSystemKey } from "./actor.js";
6
6
  import { machine_exports } from "./machine.js";
7
7
  import { assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
8
- export { ActorExit, ActorScope, ActorStoppedError, Default as ActorSystemDefault, ActorSystem as ActorSystemService, AssertionError, DuplicateActorError, Event, Inspector as InspectorService, InvalidSchemaError, machine_exports as Machine, MissingMatchHandlerError, NoReplyError, PersistenceError, State, Supervision, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createTestHarness, makeInspector, makeInspectorEffect, simulate, tracingInspector };
8
+ export { ActorExit, ActorScope, ActorStoppedError, Default as ActorSystemDefault, ActorSystemKey, ActorSystem as ActorSystemService, AssertionError, DuplicateActorError, Event, Inspector as InspectorService, InvalidSchemaError, machine_exports as Machine, MissingMatchHandlerError, NoReplyError, PersistenceError, State, Supervision, VersionConflictError, actorSystemKey, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createTestHarness, makeInspector, makeInspectorEffect, simulate, tracingInspector };
@@ -64,6 +64,7 @@ const isEffect = Effect.isEffect;
64
64
  const stubSystem = {
65
65
  spawn: () => Effect.die("spawn not supported in stub system"),
66
66
  get: () => Effect.die("get not supported in stub system"),
67
+ watch: () => Stream.die("watch not supported in stub system"),
67
68
  stop: () => Effect.die("stop not supported in stub system"),
68
69
  events: Stream.empty,
69
70
  get actors() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-machine",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/cevr/effect-machine.git"