@mantaq/core 0.0.1 → 0.0.3
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
CHANGED
|
@@ -177,8 +177,8 @@ const actor = new Actor({
|
|
|
177
177
|
initial: idleState,
|
|
178
178
|
setup: (m) => {
|
|
179
179
|
m.effect(loadingState, ({ state, emit, clock }) => {
|
|
180
|
-
// state.payload is
|
|
181
|
-
const
|
|
180
|
+
// state.payload is typed to the state's declared payload: { url: string }
|
|
181
|
+
const url = state.payload.url;
|
|
182
182
|
clock.setTimeout(1000, () => {
|
|
183
183
|
emit(doneEvent.create());
|
|
184
184
|
});
|
|
@@ -61,21 +61,22 @@ interface Clock {
|
|
|
61
61
|
}
|
|
62
62
|
//#endregion
|
|
63
63
|
//#region src/actor-internal.d.ts
|
|
64
|
-
interface Snapshot {
|
|
64
|
+
interface Snapshot<C = unknown> {
|
|
65
65
|
path: string[];
|
|
66
|
-
|
|
66
|
+
context: C;
|
|
67
|
+
regions: Record<string, Snapshot<unknown>>;
|
|
67
68
|
done?: boolean;
|
|
68
69
|
}
|
|
69
|
-
interface AnyActor {
|
|
70
|
+
interface AnyActor<C = Record<string, unknown>> {
|
|
70
71
|
state: AnyStateRef;
|
|
71
72
|
clock: Clock;
|
|
72
73
|
regions: Record<string, AnyActor>;
|
|
73
74
|
send(event: AnyEventRef | InternalEvent): void;
|
|
74
|
-
snapshot(): Snapshot
|
|
75
|
-
on(event: "change", fn: (snapshot: Snapshot) => void): () => void;
|
|
75
|
+
snapshot(): Snapshot<C>;
|
|
76
|
+
on(event: "change", fn: (snapshot: Snapshot<C>, prev: Snapshot<C>) => void): () => void;
|
|
76
77
|
on(event: "done", fn: () => void): () => void;
|
|
77
78
|
settled(): Promise<void>;
|
|
78
|
-
context?:
|
|
79
|
+
context?: C;
|
|
79
80
|
options?: {
|
|
80
81
|
transitions?: Record<string, Record<string, unknown>>;
|
|
81
82
|
effects?: Record<string, unknown[]>;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as CreatedOfEvent, c as event, d as state, i as AnyEventRef, l as AnyStateRef, n as Snapshot, o as EventRef, r as Clock, s as InternalEvent, t as AnyActor, u as StateRef } from "./actor-internal-
|
|
1
|
+
import { a as CreatedOfEvent, c as event, d as state, i as AnyEventRef, l as AnyStateRef, n as Snapshot, o as EventRef, r as Clock, s as InternalEvent, t as AnyActor, u as StateRef } from "./actor-internal-CBU_EDPZ.mjs";
|
|
2
2
|
//#region src/real-clock.d.ts
|
|
3
3
|
declare class RealClock implements Clock {
|
|
4
4
|
#private;
|
|
@@ -38,23 +38,31 @@ declare class VirtualClock implements Clock {
|
|
|
38
38
|
setDrain(fn: () => void): void;
|
|
39
39
|
}
|
|
40
40
|
//#endregion
|
|
41
|
+
//#region src/context.d.ts
|
|
42
|
+
declare class Context<T> {
|
|
43
|
+
#private;
|
|
44
|
+
constructor(get: () => T, set: (value: T) => void);
|
|
45
|
+
get(): T;
|
|
46
|
+
set(value: T): void;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
41
49
|
//#region src/actor-types.d.ts
|
|
42
50
|
type CreatedOf<E extends AnyEventRef> = E extends EventRef<infer Id, infer P> ? CreatedOfEvent<Id, P> : never;
|
|
43
51
|
type NonFinalStateRef<States extends AnyStateRef[]> = Extract<States[number], {
|
|
44
52
|
isFinal: false;
|
|
45
53
|
}>;
|
|
46
|
-
interface EffectInput<ActorContext> {
|
|
54
|
+
interface EffectInput<ActorContext, Payload = unknown> {
|
|
47
55
|
signal: AbortSignal;
|
|
48
56
|
state: {
|
|
49
57
|
name: string;
|
|
50
|
-
payload:
|
|
58
|
+
payload: Payload;
|
|
51
59
|
};
|
|
52
60
|
event: InternalEvent;
|
|
53
|
-
context: ActorContext
|
|
61
|
+
context: Context<ActorContext>;
|
|
54
62
|
emit: (event: InternalEvent) => void;
|
|
55
63
|
clock: Clock;
|
|
56
64
|
}
|
|
57
|
-
type EffectFn<ActorContext> = (input: EffectInput<ActorContext>) => void;
|
|
65
|
+
type EffectFn<ActorContext, Payload = unknown> = (input: EffectInput<ActorContext, Payload>) => void;
|
|
58
66
|
type TransitionResult<AllowedState extends AnyStateRef = AnyStateRef, AllowedEmit extends string = string> = {
|
|
59
67
|
state?: AllowedState | {
|
|
60
68
|
state: AllowedState;
|
|
@@ -68,8 +76,9 @@ type TransitionResult<AllowedState extends AnyStateRef = AnyStateRef, AllowedEmi
|
|
|
68
76
|
//#endregion
|
|
69
77
|
//#region src/builder.d.ts
|
|
70
78
|
type EventIdOf<E extends AnyEventRef> = E extends EventRef<infer Id, object | void> ? Id : never;
|
|
79
|
+
type PayloadOf<S extends AnyStateRef> = S extends StateRef<infer _Name, infer Payload, infer _IsFinal> ? Payload : never;
|
|
71
80
|
type TransitionHandler<States extends readonly AnyStateRef[], ActorContext> = (event: InternalEvent, opts: {
|
|
72
|
-
context: ActorContext
|
|
81
|
+
context: Context<ActorContext>;
|
|
73
82
|
actor: AnyActor;
|
|
74
83
|
}) => TransitionResult<States[number], string>;
|
|
75
84
|
interface BuiltMaps<States extends readonly AnyStateRef[], ActorContext> {
|
|
@@ -79,14 +88,14 @@ interface BuiltMaps<States extends readonly AnyStateRef[], ActorContext> {
|
|
|
79
88
|
declare class ActorBuilder<States extends readonly AnyStateRef[], Inputs extends readonly AnyEventRef[], Internal extends readonly AnyEventRef[], Outputs extends readonly AnyEventRef[], ActorContext> {
|
|
80
89
|
#private;
|
|
81
90
|
on<S extends States[number], E extends Inputs[number] | Internal[number]>(stateRef: S, eventRef: E, fn: (event: E extends EventRef<infer Id, infer P> ? CreatedOfEvent<Id, P> : never, opts: {
|
|
82
|
-
context: ActorContext
|
|
91
|
+
context: Context<ActorContext>;
|
|
83
92
|
actor: AnyActor;
|
|
84
93
|
}) => TransitionResult<States[number], EventIdOf<Outputs[number]>>): this;
|
|
85
94
|
onAny<E extends Inputs[number] | Internal[number]>(eventRef: E, fn: (event: E extends EventRef<infer Id, infer P> ? CreatedOfEvent<Id, P> : never, opts: {
|
|
86
|
-
context: ActorContext
|
|
95
|
+
context: Context<ActorContext>;
|
|
87
96
|
actor: AnyActor;
|
|
88
97
|
}) => TransitionResult<States[number], EventIdOf<Outputs[number]>>): this;
|
|
89
|
-
effect<S extends States[number]>(stateRef: S, fn: EffectFn<ActorContext
|
|
98
|
+
effect<S extends States[number]>(stateRef: S, fn: EffectFn<ActorContext, PayloadOf<S>>): this;
|
|
90
99
|
/** @internal */ build(): BuiltMaps<States, ActorContext>;
|
|
91
100
|
}
|
|
92
101
|
type SetupFn<States extends readonly AnyStateRef[], Inputs extends readonly AnyEventRef[], Internal extends readonly AnyEventRef[], Outputs extends readonly AnyEventRef[], ActorContext> = (m: ActorBuilder<States, Inputs, Internal, Outputs, ActorContext>) => void;
|
|
@@ -130,7 +139,7 @@ interface InternalActorOptions<States extends readonly AnyStateRef[], Inputs ext
|
|
|
130
139
|
regions?: Record<string, AnyActor>;
|
|
131
140
|
}
|
|
132
141
|
type TransitionDispatch<States extends readonly AnyStateRef[], ActorContext> = Record<string, Record<string, ((event: InternalEvent, options: {
|
|
133
|
-
context: ActorContext
|
|
142
|
+
context: Context<ActorContext>;
|
|
134
143
|
actor: AnyActor;
|
|
135
144
|
}) => TransitionResult<States[number], string>) | undefined>>;
|
|
136
145
|
declare class Actor<const States extends readonly AnyStateRef[], const Inputs extends readonly AnyEventRef[], const Internal extends readonly AnyEventRef[] = readonly [], const Outputs extends readonly AnyEventRef[] = readonly [], ActorContext = Record<string, unknown>> {
|
|
@@ -141,11 +150,11 @@ declare class Actor<const States extends readonly AnyStateRef[], const Inputs ex
|
|
|
141
150
|
get regions(): Record<string, AnyActor>;
|
|
142
151
|
get options(): InternalActorOptions<States, Inputs, Internal, Outputs, ActorContext>;
|
|
143
152
|
constructor(options: ActorOptions<States, Inputs, Internal, Outputs, ActorContext>);
|
|
144
|
-
on(event: "change", fn: (snapshot: Snapshot) => void): () => void;
|
|
153
|
+
on(event: "change", fn: (snapshot: Snapshot<ActorContext>, prev: Snapshot<ActorContext>) => void): () => void;
|
|
145
154
|
on(event: "done", fn: () => void): () => void;
|
|
146
155
|
settled(): Promise<void>;
|
|
147
156
|
send(event: CreatedOf$1<Inputs[number]>): void;
|
|
148
|
-
snapshot(): Snapshot
|
|
157
|
+
snapshot(): Snapshot<ActorContext>;
|
|
149
158
|
}
|
|
150
159
|
//#endregion
|
|
151
|
-
export { Actor, type ActorBuilder, type AnyActor, type AnyEventRef, type AnyStateRef, type Clock, type CreatedOf, type CreatedOfEvent, type EffectFn, type EffectInput, EventRef, type InternalEvent, type NonFinalStateRef, RealClock, type SetupFn, type Snapshot, StateRef, VirtualClock, event, state };
|
|
160
|
+
export { Actor, type ActorBuilder, type AnyActor, type AnyEventRef, type AnyStateRef, type Clock, Context, type CreatedOf, type CreatedOfEvent, type EffectFn, type EffectInput, EventRef, type InternalEvent, type NonFinalStateRef, RealClock, type SetupFn, type Snapshot, StateRef, VirtualClock, event, state };
|
package/dist/index.mjs
CHANGED
|
@@ -254,8 +254,13 @@ var InternalQueue = class {
|
|
|
254
254
|
var Subscribers = class {
|
|
255
255
|
change = /* @__PURE__ */ new Set();
|
|
256
256
|
done = /* @__PURE__ */ new Set();
|
|
257
|
+
#last = null;
|
|
258
|
+
seed(snapshot) {
|
|
259
|
+
this.#last = snapshot;
|
|
260
|
+
}
|
|
257
261
|
addChange(fn) {
|
|
258
262
|
this.change.add(fn);
|
|
263
|
+
if (this.#last) fn(this.#last, this.#last);
|
|
259
264
|
return () => this.change.delete(fn);
|
|
260
265
|
}
|
|
261
266
|
addDone(fn) {
|
|
@@ -263,7 +268,9 @@ var Subscribers = class {
|
|
|
263
268
|
return () => this.done.delete(fn);
|
|
264
269
|
}
|
|
265
270
|
emitChange(snapshot) {
|
|
266
|
-
|
|
271
|
+
const prev = this.#last ?? snapshot;
|
|
272
|
+
this.#last = snapshot;
|
|
273
|
+
for (const fn of this.change) fn(snapshot, prev);
|
|
267
274
|
}
|
|
268
275
|
emitDone() {
|
|
269
276
|
for (const fn of this.done) fn();
|
|
@@ -275,12 +282,13 @@ var Subscribers = class {
|
|
|
275
282
|
};
|
|
276
283
|
//#endregion
|
|
277
284
|
//#region src/snapshot.ts
|
|
278
|
-
function buildSnapshot(s, regions) {
|
|
285
|
+
function buildSnapshot(s, regions, context) {
|
|
279
286
|
const path = [s.name];
|
|
280
287
|
const regionSnapshots = {};
|
|
281
288
|
for (const [regionName, child] of Object.entries(regions)) regionSnapshots[regionName] = child.snapshot();
|
|
282
289
|
const snap = {
|
|
283
290
|
path,
|
|
291
|
+
context,
|
|
284
292
|
regions: regionSnapshots
|
|
285
293
|
};
|
|
286
294
|
if (s.isFinal) snap.done = true;
|
|
@@ -320,6 +328,22 @@ function parseTarget(step) {
|
|
|
320
328
|
};
|
|
321
329
|
}
|
|
322
330
|
//#endregion
|
|
331
|
+
//#region src/context.ts
|
|
332
|
+
var Context = class {
|
|
333
|
+
#get;
|
|
334
|
+
#set;
|
|
335
|
+
constructor(get, set) {
|
|
336
|
+
this.#get = get;
|
|
337
|
+
this.#set = set;
|
|
338
|
+
}
|
|
339
|
+
get() {
|
|
340
|
+
return this.#get();
|
|
341
|
+
}
|
|
342
|
+
set(value) {
|
|
343
|
+
this.#set(value);
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
//#endregion
|
|
323
347
|
//#region src/builder.ts
|
|
324
348
|
var ActorBuilder = class {
|
|
325
349
|
#transitions = {};
|
|
@@ -358,6 +382,9 @@ var Actor = class {
|
|
|
358
382
|
state;
|
|
359
383
|
clock;
|
|
360
384
|
#context;
|
|
385
|
+
#contextHandle;
|
|
386
|
+
#contextWritten = false;
|
|
387
|
+
#lastState;
|
|
361
388
|
#options;
|
|
362
389
|
#regions = {};
|
|
363
390
|
#children = /* @__PURE__ */ new Map();
|
|
@@ -407,6 +434,12 @@ var Actor = class {
|
|
|
407
434
|
if (!stateNames.has(initState.name)) console.warn(`[Actor] initial state "${initState.name}" not found in declared states [${[...stateNames].join(", ")}]`);
|
|
408
435
|
this.state = initState;
|
|
409
436
|
this.#context = options.context ?? {};
|
|
437
|
+
this.#lastState = initState;
|
|
438
|
+
this.#contextHandle = new Context(() => this.#context, (value) => {
|
|
439
|
+
this.#context = value;
|
|
440
|
+
this.#contextWritten = true;
|
|
441
|
+
});
|
|
442
|
+
this.#subs.seed(this.snapshot());
|
|
410
443
|
if (options.regions) for (const [key, child] of Object.entries(options.regions)) {
|
|
411
444
|
this.#regions[key] = child;
|
|
412
445
|
const result = setOutputHandler(child, (event) => {
|
|
@@ -420,19 +453,23 @@ var Actor = class {
|
|
|
420
453
|
on(event, fn) {
|
|
421
454
|
if (event === "change") {
|
|
422
455
|
const cb = fn;
|
|
423
|
-
this.#subs.
|
|
424
|
-
cb(this.snapshot());
|
|
425
|
-
return () => this.#subs.change.delete(cb);
|
|
456
|
+
return this.#subs.addChange(cb);
|
|
426
457
|
}
|
|
427
458
|
const cb = fn;
|
|
428
|
-
this.#subs.
|
|
429
|
-
return () => this.#subs.done.delete(cb);
|
|
459
|
+
return this.#subs.addDone(cb);
|
|
430
460
|
}
|
|
431
461
|
settled() {
|
|
432
462
|
return this.#queue.settled();
|
|
433
463
|
}
|
|
434
464
|
send(event) {
|
|
435
465
|
this.#dispatch(event);
|
|
466
|
+
this.#emitChangeIfDirty();
|
|
467
|
+
}
|
|
468
|
+
#emitChangeIfDirty() {
|
|
469
|
+
if (this.state === this.#lastState && !this.#contextWritten) return;
|
|
470
|
+
this.#lastState = this.state;
|
|
471
|
+
this.#contextWritten = false;
|
|
472
|
+
this.#subs.emitChange(this.snapshot());
|
|
436
473
|
}
|
|
437
474
|
#dispatch(event) {
|
|
438
475
|
if (this.state.isFinal) return;
|
|
@@ -445,7 +482,7 @@ var Actor = class {
|
|
|
445
482
|
}
|
|
446
483
|
#applyStateStep(event, transition) {
|
|
447
484
|
const step = transition(event, {
|
|
448
|
-
context: this.#
|
|
485
|
+
context: this.#contextHandle,
|
|
449
486
|
actor: this
|
|
450
487
|
});
|
|
451
488
|
if (step.emit) this.#queue.push(...step.emit);
|
|
@@ -457,7 +494,7 @@ var Actor = class {
|
|
|
457
494
|
}
|
|
458
495
|
#applyAnyStep(event, transition, allowTransition) {
|
|
459
496
|
const step = transition(event, {
|
|
460
|
-
context: this.#
|
|
497
|
+
context: this.#contextHandle,
|
|
461
498
|
actor: this
|
|
462
499
|
});
|
|
463
500
|
if (step.state && allowTransition) this.#applyTransition(event, step);
|
|
@@ -468,7 +505,7 @@ var Actor = class {
|
|
|
468
505
|
return false;
|
|
469
506
|
}
|
|
470
507
|
snapshot() {
|
|
471
|
-
return buildSnapshot(this.state, this.#regions);
|
|
508
|
+
return buildSnapshot(this.state, this.#regions, this.#context);
|
|
472
509
|
}
|
|
473
510
|
#pushEvent(event) {
|
|
474
511
|
this.#queue.push(event);
|
|
@@ -484,7 +521,6 @@ var Actor = class {
|
|
|
484
521
|
if (!resolved) return;
|
|
485
522
|
this.state = resolved.state;
|
|
486
523
|
this.#runEffects(event, resolved.payload);
|
|
487
|
-
this.#subs.emitChange(this.snapshot());
|
|
488
524
|
if (this.state.isFinal) this.#subs.emitDone();
|
|
489
525
|
}
|
|
490
526
|
#runEffects(event, statePayload) {
|
|
@@ -498,7 +534,7 @@ var Actor = class {
|
|
|
498
534
|
state: this.state,
|
|
499
535
|
statePayload,
|
|
500
536
|
event,
|
|
501
|
-
context: this.#
|
|
537
|
+
context: this.#contextHandle,
|
|
502
538
|
emit: (e) => {
|
|
503
539
|
this.#queue.push(e);
|
|
504
540
|
this.#drainInternal();
|
|
@@ -521,13 +557,13 @@ var Actor = class {
|
|
|
521
557
|
return false;
|
|
522
558
|
}
|
|
523
559
|
count++;
|
|
524
|
-
if (this.#internalIds.has(event.id)) this.#dispatch(event);
|
|
525
|
-
else if (this.#inputIds.has(event.id)) this.#dispatch(event);
|
|
560
|
+
if (this.#internalIds.has(event.id) || this.#inputIds.has(event.id)) this.#dispatch(event);
|
|
526
561
|
else if (this.#outputHandler) this.#outputHandler(event);
|
|
527
562
|
return true;
|
|
528
563
|
});
|
|
529
564
|
} finally {
|
|
530
565
|
this.#draining = false;
|
|
566
|
+
this.#emitChangeIfDirty();
|
|
531
567
|
}
|
|
532
568
|
if (budgetExceeded) console.warn(`[Actor] internal event budget (${this.#internalBudget}) exceeded — possible emit loop. Actor halting.`);
|
|
533
569
|
}
|
|
@@ -554,4 +590,4 @@ var EventRef = class {
|
|
|
554
590
|
}
|
|
555
591
|
};
|
|
556
592
|
//#endregion
|
|
557
|
-
export { Actor, EventRef, RealClock, StateRef, VirtualClock, event, state };
|
|
593
|
+
export { Actor, Context, EventRef, RealClock, StateRef, VirtualClock, event, state };
|
package/dist/internal.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as InternalEvent, t as AnyActor } from "./actor-internal-
|
|
1
|
+
import { s as InternalEvent, t as AnyActor } from "./actor-internal-CBU_EDPZ.mjs";
|
|
2
2
|
import { Either } from "@mantaq/utils";
|
|
3
3
|
//#region src/internal-registry.d.ts
|
|
4
4
|
interface ActorInternal {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mantaq/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "State machine runtime with actor model, event system, state hierarchy, effects, and virtual clock.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"vite": "npm:@voidzero-dev/vite-plus-core@0.2.8",
|
|
34
34
|
"vite-plus": "0.2.8",
|
|
35
35
|
"vitest": "4.1.10",
|
|
36
|
-
"@mantaq/pbt": "0.0.
|
|
36
|
+
"@mantaq/pbt": "0.0.2"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "vp pack",
|