effect-machine 0.23.0 → 0.24.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 +2 -1
- package/dist/actor.d.ts +13 -0
- package/dist/actor.js +24 -15
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/inspection.d.ts +1 -19
- package/dist/inspection.js +3 -34
- package/dist/internal/inspection.d.ts +12 -2
- package/dist/internal/inspection.js +22 -4
- package/dist/internal/utils.js +2 -1
- package/dist/machine.d.ts +3 -0
- package/dist/machine.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -208,7 +208,8 @@ Read [Atom and UI integration](./docs/atom-and-ui.md) and browse [all examples](
|
|
|
208
208
|
- Durability saves committed transitions.
|
|
209
209
|
- Supervision restarts defects within an Effect `Schedule` budget.
|
|
210
210
|
- Inspection reports events, named transition operations, transitions, named guards, tasks, Effects, errors, stops, and actor generations.
|
|
211
|
-
-
|
|
211
|
+
- Typed `inspect` spawn options observe one actor.
|
|
212
|
+
- `actor.system.inspect` lets a late tool observe all actors in one system.
|
|
212
213
|
|
|
213
214
|
Read [Persistence and supervision](./docs/persistence-and-supervision.md) and [Inspection](./docs/inspection.md).
|
|
214
215
|
|
package/dist/actor.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ExtractReply, ReplyTypeBrand } from "./internal/brands.js";
|
|
2
2
|
import { ActorStoppedError, DuplicateActorError, NoReplyError } from "./errors.js";
|
|
3
|
+
import { InspectorService } from "./inspection.js";
|
|
3
4
|
import { ActorExit, Supervision } from "./supervision.js";
|
|
4
5
|
import { Lifecycle, Machine } from "./machine.js";
|
|
5
6
|
import { ProcessEventResult } from "./internal/transition.js";
|
|
@@ -238,11 +239,22 @@ interface ActorSystemService {
|
|
|
238
239
|
* Returns an unsubscribe function.
|
|
239
240
|
*/
|
|
240
241
|
readonly subscribe: (fn: SystemEventListener) => () => void;
|
|
242
|
+
/**
|
|
243
|
+
* Inspect all actors in this system.
|
|
244
|
+
*
|
|
245
|
+
* Registration affects future events only. The returned function removes the inspector.
|
|
246
|
+
*/
|
|
247
|
+
readonly inspect: (inspector: InspectorService<{
|
|
248
|
+
readonly _tag: string;
|
|
249
|
+
}, {
|
|
250
|
+
readonly _tag: string;
|
|
251
|
+
}>) => () => void;
|
|
241
252
|
}
|
|
242
253
|
type SystemSpawnOptions<S, E, Input> = {
|
|
243
254
|
readonly supervision?: Supervision.Policy;
|
|
244
255
|
readonly lifecycle?: Lifecycle<S, E>;
|
|
245
256
|
readonly hydrate?: S;
|
|
257
|
+
readonly inspect?: InspectorService<S, E>;
|
|
246
258
|
} & ([Input] extends [void] ? {
|
|
247
259
|
readonly input?: never;
|
|
248
260
|
} : {
|
|
@@ -278,6 +290,7 @@ declare const createActor: <S extends {
|
|
|
278
290
|
hydrated?: boolean;
|
|
279
291
|
supervision?: Supervision.Policy;
|
|
280
292
|
lifecycle?: Lifecycle<S, E>;
|
|
293
|
+
inspect?: InspectorService<S, E>;
|
|
281
294
|
/** @internal Called by system after each restart — emits ActorRestarted system event */
|
|
282
295
|
onRestart?: (generation: number, exit: ActorExit<unknown>) => Effect.Effect<void>;
|
|
283
296
|
}) => Effect.Effect<ActorRef<S, E, O>, never, R>;
|
package/dist/actor.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ActorStoppedError, DuplicateActorError } from "./errors.js";
|
|
2
2
|
import { resolveTransition, resolveTransitionEffect } from "./internal/transition.js";
|
|
3
|
-
import { emitWithTimestamp, makeInspectionHooks } from "./internal/inspection.js";
|
|
3
|
+
import { emitWithTimestamp, makeInspectionDispatcher, makeInspectionHooks } from "./internal/inspection.js";
|
|
4
4
|
import { Inspector } from "./inspection.js";
|
|
5
5
|
import { ActorExit } from "./supervision.js";
|
|
6
6
|
import { createRuntime } from "./internal/runtime.js";
|
|
@@ -27,6 +27,7 @@ const actorSystemId = (id) => {
|
|
|
27
27
|
if (typeof id === "string") return id;
|
|
28
28
|
return id.id;
|
|
29
29
|
};
|
|
30
|
+
const systemInspectorsBySystem = /* @__PURE__ */ new WeakMap();
|
|
30
31
|
/**
|
|
31
32
|
* ActorSystem service tag
|
|
32
33
|
*/
|
|
@@ -280,20 +281,21 @@ const runSupervisionLoop = (cell, options) => Effect.gen(function* () {
|
|
|
280
281
|
*/
|
|
281
282
|
const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machine, options) {
|
|
282
283
|
const lifecycle = options.lifecycle;
|
|
283
|
-
const
|
|
284
|
+
const capturedContext = yield* Effect.context();
|
|
284
285
|
const initial = options.initialState;
|
|
285
286
|
yield* Effect.annotateCurrentSpan("effect_machine.actor.id", id);
|
|
286
287
|
yield* Effect.annotateCurrentSpan("effect_machine.actor.initial_state", initial._tag);
|
|
287
288
|
const { system, implicitSystemScope } = yield* resolveActorSystem();
|
|
288
|
-
const
|
|
289
|
+
const ambientInspector = Option.getOrUndefined(yield* Effect.serviceOption(Inspector));
|
|
290
|
+
const localInspector = options.inspect ?? ambientInspector;
|
|
291
|
+
const systemInspectors = systemInspectorsBySystem.get(system) ?? /* @__PURE__ */ new Set();
|
|
292
|
+
const inspectorValue = makeInspectionDispatcher(localInspector, systemInspectors);
|
|
293
|
+
const serviceContext = Context.add(capturedContext, Inspector, inspectorValue);
|
|
289
294
|
const childrenMap = /* @__PURE__ */ new Map();
|
|
290
295
|
const listeners = /* @__PURE__ */ new Set();
|
|
291
296
|
const transitionsPubSub = yield* PubSub.unbounded();
|
|
292
297
|
const generation = { current: 0 };
|
|
293
|
-
const inspectionHooks = (runtimeGeneration) =>
|
|
294
|
-
if (inspectorValue === void 0) return void 0;
|
|
295
|
-
return makeInspectionHooks(id, inspectorValue, () => runtimeGeneration);
|
|
296
|
-
};
|
|
298
|
+
const inspectionHooks = (runtimeGeneration) => makeInspectionHooks(id, inspectorValue, () => runtimeGeneration);
|
|
297
299
|
const stateRef = yield* SubscriptionRef.make(initial);
|
|
298
300
|
const lifecycleRef = yield* SubscriptionRef.make({ _tag: "Created" });
|
|
299
301
|
const latestTransitionRef = yield* SubscriptionRef.make(void 0);
|
|
@@ -323,8 +325,7 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
323
325
|
/** Build lifecycle hooks for a generation */
|
|
324
326
|
const buildRuntimeLifecycle = (runtimeGeneration) => {
|
|
325
327
|
let stopEmitted = false;
|
|
326
|
-
|
|
327
|
-
if (inspectorValue !== void 0) onEvent = (state, event) => emitWithTimestamp(inspectorValue, (timestamp) => ({
|
|
328
|
+
const onEvent = (state, event) => emitWithTimestamp(inspectorValue, (timestamp) => ({
|
|
328
329
|
type: "@machine.event",
|
|
329
330
|
actorId: id,
|
|
330
331
|
generation: runtimeGeneration,
|
|
@@ -332,8 +333,7 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
332
333
|
event,
|
|
333
334
|
timestamp
|
|
334
335
|
}));
|
|
335
|
-
|
|
336
|
-
if (inspectorValue !== void 0) onFinal = (state) => Effect.gen(function* () {
|
|
336
|
+
const onFinal = (state) => Effect.gen(function* () {
|
|
337
337
|
stopEmitted = true;
|
|
338
338
|
yield* emitWithTimestamp(inspectorValue, (timestamp) => ({
|
|
339
339
|
type: "@machine.stop",
|
|
@@ -343,8 +343,7 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
343
343
|
timestamp
|
|
344
344
|
}));
|
|
345
345
|
});
|
|
346
|
-
|
|
347
|
-
if (inspectorValue !== void 0) onInitialSpawnEffects = (state) => emitWithTimestamp(inspectorValue, (timestamp) => ({
|
|
346
|
+
const onInitialSpawnEffects = (state) => emitWithTimestamp(inspectorValue, (timestamp) => ({
|
|
348
347
|
type: "@machine.effect",
|
|
349
348
|
actorId: id,
|
|
350
349
|
generation: runtimeGeneration,
|
|
@@ -484,13 +483,14 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
|
|
|
484
483
|
const withSpawnGate = (yield* Semaphore.make(1)).withPermits(1);
|
|
485
484
|
const eventPubSub = yield* PubSub.unbounded();
|
|
486
485
|
const eventListeners = /* @__PURE__ */ new Set();
|
|
486
|
+
const systemInspectors = /* @__PURE__ */ new Set();
|
|
487
487
|
const emitSystemEvent = (event) => Effect.sync(() => notifySystemListeners(eventListeners, event)).pipe(Effect.andThen(PubSub.publish(eventPubSub, event)), Effect.catchCause(() => Effect.void), Effect.asVoid);
|
|
488
488
|
yield* Effect.addFinalizer(() => {
|
|
489
489
|
const stops = [];
|
|
490
490
|
MutableHashMap.forEach(actorsMap, (actor) => {
|
|
491
491
|
stops.push(actor.stop);
|
|
492
492
|
});
|
|
493
|
-
return Effect.all(stops).pipe(Effect.andThen(PubSub.shutdown(eventPubSub)), Effect.asVoid);
|
|
493
|
+
return Effect.all(stops).pipe(Effect.andThen(Effect.sync(() => systemInspectors.clear())), Effect.andThen(PubSub.shutdown(eventPubSub)), Effect.asVoid);
|
|
494
494
|
});
|
|
495
495
|
/** Check for duplicate ID, register actor, attach scope cleanup if available */
|
|
496
496
|
const registerActor = Effect.fn("effect-machine.actorSystem.register")(function* (id, actor) {
|
|
@@ -554,6 +554,7 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
|
|
|
554
554
|
hydrated: spawnOptions?.hydrate !== void 0,
|
|
555
555
|
supervision: spawnOptions?.supervision,
|
|
556
556
|
lifecycle: spawnOptions?.lifecycle,
|
|
557
|
+
inspect: spawnOptions?.inspect,
|
|
557
558
|
onRestart
|
|
558
559
|
});
|
|
559
560
|
actorRef = actor;
|
|
@@ -602,7 +603,7 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
|
|
|
602
603
|
yield* actor.stop;
|
|
603
604
|
return true;
|
|
604
605
|
});
|
|
605
|
-
|
|
606
|
+
const system = ActorSystem.of({
|
|
606
607
|
spawn,
|
|
607
608
|
get,
|
|
608
609
|
watch,
|
|
@@ -620,8 +621,16 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
|
|
|
620
621
|
return () => {
|
|
621
622
|
eventListeners.delete(fn);
|
|
622
623
|
};
|
|
624
|
+
},
|
|
625
|
+
inspect: (inspector) => {
|
|
626
|
+
systemInspectors.add(inspector);
|
|
627
|
+
return () => {
|
|
628
|
+
systemInspectors.delete(inspector);
|
|
629
|
+
};
|
|
623
630
|
}
|
|
624
631
|
});
|
|
632
|
+
systemInspectorsBySystem.set(system, systemInspectors);
|
|
633
|
+
return system;
|
|
625
634
|
});
|
|
626
635
|
/**
|
|
627
636
|
* Create an ActorSystem instance. Must be run in a Scope.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { DeferReplyResult, ReplyResult } from "./internal/utils.js";
|
|
2
2
|
import { Event, MachineEventSchema, MachineStateSchema, ReplyFields, State } from "./schema.js";
|
|
3
3
|
import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, NoReplyError, PersistenceError, VersionConflictError } from "./errors.js";
|
|
4
|
+
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";
|
|
4
5
|
import { ActorExit, DefectPhase, Supervision } from "./supervision.js";
|
|
5
6
|
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
7
|
import { ProcessEventResult } from "./internal/transition.js";
|
|
7
8
|
import { ActorClient, ActorLifecycle, ActorRef, ActorRefSync, ActorScope, ActorSystem, ActorSystemKey, ActorSystemService, Default, SystemEvent, SystemEventListener, SystemSpawnOptions, TransitionInfo, actorSystemKey } from "./actor.js";
|
|
8
9
|
import { InputTestHarnessOptions, SimulationOptions, SimulationResult, TestHarness, TestHarnessOptions, assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
|
|
9
|
-
|
|
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, type InspectorHub, 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, makeInspectorHub, 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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, NoReplyError, PersistenceError, VersionConflictError } from "./errors.js";
|
|
2
2
|
import { Event, State } from "./schema.js";
|
|
3
|
-
import { Inspector, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect,
|
|
3
|
+
import { Inspector, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector } from "./inspection.js";
|
|
4
4
|
import { ActorExit, Supervision } from "./supervision.js";
|
|
5
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, 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,
|
|
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 };
|
package/dist/inspection.d.ts
CHANGED
|
@@ -124,13 +124,6 @@ type InspectorHandler<S, E> = (event: InspectionEvent<S, E>) => void | Effect.Ef
|
|
|
124
124
|
interface InspectorService<S, E> {
|
|
125
125
|
readonly onInspect: InspectorHandler<S, E>;
|
|
126
126
|
}
|
|
127
|
-
/**
|
|
128
|
-
* Dynamic Inspector fan-out for applications that load inspection consumers after actors start.
|
|
129
|
-
*/
|
|
130
|
-
interface InspectorHub<S, E> {
|
|
131
|
-
readonly inspector: InspectorService<S, E>;
|
|
132
|
-
readonly register: (inspector: InspectorService<S, E>) => () => void;
|
|
133
|
-
}
|
|
134
127
|
declare const Inspector_base: Context.ServiceClass<Inspector, "effect-machine/inspection/Inspector", InspectorService<any, any>>;
|
|
135
128
|
/**
|
|
136
129
|
* Inspector service tag - optional service for machine introspection
|
|
@@ -156,17 +149,6 @@ declare const makeInspectorEffect: <S = {
|
|
|
156
149
|
readonly _tag: string;
|
|
157
150
|
}>(onInspect: (event: InspectionEvent<ResolveType<S>, ResolveType<E>>) => Effect.Effect<void>) => InspectorService<ResolveType<S>, ResolveType<E>>;
|
|
158
151
|
declare const combineInspectors: <S, E>(...inspectors: ReadonlyArray<InspectorService<S, E>>) => InspectorService<S, E>;
|
|
159
|
-
/**
|
|
160
|
-
* Create an Inspector that accepts sinks throughout its lifetime.
|
|
161
|
-
*
|
|
162
|
-
* Provide `hub.inspector` before actor startup. Consumers can then register and unregister sinks
|
|
163
|
-
* without restarting the actor. A sink failure does not affect the actor or other sinks.
|
|
164
|
-
*/
|
|
165
|
-
declare const makeInspectorHub: <S = {
|
|
166
|
-
readonly _tag: string;
|
|
167
|
-
}, E = {
|
|
168
|
-
readonly _tag: string;
|
|
169
|
-
}>() => InspectorHub<ResolveType<S>, ResolveType<E>>;
|
|
170
152
|
interface TracingInspectorOptions<S, E> {
|
|
171
153
|
readonly spanName?: string | ((event: InspectionEvent<S, E>) => string);
|
|
172
154
|
readonly attributes?: (event: InspectionEvent<S, E>) => Readonly<Record<string, string | number | boolean>>;
|
|
@@ -194,4 +176,4 @@ declare const collectingInspector: <S extends {
|
|
|
194
176
|
readonly _tag: string;
|
|
195
177
|
}>(events: InspectionEvent<S, E>[]) => InspectorService<S, E>;
|
|
196
178
|
//#endregion
|
|
197
|
-
export { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, GuardEvent, InspectionEvent, Inspector, InspectorHandler,
|
|
179
|
+
export { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, GuardEvent, InspectionEvent, Inspector, InspectorHandler, InspectorService, OperationEvent, SpawnEvent, StopEvent, TaskEvent, TracingInspectorOptions, TransitionEvent, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector };
|
package/dist/inspection.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { runInspectors } from "./internal/inspection.js";
|
|
1
2
|
import { Context, Effect, Option } from "effect";
|
|
2
3
|
//#region src/inspection.ts
|
|
3
4
|
/**
|
|
@@ -15,39 +16,7 @@ var Inspector = class extends Context.Service()("effect-machine/inspection/Inspe
|
|
|
15
16
|
*/
|
|
16
17
|
const makeInspector = (onInspect) => ({ onInspect });
|
|
17
18
|
const makeInspectorEffect = (onInspect) => ({ onInspect });
|
|
18
|
-
const
|
|
19
|
-
const result = inspector.onInspect(event);
|
|
20
|
-
if (Effect.isEffect(result)) return result;
|
|
21
|
-
return Effect.void;
|
|
22
|
-
});
|
|
23
|
-
const combineInspectors = (...inspectors) => ({ onInspect: (event) => Effect.forEach(inspectors, (inspector) => inspectionEffect(inspector, event).pipe(Effect.ignoreCause), {
|
|
24
|
-
concurrency: 16,
|
|
25
|
-
discard: true
|
|
26
|
-
}) });
|
|
27
|
-
/**
|
|
28
|
-
* Create an Inspector that accepts sinks throughout its lifetime.
|
|
29
|
-
*
|
|
30
|
-
* Provide `hub.inspector` before actor startup. Consumers can then register and unregister sinks
|
|
31
|
-
* without restarting the actor. A sink failure does not affect the actor or other sinks.
|
|
32
|
-
*/
|
|
33
|
-
const makeInspectorHub = () => {
|
|
34
|
-
const inspectorByRegistration = /* @__PURE__ */ new Map();
|
|
35
|
-
const inspector = { onInspect: (event) => Effect.forEach(Array.from(inspectorByRegistration.values()), (registeredInspector) => inspectionEffect(registeredInspector, event).pipe(Effect.ignoreCause), {
|
|
36
|
-
concurrency: 16,
|
|
37
|
-
discard: true
|
|
38
|
-
}) };
|
|
39
|
-
const register = (registeredInspector) => {
|
|
40
|
-
const registration = Symbol();
|
|
41
|
-
inspectorByRegistration.set(registration, registeredInspector);
|
|
42
|
-
return () => {
|
|
43
|
-
inspectorByRegistration.delete(registration);
|
|
44
|
-
};
|
|
45
|
-
};
|
|
46
|
-
return {
|
|
47
|
-
inspector,
|
|
48
|
-
register
|
|
49
|
-
};
|
|
50
|
-
};
|
|
19
|
+
const combineInspectors = (...inspectors) => ({ onInspect: (event) => runInspectors(inspectors, event) });
|
|
51
20
|
const inspectionSpanName = (event) => {
|
|
52
21
|
switch (event.type) {
|
|
53
22
|
case "@machine.spawn": return `Machine.inspect ${event.initialState._tag}`;
|
|
@@ -181,4 +150,4 @@ const collectingInspector = (events) => ({ onInspect: (event) => {
|
|
|
181
150
|
events.push(event);
|
|
182
151
|
} });
|
|
183
152
|
//#endregion
|
|
184
|
-
export { Inspector, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect,
|
|
153
|
+
export { Inspector, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector };
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
+
import { InspectionEvent, InspectorService } from "../inspection.js";
|
|
1
2
|
import { ProcessEventHooks } from "./transition.js";
|
|
2
|
-
import {
|
|
3
|
+
import { Effect } from "effect";
|
|
3
4
|
//#region src/internal/inspection.d.ts
|
|
5
|
+
type Tagged = {
|
|
6
|
+
readonly _tag: string;
|
|
7
|
+
};
|
|
8
|
+
/** Run one inspector without letting its failure affect the machine. */
|
|
9
|
+
declare const runInspector: <S, E>(inspector: InspectorService<S, E>, event: InspectionEvent<S, E>) => Effect.Effect<void, never, never>;
|
|
10
|
+
/** Run inspectors in order and isolate each failure. */
|
|
11
|
+
declare const runInspectors: <S, E>(inspectors: Iterable<InspectorService<S, E>>, event: InspectionEvent<S, E>) => Effect.Effect<void, never, never>;
|
|
12
|
+
/** Build the actor-owned dispatcher for local and system inspection. */
|
|
13
|
+
declare const makeInspectionDispatcher: <S extends Tagged, E extends Tagged>(localInspector: InspectorService<S, E> | undefined, systemInspectors: ReadonlySet<InspectorService<Tagged, Tagged>>) => InspectorService<S, E>;
|
|
4
14
|
/** Adapt the Inspector service to the transition kernel. */
|
|
5
15
|
declare const makeInspectionHooks: <S, E>(actorId: string, inspector: InspectorService<S, E>, getGeneration?: () => number) => ProcessEventHooks<S, E>;
|
|
6
16
|
//#endregion
|
|
7
|
-
export { makeInspectionHooks };
|
|
17
|
+
export { makeInspectionDispatcher, makeInspectionHooks, runInspector, runInspectors };
|
|
@@ -1,14 +1,32 @@
|
|
|
1
1
|
import { Cause, Clock, Effect } from "effect";
|
|
2
2
|
//#region src/internal/inspection.ts
|
|
3
|
+
const inspectorActivity = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
/** Run one inspector without letting its failure affect the machine. */
|
|
5
|
+
const runInspector = Effect.fn("effect-machine.runInspector")(function* (inspector, event) {
|
|
6
|
+
const result = yield* Effect.try(() => inspector.onInspect(event)).pipe(Effect.orElseSucceed(() => void 0));
|
|
7
|
+
if (Effect.isEffect(result)) yield* result.pipe(Effect.ignoreCause);
|
|
8
|
+
});
|
|
9
|
+
/** Run inspectors in order and isolate each failure. */
|
|
10
|
+
const runInspectors = Effect.fn("effect-machine.runInspectors")(function* (inspectors, event) {
|
|
11
|
+
for (const inspector of inspectors) yield* runInspector(inspector, event);
|
|
12
|
+
});
|
|
13
|
+
/** Build the actor-owned dispatcher for local and system inspection. */
|
|
14
|
+
const makeInspectionDispatcher = (localInspector, systemInspectors) => {
|
|
15
|
+
const inspector = { onInspect: (event) => Effect.gen(function* () {
|
|
16
|
+
if (localInspector !== void 0) yield* runInspector(localInspector, event);
|
|
17
|
+
for (const systemInspector of systemInspectors) yield* runInspector(systemInspector, event);
|
|
18
|
+
}) };
|
|
19
|
+
inspectorActivity.set(inspector, () => localInspector !== void 0 || systemInspectors.size > 0);
|
|
20
|
+
return inspector;
|
|
21
|
+
};
|
|
3
22
|
/**
|
|
4
23
|
* Emit an inspection event with timestamp from Clock.
|
|
5
24
|
* @internal
|
|
6
25
|
*/
|
|
7
26
|
const emitWithTimestamp = Effect.fn("effect-machine.emitWithTimestamp")(function* (inspector, makeEvent) {
|
|
8
|
-
if (inspector === void 0) return;
|
|
27
|
+
if (inspector === void 0 || inspectorActivity.get(inspector)?.() === false) return;
|
|
9
28
|
const event = makeEvent(yield* Clock.currentTimeMillis);
|
|
10
|
-
|
|
11
|
-
if (Effect.isEffect(result)) yield* result.pipe(Effect.ignoreCause);
|
|
29
|
+
yield* runInspector(inspector, event);
|
|
12
30
|
});
|
|
13
31
|
/** Adapt the Inspector service to the transition kernel. */
|
|
14
32
|
const makeInspectionHooks = (actorId, inspector, getGeneration = () => 0) => ({
|
|
@@ -60,4 +78,4 @@ const makeInspectionHooks = (actorId, inspector, getGeneration = () => 0) => ({
|
|
|
60
78
|
}))
|
|
61
79
|
});
|
|
62
80
|
//#endregion
|
|
63
|
-
export { emitWithTimestamp, makeInspectionHooks };
|
|
81
|
+
export { emitWithTimestamp, makeInspectionDispatcher, makeInspectionHooks, runInspector, runInspectors };
|
package/dist/internal/utils.js
CHANGED
|
@@ -70,7 +70,8 @@ const stubSystem = {
|
|
|
70
70
|
get actors() {
|
|
71
71
|
return /* @__PURE__ */ new Map();
|
|
72
72
|
},
|
|
73
|
-
subscribe: () => () => {}
|
|
73
|
+
subscribe: () => () => {},
|
|
74
|
+
inspect: () => () => {}
|
|
74
75
|
};
|
|
75
76
|
//#endregion
|
|
76
77
|
export { INTERNAL_ENTER_EVENT, INTERNAL_INIT_EVENT, getTag, isDeferReplyResult, isEffect, isReplyResult, makeDeferReply, makeReply, stubSystem };
|
package/dist/machine.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { DeferReplyResult, ReplyResult, TransitionResult, makeDeferReply, makeRe
|
|
|
2
2
|
import { BrandedEvent, BrandedState, ExtractReply, TaggedOrConstructor } from "./internal/brands.js";
|
|
3
3
|
import { MachineEventSchema, MachineStateSchema, VariantsUnion } from "./schema.js";
|
|
4
4
|
import { ActorStoppedError, DuplicateActorError } from "./errors.js";
|
|
5
|
+
import { InspectorService } from "./inspection.js";
|
|
5
6
|
import { Supervision } from "./supervision.js";
|
|
6
7
|
import { ActorRef, ActorSystemService, TransitionInfo } from "./actor.js";
|
|
7
8
|
import { Duration, Effect, Option, Schema, Scope, SubscriptionRef } from "effect";
|
|
@@ -329,6 +330,7 @@ type SpawnOptions<S, E, Input> = {
|
|
|
329
330
|
readonly hydrate?: S;
|
|
330
331
|
readonly supervision?: Supervision.Policy;
|
|
331
332
|
readonly lifecycle?: Lifecycle<S, E>;
|
|
333
|
+
readonly inspect?: InspectorService<S, E>;
|
|
332
334
|
} & ([Input] extends [void] ? {
|
|
333
335
|
readonly input?: never;
|
|
334
336
|
} : {
|
|
@@ -343,6 +345,7 @@ type SpawnOptions<S, E, Input> = {
|
|
|
343
345
|
*
|
|
344
346
|
* // With lifecycle (recovery + durability)
|
|
345
347
|
* const actor = yield* Machine.spawn(machine, {
|
|
348
|
+
* inspect: consoleInspector(),
|
|
346
349
|
* lifecycle: {
|
|
347
350
|
* recovery: { resolve: (ctx) => storage.get("actor-state") },
|
|
348
351
|
* durability: { save: (commit) => storage.set("actor-state", commit.nextState) },
|
package/dist/machine.js
CHANGED
|
@@ -443,7 +443,8 @@ const spawnImpl = Effect.fn("effect-machine.spawn")(function* (machine, idOrOpti
|
|
|
443
443
|
machineInitial,
|
|
444
444
|
hydrated: opts?.hydrate !== void 0,
|
|
445
445
|
supervision: opts?.supervision,
|
|
446
|
-
lifecycle: opts?.lifecycle
|
|
446
|
+
lifecycle: opts?.lifecycle,
|
|
447
|
+
inspect: opts?.inspect
|
|
447
448
|
});
|
|
448
449
|
const maybeScope = yield* Effect.serviceOption(ActorScope);
|
|
449
450
|
if (Option.isSome(maybeScope)) yield* Scope.addFinalizer(maybeScope.value, actor.stop);
|
|
@@ -458,6 +459,7 @@ const spawnImpl = Effect.fn("effect-machine.spawn")(function* (machine, idOrOpti
|
|
|
458
459
|
*
|
|
459
460
|
* // With lifecycle (recovery + durability)
|
|
460
461
|
* const actor = yield* Machine.spawn(machine, {
|
|
462
|
+
* inspect: consoleInspector(),
|
|
461
463
|
* lifecycle: {
|
|
462
464
|
* recovery: { resolve: (ctx) => storage.get("actor-state") },
|
|
463
465
|
* durability: { save: (commit) => storage.set("actor-state", commit.nextState) },
|