ihsm 0.1.23 → 0.1.25
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 +3 -3
- package/lib/cjs/internal/console-instrumentation.d.ts +1 -1
- package/lib/cjs/internal/console-instrumentation.js +1 -1
- package/lib/cjs/internal/runtime.d.ts +19 -3
- package/lib/cjs/internal/runtime.js +74 -11
- package/lib/cjs/internal/runtime.js.map +1 -1
- package/lib/cjs/internal/scheduler.d.ts +5 -0
- package/lib/cjs/internal/scheduler.js +48 -0
- package/lib/cjs/internal/scheduler.js.map +1 -0
- package/lib/cjs/testing.d.ts +2 -1
- package/lib/cjs/testing.js +3 -29
- package/lib/cjs/testing.js.map +1 -1
- package/lib/esm/internal/console-instrumentation.d.ts +1 -1
- package/lib/esm/internal/console-instrumentation.js +1 -1
- package/lib/esm/internal/runtime.d.ts +19 -3
- package/lib/esm/internal/runtime.js +72 -11
- package/lib/esm/internal/runtime.js.map +1 -1
- package/lib/esm/internal/scheduler.d.ts +5 -0
- package/lib/esm/internal/scheduler.js +44 -0
- package/lib/esm/internal/scheduler.js.map +1 -0
- package/lib/esm/testing.d.ts +2 -1
- package/lib/esm/testing.js +4 -30
- package/lib/esm/testing.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -83,7 +83,7 @@ class Open extends DoorTop {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
const door = makeActor(DoorTop, { openCount: 0 }
|
|
86
|
+
const door = makeActor(DoorTop, { openCount: 0 });
|
|
87
87
|
await door.hsm.sync();
|
|
88
88
|
|
|
89
89
|
door.notify.open();
|
|
@@ -140,7 +140,7 @@ class WalletTop extends TopState<WalletConfig> {
|
|
|
140
140
|
@InitialState
|
|
141
141
|
class Open extends WalletTop {}
|
|
142
142
|
|
|
143
|
-
const wallet = makeActor(WalletTop, { balance: 100 }
|
|
143
|
+
const wallet = makeActor(WalletTop, { balance: 100 });
|
|
144
144
|
await wallet.hsm.sync();
|
|
145
145
|
|
|
146
146
|
wallet.notify.deposit(50);
|
|
@@ -212,7 +212,7 @@ class Stopped extends PlayerTop {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
const player = makeActor(PlayerTop, { track: '' }
|
|
215
|
+
const player = makeActor(PlayerTop, { track: '' });
|
|
216
216
|
await player.hsm.sync();
|
|
217
217
|
|
|
218
218
|
player.notify.play();
|
|
@@ -28,7 +28,7 @@ export interface ConsoleInstrumentationOptions {
|
|
|
28
28
|
* ```ts
|
|
29
29
|
* import { createConsoleInstrumentation, registerCollector, makeActor, Port } from 'ihsm';
|
|
30
30
|
* registerCollector(createConsoleInstrumentation());
|
|
31
|
-
* const actor = makeActor(Top, ctx,
|
|
31
|
+
* const actor = makeActor(Top, ctx, { initialize: true });
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
34
|
export declare function createConsoleInstrumentation(options?: ConsoleInstrumentationOptions): Instrumentation;
|
|
@@ -23,7 +23,7 @@ function shortUuid(uuid) {
|
|
|
23
23
|
* ```ts
|
|
24
24
|
* import { createConsoleInstrumentation, registerCollector, makeActor, Port } from 'ihsm';
|
|
25
25
|
* registerCollector(createConsoleInstrumentation());
|
|
26
|
-
* const actor = makeActor(Top, ctx,
|
|
26
|
+
* const actor = makeActor(Top, ctx, { initialize: true });
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
29
|
function createConsoleInstrumentation(options = {}) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** @internal Consolidated ihsm runtime (no pure types — see ./types.ts). */
|
|
2
1
|
import type { ActorConfig, ActorContextOf, ActorConfigOf, ActorOptions, ChildActor, ChildHsm, DispatchableMachine, EmbodimentKind, ErrorHost, ExternalActor, ExternalHsm, HandlerHsm, HsmWithTracing, InboundActor, InboundHsm, Instance, NotificationQueue, ParentActor, PlannedTransition, IPort, MachinePortInput, Properties, ProtocolIndex, RandomService, ReservedName, SelfNotifications, ServiceCallOptions, StateClass, StateEvents, Task, TimerService, TopStateArg, TraceWriter, DispatchErrorCallback, Transition, TransitionResolver, TransitionHost, TransitionRoutineExecuteOptions, TransitionRoutinePlan, TransitionTracer, Disposable, EventObserver, TransitionTraceHost, ActorIdentity, ActorLogger, Instrumentation, OutboundCallBegin, TraceFrame } from './types';
|
|
3
2
|
export declare enum TraceLevel {
|
|
4
3
|
PRODUCTION = 0,
|
|
@@ -252,6 +251,10 @@ export declare class HsmObject<C extends ActorConfig> implements HsmWithTracing<
|
|
|
252
251
|
private _traceDomainStack;
|
|
253
252
|
protected _instrumentationHost?: InstrumentationHost;
|
|
254
253
|
private _drainWaiters;
|
|
254
|
+
private _tasksSinceYield;
|
|
255
|
+
private _sliceStart;
|
|
256
|
+
/** @internal Pending actor initialization — always runs before hi-priority work. */
|
|
257
|
+
_initTask?: Task;
|
|
255
258
|
constructor(TopState: StateClass<C>, instance: Instance<C>, traceWriter: TraceWriter, traceLevel: TraceLevel, dispatchErrorCallback: DispatchErrorCallback<C>, identity: ActorIdentity);
|
|
256
259
|
get ctx(): ActorContextOf<C>;
|
|
257
260
|
set ctx(ctx: ActorContextOf<C>);
|
|
@@ -282,10 +285,12 @@ export declare class HsmObject<C extends ActorConfig> implements HsmWithTracing<
|
|
|
282
285
|
/** Invoke the user dispatch-error callback, first notifying instrumentation (pure observer). */
|
|
283
286
|
reportDispatchError(err: Error): void;
|
|
284
287
|
private flushDrainWaiters;
|
|
288
|
+
protected enqueueInitTask(task: Task): void;
|
|
285
289
|
pushTask(t: Task): void;
|
|
286
290
|
pushHiPriorityTask(t: Task): void;
|
|
287
291
|
unshiftHiPriorityTask(t: Task): void;
|
|
288
292
|
private enqueueTask;
|
|
293
|
+
private scheduleKickoff;
|
|
289
294
|
restore(state: StateClass<C>, ctx: ActorContextOf<C>): void;
|
|
290
295
|
private dequeue;
|
|
291
296
|
private exec;
|
|
@@ -363,13 +368,24 @@ type ActorHandleFor<C extends ActorConfig, K extends EmbodimentKind> = K extends
|
|
|
363
368
|
type SpawnContext<C extends ActorConfig = ActorConfig> = {
|
|
364
369
|
readonly parentMachine?: Machine<C>;
|
|
365
370
|
};
|
|
371
|
+
/** @internal Distinguish {@link ActorOptions} from a port when the port argument is omitted. */
|
|
372
|
+
export declare function isActorOptions(value: unknown): value is ActorOptions<ActorConfig>;
|
|
373
|
+
/** @internal */
|
|
374
|
+
export declare function resolveFactoryPortAndOptions<C extends ActorConfig>(portOrOptions?: MachinePortInput<C> | ActorOptions<C>, maybeOptions?: ActorOptions<C>): {
|
|
375
|
+
port: MachinePortInput<C> | undefined;
|
|
376
|
+
options: ActorOptions<C>;
|
|
377
|
+
};
|
|
366
378
|
/** @internal Spawn with embodiment kind — used by factories and `ihsm/testing`. */
|
|
367
379
|
export declare function spawnActor<C extends ActorConfig, K extends EmbodimentKind>(kind: K, topState: TopStateArg<C>, ctx: ActorContextOf<C>, port: MachinePortInput<C> | undefined, options: ActorOptions<C>, spawnContext?: SpawnContext<C>): ActorHandleFor<C, K>;
|
|
368
380
|
/** Production black-box — public protocol only (generated handle). */
|
|
369
|
-
export declare function makeActor<T extends TopStateArg<ActorConfig>>(topState: T, ctx: ActorContextOf<ActorConfigOf<T>>,
|
|
381
|
+
export declare function makeActor<T extends TopStateArg<ActorConfig>>(topState: T, ctx: ActorContextOf<ActorConfigOf<T>>, options?: ActorOptions<ActorConfigOf<T>>): ExternalActor<ActorConfigOf<T>>;
|
|
382
|
+
export declare function makeActor<T extends TopStateArg<ActorConfig>>(topState: T, ctx: ActorContextOf<ActorConfigOf<T>>, port: MachinePortInput<ActorConfigOf<T>>, options?: ActorOptions<ActorConfigOf<T>>): ExternalActor<ActorConfigOf<T>>;
|
|
370
383
|
export declare function asParentActor<T extends TopStateArg<ActorConfig>>(handler: TopState<ActorConfigOf<T>>): ParentActor<T>;
|
|
371
384
|
/** Parent composes a child machine — returns full child protocol shell with `parent` set. */
|
|
372
|
-
export declare function makeChildActor<ParentT extends TopStateArg<ActorConfig>, ChildT extends TopStateArg<ActorConfig>>(parent: ParentActor<ParentT>, childTop: ChildT, childCtx: ActorContextOf<ActorConfigOf<ChildT>>,
|
|
385
|
+
export declare function makeChildActor<ParentT extends TopStateArg<ActorConfig>, ChildT extends TopStateArg<ActorConfig>>(parent: ParentActor<ParentT>, childTop: ChildT, childCtx: ActorContextOf<ActorConfigOf<ChildT>>, options?: ActorOptions<ActorConfigOf<ChildT>>): ChildActor<ActorConfigOf<ChildT>> & {
|
|
386
|
+
readonly parent: ParentActor<ParentT>;
|
|
387
|
+
};
|
|
388
|
+
export declare function makeChildActor<ParentT extends TopStateArg<ActorConfig>, ChildT extends TopStateArg<ActorConfig>>(parent: ParentActor<ParentT>, childTop: ChildT, childCtx: ActorContextOf<ActorConfigOf<ChildT>>, port: MachinePortInput<ActorConfigOf<ChildT>>, options?: ActorOptions<ActorConfigOf<ChildT>>): ChildActor<ActorConfigOf<ChildT>> & {
|
|
373
389
|
readonly parent: ParentActor<ParentT>;
|
|
374
390
|
};
|
|
375
391
|
export { kHandlerMachine, kParentLink } from './types';
|
|
@@ -33,10 +33,15 @@ exports.createNotificationTask = createNotificationTask;
|
|
|
33
33
|
exports.createServiceTask = createServiceTask;
|
|
34
34
|
exports.isRequestingPort = isRequestingPort;
|
|
35
35
|
exports.defaultDispatchErrorCallback = defaultDispatchErrorCallback;
|
|
36
|
+
exports.isActorOptions = isActorOptions;
|
|
37
|
+
exports.resolveFactoryPortAndOptions = resolveFactoryPortAndOptions;
|
|
36
38
|
exports.spawnActor = spawnActor;
|
|
37
39
|
exports.makeActor = makeActor;
|
|
38
40
|
exports.asParentActor = asParentActor;
|
|
39
41
|
exports.makeChildActor = makeChildActor;
|
|
42
|
+
/** @internal Consolidated ihsm runtime (no pure types — see ./types.ts). */
|
|
43
|
+
/// <reference types="node" />
|
|
44
|
+
const scheduler_1 = require("./scheduler");
|
|
40
45
|
const types_1 = require("./types");
|
|
41
46
|
const identity_1 = require("./identity");
|
|
42
47
|
const instrumentation_1 = require("./instrumentation");
|
|
@@ -1614,6 +1619,10 @@ class HsmObject {
|
|
|
1614
1619
|
_traceDomainStack;
|
|
1615
1620
|
_instrumentationHost;
|
|
1616
1621
|
_drainWaiters = [];
|
|
1622
|
+
_tasksSinceYield = 0;
|
|
1623
|
+
_sliceStart = 0;
|
|
1624
|
+
/** @internal Pending actor initialization — always runs before hi-priority work. */
|
|
1625
|
+
_initTask;
|
|
1617
1626
|
constructor(TopState, instance, traceWriter, traceLevel, dispatchErrorCallback, identity) {
|
|
1618
1627
|
this._instance = instance;
|
|
1619
1628
|
this._transitionState = undefined;
|
|
@@ -1729,6 +1738,13 @@ class HsmObject {
|
|
|
1729
1738
|
for (const resolve of waiters)
|
|
1730
1739
|
resolve();
|
|
1731
1740
|
}
|
|
1741
|
+
enqueueInitTask(task) {
|
|
1742
|
+
this._initTask = task;
|
|
1743
|
+
if (this._isRunning)
|
|
1744
|
+
return;
|
|
1745
|
+
this._isRunning = true;
|
|
1746
|
+
this.scheduleKickoff();
|
|
1747
|
+
}
|
|
1732
1748
|
pushTask(t) {
|
|
1733
1749
|
this.enqueueTask(t, this._jobs);
|
|
1734
1750
|
}
|
|
@@ -1740,31 +1756,53 @@ class HsmObject {
|
|
|
1740
1756
|
if (this._isRunning)
|
|
1741
1757
|
return;
|
|
1742
1758
|
this._isRunning = true;
|
|
1743
|
-
this.
|
|
1759
|
+
this.scheduleKickoff();
|
|
1744
1760
|
}
|
|
1745
1761
|
enqueueTask(t, queue) {
|
|
1746
1762
|
queue.push(t);
|
|
1747
1763
|
if (this._isRunning)
|
|
1748
1764
|
return;
|
|
1749
1765
|
this._isRunning = true;
|
|
1750
|
-
this.
|
|
1766
|
+
this.scheduleKickoff();
|
|
1767
|
+
}
|
|
1768
|
+
scheduleKickoff() {
|
|
1769
|
+
queueMicrotask(() => this.dequeue());
|
|
1751
1770
|
}
|
|
1752
1771
|
restore(state, ctx) {
|
|
1753
1772
|
this.currentState = state;
|
|
1754
1773
|
this.ctx = ctx;
|
|
1755
1774
|
}
|
|
1756
1775
|
dequeue() {
|
|
1757
|
-
if (this._hiPriorityJobs.length == 0 && this._jobs.length == 0) {
|
|
1776
|
+
if (this._initTask === undefined && this._hiPriorityJobs.length == 0 && this._jobs.length == 0) {
|
|
1758
1777
|
this._isRunning = false;
|
|
1759
1778
|
this._instrumentationHost?.onQueuesDrained();
|
|
1760
1779
|
this.flushDrainWaiters();
|
|
1761
1780
|
return;
|
|
1762
1781
|
}
|
|
1782
|
+
if (this._initTask !== undefined) {
|
|
1783
|
+
const task = this._initTask;
|
|
1784
|
+
this._initTask = undefined;
|
|
1785
|
+
this.exec(task);
|
|
1786
|
+
return;
|
|
1787
|
+
}
|
|
1763
1788
|
const task = this._hiPriorityJobs.length > 0 ? this._hiPriorityJobs.shift() : this._jobs.shift();
|
|
1764
1789
|
this.exec(task);
|
|
1765
1790
|
}
|
|
1766
1791
|
exec(task) {
|
|
1767
|
-
|
|
1792
|
+
if (this._tasksSinceYield === 0) {
|
|
1793
|
+
this._sliceStart = (0, scheduler_1.nowMs)();
|
|
1794
|
+
}
|
|
1795
|
+
void this.runTask(task).then(() => {
|
|
1796
|
+
this._tasksSinceYield++;
|
|
1797
|
+
const overBudget = this._tasksSinceYield >= scheduler_1.YIELD_TASK_BUDGET || (0, scheduler_1.nowMs)() - this._sliceStart >= scheduler_1.YIELD_TIME_BUDGET_MS;
|
|
1798
|
+
if (overBudget) {
|
|
1799
|
+
this._tasksSinceYield = 0;
|
|
1800
|
+
(0, scheduler_1.yieldToMacrotask)(() => this.dequeue());
|
|
1801
|
+
}
|
|
1802
|
+
else {
|
|
1803
|
+
this.dequeue();
|
|
1804
|
+
}
|
|
1805
|
+
});
|
|
1768
1806
|
}
|
|
1769
1807
|
runTask(task) {
|
|
1770
1808
|
this._instrumentationHost?.onTaskBegin(task);
|
|
@@ -1881,7 +1919,7 @@ class Machine extends HsmObject {
|
|
|
1881
1919
|
if (initialize) {
|
|
1882
1920
|
const initTask = createInitTask(this, this.transitionResolver);
|
|
1883
1921
|
(0, instrumentation_1.setTaskMeta)(initTask, { event: 'initialize', queue: 'default', triggerKind: 'init', internal: false });
|
|
1884
|
-
this.
|
|
1922
|
+
this.enqueueInitTask(initTask);
|
|
1885
1923
|
}
|
|
1886
1924
|
}
|
|
1887
1925
|
allocateChildSpawnIndex(childTopName) {
|
|
@@ -2453,6 +2491,31 @@ function defaultDispatchErrorCallback(hsm, err) {
|
|
|
2453
2491
|
hsm.traceWriter.write(hsm, err);
|
|
2454
2492
|
throw err;
|
|
2455
2493
|
}
|
|
2494
|
+
const ACTOR_OPTION_KEYS = new Set(['initialize', 'traceLevel', 'traceWriter', 'dispatchErrorCallback', 'transitions']);
|
|
2495
|
+
/** @internal Distinguish {@link ActorOptions} from a port when the port argument is omitted. */
|
|
2496
|
+
function isActorOptions(value) {
|
|
2497
|
+
if (value === null || typeof value !== 'object') {
|
|
2498
|
+
return false;
|
|
2499
|
+
}
|
|
2500
|
+
if (value instanceof Port || isRequestingPort(value)) {
|
|
2501
|
+
return false;
|
|
2502
|
+
}
|
|
2503
|
+
const keys = Object.keys(value);
|
|
2504
|
+
if (keys.length === 0) {
|
|
2505
|
+
return true;
|
|
2506
|
+
}
|
|
2507
|
+
return keys.every(key => ACTOR_OPTION_KEYS.has(key));
|
|
2508
|
+
}
|
|
2509
|
+
/** @internal */
|
|
2510
|
+
function resolveFactoryPortAndOptions(portOrOptions, maybeOptions) {
|
|
2511
|
+
if (maybeOptions !== undefined) {
|
|
2512
|
+
return { port: portOrOptions, options: maybeOptions };
|
|
2513
|
+
}
|
|
2514
|
+
if (portOrOptions !== undefined && isActorOptions(portOrOptions)) {
|
|
2515
|
+
return { port: undefined, options: portOrOptions };
|
|
2516
|
+
}
|
|
2517
|
+
return { port: portOrOptions, options: {} };
|
|
2518
|
+
}
|
|
2456
2519
|
/** @internal Spawn with embodiment kind — used by factories and `ihsm/testing`. */
|
|
2457
2520
|
function spawnActor(kind, topState, ctx, port, options, spawnContext = {}) {
|
|
2458
2521
|
const { initialize = exports.defaultInitialize, traceLevel = TraceLevel.DEBUG, traceWriter = exports.defaultTraceWriter, dispatchErrorCallback = defaultDispatchErrorCallback, transitions } = options;
|
|
@@ -2495,9 +2558,9 @@ function spawnActor(kind, topState, ctx, port, options, spawnContext = {}) {
|
|
|
2495
2558
|
boundPort.actor = createActorHandle(machine, topState, protocolIndex, portKind);
|
|
2496
2559
|
return createActorHandle(machine, topState, protocolIndex, kind);
|
|
2497
2560
|
}
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
return spawnActor('root', topState, ctx, port,
|
|
2561
|
+
function makeActor(topState, ctx, portOrOptions, options) {
|
|
2562
|
+
const { port, options: resolvedOptions } = resolveFactoryPortAndOptions(portOrOptions, options);
|
|
2563
|
+
return spawnActor('root', topState, ctx, port, resolvedOptions);
|
|
2501
2564
|
}
|
|
2502
2565
|
function asParentActor(handler) {
|
|
2503
2566
|
const machine = handler[types_1.kHandlerMachine];
|
|
@@ -2509,10 +2572,10 @@ function asParentActor(handler) {
|
|
|
2509
2572
|
[types_1.kParentLink]: machine,
|
|
2510
2573
|
};
|
|
2511
2574
|
}
|
|
2512
|
-
|
|
2513
|
-
|
|
2575
|
+
function makeChildActor(parent, childTop, childCtx, portOrOptions, options) {
|
|
2576
|
+
const { port, options: resolvedOptions } = resolveFactoryPortAndOptions(portOrOptions, options);
|
|
2514
2577
|
const parentMachine = parent[types_1.kParentLink];
|
|
2515
|
-
const child = spawnActor('child', childTop, childCtx, port,
|
|
2578
|
+
const child = spawnActor('child', childTop, childCtx, port, resolvedOptions, { parentMachine: parentMachine });
|
|
2516
2579
|
Object.defineProperty(child, 'parent', { value: parent, enumerable: true, writable: false, configurable: true });
|
|
2517
2580
|
return child;
|
|
2518
2581
|
}
|