@mantaq/core 0.4.0 → 0.5.1
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 +7 -4
- package/dist/index.d.mts +62 -79
- package/dist/index.mjs +1 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ npm install @mantaq/core
|
|
|
12
12
|
|
|
13
13
|
| Pattern | Correct | Anti-pattern |
|
|
14
14
|
| --------------- | -------------------------------------------------- | ------------------------------------- |
|
|
15
|
-
| Type context | `
|
|
15
|
+
| Type context | `const c: MyContext = {...}`, `context: c` | `as` cast on the context value |
|
|
16
16
|
| Write context | `const s = context.get(); s.x = y; context.set(s)` | mutate without `set()` |
|
|
17
17
|
| Type events | `event("ID")<Payload>()` | `event("ID")()` without generic |
|
|
18
18
|
| Send events | `actor.send(signInEvent.create(data))` | raw `{ type: "ID", payload }` objects |
|
|
@@ -81,7 +81,7 @@ See [anderscan.github.io/mantaq](https://anderscan.github.io/mantaq) for full do
|
|
|
81
81
|
|
|
82
82
|
### Typed Actor Context
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
Declare the context value with its type once, then pass it to the constructor. Handlers receive the typed context automatically. `as` on the context is an anti-pattern: it hides missing fields.
|
|
85
85
|
|
|
86
86
|
```ts
|
|
87
87
|
interface AuthContext {
|
|
@@ -89,11 +89,13 @@ interface AuthContext {
|
|
|
89
89
|
phoneNumber?: string;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
const initialContext: AuthContext = {};
|
|
93
|
+
|
|
92
94
|
const actor = new Actor({
|
|
93
95
|
inputs: [signInEvent],
|
|
94
96
|
states: [idleState, signingInState],
|
|
95
97
|
initial: idleState,
|
|
96
|
-
context:
|
|
98
|
+
context: initialContext,
|
|
97
99
|
setup: (m) => {
|
|
98
100
|
m.on(idleState, signInEvent, (event, opts) => {
|
|
99
101
|
// ✅ typed — context.get()/set() flow the constructor type
|
|
@@ -299,12 +301,13 @@ const doneEvent = event("WORK_DONE")();
|
|
|
299
301
|
const failedEvent = event("WORK_FAILED")<{ error: string }>();
|
|
300
302
|
|
|
301
303
|
function createActor() {
|
|
304
|
+
const initialContext: MyContext = { retryCount: 0, maxRetries: 3 };
|
|
302
305
|
return new Actor({
|
|
303
306
|
inputs: [startEvent],
|
|
304
307
|
internal: [doneEvent, failedEvent],
|
|
305
308
|
states: [idleState, workingState, doneState, errorState],
|
|
306
309
|
initial: idleState,
|
|
307
|
-
context:
|
|
310
|
+
context: initialContext,
|
|
308
311
|
setup: (m) => {
|
|
309
312
|
m.effect(workingState, {
|
|
310
313
|
name: "attemptWork",
|
package/dist/index.d.mts
CHANGED
|
@@ -1,28 +1,3 @@
|
|
|
1
|
-
//#region src/event.d.ts
|
|
2
|
-
declare function event<const T extends string>(type: T): <Payload extends object | void = void>() => EventRef<T, Payload>;
|
|
3
|
-
interface EventRef<T extends string = string, Payload extends object | void = void> {
|
|
4
|
-
readonly type: T;
|
|
5
|
-
is(anyEvent: unknown): anyEvent is CreatedOfEvent<T, Payload>;
|
|
6
|
-
create(): Payload extends void ? {
|
|
7
|
-
type: T;
|
|
8
|
-
} : void;
|
|
9
|
-
create(payload: Payload): Payload extends void ? {
|
|
10
|
-
type: T;
|
|
11
|
-
} : {
|
|
12
|
-
type: T;
|
|
13
|
-
payload: Payload;
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
type AnyEventRef = EventRef<string, object | void>;
|
|
17
|
-
type CreatedOfEvent<T extends string, P> = P extends void ? {
|
|
18
|
-
type: T;
|
|
19
|
-
} : {
|
|
20
|
-
type: T;
|
|
21
|
-
payload: P;
|
|
22
|
-
};
|
|
23
|
-
declare function EventRef<const T extends string, Payload extends object | void = void>(type: T): EventRef<T, Payload>;
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/clock.d.ts
|
|
26
1
|
interface Clock {
|
|
27
2
|
setTimeout(ms: number, options: ClockTimerOptions): number;
|
|
28
3
|
clearTimeout(id: number): void;
|
|
@@ -41,27 +16,23 @@ interface ClockIntervalOptions {
|
|
|
41
16
|
cb: () => void;
|
|
42
17
|
signal?: AbortSignal;
|
|
43
18
|
}
|
|
44
|
-
|
|
45
|
-
//#region src/context.d.ts
|
|
46
|
-
interface Context<T> {
|
|
19
|
+
export interface Context<T> {
|
|
47
20
|
get(): T;
|
|
48
21
|
set(value: T): void;
|
|
49
22
|
}
|
|
50
23
|
/** Two-way handle over an owner's context: reads see live values, writes flag dirty state upstream. */
|
|
51
|
-
declare function Context<T>(options: {
|
|
24
|
+
export declare function Context<T>(options: {
|
|
52
25
|
get: () => T;
|
|
53
26
|
set: (value: T) => void;
|
|
54
27
|
}): Context<T>;
|
|
55
|
-
|
|
56
|
-
//#region src/state.d.ts
|
|
57
|
-
declare function state<const T extends string>(name: T): <Payload = unknown>() => StateRef<T, Payload, false>;
|
|
28
|
+
export declare function state<const T extends string>(name: T): <Payload = unknown>() => StateRef<T, Payload, false>;
|
|
58
29
|
type AnyStateRef = StateRef<string, unknown, boolean>;
|
|
59
30
|
interface RegionOptions {
|
|
60
31
|
initial: string;
|
|
61
32
|
states: Record<string, AnyStateRef>;
|
|
62
33
|
}
|
|
63
34
|
type RegionsOptions = Record<string, RegionOptions>;
|
|
64
|
-
interface StateRef<T extends string = string, Payload = unknown, IsFinal extends boolean = false> {
|
|
35
|
+
export interface StateRef<T extends string = string, Payload = unknown, IsFinal extends boolean = false> {
|
|
65
36
|
readonly name: T;
|
|
66
37
|
readonly isFinal: IsFinal;
|
|
67
38
|
/** @internal */ _regions?: RegionsOptions;
|
|
@@ -72,17 +43,15 @@ interface StateRef<T extends string = string, Payload = unknown, IsFinal extends
|
|
|
72
43
|
payload: Payload;
|
|
73
44
|
};
|
|
74
45
|
}
|
|
75
|
-
declare function isStateRef(value: unknown): value is StateRef;
|
|
76
|
-
declare function StateRef<T extends string, Payload = unknown, IsFinal extends boolean = false>(name: T, options: {
|
|
46
|
+
export declare function isStateRef(value: unknown): value is StateRef;
|
|
47
|
+
export declare function StateRef<T extends string, Payload = unknown, IsFinal extends boolean = false>(name: T, options: {
|
|
77
48
|
isFinal: IsFinal;
|
|
78
49
|
}): StateRef<T, Payload, IsFinal>;
|
|
79
|
-
//#endregion
|
|
80
|
-
//#region src/actor-types.d.ts
|
|
81
50
|
type CreatedOf<E extends EventRef<string, object | void>> = E extends EventRef<infer Type, infer P> ? CreatedOfEvent<Type, P> : never;
|
|
82
51
|
type NonFinalStateRef<States extends AnyStateRef[]> = Extract<States[number], {
|
|
83
52
|
isFinal: false;
|
|
84
53
|
}>;
|
|
85
|
-
interface EffectInput<ActorContext, Payload = unknown> {
|
|
54
|
+
interface EffectInput<ActorContext, Payload = unknown, Emit = InternalEvent> {
|
|
86
55
|
signal: AbortSignal;
|
|
87
56
|
state: {
|
|
88
57
|
name: string;
|
|
@@ -90,10 +59,10 @@ interface EffectInput<ActorContext, Payload = unknown> {
|
|
|
90
59
|
};
|
|
91
60
|
event: InternalEvent;
|
|
92
61
|
context: Context<ActorContext>;
|
|
93
|
-
emit: (event:
|
|
62
|
+
emit: (event: Emit) => void;
|
|
94
63
|
clock: Clock;
|
|
95
64
|
}
|
|
96
|
-
type EffectFn<ActorContext, Payload = unknown> = (input: EffectInput<ActorContext, Payload>) => void | Promise<void> | {
|
|
65
|
+
type EffectFn<ActorContext, Payload = unknown, Emit = InternalEvent> = (input: EffectInput<ActorContext, Payload, Emit>) => void | Promise<void> | {
|
|
97
66
|
then(onFulfilled: unknown, onRejected: unknown): unknown;
|
|
98
67
|
};
|
|
99
68
|
type ErrorReason = "transition" | "effect" | "budget" | "output" | "internal" | "async" | "unhandled";
|
|
@@ -124,8 +93,6 @@ type TransitionResult<AllowedState extends AnyStateRef = AnyStateRef, AllowedEmi
|
|
|
124
93
|
payload?: unknown;
|
|
125
94
|
}>;
|
|
126
95
|
};
|
|
127
|
-
//#endregion
|
|
128
|
-
//#region src/actor-internal.d.ts
|
|
129
96
|
interface Snapshot<C = unknown> {
|
|
130
97
|
path: string[];
|
|
131
98
|
context: C;
|
|
@@ -153,6 +120,7 @@ interface AnyActor<C = Record<string, unknown>> {
|
|
|
153
120
|
context?: C;
|
|
154
121
|
options?: {
|
|
155
122
|
transitions?: Record<string, Record<string, unknown>>;
|
|
123
|
+
targets?: Record<string, Record<string, string[]>>;
|
|
156
124
|
effects?: Record<string, unknown[]>;
|
|
157
125
|
states?: ReadonlyArray<{
|
|
158
126
|
name: string;
|
|
@@ -162,53 +130,74 @@ interface AnyActor<C = Record<string, unknown>> {
|
|
|
162
130
|
inject(event: InternalEvent): void;
|
|
163
131
|
dispose(): void;
|
|
164
132
|
}
|
|
165
|
-
//#endregion
|
|
166
|
-
//#region src/parse-handler.d.ts
|
|
167
133
|
type RuntimeTransitionHandler<States extends readonly AnyStateRef[], ActorContext> = (event: InternalEvent, options: {
|
|
168
134
|
context: Context<ActorContext>;
|
|
169
135
|
actor: AnyActor<ActorContext>;
|
|
170
136
|
}) => TransitionResult<States[number], string>;
|
|
171
|
-
//#endregion
|
|
172
|
-
//#region src/builder.d.ts
|
|
173
137
|
type EventTypeOf<E extends AnyEventRef> = E extends EventRef<infer Type, object | void> ? Type : never;
|
|
174
138
|
type PayloadOf<S extends AnyStateRef> = S extends StateRef<infer _Name, infer Payload, infer _IsFinal> ? Payload : never;
|
|
175
139
|
type TransitionHandler<States extends readonly AnyStateRef[], ActorContext> = RuntimeTransitionHandler<States, ActorContext>;
|
|
176
140
|
interface EffectEntry<ActorContext> {
|
|
177
141
|
name: string;
|
|
142
|
+
sends?: string[];
|
|
178
143
|
fn: EffectFn<ActorContext>;
|
|
179
144
|
}
|
|
145
|
+
type EmitOf<E> = E extends readonly AnyEventRef[] ? CreatedOf<E[number]> : InternalEvent;
|
|
146
|
+
type SendList<I extends readonly AnyEventRef[]> = readonly I[number][] | undefined;
|
|
180
147
|
interface BuiltMaps<States extends readonly AnyStateRef[], ActorContext> {
|
|
181
148
|
transitions: Record<string, Record<string, TransitionHandler<States, ActorContext>>>;
|
|
149
|
+
/** Declared `to` state names per `[state][event]`; `Any` keys `onAny`. Static graph for tooling. */
|
|
150
|
+
targets: Record<string, Record<string, string[]>>;
|
|
182
151
|
effects: Record<string, Array<EffectEntry<ActorContext>>>;
|
|
183
152
|
}
|
|
184
|
-
|
|
153
|
+
/** Handler may only return states listed in `to`; no `to` means it can only stay. */
|
|
154
|
+
type HandlerFn<To extends AnyStateRef, Outputs extends readonly AnyEventRef[], ActorContext, E extends AnyEventRef> = (event: E extends EventRef<infer Type, infer P> ? CreatedOfEvent<Type, P> : never, opts: {
|
|
185
155
|
context: Context<ActorContext>;
|
|
186
156
|
actor: AnyActor<ActorContext>;
|
|
187
|
-
}) => TransitionResult<
|
|
157
|
+
}) => TransitionResult<To, EventTypeOf<Outputs[number]>>;
|
|
158
|
+
interface HandlerOptions<To extends readonly AnyStateRef[], Outputs extends readonly AnyEventRef[], ActorContext, E extends AnyEventRef> {
|
|
159
|
+
event: E;
|
|
160
|
+
to?: To;
|
|
161
|
+
handler: HandlerFn<NoInfer<To[number]>, Outputs, ActorContext, E>;
|
|
162
|
+
}
|
|
188
163
|
interface ActorBuilder<States extends readonly AnyStateRef[], Inputs extends readonly AnyEventRef[], Internal extends readonly AnyEventRef[], Outputs extends readonly AnyEventRef[], ActorContext> {
|
|
189
|
-
on<S extends States[number], E extends Inputs[number] | Internal[number]>(stateRef: S, options:
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
onAny<E extends Inputs[number] | Internal[number]>(options: {
|
|
194
|
-
eventRef: E;
|
|
195
|
-
handler: HandlerFn<States, Inputs | Internal, Outputs, ActorContext, E>;
|
|
196
|
-
}): ActorBuilder<States, Inputs, Internal, Outputs, ActorContext>;
|
|
197
|
-
effect<S extends States[number]>(stateRef: S, definition: {
|
|
164
|
+
on<S extends States[number], E extends Inputs[number] | Internal[number], const To extends readonly States[number][] = readonly []>(stateRef: S, options: HandlerOptions<To, Outputs, ActorContext, E>): ActorBuilder<States, Inputs, Internal, Outputs, ActorContext>;
|
|
165
|
+
onAny<E extends Inputs[number] | Internal[number], const To extends readonly States[number][] = readonly []>(options: HandlerOptions<To, Outputs, ActorContext, E>): ActorBuilder<States, Inputs, Internal, Outputs, ActorContext>;
|
|
166
|
+
/** `sends`: internal events `fn` may emit; `emit` only accepts those. Omit for untyped `emit`. */
|
|
167
|
+
effect<S extends States[number], const E extends SendList<Internal> = undefined>(stateRef: S, definition: {
|
|
198
168
|
name: string;
|
|
199
|
-
|
|
169
|
+
sends?: E;
|
|
170
|
+
fn: EffectFn<ActorContext, PayloadOf<S>, EmitOf<E>>;
|
|
200
171
|
}): ActorBuilder<States, Inputs, Internal, Outputs, ActorContext>;
|
|
201
172
|
/** @internal */
|
|
202
173
|
build(): BuiltMaps<States, ActorContext>;
|
|
203
174
|
}
|
|
204
175
|
declare function ActorBuilder<States extends readonly AnyStateRef[], Inputs extends readonly AnyEventRef[], Internal extends readonly AnyEventRef[], Outputs extends readonly AnyEventRef[], ActorContext>(): ActorBuilder<States, Inputs, Internal, Outputs, ActorContext>;
|
|
205
176
|
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;
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
177
|
+
export declare function event<const T extends string>(type: T): <Payload extends object | void = void>() => EventRef<T, Payload>;
|
|
178
|
+
export interface EventRef<T extends string = string, Payload extends object | void = void> {
|
|
179
|
+
readonly type: T;
|
|
180
|
+
is(anyEvent: unknown): anyEvent is CreatedOfEvent<T, Payload>;
|
|
181
|
+
create(): Payload extends void ? {
|
|
182
|
+
type: T;
|
|
183
|
+
} : void;
|
|
184
|
+
create(payload: Payload): Payload extends void ? {
|
|
185
|
+
type: T;
|
|
186
|
+
} : {
|
|
187
|
+
type: T;
|
|
188
|
+
payload: Payload;
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
type AnyEventRef = EventRef<string, object | void>;
|
|
192
|
+
type CreatedOfEvent<T extends string, P> = P extends void ? {
|
|
193
|
+
type: T;
|
|
194
|
+
} : {
|
|
195
|
+
type: T;
|
|
196
|
+
payload: P;
|
|
197
|
+
};
|
|
198
|
+
export declare function EventRef<const T extends string, Payload extends object | void = void>(type: T): EventRef<T, Payload>;
|
|
199
|
+
export declare function RealClock(): Clock;
|
|
200
|
+
export interface VirtualClock {
|
|
212
201
|
now(): number;
|
|
213
202
|
setTimeout(ms: number, options: ClockTimerOptions): number;
|
|
214
203
|
clearTimeout(id: number): void;
|
|
@@ -224,11 +213,7 @@ interface VirtualClock {
|
|
|
224
213
|
}>;
|
|
225
214
|
setDrain(fn: () => void): void;
|
|
226
215
|
}
|
|
227
|
-
declare function VirtualClock(): VirtualClock;
|
|
228
|
-
//#endregion
|
|
229
|
-
//#region src/actor.d.ts
|
|
230
|
-
type CreatedOf$1<E extends AnyEventRef$1> = E extends EventRef<infer Type, infer P> ? CreatedOfEvent<Type, P> : never;
|
|
231
|
-
type AnyEventRef$1 = AnyEventRef;
|
|
216
|
+
export declare function VirtualClock(): VirtualClock;
|
|
232
217
|
type InitialState<S extends AnyStateRef> = S extends StateRef<infer _N extends string, infer P, infer _I extends boolean> ? [unknown] extends [P] ? S | {
|
|
233
218
|
state: S;
|
|
234
219
|
payload?: P;
|
|
@@ -236,7 +221,7 @@ type InitialState<S extends AnyStateRef> = S extends StateRef<infer _N extends s
|
|
|
236
221
|
state: S;
|
|
237
222
|
payload: P;
|
|
238
223
|
} : never;
|
|
239
|
-
interface ActorOptions<States extends readonly AnyStateRef[], Inputs extends readonly AnyEventRef
|
|
224
|
+
interface ActorOptions<States extends readonly AnyStateRef[], Inputs extends readonly AnyEventRef[], Internal extends readonly AnyEventRef[], Outputs extends readonly AnyEventRef[], ActorContext = Record<string, unknown>> {
|
|
240
225
|
inputs: Inputs;
|
|
241
226
|
outputs?: Outputs;
|
|
242
227
|
internal?: Internal;
|
|
@@ -248,8 +233,9 @@ interface ActorOptions<States extends readonly AnyStateRef[], Inputs extends rea
|
|
|
248
233
|
setup: SetupFn<States, Inputs, Internal, Outputs, ActorContext>;
|
|
249
234
|
regions?: Record<string, AnyActor>;
|
|
250
235
|
}
|
|
251
|
-
interface InternalActorOptions<States extends readonly AnyStateRef[], Inputs extends readonly AnyEventRef
|
|
236
|
+
interface InternalActorOptions<States extends readonly AnyStateRef[], Inputs extends readonly AnyEventRef[], Internal extends readonly AnyEventRef[], Outputs extends readonly AnyEventRef[], ActorContext = Record<string, unknown>> extends Omit<ActorOptions<States, Inputs, Internal, Outputs, ActorContext>, "setup"> {
|
|
252
237
|
transitions: TransitionDispatch<States, ActorContext>;
|
|
238
|
+
targets: Record<string, Record<string, string[]>>;
|
|
253
239
|
effects: Record<string, Array<EffectEntry<ActorContext>>>;
|
|
254
240
|
}
|
|
255
241
|
type TransitionDispatch<States extends readonly AnyStateRef[], ActorContext> = Record<string, Record<string, TransitionStepFn<States, ActorContext> | undefined>>;
|
|
@@ -257,7 +243,7 @@ type TransitionStepFn<States extends readonly AnyStateRef[], ActorContext> = (ev
|
|
|
257
243
|
context: Context<ActorContext>;
|
|
258
244
|
actor: AnyActor<ActorContext>;
|
|
259
245
|
}) => TransitionResult<States[number], string>;
|
|
260
|
-
interface Actor<States extends readonly AnyStateRef[], Inputs extends readonly AnyEventRef
|
|
246
|
+
export interface Actor<States extends readonly AnyStateRef[], Inputs extends readonly AnyEventRef[], Internal extends readonly AnyEventRef[] = readonly [], Outputs extends readonly AnyEventRef[] = readonly [], ActorContext = Record<string, unknown>> extends AnyActor<ActorContext> {
|
|
261
247
|
state: States[number] | ErrorState;
|
|
262
248
|
readonly clock: Clock;
|
|
263
249
|
readonly context: ActorContext;
|
|
@@ -268,7 +254,7 @@ interface Actor<States extends readonly AnyStateRef[], Inputs extends readonly A
|
|
|
268
254
|
}): () => void;
|
|
269
255
|
settled(): Promise<void>;
|
|
270
256
|
pendingEffectCount(): number;
|
|
271
|
-
send(event: CreatedOf
|
|
257
|
+
send(event: CreatedOf<Inputs[number]>): void;
|
|
272
258
|
recover(target: {
|
|
273
259
|
state: States[number];
|
|
274
260
|
context: ActorContext;
|
|
@@ -277,12 +263,9 @@ interface Actor<States extends readonly AnyStateRef[], Inputs extends readonly A
|
|
|
277
263
|
inject(event: InternalEvent): void;
|
|
278
264
|
dispose(): void;
|
|
279
265
|
}
|
|
280
|
-
declare function Actor<const States extends readonly AnyStateRef[], const Inputs extends readonly AnyEventRef
|
|
281
|
-
|
|
282
|
-
//#region src/index.d.ts
|
|
283
|
-
type InternalEvent = {
|
|
266
|
+
export declare function 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>>(options: ActorOptions<States, Inputs, Internal, Outputs, ActorContext>): Actor<States, Inputs, Internal, Outputs, ActorContext>;
|
|
267
|
+
export type InternalEvent = {
|
|
284
268
|
type: string;
|
|
285
269
|
payload?: unknown;
|
|
286
270
|
};
|
|
287
|
-
|
|
288
|
-
export { Actor, type ActorBuilder, type ActorOptions, type AnyActor, type AnyEventRef, type AnyStateRef, type BuiltMaps, type Clock, Context, type CreatedOf, type CreatedOfEvent, type EffectFn, type EffectInput, type ErrorInfo, type ErrorReason, type ErrorState, EventRef, type EventTypeOf, type InitialState, InternalEvent, type NonFinalStateRef, type PayloadOf, RealClock, type SetupFn, type Snapshot, StateRef, type TransitionHandler, type TransitionInfo, type TransitionResult, VirtualClock, event, isStateRef, state };
|
|
271
|
+
export type { ActorBuilder, ActorOptions, AnyActor, AnyEventRef, AnyStateRef, BuiltMaps, Clock, CreatedOf, CreatedOfEvent, EffectFn, EffectInput, ErrorInfo, ErrorReason, ErrorState, EventTypeOf, InitialState, NonFinalStateRef, PayloadOf, SetupFn, Snapshot, TransitionHandler, TransitionInfo, TransitionResult };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Either as e}from"@mantaq/utils";function t(e){let t=e;return typeof t==`function`?t:()=>({})}function n(e){return e}function r(){let e={},r={},i={on(n,{eventRef:r,handler:a}){let o=n.name,s=r.type;return(e[o]??={})[s]=t(a),i},onAny(n){let r=n.eventRef.type;return(e.Any??={})[r]=t(n.handler),i},effect(e,{name:t,fn:a}){return(r[e.name]??=[]).push({name:t,fn:n(a)}),i},build(){return{transitions:e,effects:r}}};return i}function i(e){return{get:e.get,set:e.set}}function a(e){return()=>c(e,{isFinal:!1})}const o=new WeakSet;function s(e){return typeof e==`object`&&!!e&&o.has(e)}function c(e,t){let n={name:e,isFinal:t.isFinal,regions(e){return n._regions=e,n},final(){let e=c(n.name,{isFinal:!0});return e._regions=n._regions,e},create(e){return{state:n,payload:e}}};return o.add(n),n}function l(e){let t=e.state;if(t)return`state`in t?{state:t.state,payload:t.payload}:{state:t,payload:e.payload}}function u(e){if(e instanceof Promise)return!0;let t=e;return typeof t==`object`&&!!t&&typeof t.then==`function`}function d(t){let n=[],r=[],i=t.effects[t.state.name];if(!i)return{pending:n,ran:r};for(let{name:a,fn:o}of i){if(t.abort.signal.aborted)break;let i,s=e.from(()=>(i=o({signal:t.abort.signal,state:{name:t.state.name,payload:t.statePayload},event:t.event,context:t.context,emit:t.emit,clock:t.clock}),!0));if(s[0]!==void 0){t.onError(s[0],t.lastGood);break}if(r.push(a),u(i)){let e=Promise.resolve(i).then(()=>void 0,e=>{t.abort.signal.aborted||t.onError(e,t.lastGood)});n.push(e)}}return{pending:n,ran:r}}function ee(e){return e??{}}function f(){let e=[],t=0,n=!1,r=!1,i=[];function a(){let e=i.splice(0);for(let t of e)t()}function o(i){if(!n){n=!0;try{for(;t<e.length&&!r;){let n=e[t];if(t++,!i(n)){r=!0;break}}}finally{e.length=0,t=0,n=!1,r=!1,a()}}}return{get length(){return e.length-t},push(...t){r||e.push(...t)},clear(){e.length=0,t=0,a()},settled(){return e.length-t===0&&!n?Promise.resolve():new Promise(e=>{i.push(e)})},processCancellable(e){o(e)}}}function p(){let e=Date.now(),t=new Map;function n(e){let n=t.get(e);n&&(n.signal.removeEventListener(`abort`,n.onAbort),t.delete(e))}return{now(){return Date.now()-e},setTimeout(e,{signal:r,cb:i}){if(r?.aborted)return-1;let a=Number(globalThis.setTimeout(()=>{n(a),i()},e));if(r){function e(){globalThis.clearTimeout(a),n(a)}t.set(a,{signal:r,onAbort:e}),r.addEventListener(`abort`,e,{once:!0})}return a},clearTimeout(e){globalThis.clearTimeout(e),n(e)},setInterval(e,{signal:r,cb:i}){if(r?.aborted)return-1;let a=Number(globalThis.setInterval(i,e));if(r){function e(){globalThis.clearInterval(a),n(a)}t.set(a,{signal:r,onAbort:e}),r.addEventListener(`abort`,e,{once:!0})}return a},clearInterval(e){globalThis.clearInterval(e),n(e)}}}function m(e){let{stateRef:t,regions:n,context:r}=e,i=[t.name],a={};for(let[e,t]of Object.entries(n))a[e]=t.snapshot();let o={path:i,context:r,regions:a};return e.payload!==void 0&&(o.payload=e.payload),t.isFinal&&(o.done=!0),e.error!==void 0&&(o.error={...e.error,context:h(e.error.context)}),o}function h(e){return typeof structuredClone==`function`?structuredClone(e):JSON.parse(JSON.stringify(e))}function g(){let t=new Set,n=new Set,r=new Set,i=new Set,a=new Set,o;function s(t){e.from(()=>(t(),!0))}return{change:t,done:n,transition:r,error:i,output:a,seed(e){o=e},addChange(e){t.add(e);let n=o;return n&&s(()=>e(n,n)),()=>t.delete(e)},addDone(e){return n.add(e),()=>n.delete(e)},addTransition(e){return r.add(e),()=>r.delete(e)},addError(e){i.add(e);let t=o?.error;return t&&s(()=>e(t)),()=>i.delete(e)},addOutput(e){return a.add(e),()=>a.delete(e)},emitChange(e){let n=o??e;o=e;for(let r of t)s(()=>r(e,n))},emitDone(){for(let e of n)s(e)},emitTransition(e){for(let t of r)s(()=>t(e))},emitError(e){for(let t of i)s(()=>t(e))},emitOutput(e){for(let t of a)t(e)},clear(){t.clear(),n.clear(),r.clear(),i.clear(),a.clear()}}}function _(e,t){let n=e?()=>{t.entries.delete(t.timerId)}:void 0;return e&&n&&e.addEventListener(`abort`,n,{once:!0}),n}function v(e){e.signal&&e.onAbort&&e.signal.removeEventListener(`abort`,e.onAbort)}function y(){let e=0,t=new Map,n=new Map,r=1,i=new Set;function a(e,t){if(!Number.isFinite(e))throw RangeError(`[VirtualClock] invalid ${t.method} ms value: ${e}`);return!0}function o(e,t){return a(e,{method:t.method}),e<=0?+!!t.interval:e}function s(e){let r=e,i=!1;for(let n of t.values())n.deadline<=e&&n.deadline<=r&&(r=n.deadline,i=!0);for(let t of n.values())t.next<=e&&t.next<=r&&(r=t.next,i=!0);return i?r:void 0}function c(e){let n=[];for(let[r,i]of t)i.deadline===e&&n.push(r);for(let e of n){let n=t.get(e);n&&(v(n),t.delete(e),n.cb())}}function l(t){let r=[];for(let[e,i]of n)i.next===t&&r.push(e);for(let t of r){let r=n.get(t);r&&(r.cb(),n.has(t)&&(r.next=e+r.ms))}}return{now(){return e},setTimeout(n,{signal:i,cb:a,eventName:s}){if(i?.aborted)return-1;let c=r++,l=_(i,{timerId:c,entries:t});return t.set(c,{deadline:e+o(n,{method:`setTimeout`,interval:!1}),cb:a,signal:i,onAbort:l,eventName:s}),c},clearTimeout(e){let n=t.get(e);n&&(v(n),t.delete(e))},setInterval(t,{signal:i,cb:a}){if(i?.aborted)return-1;let s=r++,c=_(i,{timerId:s,entries:n}),l=o(t,{method:`setInterval`,interval:!0});return n.set(s,{ms:l,next:e+l,cb:a,signal:i,onAbort:c}),s},clearInterval(e){let t=n.get(e);t&&(v(t),n.delete(e))},advance(t){a(t,{method:`advance`});let n=e+Math.max(0,t),r=-1,o=0;for(;;){let t=s(n);if(t===void 0)break;if(t===r){if(++o>=1e6)break}else o=0,r=t;e=t,c(t),l(t)}e=n;for(let e of i)e()},hasPending(){return t.size>0||n.size>0},pendingTimers(){let n=[];for(let[r,i]of t)n.push({id:r,deadline:i.deadline,ms:i.deadline-e,eventName:i.eventName});return n},setDrain(e){i.add(e)}}}function b(e){return`state`in e?e.state:e}function x(e,t){if(!e.has(t.candidate.name))throw Error(`[Actor] initial state "${t.candidate.name}" not found in declared states [${[...e].join(`, `)}]`);return!0}function S(t){let n=r();t.setup(n);let a=n.build(),o={...t,transitions:a.transitions,effects:a.effects},u=new Set((t.internal??[]).map(e=>e.type)),_=new Set(t.inputs.map(e=>e.type)),v=t.internalBudget??1e4,y=t.clock??p();y.setDrain?.(Y);let S,C,w=ee(t.context),T,E=!0,D,O={},k=f(),A=g(),j,M=!1,N=[],P,F,I=!1,L=!1,R=c(`__error`,{isFinal:!0}),z=i({get:()=>w,set:e=>{w=e,L=!0,E=!0}}),B=b(t.initial);x(new Set(t.states.map(e=>e.name)),{candidate:B}),S=B;let V=t.initial;if(C=!s(V)&&`payload`in V?V.payload:void 0,D=B,t.regions)for(let[e,n]of Object.entries(t.regions))O[e]=n,n.on(`output`,{fn:e=>{k.push(e),Y()}});let H={get state(){return S},clock:y,get regions(){return O},get context(){return w},get options(){return o},on(e,t){return{change:e=>A.addChange(e),done:e=>A.addDone(e),transition:e=>A.addTransition(e),error:e=>A.addError(e),output:e=>A.addOutput(e)}[e](t.fn)},settled(){return Q()},pendingEffectCount(){return N.length},send(e){I||(G(e),U())},recover:W,snapshot(){return K()},inject(e){ae(e)},dispose(){oe()}};J({type:`__init`},{payloadForState:C}),A.seed(K());function U(){S===D&&!L||(D=S,L=!1,A.emitChange(K()))}function W(e){P===void 0||I||(j?.abort(),j=void 0,k.clear(),k=f(),P=void 0,S=e.state,C=void 0,w=e.context,D=e.state,L=!1,E=!0,T=void 0,F=void 0,N=[],A.emitChange(K()))}function G(e){if(P!==void 0||S.isFinal)return;let t={...e,payload:e.payload??{}},n=S.name,r=F;F={state:S,context:w};try{let r=o.transitions,i=r[S.name]?.[e.type],a=r.Any?.[e.type],s=te(t,{stateTransition:i,anyTransition:a});ne(t,{from:n,handled:!!(i||a),outcome:s}),s.emitted||k.length>0?Y():!i&&!a&&u.has(e.type)&&Z(`unhandled`,{event:e,error:Error(`[Actor] internal event "${e.type}" emitted but no handler in state "${S.name}"`)})}finally{F=r}}function te(e,t){let n=t.stateTransition?re(e,{transition:t.stateTransition}):{applied:!1,target:void 0,effects:void 0};if(P===void 0){let r=ie(e,{transition:t.anyTransition,allowTransition:!n.applied});return{emitted:r.emitted,transitioned:n.applied||r.transitioned,target:n.target??r.target,effects:n.effects??r.effects}}return{emitted:!1,transitioned:!1}}function ne(e,t){P===void 0&&t.handled&&A.emitTransition({event:e,from:t.from,to:t.outcome.target??S.name,transitioned:t.outcome.transitioned,effects:t.outcome.effects??[]})}function re(e,t){let n=!1,r,i;return X(`transition`,{event:e,operation:()=>{let a=t.transition(e,{context:z,actor:$()});if(a.emit&&k.push(...a.emit),a.state){let t=q(e,{step:a});r=t.target,i=t.effects,n=!0}}}),{applied:n,target:r,effects:i}}function ie(e,t){if(t.transition===void 0)return{emitted:!1,transitioned:!1};let n=t.transition,r=!1,i=!1,a,o;return X(`transition`,{event:e,operation:()=>{let s=n(e,{context:z,actor:$()});if(s.state&&t.allowTransition){let t=q(e,{step:s});a=t.target,o=t.effects,i=!0}s.emit&&(k.push(...s.emit),r=!0)}}),{emitted:r,transitioned:i,target:a,effects:o}}function K(){return(T===void 0||E)&&(T=h(w),E=!1),m({stateRef:S,regions:O,context:T,error:P,payload:C})}function q(e,t){if(P!==void 0||!t.step.state)return{};let n=l(t.step);if(!n)return{};if(!s(n.state))return Z(`transition`,{event:e,error:Error(`invalid transition target`)}),{};j?.abort(),S=n.state;let r=S.name;C=n.payload,F={state:S,context:w};let i=J(e,{payloadForState:n.payload});return n.state.isFinal&&P===void 0&&A.emitDone(),{target:r,effects:i}}function J(e,t){if(I)return[];let n=o.effects[S.name];if(!n)return j=void 0,[];let r=new AbortController;j=r;let i=F??{state:S,context:w},a=d({effects:{[S.name]:n},state:S,statePayload:t.payloadForState,event:e,context:z,emit:e=>{P!==void 0||r.signal.aborted||(k.push(e),Y())},clock:y,abort:r,lastGood:i,onError:t=>Z(`effect`,{event:e,error:t})});for(let e of a.pending)N.push(e),e.finally(()=>{let t=N.indexOf(e);t!==-1&&N.splice(t,1)}).catch(()=>{});return a.ran}function Y(){if(!(M||I)){M=!0;try{let e=0;k.processCancellable(t=>{if(P!==void 0)return!1;if(e>=v)return Z(`budget`,{event:t,error:Error(`internal event budget exceeded`)}),!1;if(e++,u.has(t.type)||_.has(t.type))G(t);else if(!X(`output`,{event:t,operation:()=>A.emitOutput(t)}))return!1;return!0})}finally{M=!1,U()}}}function X(t,n){let r=e.from(()=>(n.operation(),!0));return r[0]===void 0||(Z(t,{event:n.event,error:r[0]}),!1)}function Z(e,t){if(P!==void 0)return;let n=t.lastGood??F??{state:S,context:w};P={error:t.error,state:n.state,context:n.context,event:t.event,reason:e},j?.abort(),S=R,C=void 0,D=R,L=!1,A.emitError(P),A.emitChange(K()),A.emitDone()}function ae(e){I||(k.push(e),Y())}function oe(){if(!I){I=!0,j?.abort(),j=void 0;for(let e of Object.values(O))e.dispose();O={},k.clear(),A.clear(),N=[]}}function Q(){return k.settled().then(()=>{if(N.length!==0)return Promise.all(N).then(()=>Q())})}function $(){return H}return H}const C=new Map;function w(e){let t=C.get(e);return t||(t=Symbol(`mantaq:event:${e}`),C.set(e,t)),t}const T=new WeakMap;function E(e){return()=>D(e)}function D(e){let t=w(e),n=function(e){return typeof e==`object`&&!!e&&T.get(e)?.has(t)===!0};function r(n){let r=n===void 0?{type:e}:{type:e,payload:n},i=T.get(r);return i||(i=new Set,T.set(r,i)),i.add(t),r}return{type:e,is:n,create:r}}export{S as Actor,i as Context,D as EventRef,p as RealClock,c as StateRef,y as VirtualClock,E as event,s as isStateRef,a as state};
|
|
1
|
+
import{Either as e}from"@mantaq/utils";function t(e){let t=e;return typeof t==`function`?t:()=>({})}function n(e){return e}function r(){let e={},r={},i={};function a(n,i){let a=i.event.type;(e[n]??={})[a]=t(i.handler),(r[n]??={})[a]=(i.to??[]).map(e=>e.name)}let o={on(e,t){return a(e.name,t),o},onAny(e){return a(`Any`,e),o},effect(e,{name:t,sends:r,fn:a}){return(i[e.name]??=[]).push({name:t,...r&&{sends:r.map(e=>e.type)},fn:n(a)}),o},build(){return{transitions:e,targets:r,effects:i}}};return o}function i(e){return{get:e.get,set:e.set}}function a(e){return()=>c(e,{isFinal:!1})}const o=/* @__PURE__ */ new WeakSet;function s(e){return typeof e==`object`&&!!e&&o.has(e)}function c(e,t){let n={name:e,isFinal:t.isFinal,regions(e){return n._regions=e,n},final(){let e=c(n.name,{isFinal:!0});return e._regions=n._regions,e},create(e){return{state:n,payload:e}}};return o.add(n),n}function l(e){let t=e.state;if(t)return`state`in t?{state:t.state,payload:t.payload}:{state:t,payload:e.payload}}function u(e){if(e instanceof Promise)return!0;let t=e;return typeof t==`object`&&!!t&&typeof t.then==`function`}function ee(t){let n=[],r=[],i=t.effects[t.state.name];if(!i)return{pending:n,ran:r};for(let{name:a,fn:o}of i){if(t.abort.signal.aborted)break;let i,s=e.from(()=>(i=o({signal:t.abort.signal,state:{name:t.state.name,payload:t.statePayload},event:t.event,context:t.context,emit:t.emit,clock:t.clock}),!0));if(s[0]!==void 0){t.onError(s[0],t.lastGood);break}if(r.push(a),u(i)){let e=Promise.resolve(i).then(()=>void 0,e=>{t.abort.signal.aborted||t.onError(e,t.lastGood)});n.push(e)}}return{pending:n,ran:r}}function d(e){return e??{}}function f(){let e=[],t=0,n=!1,r=!1,i=[];function a(){let e=i.splice(0);for(let t of e)t()}function o(i){if(!n){n=!0;try{for(;t<e.length&&!r;){let n=e[t];if(t++,!i(n)){r=!0;break}}}finally{e.length=0,t=0,n=!1,r=!1,a()}}}return{get length(){return e.length-t},push(...t){r||e.push(...t)},clear(){e.length=0,t=0,a()},settled(){return e.length-t===0&&!n?Promise.resolve():new Promise(e=>{i.push(e)})},processCancellable(e){o(e)}}}function p(){let e=Date.now(),t=/* @__PURE__ */ new Map;function n(e){let n=t.get(e);n&&(n.signal.removeEventListener(`abort`,n.onAbort),t.delete(e))}return{now(){return Date.now()-e},setTimeout(e,{signal:r,cb:i}){if(r?.aborted)return-1;let a=Number(globalThis.setTimeout(()=>{n(a),i()},e));if(r){function e(){globalThis.clearTimeout(a),n(a)}t.set(a,{signal:r,onAbort:e}),r.addEventListener(`abort`,e,{once:!0})}return a},clearTimeout(e){globalThis.clearTimeout(e),n(e)},setInterval(e,{signal:r,cb:i}){if(r?.aborted)return-1;let a=Number(globalThis.setInterval(i,e));if(r){function e(){globalThis.clearInterval(a),n(a)}t.set(a,{signal:r,onAbort:e}),r.addEventListener(`abort`,e,{once:!0})}return a},clearInterval(e){globalThis.clearInterval(e),n(e)}}}function te(e){let{stateRef:t,regions:n,context:r}=e,i=[t.name],a={};for(let[e,t]of Object.entries(n))a[e]=t.snapshot();let o={path:i,context:r,regions:a};return e.payload!==void 0&&(o.payload=e.payload),t.isFinal&&(o.done=!0),e.error!==void 0&&(o.error={...e.error,context:m(e.error.context)}),o}function m(e){return typeof structuredClone==`function`?structuredClone(e):JSON.parse(JSON.stringify(e))}function h(){let t=/* @__PURE__ */ new Set,n=/* @__PURE__ */ new Set,r=/* @__PURE__ */ new Set,i=/* @__PURE__ */ new Set,a=/* @__PURE__ */ new Set,o;function s(t){e.from(()=>(t(),!0))}return{change:t,done:n,transition:r,error:i,output:a,seed(e){o=e},addChange(e){t.add(e);let n=o;return n&&s(()=>e(n,n)),()=>t.delete(e)},addDone(e){return n.add(e),()=>n.delete(e)},addTransition(e){return r.add(e),()=>r.delete(e)},addError(e){i.add(e);let t=o?.error;return t&&s(()=>e(t)),()=>i.delete(e)},addOutput(e){return a.add(e),()=>a.delete(e)},emitChange(e){let n=o??e;o=e;for(let r of t)s(()=>r(e,n))},emitDone(){for(let e of n)s(e)},emitTransition(e){for(let t of r)s(()=>t(e))},emitError(e){for(let t of i)s(()=>t(e))},emitOutput(e){for(let t of a)t(e)},clear(){t.clear(),n.clear(),r.clear(),i.clear(),a.clear()}}}function g(e,t){let n=e?()=>{t.entries.delete(t.timerId)}:void 0;return e&&n&&e.addEventListener(`abort`,n,{once:!0}),n}function _(e){e.signal&&e.onAbort&&e.signal.removeEventListener(`abort`,e.onAbort)}function v(){let e=0,t=/* @__PURE__ */ new Map,n=/* @__PURE__ */ new Map,r=1,i=/* @__PURE__ */ new Set;function a(e,t){if(!Number.isFinite(e))throw RangeError(`[VirtualClock] invalid ${t.method} ms value: ${e}`);return!0}function o(e,t){return a(e,{method:t.method}),e<=0?+!!t.interval:e}function s(e){let r=e,i=!1;for(let n of t.values())n.deadline<=e&&n.deadline<=r&&(r=n.deadline,i=!0);for(let t of n.values())t.next<=e&&t.next<=r&&(r=t.next,i=!0);return i?r:void 0}function c(e){let n=[];for(let[r,i]of t)i.deadline===e&&n.push(r);for(let e of n){let n=t.get(e);n&&(_(n),t.delete(e),n.cb())}}function l(t){let r=[];for(let[e,i]of n)i.next===t&&r.push(e);for(let t of r){let r=n.get(t);r&&(r.cb(),n.has(t)&&(r.next=e+r.ms))}}return{now(){return e},setTimeout(n,{signal:i,cb:a,eventName:s}){if(i?.aborted)return-1;let c=r++,l=g(i,{timerId:c,entries:t});return t.set(c,{deadline:e+o(n,{method:`setTimeout`,interval:!1}),cb:a,signal:i,onAbort:l,eventName:s}),c},clearTimeout(e){let n=t.get(e);n&&(_(n),t.delete(e))},setInterval(t,{signal:i,cb:a}){if(i?.aborted)return-1;let s=r++,c=g(i,{timerId:s,entries:n}),l=o(t,{method:`setInterval`,interval:!0});return n.set(s,{ms:l,next:e+l,cb:a,signal:i,onAbort:c}),s},clearInterval(e){let t=n.get(e);t&&(_(t),n.delete(e))},advance(t){a(t,{method:`advance`});let n=e+Math.max(0,t),r=-1,o=0;for(;;){let t=s(n);if(t===void 0)break;if(t===r){if(++o>=1e6)break}else o=0,r=t;e=t,c(t),l(t)}e=n;for(let e of i)e()},hasPending(){return t.size>0||n.size>0},pendingTimers(){let n=[];for(let[r,i]of t)n.push({id:r,deadline:i.deadline,ms:i.deadline-e,eventName:i.eventName});return n},setDrain(e){i.add(e)}}}function y(e){return`state`in e?e.state:e}function b(e,t){if(!e.has(t.candidate.name))throw Error(`[Actor] initial state "${t.candidate.name}" not found in declared states [${[...e].join(`, `)}]`);return!0}function x(t){let n=r();t.setup(n);let a=n.build(),o={...t,transitions:a.transitions,targets:a.targets,effects:a.effects},u=new Set((t.internal??[]).map(e=>e.type)),g=new Set(t.inputs.map(e=>e.type)),_=t.internalBudget??1e4,v=t.clock??p();v.setDrain?.(Y);let x,S,C=d(t.context),w,T=!0,E,D={},O=f(),k=h(),A,j=!1,M=[],N,P,F=!1,I=!1,L=c(`__error`,{isFinal:!0}),R=i({get:()=>C,set:e=>{C=e,I=!0,T=!0}}),z=y(t.initial);b(new Set(t.states.map(e=>e.name)),{candidate:z}),x=z;let B=t.initial;if(S=!s(B)&&`payload`in B?B.payload:void 0,E=z,t.regions)for(let[e,n]of Object.entries(t.regions))D[e]=n,n.on(`output`,{fn:e=>{O.push(e),Y()}});let V={get state(){return x},clock:v,get regions(){return D},get context(){return C},get options(){return o},on(e,t){return{change:e=>k.addChange(e),done:e=>k.addDone(e),transition:e=>k.addTransition(e),error:e=>k.addError(e),output:e=>k.addOutput(e)}[e](t.fn)},settled(){return Q()},pendingEffectCount(){return M.length},send(e){F||(W(e),H())},recover:U,snapshot(){return K()},inject(e){ae(e)},dispose(){oe()}};J({type:`__init`},{payloadForState:S}),k.seed(K());function H(){(x!==E||I)&&(E=x,I=!1,k.emitChange(K()))}function U(e){N===void 0||F||(A?.abort(),A=void 0,O.clear(),O=f(),N=void 0,x=e.state,S=void 0,C=e.context,E=e.state,I=!1,T=!0,w=void 0,P=void 0,M=[],k.emitChange(K()))}function W(e){if(N!==void 0||x.isFinal)return;let t={...e,payload:e.payload??{}},n=x.name,r=P;P={state:x,context:C};try{let r=o.transitions,i=r[x.name]?.[e.type],a=r.Any?.[e.type],s=G(t,{stateTransition:i,anyTransition:a});ne(t,{from:n,handled:!!(i||a),outcome:s}),s.emitted||O.length>0?Y():!i&&!a&&u.has(e.type)&&Z(`unhandled`,{event:e,error:/* @__PURE__ */ Error(`[Actor] internal event "${e.type}" emitted but no handler in state "${x.name}"`)})}finally{P=r}}function G(e,t){let n=t.stateTransition?re(e,{transition:t.stateTransition}):{applied:!1,target:void 0,effects:void 0};if(N===void 0){let r=ie(e,{transition:t.anyTransition,allowTransition:!n.applied});return{emitted:r.emitted,transitioned:n.applied||r.transitioned,target:n.target??r.target,effects:n.effects??r.effects}}return{emitted:!1,transitioned:!1}}function ne(e,t){N===void 0&&t.handled&&k.emitTransition({event:e,from:t.from,to:t.outcome.target??x.name,transitioned:t.outcome.transitioned,effects:t.outcome.effects??[]})}function re(e,t){let n=!1,r,i;return X(`transition`,{event:e,operation:()=>{let a=t.transition(e,{context:R,actor:$()});if(a.emit&&O.push(...a.emit),a.state){let t=q(e,{step:a});r=t.target,i=t.effects,n=!0}}}),{applied:n,target:r,effects:i}}function ie(e,t){if(t.transition===void 0)return{emitted:!1,transitioned:!1};let n=t.transition,r=!1,i=!1,a,o;return X(`transition`,{event:e,operation:()=>{let s=n(e,{context:R,actor:$()});if(s.state&&t.allowTransition){let t=q(e,{step:s});a=t.target,o=t.effects,i=!0}s.emit&&(O.push(...s.emit),r=!0)}}),{emitted:r,transitioned:i,target:a,effects:o}}function K(){return(w===void 0||T)&&(w=m(C),T=!1),te({stateRef:x,regions:D,context:w,error:N,payload:S})}function q(e,t){if(N!==void 0||!t.step.state)return{};let n=l(t.step);if(!n)return{};if(!s(n.state))return Z(`transition`,{event:e,error:/* @__PURE__ */ Error(`invalid transition target`)}),{};A?.abort(),x=n.state;let r=x.name;S=n.payload,P={state:x,context:C};let i=J(e,{payloadForState:n.payload});return n.state.isFinal&&N===void 0&&k.emitDone(),{target:r,effects:i}}function J(e,t){if(F)return[];let n=o.effects[x.name];if(!n)return A=void 0,[];let r=new AbortController;A=r;let i=P??{state:x,context:C},a=ee({effects:{[x.name]:n},state:x,statePayload:t.payloadForState,event:e,context:R,emit:e=>{N!==void 0||r.signal.aborted||(O.push(e),Y())},clock:v,abort:r,lastGood:i,onError:t=>Z(`effect`,{event:e,error:t})});for(let e of a.pending)M.push(e),e.finally(()=>{let t=M.indexOf(e);t!==-1&&M.splice(t,1)}).catch(()=>{});return a.ran}function Y(){if(!(j||F)){j=!0;try{let e=0;O.processCancellable(t=>{if(N!==void 0)return!1;if(e>=_)return Z(`budget`,{event:t,error:/* @__PURE__ */ Error(`internal event budget exceeded`)}),!1;if(e++,u.has(t.type)||g.has(t.type))W(t);else if(!X(`output`,{event:t,operation:()=>k.emitOutput(t)}))return!1;return!0})}finally{j=!1,H()}}}function X(t,n){let r=e.from(()=>(n.operation(),!0));return r[0]===void 0||(Z(t,{event:n.event,error:r[0]}),!1)}function Z(e,t){if(N!==void 0)return;let n=t.lastGood??P??{state:x,context:C};N={error:t.error,state:n.state,context:n.context,event:t.event,reason:e},A?.abort(),x=L,S=void 0,E=L,I=!1,k.emitError(N),k.emitChange(K()),k.emitDone()}function ae(e){F||(O.push(e),Y())}function oe(){if(!F){F=!0,A?.abort(),A=void 0;for(let e of Object.values(D))e.dispose();D={},O.clear(),k.clear(),M=[]}}function Q(){return O.settled().then(()=>{if(M.length!==0)return Promise.all(M).then(()=>Q())})}function $(){return V}return V}function S(e){return Symbol.for(`mantaq:event:${e}`)}function C(e){return()=>w(e)}function w(e){let t=S(e),n=function(e){return typeof e==`object`&&!!e&&Object.hasOwn(e,t)};function r(n){return Object.defineProperty(n===void 0?{type:e}:{type:e,payload:n},t,{value:!0})}return{type:e,is:n,create:r}}export{x as Actor,i as Context,w as EventRef,p as RealClock,c as StateRef,v as VirtualClock,C as event,s as isStateRef,a as state};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mantaq/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "State machine runtime with actor model, event system, state hierarchy, effects, and virtual clock.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -24,15 +24,15 @@
|
|
|
24
24
|
"@mantaq/utils": "0.0.4"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@stryker-mutator/core": "^
|
|
28
|
-
"@stryker-mutator/vitest-runner": "^
|
|
27
|
+
"@stryker-mutator/core": "^10",
|
|
28
|
+
"@stryker-mutator/vitest-runner": "^10",
|
|
29
29
|
"@types/node": "^26.2.0",
|
|
30
30
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
31
|
-
"@vitest/coverage-v8": "
|
|
31
|
+
"@vitest/coverage-v8": "5.0.5",
|
|
32
32
|
"typescript": "6.0.3",
|
|
33
|
-
"vite": "npm:@voidzero-dev/vite-plus-core@
|
|
34
|
-
"vite-plus": "
|
|
35
|
-
"vitest": "
|
|
33
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@1.4.0",
|
|
34
|
+
"vite-plus": "1.4.0",
|
|
35
|
+
"vitest": "5.0.5",
|
|
36
36
|
"@mantaq/pbt": "0.0.3"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|