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.
Files changed (73) hide show
  1. package/README.md +118 -55
  2. package/dist/actor.d.ts +77 -179
  3. package/dist/actor.js +161 -113
  4. package/dist/cluster/entity-machine.js +5 -3
  5. package/dist/errors.d.ts +12 -1
  6. package/dist/errors.js +8 -1
  7. package/dist/index.d.ts +4 -8
  8. package/dist/index.js +2 -7
  9. package/dist/internal/transition.d.ts +27 -3
  10. package/dist/internal/transition.js +38 -9
  11. package/dist/internal/utils.d.ts +7 -2
  12. package/dist/internal/utils.js +1 -5
  13. package/dist/machine.d.ts +94 -35
  14. package/dist/machine.js +128 -13
  15. package/dist/testing.js +57 -3
  16. package/package.json +10 -9
  17. package/v3/dist/actor.d.ts +210 -0
  18. package/{dist-v3 → v3/dist}/actor.js +198 -117
  19. package/{dist-v3 → v3/dist}/cluster/entity-machine.d.ts +1 -1
  20. package/{dist-v3 → v3/dist}/cluster/entity-machine.js +8 -6
  21. package/{dist-v3 → v3/dist}/cluster/to-entity.d.ts +1 -1
  22. package/{dist-v3 → v3/dist}/cluster/to-entity.js +1 -1
  23. package/v3/dist/errors.d.ts +76 -0
  24. package/{dist-v3 → v3/dist}/errors.js +9 -2
  25. package/v3/dist/index.d.ts +9 -0
  26. package/v3/dist/index.js +8 -0
  27. package/{dist-v3 → v3/dist}/inspection.d.ts +53 -8
  28. package/v3/dist/inspection.js +156 -0
  29. package/{dist-v3 → v3/dist}/internal/brands.d.ts +1 -1
  30. package/{dist-v3 → v3/dist}/internal/inspection.d.ts +1 -1
  31. package/v3/dist/internal/inspection.js +20 -0
  32. package/{dist-v3 → v3/dist}/internal/transition.d.ts +35 -11
  33. package/{dist-v3 → v3/dist}/internal/transition.js +47 -15
  34. package/{dist-v3 → v3/dist}/internal/utils.d.ts +9 -4
  35. package/{dist-v3 → v3/dist}/internal/utils.js +2 -6
  36. package/{dist-v3 → v3/dist}/machine.d.ts +113 -40
  37. package/{dist-v3 → v3/dist}/machine.js +191 -15
  38. package/{dist-v3 → v3/dist}/schema.d.ts +1 -1
  39. package/{dist-v3 → v3/dist}/schema.js +5 -2
  40. package/{dist-v3 → v3/dist}/slot.d.ts +4 -3
  41. package/{dist-v3 → v3/dist}/slot.js +1 -1
  42. package/{dist-v3 → v3/dist}/testing.d.ts +14 -8
  43. package/{dist-v3 → v3/dist}/testing.js +60 -6
  44. package/dist/persistence/adapter.d.ts +0 -135
  45. package/dist/persistence/adapter.js +0 -25
  46. package/dist/persistence/adapters/in-memory.d.ts +0 -32
  47. package/dist/persistence/adapters/in-memory.js +0 -174
  48. package/dist/persistence/index.d.ts +0 -5
  49. package/dist/persistence/index.js +0 -5
  50. package/dist/persistence/persistent-actor.d.ts +0 -50
  51. package/dist/persistence/persistent-actor.js +0 -368
  52. package/dist/persistence/persistent-machine.d.ts +0 -105
  53. package/dist/persistence/persistent-machine.js +0 -22
  54. package/dist-v3/actor.d.ts +0 -291
  55. package/dist-v3/errors.d.ts +0 -27
  56. package/dist-v3/index.d.ts +0 -12
  57. package/dist-v3/index.js +0 -13
  58. package/dist-v3/inspection.js +0 -48
  59. package/dist-v3/internal/inspection.js +0 -13
  60. package/dist-v3/persistence/adapter.d.ts +0 -125
  61. package/dist-v3/persistence/adapter.js +0 -25
  62. package/dist-v3/persistence/adapters/in-memory.d.ts +0 -32
  63. package/dist-v3/persistence/adapters/in-memory.js +0 -174
  64. package/dist-v3/persistence/index.d.ts +0 -5
  65. package/dist-v3/persistence/index.js +0 -5
  66. package/dist-v3/persistence/persistent-actor.d.ts +0 -49
  67. package/dist-v3/persistence/persistent-actor.js +0 -365
  68. package/dist-v3/persistence/persistent-machine.d.ts +0 -105
  69. package/dist-v3/persistence/persistent-machine.js +0 -22
  70. /package/{dist-v3 → v3/dist}/_virtual/_rolldown/runtime.js +0 -0
  71. /package/{dist-v3 → v3/dist}/cluster/index.d.ts +0 -0
  72. /package/{dist-v3 → v3/dist}/cluster/index.js +0 -0
  73. /package/{dist-v3 → v3/dist}/internal/brands.js +0 -0
@@ -1,9 +1,9 @@
1
1
  import { stubSystem } from "./internal/utils.js";
2
2
  import { AssertionError } from "./errors.js";
3
3
  import { BuiltMachine } from "./machine.js";
4
- import { executeTransition } from "./internal/transition.js";
4
+ import { executeTransition, shouldPostpone } from "./internal/transition.js";
5
5
  import { Effect, SubscriptionRef } from "effect";
6
- //#region src-v3/testing.ts
6
+ //#region src/testing.ts
7
7
  /**
8
8
  * Simulate a sequence of events through a machine without running an actor.
9
9
  * Useful for testing state transitions in isolation.
@@ -26,18 +26,44 @@ import { Effect, SubscriptionRef } from "effect";
26
26
  */
27
27
  const simulate = Effect.fn("effect-machine.simulate")(function* (input, events) {
28
28
  const machine = input instanceof BuiltMachine ? input._inner : input;
29
+ const dummySend = Effect.fn("effect-machine.testing.simulate.send")((_event) => Effect.void);
29
30
  const dummySelf = {
30
- send: Effect.fn("effect-machine.testing.simulate.send")((_event) => Effect.void),
31
+ send: dummySend,
32
+ cast: dummySend,
31
33
  spawn: () => Effect.die("spawn not supported in simulation")
32
34
  };
33
35
  let currentState = machine.initial;
34
36
  const states = [currentState];
37
+ const hasPostponeRules = machine.postponeRules.length > 0;
38
+ const postponed = [];
35
39
  for (const event of events) {
36
- const result = yield* executeTransition(machine, currentState, event, dummySelf, stubSystem);
40
+ if (hasPostponeRules && shouldPostpone(machine, currentState._tag, event._tag)) {
41
+ postponed.push(event);
42
+ continue;
43
+ }
44
+ const result = yield* executeTransition(machine, currentState, event, dummySelf, stubSystem, "simulation");
37
45
  if (!result.transitioned) continue;
46
+ const prevTag = currentState._tag;
38
47
  currentState = result.newState;
39
48
  states.push(currentState);
40
49
  if (machine.finalStates.has(currentState._tag)) break;
50
+ let drainTag = prevTag;
51
+ while (currentState._tag !== drainTag && postponed.length > 0) {
52
+ drainTag = currentState._tag;
53
+ const drained = postponed.splice(0);
54
+ for (const postponedEvent of drained) {
55
+ if (shouldPostpone(machine, currentState._tag, postponedEvent._tag)) {
56
+ postponed.push(postponedEvent);
57
+ continue;
58
+ }
59
+ const drainResult = yield* executeTransition(machine, currentState, postponedEvent, dummySelf, stubSystem, "simulation");
60
+ if (drainResult.transitioned) {
61
+ currentState = drainResult.newState;
62
+ states.push(currentState);
63
+ if (machine.finalStates.has(currentState._tag)) break;
64
+ }
65
+ }
66
+ }
41
67
  }
42
68
  return {
43
69
  states,
@@ -113,20 +139,48 @@ const assertNeverReaches = Effect.fn("effect-machine.assertNeverReaches")(functi
113
139
  */
114
140
  const createTestHarness = Effect.fn("effect-machine.createTestHarness")(function* (input, options) {
115
141
  const machine = input instanceof BuiltMachine ? input._inner : input;
142
+ const dummySend = Effect.fn("effect-machine.testing.harness.send")((_event) => Effect.void);
116
143
  const dummySelf = {
117
- send: Effect.fn("effect-machine.testing.harness.send")((_event) => Effect.void),
144
+ send: dummySend,
145
+ cast: dummySend,
118
146
  spawn: () => Effect.die("spawn not supported in test harness")
119
147
  };
120
148
  const stateRef = yield* SubscriptionRef.make(machine.initial);
149
+ const hasPostponeRules = machine.postponeRules.length > 0;
150
+ const postponed = [];
121
151
  return {
122
152
  state: stateRef,
123
153
  send: Effect.fn("effect-machine.testHarness.send")(function* (event) {
124
154
  const currentState = yield* SubscriptionRef.get(stateRef);
125
- const result = yield* executeTransition(machine, currentState, event, dummySelf, stubSystem);
155
+ if (hasPostponeRules && shouldPostpone(machine, currentState._tag, event._tag)) {
156
+ postponed.push(event);
157
+ return currentState;
158
+ }
159
+ const result = yield* executeTransition(machine, currentState, event, dummySelf, stubSystem, "test-harness");
126
160
  if (!result.transitioned) return currentState;
161
+ const prevTag = currentState._tag;
127
162
  const newState = result.newState;
128
163
  yield* SubscriptionRef.set(stateRef, newState);
129
164
  if (options?.onTransition !== void 0) options.onTransition(currentState, event, newState);
165
+ let drainTag = prevTag;
166
+ let currentTag = newState._tag;
167
+ while (currentTag !== drainTag && postponed.length > 0) {
168
+ drainTag = currentTag;
169
+ const drained = postponed.splice(0);
170
+ for (const postponedEvent of drained) {
171
+ const state = yield* SubscriptionRef.get(stateRef);
172
+ if (shouldPostpone(machine, state._tag, postponedEvent._tag)) {
173
+ postponed.push(postponedEvent);
174
+ continue;
175
+ }
176
+ const drainResult = yield* executeTransition(machine, state, postponedEvent, dummySelf, stubSystem, "test-harness");
177
+ if (drainResult.transitioned) {
178
+ yield* SubscriptionRef.set(stateRef, drainResult.newState);
179
+ currentTag = drainResult.newState._tag;
180
+ if (options?.onTransition !== void 0) options.onTransition(state, postponedEvent, drainResult.newState);
181
+ }
182
+ }
183
+ }
130
184
  return newState;
131
185
  }),
132
186
  getState: SubscriptionRef.get(stateRef)
@@ -1,135 +0,0 @@
1
- import { DuplicateActorError } from "../errors.js";
2
- import { PersistentActorRef } from "./persistent-actor.js";
3
- import { Effect, Option, Schema, ServiceMap } from "effect";
4
- import * as effect_Cause0 from "effect/Cause";
5
-
6
- //#region src/persistence/adapter.d.ts
7
- /**
8
- * Metadata for a persisted actor.
9
- * Used for discovery and filtering during bulk restore.
10
- */
11
- interface ActorMetadata {
12
- readonly id: string;
13
- /** User-provided identifier for the machine type */
14
- readonly machineType: string;
15
- readonly createdAt: number;
16
- readonly lastActivityAt: number;
17
- readonly version: number;
18
- /** Current state _tag value */
19
- readonly stateTag: string;
20
- }
21
- /**
22
- * Result of a bulk restore operation.
23
- * Contains both successfully restored actors and failures.
24
- */
25
- interface RestoreResult<S extends {
26
- readonly _tag: string;
27
- }, E extends {
28
- readonly _tag: string;
29
- }, R = never> {
30
- readonly restored: ReadonlyArray<PersistentActorRef<S, E, R>>;
31
- readonly failed: ReadonlyArray<RestoreFailure>;
32
- }
33
- /**
34
- * A single restore failure with actor ID and error details.
35
- */
36
- interface RestoreFailure {
37
- readonly id: string;
38
- readonly error: PersistenceError | DuplicateActorError;
39
- }
40
- /**
41
- * Snapshot of actor state at a point in time
42
- */
43
- interface Snapshot<S> {
44
- readonly state: S;
45
- readonly version: number;
46
- readonly timestamp: number;
47
- }
48
- /**
49
- * Persisted event with metadata
50
- */
51
- interface PersistedEvent<E> {
52
- readonly event: E;
53
- readonly version: number;
54
- readonly timestamp: number;
55
- }
56
- /**
57
- * Adapter for persisting actor state and events.
58
- *
59
- * Implementations handle serialization and storage of snapshots and event journals.
60
- * Schema parameters ensure type-safe serialization/deserialization.
61
- * Schemas must have no context requirements (use Schema<S, SI, never>).
62
- */
63
- interface PersistenceAdapter {
64
- /**
65
- * Save a snapshot of actor state.
66
- * Implementations should use optimistic locking — fail if version mismatch.
67
- */
68
- readonly saveSnapshot: <S>(id: string, snapshot: Snapshot<S>, schema: Schema.Codec<S, unknown, never, never>) => Effect.Effect<void, PersistenceError | VersionConflictError>;
69
- /**
70
- * Load the latest snapshot for an actor.
71
- * Returns None if no snapshot exists.
72
- */
73
- readonly loadSnapshot: <S>(id: string, schema: Schema.Codec<S, unknown, never, never>) => Effect.Effect<Option.Option<Snapshot<S>>, PersistenceError>;
74
- /**
75
- * Append an event to the actor's event journal.
76
- */
77
- readonly appendEvent: <E>(id: string, event: PersistedEvent<E>, schema: Schema.Codec<E, unknown, never, never>) => Effect.Effect<void, PersistenceError>;
78
- /**
79
- * Load events from the journal, optionally after a specific version.
80
- */
81
- readonly loadEvents: <E>(id: string, schema: Schema.Codec<E, unknown, never, never>, afterVersion?: number) => Effect.Effect<ReadonlyArray<PersistedEvent<E>>, PersistenceError>;
82
- /**
83
- * Delete all persisted data for an actor (snapshot + events).
84
- */
85
- readonly deleteActor: (id: string) => Effect.Effect<void, PersistenceError>;
86
- /**
87
- * List all persisted actor metadata.
88
- * Optional — adapters without registry support can omit this.
89
- */
90
- readonly listActors?: () => Effect.Effect<ReadonlyArray<ActorMetadata>, PersistenceError>;
91
- /**
92
- * Save or update actor metadata.
93
- * Called on spawn and state transitions.
94
- * Optional — adapters without registry support can omit this.
95
- */
96
- readonly saveMetadata?: (metadata: ActorMetadata) => Effect.Effect<void, PersistenceError>;
97
- /**
98
- * Delete actor metadata.
99
- * Called when actor is deleted.
100
- * Optional — adapters without registry support can omit this.
101
- */
102
- readonly deleteMetadata?: (id: string) => Effect.Effect<void, PersistenceError>;
103
- /**
104
- * Load metadata for a specific actor by ID.
105
- * Returns None if no metadata exists.
106
- * Optional — adapters without registry support can omit this.
107
- */
108
- readonly loadMetadata?: (id: string) => Effect.Effect<Option.Option<ActorMetadata>, PersistenceError>;
109
- }
110
- declare const PersistenceError_base: Schema.ErrorClass<PersistenceError, Schema.TaggedStruct<"PersistenceError", {
111
- readonly operation: Schema.String;
112
- readonly actorId: Schema.String;
113
- readonly cause: Schema.optional<Schema.Unknown>;
114
- readonly message: Schema.optional<Schema.String>;
115
- }>, effect_Cause0.YieldableError>;
116
- /**
117
- * Error type for persistence operations
118
- */
119
- declare class PersistenceError extends PersistenceError_base {}
120
- declare const VersionConflictError_base: Schema.ErrorClass<VersionConflictError, Schema.TaggedStruct<"VersionConflictError", {
121
- readonly actorId: Schema.String;
122
- readonly expectedVersion: Schema.Number;
123
- readonly actualVersion: Schema.Number;
124
- }>, effect_Cause0.YieldableError>;
125
- /**
126
- * Version conflict error — snapshot version doesn't match expected
127
- */
128
- declare class VersionConflictError extends VersionConflictError_base {}
129
- declare const PersistenceAdapterTag_base: ServiceMap.ServiceClass<PersistenceAdapterTag, "effect-machine/src/persistence/adapter/PersistenceAdapterTag", PersistenceAdapter>;
130
- /**
131
- * PersistenceAdapter service tag
132
- */
133
- declare class PersistenceAdapterTag extends PersistenceAdapterTag_base {}
134
- //#endregion
135
- export { ActorMetadata, PersistedEvent, PersistenceAdapter, PersistenceAdapterTag, PersistenceError, RestoreFailure, RestoreResult, Snapshot, VersionConflictError };
@@ -1,25 +0,0 @@
1
- import { Schema, ServiceMap } from "effect";
2
- //#region src/persistence/adapter.ts
3
- /**
4
- * Error type for persistence operations
5
- */
6
- var PersistenceError = class extends Schema.TaggedErrorClass()("PersistenceError", {
7
- operation: Schema.String,
8
- actorId: Schema.String,
9
- cause: Schema.optional(Schema.Unknown),
10
- message: Schema.optional(Schema.String)
11
- }) {};
12
- /**
13
- * Version conflict error — snapshot version doesn't match expected
14
- */
15
- var VersionConflictError = class extends Schema.TaggedErrorClass()("VersionConflictError", {
16
- actorId: Schema.String,
17
- expectedVersion: Schema.Number,
18
- actualVersion: Schema.Number
19
- }) {};
20
- /**
21
- * PersistenceAdapter service tag
22
- */
23
- var PersistenceAdapterTag = class extends ServiceMap.Service()("effect-machine/src/persistence/adapter/PersistenceAdapterTag") {};
24
- //#endregion
25
- export { PersistenceAdapterTag, PersistenceError, VersionConflictError };
@@ -1,32 +0,0 @@
1
- import { PersistenceAdapter, PersistenceAdapterTag } from "../adapter.js";
2
- import { Effect, Layer } from "effect";
3
-
4
- //#region src/persistence/adapters/in-memory.d.ts
5
- /**
6
- * Create an in-memory persistence adapter effect.
7
- * Returns the adapter directly for custom layer composition.
8
- */
9
- declare const makeInMemoryPersistenceAdapter: Effect.Effect<PersistenceAdapter, never, never>;
10
- /**
11
- * In-memory persistence adapter layer.
12
- * Data is not persisted across process restarts.
13
- *
14
- * NOTE: Each `Effect.provide(InMemoryPersistenceAdapter)` creates a NEW adapter
15
- * with empty storage. For tests that need persistent storage across multiple
16
- * runPromise calls, use `makeInMemoryPersistenceAdapter` with a shared scope.
17
- *
18
- * @example
19
- * ```ts
20
- * const program = Effect.gen(function* () {
21
- * const system = yield* ActorSystemService;
22
- * const actor = yield* system.spawn("my-actor", persistentMachine);
23
- * // ...
24
- * }).pipe(
25
- * Effect.provide(InMemoryPersistenceAdapter),
26
- * Effect.provide(ActorSystemDefault),
27
- * );
28
- * ```
29
- */
30
- declare const InMemoryPersistenceAdapter: Layer.Layer<PersistenceAdapterTag>;
31
- //#endregion
32
- export { InMemoryPersistenceAdapter, makeInMemoryPersistenceAdapter };
@@ -1,174 +0,0 @@
1
- import { PersistenceAdapterTag, PersistenceError, VersionConflictError } from "../adapter.js";
2
- import { Effect, Layer, Option, Ref, Schema } from "effect";
3
- //#region src/persistence/adapters/in-memory.ts
4
- /**
5
- * Create an in-memory persistence adapter.
6
- * Useful for testing and development.
7
- */
8
- const make = Effect.gen(function* () {
9
- const storage = yield* Ref.make(/* @__PURE__ */ new Map());
10
- const registry = yield* Ref.make(/* @__PURE__ */ new Map());
11
- const getOrCreateStorage = Effect.fn("effect-machine.persistence.inMemory.getOrCreateStorage")(function* (id) {
12
- return yield* Ref.modify(storage, (map) => {
13
- const existing = map.get(id);
14
- if (existing !== void 0) return [existing, map];
15
- const newStorage = {
16
- snapshot: Option.none(),
17
- events: []
18
- };
19
- const newMap = new Map(map);
20
- newMap.set(id, newStorage);
21
- return [newStorage, newMap];
22
- });
23
- });
24
- const updateStorage = Effect.fn("effect-machine.persistence.inMemory.updateStorage")(function* (id, update) {
25
- yield* Ref.update(storage, (map) => {
26
- const existing = map.get(id);
27
- if (existing === void 0) return map;
28
- const newMap = new Map(map);
29
- newMap.set(id, update(existing));
30
- return newMap;
31
- });
32
- });
33
- return {
34
- saveSnapshot: Effect.fn("effect-machine.persistence.inMemory.saveSnapshot")(function* (id, snapshot, schema) {
35
- const actorStorage = yield* getOrCreateStorage(id);
36
- if (Option.isSome(actorStorage.snapshot)) {
37
- const existingVersion = actorStorage.snapshot.value.version;
38
- if (snapshot.version < existingVersion) return yield* new VersionConflictError({
39
- actorId: id,
40
- expectedVersion: existingVersion,
41
- actualVersion: snapshot.version
42
- });
43
- }
44
- const encoded = yield* Schema.encodeEffect(schema)(snapshot.state).pipe(Effect.mapError((cause) => new PersistenceError({
45
- operation: "saveSnapshot",
46
- actorId: id,
47
- cause,
48
- message: "Failed to encode state"
49
- })));
50
- yield* updateStorage(id, (s) => ({
51
- ...s,
52
- snapshot: Option.some({
53
- data: encoded,
54
- version: snapshot.version,
55
- timestamp: snapshot.timestamp
56
- })
57
- }));
58
- }),
59
- loadSnapshot: Effect.fn("effect-machine.persistence.inMemory.loadSnapshot")(function* (id, schema) {
60
- const actorStorage = yield* getOrCreateStorage(id);
61
- if (Option.isNone(actorStorage.snapshot)) return Option.none();
62
- const stored = actorStorage.snapshot.value;
63
- const decoded = yield* Schema.decodeEffect(schema)(stored.data).pipe(Effect.mapError((cause) => new PersistenceError({
64
- operation: "loadSnapshot",
65
- actorId: id,
66
- cause,
67
- message: "Failed to decode state"
68
- })));
69
- return Option.some({
70
- state: decoded,
71
- version: stored.version,
72
- timestamp: stored.timestamp
73
- });
74
- }),
75
- appendEvent: Effect.fn("effect-machine.persistence.inMemory.appendEvent")(function* (id, event, schema) {
76
- yield* getOrCreateStorage(id);
77
- const encoded = yield* Schema.encodeEffect(schema)(event.event).pipe(Effect.mapError((cause) => new PersistenceError({
78
- operation: "appendEvent",
79
- actorId: id,
80
- cause,
81
- message: "Failed to encode event"
82
- })));
83
- yield* updateStorage(id, (s) => ({
84
- ...s,
85
- events: [...s.events, {
86
- data: encoded,
87
- version: event.version,
88
- timestamp: event.timestamp
89
- }]
90
- }));
91
- }),
92
- loadEvents: Effect.fn("effect-machine.persistence.inMemory.loadEvents")(function* (id, schema, afterVersion) {
93
- const actorStorage = yield* getOrCreateStorage(id);
94
- const decoded = [];
95
- for (const stored of actorStorage.events) {
96
- if (afterVersion !== void 0 && stored.version <= afterVersion) continue;
97
- const event = yield* Schema.decodeEffect(schema)(stored.data).pipe(Effect.mapError((cause) => new PersistenceError({
98
- operation: "loadEvents",
99
- actorId: id,
100
- cause,
101
- message: "Failed to decode event"
102
- })));
103
- decoded.push({
104
- event,
105
- version: stored.version,
106
- timestamp: stored.timestamp
107
- });
108
- }
109
- return decoded;
110
- }),
111
- deleteActor: Effect.fn("effect-machine.persistence.inMemory.deleteActor")(function* (id) {
112
- yield* Ref.update(storage, (map) => {
113
- const newMap = new Map(map);
114
- newMap.delete(id);
115
- return newMap;
116
- });
117
- yield* Ref.update(registry, (map) => {
118
- const newMap = new Map(map);
119
- newMap.delete(id);
120
- return newMap;
121
- });
122
- }),
123
- listActors: Effect.fn("effect-machine.persistence.inMemory.listActors")(function* () {
124
- const map = yield* Ref.get(registry);
125
- return Array.from(map.values());
126
- }),
127
- saveMetadata: Effect.fn("effect-machine.persistence.inMemory.saveMetadata")(function* (metadata) {
128
- yield* Ref.update(registry, (map) => {
129
- const newMap = new Map(map);
130
- newMap.set(metadata.id, metadata);
131
- return newMap;
132
- });
133
- }),
134
- deleteMetadata: Effect.fn("effect-machine.persistence.inMemory.deleteMetadata")(function* (id) {
135
- yield* Ref.update(registry, (map) => {
136
- const newMap = new Map(map);
137
- newMap.delete(id);
138
- return newMap;
139
- });
140
- }),
141
- loadMetadata: Effect.fn("effect-machine.persistence.inMemory.loadMetadata")(function* (id) {
142
- const meta = (yield* Ref.get(registry)).get(id);
143
- return meta !== void 0 ? Option.some(meta) : Option.none();
144
- })
145
- };
146
- }).pipe(Effect.withSpan("effect-machine.persistence.inMemory.make"));
147
- /**
148
- * Create an in-memory persistence adapter effect.
149
- * Returns the adapter directly for custom layer composition.
150
- */
151
- const makeInMemoryPersistenceAdapter = make;
152
- /**
153
- * In-memory persistence adapter layer.
154
- * Data is not persisted across process restarts.
155
- *
156
- * NOTE: Each `Effect.provide(InMemoryPersistenceAdapter)` creates a NEW adapter
157
- * with empty storage. For tests that need persistent storage across multiple
158
- * runPromise calls, use `makeInMemoryPersistenceAdapter` with a shared scope.
159
- *
160
- * @example
161
- * ```ts
162
- * const program = Effect.gen(function* () {
163
- * const system = yield* ActorSystemService;
164
- * const actor = yield* system.spawn("my-actor", persistentMachine);
165
- * // ...
166
- * }).pipe(
167
- * Effect.provide(InMemoryPersistenceAdapter),
168
- * Effect.provide(ActorSystemDefault),
169
- * );
170
- * ```
171
- */
172
- const InMemoryPersistenceAdapter = Layer.effect(PersistenceAdapterTag, make);
173
- //#endregion
174
- export { InMemoryPersistenceAdapter, makeInMemoryPersistenceAdapter };
@@ -1,5 +0,0 @@
1
- import { PersistenceConfig, PersistentMachine, isPersistentMachine, persist } from "./persistent-machine.js";
2
- import { PersistentActorRef, createPersistentActor, restorePersistentActor } from "./persistent-actor.js";
3
- import { ActorMetadata, PersistedEvent, PersistenceAdapter, PersistenceAdapterTag, PersistenceError, RestoreFailure, RestoreResult, Snapshot, VersionConflictError } from "./adapter.js";
4
- import { InMemoryPersistenceAdapter, makeInMemoryPersistenceAdapter } from "./adapters/in-memory.js";
5
- export { type ActorMetadata, InMemoryPersistenceAdapter, type PersistedEvent, type PersistenceAdapter, PersistenceAdapterTag, type PersistenceConfig, PersistenceError, type PersistentActorRef, type PersistentMachine, type RestoreFailure, type RestoreResult, type Snapshot, VersionConflictError, createPersistentActor, isPersistentMachine, makeInMemoryPersistenceAdapter, persist, restorePersistentActor };
@@ -1,5 +0,0 @@
1
- import { isPersistentMachine, persist } from "./persistent-machine.js";
2
- import { PersistenceAdapterTag, PersistenceError, VersionConflictError } from "./adapter.js";
3
- import { createPersistentActor, restorePersistentActor } from "./persistent-actor.js";
4
- import { InMemoryPersistenceAdapter, makeInMemoryPersistenceAdapter } from "./adapters/in-memory.js";
5
- export { InMemoryPersistenceAdapter, PersistenceAdapterTag, PersistenceError, VersionConflictError, createPersistentActor, isPersistentMachine, makeInMemoryPersistenceAdapter, persist, restorePersistentActor };
@@ -1,50 +0,0 @@
1
- import { EffectsDef, GuardsDef, MachineContext } from "../slot.js";
2
- import { PersistentMachine } from "./persistent-machine.js";
3
- import { PersistedEvent, PersistenceAdapterTag, PersistenceError, Snapshot, VersionConflictError } from "./adapter.js";
4
- import { MachineRef } from "../machine.js";
5
- import { ActorRef } from "../actor.js";
6
- import { Effect, Option, Scope } from "effect";
7
-
8
- //#region src/persistence/persistent-actor.d.ts
9
- /**
10
- * Extended ActorRef with persistence capabilities
11
- */
12
- interface PersistentActorRef<S extends {
13
- readonly _tag: string;
14
- }, E extends {
15
- readonly _tag: string;
16
- }, R = never> extends ActorRef<S, E> {
17
- /**
18
- * Force an immediate snapshot save
19
- */
20
- readonly persist: Effect.Effect<void, PersistenceError | VersionConflictError>;
21
- /**
22
- * Get the current persistence version
23
- */
24
- readonly version: Effect.Effect<number>;
25
- /**
26
- * Replay events to restore actor to a specific version.
27
- * Note: This only computes state; does not re-run transition effects.
28
- */
29
- readonly replayTo: (version: number) => Effect.Effect<void, PersistenceError, R>;
30
- }
31
- /**
32
- * Create a persistent actor from a PersistentMachine.
33
- * Restores from existing snapshot if available, otherwise starts fresh.
34
- */
35
- declare const createPersistentActor: <S extends {
36
- readonly _tag: string;
37
- }, E extends {
38
- readonly _tag: string;
39
- }, R, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>>(id: string, persistentMachine: PersistentMachine<S, E, R>, initialSnapshot: Option.Option<Snapshot<S>>, initialEvents: readonly PersistedEvent<E>[]) => Effect.Effect<PersistentActorRef<S, E, R>, PersistenceError, PersistenceAdapterTag | Exclude<R, MachineContext<S, E, MachineRef<E>>> | Exclude<Exclude<R, MachineContext<S, E, MachineRef<E>>>, Scope.Scope>>;
40
- /**
41
- * Restore an actor from persistence.
42
- * Returns None if no persisted state exists.
43
- */
44
- declare const restorePersistentActor: <S extends {
45
- readonly _tag: string;
46
- }, E extends {
47
- readonly _tag: string;
48
- }, R>(id: string, persistentMachine: PersistentMachine<S, E, R>) => Effect.Effect<Option.None<PersistentActorRef<S, E, R>> | Option.Some<PersistentActorRef<S, E, R>>, PersistenceError, PersistenceAdapterTag | Exclude<R, MachineContext<S, E, MachineRef<E>>> | Exclude<Exclude<R, MachineContext<S, E, MachineRef<E>>>, Scope.Scope>>;
49
- //#endregion
50
- export { PersistentActorRef, createPersistentActor, restorePersistentActor };