effect-machine 0.10.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 +65 -62
- package/dist/actor.d.ts +26 -94
- package/dist/actor.js +38 -95
- package/dist/index.d.ts +3 -7
- package/dist/index.js +1 -6
- package/dist/internal/transition.d.ts +1 -1
- package/dist/internal/transition.js +1 -1
- package/dist/internal/utils.js +1 -5
- package/dist/machine.d.ts +31 -35
- package/dist/machine.js +63 -13
- package/package.json +2 -2
- package/v3/dist/actor.d.ts +25 -93
- package/v3/dist/actor.js +37 -94
- package/v3/dist/index.d.ts +3 -7
- package/v3/dist/index.js +1 -6
- package/v3/dist/internal/utils.js +1 -5
- package/v3/dist/machine.d.ts +31 -35
- package/v3/dist/machine.js +63 -13
- 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 -404
- package/dist/persistence/persistent-machine.d.ts +0 -105
- package/dist/persistence/persistent-machine.js +0 -22
- package/v3/dist/persistence/adapter.d.ts +0 -138
- package/v3/dist/persistence/adapter.js +0 -25
- package/v3/dist/persistence/adapters/in-memory.d.ts +0 -32
- package/v3/dist/persistence/adapters/in-memory.js +0 -174
- package/v3/dist/persistence/index.d.ts +0 -5
- package/v3/dist/persistence/index.js +0 -5
- package/v3/dist/persistence/persistent-actor.d.ts +0 -50
- package/v3/dist/persistence/persistent-actor.js +0 -404
- package/v3/dist/persistence/persistent-machine.d.ts +0 -105
- package/v3/dist/persistence/persistent-machine.js +0 -22
package/v3/dist/actor.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import { Inspector } from "./inspection.js";
|
|
2
2
|
import { INTERNAL_INIT_EVENT } from "./internal/utils.js";
|
|
3
3
|
import { ActorStoppedError, DuplicateActorError, NoReplyError } from "./errors.js";
|
|
4
|
-
import { isPersistentMachine } from "./persistence/persistent-machine.js";
|
|
5
4
|
import { emitWithTimestamp } from "./internal/inspection.js";
|
|
6
5
|
import { processEventCore, resolveTransition, runSpawnEffects, shouldPostpone } from "./internal/transition.js";
|
|
7
|
-
import { PersistenceAdapterTag, PersistenceError } from "./persistence/adapter.js";
|
|
8
|
-
import { createPersistentActor, restorePersistentActor } from "./persistence/persistent-actor.js";
|
|
9
6
|
import { Cause, Context, Deferred, Effect, Exit, Fiber, Layer, MutableHashMap, Option, PubSub, Queue, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect";
|
|
10
7
|
//#region src/actor.ts
|
|
11
8
|
/**
|
|
@@ -31,7 +28,7 @@ const notifyListeners = (listeners, state) => {
|
|
|
31
28
|
/**
|
|
32
29
|
* Build core ActorRef methods shared between regular and persistent actors.
|
|
33
30
|
*/
|
|
34
|
-
const buildActorRefCore = (id, machine, stateRef, eventQueue, stoppedRef, listeners, stop, system, childrenMap, pendingReplies) => {
|
|
31
|
+
const buildActorRefCore = (id, machine, stateRef, eventQueue, stoppedRef, listeners, stop, system, childrenMap, pendingReplies, transitionsPubSub) => {
|
|
35
32
|
const send = Effect.fn("effect-machine.actor.send")(function* (event) {
|
|
36
33
|
if (yield* Ref.get(stoppedRef)) return;
|
|
37
34
|
yield* Queue.offer(eventQueue, {
|
|
@@ -121,6 +118,7 @@ const buildActorRefCore = (id, machine, stateRef, eventQueue, stoppedRef, listen
|
|
|
121
118
|
matches,
|
|
122
119
|
can,
|
|
123
120
|
changes: stateRef.changes,
|
|
121
|
+
transitions: transitionsPubSub !== void 0 ? Stream.fromPubSub(transitionsPubSub) : Stream.empty,
|
|
124
122
|
waitFor,
|
|
125
123
|
awaitFinal,
|
|
126
124
|
sendAndWait,
|
|
@@ -151,7 +149,8 @@ const buildActorRefCore = (id, machine, stateRef, eventQueue, stoppedRef, listen
|
|
|
151
149
|
/**
|
|
152
150
|
* Create and start an actor for a machine
|
|
153
151
|
*/
|
|
154
|
-
const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machine) {
|
|
152
|
+
const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machine, options) {
|
|
153
|
+
const initial = options?.initialState ?? machine.initial;
|
|
155
154
|
yield* Effect.annotateCurrentSpan("effect_machine.actor.id", id);
|
|
156
155
|
const existingSystem = yield* Effect.serviceOption(ActorSystem);
|
|
157
156
|
let system;
|
|
@@ -186,20 +185,20 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
186
185
|
return child;
|
|
187
186
|
})
|
|
188
187
|
};
|
|
189
|
-
yield* Effect.annotateCurrentSpan("effect_machine.actor.initial_state",
|
|
188
|
+
yield* Effect.annotateCurrentSpan("effect_machine.actor.initial_state", initial._tag);
|
|
190
189
|
yield* emitWithTimestamp(inspectorValue, (timestamp) => ({
|
|
191
190
|
type: "@machine.spawn",
|
|
192
191
|
actorId: id,
|
|
193
|
-
initialState:
|
|
192
|
+
initialState: initial,
|
|
194
193
|
timestamp
|
|
195
194
|
}));
|
|
196
|
-
const stateRef = yield* SubscriptionRef.make(
|
|
195
|
+
const stateRef = yield* SubscriptionRef.make(initial);
|
|
197
196
|
const listeners = /* @__PURE__ */ new Set();
|
|
198
197
|
const backgroundFibers = [];
|
|
199
198
|
const initEvent = { _tag: INTERNAL_INIT_EVENT };
|
|
200
199
|
const ctx = {
|
|
201
200
|
actorId: id,
|
|
202
|
-
state:
|
|
201
|
+
state: initial,
|
|
203
202
|
event: initEvent,
|
|
204
203
|
self,
|
|
205
204
|
system
|
|
@@ -208,7 +207,7 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
208
207
|
for (const bg of machine.backgroundEffects) {
|
|
209
208
|
const fiber = yield* Effect.forkDaemon(bg.handler({
|
|
210
209
|
actorId: id,
|
|
211
|
-
state:
|
|
210
|
+
state: initial,
|
|
212
211
|
event: initEvent,
|
|
213
212
|
self,
|
|
214
213
|
effects: effectSlots,
|
|
@@ -217,14 +216,14 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
217
216
|
backgroundFibers.push(fiber);
|
|
218
217
|
}
|
|
219
218
|
const stateScopeRef = { current: yield* Scope.make() };
|
|
220
|
-
yield* runSpawnEffectsWithInspection(machine,
|
|
221
|
-
if (machine.finalStates.has(
|
|
219
|
+
yield* runSpawnEffectsWithInspection(machine, initial, initEvent, self, stateScopeRef.current, id, inspectorValue, system);
|
|
220
|
+
if (machine.finalStates.has(initial._tag)) {
|
|
222
221
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
223
222
|
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
224
223
|
yield* emitWithTimestamp(inspectorValue, (timestamp) => ({
|
|
225
224
|
type: "@machine.stop",
|
|
226
225
|
actorId: id,
|
|
227
|
-
finalState:
|
|
226
|
+
finalState: initial,
|
|
228
227
|
timestamp
|
|
229
228
|
}));
|
|
230
229
|
yield* Ref.set(stoppedRef, true);
|
|
@@ -232,7 +231,8 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
232
231
|
return buildActorRefCore(id, machine, stateRef, eventQueue, stoppedRef, listeners, Ref.set(stoppedRef, true).pipe(Effect.withSpan("effect-machine.actor.stop"), Effect.asVoid), system, childrenMap, /* @__PURE__ */ new Set());
|
|
233
232
|
}
|
|
234
233
|
const pendingReplies = /* @__PURE__ */ new Set();
|
|
235
|
-
const
|
|
234
|
+
const transitionsPubSub = yield* PubSub.unbounded();
|
|
235
|
+
const loopFiber = yield* Effect.forkDaemon(eventLoop(machine, stateRef, eventQueue, stoppedRef, self, listeners, backgroundFibers, stateScopeRef, id, inspectorValue, system, pendingReplies, transitionsPubSub));
|
|
236
236
|
return buildActorRefCore(id, machine, stateRef, eventQueue, stoppedRef, listeners, Effect.gen(function* () {
|
|
237
237
|
const finalState = yield* SubscriptionRef.get(stateRef);
|
|
238
238
|
yield* emitWithTimestamp(inspectorValue, (timestamp) => ({
|
|
@@ -247,7 +247,7 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
247
247
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
248
248
|
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
249
249
|
if (implicitSystemScope !== void 0) yield* Scope.close(implicitSystemScope, Exit.void);
|
|
250
|
-
}).pipe(Effect.withSpan("effect-machine.actor.stop"), Effect.asVoid), system, childrenMap, pendingReplies);
|
|
250
|
+
}).pipe(Effect.withSpan("effect-machine.actor.stop"), Effect.asVoid), system, childrenMap, pendingReplies, transitionsPubSub);
|
|
251
251
|
});
|
|
252
252
|
/** Fail all pending call/ask Deferreds with ActorStoppedError. Safe to call multiple times. */
|
|
253
253
|
const settlePendingReplies = (pendingReplies, actorId) => Effect.sync(() => {
|
|
@@ -260,7 +260,7 @@ const settlePendingReplies = (pendingReplies, actorId) => Effect.sync(() => {
|
|
|
260
260
|
* Includes postpone buffer — events matching postpone rules are buffered
|
|
261
261
|
* and drained after state tag changes (gen_statem semantics).
|
|
262
262
|
*/
|
|
263
|
-
const eventLoop = Effect.fn("effect-machine.actor.eventLoop")(function* (machine, stateRef, eventQueue, stoppedRef, self, listeners, backgroundFibers, stateScopeRef, actorId, inspector, system, pendingReplies) {
|
|
263
|
+
const eventLoop = Effect.fn("effect-machine.actor.eventLoop")(function* (machine, stateRef, eventQueue, stoppedRef, self, listeners, backgroundFibers, stateScopeRef, actorId, inspector, system, pendingReplies, transitionsPubSub) {
|
|
264
264
|
const postponed = [];
|
|
265
265
|
const hasPostponeRules = machine.postponeRules.length > 0;
|
|
266
266
|
const processQueued = Effect.fn("effect-machine.actor.processQueued")(function* (queued) {
|
|
@@ -303,6 +303,11 @@ const eventLoop = Effect.fn("effect-machine.actor.eventLoop")(function* (machine
|
|
|
303
303
|
}));
|
|
304
304
|
break;
|
|
305
305
|
}
|
|
306
|
+
if (result.transitioned) yield* PubSub.publish(transitionsPubSub, {
|
|
307
|
+
fromState: result.previousState,
|
|
308
|
+
toState: result.newState,
|
|
309
|
+
event
|
|
310
|
+
});
|
|
306
311
|
return {
|
|
307
312
|
shouldStop,
|
|
308
313
|
stateChanged: result.lifecycleRan
|
|
@@ -318,15 +323,21 @@ const eventLoop = Effect.fn("effect-machine.actor.eventLoop")(function* (machine
|
|
|
318
323
|
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
319
324
|
return;
|
|
320
325
|
}
|
|
321
|
-
|
|
326
|
+
let drainTriggered = stateChanged;
|
|
327
|
+
while (drainTriggered && postponed.length > 0) {
|
|
328
|
+
drainTriggered = false;
|
|
322
329
|
const drained = postponed.splice(0);
|
|
323
|
-
for (const entry of drained)
|
|
324
|
-
yield*
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
+
for (const entry of drained) {
|
|
331
|
+
const drain = yield* processQueued(entry);
|
|
332
|
+
if (drain.shouldStop) {
|
|
333
|
+
yield* Ref.set(stoppedRef, true);
|
|
334
|
+
settlePostponedBuffer(postponed, pendingReplies, actorId);
|
|
335
|
+
yield* settlePendingReplies(pendingReplies, actorId);
|
|
336
|
+
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
337
|
+
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (drain.stateChanged) drainTriggered = true;
|
|
330
341
|
}
|
|
331
342
|
}
|
|
332
343
|
}
|
|
@@ -482,25 +493,7 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
|
|
|
482
493
|
if (MutableHashMap.has(actorsMap, id)) return yield* new DuplicateActorError({ actorId: id });
|
|
483
494
|
return yield* registerActor(id, yield* createActor(id, built._inner));
|
|
484
495
|
});
|
|
485
|
-
const
|
|
486
|
-
if (MutableHashMap.has(actorsMap, id)) return yield* new DuplicateActorError({ actorId: id });
|
|
487
|
-
const adapter = yield* PersistenceAdapterTag;
|
|
488
|
-
const maybeSnapshot = yield* adapter.loadSnapshot(id, persistentMachine.persistence.stateSchema);
|
|
489
|
-
return yield* registerActor(id, yield* createPersistentActor(id, persistentMachine, maybeSnapshot, yield* adapter.loadEvents(id, persistentMachine.persistence.eventSchema, Option.isSome(maybeSnapshot) ? maybeSnapshot.value.version : void 0)));
|
|
490
|
-
});
|
|
491
|
-
const spawnImpl = Effect.fn("effect-machine.actorSystem.spawn")(function* (id, machine) {
|
|
492
|
-
if (isPersistentMachine(machine)) return yield* spawnPersistent(id, machine);
|
|
493
|
-
return yield* spawnRegular(id, machine);
|
|
494
|
-
});
|
|
495
|
-
function spawn(id, machine) {
|
|
496
|
-
return withSpawnGate(spawnImpl(id, machine));
|
|
497
|
-
}
|
|
498
|
-
const restoreImpl = Effect.fn("effect-machine.actorSystem.restore")(function* (id, persistentMachine) {
|
|
499
|
-
const maybeActor = yield* restorePersistentActor(id, persistentMachine);
|
|
500
|
-
if (Option.isSome(maybeActor)) yield* registerActor(id, maybeActor.value);
|
|
501
|
-
return maybeActor;
|
|
502
|
-
});
|
|
503
|
-
const restore = (id, persistentMachine) => withSpawnGate(restoreImpl(id, persistentMachine));
|
|
496
|
+
const spawn = (id, machine) => withSpawnGate(spawnRegular(id, machine));
|
|
504
497
|
const get = Effect.fn("effect-machine.actorSystem.get")(function* (id) {
|
|
505
498
|
return yield* Effect.sync(() => MutableHashMap.get(actorsMap, id));
|
|
506
499
|
});
|
|
@@ -517,55 +510,8 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
|
|
|
517
510
|
yield* actor.stop;
|
|
518
511
|
return true;
|
|
519
512
|
});
|
|
520
|
-
const listPersisted = Effect.fn("effect-machine.actorSystem.listPersisted")(function* () {
|
|
521
|
-
const adapter = yield* PersistenceAdapterTag;
|
|
522
|
-
if (adapter.listActors === void 0) return [];
|
|
523
|
-
return yield* adapter.listActors();
|
|
524
|
-
});
|
|
525
|
-
const restoreMany = Effect.fn("effect-machine.actorSystem.restoreMany")(function* (ids, persistentMachine) {
|
|
526
|
-
const restored = [];
|
|
527
|
-
const failed = [];
|
|
528
|
-
for (const id of ids) {
|
|
529
|
-
if (MutableHashMap.has(actorsMap, id)) continue;
|
|
530
|
-
const result = yield* Effect.either(restore(id, persistentMachine));
|
|
531
|
-
if (result._tag === "Left") failed.push({
|
|
532
|
-
id,
|
|
533
|
-
error: result.left
|
|
534
|
-
});
|
|
535
|
-
else if (Option.isSome(result.right)) restored.push(result.right.value);
|
|
536
|
-
else failed.push({
|
|
537
|
-
id,
|
|
538
|
-
error: new PersistenceError({
|
|
539
|
-
operation: "restore",
|
|
540
|
-
actorId: id,
|
|
541
|
-
message: "No persisted state found"
|
|
542
|
-
})
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
return {
|
|
546
|
-
restored,
|
|
547
|
-
failed
|
|
548
|
-
};
|
|
549
|
-
});
|
|
550
|
-
const restoreAll = Effect.fn("effect-machine.actorSystem.restoreAll")(function* (persistentMachine, options) {
|
|
551
|
-
const adapter = yield* PersistenceAdapterTag;
|
|
552
|
-
if (adapter.listActors === void 0) return {
|
|
553
|
-
restored: [],
|
|
554
|
-
failed: []
|
|
555
|
-
};
|
|
556
|
-
const machineType = persistentMachine.persistence.machineType;
|
|
557
|
-
if (machineType === void 0) return yield* new PersistenceError({
|
|
558
|
-
operation: "restoreAll",
|
|
559
|
-
actorId: "*",
|
|
560
|
-
message: "restoreAll requires explicit machineType in persistence config"
|
|
561
|
-
});
|
|
562
|
-
let filtered = (yield* adapter.listActors()).filter((meta) => meta.machineType === machineType);
|
|
563
|
-
if (options?.filter !== void 0) filtered = filtered.filter(options.filter);
|
|
564
|
-
return yield* restoreMany(filtered.map((meta) => meta.id), persistentMachine);
|
|
565
|
-
});
|
|
566
513
|
return ActorSystem.of({
|
|
567
514
|
spawn,
|
|
568
|
-
restore,
|
|
569
515
|
get,
|
|
570
516
|
stop,
|
|
571
517
|
events: Stream.fromPubSub(eventPubSub),
|
|
@@ -581,10 +527,7 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
|
|
|
581
527
|
return () => {
|
|
582
528
|
eventListeners.delete(fn);
|
|
583
529
|
};
|
|
584
|
-
}
|
|
585
|
-
listPersisted,
|
|
586
|
-
restoreMany,
|
|
587
|
-
restoreAll
|
|
530
|
+
}
|
|
588
531
|
});
|
|
589
532
|
});
|
|
590
533
|
/**
|
package/v3/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { EffectHandlers, EffectSlot, EffectSlots, EffectsDef, EffectsSchema, GuardHandlers, GuardSlot, GuardSlots, GuardsDef, GuardsSchema, MachineContext, Slot } from "./slot.js";
|
|
2
2
|
import { Event, MachineEventSchema, MachineStateSchema, State } from "./schema.js";
|
|
3
|
-
import { PersistenceConfig, PersistentMachine, isPersistentMachine } from "./persistence/persistent-machine.js";
|
|
4
3
|
import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError } from "./errors.js";
|
|
5
4
|
import { ProcessEventResult } from "./internal/transition.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { InMemoryPersistenceAdapter, makeInMemoryPersistenceAdapter } from "./persistence/adapters/in-memory.js";
|
|
9
|
-
import { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig, PersistOptions, ProvideHandlers, SpawnEffect, StateHandlerContext, TaskOptions, Transition, machine_d_exports } from "./machine.js";
|
|
10
|
-
import { ActorRef, ActorRefSync, ActorSystem, Default, SystemEvent, SystemEventListener } from "./actor.js";
|
|
5
|
+
import { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig, ProvideHandlers, SpawnEffect, StateHandlerContext, TaskOptions, Transition, machine_d_exports } from "./machine.js";
|
|
6
|
+
import { ActorRef, ActorRefSync, ActorSystem, Default, SystemEvent, SystemEventListener, TransitionInfo } from "./actor.js";
|
|
11
7
|
import { SimulationResult, TestHarness, TestHarnessOptions, assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
|
|
12
8
|
import { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, InspectionEvent, Inspector, InspectorHandler, SpawnEvent, StopEvent, TaskEvent, TracingInspectorOptions, TransitionEvent, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector } from "./inspection.js";
|
|
13
|
-
export { type
|
|
9
|
+
export { type ActorRef, type ActorRefSync, ActorStoppedError, type ActorSystem, Default as ActorSystemDefault, ActorSystem as ActorSystemService, type AnyInspectionEvent, AssertionError, type BackgroundEffect, type BuiltMachine, DuplicateActorError, type EffectEvent, type EffectSlots, type EffectsDef, type EffectsSchema, type ErrorEvent, Event, type EventReceivedEvent, type GuardHandlers, type GuardSlot, type GuardSlots, type GuardsDef, type GuardsSchema, type HandlerContext, type InspectionEvent, type Inspector, type InspectorHandler, Inspector as InspectorService, InvalidSchemaError, machine_d_exports as Machine, type MachineContext, type MachineEventSchema, type MachineRef, type MachineStateSchema, type Machine as MachineType, type MakeConfig, MissingMatchHandlerError, MissingSchemaError, NoReplyError, type ProcessEventResult, type ProvideHandlers, ProvisionValidationError, type SimulationResult, Slot, type EffectHandlers as SlotEffectHandlers, type EffectSlot as SlotEffectSlot, SlotProvisionError, type SpawnEffect, type SpawnEvent, State, type StateHandlerContext, type StopEvent, type SystemEvent, type SystemEventListener, type TaskEvent, type TaskOptions, type TestHarness, type TestHarnessOptions, type TracingInspectorOptions, type Transition, type TransitionEvent, type TransitionInfo, UnprovidedSlotsError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createTestHarness, makeInspector, makeInspectorEffect, simulate, tracingInspector };
|
package/v3/dist/index.js
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import { Inspector, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector } from "./inspection.js";
|
|
2
2
|
import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError } from "./errors.js";
|
|
3
|
-
import { isPersistentMachine } from "./persistence/persistent-machine.js";
|
|
4
3
|
import { Slot } from "./slot.js";
|
|
5
4
|
import { machine_exports } from "./machine.js";
|
|
6
|
-
import { PersistenceAdapterTag, PersistenceError, VersionConflictError } from "./persistence/adapter.js";
|
|
7
|
-
import { createPersistentActor, restorePersistentActor } from "./persistence/persistent-actor.js";
|
|
8
5
|
import { ActorSystem, Default } from "./actor.js";
|
|
9
6
|
import { Event, State } from "./schema.js";
|
|
10
7
|
import { assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
|
|
11
|
-
|
|
12
|
-
import "./persistence/index.js";
|
|
13
|
-
export { ActorStoppedError, Default as ActorSystemDefault, ActorSystem as ActorSystemService, AssertionError, DuplicateActorError, Event, InMemoryPersistenceAdapter, Inspector as InspectorService, InvalidSchemaError, machine_exports as Machine, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceAdapterTag, PersistenceError, ProvisionValidationError, Slot, SlotProvisionError, State, UnprovidedSlotsError, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createPersistentActor, createTestHarness, isPersistentMachine, makeInMemoryPersistenceAdapter, makeInspector, makeInspectorEffect, restorePersistentActor, simulate, tracingInspector };
|
|
8
|
+
export { ActorStoppedError, Default as ActorSystemDefault, ActorSystem as ActorSystemService, AssertionError, DuplicateActorError, Event, Inspector as InspectorService, InvalidSchemaError, machine_exports as Machine, MissingMatchHandlerError, MissingSchemaError, NoReplyError, ProvisionValidationError, Slot, SlotProvisionError, State, UnprovidedSlotsError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createTestHarness, makeInspector, makeInspectorEffect, simulate, tracingInspector };
|
|
@@ -33,17 +33,13 @@ const isEffect = (value) => typeof value === "object" && value !== null && Effec
|
|
|
33
33
|
*/
|
|
34
34
|
const stubSystem = {
|
|
35
35
|
spawn: () => Effect.die("spawn not supported in stub system"),
|
|
36
|
-
restore: () => Effect.die("restore not supported in stub system"),
|
|
37
36
|
get: () => Effect.die("get not supported in stub system"),
|
|
38
37
|
stop: () => Effect.die("stop not supported in stub system"),
|
|
39
38
|
events: Stream.empty,
|
|
40
39
|
get actors() {
|
|
41
40
|
return /* @__PURE__ */ new Map();
|
|
42
41
|
},
|
|
43
|
-
subscribe: () => () => {}
|
|
44
|
-
listPersisted: () => Effect.die("listPersisted not supported in stub system"),
|
|
45
|
-
restoreMany: () => Effect.die("restoreMany not supported in stub system"),
|
|
46
|
-
restoreAll: () => Effect.die("restoreAll not supported in stub system")
|
|
42
|
+
subscribe: () => () => {}
|
|
47
43
|
};
|
|
48
44
|
//#endregion
|
|
49
45
|
export { INTERNAL_ENTER_EVENT, INTERNAL_INIT_EVENT, getTag, isEffect, stubSystem };
|
package/v3/dist/machine.d.ts
CHANGED
|
@@ -2,15 +2,14 @@ import { EffectHandlers, EffectSlots, EffectsDef, EffectsSchema, GuardHandlers,
|
|
|
2
2
|
import { TransitionResult } from "./internal/utils.js";
|
|
3
3
|
import { BrandedEvent, BrandedState, TaggedOrConstructor } from "./internal/brands.js";
|
|
4
4
|
import { MachineEventSchema, MachineStateSchema, VariantsUnion } from "./schema.js";
|
|
5
|
-
import { PersistenceConfig, PersistentMachine } from "./persistence/persistent-machine.js";
|
|
6
5
|
import { DuplicateActorError } from "./errors.js";
|
|
7
6
|
import { findTransitions } from "./internal/transition.js";
|
|
8
7
|
import { ActorRef, ActorSystem } from "./actor.js";
|
|
9
|
-
import { Cause, Context, Duration, Effect,
|
|
8
|
+
import { Cause, Context, Duration, Effect, Schema, Scope } from "effect";
|
|
10
9
|
|
|
11
10
|
//#region src/machine.d.ts
|
|
12
11
|
declare namespace machine_d_exports {
|
|
13
|
-
export { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig,
|
|
12
|
+
export { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig, ProvideHandlers, SlotContext, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, TransitionHandler, findTransitions, make, replay, spawn };
|
|
14
13
|
}
|
|
15
14
|
/**
|
|
16
15
|
* Self reference for sending events back to the machine
|
|
@@ -75,14 +74,6 @@ interface SpawnEffect<State, Event, ED extends EffectsDef, R> {
|
|
|
75
74
|
interface BackgroundEffect<State, Event, ED extends EffectsDef, R> {
|
|
76
75
|
readonly handler: StateEffectHandler<State, Event, ED, R>;
|
|
77
76
|
}
|
|
78
|
-
/** Options for `persist` */
|
|
79
|
-
interface PersistOptions {
|
|
80
|
-
readonly snapshotSchedule: Schedule.Schedule<unknown, {
|
|
81
|
-
readonly _tag: string;
|
|
82
|
-
}>;
|
|
83
|
-
readonly journalEvents: boolean;
|
|
84
|
-
readonly machineType?: string;
|
|
85
|
-
}
|
|
86
77
|
interface TaskOptions<State, Event, ED extends EffectsDef, A, E1, ES, EF> {
|
|
87
78
|
readonly onSuccess: (value: A, ctx: StateHandlerContext<State, Event, ED>) => ES;
|
|
88
79
|
readonly onFailure?: (cause: Cause.Cause<E1>, ctx: StateHandlerContext<State, Event, ED>) => EF;
|
|
@@ -137,11 +128,6 @@ declare class BuiltMachine<State, Event, R = never> {
|
|
|
137
128
|
/** @internal */
|
|
138
129
|
constructor(machine: Machine<State, Event, R, any, any, any, any>);
|
|
139
130
|
get initial(): State;
|
|
140
|
-
persist(config: PersistOptions): PersistentMachine<State & {
|
|
141
|
-
readonly _tag: string;
|
|
142
|
-
}, Event & {
|
|
143
|
-
readonly _tag: string;
|
|
144
|
-
}, R>;
|
|
145
131
|
}
|
|
146
132
|
/**
|
|
147
133
|
* Machine definition with fluent builder API.
|
|
@@ -322,12 +308,6 @@ declare class Machine<State, Event, R = never, _SD extends Record<string, Schema
|
|
|
322
308
|
* - Machines without slots: call with no arguments.
|
|
323
309
|
*/
|
|
324
310
|
build<R2 = never>(...args: HasSlots<GD, EFD> extends true ? [handlers: ProvideHandlers<State, Event, GD, EFD, R2>] : [handlers?: ProvideHandlers<State, Event, GD, EFD, R2>]): BuiltMachine<State, Event, R | NormalizeR<R2>>;
|
|
325
|
-
/** @internal Persist from raw Machine — prefer BuiltMachine.persist() */
|
|
326
|
-
persist(config: PersistOptions): PersistentMachine<State & {
|
|
327
|
-
readonly _tag: string;
|
|
328
|
-
}, Event & {
|
|
329
|
-
readonly _tag: string;
|
|
330
|
-
}, R>;
|
|
331
311
|
static make<SD extends Record<string, Schema.Struct.Fields>, ED extends Record<string, Schema.Struct.Fields>, S extends BrandedState, E extends BrandedEvent, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>>(config: MakeConfig<SD, ED, S, E, GD, EFD>): Machine<S, E, never, SD, ED, GD, EFD>;
|
|
332
312
|
}
|
|
333
313
|
declare class TransitionScope<State, Event, R, _SD extends Record<string, Schema.Struct.Fields>, _ED extends Record<string, Schema.Struct.Fields>, GD extends GuardsDef, EFD extends EffectsDef, SelectedState extends VariantsUnion<_SD> & BrandedState> {
|
|
@@ -338,17 +318,33 @@ declare class TransitionScope<State, Event, R, _SD extends Record<string, Schema
|
|
|
338
318
|
reenter<NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(event: TaggedOrConstructor<NE>, handler: TransitionHandler<SelectedState, NE, RS, GD, EFD, never>): TransitionScope<State, Event, R, _SD, _ED, GD, EFD, SelectedState>;
|
|
339
319
|
}
|
|
340
320
|
declare const make: typeof Machine.make;
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
321
|
+
/**
|
|
322
|
+
* Spawn an actor from a built machine.
|
|
323
|
+
*
|
|
324
|
+
* Options:
|
|
325
|
+
* - `id` — custom actor ID (default: random)
|
|
326
|
+
* - `hydrate` — restore from a previously-saved state snapshot.
|
|
327
|
+
* The actor starts in the hydrated state and re-runs spawn effects
|
|
328
|
+
* for that state (timers, scoped resources, etc.). Transition history
|
|
329
|
+
* is not replayed — only the current state's entry effects run.
|
|
330
|
+
*
|
|
331
|
+
* Persistence is composed in userland by observing `actor.changes`
|
|
332
|
+
* and saving snapshots to your own storage.
|
|
333
|
+
*/
|
|
334
|
+
declare const spawn: <S extends {
|
|
335
|
+
readonly _tag: string;
|
|
336
|
+
}, E extends {
|
|
337
|
+
readonly _tag: string;
|
|
338
|
+
}, R>(machine: BuiltMachine<S, E, R>, idOrOptions?: string | {
|
|
339
|
+
id?: string;
|
|
340
|
+
hydrate?: S;
|
|
341
|
+
}) => Effect.Effect<ActorRef<S, E>, never, R>;
|
|
342
|
+
declare const replay: <S extends {
|
|
343
|
+
readonly _tag: string;
|
|
344
|
+
}, E extends {
|
|
345
|
+
readonly _tag: string;
|
|
346
|
+
}, R>(machine: BuiltMachine<S, E, R>, events: ReadonlyArray<E>, options?: {
|
|
347
|
+
from?: S;
|
|
348
|
+
}) => Effect.Effect<S, never, R>;
|
|
353
349
|
//#endregion
|
|
354
|
-
export { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig,
|
|
350
|
+
export { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig, ProvideHandlers, SlotContext, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, TransitionHandler, findTransitions, machine_d_exports, make, replay, spawn };
|
package/v3/dist/machine.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { Inspector } from "./inspection.js";
|
|
3
|
-
import { getTag } from "./internal/utils.js";
|
|
3
|
+
import { getTag, stubSystem } from "./internal/utils.js";
|
|
4
4
|
import { ProvisionValidationError, SlotProvisionError } from "./errors.js";
|
|
5
|
-
import { persist } from "./persistence/persistent-machine.js";
|
|
6
5
|
import { emitWithTimestamp } from "./internal/inspection.js";
|
|
7
6
|
import { MachineContextTag } from "./slot.js";
|
|
8
|
-
import { findTransitions, invalidateIndex } from "./internal/transition.js";
|
|
7
|
+
import { findTransitions, invalidateIndex, resolveTransition, runTransitionHandler, shouldPostpone } from "./internal/transition.js";
|
|
9
8
|
import { createActor } from "./actor.js";
|
|
10
9
|
import { Cause, Effect, Exit, Option, Scope } from "effect";
|
|
11
10
|
//#region src/machine.ts
|
|
@@ -14,6 +13,7 @@ var machine_exports = /* @__PURE__ */ __exportAll({
|
|
|
14
13
|
Machine: () => Machine,
|
|
15
14
|
findTransitions: () => findTransitions,
|
|
16
15
|
make: () => make,
|
|
16
|
+
replay: () => replay,
|
|
17
17
|
spawn: () => spawn
|
|
18
18
|
});
|
|
19
19
|
const emitTaskInspection = (input) => Effect.flatMap(Effect.serviceOptional(Inspector).pipe(Effect.option), (inspector) => Option.isNone(inspector) ? Effect.void : emitWithTimestamp(inspector.value, (timestamp) => ({
|
|
@@ -42,9 +42,6 @@ var BuiltMachine = class {
|
|
|
42
42
|
get initial() {
|
|
43
43
|
return this._inner.initial;
|
|
44
44
|
}
|
|
45
|
-
persist(config) {
|
|
46
|
-
return this._inner.persist(config);
|
|
47
|
-
}
|
|
48
45
|
};
|
|
49
46
|
/**
|
|
50
47
|
* Machine definition with fluent builder API.
|
|
@@ -381,10 +378,6 @@ var Machine = class Machine {
|
|
|
381
378
|
}
|
|
382
379
|
return new BuiltMachine(this);
|
|
383
380
|
}
|
|
384
|
-
/** @internal Persist from raw Machine — prefer BuiltMachine.persist() */
|
|
385
|
-
persist(config) {
|
|
386
|
-
return persist(config)(this);
|
|
387
|
-
}
|
|
388
381
|
static make(config) {
|
|
389
382
|
return new Machine(config.initial, config.state, config.event, config.guards, config.effects);
|
|
390
383
|
}
|
|
@@ -404,11 +397,68 @@ var TransitionScope = class {
|
|
|
404
397
|
}
|
|
405
398
|
};
|
|
406
399
|
const make = Machine.make;
|
|
407
|
-
|
|
408
|
-
|
|
400
|
+
/**
|
|
401
|
+
* Spawn an actor from a built machine.
|
|
402
|
+
*
|
|
403
|
+
* Options:
|
|
404
|
+
* - `id` — custom actor ID (default: random)
|
|
405
|
+
* - `hydrate` — restore from a previously-saved state snapshot.
|
|
406
|
+
* The actor starts in the hydrated state and re-runs spawn effects
|
|
407
|
+
* for that state (timers, scoped resources, etc.). Transition history
|
|
408
|
+
* is not replayed — only the current state's entry effects run.
|
|
409
|
+
*
|
|
410
|
+
* Persistence is composed in userland by observing `actor.changes`
|
|
411
|
+
* and saving snapshots to your own storage.
|
|
412
|
+
*/
|
|
413
|
+
const spawn = Effect.fn("effect-machine.spawn")(function* (built, idOrOptions) {
|
|
414
|
+
const opts = typeof idOrOptions === "string" ? { id: idOrOptions } : idOrOptions;
|
|
415
|
+
const actor = yield* createActor(opts?.id ?? `actor-${Math.random().toString(36).slice(2)}`, built._inner, { initialState: opts?.hydrate });
|
|
409
416
|
const maybeScope = yield* Effect.serviceOption(Scope.Scope);
|
|
410
417
|
if (Option.isSome(maybeScope)) yield* Scope.addFinalizer(maybeScope.value, actor.stop);
|
|
411
418
|
return actor;
|
|
412
419
|
});
|
|
420
|
+
const replay = Effect.fn("effect-machine.replay")(function* (built, events, options) {
|
|
421
|
+
const machine = built._inner;
|
|
422
|
+
let state = options?.from ?? machine.initial;
|
|
423
|
+
const hasPostponeRules = machine.postponeRules.length > 0;
|
|
424
|
+
const postponed = [];
|
|
425
|
+
const dummySend = Effect.fn("effect-machine.replay.send")((_event) => Effect.void);
|
|
426
|
+
const self = {
|
|
427
|
+
send: dummySend,
|
|
428
|
+
cast: dummySend,
|
|
429
|
+
spawn: () => Effect.die("spawn not supported in replay")
|
|
430
|
+
};
|
|
431
|
+
for (const event of events) {
|
|
432
|
+
if (machine.finalStates.has(state._tag)) break;
|
|
433
|
+
if (hasPostponeRules && shouldPostpone(machine, state._tag, event._tag)) {
|
|
434
|
+
postponed.push(event);
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
const transition = resolveTransition(machine, state, event);
|
|
438
|
+
if (transition !== void 0) {
|
|
439
|
+
const result = yield* runTransitionHandler(machine, transition, state, event, self, stubSystem, "replay");
|
|
440
|
+
const previousTag = state._tag;
|
|
441
|
+
state = result.newState;
|
|
442
|
+
if ((state._tag !== previousTag || transition.reenter === true) && postponed.length > 0) {
|
|
443
|
+
let drainTag = previousTag;
|
|
444
|
+
while (state._tag !== drainTag && postponed.length > 0) {
|
|
445
|
+
if (machine.finalStates.has(state._tag)) break;
|
|
446
|
+
drainTag = state._tag;
|
|
447
|
+
const drained = postponed.splice(0);
|
|
448
|
+
for (const postponedEvent of drained) {
|
|
449
|
+
if (machine.finalStates.has(state._tag)) break;
|
|
450
|
+
if (shouldPostpone(machine, state._tag, postponedEvent._tag)) {
|
|
451
|
+
postponed.push(postponedEvent);
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
const pTransition = resolveTransition(machine, state, postponedEvent);
|
|
455
|
+
if (pTransition !== void 0) state = (yield* runTransitionHandler(machine, pTransition, state, postponedEvent, self, stubSystem, "replay")).newState;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return state;
|
|
462
|
+
});
|
|
413
463
|
//#endregion
|
|
414
|
-
export { BuiltMachine, Machine, findTransitions, machine_exports, make, spawn };
|
|
464
|
+
export { BuiltMachine, Machine, findTransitions, machine_exports, make, replay, spawn };
|