@rytejs/core 0.2.0 → 0.3.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/dist/index.cjs +182 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -8
- package/dist/index.d.ts +61 -8
- package/dist/index.js +179 -44
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -24,10 +24,30 @@ __export(index_exports, {
|
|
|
24
24
|
ValidationError: () => ValidationError,
|
|
25
25
|
WorkflowRouter: () => WorkflowRouter,
|
|
26
26
|
createKey: () => createKey,
|
|
27
|
-
|
|
27
|
+
definePlugin: () => definePlugin,
|
|
28
|
+
defineWorkflow: () => defineWorkflow,
|
|
29
|
+
isPlugin: () => isPlugin
|
|
28
30
|
});
|
|
29
31
|
module.exports = __toCommonJS(index_exports);
|
|
30
32
|
|
|
33
|
+
// src/types.ts
|
|
34
|
+
var ValidationError = class extends Error {
|
|
35
|
+
constructor(source, issues) {
|
|
36
|
+
super(`Validation failed (${source}): ${issues.map((i) => i.message).join(", ")}`);
|
|
37
|
+
this.source = source;
|
|
38
|
+
this.issues = issues;
|
|
39
|
+
this.name = "ValidationError";
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var DomainErrorSignal = class extends Error {
|
|
43
|
+
constructor(code, data) {
|
|
44
|
+
super(`Domain error: ${code}`);
|
|
45
|
+
this.code = code;
|
|
46
|
+
this.data = data;
|
|
47
|
+
this.name = "DomainErrorSignal";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
31
51
|
// src/definition.ts
|
|
32
52
|
function defineWorkflow(name, config) {
|
|
33
53
|
return {
|
|
@@ -74,6 +94,51 @@ function defineWorkflow(name, config) {
|
|
|
74
94
|
},
|
|
75
95
|
hasState(stateName) {
|
|
76
96
|
return stateName in config.states;
|
|
97
|
+
},
|
|
98
|
+
snapshot(workflow) {
|
|
99
|
+
return {
|
|
100
|
+
id: workflow.id,
|
|
101
|
+
definitionName: name,
|
|
102
|
+
state: workflow.state,
|
|
103
|
+
data: workflow.data,
|
|
104
|
+
createdAt: workflow.createdAt.toISOString(),
|
|
105
|
+
updatedAt: workflow.updatedAt.toISOString(),
|
|
106
|
+
modelVersion: config.modelVersion ?? 1
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
restore(snap) {
|
|
110
|
+
const stateSchema = config.states[snap.state];
|
|
111
|
+
if (!stateSchema) {
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
error: new ValidationError("restore", [
|
|
115
|
+
{
|
|
116
|
+
code: "custom",
|
|
117
|
+
message: `Unknown state: ${snap.state}`,
|
|
118
|
+
input: snap.state,
|
|
119
|
+
path: ["state"]
|
|
120
|
+
}
|
|
121
|
+
])
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
const result = stateSchema.safeParse(snap.data);
|
|
125
|
+
if (!result.success) {
|
|
126
|
+
return {
|
|
127
|
+
ok: false,
|
|
128
|
+
error: new ValidationError("restore", result.error.issues)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
ok: true,
|
|
133
|
+
workflow: {
|
|
134
|
+
id: snap.id,
|
|
135
|
+
definitionName: snap.definitionName,
|
|
136
|
+
state: snap.state,
|
|
137
|
+
data: result.data,
|
|
138
|
+
createdAt: new Date(snap.createdAt),
|
|
139
|
+
updatedAt: new Date(snap.updatedAt)
|
|
140
|
+
}
|
|
141
|
+
};
|
|
77
142
|
}
|
|
78
143
|
};
|
|
79
144
|
}
|
|
@@ -83,6 +148,17 @@ function createKey(name) {
|
|
|
83
148
|
return { id: Symbol(name) };
|
|
84
149
|
}
|
|
85
150
|
|
|
151
|
+
// src/plugin.ts
|
|
152
|
+
var PLUGIN_SYMBOL = /* @__PURE__ */ Symbol.for("ryte:plugin");
|
|
153
|
+
function definePlugin(fn) {
|
|
154
|
+
const plugin = fn;
|
|
155
|
+
Object.defineProperty(plugin, PLUGIN_SYMBOL, { value: true, writable: false });
|
|
156
|
+
return plugin;
|
|
157
|
+
}
|
|
158
|
+
function isPlugin(value) {
|
|
159
|
+
return typeof value === "function" && PLUGIN_SYMBOL in value;
|
|
160
|
+
}
|
|
161
|
+
|
|
86
162
|
// src/compose.ts
|
|
87
163
|
function compose(middleware) {
|
|
88
164
|
return async (ctx) => {
|
|
@@ -98,24 +174,6 @@ function compose(middleware) {
|
|
|
98
174
|
};
|
|
99
175
|
}
|
|
100
176
|
|
|
101
|
-
// src/types.ts
|
|
102
|
-
var ValidationError = class extends Error {
|
|
103
|
-
constructor(source, issues) {
|
|
104
|
-
super(`Validation failed (${source}): ${issues.map((i) => i.message).join(", ")}`);
|
|
105
|
-
this.source = source;
|
|
106
|
-
this.issues = issues;
|
|
107
|
-
this.name = "ValidationError";
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
var DomainErrorSignal = class extends Error {
|
|
111
|
-
constructor(code, data) {
|
|
112
|
-
super(`Domain error: ${code}`);
|
|
113
|
-
this.code = code;
|
|
114
|
-
this.data = data;
|
|
115
|
-
this.name = "DomainErrorSignal";
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
177
|
// src/context.ts
|
|
120
178
|
function createContext(definition, originalWorkflow, command, deps) {
|
|
121
179
|
let mutableState = originalWorkflow.state;
|
|
@@ -199,6 +257,46 @@ function createContext(definition, originalWorkflow, command, deps) {
|
|
|
199
257
|
return ctx;
|
|
200
258
|
}
|
|
201
259
|
|
|
260
|
+
// src/hooks.ts
|
|
261
|
+
var HOOK_EVENTS = /* @__PURE__ */ new Set([
|
|
262
|
+
"dispatch:start",
|
|
263
|
+
"dispatch:end",
|
|
264
|
+
"transition",
|
|
265
|
+
"error",
|
|
266
|
+
"event"
|
|
267
|
+
]);
|
|
268
|
+
var HookRegistry = class {
|
|
269
|
+
// biome-ignore lint/complexity/noBannedTypes: callbacks have varying signatures per hook event
|
|
270
|
+
hooks = /* @__PURE__ */ new Map();
|
|
271
|
+
/** Register a callback for a hook event. */
|
|
272
|
+
// biome-ignore lint/complexity/noBannedTypes: callbacks have varying signatures per hook event
|
|
273
|
+
add(event, callback) {
|
|
274
|
+
const existing = this.hooks.get(event) ?? [];
|
|
275
|
+
existing.push(callback);
|
|
276
|
+
this.hooks.set(event, existing);
|
|
277
|
+
}
|
|
278
|
+
/** Emit a hook event, calling all registered callbacks. Errors are caught and forwarded. */
|
|
279
|
+
async emit(event, onError, ...args) {
|
|
280
|
+
const callbacks = this.hooks.get(event);
|
|
281
|
+
if (!callbacks) return;
|
|
282
|
+
for (const cb of callbacks) {
|
|
283
|
+
try {
|
|
284
|
+
await cb(...args);
|
|
285
|
+
} catch (err) {
|
|
286
|
+
onError(err);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/** Merge another registry's hooks into this one (used by composable routers). */
|
|
291
|
+
merge(other) {
|
|
292
|
+
for (const [event, callbacks] of other.hooks) {
|
|
293
|
+
const existing = this.hooks.get(event) ?? [];
|
|
294
|
+
existing.push(...callbacks);
|
|
295
|
+
this.hooks.set(event, existing);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
202
300
|
// src/router.ts
|
|
203
301
|
var StateBuilder = class {
|
|
204
302
|
/** @internal */
|
|
@@ -221,9 +319,10 @@ var StateBuilder = class {
|
|
|
221
319
|
}
|
|
222
320
|
};
|
|
223
321
|
var WorkflowRouter = class _WorkflowRouter {
|
|
224
|
-
constructor(definition, deps = {}) {
|
|
322
|
+
constructor(definition, deps = {}, options = {}) {
|
|
225
323
|
this.definition = definition;
|
|
226
324
|
this.deps = deps;
|
|
325
|
+
this.onHookError = options.onHookError ?? console.error;
|
|
227
326
|
}
|
|
228
327
|
globalMiddleware = [];
|
|
229
328
|
// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types
|
|
@@ -231,12 +330,16 @@ var WorkflowRouter = class _WorkflowRouter {
|
|
|
231
330
|
// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types
|
|
232
331
|
multiStateBuilders = /* @__PURE__ */ new Map();
|
|
233
332
|
wildcardHandlers = /* @__PURE__ */ new Map();
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
333
|
+
hookRegistry = new HookRegistry();
|
|
334
|
+
onHookError;
|
|
335
|
+
/** Adds global middleware, merges another router, or applies a plugin. */
|
|
336
|
+
use(arg) {
|
|
337
|
+
if (arg instanceof _WorkflowRouter) {
|
|
338
|
+
this.merge(arg);
|
|
339
|
+
} else if (isPlugin(arg)) {
|
|
340
|
+
arg(this);
|
|
238
341
|
} else {
|
|
239
|
-
this.globalMiddleware.push(
|
|
342
|
+
this.globalMiddleware.push(arg);
|
|
240
343
|
}
|
|
241
344
|
return this;
|
|
242
345
|
}
|
|
@@ -257,6 +360,7 @@ var WorkflowRouter = class _WorkflowRouter {
|
|
|
257
360
|
});
|
|
258
361
|
}
|
|
259
362
|
}
|
|
363
|
+
this.hookRegistry.merge(child.hookRegistry);
|
|
260
364
|
}
|
|
261
365
|
mergeStateBuilders(target, source) {
|
|
262
366
|
for (const [stateName, childBuilder] of source) {
|
|
@@ -291,19 +395,29 @@ var WorkflowRouter = class _WorkflowRouter {
|
|
|
291
395
|
}
|
|
292
396
|
return this;
|
|
293
397
|
}
|
|
294
|
-
|
|
295
|
-
on(
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
handler
|
|
305
|
-
|
|
306
|
-
|
|
398
|
+
// biome-ignore lint/suspicious/noExplicitAny: implementation signature must be loose to handle all overloads
|
|
399
|
+
on(...args) {
|
|
400
|
+
const first = args[0];
|
|
401
|
+
if (HOOK_EVENTS.has(first)) {
|
|
402
|
+
this.hookRegistry.add(first, args[1]);
|
|
403
|
+
return this;
|
|
404
|
+
}
|
|
405
|
+
if (first === "*") {
|
|
406
|
+
const command = args[1];
|
|
407
|
+
const fns = args.slice(2);
|
|
408
|
+
if (fns.length === 0) throw new Error("on() requires at least a handler");
|
|
409
|
+
const handler = fns.pop();
|
|
410
|
+
const inlineMiddleware = fns;
|
|
411
|
+
const wrappedHandler = async (ctx, _next) => {
|
|
412
|
+
await handler(ctx);
|
|
413
|
+
};
|
|
414
|
+
this.wildcardHandlers.set(command, {
|
|
415
|
+
inlineMiddleware,
|
|
416
|
+
handler: wrappedHandler
|
|
417
|
+
});
|
|
418
|
+
return this;
|
|
419
|
+
}
|
|
420
|
+
throw new Error(`Unknown event or state: ${first}`);
|
|
307
421
|
}
|
|
308
422
|
/** Dispatches a command to the appropriate handler and returns the result. */
|
|
309
423
|
async dispatch(workflow, command) {
|
|
@@ -377,17 +491,35 @@ var WorkflowRouter = class _WorkflowRouter {
|
|
|
377
491
|
validatedCommand,
|
|
378
492
|
this.deps
|
|
379
493
|
);
|
|
494
|
+
await this.hookRegistry.emit("dispatch:start", this.onHookError, ctx);
|
|
380
495
|
try {
|
|
381
496
|
const composed = compose(chain);
|
|
382
497
|
await composed(ctx);
|
|
383
|
-
|
|
498
|
+
const result = {
|
|
384
499
|
ok: true,
|
|
385
500
|
workflow: ctx.getWorkflowSnapshot(),
|
|
386
501
|
events: [...ctx.events]
|
|
387
502
|
};
|
|
503
|
+
if (result.ok && result.workflow.state !== workflow.state) {
|
|
504
|
+
await this.hookRegistry.emit(
|
|
505
|
+
"transition",
|
|
506
|
+
this.onHookError,
|
|
507
|
+
workflow.state,
|
|
508
|
+
result.workflow.state,
|
|
509
|
+
result.workflow
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
if (result.ok) {
|
|
513
|
+
for (const event of result.events) {
|
|
514
|
+
await this.hookRegistry.emit("event", this.onHookError, event, result.workflow);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
await this.hookRegistry.emit("dispatch:end", this.onHookError, ctx, result);
|
|
518
|
+
return result;
|
|
388
519
|
} catch (err) {
|
|
520
|
+
let result;
|
|
389
521
|
if (err instanceof DomainErrorSignal) {
|
|
390
|
-
|
|
522
|
+
result = {
|
|
391
523
|
ok: false,
|
|
392
524
|
error: {
|
|
393
525
|
category: "domain",
|
|
@@ -395,9 +527,8 @@ var WorkflowRouter = class _WorkflowRouter {
|
|
|
395
527
|
data: err.data
|
|
396
528
|
}
|
|
397
529
|
};
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
return {
|
|
530
|
+
} else if (err instanceof ValidationError) {
|
|
531
|
+
result = {
|
|
401
532
|
ok: false,
|
|
402
533
|
error: {
|
|
403
534
|
category: "validation",
|
|
@@ -406,8 +537,12 @@ var WorkflowRouter = class _WorkflowRouter {
|
|
|
406
537
|
message: err.message
|
|
407
538
|
}
|
|
408
539
|
};
|
|
540
|
+
} else {
|
|
541
|
+
throw err;
|
|
409
542
|
}
|
|
410
|
-
|
|
543
|
+
await this.hookRegistry.emit("error", this.onHookError, result.error, ctx);
|
|
544
|
+
await this.hookRegistry.emit("dispatch:end", this.onHookError, ctx, result);
|
|
545
|
+
return result;
|
|
411
546
|
}
|
|
412
547
|
}
|
|
413
548
|
};
|
|
@@ -417,6 +552,8 @@ var WorkflowRouter = class _WorkflowRouter {
|
|
|
417
552
|
ValidationError,
|
|
418
553
|
WorkflowRouter,
|
|
419
554
|
createKey,
|
|
420
|
-
|
|
555
|
+
definePlugin,
|
|
556
|
+
defineWorkflow,
|
|
557
|
+
isPlugin
|
|
421
558
|
});
|
|
422
559
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/definition.ts","../src/key.ts","../src/compose.ts","../src/types.ts","../src/context.ts","../src/router.ts"],"sourcesContent":["export type { Context } from \"./context.js\";\nexport type { WorkflowDefinition } from \"./definition.js\";\nexport { defineWorkflow } from \"./definition.js\";\nexport type { Handler } from \"./handler.js\";\nexport type { ContextKey } from \"./key.js\";\nexport { createKey } from \"./key.js\";\nexport type { Middleware } from \"./middleware.js\";\nexport { WorkflowRouter } from \"./router.js\";\nexport type {\n\tCommandNames,\n\tCommandPayload,\n\tDispatchResult,\n\tErrorCodes,\n\tErrorData,\n\tEventData,\n\tEventNames,\n\tPipelineError,\n\tStateData,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowOf,\n} from \"./types.js\";\nexport { DomainErrorSignal, ValidationError } from \"./types.js\";\n","import type { ZodType, z } from \"zod\";\nimport type { StateNames, WorkflowConfig, WorkflowOf } from \"./types.js\";\n\n/** The result of defineWorkflow() — holds schemas and creates workflow instances. */\nexport interface WorkflowDefinition<TConfig extends WorkflowConfig = WorkflowConfig> {\n\treadonly config: TConfig;\n\treadonly name: string;\n\tcreateWorkflow<S extends StateNames<TConfig>>(\n\t\tid: string,\n\t\tconfig: { initialState: S; data: z.infer<TConfig[\"states\"][S]> },\n\t): WorkflowOf<TConfig, S>;\n\tgetStateSchema(stateName: string): ZodType;\n\tgetCommandSchema(commandName: string): ZodType;\n\tgetEventSchema(eventName: string): ZodType;\n\tgetErrorSchema(errorCode: string): ZodType;\n\thasState(stateName: string): boolean;\n}\n\n/**\n * Creates a workflow definition from a name and Zod schema configuration.\n */\nexport function defineWorkflow<const TConfig extends WorkflowConfig>(\n\tname: string,\n\tconfig: TConfig,\n): WorkflowDefinition<TConfig> {\n\treturn {\n\t\tconfig,\n\t\tname,\n\n\t\tcreateWorkflow(id, wfConfig) {\n\t\t\tconst schema = config.states[wfConfig.initialState as string];\n\t\t\tif (!schema) throw new Error(`Unknown state: ${wfConfig.initialState as string}`);\n\t\t\tconst result = schema.safeParse(wfConfig.data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid initial data for state '${wfConfig.initialState as string}': ${result.error.issues.map((i) => i.message).join(\", \")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst now = new Date();\n\t\t\treturn {\n\t\t\t\tid,\n\t\t\t\tdefinitionName: name,\n\t\t\t\tstate: wfConfig.initialState,\n\t\t\t\tdata: result.data,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t} as WorkflowOf<TConfig, typeof wfConfig.initialState>;\n\t\t},\n\n\t\tgetStateSchema(stateName: string): ZodType {\n\t\t\tconst schema = config.states[stateName];\n\t\t\tif (!schema) throw new Error(`Unknown state: ${stateName}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\tgetCommandSchema(commandName: string): ZodType {\n\t\t\tconst schema = config.commands[commandName];\n\t\t\tif (!schema) throw new Error(`Unknown command: ${commandName}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\tgetEventSchema(eventName: string): ZodType {\n\t\t\tconst schema = config.events[eventName];\n\t\t\tif (!schema) throw new Error(`Unknown event: ${eventName}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\tgetErrorSchema(errorCode: string): ZodType {\n\t\t\tconst schema = config.errors[errorCode];\n\t\t\tif (!schema) throw new Error(`Unknown error: ${errorCode}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\thasState(stateName: string): boolean {\n\t\t\treturn stateName in config.states;\n\t\t},\n\t};\n}\n","/** A phantom-typed key for type-safe middleware state storage. */\nexport interface ContextKey<T> {\n\treadonly _phantom: T;\n\treadonly id: symbol;\n}\n\n/** Creates a unique typed key for storing/retrieving values in context. */\nexport function createKey<T>(name: string): ContextKey<T> {\n\treturn { id: Symbol(name) } as ContextKey<T>;\n}\n","type Middleware<TCtx> = (ctx: TCtx, next: () => Promise<void>) => Promise<void>;\n\n/** Composes an array of middleware into a single function (Koa-style onion model). */\nexport function compose<TCtx>(middleware: Middleware<TCtx>[]): (ctx: TCtx) => Promise<void> {\n\treturn async (ctx: TCtx) => {\n\t\tlet index = -1;\n\t\tasync function dispatch(i: number): Promise<void> {\n\t\t\tif (i <= index) throw new Error(\"next() called multiple times\");\n\t\t\tindex = i;\n\t\t\tconst fn = middleware[i];\n\t\t\tif (!fn) return;\n\t\t\tawait fn(ctx, () => dispatch(i + 1));\n\t\t}\n\t\tawait dispatch(0);\n\t};\n}\n","import type { ZodType, z } from \"zod\";\n\nexport interface WorkflowConfig {\n\tstates: Record<string, ZodType>;\n\tcommands: Record<string, ZodType>;\n\tevents: Record<string, ZodType>;\n\terrors: Record<string, ZodType>;\n}\n\nexport type StateNames<T extends WorkflowConfig> = keyof T[\"states\"] & string;\nexport type CommandNames<T extends WorkflowConfig> = keyof T[\"commands\"] & string;\nexport type EventNames<T extends WorkflowConfig> = keyof T[\"events\"] & string;\nexport type ErrorCodes<T extends WorkflowConfig> = keyof T[\"errors\"] & string;\n\nexport type StateData<\n\tT extends WorkflowConfig,\n\tS extends StateNames<T>,\n> = T[\"states\"][S] extends ZodType ? z.infer<T[\"states\"][S]> : never;\n\nexport type CommandPayload<\n\tT extends WorkflowConfig,\n\tC extends CommandNames<T>,\n> = T[\"commands\"][C] extends ZodType ? z.infer<T[\"commands\"][C]> : never;\n\nexport type EventData<\n\tT extends WorkflowConfig,\n\tE extends EventNames<T>,\n> = T[\"events\"][E] extends ZodType ? z.infer<T[\"events\"][E]> : never;\n\nexport type ErrorData<\n\tT extends WorkflowConfig,\n\tC extends ErrorCodes<T>,\n> = T[\"errors\"][C] extends ZodType ? z.infer<T[\"errors\"][C]> : never;\n\n/** Workflow narrowed to a specific known state. */\nexport interface WorkflowOf<TConfig extends WorkflowConfig, S extends StateNames<TConfig>> {\n\treadonly id: string;\n\treadonly definitionName: string;\n\treadonly state: S;\n\treadonly data: StateData<TConfig, S>;\n\treadonly createdAt: Date;\n\treadonly updatedAt: Date;\n}\n\n/** Discriminated union of all possible workflow states — checking .state narrows .data. */\nexport type Workflow<TConfig extends WorkflowConfig = WorkflowConfig> = {\n\t[S in StateNames<TConfig>]: WorkflowOf<TConfig, S>;\n}[StateNames<TConfig>];\n\nexport type PipelineError<TConfig extends WorkflowConfig = WorkflowConfig> =\n\t| {\n\t\t\tcategory: \"validation\";\n\t\t\tsource: \"command\" | \"state\" | \"event\" | \"transition\";\n\t\t\tissues: z.core.$ZodIssue[];\n\t\t\tmessage: string;\n\t }\n\t| {\n\t\t\tcategory: \"domain\";\n\t\t\tcode: ErrorCodes<TConfig>;\n\t\t\tdata: ErrorData<TConfig, ErrorCodes<TConfig>>;\n\t }\n\t| {\n\t\t\tcategory: \"router\";\n\t\t\tcode: \"NO_HANDLER\" | \"UNKNOWN_STATE\";\n\t\t\tmessage: string;\n\t };\n\nexport type DispatchResult<TConfig extends WorkflowConfig = WorkflowConfig> =\n\t| {\n\t\t\tok: true;\n\t\t\tworkflow: Workflow<TConfig>;\n\t\t\tevents: Array<{ type: EventNames<TConfig>; data: unknown }>;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\terror: PipelineError<TConfig>;\n\t };\n\n/** Thrown internally when Zod validation fails during dispatch. */\nexport class ValidationError extends Error {\n\tconstructor(\n\t\tpublic readonly source: \"command\" | \"state\" | \"event\" | \"transition\",\n\t\tpublic readonly issues: z.core.$ZodIssue[],\n\t) {\n\t\tsuper(`Validation failed (${source}): ${issues.map((i) => i.message).join(\", \")}`);\n\t\tthis.name = \"ValidationError\";\n\t}\n}\n\n/** Thrown internally when a handler calls ctx.error(). Caught by the router. */\nexport class DomainErrorSignal extends Error {\n\tconstructor(\n\t\tpublic readonly code: string,\n\t\tpublic readonly data: unknown,\n\t) {\n\t\tsuper(`Domain error: ${code}`);\n\t\tthis.name = \"DomainErrorSignal\";\n\t}\n}\n","import type { WorkflowDefinition } from \"./definition.js\";\nimport type { ContextKey } from \"./key.js\";\nimport type {\n\tCommandNames,\n\tCommandPayload,\n\tErrorCodes,\n\tErrorData,\n\tEventData,\n\tEventNames,\n\tStateData,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowOf,\n} from \"./types.js\";\nimport { DomainErrorSignal, ValidationError } from \"./types.js\";\n\n/** Mutable context flowing through the middleware pipeline during dispatch. */\nexport interface Context<\n\tTConfig extends WorkflowConfig,\n\tTDeps,\n\tTState extends StateNames<TConfig> = StateNames<TConfig>,\n\tTCommand extends CommandNames<TConfig> = CommandNames<TConfig>,\n> {\n\treadonly command: {\n\t\treadonly type: TCommand;\n\t\treadonly payload: CommandPayload<TConfig, TCommand>;\n\t};\n\treadonly workflow: WorkflowOf<TConfig, TState>;\n\treadonly deps: TDeps;\n\n\treadonly data: StateData<TConfig, TState>;\n\tupdate(data: Partial<StateData<TConfig, TState>>): void;\n\n\ttransition<Target extends StateNames<TConfig>>(\n\t\ttarget: Target,\n\t\tdata: StateData<TConfig, Target>,\n\t): void;\n\n\temit<E extends EventNames<TConfig>>(event: { type: E; data: EventData<TConfig, E> }): void;\n\treadonly events: ReadonlyArray<{ type: EventNames<TConfig>; data: unknown }>;\n\n\terror<C extends ErrorCodes<TConfig>>(err: { code: C; data: ErrorData<TConfig, C> }): never;\n\n\tset<T>(key: ContextKey<T>, value: T): void;\n\tget<T>(key: ContextKey<T>): T;\n\tgetOrNull<T>(key: ContextKey<T>): T | undefined;\n\n\t/** @internal — not part of the handler API */\n\tgetWorkflowSnapshot(): Workflow<TConfig>;\n}\n\ninterface DomainEvent {\n\ttype: string;\n\tdata: unknown;\n}\n\n/** @internal Creates a context for dispatch. Not part of public API. */\nexport function createContext<TConfig extends WorkflowConfig, TDeps>(\n\tdefinition: WorkflowDefinition<TConfig>,\n\toriginalWorkflow: Workflow<TConfig>,\n\tcommand: { type: string; payload: unknown },\n\tdeps: TDeps,\n): Context<TConfig, TDeps> {\n\tlet mutableState = originalWorkflow.state;\n\tlet mutableData: Record<string, unknown> = {\n\t\t...(originalWorkflow.data as Record<string, unknown>),\n\t};\n\n\tconst accumulatedEvents: DomainEvent[] = [];\n\tconst middlewareState = new Map<symbol, unknown>();\n\n\tconst ctx = {\n\t\tcommand,\n\t\tworkflow: originalWorkflow,\n\t\tdeps,\n\n\t\tget data() {\n\t\t\treturn { ...mutableData } as StateData<TConfig, StateNames<TConfig>>;\n\t\t},\n\n\t\tupdate(data: Record<string, unknown>) {\n\t\t\tconst merged = { ...mutableData, ...data };\n\t\t\tconst schema = definition.getStateSchema(mutableState);\n\t\t\tconst result = schema.safeParse(merged);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new ValidationError(\"state\", result.error.issues);\n\t\t\t}\n\t\t\tmutableData = result.data as Record<string, unknown>;\n\t\t},\n\n\t\ttransition(target: string, data: unknown) {\n\t\t\tif (!definition.hasState(target)) {\n\t\t\t\tthrow new Error(`Unknown state: ${target}`);\n\t\t\t}\n\t\t\tconst schema = definition.getStateSchema(target);\n\t\t\tconst result = schema.safeParse(data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new ValidationError(\"transition\", result.error.issues);\n\t\t\t}\n\t\t\tmutableState = target;\n\t\t\tmutableData = result.data as Record<string, unknown>;\n\t\t},\n\n\t\temit(event: { type: string; data: unknown }) {\n\t\t\tconst schema = definition.getEventSchema(event.type);\n\t\t\tconst result = schema.safeParse(event.data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new ValidationError(\"event\", result.error.issues);\n\t\t\t}\n\t\t\taccumulatedEvents.push({ type: event.type, data: result.data });\n\t\t},\n\n\t\tget events() {\n\t\t\treturn [...accumulatedEvents];\n\t\t},\n\n\t\terror(err: { code: string; data: unknown }) {\n\t\t\tconst schema = definition.getErrorSchema(err.code);\n\t\t\tconst result = schema.safeParse(err.data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid error data for '${err.code}': ${result.error.issues.map((i) => i.message).join(\", \")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new DomainErrorSignal(err.code, result.data);\n\t\t},\n\n\t\tset<T>(key: ContextKey<T>, value: T) {\n\t\t\tmiddlewareState.set(key.id, value);\n\t\t},\n\n\t\tget<T>(key: ContextKey<T>): T {\n\t\t\tif (!middlewareState.has(key.id)) {\n\t\t\t\tthrow new Error(`Context key not set: ${key.id.toString()}`);\n\t\t\t}\n\t\t\treturn middlewareState.get(key.id) as T;\n\t\t},\n\n\t\tgetOrNull<T>(key: ContextKey<T>): T | undefined {\n\t\t\treturn middlewareState.get(key.id) as T | undefined;\n\t\t},\n\n\t\tgetWorkflowSnapshot(): Workflow<TConfig> {\n\t\t\treturn {\n\t\t\t\tid: originalWorkflow.id,\n\t\t\t\tdefinitionName: originalWorkflow.definitionName,\n\t\t\t\tstate: mutableState,\n\t\t\t\tdata: { ...mutableData },\n\t\t\t\tcreatedAt: originalWorkflow.createdAt,\n\t\t\t\tupdatedAt: new Date(),\n\t\t\t} as Workflow<TConfig>;\n\t\t},\n\t};\n\n\treturn ctx as unknown as Context<TConfig, TDeps>;\n}\n","import { compose } from \"./compose.js\";\nimport { type Context, createContext } from \"./context.js\";\nimport type { WorkflowDefinition } from \"./definition.js\";\nimport type {\n\tCommandNames,\n\tDispatchResult,\n\tErrorCodes,\n\tErrorData,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n} from \"./types.js\";\nimport { DomainErrorSignal, ValidationError } from \"./types.js\";\n\n// biome-ignore lint/suspicious/noExplicitAny: internal type erasure for heterogeneous middleware storage\ntype AnyMiddleware = (ctx: any, next: () => Promise<void>) => Promise<void>;\n// biome-ignore lint/suspicious/noExplicitAny: internal type erasure for heterogeneous handler storage\ntype AnyHandler = (ctx: any) => void | Promise<void>;\n\ntype HandlerEntry = { inlineMiddleware: AnyMiddleware[]; handler: AnyMiddleware };\n\nclass StateBuilder<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TConfig>> {\n\t/** @internal */ readonly middleware: AnyMiddleware[] = [];\n\t/** @internal */ readonly handlers = new Map<string, HandlerEntry>();\n\n\ton<C extends CommandNames<TConfig>>(\n\t\tcommand: C,\n\t\t...fns: [...AnyMiddleware[], (ctx: Context<TConfig, TDeps, TState, C>) => void | Promise<void>]\n\t): this {\n\t\tif (fns.length === 0) throw new Error(\"on() requires at least a handler\");\n\t\tconst handler = fns.pop() as AnyHandler;\n\t\tconst inlineMiddleware = fns as AnyMiddleware[];\n\t\tconst wrappedHandler: AnyMiddleware = async (ctx, _next) => {\n\t\t\tawait handler(ctx);\n\t\t};\n\t\tthis.handlers.set(command as string, { inlineMiddleware, handler: wrappedHandler });\n\t\treturn this;\n\t}\n\n\tuse(\n\t\tmiddleware: (ctx: Context<TConfig, TDeps, TState>, next: () => Promise<void>) => Promise<void>,\n\t): this {\n\t\tthis.middleware.push(middleware as AnyMiddleware);\n\t\treturn this;\n\t}\n}\n\n/**\n * Routes commands to handlers based on workflow state.\n *\n * Supports global middleware, state-scoped middleware, inline middleware,\n * wildcard handlers, and multi-state handlers.\n */\n// biome-ignore lint/complexity/noBannedTypes: {} is correct here — TDeps defaults to \"no deps\", inferred away when deps are provided\nexport class WorkflowRouter<TConfig extends WorkflowConfig, TDeps = {}> {\n\tprivate globalMiddleware: AnyMiddleware[] = [];\n\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\tprivate singleStateBuilders = new Map<string, StateBuilder<TConfig, TDeps, any>>();\n\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\tprivate multiStateBuilders = new Map<string, StateBuilder<TConfig, TDeps, any>>();\n\tprivate wildcardHandlers = new Map<string, HandlerEntry>();\n\n\tconstructor(\n\t\tprivate readonly definition: WorkflowDefinition<TConfig>,\n\t\tprivate readonly deps: TDeps = {} as TDeps,\n\t) {}\n\n\t/** Adds global middleware or merges another router's handlers. */\n\tuse(\n\t\tmiddlewareOrRouter:\n\t\t\t| ((ctx: Context<TConfig, TDeps>, next: () => Promise<void>) => Promise<void>)\n\t\t\t| WorkflowRouter<TConfig, TDeps>,\n\t): this {\n\t\tif (middlewareOrRouter instanceof WorkflowRouter) {\n\t\t\tthis.merge(middlewareOrRouter);\n\t\t} else {\n\t\t\tthis.globalMiddleware.push(middlewareOrRouter as AnyMiddleware);\n\t\t}\n\t\treturn this;\n\t}\n\n\tprivate merge(child: WorkflowRouter<TConfig, TDeps>): void {\n\t\tif (child.definition !== this.definition) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot merge router for '${child.definition.name}' into router for '${this.definition.name}': definition mismatch`,\n\t\t\t);\n\t\t}\n\n\t\tthis.globalMiddleware.push(...child.globalMiddleware);\n\t\tthis.mergeStateBuilders(this.singleStateBuilders, child.singleStateBuilders);\n\t\tthis.mergeStateBuilders(this.multiStateBuilders, child.multiStateBuilders);\n\n\t\tfor (const [command, entry] of child.wildcardHandlers) {\n\t\t\tif (!this.wildcardHandlers.has(command)) {\n\t\t\t\tthis.wildcardHandlers.set(command, {\n\t\t\t\t\tinlineMiddleware: [...entry.inlineMiddleware],\n\t\t\t\t\thandler: entry.handler,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate mergeStateBuilders(\n\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\t\ttarget: Map<string, StateBuilder<TConfig, TDeps, any>>,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\t\tsource: Map<string, StateBuilder<TConfig, TDeps, any>>,\n\t): void {\n\t\tfor (const [stateName, childBuilder] of source) {\n\t\t\tlet parentBuilder = target.get(stateName);\n\t\t\tif (!parentBuilder) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — state name is dynamic at runtime\n\t\t\t\tparentBuilder = new StateBuilder<TConfig, TDeps, any>();\n\t\t\t\ttarget.set(stateName, parentBuilder);\n\t\t\t}\n\t\t\tfor (const [command, entry] of childBuilder.handlers) {\n\t\t\t\tif (!parentBuilder.handlers.has(command)) {\n\t\t\t\t\tparentBuilder.handlers.set(command, {\n\t\t\t\t\t\tinlineMiddleware: [...entry.inlineMiddleware],\n\t\t\t\t\t\thandler: entry.handler,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tparentBuilder.middleware.push(...childBuilder.middleware);\n\t\t}\n\t}\n\n\t/** Registers handlers for one or more states. */\n\tstate<P extends StateNames<TConfig> | readonly StateNames<TConfig>[]>(\n\t\tname: P,\n\t\tsetup: (\n\t\t\tstate: StateBuilder<\n\t\t\t\tTConfig,\n\t\t\t\tTDeps,\n\t\t\t\tP extends readonly (infer S)[] ? S & StateNames<TConfig> : P & StateNames<TConfig>\n\t\t\t>,\n\t\t) => void,\n\t): this {\n\t\tconst names = Array.isArray(name) ? name : [name];\n\t\tconst isMulti = Array.isArray(name);\n\t\tconst routerMap = isMulti ? this.multiStateBuilders : this.singleStateBuilders;\n\n\t\tfor (const n of names as string[]) {\n\t\t\tlet router = routerMap.get(n);\n\t\t\tif (!router) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — state name is dynamic at runtime\n\t\t\t\trouter = new StateBuilder<TConfig, TDeps, any>();\n\t\t\t\trouterMap.set(n, router);\n\t\t\t}\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — setup callback expects a specific state type\n\t\t\tsetup(router as any);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/** Registers a wildcard handler that matches any state. */\n\ton<C extends CommandNames<TConfig>>(\n\t\t_state: \"*\",\n\t\tcommand: C,\n\t\t...fns: [\n\t\t\t...AnyMiddleware[],\n\t\t\t(ctx: Context<TConfig, TDeps, StateNames<TConfig>, C>) => void | Promise<void>,\n\t\t]\n\t): this {\n\t\tif (fns.length === 0) throw new Error(\"on() requires at least a handler\");\n\t\tconst handler = fns.pop() as AnyHandler;\n\t\tconst inlineMiddleware = fns as AnyMiddleware[];\n\t\tconst wrappedHandler: AnyMiddleware = async (ctx, _next) => {\n\t\t\tawait handler(ctx);\n\t\t};\n\t\tthis.wildcardHandlers.set(command as string, {\n\t\t\tinlineMiddleware,\n\t\t\thandler: wrappedHandler,\n\t\t});\n\t\treturn this;\n\t}\n\n\t/** Dispatches a command to the appropriate handler and returns the result. */\n\tasync dispatch(\n\t\tworkflow: Workflow<TConfig>,\n\t\tcommand: { type: CommandNames<TConfig>; payload: unknown },\n\t): Promise<DispatchResult<TConfig>> {\n\t\tif (!this.definition.hasState(workflow.state)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"router\",\n\t\t\t\t\tcode: \"UNKNOWN_STATE\",\n\t\t\t\t\tmessage: `Unknown state: ${workflow.state}`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst commandSchema = this.definition.getCommandSchema(command.type);\n\t\tconst payloadResult = commandSchema.safeParse(command.payload);\n\t\tif (!payloadResult.success) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"validation\",\n\t\t\t\t\tsource: \"command\",\n\t\t\t\t\tissues: payloadResult.error.issues,\n\t\t\t\t\tmessage: `Invalid command payload: ${payloadResult.error.issues.map((i) => i.message).join(\", \")}`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tconst validatedCommand = { type: command.type, payload: payloadResult.data };\n\n\t\tconst stateName = workflow.state;\n\t\tconst singleRouter = this.singleStateBuilders.get(stateName);\n\t\tconst multiRouter = this.multiStateBuilders.get(stateName);\n\t\tconst singleHandler = singleRouter?.handlers.get(command.type);\n\t\tconst multiHandler = multiRouter?.handlers.get(command.type);\n\t\tconst wildcardHandler = this.wildcardHandlers.get(command.type);\n\n\t\tlet routeEntry: HandlerEntry | undefined;\n\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — matched router's state type is dynamic\n\t\tlet matchedRouter: StateBuilder<TConfig, TDeps, any> | undefined;\n\n\t\tif (singleHandler) {\n\t\t\trouteEntry = singleHandler;\n\t\t\tmatchedRouter = singleRouter;\n\t\t} else if (multiHandler) {\n\t\t\trouteEntry = multiHandler;\n\t\t\tmatchedRouter = multiRouter;\n\t\t} else if (wildcardHandler) {\n\t\t\trouteEntry = wildcardHandler;\n\t\t\tmatchedRouter = undefined;\n\t\t}\n\n\t\tif (!routeEntry) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"router\",\n\t\t\t\t\tcode: \"NO_HANDLER\",\n\t\t\t\t\tmessage: `No handler for command '${command.type}' in state '${stateName}'`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst stateMiddleware: AnyMiddleware[] = [];\n\t\tif (matchedRouter) {\n\t\t\tif (singleRouter) stateMiddleware.push(...singleRouter.middleware);\n\t\t\tif (multiRouter && multiRouter !== singleRouter)\n\t\t\t\tstateMiddleware.push(...multiRouter.middleware);\n\t\t}\n\n\t\tconst chain: AnyMiddleware[] = [\n\t\t\t...this.globalMiddleware,\n\t\t\t...stateMiddleware,\n\t\t\t...routeEntry.inlineMiddleware,\n\t\t\trouteEntry.handler,\n\t\t];\n\n\t\tconst ctx = createContext<TConfig, TDeps>(\n\t\t\tthis.definition,\n\t\t\tworkflow,\n\t\t\tvalidatedCommand,\n\t\t\tthis.deps,\n\t\t);\n\n\t\ttry {\n\t\t\tconst composed = compose(chain);\n\t\t\tawait composed(ctx);\n\t\t\treturn {\n\t\t\t\tok: true as const,\n\t\t\t\tworkflow: ctx.getWorkflowSnapshot(),\n\t\t\t\tevents: [...ctx.events],\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tif (err instanceof DomainErrorSignal) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false as const,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcategory: \"domain\" as const,\n\t\t\t\t\t\tcode: err.code as ErrorCodes<TConfig>,\n\t\t\t\t\t\tdata: err.data as ErrorData<TConfig, ErrorCodes<TConfig>>,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (err instanceof ValidationError) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false as const,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcategory: \"validation\" as const,\n\t\t\t\t\t\tsource: err.source,\n\t\t\t\t\t\tissues: err.issues,\n\t\t\t\t\t\tmessage: err.message,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACqBO,SAAS,eACf,MACA,QAC8B;AAC9B,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IAEA,eAAe,IAAI,UAAU;AAC5B,YAAM,SAAS,OAAO,OAAO,SAAS,YAAsB;AAC5D,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,kBAAkB,SAAS,YAAsB,EAAE;AAChF,YAAM,SAAS,OAAO,UAAU,SAAS,IAAI;AAC7C,UAAI,CAAC,OAAO,SAAS;AACpB,cAAM,IAAI;AAAA,UACT,mCAAmC,SAAS,YAAsB,MAAM,OAAO,MAAM,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,QAC7H;AAAA,MACD;AACA,YAAM,MAAM,oBAAI,KAAK;AACrB,aAAO;AAAA,QACN;AAAA,QACA,gBAAgB;AAAA,QAChB,OAAO,SAAS;AAAA,QAChB,MAAM,OAAO;AAAA,QACb,WAAW;AAAA,QACX,WAAW;AAAA,MACZ;AAAA,IACD;AAAA,IAEA,eAAe,WAA4B;AAC1C,YAAM,SAAS,OAAO,OAAO,SAAS;AACtC,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,kBAAkB,SAAS,EAAE;AAC1D,aAAO;AAAA,IACR;AAAA,IAEA,iBAAiB,aAA8B;AAC9C,YAAM,SAAS,OAAO,SAAS,WAAW;AAC1C,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,oBAAoB,WAAW,EAAE;AAC9D,aAAO;AAAA,IACR;AAAA,IAEA,eAAe,WAA4B;AAC1C,YAAM,SAAS,OAAO,OAAO,SAAS;AACtC,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,kBAAkB,SAAS,EAAE;AAC1D,aAAO;AAAA,IACR;AAAA,IAEA,eAAe,WAA4B;AAC1C,YAAM,SAAS,OAAO,OAAO,SAAS;AACtC,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,kBAAkB,SAAS,EAAE;AAC1D,aAAO;AAAA,IACR;AAAA,IAEA,SAAS,WAA4B;AACpC,aAAO,aAAa,OAAO;AAAA,IAC5B;AAAA,EACD;AACD;;;ACtEO,SAAS,UAAa,MAA6B;AACzD,SAAO,EAAE,IAAI,OAAO,IAAI,EAAE;AAC3B;;;ACNO,SAAS,QAAc,YAA8D;AAC3F,SAAO,OAAO,QAAc;AAC3B,QAAI,QAAQ;AACZ,mBAAe,SAAS,GAA0B;AACjD,UAAI,KAAK,MAAO,OAAM,IAAI,MAAM,8BAA8B;AAC9D,cAAQ;AACR,YAAM,KAAK,WAAW,CAAC;AACvB,UAAI,CAAC,GAAI;AACT,YAAM,GAAG,KAAK,MAAM,SAAS,IAAI,CAAC,CAAC;AAAA,IACpC;AACA,UAAM,SAAS,CAAC;AAAA,EACjB;AACD;;;ACgEO,IAAM,kBAAN,cAA8B,MAAM;AAAA,EAC1C,YACiB,QACA,QACf;AACD,UAAM,sBAAsB,MAAM,MAAM,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC,EAAE;AAHjE;AACA;AAGhB,SAAK,OAAO;AAAA,EACb;AACD;AAGO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAC5C,YACiB,MACA,MACf;AACD,UAAM,iBAAiB,IAAI,EAAE;AAHb;AACA;AAGhB,SAAK,OAAO;AAAA,EACb;AACD;;;ACxCO,SAAS,cACf,YACA,kBACA,SACA,MAC0B;AAC1B,MAAI,eAAe,iBAAiB;AACpC,MAAI,cAAuC;AAAA,IAC1C,GAAI,iBAAiB;AAAA,EACtB;AAEA,QAAM,oBAAmC,CAAC;AAC1C,QAAM,kBAAkB,oBAAI,IAAqB;AAEjD,QAAM,MAAM;AAAA,IACX;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IAEA,IAAI,OAAO;AACV,aAAO,EAAE,GAAG,YAAY;AAAA,IACzB;AAAA,IAEA,OAAO,MAA+B;AACrC,YAAM,SAAS,EAAE,GAAG,aAAa,GAAG,KAAK;AACzC,YAAM,SAAS,WAAW,eAAe,YAAY;AACrD,YAAM,SAAS,OAAO,UAAU,MAAM;AACtC,UAAI,CAAC,OAAO,SAAS;AACpB,cAAM,IAAI,gBAAgB,SAAS,OAAO,MAAM,MAAM;AAAA,MACvD;AACA,oBAAc,OAAO;AAAA,IACtB;AAAA,IAEA,WAAW,QAAgB,MAAe;AACzC,UAAI,CAAC,WAAW,SAAS,MAAM,GAAG;AACjC,cAAM,IAAI,MAAM,kBAAkB,MAAM,EAAE;AAAA,MAC3C;AACA,YAAM,SAAS,WAAW,eAAe,MAAM;AAC/C,YAAM,SAAS,OAAO,UAAU,IAAI;AACpC,UAAI,CAAC,OAAO,SAAS;AACpB,cAAM,IAAI,gBAAgB,cAAc,OAAO,MAAM,MAAM;AAAA,MAC5D;AACA,qBAAe;AACf,oBAAc,OAAO;AAAA,IACtB;AAAA,IAEA,KAAK,OAAwC;AAC5C,YAAM,SAAS,WAAW,eAAe,MAAM,IAAI;AACnD,YAAM,SAAS,OAAO,UAAU,MAAM,IAAI;AAC1C,UAAI,CAAC,OAAO,SAAS;AACpB,cAAM,IAAI,gBAAgB,SAAS,OAAO,MAAM,MAAM;AAAA,MACvD;AACA,wBAAkB,KAAK,EAAE,MAAM,MAAM,MAAM,MAAM,OAAO,KAAK,CAAC;AAAA,IAC/D;AAAA,IAEA,IAAI,SAAS;AACZ,aAAO,CAAC,GAAG,iBAAiB;AAAA,IAC7B;AAAA,IAEA,MAAM,KAAsC;AAC3C,YAAM,SAAS,WAAW,eAAe,IAAI,IAAI;AACjD,YAAM,SAAS,OAAO,UAAU,IAAI,IAAI;AACxC,UAAI,CAAC,OAAO,SAAS;AACpB,cAAM,IAAI;AAAA,UACT,2BAA2B,IAAI,IAAI,MAAM,OAAO,MAAM,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,QAC9F;AAAA,MACD;AACA,YAAM,IAAI,kBAAkB,IAAI,MAAM,OAAO,IAAI;AAAA,IAClD;AAAA,IAEA,IAAO,KAAoB,OAAU;AACpC,sBAAgB,IAAI,IAAI,IAAI,KAAK;AAAA,IAClC;AAAA,IAEA,IAAO,KAAuB;AAC7B,UAAI,CAAC,gBAAgB,IAAI,IAAI,EAAE,GAAG;AACjC,cAAM,IAAI,MAAM,wBAAwB,IAAI,GAAG,SAAS,CAAC,EAAE;AAAA,MAC5D;AACA,aAAO,gBAAgB,IAAI,IAAI,EAAE;AAAA,IAClC;AAAA,IAEA,UAAa,KAAmC;AAC/C,aAAO,gBAAgB,IAAI,IAAI,EAAE;AAAA,IAClC;AAAA,IAEA,sBAAyC;AACxC,aAAO;AAAA,QACN,IAAI,iBAAiB;AAAA,QACrB,gBAAgB,iBAAiB;AAAA,QACjC,OAAO;AAAA,QACP,MAAM,EAAE,GAAG,YAAY;AAAA,QACvB,WAAW,iBAAiB;AAAA,QAC5B,WAAW,oBAAI,KAAK;AAAA,MACrB;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;;;ACvIA,IAAM,eAAN,MAA8F;AAAA;AAAA,EACnE,aAA8B,CAAC;AAAA;AAAA,EAC/B,WAAW,oBAAI,IAA0B;AAAA,EAEnE,GACC,YACG,KACI;AACP,QAAI,IAAI,WAAW,EAAG,OAAM,IAAI,MAAM,kCAAkC;AACxE,UAAM,UAAU,IAAI,IAAI;AACxB,UAAM,mBAAmB;AACzB,UAAM,iBAAgC,OAAO,KAAK,UAAU;AAC3D,YAAM,QAAQ,GAAG;AAAA,IAClB;AACA,SAAK,SAAS,IAAI,SAAmB,EAAE,kBAAkB,SAAS,eAAe,CAAC;AAClF,WAAO;AAAA,EACR;AAAA,EAEA,IACC,YACO;AACP,SAAK,WAAW,KAAK,UAA2B;AAChD,WAAO;AAAA,EACR;AACD;AASO,IAAM,iBAAN,MAAM,gBAA2D;AAAA,EAQvE,YACkB,YACA,OAAc,CAAC,GAC/B;AAFgB;AACA;AAAA,EACf;AAAA,EAVK,mBAAoC,CAAC;AAAA;AAAA,EAErC,sBAAsB,oBAAI,IAA+C;AAAA;AAAA,EAEzE,qBAAqB,oBAAI,IAA+C;AAAA,EACxE,mBAAmB,oBAAI,IAA0B;AAAA;AAAA,EAQzD,IACC,oBAGO;AACP,QAAI,8BAA8B,iBAAgB;AACjD,WAAK,MAAM,kBAAkB;AAAA,IAC9B,OAAO;AACN,WAAK,iBAAiB,KAAK,kBAAmC;AAAA,IAC/D;AACA,WAAO;AAAA,EACR;AAAA,EAEQ,MAAM,OAA6C;AAC1D,QAAI,MAAM,eAAe,KAAK,YAAY;AACzC,YAAM,IAAI;AAAA,QACT,4BAA4B,MAAM,WAAW,IAAI,sBAAsB,KAAK,WAAW,IAAI;AAAA,MAC5F;AAAA,IACD;AAEA,SAAK,iBAAiB,KAAK,GAAG,MAAM,gBAAgB;AACpD,SAAK,mBAAmB,KAAK,qBAAqB,MAAM,mBAAmB;AAC3E,SAAK,mBAAmB,KAAK,oBAAoB,MAAM,kBAAkB;AAEzE,eAAW,CAAC,SAAS,KAAK,KAAK,MAAM,kBAAkB;AACtD,UAAI,CAAC,KAAK,iBAAiB,IAAI,OAAO,GAAG;AACxC,aAAK,iBAAiB,IAAI,SAAS;AAAA,UAClC,kBAAkB,CAAC,GAAG,MAAM,gBAAgB;AAAA,UAC5C,SAAS,MAAM;AAAA,QAChB,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA,EAEQ,mBAEP,QAEA,QACO;AACP,eAAW,CAAC,WAAW,YAAY,KAAK,QAAQ;AAC/C,UAAI,gBAAgB,OAAO,IAAI,SAAS;AACxC,UAAI,CAAC,eAAe;AAEnB,wBAAgB,IAAI,aAAkC;AACtD,eAAO,IAAI,WAAW,aAAa;AAAA,MACpC;AACA,iBAAW,CAAC,SAAS,KAAK,KAAK,aAAa,UAAU;AACrD,YAAI,CAAC,cAAc,SAAS,IAAI,OAAO,GAAG;AACzC,wBAAc,SAAS,IAAI,SAAS;AAAA,YACnC,kBAAkB,CAAC,GAAG,MAAM,gBAAgB;AAAA,YAC5C,SAAS,MAAM;AAAA,UAChB,CAAC;AAAA,QACF;AAAA,MACD;AACA,oBAAc,WAAW,KAAK,GAAG,aAAa,UAAU;AAAA,IACzD;AAAA,EACD;AAAA;AAAA,EAGA,MACC,MACA,OAOO;AACP,UAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AAChD,UAAM,UAAU,MAAM,QAAQ,IAAI;AAClC,UAAM,YAAY,UAAU,KAAK,qBAAqB,KAAK;AAE3D,eAAW,KAAK,OAAmB;AAClC,UAAI,SAAS,UAAU,IAAI,CAAC;AAC5B,UAAI,CAAC,QAAQ;AAEZ,iBAAS,IAAI,aAAkC;AAC/C,kBAAU,IAAI,GAAG,MAAM;AAAA,MACxB;AAEA,YAAM,MAAa;AAAA,IACpB;AACA,WAAO;AAAA,EACR;AAAA;AAAA,EAGA,GACC,QACA,YACG,KAII;AACP,QAAI,IAAI,WAAW,EAAG,OAAM,IAAI,MAAM,kCAAkC;AACxE,UAAM,UAAU,IAAI,IAAI;AACxB,UAAM,mBAAmB;AACzB,UAAM,iBAAgC,OAAO,KAAK,UAAU;AAC3D,YAAM,QAAQ,GAAG;AAAA,IAClB;AACA,SAAK,iBAAiB,IAAI,SAAmB;AAAA,MAC5C;AAAA,MACA,SAAS;AAAA,IACV,CAAC;AACD,WAAO;AAAA,EACR;AAAA;AAAA,EAGA,MAAM,SACL,UACA,SACmC;AACnC,QAAI,CAAC,KAAK,WAAW,SAAS,SAAS,KAAK,GAAG;AAC9C,aAAO;AAAA,QACN,IAAI;AAAA,QACJ,OAAO;AAAA,UACN,UAAU;AAAA,UACV,MAAM;AAAA,UACN,SAAS,kBAAkB,SAAS,KAAK;AAAA,QAC1C;AAAA,MACD;AAAA,IACD;AAEA,UAAM,gBAAgB,KAAK,WAAW,iBAAiB,QAAQ,IAAI;AACnE,UAAM,gBAAgB,cAAc,UAAU,QAAQ,OAAO;AAC7D,QAAI,CAAC,cAAc,SAAS;AAC3B,aAAO;AAAA,QACN,IAAI;AAAA,QACJ,OAAO;AAAA,UACN,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,QAAQ,cAAc,MAAM;AAAA,UAC5B,SAAS,4BAA4B,cAAc,MAAM,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,QACjG;AAAA,MACD;AAAA,IACD;AACA,UAAM,mBAAmB,EAAE,MAAM,QAAQ,MAAM,SAAS,cAAc,KAAK;AAE3E,UAAM,YAAY,SAAS;AAC3B,UAAM,eAAe,KAAK,oBAAoB,IAAI,SAAS;AAC3D,UAAM,cAAc,KAAK,mBAAmB,IAAI,SAAS;AACzD,UAAM,gBAAgB,cAAc,SAAS,IAAI,QAAQ,IAAI;AAC7D,UAAM,eAAe,aAAa,SAAS,IAAI,QAAQ,IAAI;AAC3D,UAAM,kBAAkB,KAAK,iBAAiB,IAAI,QAAQ,IAAI;AAE9D,QAAI;AAEJ,QAAI;AAEJ,QAAI,eAAe;AAClB,mBAAa;AACb,sBAAgB;AAAA,IACjB,WAAW,cAAc;AACxB,mBAAa;AACb,sBAAgB;AAAA,IACjB,WAAW,iBAAiB;AAC3B,mBAAa;AACb,sBAAgB;AAAA,IACjB;AAEA,QAAI,CAAC,YAAY;AAChB,aAAO;AAAA,QACN,IAAI;AAAA,QACJ,OAAO;AAAA,UACN,UAAU;AAAA,UACV,MAAM;AAAA,UACN,SAAS,2BAA2B,QAAQ,IAAI,eAAe,SAAS;AAAA,QACzE;AAAA,MACD;AAAA,IACD;AAEA,UAAM,kBAAmC,CAAC;AAC1C,QAAI,eAAe;AAClB,UAAI,aAAc,iBAAgB,KAAK,GAAG,aAAa,UAAU;AACjE,UAAI,eAAe,gBAAgB;AAClC,wBAAgB,KAAK,GAAG,YAAY,UAAU;AAAA,IAChD;AAEA,UAAM,QAAyB;AAAA,MAC9B,GAAG,KAAK;AAAA,MACR,GAAG;AAAA,MACH,GAAG,WAAW;AAAA,MACd,WAAW;AAAA,IACZ;AAEA,UAAM,MAAM;AAAA,MACX,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACN;AAEA,QAAI;AACH,YAAM,WAAW,QAAQ,KAAK;AAC9B,YAAM,SAAS,GAAG;AAClB,aAAO;AAAA,QACN,IAAI;AAAA,QACJ,UAAU,IAAI,oBAAoB;AAAA,QAClC,QAAQ,CAAC,GAAG,IAAI,MAAM;AAAA,MACvB;AAAA,IACD,SAAS,KAAK;AACb,UAAI,eAAe,mBAAmB;AACrC,eAAO;AAAA,UACN,IAAI;AAAA,UACJ,OAAO;AAAA,YACN,UAAU;AAAA,YACV,MAAM,IAAI;AAAA,YACV,MAAM,IAAI;AAAA,UACX;AAAA,QACD;AAAA,MACD;AACA,UAAI,eAAe,iBAAiB;AACnC,eAAO;AAAA,UACN,IAAI;AAAA,UACJ,OAAO;AAAA,YACN,UAAU;AAAA,YACV,QAAQ,IAAI;AAAA,YACZ,QAAQ,IAAI;AAAA,YACZ,SAAS,IAAI;AAAA,UACd;AAAA,QACD;AAAA,MACD;AACA,YAAM;AAAA,IACP;AAAA,EACD;AACD;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/definition.ts","../src/key.ts","../src/plugin.ts","../src/compose.ts","../src/context.ts","../src/hooks.ts","../src/router.ts"],"sourcesContent":["export type { Context } from \"./context.js\";\nexport type { WorkflowDefinition } from \"./definition.js\";\nexport { defineWorkflow } from \"./definition.js\";\nexport type { Handler } from \"./handler.js\";\nexport type { HookEvent } from \"./hooks.js\";\nexport type { ContextKey } from \"./key.js\";\nexport { createKey } from \"./key.js\";\nexport type { Middleware } from \"./middleware.js\";\nexport type { Plugin } from \"./plugin.js\";\nexport { definePlugin, isPlugin } from \"./plugin.js\";\nexport type { ReadonlyContext } from \"./readonly-context.js\";\nexport type { RouterOptions } from \"./router.js\";\nexport { WorkflowRouter } from \"./router.js\";\nexport type { WorkflowSnapshot } from \"./snapshot.js\";\nexport type {\n\tCommandNames,\n\tCommandPayload,\n\tDispatchResult,\n\tErrorCodes,\n\tErrorData,\n\tEventData,\n\tEventNames,\n\tPipelineError,\n\tStateData,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowOf,\n} from \"./types.js\";\nexport { DomainErrorSignal, ValidationError } from \"./types.js\";\n","import type { ZodType, z } from \"zod\";\n\nexport interface WorkflowConfig {\n\tmodelVersion?: number;\n\tstates: Record<string, ZodType>;\n\tcommands: Record<string, ZodType>;\n\tevents: Record<string, ZodType>;\n\terrors: Record<string, ZodType>;\n}\n\nexport type StateNames<T extends WorkflowConfig> = keyof T[\"states\"] & string;\nexport type CommandNames<T extends WorkflowConfig> = keyof T[\"commands\"] & string;\nexport type EventNames<T extends WorkflowConfig> = keyof T[\"events\"] & string;\nexport type ErrorCodes<T extends WorkflowConfig> = keyof T[\"errors\"] & string;\n\nexport type StateData<\n\tT extends WorkflowConfig,\n\tS extends StateNames<T>,\n> = T[\"states\"][S] extends ZodType ? z.infer<T[\"states\"][S]> : never;\n\nexport type CommandPayload<\n\tT extends WorkflowConfig,\n\tC extends CommandNames<T>,\n> = T[\"commands\"][C] extends ZodType ? z.infer<T[\"commands\"][C]> : never;\n\nexport type EventData<\n\tT extends WorkflowConfig,\n\tE extends EventNames<T>,\n> = T[\"events\"][E] extends ZodType ? z.infer<T[\"events\"][E]> : never;\n\nexport type ErrorData<\n\tT extends WorkflowConfig,\n\tC extends ErrorCodes<T>,\n> = T[\"errors\"][C] extends ZodType ? z.infer<T[\"errors\"][C]> : never;\n\n/** Workflow narrowed to a specific known state. */\nexport interface WorkflowOf<TConfig extends WorkflowConfig, S extends StateNames<TConfig>> {\n\treadonly id: string;\n\treadonly definitionName: string;\n\treadonly state: S;\n\treadonly data: StateData<TConfig, S>;\n\treadonly createdAt: Date;\n\treadonly updatedAt: Date;\n}\n\n/** Discriminated union of all possible workflow states — checking .state narrows .data. */\nexport type Workflow<TConfig extends WorkflowConfig = WorkflowConfig> = {\n\t[S in StateNames<TConfig>]: WorkflowOf<TConfig, S>;\n}[StateNames<TConfig>];\n\nexport type PipelineError<TConfig extends WorkflowConfig = WorkflowConfig> =\n\t| {\n\t\t\tcategory: \"validation\";\n\t\t\tsource: \"command\" | \"state\" | \"event\" | \"transition\" | \"restore\";\n\t\t\tissues: z.core.$ZodIssue[];\n\t\t\tmessage: string;\n\t }\n\t| {\n\t\t\tcategory: \"domain\";\n\t\t\tcode: ErrorCodes<TConfig>;\n\t\t\tdata: ErrorData<TConfig, ErrorCodes<TConfig>>;\n\t }\n\t| {\n\t\t\tcategory: \"router\";\n\t\t\tcode: \"NO_HANDLER\" | \"UNKNOWN_STATE\";\n\t\t\tmessage: string;\n\t };\n\nexport type DispatchResult<TConfig extends WorkflowConfig = WorkflowConfig> =\n\t| {\n\t\t\tok: true;\n\t\t\tworkflow: Workflow<TConfig>;\n\t\t\tevents: Array<{ type: EventNames<TConfig>; data: unknown }>;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\terror: PipelineError<TConfig>;\n\t };\n\n/** Thrown internally when Zod validation fails during dispatch. */\nexport class ValidationError extends Error {\n\tconstructor(\n\t\tpublic readonly source: \"command\" | \"state\" | \"event\" | \"transition\" | \"restore\",\n\t\tpublic readonly issues: z.core.$ZodIssue[],\n\t) {\n\t\tsuper(`Validation failed (${source}): ${issues.map((i) => i.message).join(\", \")}`);\n\t\tthis.name = \"ValidationError\";\n\t}\n}\n\n/** Thrown internally when a handler calls ctx.error(). Caught by the router. */\nexport class DomainErrorSignal extends Error {\n\tconstructor(\n\t\tpublic readonly code: string,\n\t\tpublic readonly data: unknown,\n\t) {\n\t\tsuper(`Domain error: ${code}`);\n\t\tthis.name = \"DomainErrorSignal\";\n\t}\n}\n","import type { ZodType, z } from \"zod\";\nimport type { WorkflowSnapshot } from \"./snapshot.js\";\nimport type { StateNames, Workflow, WorkflowConfig, WorkflowOf } from \"./types.js\";\nimport { ValidationError } from \"./types.js\";\n\n/** The result of defineWorkflow() — holds schemas and creates workflow instances. */\nexport interface WorkflowDefinition<TConfig extends WorkflowConfig = WorkflowConfig> {\n\treadonly config: TConfig;\n\treadonly name: string;\n\tcreateWorkflow<S extends StateNames<TConfig>>(\n\t\tid: string,\n\t\tconfig: { initialState: S; data: z.infer<TConfig[\"states\"][S]> },\n\t): WorkflowOf<TConfig, S>;\n\tgetStateSchema(stateName: string): ZodType;\n\tgetCommandSchema(commandName: string): ZodType;\n\tgetEventSchema(eventName: string): ZodType;\n\tgetErrorSchema(errorCode: string): ZodType;\n\thasState(stateName: string): boolean;\n\tsnapshot(workflow: Workflow<TConfig>): WorkflowSnapshot<TConfig>;\n\trestore(\n\t\tsnapshot: WorkflowSnapshot<TConfig>,\n\t): { ok: true; workflow: Workflow<TConfig> } | { ok: false; error: ValidationError };\n}\n\n/**\n * Creates a workflow definition from a name and Zod schema configuration.\n */\nexport function defineWorkflow<const TConfig extends WorkflowConfig>(\n\tname: string,\n\tconfig: TConfig,\n): WorkflowDefinition<TConfig> {\n\treturn {\n\t\tconfig,\n\t\tname,\n\n\t\tcreateWorkflow(id, wfConfig) {\n\t\t\tconst schema = config.states[wfConfig.initialState as string];\n\t\t\tif (!schema) throw new Error(`Unknown state: ${wfConfig.initialState as string}`);\n\t\t\tconst result = schema.safeParse(wfConfig.data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid initial data for state '${wfConfig.initialState as string}': ${result.error.issues.map((i) => i.message).join(\", \")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst now = new Date();\n\t\t\treturn {\n\t\t\t\tid,\n\t\t\t\tdefinitionName: name,\n\t\t\t\tstate: wfConfig.initialState,\n\t\t\t\tdata: result.data,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t} as WorkflowOf<TConfig, typeof wfConfig.initialState>;\n\t\t},\n\n\t\tgetStateSchema(stateName: string): ZodType {\n\t\t\tconst schema = config.states[stateName];\n\t\t\tif (!schema) throw new Error(`Unknown state: ${stateName}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\tgetCommandSchema(commandName: string): ZodType {\n\t\t\tconst schema = config.commands[commandName];\n\t\t\tif (!schema) throw new Error(`Unknown command: ${commandName}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\tgetEventSchema(eventName: string): ZodType {\n\t\t\tconst schema = config.events[eventName];\n\t\t\tif (!schema) throw new Error(`Unknown event: ${eventName}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\tgetErrorSchema(errorCode: string): ZodType {\n\t\t\tconst schema = config.errors[errorCode];\n\t\t\tif (!schema) throw new Error(`Unknown error: ${errorCode}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\thasState(stateName: string): boolean {\n\t\t\treturn stateName in config.states;\n\t\t},\n\n\t\tsnapshot(workflow: Workflow<TConfig>): WorkflowSnapshot<TConfig> {\n\t\t\treturn {\n\t\t\t\tid: workflow.id,\n\t\t\t\tdefinitionName: name,\n\t\t\t\tstate: workflow.state,\n\t\t\t\tdata: workflow.data,\n\t\t\t\tcreatedAt: workflow.createdAt.toISOString(),\n\t\t\t\tupdatedAt: workflow.updatedAt.toISOString(),\n\t\t\t\tmodelVersion: config.modelVersion ?? 1,\n\t\t\t} as WorkflowSnapshot<TConfig>;\n\t\t},\n\n\t\trestore(\n\t\t\tsnap: WorkflowSnapshot<TConfig>,\n\t\t): { ok: true; workflow: Workflow<TConfig> } | { ok: false; error: ValidationError } {\n\t\t\tconst stateSchema = config.states[snap.state as string];\n\t\t\tif (!stateSchema) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: new ValidationError(\"restore\", [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcode: \"custom\",\n\t\t\t\t\t\t\tmessage: `Unknown state: ${snap.state}`,\n\t\t\t\t\t\t\tinput: snap.state,\n\t\t\t\t\t\t\tpath: [\"state\"],\n\t\t\t\t\t\t},\n\t\t\t\t\t]),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst result = stateSchema.safeParse(snap.data);\n\t\t\tif (!result.success) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: new ValidationError(\"restore\", result.error.issues),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tok: true,\n\t\t\t\tworkflow: {\n\t\t\t\t\tid: snap.id,\n\t\t\t\t\tdefinitionName: snap.definitionName,\n\t\t\t\t\tstate: snap.state,\n\t\t\t\t\tdata: result.data,\n\t\t\t\t\tcreatedAt: new Date(snap.createdAt),\n\t\t\t\t\tupdatedAt: new Date(snap.updatedAt),\n\t\t\t\t} as Workflow<TConfig>,\n\t\t\t};\n\t\t},\n\t};\n}\n","/** A phantom-typed key for type-safe middleware state storage. */\nexport interface ContextKey<T> {\n\treadonly _phantom: T;\n\treadonly id: symbol;\n}\n\n/** Creates a unique typed key for storing/retrieving values in context. */\nexport function createKey<T>(name: string): ContextKey<T> {\n\treturn { id: Symbol(name) } as ContextKey<T>;\n}\n","import type { WorkflowRouter } from \"./router.js\";\nimport type { WorkflowConfig } from \"./types.js\";\n\nconst PLUGIN_SYMBOL: unique symbol = Symbol.for(\"ryte:plugin\");\n\n/** A branded plugin function that can be passed to router.use(). */\nexport type Plugin<TConfig extends WorkflowConfig, TDeps> = ((\n\trouter: WorkflowRouter<TConfig, TDeps>,\n) => void) & { readonly [PLUGIN_SYMBOL]: true };\n\n/** Brands a function as a Ryte plugin for use with router.use(). */\nexport function definePlugin<TConfig extends WorkflowConfig, TDeps>(\n\tfn: (router: WorkflowRouter<TConfig, TDeps>) => void,\n): Plugin<TConfig, TDeps> {\n\tconst plugin = fn as Plugin<TConfig, TDeps>;\n\tObject.defineProperty(plugin, PLUGIN_SYMBOL, { value: true, writable: false });\n\treturn plugin;\n}\n\n/** Checks whether a value is a branded Ryte plugin. */\nexport function isPlugin(value: unknown): value is Plugin<WorkflowConfig, unknown> {\n\treturn typeof value === \"function\" && PLUGIN_SYMBOL in value;\n}\n","type Middleware<TCtx> = (ctx: TCtx, next: () => Promise<void>) => Promise<void>;\n\n/** Composes an array of middleware into a single function (Koa-style onion model). */\nexport function compose<TCtx>(middleware: Middleware<TCtx>[]): (ctx: TCtx) => Promise<void> {\n\treturn async (ctx: TCtx) => {\n\t\tlet index = -1;\n\t\tasync function dispatch(i: number): Promise<void> {\n\t\t\tif (i <= index) throw new Error(\"next() called multiple times\");\n\t\t\tindex = i;\n\t\t\tconst fn = middleware[i];\n\t\t\tif (!fn) return;\n\t\t\tawait fn(ctx, () => dispatch(i + 1));\n\t\t}\n\t\tawait dispatch(0);\n\t};\n}\n","import type { WorkflowDefinition } from \"./definition.js\";\nimport type { ContextKey } from \"./key.js\";\nimport type {\n\tCommandNames,\n\tCommandPayload,\n\tErrorCodes,\n\tErrorData,\n\tEventData,\n\tEventNames,\n\tStateData,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowOf,\n} from \"./types.js\";\nimport { DomainErrorSignal, ValidationError } from \"./types.js\";\n\n/** Mutable context flowing through the middleware pipeline during dispatch. */\nexport interface Context<\n\tTConfig extends WorkflowConfig,\n\tTDeps,\n\tTState extends StateNames<TConfig> = StateNames<TConfig>,\n\tTCommand extends CommandNames<TConfig> = CommandNames<TConfig>,\n> {\n\treadonly command: {\n\t\treadonly type: TCommand;\n\t\treadonly payload: CommandPayload<TConfig, TCommand>;\n\t};\n\treadonly workflow: WorkflowOf<TConfig, TState>;\n\treadonly deps: TDeps;\n\n\treadonly data: StateData<TConfig, TState>;\n\tupdate(data: Partial<StateData<TConfig, TState>>): void;\n\n\ttransition<Target extends StateNames<TConfig>>(\n\t\ttarget: Target,\n\t\tdata: StateData<TConfig, Target>,\n\t): void;\n\n\temit<E extends EventNames<TConfig>>(event: { type: E; data: EventData<TConfig, E> }): void;\n\treadonly events: ReadonlyArray<{ type: EventNames<TConfig>; data: unknown }>;\n\n\terror<C extends ErrorCodes<TConfig>>(err: { code: C; data: ErrorData<TConfig, C> }): never;\n\n\tset<T>(key: ContextKey<T>, value: T): void;\n\tget<T>(key: ContextKey<T>): T;\n\tgetOrNull<T>(key: ContextKey<T>): T | undefined;\n\n\t/** @internal — not part of the handler API */\n\tgetWorkflowSnapshot(): Workflow<TConfig>;\n}\n\ninterface DomainEvent {\n\ttype: string;\n\tdata: unknown;\n}\n\n/** @internal Creates a context for dispatch. Not part of public API. */\nexport function createContext<TConfig extends WorkflowConfig, TDeps>(\n\tdefinition: WorkflowDefinition<TConfig>,\n\toriginalWorkflow: Workflow<TConfig>,\n\tcommand: { type: string; payload: unknown },\n\tdeps: TDeps,\n): Context<TConfig, TDeps> {\n\tlet mutableState = originalWorkflow.state;\n\tlet mutableData: Record<string, unknown> = {\n\t\t...(originalWorkflow.data as Record<string, unknown>),\n\t};\n\n\tconst accumulatedEvents: DomainEvent[] = [];\n\tconst middlewareState = new Map<symbol, unknown>();\n\n\tconst ctx = {\n\t\tcommand,\n\t\tworkflow: originalWorkflow,\n\t\tdeps,\n\n\t\tget data() {\n\t\t\treturn { ...mutableData } as StateData<TConfig, StateNames<TConfig>>;\n\t\t},\n\n\t\tupdate(data: Record<string, unknown>) {\n\t\t\tconst merged = { ...mutableData, ...data };\n\t\t\tconst schema = definition.getStateSchema(mutableState);\n\t\t\tconst result = schema.safeParse(merged);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new ValidationError(\"state\", result.error.issues);\n\t\t\t}\n\t\t\tmutableData = result.data as Record<string, unknown>;\n\t\t},\n\n\t\ttransition(target: string, data: unknown) {\n\t\t\tif (!definition.hasState(target)) {\n\t\t\t\tthrow new Error(`Unknown state: ${target}`);\n\t\t\t}\n\t\t\tconst schema = definition.getStateSchema(target);\n\t\t\tconst result = schema.safeParse(data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new ValidationError(\"transition\", result.error.issues);\n\t\t\t}\n\t\t\tmutableState = target;\n\t\t\tmutableData = result.data as Record<string, unknown>;\n\t\t},\n\n\t\temit(event: { type: string; data: unknown }) {\n\t\t\tconst schema = definition.getEventSchema(event.type);\n\t\t\tconst result = schema.safeParse(event.data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new ValidationError(\"event\", result.error.issues);\n\t\t\t}\n\t\t\taccumulatedEvents.push({ type: event.type, data: result.data });\n\t\t},\n\n\t\tget events() {\n\t\t\treturn [...accumulatedEvents];\n\t\t},\n\n\t\terror(err: { code: string; data: unknown }) {\n\t\t\tconst schema = definition.getErrorSchema(err.code);\n\t\t\tconst result = schema.safeParse(err.data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid error data for '${err.code}': ${result.error.issues.map((i) => i.message).join(\", \")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new DomainErrorSignal(err.code, result.data);\n\t\t},\n\n\t\tset<T>(key: ContextKey<T>, value: T) {\n\t\t\tmiddlewareState.set(key.id, value);\n\t\t},\n\n\t\tget<T>(key: ContextKey<T>): T {\n\t\t\tif (!middlewareState.has(key.id)) {\n\t\t\t\tthrow new Error(`Context key not set: ${key.id.toString()}`);\n\t\t\t}\n\t\t\treturn middlewareState.get(key.id) as T;\n\t\t},\n\n\t\tgetOrNull<T>(key: ContextKey<T>): T | undefined {\n\t\t\treturn middlewareState.get(key.id) as T | undefined;\n\t\t},\n\n\t\tgetWorkflowSnapshot(): Workflow<TConfig> {\n\t\t\treturn {\n\t\t\t\tid: originalWorkflow.id,\n\t\t\t\tdefinitionName: originalWorkflow.definitionName,\n\t\t\t\tstate: mutableState,\n\t\t\t\tdata: { ...mutableData },\n\t\t\t\tcreatedAt: originalWorkflow.createdAt,\n\t\t\t\tupdatedAt: new Date(),\n\t\t\t} as Workflow<TConfig>;\n\t\t},\n\t};\n\n\treturn ctx as unknown as Context<TConfig, TDeps>;\n}\n","/** The lifecycle hook event names. */\nexport type HookEvent = \"dispatch:start\" | \"dispatch:end\" | \"transition\" | \"error\" | \"event\";\n\nexport const HOOK_EVENTS: ReadonlySet<string> = new Set<HookEvent>([\n\t\"dispatch:start\",\n\t\"dispatch:end\",\n\t\"transition\",\n\t\"error\",\n\t\"event\",\n]);\n\n/**\n * Internal registry for lifecycle hook callbacks.\n * Hooks are observers — errors are caught and forwarded, never affecting dispatch.\n */\nexport class HookRegistry {\n\t// biome-ignore lint/complexity/noBannedTypes: callbacks have varying signatures per hook event\n\tprivate hooks = new Map<string, Function[]>();\n\n\t/** Register a callback for a hook event. */\n\t// biome-ignore lint/complexity/noBannedTypes: callbacks have varying signatures per hook event\n\tadd(event: string, callback: Function): void {\n\t\tconst existing = this.hooks.get(event) ?? [];\n\t\texisting.push(callback);\n\t\tthis.hooks.set(event, existing);\n\t}\n\n\t/** Emit a hook event, calling all registered callbacks. Errors are caught and forwarded. */\n\tasync emit(event: string, onError: (err: unknown) => void, ...args: unknown[]): Promise<void> {\n\t\tconst callbacks = this.hooks.get(event);\n\t\tif (!callbacks) return;\n\t\tfor (const cb of callbacks) {\n\t\t\ttry {\n\t\t\t\tawait cb(...args);\n\t\t\t} catch (err) {\n\t\t\t\tonError(err);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Merge another registry's hooks into this one (used by composable routers). */\n\tmerge(other: HookRegistry): void {\n\t\tfor (const [event, callbacks] of other.hooks) {\n\t\t\tconst existing = this.hooks.get(event) ?? [];\n\t\t\texisting.push(...callbacks);\n\t\t\tthis.hooks.set(event, existing);\n\t\t}\n\t}\n}\n","import { compose } from \"./compose.js\";\nimport { type Context, createContext } from \"./context.js\";\nimport type { WorkflowDefinition } from \"./definition.js\";\nimport { HOOK_EVENTS, HookRegistry } from \"./hooks.js\";\nimport type { Plugin } from \"./plugin.js\";\nimport { isPlugin } from \"./plugin.js\";\nimport type { ReadonlyContext } from \"./readonly-context.js\";\nimport type {\n\tCommandNames,\n\tDispatchResult,\n\tErrorCodes,\n\tErrorData,\n\tEventNames,\n\tPipelineError,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n} from \"./types.js\";\nimport { DomainErrorSignal, ValidationError } from \"./types.js\";\n\n// biome-ignore lint/suspicious/noExplicitAny: internal type erasure for heterogeneous middleware storage\ntype AnyMiddleware = (ctx: any, next: () => Promise<void>) => Promise<void>;\n// biome-ignore lint/suspicious/noExplicitAny: internal type erasure for heterogeneous handler storage\ntype AnyHandler = (ctx: any) => void | Promise<void>;\n\ntype HandlerEntry = {\n\tinlineMiddleware: AnyMiddleware[];\n\thandler: AnyMiddleware;\n};\n\nexport interface RouterOptions {\n\tonHookError?: (error: unknown) => void;\n}\n\nclass StateBuilder<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TConfig>> {\n\t/** @internal */ readonly middleware: AnyMiddleware[] = [];\n\t/** @internal */ readonly handlers = new Map<string, HandlerEntry>();\n\n\ton<C extends CommandNames<TConfig>>(\n\t\tcommand: C,\n\t\t...fns: [...AnyMiddleware[], (ctx: Context<TConfig, TDeps, TState, C>) => void | Promise<void>]\n\t): this {\n\t\tif (fns.length === 0) throw new Error(\"on() requires at least a handler\");\n\t\tconst handler = fns.pop() as AnyHandler;\n\t\tconst inlineMiddleware = fns as AnyMiddleware[];\n\t\tconst wrappedHandler: AnyMiddleware = async (ctx, _next) => {\n\t\t\tawait handler(ctx);\n\t\t};\n\t\tthis.handlers.set(command as string, { inlineMiddleware, handler: wrappedHandler });\n\t\treturn this;\n\t}\n\n\tuse(\n\t\tmiddleware: (ctx: Context<TConfig, TDeps, TState>, next: () => Promise<void>) => Promise<void>,\n\t): this {\n\t\tthis.middleware.push(middleware as AnyMiddleware);\n\t\treturn this;\n\t}\n}\n\n/**\n * Routes commands to handlers based on workflow state.\n *\n * Supports global middleware, state-scoped middleware, inline middleware,\n * wildcard handlers, and multi-state handlers.\n */\n// biome-ignore lint/complexity/noBannedTypes: {} is correct here — TDeps defaults to \"no deps\", inferred away when deps are provided\nexport class WorkflowRouter<TConfig extends WorkflowConfig, TDeps = {}> {\n\tprivate globalMiddleware: AnyMiddleware[] = [];\n\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\tprivate singleStateBuilders = new Map<string, StateBuilder<TConfig, TDeps, any>>();\n\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\tprivate multiStateBuilders = new Map<string, StateBuilder<TConfig, TDeps, any>>();\n\tprivate wildcardHandlers = new Map<string, HandlerEntry>();\n\tprivate hookRegistry = new HookRegistry();\n\tprivate readonly onHookError: (error: unknown) => void;\n\n\tconstructor(\n\t\tprivate readonly definition: WorkflowDefinition<TConfig>,\n\t\tprivate readonly deps: TDeps = {} as TDeps,\n\t\toptions: RouterOptions = {},\n\t) {\n\t\tthis.onHookError = options.onHookError ?? console.error;\n\t}\n\n\t/** Adds global middleware, merges another router, or applies a plugin. */\n\tuse(\n\t\targ:\n\t\t\t| ((ctx: Context<TConfig, TDeps>, next: () => Promise<void>) => Promise<void>)\n\t\t\t| WorkflowRouter<TConfig, TDeps>\n\t\t\t| Plugin<TConfig, TDeps>,\n\t): this {\n\t\tif (arg instanceof WorkflowRouter) {\n\t\t\tthis.merge(arg);\n\t\t} else if (isPlugin(arg)) {\n\t\t\t(arg as (router: WorkflowRouter<TConfig, TDeps>) => void)(this);\n\t\t} else {\n\t\t\tthis.globalMiddleware.push(arg as AnyMiddleware);\n\t\t}\n\t\treturn this;\n\t}\n\n\tprivate merge(child: WorkflowRouter<TConfig, TDeps>): void {\n\t\tif (child.definition !== this.definition) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot merge router for '${child.definition.name}' into router for '${this.definition.name}': definition mismatch`,\n\t\t\t);\n\t\t}\n\n\t\tthis.globalMiddleware.push(...child.globalMiddleware);\n\t\tthis.mergeStateBuilders(this.singleStateBuilders, child.singleStateBuilders);\n\t\tthis.mergeStateBuilders(this.multiStateBuilders, child.multiStateBuilders);\n\n\t\tfor (const [command, entry] of child.wildcardHandlers) {\n\t\t\tif (!this.wildcardHandlers.has(command)) {\n\t\t\t\tthis.wildcardHandlers.set(command, {\n\t\t\t\t\tinlineMiddleware: [...entry.inlineMiddleware],\n\t\t\t\t\thandler: entry.handler,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis.hookRegistry.merge(child.hookRegistry);\n\t}\n\n\tprivate mergeStateBuilders(\n\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\t\ttarget: Map<string, StateBuilder<TConfig, TDeps, any>>,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\t\tsource: Map<string, StateBuilder<TConfig, TDeps, any>>,\n\t): void {\n\t\tfor (const [stateName, childBuilder] of source) {\n\t\t\tlet parentBuilder = target.get(stateName);\n\t\t\tif (!parentBuilder) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — state name is dynamic at runtime\n\t\t\t\tparentBuilder = new StateBuilder<TConfig, TDeps, any>();\n\t\t\t\ttarget.set(stateName, parentBuilder);\n\t\t\t}\n\t\t\tfor (const [command, entry] of childBuilder.handlers) {\n\t\t\t\tif (!parentBuilder.handlers.has(command)) {\n\t\t\t\t\tparentBuilder.handlers.set(command, {\n\t\t\t\t\t\tinlineMiddleware: [...entry.inlineMiddleware],\n\t\t\t\t\t\thandler: entry.handler,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tparentBuilder.middleware.push(...childBuilder.middleware);\n\t\t}\n\t}\n\n\t/** Registers handlers for one or more states. */\n\tstate<P extends StateNames<TConfig> | readonly StateNames<TConfig>[]>(\n\t\tname: P,\n\t\tsetup: (\n\t\t\tstate: StateBuilder<\n\t\t\t\tTConfig,\n\t\t\t\tTDeps,\n\t\t\t\tP extends readonly (infer S)[] ? S & StateNames<TConfig> : P & StateNames<TConfig>\n\t\t\t>,\n\t\t) => void,\n\t): this {\n\t\tconst names = Array.isArray(name) ? name : [name];\n\t\tconst isMulti = Array.isArray(name);\n\t\tconst routerMap = isMulti ? this.multiStateBuilders : this.singleStateBuilders;\n\n\t\tfor (const n of names as string[]) {\n\t\t\tlet router = routerMap.get(n);\n\t\t\tif (!router) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — state name is dynamic at runtime\n\t\t\t\trouter = new StateBuilder<TConfig, TDeps, any>();\n\t\t\t\trouterMap.set(n, router);\n\t\t\t}\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — setup callback expects a specific state type\n\t\t\tsetup(router as any);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/** Registers a lifecycle hook callback. */\n\ton(\n\t\tevent: \"dispatch:start\",\n\t\tcallback: (ctx: ReadonlyContext<TConfig, TDeps>) => void | Promise<void>,\n\t): this;\n\ton(\n\t\tevent: \"dispatch:end\",\n\t\tcallback: (\n\t\t\tctx: ReadonlyContext<TConfig, TDeps>,\n\t\t\tresult: DispatchResult<TConfig>,\n\t\t) => void | Promise<void>,\n\t): this;\n\ton(\n\t\tevent: \"transition\",\n\t\tcallback: (\n\t\t\tfrom: StateNames<TConfig>,\n\t\t\tto: StateNames<TConfig>,\n\t\t\tworkflow: Workflow<TConfig>,\n\t\t) => void | Promise<void>,\n\t): this;\n\ton(\n\t\tevent: \"error\",\n\t\tcallback: (\n\t\t\terror: PipelineError<TConfig>,\n\t\t\tctx: ReadonlyContext<TConfig, TDeps>,\n\t\t) => void | Promise<void>,\n\t): this;\n\ton(\n\t\tevent: \"event\",\n\t\tcallback: (\n\t\t\tevent: { type: EventNames<TConfig>; data: unknown },\n\t\t\tworkflow: Workflow<TConfig>,\n\t\t) => void | Promise<void>,\n\t): this;\n\t/** Registers a wildcard handler that matches any state. */\n\ton<C extends CommandNames<TConfig>>(\n\t\tstate: \"*\",\n\t\tcommand: C,\n\t\t...fns: [\n\t\t\t...AnyMiddleware[],\n\t\t\t(ctx: Context<TConfig, TDeps, StateNames<TConfig>, C>) => void | Promise<void>,\n\t\t]\n\t): this;\n\t// biome-ignore lint/suspicious/noExplicitAny: implementation signature must be loose to handle all overloads\n\ton(...args: any[]): this {\n\t\tconst first = args[0] as string;\n\n\t\tif (HOOK_EVENTS.has(first)) {\n\t\t\t// biome-ignore lint/complexity/noBannedTypes: callbacks have varying signatures per hook event\n\t\t\tthis.hookRegistry.add(first, args[1] as Function);\n\t\t\treturn this;\n\t\t}\n\n\t\tif (first === \"*\") {\n\t\t\tconst command = args[1] as string;\n\t\t\tconst fns = args.slice(2) as unknown[];\n\t\t\tif (fns.length === 0) throw new Error(\"on() requires at least a handler\");\n\t\t\tconst handler = fns.pop() as AnyHandler;\n\t\t\tconst inlineMiddleware = fns as AnyMiddleware[];\n\t\t\tconst wrappedHandler: AnyMiddleware = async (ctx, _next) => {\n\t\t\t\tawait handler(ctx);\n\t\t\t};\n\t\t\tthis.wildcardHandlers.set(command, {\n\t\t\t\tinlineMiddleware,\n\t\t\t\thandler: wrappedHandler,\n\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\tthrow new Error(`Unknown event or state: ${first}`);\n\t}\n\n\t/** Dispatches a command to the appropriate handler and returns the result. */\n\tasync dispatch(\n\t\tworkflow: Workflow<TConfig>,\n\t\tcommand: { type: CommandNames<TConfig>; payload: unknown },\n\t): Promise<DispatchResult<TConfig>> {\n\t\tif (!this.definition.hasState(workflow.state)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"router\",\n\t\t\t\t\tcode: \"UNKNOWN_STATE\",\n\t\t\t\t\tmessage: `Unknown state: ${workflow.state}`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst commandSchema = this.definition.getCommandSchema(command.type);\n\t\tconst payloadResult = commandSchema.safeParse(command.payload);\n\t\tif (!payloadResult.success) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"validation\",\n\t\t\t\t\tsource: \"command\",\n\t\t\t\t\tissues: payloadResult.error.issues,\n\t\t\t\t\tmessage: `Invalid command payload: ${payloadResult.error.issues.map((i) => i.message).join(\", \")}`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tconst validatedCommand = { type: command.type, payload: payloadResult.data };\n\n\t\tconst stateName = workflow.state;\n\t\tconst singleRouter = this.singleStateBuilders.get(stateName);\n\t\tconst multiRouter = this.multiStateBuilders.get(stateName);\n\t\tconst singleHandler = singleRouter?.handlers.get(command.type);\n\t\tconst multiHandler = multiRouter?.handlers.get(command.type);\n\t\tconst wildcardHandler = this.wildcardHandlers.get(command.type);\n\n\t\tlet routeEntry: HandlerEntry | undefined;\n\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — matched router's state type is dynamic\n\t\tlet matchedRouter: StateBuilder<TConfig, TDeps, any> | undefined;\n\n\t\tif (singleHandler) {\n\t\t\trouteEntry = singleHandler;\n\t\t\tmatchedRouter = singleRouter;\n\t\t} else if (multiHandler) {\n\t\t\trouteEntry = multiHandler;\n\t\t\tmatchedRouter = multiRouter;\n\t\t} else if (wildcardHandler) {\n\t\t\trouteEntry = wildcardHandler;\n\t\t\tmatchedRouter = undefined;\n\t\t}\n\n\t\tif (!routeEntry) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"router\",\n\t\t\t\t\tcode: \"NO_HANDLER\",\n\t\t\t\t\tmessage: `No handler for command '${command.type}' in state '${stateName}'`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst stateMiddleware: AnyMiddleware[] = [];\n\t\tif (matchedRouter) {\n\t\t\tif (singleRouter) stateMiddleware.push(...singleRouter.middleware);\n\t\t\tif (multiRouter && multiRouter !== singleRouter)\n\t\t\t\tstateMiddleware.push(...multiRouter.middleware);\n\t\t}\n\n\t\tconst chain: AnyMiddleware[] = [\n\t\t\t...this.globalMiddleware,\n\t\t\t...stateMiddleware,\n\t\t\t...routeEntry.inlineMiddleware,\n\t\t\trouteEntry.handler,\n\t\t];\n\n\t\tconst ctx = createContext<TConfig, TDeps>(\n\t\t\tthis.definition,\n\t\t\tworkflow,\n\t\t\tvalidatedCommand,\n\t\t\tthis.deps,\n\t\t);\n\n\t\t// Hook: dispatch:start\n\t\tawait this.hookRegistry.emit(\"dispatch:start\", this.onHookError, ctx);\n\n\t\ttry {\n\t\t\tconst composed = compose(chain);\n\t\t\tawait composed(ctx);\n\t\t\tconst result: DispatchResult<TConfig> = {\n\t\t\t\tok: true as const,\n\t\t\t\tworkflow: ctx.getWorkflowSnapshot(),\n\t\t\t\tevents: [...ctx.events],\n\t\t\t};\n\n\t\t\t// Hook: transition (if state changed)\n\t\t\tif (result.ok && result.workflow.state !== workflow.state) {\n\t\t\t\tawait this.hookRegistry.emit(\n\t\t\t\t\t\"transition\",\n\t\t\t\t\tthis.onHookError,\n\t\t\t\t\tworkflow.state,\n\t\t\t\t\tresult.workflow.state,\n\t\t\t\t\tresult.workflow,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Hook: event (for each emitted event)\n\t\t\tif (result.ok) {\n\t\t\t\tfor (const event of result.events) {\n\t\t\t\t\tawait this.hookRegistry.emit(\"event\", this.onHookError, event, result.workflow);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Hook: dispatch:end\n\t\t\tawait this.hookRegistry.emit(\"dispatch:end\", this.onHookError, ctx, result);\n\n\t\t\treturn result;\n\t\t} catch (err) {\n\t\t\tlet result: DispatchResult<TConfig>;\n\t\t\tif (err instanceof DomainErrorSignal) {\n\t\t\t\tresult = {\n\t\t\t\t\tok: false as const,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcategory: \"domain\" as const,\n\t\t\t\t\t\tcode: err.code as ErrorCodes<TConfig>,\n\t\t\t\t\t\tdata: err.data as ErrorData<TConfig, ErrorCodes<TConfig>>,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} else if (err instanceof ValidationError) {\n\t\t\t\tresult = {\n\t\t\t\t\tok: false as const,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcategory: \"validation\" as const,\n\t\t\t\t\t\tsource: err.source,\n\t\t\t\t\t\tissues: err.issues,\n\t\t\t\t\t\tmessage: err.message,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tthrow err;\n\t\t\t}\n\n\t\t\t// Hook: error\n\t\t\tawait this.hookRegistry.emit(\"error\", this.onHookError, result.error, ctx);\n\n\t\t\t// Hook: dispatch:end\n\t\t\tawait this.hookRegistry.emit(\"dispatch:end\", this.onHookError, ctx, result);\n\n\t\t\treturn result;\n\t\t}\n\t}\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ZodType, z } from 'zod';
|
|
2
2
|
|
|
3
3
|
interface WorkflowConfig {
|
|
4
|
+
modelVersion?: number;
|
|
4
5
|
states: Record<string, ZodType>;
|
|
5
6
|
commands: Record<string, ZodType>;
|
|
6
7
|
events: Record<string, ZodType>;
|
|
@@ -29,7 +30,7 @@ type Workflow<TConfig extends WorkflowConfig = WorkflowConfig> = {
|
|
|
29
30
|
}[StateNames<TConfig>];
|
|
30
31
|
type PipelineError<TConfig extends WorkflowConfig = WorkflowConfig> = {
|
|
31
32
|
category: "validation";
|
|
32
|
-
source: "command" | "state" | "event" | "transition";
|
|
33
|
+
source: "command" | "state" | "event" | "transition" | "restore";
|
|
33
34
|
issues: z.core.$ZodIssue[];
|
|
34
35
|
message: string;
|
|
35
36
|
} | {
|
|
@@ -54,9 +55,9 @@ type DispatchResult<TConfig extends WorkflowConfig = WorkflowConfig> = {
|
|
|
54
55
|
};
|
|
55
56
|
/** Thrown internally when Zod validation fails during dispatch. */
|
|
56
57
|
declare class ValidationError extends Error {
|
|
57
|
-
readonly source: "command" | "state" | "event" | "transition";
|
|
58
|
+
readonly source: "command" | "state" | "event" | "transition" | "restore";
|
|
58
59
|
readonly issues: z.core.$ZodIssue[];
|
|
59
|
-
constructor(source: "command" | "state" | "event" | "transition", issues: z.core.$ZodIssue[]);
|
|
60
|
+
constructor(source: "command" | "state" | "event" | "transition" | "restore", issues: z.core.$ZodIssue[]);
|
|
60
61
|
}
|
|
61
62
|
/** Thrown internally when a handler calls ctx.error(). Caught by the router. */
|
|
62
63
|
declare class DomainErrorSignal extends Error {
|
|
@@ -65,6 +66,17 @@ declare class DomainErrorSignal extends Error {
|
|
|
65
66
|
constructor(code: string, data: unknown);
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
/** A plain, JSON-safe representation of a workflow's state. */
|
|
70
|
+
interface WorkflowSnapshot<TConfig extends WorkflowConfig = WorkflowConfig> {
|
|
71
|
+
readonly id: string;
|
|
72
|
+
readonly definitionName: string;
|
|
73
|
+
readonly state: StateNames<TConfig>;
|
|
74
|
+
readonly data: unknown;
|
|
75
|
+
readonly createdAt: string;
|
|
76
|
+
readonly updatedAt: string;
|
|
77
|
+
readonly modelVersion: number;
|
|
78
|
+
}
|
|
79
|
+
|
|
68
80
|
/** The result of defineWorkflow() — holds schemas and creates workflow instances. */
|
|
69
81
|
interface WorkflowDefinition<TConfig extends WorkflowConfig = WorkflowConfig> {
|
|
70
82
|
readonly config: TConfig;
|
|
@@ -78,6 +90,14 @@ interface WorkflowDefinition<TConfig extends WorkflowConfig = WorkflowConfig> {
|
|
|
78
90
|
getEventSchema(eventName: string): ZodType;
|
|
79
91
|
getErrorSchema(errorCode: string): ZodType;
|
|
80
92
|
hasState(stateName: string): boolean;
|
|
93
|
+
snapshot(workflow: Workflow<TConfig>): WorkflowSnapshot<TConfig>;
|
|
94
|
+
restore(snapshot: WorkflowSnapshot<TConfig>): {
|
|
95
|
+
ok: true;
|
|
96
|
+
workflow: Workflow<TConfig>;
|
|
97
|
+
} | {
|
|
98
|
+
ok: false;
|
|
99
|
+
error: ValidationError;
|
|
100
|
+
};
|
|
81
101
|
}
|
|
82
102
|
/**
|
|
83
103
|
* Creates a workflow definition from a name and Zod schema configuration.
|
|
@@ -125,6 +145,9 @@ interface Context<TConfig extends WorkflowConfig, TDeps, TState extends StateNam
|
|
|
125
145
|
/** Terminal handler function — receives fully typed context with state and command narrowing. */
|
|
126
146
|
type Handler<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TConfig>, TCommand extends CommandNames<TConfig>> = (ctx: Context<TConfig, TDeps, TState, TCommand>) => void | Promise<void>;
|
|
127
147
|
|
|
148
|
+
/** The lifecycle hook event names. */
|
|
149
|
+
type HookEvent = "dispatch:start" | "dispatch:end" | "transition" | "error" | "event";
|
|
150
|
+
|
|
128
151
|
/**
|
|
129
152
|
* Koa-style middleware function with full context narrowing via defaults.
|
|
130
153
|
*
|
|
@@ -134,11 +157,20 @@ type Handler<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TC
|
|
|
134
157
|
*/
|
|
135
158
|
type Middleware<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TConfig> = StateNames<TConfig>, TCommand extends CommandNames<TConfig> = CommandNames<TConfig>> = (ctx: Context<TConfig, TDeps, TState, TCommand>, next: () => Promise<void>) => Promise<void>;
|
|
136
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Read-only subset of Context for hook callbacks.
|
|
162
|
+
* Includes context-key access (set/get) but excludes dispatch mutation methods.
|
|
163
|
+
*/
|
|
164
|
+
type ReadonlyContext<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TConfig> = StateNames<TConfig>, TCommand extends CommandNames<TConfig> = CommandNames<TConfig>> = Omit<Context<TConfig, TDeps, TState, TCommand>, "update" | "transition" | "emit" | "error" | "getWorkflowSnapshot">;
|
|
165
|
+
|
|
137
166
|
type AnyMiddleware = (ctx: any, next: () => Promise<void>) => Promise<void>;
|
|
138
167
|
type HandlerEntry = {
|
|
139
168
|
inlineMiddleware: AnyMiddleware[];
|
|
140
169
|
handler: AnyMiddleware;
|
|
141
170
|
};
|
|
171
|
+
interface RouterOptions {
|
|
172
|
+
onHookError?: (error: unknown) => void;
|
|
173
|
+
}
|
|
142
174
|
declare class StateBuilder<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TConfig>> {
|
|
143
175
|
/** @internal */ readonly middleware: AnyMiddleware[];
|
|
144
176
|
/** @internal */ readonly handlers: Map<string, HandlerEntry>;
|
|
@@ -158,15 +190,26 @@ declare class WorkflowRouter<TConfig extends WorkflowConfig, TDeps = {}> {
|
|
|
158
190
|
private singleStateBuilders;
|
|
159
191
|
private multiStateBuilders;
|
|
160
192
|
private wildcardHandlers;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
193
|
+
private hookRegistry;
|
|
194
|
+
private readonly onHookError;
|
|
195
|
+
constructor(definition: WorkflowDefinition<TConfig>, deps?: TDeps, options?: RouterOptions);
|
|
196
|
+
/** Adds global middleware, merges another router, or applies a plugin. */
|
|
197
|
+
use(arg: ((ctx: Context<TConfig, TDeps>, next: () => Promise<void>) => Promise<void>) | WorkflowRouter<TConfig, TDeps> | Plugin<TConfig, TDeps>): this;
|
|
164
198
|
private merge;
|
|
165
199
|
private mergeStateBuilders;
|
|
166
200
|
/** Registers handlers for one or more states. */
|
|
167
201
|
state<P extends StateNames<TConfig> | readonly StateNames<TConfig>[]>(name: P, setup: (state: StateBuilder<TConfig, TDeps, P extends readonly (infer S)[] ? S & StateNames<TConfig> : P & StateNames<TConfig>>) => void): this;
|
|
202
|
+
/** Registers a lifecycle hook callback. */
|
|
203
|
+
on(event: "dispatch:start", callback: (ctx: ReadonlyContext<TConfig, TDeps>) => void | Promise<void>): this;
|
|
204
|
+
on(event: "dispatch:end", callback: (ctx: ReadonlyContext<TConfig, TDeps>, result: DispatchResult<TConfig>) => void | Promise<void>): this;
|
|
205
|
+
on(event: "transition", callback: (from: StateNames<TConfig>, to: StateNames<TConfig>, workflow: Workflow<TConfig>) => void | Promise<void>): this;
|
|
206
|
+
on(event: "error", callback: (error: PipelineError<TConfig>, ctx: ReadonlyContext<TConfig, TDeps>) => void | Promise<void>): this;
|
|
207
|
+
on(event: "event", callback: (event: {
|
|
208
|
+
type: EventNames<TConfig>;
|
|
209
|
+
data: unknown;
|
|
210
|
+
}, workflow: Workflow<TConfig>) => void | Promise<void>): this;
|
|
168
211
|
/** Registers a wildcard handler that matches any state. */
|
|
169
|
-
on<C extends CommandNames<TConfig>>(
|
|
212
|
+
on<C extends CommandNames<TConfig>>(state: "*", command: C, ...fns: [
|
|
170
213
|
...AnyMiddleware[],
|
|
171
214
|
(ctx: Context<TConfig, TDeps, StateNames<TConfig>, C>) => void | Promise<void>
|
|
172
215
|
]): this;
|
|
@@ -177,4 +220,14 @@ declare class WorkflowRouter<TConfig extends WorkflowConfig, TDeps = {}> {
|
|
|
177
220
|
}): Promise<DispatchResult<TConfig>>;
|
|
178
221
|
}
|
|
179
222
|
|
|
180
|
-
|
|
223
|
+
declare const PLUGIN_SYMBOL: unique symbol;
|
|
224
|
+
/** A branded plugin function that can be passed to router.use(). */
|
|
225
|
+
type Plugin<TConfig extends WorkflowConfig, TDeps> = ((router: WorkflowRouter<TConfig, TDeps>) => void) & {
|
|
226
|
+
readonly [PLUGIN_SYMBOL]: true;
|
|
227
|
+
};
|
|
228
|
+
/** Brands a function as a Ryte plugin for use with router.use(). */
|
|
229
|
+
declare function definePlugin<TConfig extends WorkflowConfig, TDeps>(fn: (router: WorkflowRouter<TConfig, TDeps>) => void): Plugin<TConfig, TDeps>;
|
|
230
|
+
/** Checks whether a value is a branded Ryte plugin. */
|
|
231
|
+
declare function isPlugin(value: unknown): value is Plugin<WorkflowConfig, unknown>;
|
|
232
|
+
|
|
233
|
+
export { type CommandNames, type CommandPayload, type Context, type ContextKey, type DispatchResult, DomainErrorSignal, type ErrorCodes, type ErrorData, type EventData, type EventNames, type Handler, type HookEvent, type Middleware, type PipelineError, type Plugin, type ReadonlyContext, type RouterOptions, type StateData, type StateNames, ValidationError, type Workflow, type WorkflowConfig, type WorkflowDefinition, type WorkflowOf, WorkflowRouter, type WorkflowSnapshot, createKey, definePlugin, defineWorkflow, isPlugin };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ZodType, z } from 'zod';
|
|
2
2
|
|
|
3
3
|
interface WorkflowConfig {
|
|
4
|
+
modelVersion?: number;
|
|
4
5
|
states: Record<string, ZodType>;
|
|
5
6
|
commands: Record<string, ZodType>;
|
|
6
7
|
events: Record<string, ZodType>;
|
|
@@ -29,7 +30,7 @@ type Workflow<TConfig extends WorkflowConfig = WorkflowConfig> = {
|
|
|
29
30
|
}[StateNames<TConfig>];
|
|
30
31
|
type PipelineError<TConfig extends WorkflowConfig = WorkflowConfig> = {
|
|
31
32
|
category: "validation";
|
|
32
|
-
source: "command" | "state" | "event" | "transition";
|
|
33
|
+
source: "command" | "state" | "event" | "transition" | "restore";
|
|
33
34
|
issues: z.core.$ZodIssue[];
|
|
34
35
|
message: string;
|
|
35
36
|
} | {
|
|
@@ -54,9 +55,9 @@ type DispatchResult<TConfig extends WorkflowConfig = WorkflowConfig> = {
|
|
|
54
55
|
};
|
|
55
56
|
/** Thrown internally when Zod validation fails during dispatch. */
|
|
56
57
|
declare class ValidationError extends Error {
|
|
57
|
-
readonly source: "command" | "state" | "event" | "transition";
|
|
58
|
+
readonly source: "command" | "state" | "event" | "transition" | "restore";
|
|
58
59
|
readonly issues: z.core.$ZodIssue[];
|
|
59
|
-
constructor(source: "command" | "state" | "event" | "transition", issues: z.core.$ZodIssue[]);
|
|
60
|
+
constructor(source: "command" | "state" | "event" | "transition" | "restore", issues: z.core.$ZodIssue[]);
|
|
60
61
|
}
|
|
61
62
|
/** Thrown internally when a handler calls ctx.error(). Caught by the router. */
|
|
62
63
|
declare class DomainErrorSignal extends Error {
|
|
@@ -65,6 +66,17 @@ declare class DomainErrorSignal extends Error {
|
|
|
65
66
|
constructor(code: string, data: unknown);
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
/** A plain, JSON-safe representation of a workflow's state. */
|
|
70
|
+
interface WorkflowSnapshot<TConfig extends WorkflowConfig = WorkflowConfig> {
|
|
71
|
+
readonly id: string;
|
|
72
|
+
readonly definitionName: string;
|
|
73
|
+
readonly state: StateNames<TConfig>;
|
|
74
|
+
readonly data: unknown;
|
|
75
|
+
readonly createdAt: string;
|
|
76
|
+
readonly updatedAt: string;
|
|
77
|
+
readonly modelVersion: number;
|
|
78
|
+
}
|
|
79
|
+
|
|
68
80
|
/** The result of defineWorkflow() — holds schemas and creates workflow instances. */
|
|
69
81
|
interface WorkflowDefinition<TConfig extends WorkflowConfig = WorkflowConfig> {
|
|
70
82
|
readonly config: TConfig;
|
|
@@ -78,6 +90,14 @@ interface WorkflowDefinition<TConfig extends WorkflowConfig = WorkflowConfig> {
|
|
|
78
90
|
getEventSchema(eventName: string): ZodType;
|
|
79
91
|
getErrorSchema(errorCode: string): ZodType;
|
|
80
92
|
hasState(stateName: string): boolean;
|
|
93
|
+
snapshot(workflow: Workflow<TConfig>): WorkflowSnapshot<TConfig>;
|
|
94
|
+
restore(snapshot: WorkflowSnapshot<TConfig>): {
|
|
95
|
+
ok: true;
|
|
96
|
+
workflow: Workflow<TConfig>;
|
|
97
|
+
} | {
|
|
98
|
+
ok: false;
|
|
99
|
+
error: ValidationError;
|
|
100
|
+
};
|
|
81
101
|
}
|
|
82
102
|
/**
|
|
83
103
|
* Creates a workflow definition from a name and Zod schema configuration.
|
|
@@ -125,6 +145,9 @@ interface Context<TConfig extends WorkflowConfig, TDeps, TState extends StateNam
|
|
|
125
145
|
/** Terminal handler function — receives fully typed context with state and command narrowing. */
|
|
126
146
|
type Handler<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TConfig>, TCommand extends CommandNames<TConfig>> = (ctx: Context<TConfig, TDeps, TState, TCommand>) => void | Promise<void>;
|
|
127
147
|
|
|
148
|
+
/** The lifecycle hook event names. */
|
|
149
|
+
type HookEvent = "dispatch:start" | "dispatch:end" | "transition" | "error" | "event";
|
|
150
|
+
|
|
128
151
|
/**
|
|
129
152
|
* Koa-style middleware function with full context narrowing via defaults.
|
|
130
153
|
*
|
|
@@ -134,11 +157,20 @@ type Handler<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TC
|
|
|
134
157
|
*/
|
|
135
158
|
type Middleware<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TConfig> = StateNames<TConfig>, TCommand extends CommandNames<TConfig> = CommandNames<TConfig>> = (ctx: Context<TConfig, TDeps, TState, TCommand>, next: () => Promise<void>) => Promise<void>;
|
|
136
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Read-only subset of Context for hook callbacks.
|
|
162
|
+
* Includes context-key access (set/get) but excludes dispatch mutation methods.
|
|
163
|
+
*/
|
|
164
|
+
type ReadonlyContext<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TConfig> = StateNames<TConfig>, TCommand extends CommandNames<TConfig> = CommandNames<TConfig>> = Omit<Context<TConfig, TDeps, TState, TCommand>, "update" | "transition" | "emit" | "error" | "getWorkflowSnapshot">;
|
|
165
|
+
|
|
137
166
|
type AnyMiddleware = (ctx: any, next: () => Promise<void>) => Promise<void>;
|
|
138
167
|
type HandlerEntry = {
|
|
139
168
|
inlineMiddleware: AnyMiddleware[];
|
|
140
169
|
handler: AnyMiddleware;
|
|
141
170
|
};
|
|
171
|
+
interface RouterOptions {
|
|
172
|
+
onHookError?: (error: unknown) => void;
|
|
173
|
+
}
|
|
142
174
|
declare class StateBuilder<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TConfig>> {
|
|
143
175
|
/** @internal */ readonly middleware: AnyMiddleware[];
|
|
144
176
|
/** @internal */ readonly handlers: Map<string, HandlerEntry>;
|
|
@@ -158,15 +190,26 @@ declare class WorkflowRouter<TConfig extends WorkflowConfig, TDeps = {}> {
|
|
|
158
190
|
private singleStateBuilders;
|
|
159
191
|
private multiStateBuilders;
|
|
160
192
|
private wildcardHandlers;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
193
|
+
private hookRegistry;
|
|
194
|
+
private readonly onHookError;
|
|
195
|
+
constructor(definition: WorkflowDefinition<TConfig>, deps?: TDeps, options?: RouterOptions);
|
|
196
|
+
/** Adds global middleware, merges another router, or applies a plugin. */
|
|
197
|
+
use(arg: ((ctx: Context<TConfig, TDeps>, next: () => Promise<void>) => Promise<void>) | WorkflowRouter<TConfig, TDeps> | Plugin<TConfig, TDeps>): this;
|
|
164
198
|
private merge;
|
|
165
199
|
private mergeStateBuilders;
|
|
166
200
|
/** Registers handlers for one or more states. */
|
|
167
201
|
state<P extends StateNames<TConfig> | readonly StateNames<TConfig>[]>(name: P, setup: (state: StateBuilder<TConfig, TDeps, P extends readonly (infer S)[] ? S & StateNames<TConfig> : P & StateNames<TConfig>>) => void): this;
|
|
202
|
+
/** Registers a lifecycle hook callback. */
|
|
203
|
+
on(event: "dispatch:start", callback: (ctx: ReadonlyContext<TConfig, TDeps>) => void | Promise<void>): this;
|
|
204
|
+
on(event: "dispatch:end", callback: (ctx: ReadonlyContext<TConfig, TDeps>, result: DispatchResult<TConfig>) => void | Promise<void>): this;
|
|
205
|
+
on(event: "transition", callback: (from: StateNames<TConfig>, to: StateNames<TConfig>, workflow: Workflow<TConfig>) => void | Promise<void>): this;
|
|
206
|
+
on(event: "error", callback: (error: PipelineError<TConfig>, ctx: ReadonlyContext<TConfig, TDeps>) => void | Promise<void>): this;
|
|
207
|
+
on(event: "event", callback: (event: {
|
|
208
|
+
type: EventNames<TConfig>;
|
|
209
|
+
data: unknown;
|
|
210
|
+
}, workflow: Workflow<TConfig>) => void | Promise<void>): this;
|
|
168
211
|
/** Registers a wildcard handler that matches any state. */
|
|
169
|
-
on<C extends CommandNames<TConfig>>(
|
|
212
|
+
on<C extends CommandNames<TConfig>>(state: "*", command: C, ...fns: [
|
|
170
213
|
...AnyMiddleware[],
|
|
171
214
|
(ctx: Context<TConfig, TDeps, StateNames<TConfig>, C>) => void | Promise<void>
|
|
172
215
|
]): this;
|
|
@@ -177,4 +220,14 @@ declare class WorkflowRouter<TConfig extends WorkflowConfig, TDeps = {}> {
|
|
|
177
220
|
}): Promise<DispatchResult<TConfig>>;
|
|
178
221
|
}
|
|
179
222
|
|
|
180
|
-
|
|
223
|
+
declare const PLUGIN_SYMBOL: unique symbol;
|
|
224
|
+
/** A branded plugin function that can be passed to router.use(). */
|
|
225
|
+
type Plugin<TConfig extends WorkflowConfig, TDeps> = ((router: WorkflowRouter<TConfig, TDeps>) => void) & {
|
|
226
|
+
readonly [PLUGIN_SYMBOL]: true;
|
|
227
|
+
};
|
|
228
|
+
/** Brands a function as a Ryte plugin for use with router.use(). */
|
|
229
|
+
declare function definePlugin<TConfig extends WorkflowConfig, TDeps>(fn: (router: WorkflowRouter<TConfig, TDeps>) => void): Plugin<TConfig, TDeps>;
|
|
230
|
+
/** Checks whether a value is a branded Ryte plugin. */
|
|
231
|
+
declare function isPlugin(value: unknown): value is Plugin<WorkflowConfig, unknown>;
|
|
232
|
+
|
|
233
|
+
export { type CommandNames, type CommandPayload, type Context, type ContextKey, type DispatchResult, DomainErrorSignal, type ErrorCodes, type ErrorData, type EventData, type EventNames, type Handler, type HookEvent, type Middleware, type PipelineError, type Plugin, type ReadonlyContext, type RouterOptions, type StateData, type StateNames, ValidationError, type Workflow, type WorkflowConfig, type WorkflowDefinition, type WorkflowOf, WorkflowRouter, type WorkflowSnapshot, createKey, definePlugin, defineWorkflow, isPlugin };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
var ValidationError = class extends Error {
|
|
3
|
+
constructor(source, issues) {
|
|
4
|
+
super(`Validation failed (${source}): ${issues.map((i) => i.message).join(", ")}`);
|
|
5
|
+
this.source = source;
|
|
6
|
+
this.issues = issues;
|
|
7
|
+
this.name = "ValidationError";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var DomainErrorSignal = class extends Error {
|
|
11
|
+
constructor(code, data) {
|
|
12
|
+
super(`Domain error: ${code}`);
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.data = data;
|
|
15
|
+
this.name = "DomainErrorSignal";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
1
19
|
// src/definition.ts
|
|
2
20
|
function defineWorkflow(name, config) {
|
|
3
21
|
return {
|
|
@@ -44,6 +62,51 @@ function defineWorkflow(name, config) {
|
|
|
44
62
|
},
|
|
45
63
|
hasState(stateName) {
|
|
46
64
|
return stateName in config.states;
|
|
65
|
+
},
|
|
66
|
+
snapshot(workflow) {
|
|
67
|
+
return {
|
|
68
|
+
id: workflow.id,
|
|
69
|
+
definitionName: name,
|
|
70
|
+
state: workflow.state,
|
|
71
|
+
data: workflow.data,
|
|
72
|
+
createdAt: workflow.createdAt.toISOString(),
|
|
73
|
+
updatedAt: workflow.updatedAt.toISOString(),
|
|
74
|
+
modelVersion: config.modelVersion ?? 1
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
restore(snap) {
|
|
78
|
+
const stateSchema = config.states[snap.state];
|
|
79
|
+
if (!stateSchema) {
|
|
80
|
+
return {
|
|
81
|
+
ok: false,
|
|
82
|
+
error: new ValidationError("restore", [
|
|
83
|
+
{
|
|
84
|
+
code: "custom",
|
|
85
|
+
message: `Unknown state: ${snap.state}`,
|
|
86
|
+
input: snap.state,
|
|
87
|
+
path: ["state"]
|
|
88
|
+
}
|
|
89
|
+
])
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const result = stateSchema.safeParse(snap.data);
|
|
93
|
+
if (!result.success) {
|
|
94
|
+
return {
|
|
95
|
+
ok: false,
|
|
96
|
+
error: new ValidationError("restore", result.error.issues)
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
ok: true,
|
|
101
|
+
workflow: {
|
|
102
|
+
id: snap.id,
|
|
103
|
+
definitionName: snap.definitionName,
|
|
104
|
+
state: snap.state,
|
|
105
|
+
data: result.data,
|
|
106
|
+
createdAt: new Date(snap.createdAt),
|
|
107
|
+
updatedAt: new Date(snap.updatedAt)
|
|
108
|
+
}
|
|
109
|
+
};
|
|
47
110
|
}
|
|
48
111
|
};
|
|
49
112
|
}
|
|
@@ -53,6 +116,17 @@ function createKey(name) {
|
|
|
53
116
|
return { id: Symbol(name) };
|
|
54
117
|
}
|
|
55
118
|
|
|
119
|
+
// src/plugin.ts
|
|
120
|
+
var PLUGIN_SYMBOL = /* @__PURE__ */ Symbol.for("ryte:plugin");
|
|
121
|
+
function definePlugin(fn) {
|
|
122
|
+
const plugin = fn;
|
|
123
|
+
Object.defineProperty(plugin, PLUGIN_SYMBOL, { value: true, writable: false });
|
|
124
|
+
return plugin;
|
|
125
|
+
}
|
|
126
|
+
function isPlugin(value) {
|
|
127
|
+
return typeof value === "function" && PLUGIN_SYMBOL in value;
|
|
128
|
+
}
|
|
129
|
+
|
|
56
130
|
// src/compose.ts
|
|
57
131
|
function compose(middleware) {
|
|
58
132
|
return async (ctx) => {
|
|
@@ -68,24 +142,6 @@ function compose(middleware) {
|
|
|
68
142
|
};
|
|
69
143
|
}
|
|
70
144
|
|
|
71
|
-
// src/types.ts
|
|
72
|
-
var ValidationError = class extends Error {
|
|
73
|
-
constructor(source, issues) {
|
|
74
|
-
super(`Validation failed (${source}): ${issues.map((i) => i.message).join(", ")}`);
|
|
75
|
-
this.source = source;
|
|
76
|
-
this.issues = issues;
|
|
77
|
-
this.name = "ValidationError";
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
var DomainErrorSignal = class extends Error {
|
|
81
|
-
constructor(code, data) {
|
|
82
|
-
super(`Domain error: ${code}`);
|
|
83
|
-
this.code = code;
|
|
84
|
-
this.data = data;
|
|
85
|
-
this.name = "DomainErrorSignal";
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
|
|
89
145
|
// src/context.ts
|
|
90
146
|
function createContext(definition, originalWorkflow, command, deps) {
|
|
91
147
|
let mutableState = originalWorkflow.state;
|
|
@@ -169,6 +225,46 @@ function createContext(definition, originalWorkflow, command, deps) {
|
|
|
169
225
|
return ctx;
|
|
170
226
|
}
|
|
171
227
|
|
|
228
|
+
// src/hooks.ts
|
|
229
|
+
var HOOK_EVENTS = /* @__PURE__ */ new Set([
|
|
230
|
+
"dispatch:start",
|
|
231
|
+
"dispatch:end",
|
|
232
|
+
"transition",
|
|
233
|
+
"error",
|
|
234
|
+
"event"
|
|
235
|
+
]);
|
|
236
|
+
var HookRegistry = class {
|
|
237
|
+
// biome-ignore lint/complexity/noBannedTypes: callbacks have varying signatures per hook event
|
|
238
|
+
hooks = /* @__PURE__ */ new Map();
|
|
239
|
+
/** Register a callback for a hook event. */
|
|
240
|
+
// biome-ignore lint/complexity/noBannedTypes: callbacks have varying signatures per hook event
|
|
241
|
+
add(event, callback) {
|
|
242
|
+
const existing = this.hooks.get(event) ?? [];
|
|
243
|
+
existing.push(callback);
|
|
244
|
+
this.hooks.set(event, existing);
|
|
245
|
+
}
|
|
246
|
+
/** Emit a hook event, calling all registered callbacks. Errors are caught and forwarded. */
|
|
247
|
+
async emit(event, onError, ...args) {
|
|
248
|
+
const callbacks = this.hooks.get(event);
|
|
249
|
+
if (!callbacks) return;
|
|
250
|
+
for (const cb of callbacks) {
|
|
251
|
+
try {
|
|
252
|
+
await cb(...args);
|
|
253
|
+
} catch (err) {
|
|
254
|
+
onError(err);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/** Merge another registry's hooks into this one (used by composable routers). */
|
|
259
|
+
merge(other) {
|
|
260
|
+
for (const [event, callbacks] of other.hooks) {
|
|
261
|
+
const existing = this.hooks.get(event) ?? [];
|
|
262
|
+
existing.push(...callbacks);
|
|
263
|
+
this.hooks.set(event, existing);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
172
268
|
// src/router.ts
|
|
173
269
|
var StateBuilder = class {
|
|
174
270
|
/** @internal */
|
|
@@ -191,9 +287,10 @@ var StateBuilder = class {
|
|
|
191
287
|
}
|
|
192
288
|
};
|
|
193
289
|
var WorkflowRouter = class _WorkflowRouter {
|
|
194
|
-
constructor(definition, deps = {}) {
|
|
290
|
+
constructor(definition, deps = {}, options = {}) {
|
|
195
291
|
this.definition = definition;
|
|
196
292
|
this.deps = deps;
|
|
293
|
+
this.onHookError = options.onHookError ?? console.error;
|
|
197
294
|
}
|
|
198
295
|
globalMiddleware = [];
|
|
199
296
|
// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types
|
|
@@ -201,12 +298,16 @@ var WorkflowRouter = class _WorkflowRouter {
|
|
|
201
298
|
// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types
|
|
202
299
|
multiStateBuilders = /* @__PURE__ */ new Map();
|
|
203
300
|
wildcardHandlers = /* @__PURE__ */ new Map();
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
301
|
+
hookRegistry = new HookRegistry();
|
|
302
|
+
onHookError;
|
|
303
|
+
/** Adds global middleware, merges another router, or applies a plugin. */
|
|
304
|
+
use(arg) {
|
|
305
|
+
if (arg instanceof _WorkflowRouter) {
|
|
306
|
+
this.merge(arg);
|
|
307
|
+
} else if (isPlugin(arg)) {
|
|
308
|
+
arg(this);
|
|
208
309
|
} else {
|
|
209
|
-
this.globalMiddleware.push(
|
|
310
|
+
this.globalMiddleware.push(arg);
|
|
210
311
|
}
|
|
211
312
|
return this;
|
|
212
313
|
}
|
|
@@ -227,6 +328,7 @@ var WorkflowRouter = class _WorkflowRouter {
|
|
|
227
328
|
});
|
|
228
329
|
}
|
|
229
330
|
}
|
|
331
|
+
this.hookRegistry.merge(child.hookRegistry);
|
|
230
332
|
}
|
|
231
333
|
mergeStateBuilders(target, source) {
|
|
232
334
|
for (const [stateName, childBuilder] of source) {
|
|
@@ -261,19 +363,29 @@ var WorkflowRouter = class _WorkflowRouter {
|
|
|
261
363
|
}
|
|
262
364
|
return this;
|
|
263
365
|
}
|
|
264
|
-
|
|
265
|
-
on(
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
handler
|
|
275
|
-
|
|
276
|
-
|
|
366
|
+
// biome-ignore lint/suspicious/noExplicitAny: implementation signature must be loose to handle all overloads
|
|
367
|
+
on(...args) {
|
|
368
|
+
const first = args[0];
|
|
369
|
+
if (HOOK_EVENTS.has(first)) {
|
|
370
|
+
this.hookRegistry.add(first, args[1]);
|
|
371
|
+
return this;
|
|
372
|
+
}
|
|
373
|
+
if (first === "*") {
|
|
374
|
+
const command = args[1];
|
|
375
|
+
const fns = args.slice(2);
|
|
376
|
+
if (fns.length === 0) throw new Error("on() requires at least a handler");
|
|
377
|
+
const handler = fns.pop();
|
|
378
|
+
const inlineMiddleware = fns;
|
|
379
|
+
const wrappedHandler = async (ctx, _next) => {
|
|
380
|
+
await handler(ctx);
|
|
381
|
+
};
|
|
382
|
+
this.wildcardHandlers.set(command, {
|
|
383
|
+
inlineMiddleware,
|
|
384
|
+
handler: wrappedHandler
|
|
385
|
+
});
|
|
386
|
+
return this;
|
|
387
|
+
}
|
|
388
|
+
throw new Error(`Unknown event or state: ${first}`);
|
|
277
389
|
}
|
|
278
390
|
/** Dispatches a command to the appropriate handler and returns the result. */
|
|
279
391
|
async dispatch(workflow, command) {
|
|
@@ -347,17 +459,35 @@ var WorkflowRouter = class _WorkflowRouter {
|
|
|
347
459
|
validatedCommand,
|
|
348
460
|
this.deps
|
|
349
461
|
);
|
|
462
|
+
await this.hookRegistry.emit("dispatch:start", this.onHookError, ctx);
|
|
350
463
|
try {
|
|
351
464
|
const composed = compose(chain);
|
|
352
465
|
await composed(ctx);
|
|
353
|
-
|
|
466
|
+
const result = {
|
|
354
467
|
ok: true,
|
|
355
468
|
workflow: ctx.getWorkflowSnapshot(),
|
|
356
469
|
events: [...ctx.events]
|
|
357
470
|
};
|
|
471
|
+
if (result.ok && result.workflow.state !== workflow.state) {
|
|
472
|
+
await this.hookRegistry.emit(
|
|
473
|
+
"transition",
|
|
474
|
+
this.onHookError,
|
|
475
|
+
workflow.state,
|
|
476
|
+
result.workflow.state,
|
|
477
|
+
result.workflow
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
if (result.ok) {
|
|
481
|
+
for (const event of result.events) {
|
|
482
|
+
await this.hookRegistry.emit("event", this.onHookError, event, result.workflow);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
await this.hookRegistry.emit("dispatch:end", this.onHookError, ctx, result);
|
|
486
|
+
return result;
|
|
358
487
|
} catch (err) {
|
|
488
|
+
let result;
|
|
359
489
|
if (err instanceof DomainErrorSignal) {
|
|
360
|
-
|
|
490
|
+
result = {
|
|
361
491
|
ok: false,
|
|
362
492
|
error: {
|
|
363
493
|
category: "domain",
|
|
@@ -365,9 +495,8 @@ var WorkflowRouter = class _WorkflowRouter {
|
|
|
365
495
|
data: err.data
|
|
366
496
|
}
|
|
367
497
|
};
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
return {
|
|
498
|
+
} else if (err instanceof ValidationError) {
|
|
499
|
+
result = {
|
|
371
500
|
ok: false,
|
|
372
501
|
error: {
|
|
373
502
|
category: "validation",
|
|
@@ -376,8 +505,12 @@ var WorkflowRouter = class _WorkflowRouter {
|
|
|
376
505
|
message: err.message
|
|
377
506
|
}
|
|
378
507
|
};
|
|
508
|
+
} else {
|
|
509
|
+
throw err;
|
|
379
510
|
}
|
|
380
|
-
|
|
511
|
+
await this.hookRegistry.emit("error", this.onHookError, result.error, ctx);
|
|
512
|
+
await this.hookRegistry.emit("dispatch:end", this.onHookError, ctx, result);
|
|
513
|
+
return result;
|
|
381
514
|
}
|
|
382
515
|
}
|
|
383
516
|
};
|
|
@@ -386,6 +519,8 @@ export {
|
|
|
386
519
|
ValidationError,
|
|
387
520
|
WorkflowRouter,
|
|
388
521
|
createKey,
|
|
389
|
-
|
|
522
|
+
definePlugin,
|
|
523
|
+
defineWorkflow,
|
|
524
|
+
isPlugin
|
|
390
525
|
};
|
|
391
526
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/definition.ts","../src/key.ts","../src/compose.ts","../src/types.ts","../src/context.ts","../src/router.ts"],"sourcesContent":["import type { ZodType, z } from \"zod\";\nimport type { StateNames, WorkflowConfig, WorkflowOf } from \"./types.js\";\n\n/** The result of defineWorkflow() — holds schemas and creates workflow instances. */\nexport interface WorkflowDefinition<TConfig extends WorkflowConfig = WorkflowConfig> {\n\treadonly config: TConfig;\n\treadonly name: string;\n\tcreateWorkflow<S extends StateNames<TConfig>>(\n\t\tid: string,\n\t\tconfig: { initialState: S; data: z.infer<TConfig[\"states\"][S]> },\n\t): WorkflowOf<TConfig, S>;\n\tgetStateSchema(stateName: string): ZodType;\n\tgetCommandSchema(commandName: string): ZodType;\n\tgetEventSchema(eventName: string): ZodType;\n\tgetErrorSchema(errorCode: string): ZodType;\n\thasState(stateName: string): boolean;\n}\n\n/**\n * Creates a workflow definition from a name and Zod schema configuration.\n */\nexport function defineWorkflow<const TConfig extends WorkflowConfig>(\n\tname: string,\n\tconfig: TConfig,\n): WorkflowDefinition<TConfig> {\n\treturn {\n\t\tconfig,\n\t\tname,\n\n\t\tcreateWorkflow(id, wfConfig) {\n\t\t\tconst schema = config.states[wfConfig.initialState as string];\n\t\t\tif (!schema) throw new Error(`Unknown state: ${wfConfig.initialState as string}`);\n\t\t\tconst result = schema.safeParse(wfConfig.data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid initial data for state '${wfConfig.initialState as string}': ${result.error.issues.map((i) => i.message).join(\", \")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst now = new Date();\n\t\t\treturn {\n\t\t\t\tid,\n\t\t\t\tdefinitionName: name,\n\t\t\t\tstate: wfConfig.initialState,\n\t\t\t\tdata: result.data,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t} as WorkflowOf<TConfig, typeof wfConfig.initialState>;\n\t\t},\n\n\t\tgetStateSchema(stateName: string): ZodType {\n\t\t\tconst schema = config.states[stateName];\n\t\t\tif (!schema) throw new Error(`Unknown state: ${stateName}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\tgetCommandSchema(commandName: string): ZodType {\n\t\t\tconst schema = config.commands[commandName];\n\t\t\tif (!schema) throw new Error(`Unknown command: ${commandName}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\tgetEventSchema(eventName: string): ZodType {\n\t\t\tconst schema = config.events[eventName];\n\t\t\tif (!schema) throw new Error(`Unknown event: ${eventName}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\tgetErrorSchema(errorCode: string): ZodType {\n\t\t\tconst schema = config.errors[errorCode];\n\t\t\tif (!schema) throw new Error(`Unknown error: ${errorCode}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\thasState(stateName: string): boolean {\n\t\t\treturn stateName in config.states;\n\t\t},\n\t};\n}\n","/** A phantom-typed key for type-safe middleware state storage. */\nexport interface ContextKey<T> {\n\treadonly _phantom: T;\n\treadonly id: symbol;\n}\n\n/** Creates a unique typed key for storing/retrieving values in context. */\nexport function createKey<T>(name: string): ContextKey<T> {\n\treturn { id: Symbol(name) } as ContextKey<T>;\n}\n","type Middleware<TCtx> = (ctx: TCtx, next: () => Promise<void>) => Promise<void>;\n\n/** Composes an array of middleware into a single function (Koa-style onion model). */\nexport function compose<TCtx>(middleware: Middleware<TCtx>[]): (ctx: TCtx) => Promise<void> {\n\treturn async (ctx: TCtx) => {\n\t\tlet index = -1;\n\t\tasync function dispatch(i: number): Promise<void> {\n\t\t\tif (i <= index) throw new Error(\"next() called multiple times\");\n\t\t\tindex = i;\n\t\t\tconst fn = middleware[i];\n\t\t\tif (!fn) return;\n\t\t\tawait fn(ctx, () => dispatch(i + 1));\n\t\t}\n\t\tawait dispatch(0);\n\t};\n}\n","import type { ZodType, z } from \"zod\";\n\nexport interface WorkflowConfig {\n\tstates: Record<string, ZodType>;\n\tcommands: Record<string, ZodType>;\n\tevents: Record<string, ZodType>;\n\terrors: Record<string, ZodType>;\n}\n\nexport type StateNames<T extends WorkflowConfig> = keyof T[\"states\"] & string;\nexport type CommandNames<T extends WorkflowConfig> = keyof T[\"commands\"] & string;\nexport type EventNames<T extends WorkflowConfig> = keyof T[\"events\"] & string;\nexport type ErrorCodes<T extends WorkflowConfig> = keyof T[\"errors\"] & string;\n\nexport type StateData<\n\tT extends WorkflowConfig,\n\tS extends StateNames<T>,\n> = T[\"states\"][S] extends ZodType ? z.infer<T[\"states\"][S]> : never;\n\nexport type CommandPayload<\n\tT extends WorkflowConfig,\n\tC extends CommandNames<T>,\n> = T[\"commands\"][C] extends ZodType ? z.infer<T[\"commands\"][C]> : never;\n\nexport type EventData<\n\tT extends WorkflowConfig,\n\tE extends EventNames<T>,\n> = T[\"events\"][E] extends ZodType ? z.infer<T[\"events\"][E]> : never;\n\nexport type ErrorData<\n\tT extends WorkflowConfig,\n\tC extends ErrorCodes<T>,\n> = T[\"errors\"][C] extends ZodType ? z.infer<T[\"errors\"][C]> : never;\n\n/** Workflow narrowed to a specific known state. */\nexport interface WorkflowOf<TConfig extends WorkflowConfig, S extends StateNames<TConfig>> {\n\treadonly id: string;\n\treadonly definitionName: string;\n\treadonly state: S;\n\treadonly data: StateData<TConfig, S>;\n\treadonly createdAt: Date;\n\treadonly updatedAt: Date;\n}\n\n/** Discriminated union of all possible workflow states — checking .state narrows .data. */\nexport type Workflow<TConfig extends WorkflowConfig = WorkflowConfig> = {\n\t[S in StateNames<TConfig>]: WorkflowOf<TConfig, S>;\n}[StateNames<TConfig>];\n\nexport type PipelineError<TConfig extends WorkflowConfig = WorkflowConfig> =\n\t| {\n\t\t\tcategory: \"validation\";\n\t\t\tsource: \"command\" | \"state\" | \"event\" | \"transition\";\n\t\t\tissues: z.core.$ZodIssue[];\n\t\t\tmessage: string;\n\t }\n\t| {\n\t\t\tcategory: \"domain\";\n\t\t\tcode: ErrorCodes<TConfig>;\n\t\t\tdata: ErrorData<TConfig, ErrorCodes<TConfig>>;\n\t }\n\t| {\n\t\t\tcategory: \"router\";\n\t\t\tcode: \"NO_HANDLER\" | \"UNKNOWN_STATE\";\n\t\t\tmessage: string;\n\t };\n\nexport type DispatchResult<TConfig extends WorkflowConfig = WorkflowConfig> =\n\t| {\n\t\t\tok: true;\n\t\t\tworkflow: Workflow<TConfig>;\n\t\t\tevents: Array<{ type: EventNames<TConfig>; data: unknown }>;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\terror: PipelineError<TConfig>;\n\t };\n\n/** Thrown internally when Zod validation fails during dispatch. */\nexport class ValidationError extends Error {\n\tconstructor(\n\t\tpublic readonly source: \"command\" | \"state\" | \"event\" | \"transition\",\n\t\tpublic readonly issues: z.core.$ZodIssue[],\n\t) {\n\t\tsuper(`Validation failed (${source}): ${issues.map((i) => i.message).join(\", \")}`);\n\t\tthis.name = \"ValidationError\";\n\t}\n}\n\n/** Thrown internally when a handler calls ctx.error(). Caught by the router. */\nexport class DomainErrorSignal extends Error {\n\tconstructor(\n\t\tpublic readonly code: string,\n\t\tpublic readonly data: unknown,\n\t) {\n\t\tsuper(`Domain error: ${code}`);\n\t\tthis.name = \"DomainErrorSignal\";\n\t}\n}\n","import type { WorkflowDefinition } from \"./definition.js\";\nimport type { ContextKey } from \"./key.js\";\nimport type {\n\tCommandNames,\n\tCommandPayload,\n\tErrorCodes,\n\tErrorData,\n\tEventData,\n\tEventNames,\n\tStateData,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowOf,\n} from \"./types.js\";\nimport { DomainErrorSignal, ValidationError } from \"./types.js\";\n\n/** Mutable context flowing through the middleware pipeline during dispatch. */\nexport interface Context<\n\tTConfig extends WorkflowConfig,\n\tTDeps,\n\tTState extends StateNames<TConfig> = StateNames<TConfig>,\n\tTCommand extends CommandNames<TConfig> = CommandNames<TConfig>,\n> {\n\treadonly command: {\n\t\treadonly type: TCommand;\n\t\treadonly payload: CommandPayload<TConfig, TCommand>;\n\t};\n\treadonly workflow: WorkflowOf<TConfig, TState>;\n\treadonly deps: TDeps;\n\n\treadonly data: StateData<TConfig, TState>;\n\tupdate(data: Partial<StateData<TConfig, TState>>): void;\n\n\ttransition<Target extends StateNames<TConfig>>(\n\t\ttarget: Target,\n\t\tdata: StateData<TConfig, Target>,\n\t): void;\n\n\temit<E extends EventNames<TConfig>>(event: { type: E; data: EventData<TConfig, E> }): void;\n\treadonly events: ReadonlyArray<{ type: EventNames<TConfig>; data: unknown }>;\n\n\terror<C extends ErrorCodes<TConfig>>(err: { code: C; data: ErrorData<TConfig, C> }): never;\n\n\tset<T>(key: ContextKey<T>, value: T): void;\n\tget<T>(key: ContextKey<T>): T;\n\tgetOrNull<T>(key: ContextKey<T>): T | undefined;\n\n\t/** @internal — not part of the handler API */\n\tgetWorkflowSnapshot(): Workflow<TConfig>;\n}\n\ninterface DomainEvent {\n\ttype: string;\n\tdata: unknown;\n}\n\n/** @internal Creates a context for dispatch. Not part of public API. */\nexport function createContext<TConfig extends WorkflowConfig, TDeps>(\n\tdefinition: WorkflowDefinition<TConfig>,\n\toriginalWorkflow: Workflow<TConfig>,\n\tcommand: { type: string; payload: unknown },\n\tdeps: TDeps,\n): Context<TConfig, TDeps> {\n\tlet mutableState = originalWorkflow.state;\n\tlet mutableData: Record<string, unknown> = {\n\t\t...(originalWorkflow.data as Record<string, unknown>),\n\t};\n\n\tconst accumulatedEvents: DomainEvent[] = [];\n\tconst middlewareState = new Map<symbol, unknown>();\n\n\tconst ctx = {\n\t\tcommand,\n\t\tworkflow: originalWorkflow,\n\t\tdeps,\n\n\t\tget data() {\n\t\t\treturn { ...mutableData } as StateData<TConfig, StateNames<TConfig>>;\n\t\t},\n\n\t\tupdate(data: Record<string, unknown>) {\n\t\t\tconst merged = { ...mutableData, ...data };\n\t\t\tconst schema = definition.getStateSchema(mutableState);\n\t\t\tconst result = schema.safeParse(merged);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new ValidationError(\"state\", result.error.issues);\n\t\t\t}\n\t\t\tmutableData = result.data as Record<string, unknown>;\n\t\t},\n\n\t\ttransition(target: string, data: unknown) {\n\t\t\tif (!definition.hasState(target)) {\n\t\t\t\tthrow new Error(`Unknown state: ${target}`);\n\t\t\t}\n\t\t\tconst schema = definition.getStateSchema(target);\n\t\t\tconst result = schema.safeParse(data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new ValidationError(\"transition\", result.error.issues);\n\t\t\t}\n\t\t\tmutableState = target;\n\t\t\tmutableData = result.data as Record<string, unknown>;\n\t\t},\n\n\t\temit(event: { type: string; data: unknown }) {\n\t\t\tconst schema = definition.getEventSchema(event.type);\n\t\t\tconst result = schema.safeParse(event.data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new ValidationError(\"event\", result.error.issues);\n\t\t\t}\n\t\t\taccumulatedEvents.push({ type: event.type, data: result.data });\n\t\t},\n\n\t\tget events() {\n\t\t\treturn [...accumulatedEvents];\n\t\t},\n\n\t\terror(err: { code: string; data: unknown }) {\n\t\t\tconst schema = definition.getErrorSchema(err.code);\n\t\t\tconst result = schema.safeParse(err.data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid error data for '${err.code}': ${result.error.issues.map((i) => i.message).join(\", \")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new DomainErrorSignal(err.code, result.data);\n\t\t},\n\n\t\tset<T>(key: ContextKey<T>, value: T) {\n\t\t\tmiddlewareState.set(key.id, value);\n\t\t},\n\n\t\tget<T>(key: ContextKey<T>): T {\n\t\t\tif (!middlewareState.has(key.id)) {\n\t\t\t\tthrow new Error(`Context key not set: ${key.id.toString()}`);\n\t\t\t}\n\t\t\treturn middlewareState.get(key.id) as T;\n\t\t},\n\n\t\tgetOrNull<T>(key: ContextKey<T>): T | undefined {\n\t\t\treturn middlewareState.get(key.id) as T | undefined;\n\t\t},\n\n\t\tgetWorkflowSnapshot(): Workflow<TConfig> {\n\t\t\treturn {\n\t\t\t\tid: originalWorkflow.id,\n\t\t\t\tdefinitionName: originalWorkflow.definitionName,\n\t\t\t\tstate: mutableState,\n\t\t\t\tdata: { ...mutableData },\n\t\t\t\tcreatedAt: originalWorkflow.createdAt,\n\t\t\t\tupdatedAt: new Date(),\n\t\t\t} as Workflow<TConfig>;\n\t\t},\n\t};\n\n\treturn ctx as unknown as Context<TConfig, TDeps>;\n}\n","import { compose } from \"./compose.js\";\nimport { type Context, createContext } from \"./context.js\";\nimport type { WorkflowDefinition } from \"./definition.js\";\nimport type {\n\tCommandNames,\n\tDispatchResult,\n\tErrorCodes,\n\tErrorData,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n} from \"./types.js\";\nimport { DomainErrorSignal, ValidationError } from \"./types.js\";\n\n// biome-ignore lint/suspicious/noExplicitAny: internal type erasure for heterogeneous middleware storage\ntype AnyMiddleware = (ctx: any, next: () => Promise<void>) => Promise<void>;\n// biome-ignore lint/suspicious/noExplicitAny: internal type erasure for heterogeneous handler storage\ntype AnyHandler = (ctx: any) => void | Promise<void>;\n\ntype HandlerEntry = { inlineMiddleware: AnyMiddleware[]; handler: AnyMiddleware };\n\nclass StateBuilder<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TConfig>> {\n\t/** @internal */ readonly middleware: AnyMiddleware[] = [];\n\t/** @internal */ readonly handlers = new Map<string, HandlerEntry>();\n\n\ton<C extends CommandNames<TConfig>>(\n\t\tcommand: C,\n\t\t...fns: [...AnyMiddleware[], (ctx: Context<TConfig, TDeps, TState, C>) => void | Promise<void>]\n\t): this {\n\t\tif (fns.length === 0) throw new Error(\"on() requires at least a handler\");\n\t\tconst handler = fns.pop() as AnyHandler;\n\t\tconst inlineMiddleware = fns as AnyMiddleware[];\n\t\tconst wrappedHandler: AnyMiddleware = async (ctx, _next) => {\n\t\t\tawait handler(ctx);\n\t\t};\n\t\tthis.handlers.set(command as string, { inlineMiddleware, handler: wrappedHandler });\n\t\treturn this;\n\t}\n\n\tuse(\n\t\tmiddleware: (ctx: Context<TConfig, TDeps, TState>, next: () => Promise<void>) => Promise<void>,\n\t): this {\n\t\tthis.middleware.push(middleware as AnyMiddleware);\n\t\treturn this;\n\t}\n}\n\n/**\n * Routes commands to handlers based on workflow state.\n *\n * Supports global middleware, state-scoped middleware, inline middleware,\n * wildcard handlers, and multi-state handlers.\n */\n// biome-ignore lint/complexity/noBannedTypes: {} is correct here — TDeps defaults to \"no deps\", inferred away when deps are provided\nexport class WorkflowRouter<TConfig extends WorkflowConfig, TDeps = {}> {\n\tprivate globalMiddleware: AnyMiddleware[] = [];\n\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\tprivate singleStateBuilders = new Map<string, StateBuilder<TConfig, TDeps, any>>();\n\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\tprivate multiStateBuilders = new Map<string, StateBuilder<TConfig, TDeps, any>>();\n\tprivate wildcardHandlers = new Map<string, HandlerEntry>();\n\n\tconstructor(\n\t\tprivate readonly definition: WorkflowDefinition<TConfig>,\n\t\tprivate readonly deps: TDeps = {} as TDeps,\n\t) {}\n\n\t/** Adds global middleware or merges another router's handlers. */\n\tuse(\n\t\tmiddlewareOrRouter:\n\t\t\t| ((ctx: Context<TConfig, TDeps>, next: () => Promise<void>) => Promise<void>)\n\t\t\t| WorkflowRouter<TConfig, TDeps>,\n\t): this {\n\t\tif (middlewareOrRouter instanceof WorkflowRouter) {\n\t\t\tthis.merge(middlewareOrRouter);\n\t\t} else {\n\t\t\tthis.globalMiddleware.push(middlewareOrRouter as AnyMiddleware);\n\t\t}\n\t\treturn this;\n\t}\n\n\tprivate merge(child: WorkflowRouter<TConfig, TDeps>): void {\n\t\tif (child.definition !== this.definition) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot merge router for '${child.definition.name}' into router for '${this.definition.name}': definition mismatch`,\n\t\t\t);\n\t\t}\n\n\t\tthis.globalMiddleware.push(...child.globalMiddleware);\n\t\tthis.mergeStateBuilders(this.singleStateBuilders, child.singleStateBuilders);\n\t\tthis.mergeStateBuilders(this.multiStateBuilders, child.multiStateBuilders);\n\n\t\tfor (const [command, entry] of child.wildcardHandlers) {\n\t\t\tif (!this.wildcardHandlers.has(command)) {\n\t\t\t\tthis.wildcardHandlers.set(command, {\n\t\t\t\t\tinlineMiddleware: [...entry.inlineMiddleware],\n\t\t\t\t\thandler: entry.handler,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate mergeStateBuilders(\n\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\t\ttarget: Map<string, StateBuilder<TConfig, TDeps, any>>,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\t\tsource: Map<string, StateBuilder<TConfig, TDeps, any>>,\n\t): void {\n\t\tfor (const [stateName, childBuilder] of source) {\n\t\t\tlet parentBuilder = target.get(stateName);\n\t\t\tif (!parentBuilder) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — state name is dynamic at runtime\n\t\t\t\tparentBuilder = new StateBuilder<TConfig, TDeps, any>();\n\t\t\t\ttarget.set(stateName, parentBuilder);\n\t\t\t}\n\t\t\tfor (const [command, entry] of childBuilder.handlers) {\n\t\t\t\tif (!parentBuilder.handlers.has(command)) {\n\t\t\t\t\tparentBuilder.handlers.set(command, {\n\t\t\t\t\t\tinlineMiddleware: [...entry.inlineMiddleware],\n\t\t\t\t\t\thandler: entry.handler,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tparentBuilder.middleware.push(...childBuilder.middleware);\n\t\t}\n\t}\n\n\t/** Registers handlers for one or more states. */\n\tstate<P extends StateNames<TConfig> | readonly StateNames<TConfig>[]>(\n\t\tname: P,\n\t\tsetup: (\n\t\t\tstate: StateBuilder<\n\t\t\t\tTConfig,\n\t\t\t\tTDeps,\n\t\t\t\tP extends readonly (infer S)[] ? S & StateNames<TConfig> : P & StateNames<TConfig>\n\t\t\t>,\n\t\t) => void,\n\t): this {\n\t\tconst names = Array.isArray(name) ? name : [name];\n\t\tconst isMulti = Array.isArray(name);\n\t\tconst routerMap = isMulti ? this.multiStateBuilders : this.singleStateBuilders;\n\n\t\tfor (const n of names as string[]) {\n\t\t\tlet router = routerMap.get(n);\n\t\t\tif (!router) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — state name is dynamic at runtime\n\t\t\t\trouter = new StateBuilder<TConfig, TDeps, any>();\n\t\t\t\trouterMap.set(n, router);\n\t\t\t}\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — setup callback expects a specific state type\n\t\t\tsetup(router as any);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/** Registers a wildcard handler that matches any state. */\n\ton<C extends CommandNames<TConfig>>(\n\t\t_state: \"*\",\n\t\tcommand: C,\n\t\t...fns: [\n\t\t\t...AnyMiddleware[],\n\t\t\t(ctx: Context<TConfig, TDeps, StateNames<TConfig>, C>) => void | Promise<void>,\n\t\t]\n\t): this {\n\t\tif (fns.length === 0) throw new Error(\"on() requires at least a handler\");\n\t\tconst handler = fns.pop() as AnyHandler;\n\t\tconst inlineMiddleware = fns as AnyMiddleware[];\n\t\tconst wrappedHandler: AnyMiddleware = async (ctx, _next) => {\n\t\t\tawait handler(ctx);\n\t\t};\n\t\tthis.wildcardHandlers.set(command as string, {\n\t\t\tinlineMiddleware,\n\t\t\thandler: wrappedHandler,\n\t\t});\n\t\treturn this;\n\t}\n\n\t/** Dispatches a command to the appropriate handler and returns the result. */\n\tasync dispatch(\n\t\tworkflow: Workflow<TConfig>,\n\t\tcommand: { type: CommandNames<TConfig>; payload: unknown },\n\t): Promise<DispatchResult<TConfig>> {\n\t\tif (!this.definition.hasState(workflow.state)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"router\",\n\t\t\t\t\tcode: \"UNKNOWN_STATE\",\n\t\t\t\t\tmessage: `Unknown state: ${workflow.state}`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst commandSchema = this.definition.getCommandSchema(command.type);\n\t\tconst payloadResult = commandSchema.safeParse(command.payload);\n\t\tif (!payloadResult.success) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"validation\",\n\t\t\t\t\tsource: \"command\",\n\t\t\t\t\tissues: payloadResult.error.issues,\n\t\t\t\t\tmessage: `Invalid command payload: ${payloadResult.error.issues.map((i) => i.message).join(\", \")}`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tconst validatedCommand = { type: command.type, payload: payloadResult.data };\n\n\t\tconst stateName = workflow.state;\n\t\tconst singleRouter = this.singleStateBuilders.get(stateName);\n\t\tconst multiRouter = this.multiStateBuilders.get(stateName);\n\t\tconst singleHandler = singleRouter?.handlers.get(command.type);\n\t\tconst multiHandler = multiRouter?.handlers.get(command.type);\n\t\tconst wildcardHandler = this.wildcardHandlers.get(command.type);\n\n\t\tlet routeEntry: HandlerEntry | undefined;\n\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — matched router's state type is dynamic\n\t\tlet matchedRouter: StateBuilder<TConfig, TDeps, any> | undefined;\n\n\t\tif (singleHandler) {\n\t\t\trouteEntry = singleHandler;\n\t\t\tmatchedRouter = singleRouter;\n\t\t} else if (multiHandler) {\n\t\t\trouteEntry = multiHandler;\n\t\t\tmatchedRouter = multiRouter;\n\t\t} else if (wildcardHandler) {\n\t\t\trouteEntry = wildcardHandler;\n\t\t\tmatchedRouter = undefined;\n\t\t}\n\n\t\tif (!routeEntry) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"router\",\n\t\t\t\t\tcode: \"NO_HANDLER\",\n\t\t\t\t\tmessage: `No handler for command '${command.type}' in state '${stateName}'`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst stateMiddleware: AnyMiddleware[] = [];\n\t\tif (matchedRouter) {\n\t\t\tif (singleRouter) stateMiddleware.push(...singleRouter.middleware);\n\t\t\tif (multiRouter && multiRouter !== singleRouter)\n\t\t\t\tstateMiddleware.push(...multiRouter.middleware);\n\t\t}\n\n\t\tconst chain: AnyMiddleware[] = [\n\t\t\t...this.globalMiddleware,\n\t\t\t...stateMiddleware,\n\t\t\t...routeEntry.inlineMiddleware,\n\t\t\trouteEntry.handler,\n\t\t];\n\n\t\tconst ctx = createContext<TConfig, TDeps>(\n\t\t\tthis.definition,\n\t\t\tworkflow,\n\t\t\tvalidatedCommand,\n\t\t\tthis.deps,\n\t\t);\n\n\t\ttry {\n\t\t\tconst composed = compose(chain);\n\t\t\tawait composed(ctx);\n\t\t\treturn {\n\t\t\t\tok: true as const,\n\t\t\t\tworkflow: ctx.getWorkflowSnapshot(),\n\t\t\t\tevents: [...ctx.events],\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tif (err instanceof DomainErrorSignal) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false as const,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcategory: \"domain\" as const,\n\t\t\t\t\t\tcode: err.code as ErrorCodes<TConfig>,\n\t\t\t\t\t\tdata: err.data as ErrorData<TConfig, ErrorCodes<TConfig>>,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (err instanceof ValidationError) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false as const,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcategory: \"validation\" as const,\n\t\t\t\t\t\tsource: err.source,\n\t\t\t\t\t\tissues: err.issues,\n\t\t\t\t\t\tmessage: err.message,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/definition.ts","../src/key.ts","../src/plugin.ts","../src/compose.ts","../src/context.ts","../src/hooks.ts","../src/router.ts"],"sourcesContent":["import type { ZodType, z } from \"zod\";\n\nexport interface WorkflowConfig {\n\tmodelVersion?: number;\n\tstates: Record<string, ZodType>;\n\tcommands: Record<string, ZodType>;\n\tevents: Record<string, ZodType>;\n\terrors: Record<string, ZodType>;\n}\n\nexport type StateNames<T extends WorkflowConfig> = keyof T[\"states\"] & string;\nexport type CommandNames<T extends WorkflowConfig> = keyof T[\"commands\"] & string;\nexport type EventNames<T extends WorkflowConfig> = keyof T[\"events\"] & string;\nexport type ErrorCodes<T extends WorkflowConfig> = keyof T[\"errors\"] & string;\n\nexport type StateData<\n\tT extends WorkflowConfig,\n\tS extends StateNames<T>,\n> = T[\"states\"][S] extends ZodType ? z.infer<T[\"states\"][S]> : never;\n\nexport type CommandPayload<\n\tT extends WorkflowConfig,\n\tC extends CommandNames<T>,\n> = T[\"commands\"][C] extends ZodType ? z.infer<T[\"commands\"][C]> : never;\n\nexport type EventData<\n\tT extends WorkflowConfig,\n\tE extends EventNames<T>,\n> = T[\"events\"][E] extends ZodType ? z.infer<T[\"events\"][E]> : never;\n\nexport type ErrorData<\n\tT extends WorkflowConfig,\n\tC extends ErrorCodes<T>,\n> = T[\"errors\"][C] extends ZodType ? z.infer<T[\"errors\"][C]> : never;\n\n/** Workflow narrowed to a specific known state. */\nexport interface WorkflowOf<TConfig extends WorkflowConfig, S extends StateNames<TConfig>> {\n\treadonly id: string;\n\treadonly definitionName: string;\n\treadonly state: S;\n\treadonly data: StateData<TConfig, S>;\n\treadonly createdAt: Date;\n\treadonly updatedAt: Date;\n}\n\n/** Discriminated union of all possible workflow states — checking .state narrows .data. */\nexport type Workflow<TConfig extends WorkflowConfig = WorkflowConfig> = {\n\t[S in StateNames<TConfig>]: WorkflowOf<TConfig, S>;\n}[StateNames<TConfig>];\n\nexport type PipelineError<TConfig extends WorkflowConfig = WorkflowConfig> =\n\t| {\n\t\t\tcategory: \"validation\";\n\t\t\tsource: \"command\" | \"state\" | \"event\" | \"transition\" | \"restore\";\n\t\t\tissues: z.core.$ZodIssue[];\n\t\t\tmessage: string;\n\t }\n\t| {\n\t\t\tcategory: \"domain\";\n\t\t\tcode: ErrorCodes<TConfig>;\n\t\t\tdata: ErrorData<TConfig, ErrorCodes<TConfig>>;\n\t }\n\t| {\n\t\t\tcategory: \"router\";\n\t\t\tcode: \"NO_HANDLER\" | \"UNKNOWN_STATE\";\n\t\t\tmessage: string;\n\t };\n\nexport type DispatchResult<TConfig extends WorkflowConfig = WorkflowConfig> =\n\t| {\n\t\t\tok: true;\n\t\t\tworkflow: Workflow<TConfig>;\n\t\t\tevents: Array<{ type: EventNames<TConfig>; data: unknown }>;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\terror: PipelineError<TConfig>;\n\t };\n\n/** Thrown internally when Zod validation fails during dispatch. */\nexport class ValidationError extends Error {\n\tconstructor(\n\t\tpublic readonly source: \"command\" | \"state\" | \"event\" | \"transition\" | \"restore\",\n\t\tpublic readonly issues: z.core.$ZodIssue[],\n\t) {\n\t\tsuper(`Validation failed (${source}): ${issues.map((i) => i.message).join(\", \")}`);\n\t\tthis.name = \"ValidationError\";\n\t}\n}\n\n/** Thrown internally when a handler calls ctx.error(). Caught by the router. */\nexport class DomainErrorSignal extends Error {\n\tconstructor(\n\t\tpublic readonly code: string,\n\t\tpublic readonly data: unknown,\n\t) {\n\t\tsuper(`Domain error: ${code}`);\n\t\tthis.name = \"DomainErrorSignal\";\n\t}\n}\n","import type { ZodType, z } from \"zod\";\nimport type { WorkflowSnapshot } from \"./snapshot.js\";\nimport type { StateNames, Workflow, WorkflowConfig, WorkflowOf } from \"./types.js\";\nimport { ValidationError } from \"./types.js\";\n\n/** The result of defineWorkflow() — holds schemas and creates workflow instances. */\nexport interface WorkflowDefinition<TConfig extends WorkflowConfig = WorkflowConfig> {\n\treadonly config: TConfig;\n\treadonly name: string;\n\tcreateWorkflow<S extends StateNames<TConfig>>(\n\t\tid: string,\n\t\tconfig: { initialState: S; data: z.infer<TConfig[\"states\"][S]> },\n\t): WorkflowOf<TConfig, S>;\n\tgetStateSchema(stateName: string): ZodType;\n\tgetCommandSchema(commandName: string): ZodType;\n\tgetEventSchema(eventName: string): ZodType;\n\tgetErrorSchema(errorCode: string): ZodType;\n\thasState(stateName: string): boolean;\n\tsnapshot(workflow: Workflow<TConfig>): WorkflowSnapshot<TConfig>;\n\trestore(\n\t\tsnapshot: WorkflowSnapshot<TConfig>,\n\t): { ok: true; workflow: Workflow<TConfig> } | { ok: false; error: ValidationError };\n}\n\n/**\n * Creates a workflow definition from a name and Zod schema configuration.\n */\nexport function defineWorkflow<const TConfig extends WorkflowConfig>(\n\tname: string,\n\tconfig: TConfig,\n): WorkflowDefinition<TConfig> {\n\treturn {\n\t\tconfig,\n\t\tname,\n\n\t\tcreateWorkflow(id, wfConfig) {\n\t\t\tconst schema = config.states[wfConfig.initialState as string];\n\t\t\tif (!schema) throw new Error(`Unknown state: ${wfConfig.initialState as string}`);\n\t\t\tconst result = schema.safeParse(wfConfig.data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid initial data for state '${wfConfig.initialState as string}': ${result.error.issues.map((i) => i.message).join(\", \")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst now = new Date();\n\t\t\treturn {\n\t\t\t\tid,\n\t\t\t\tdefinitionName: name,\n\t\t\t\tstate: wfConfig.initialState,\n\t\t\t\tdata: result.data,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t} as WorkflowOf<TConfig, typeof wfConfig.initialState>;\n\t\t},\n\n\t\tgetStateSchema(stateName: string): ZodType {\n\t\t\tconst schema = config.states[stateName];\n\t\t\tif (!schema) throw new Error(`Unknown state: ${stateName}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\tgetCommandSchema(commandName: string): ZodType {\n\t\t\tconst schema = config.commands[commandName];\n\t\t\tif (!schema) throw new Error(`Unknown command: ${commandName}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\tgetEventSchema(eventName: string): ZodType {\n\t\t\tconst schema = config.events[eventName];\n\t\t\tif (!schema) throw new Error(`Unknown event: ${eventName}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\tgetErrorSchema(errorCode: string): ZodType {\n\t\t\tconst schema = config.errors[errorCode];\n\t\t\tif (!schema) throw new Error(`Unknown error: ${errorCode}`);\n\t\t\treturn schema;\n\t\t},\n\n\t\thasState(stateName: string): boolean {\n\t\t\treturn stateName in config.states;\n\t\t},\n\n\t\tsnapshot(workflow: Workflow<TConfig>): WorkflowSnapshot<TConfig> {\n\t\t\treturn {\n\t\t\t\tid: workflow.id,\n\t\t\t\tdefinitionName: name,\n\t\t\t\tstate: workflow.state,\n\t\t\t\tdata: workflow.data,\n\t\t\t\tcreatedAt: workflow.createdAt.toISOString(),\n\t\t\t\tupdatedAt: workflow.updatedAt.toISOString(),\n\t\t\t\tmodelVersion: config.modelVersion ?? 1,\n\t\t\t} as WorkflowSnapshot<TConfig>;\n\t\t},\n\n\t\trestore(\n\t\t\tsnap: WorkflowSnapshot<TConfig>,\n\t\t): { ok: true; workflow: Workflow<TConfig> } | { ok: false; error: ValidationError } {\n\t\t\tconst stateSchema = config.states[snap.state as string];\n\t\t\tif (!stateSchema) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: new ValidationError(\"restore\", [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcode: \"custom\",\n\t\t\t\t\t\t\tmessage: `Unknown state: ${snap.state}`,\n\t\t\t\t\t\t\tinput: snap.state,\n\t\t\t\t\t\t\tpath: [\"state\"],\n\t\t\t\t\t\t},\n\t\t\t\t\t]),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst result = stateSchema.safeParse(snap.data);\n\t\t\tif (!result.success) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: new ValidationError(\"restore\", result.error.issues),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tok: true,\n\t\t\t\tworkflow: {\n\t\t\t\t\tid: snap.id,\n\t\t\t\t\tdefinitionName: snap.definitionName,\n\t\t\t\t\tstate: snap.state,\n\t\t\t\t\tdata: result.data,\n\t\t\t\t\tcreatedAt: new Date(snap.createdAt),\n\t\t\t\t\tupdatedAt: new Date(snap.updatedAt),\n\t\t\t\t} as Workflow<TConfig>,\n\t\t\t};\n\t\t},\n\t};\n}\n","/** A phantom-typed key for type-safe middleware state storage. */\nexport interface ContextKey<T> {\n\treadonly _phantom: T;\n\treadonly id: symbol;\n}\n\n/** Creates a unique typed key for storing/retrieving values in context. */\nexport function createKey<T>(name: string): ContextKey<T> {\n\treturn { id: Symbol(name) } as ContextKey<T>;\n}\n","import type { WorkflowRouter } from \"./router.js\";\nimport type { WorkflowConfig } from \"./types.js\";\n\nconst PLUGIN_SYMBOL: unique symbol = Symbol.for(\"ryte:plugin\");\n\n/** A branded plugin function that can be passed to router.use(). */\nexport type Plugin<TConfig extends WorkflowConfig, TDeps> = ((\n\trouter: WorkflowRouter<TConfig, TDeps>,\n) => void) & { readonly [PLUGIN_SYMBOL]: true };\n\n/** Brands a function as a Ryte plugin for use with router.use(). */\nexport function definePlugin<TConfig extends WorkflowConfig, TDeps>(\n\tfn: (router: WorkflowRouter<TConfig, TDeps>) => void,\n): Plugin<TConfig, TDeps> {\n\tconst plugin = fn as Plugin<TConfig, TDeps>;\n\tObject.defineProperty(plugin, PLUGIN_SYMBOL, { value: true, writable: false });\n\treturn plugin;\n}\n\n/** Checks whether a value is a branded Ryte plugin. */\nexport function isPlugin(value: unknown): value is Plugin<WorkflowConfig, unknown> {\n\treturn typeof value === \"function\" && PLUGIN_SYMBOL in value;\n}\n","type Middleware<TCtx> = (ctx: TCtx, next: () => Promise<void>) => Promise<void>;\n\n/** Composes an array of middleware into a single function (Koa-style onion model). */\nexport function compose<TCtx>(middleware: Middleware<TCtx>[]): (ctx: TCtx) => Promise<void> {\n\treturn async (ctx: TCtx) => {\n\t\tlet index = -1;\n\t\tasync function dispatch(i: number): Promise<void> {\n\t\t\tif (i <= index) throw new Error(\"next() called multiple times\");\n\t\t\tindex = i;\n\t\t\tconst fn = middleware[i];\n\t\t\tif (!fn) return;\n\t\t\tawait fn(ctx, () => dispatch(i + 1));\n\t\t}\n\t\tawait dispatch(0);\n\t};\n}\n","import type { WorkflowDefinition } from \"./definition.js\";\nimport type { ContextKey } from \"./key.js\";\nimport type {\n\tCommandNames,\n\tCommandPayload,\n\tErrorCodes,\n\tErrorData,\n\tEventData,\n\tEventNames,\n\tStateData,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowOf,\n} from \"./types.js\";\nimport { DomainErrorSignal, ValidationError } from \"./types.js\";\n\n/** Mutable context flowing through the middleware pipeline during dispatch. */\nexport interface Context<\n\tTConfig extends WorkflowConfig,\n\tTDeps,\n\tTState extends StateNames<TConfig> = StateNames<TConfig>,\n\tTCommand extends CommandNames<TConfig> = CommandNames<TConfig>,\n> {\n\treadonly command: {\n\t\treadonly type: TCommand;\n\t\treadonly payload: CommandPayload<TConfig, TCommand>;\n\t};\n\treadonly workflow: WorkflowOf<TConfig, TState>;\n\treadonly deps: TDeps;\n\n\treadonly data: StateData<TConfig, TState>;\n\tupdate(data: Partial<StateData<TConfig, TState>>): void;\n\n\ttransition<Target extends StateNames<TConfig>>(\n\t\ttarget: Target,\n\t\tdata: StateData<TConfig, Target>,\n\t): void;\n\n\temit<E extends EventNames<TConfig>>(event: { type: E; data: EventData<TConfig, E> }): void;\n\treadonly events: ReadonlyArray<{ type: EventNames<TConfig>; data: unknown }>;\n\n\terror<C extends ErrorCodes<TConfig>>(err: { code: C; data: ErrorData<TConfig, C> }): never;\n\n\tset<T>(key: ContextKey<T>, value: T): void;\n\tget<T>(key: ContextKey<T>): T;\n\tgetOrNull<T>(key: ContextKey<T>): T | undefined;\n\n\t/** @internal — not part of the handler API */\n\tgetWorkflowSnapshot(): Workflow<TConfig>;\n}\n\ninterface DomainEvent {\n\ttype: string;\n\tdata: unknown;\n}\n\n/** @internal Creates a context for dispatch. Not part of public API. */\nexport function createContext<TConfig extends WorkflowConfig, TDeps>(\n\tdefinition: WorkflowDefinition<TConfig>,\n\toriginalWorkflow: Workflow<TConfig>,\n\tcommand: { type: string; payload: unknown },\n\tdeps: TDeps,\n): Context<TConfig, TDeps> {\n\tlet mutableState = originalWorkflow.state;\n\tlet mutableData: Record<string, unknown> = {\n\t\t...(originalWorkflow.data as Record<string, unknown>),\n\t};\n\n\tconst accumulatedEvents: DomainEvent[] = [];\n\tconst middlewareState = new Map<symbol, unknown>();\n\n\tconst ctx = {\n\t\tcommand,\n\t\tworkflow: originalWorkflow,\n\t\tdeps,\n\n\t\tget data() {\n\t\t\treturn { ...mutableData } as StateData<TConfig, StateNames<TConfig>>;\n\t\t},\n\n\t\tupdate(data: Record<string, unknown>) {\n\t\t\tconst merged = { ...mutableData, ...data };\n\t\t\tconst schema = definition.getStateSchema(mutableState);\n\t\t\tconst result = schema.safeParse(merged);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new ValidationError(\"state\", result.error.issues);\n\t\t\t}\n\t\t\tmutableData = result.data as Record<string, unknown>;\n\t\t},\n\n\t\ttransition(target: string, data: unknown) {\n\t\t\tif (!definition.hasState(target)) {\n\t\t\t\tthrow new Error(`Unknown state: ${target}`);\n\t\t\t}\n\t\t\tconst schema = definition.getStateSchema(target);\n\t\t\tconst result = schema.safeParse(data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new ValidationError(\"transition\", result.error.issues);\n\t\t\t}\n\t\t\tmutableState = target;\n\t\t\tmutableData = result.data as Record<string, unknown>;\n\t\t},\n\n\t\temit(event: { type: string; data: unknown }) {\n\t\t\tconst schema = definition.getEventSchema(event.type);\n\t\t\tconst result = schema.safeParse(event.data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new ValidationError(\"event\", result.error.issues);\n\t\t\t}\n\t\t\taccumulatedEvents.push({ type: event.type, data: result.data });\n\t\t},\n\n\t\tget events() {\n\t\t\treturn [...accumulatedEvents];\n\t\t},\n\n\t\terror(err: { code: string; data: unknown }) {\n\t\t\tconst schema = definition.getErrorSchema(err.code);\n\t\t\tconst result = schema.safeParse(err.data);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid error data for '${err.code}': ${result.error.issues.map((i) => i.message).join(\", \")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new DomainErrorSignal(err.code, result.data);\n\t\t},\n\n\t\tset<T>(key: ContextKey<T>, value: T) {\n\t\t\tmiddlewareState.set(key.id, value);\n\t\t},\n\n\t\tget<T>(key: ContextKey<T>): T {\n\t\t\tif (!middlewareState.has(key.id)) {\n\t\t\t\tthrow new Error(`Context key not set: ${key.id.toString()}`);\n\t\t\t}\n\t\t\treturn middlewareState.get(key.id) as T;\n\t\t},\n\n\t\tgetOrNull<T>(key: ContextKey<T>): T | undefined {\n\t\t\treturn middlewareState.get(key.id) as T | undefined;\n\t\t},\n\n\t\tgetWorkflowSnapshot(): Workflow<TConfig> {\n\t\t\treturn {\n\t\t\t\tid: originalWorkflow.id,\n\t\t\t\tdefinitionName: originalWorkflow.definitionName,\n\t\t\t\tstate: mutableState,\n\t\t\t\tdata: { ...mutableData },\n\t\t\t\tcreatedAt: originalWorkflow.createdAt,\n\t\t\t\tupdatedAt: new Date(),\n\t\t\t} as Workflow<TConfig>;\n\t\t},\n\t};\n\n\treturn ctx as unknown as Context<TConfig, TDeps>;\n}\n","/** The lifecycle hook event names. */\nexport type HookEvent = \"dispatch:start\" | \"dispatch:end\" | \"transition\" | \"error\" | \"event\";\n\nexport const HOOK_EVENTS: ReadonlySet<string> = new Set<HookEvent>([\n\t\"dispatch:start\",\n\t\"dispatch:end\",\n\t\"transition\",\n\t\"error\",\n\t\"event\",\n]);\n\n/**\n * Internal registry for lifecycle hook callbacks.\n * Hooks are observers — errors are caught and forwarded, never affecting dispatch.\n */\nexport class HookRegistry {\n\t// biome-ignore lint/complexity/noBannedTypes: callbacks have varying signatures per hook event\n\tprivate hooks = new Map<string, Function[]>();\n\n\t/** Register a callback for a hook event. */\n\t// biome-ignore lint/complexity/noBannedTypes: callbacks have varying signatures per hook event\n\tadd(event: string, callback: Function): void {\n\t\tconst existing = this.hooks.get(event) ?? [];\n\t\texisting.push(callback);\n\t\tthis.hooks.set(event, existing);\n\t}\n\n\t/** Emit a hook event, calling all registered callbacks. Errors are caught and forwarded. */\n\tasync emit(event: string, onError: (err: unknown) => void, ...args: unknown[]): Promise<void> {\n\t\tconst callbacks = this.hooks.get(event);\n\t\tif (!callbacks) return;\n\t\tfor (const cb of callbacks) {\n\t\t\ttry {\n\t\t\t\tawait cb(...args);\n\t\t\t} catch (err) {\n\t\t\t\tonError(err);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Merge another registry's hooks into this one (used by composable routers). */\n\tmerge(other: HookRegistry): void {\n\t\tfor (const [event, callbacks] of other.hooks) {\n\t\t\tconst existing = this.hooks.get(event) ?? [];\n\t\t\texisting.push(...callbacks);\n\t\t\tthis.hooks.set(event, existing);\n\t\t}\n\t}\n}\n","import { compose } from \"./compose.js\";\nimport { type Context, createContext } from \"./context.js\";\nimport type { WorkflowDefinition } from \"./definition.js\";\nimport { HOOK_EVENTS, HookRegistry } from \"./hooks.js\";\nimport type { Plugin } from \"./plugin.js\";\nimport { isPlugin } from \"./plugin.js\";\nimport type { ReadonlyContext } from \"./readonly-context.js\";\nimport type {\n\tCommandNames,\n\tDispatchResult,\n\tErrorCodes,\n\tErrorData,\n\tEventNames,\n\tPipelineError,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n} from \"./types.js\";\nimport { DomainErrorSignal, ValidationError } from \"./types.js\";\n\n// biome-ignore lint/suspicious/noExplicitAny: internal type erasure for heterogeneous middleware storage\ntype AnyMiddleware = (ctx: any, next: () => Promise<void>) => Promise<void>;\n// biome-ignore lint/suspicious/noExplicitAny: internal type erasure for heterogeneous handler storage\ntype AnyHandler = (ctx: any) => void | Promise<void>;\n\ntype HandlerEntry = {\n\tinlineMiddleware: AnyMiddleware[];\n\thandler: AnyMiddleware;\n};\n\nexport interface RouterOptions {\n\tonHookError?: (error: unknown) => void;\n}\n\nclass StateBuilder<TConfig extends WorkflowConfig, TDeps, TState extends StateNames<TConfig>> {\n\t/** @internal */ readonly middleware: AnyMiddleware[] = [];\n\t/** @internal */ readonly handlers = new Map<string, HandlerEntry>();\n\n\ton<C extends CommandNames<TConfig>>(\n\t\tcommand: C,\n\t\t...fns: [...AnyMiddleware[], (ctx: Context<TConfig, TDeps, TState, C>) => void | Promise<void>]\n\t): this {\n\t\tif (fns.length === 0) throw new Error(\"on() requires at least a handler\");\n\t\tconst handler = fns.pop() as AnyHandler;\n\t\tconst inlineMiddleware = fns as AnyMiddleware[];\n\t\tconst wrappedHandler: AnyMiddleware = async (ctx, _next) => {\n\t\t\tawait handler(ctx);\n\t\t};\n\t\tthis.handlers.set(command as string, { inlineMiddleware, handler: wrappedHandler });\n\t\treturn this;\n\t}\n\n\tuse(\n\t\tmiddleware: (ctx: Context<TConfig, TDeps, TState>, next: () => Promise<void>) => Promise<void>,\n\t): this {\n\t\tthis.middleware.push(middleware as AnyMiddleware);\n\t\treturn this;\n\t}\n}\n\n/**\n * Routes commands to handlers based on workflow state.\n *\n * Supports global middleware, state-scoped middleware, inline middleware,\n * wildcard handlers, and multi-state handlers.\n */\n// biome-ignore lint/complexity/noBannedTypes: {} is correct here — TDeps defaults to \"no deps\", inferred away when deps are provided\nexport class WorkflowRouter<TConfig extends WorkflowConfig, TDeps = {}> {\n\tprivate globalMiddleware: AnyMiddleware[] = [];\n\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\tprivate singleStateBuilders = new Map<string, StateBuilder<TConfig, TDeps, any>>();\n\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\tprivate multiStateBuilders = new Map<string, StateBuilder<TConfig, TDeps, any>>();\n\tprivate wildcardHandlers = new Map<string, HandlerEntry>();\n\tprivate hookRegistry = new HookRegistry();\n\tprivate readonly onHookError: (error: unknown) => void;\n\n\tconstructor(\n\t\tprivate readonly definition: WorkflowDefinition<TConfig>,\n\t\tprivate readonly deps: TDeps = {} as TDeps,\n\t\toptions: RouterOptions = {},\n\t) {\n\t\tthis.onHookError = options.onHookError ?? console.error;\n\t}\n\n\t/** Adds global middleware, merges another router, or applies a plugin. */\n\tuse(\n\t\targ:\n\t\t\t| ((ctx: Context<TConfig, TDeps>, next: () => Promise<void>) => Promise<void>)\n\t\t\t| WorkflowRouter<TConfig, TDeps>\n\t\t\t| Plugin<TConfig, TDeps>,\n\t): this {\n\t\tif (arg instanceof WorkflowRouter) {\n\t\t\tthis.merge(arg);\n\t\t} else if (isPlugin(arg)) {\n\t\t\t(arg as (router: WorkflowRouter<TConfig, TDeps>) => void)(this);\n\t\t} else {\n\t\t\tthis.globalMiddleware.push(arg as AnyMiddleware);\n\t\t}\n\t\treturn this;\n\t}\n\n\tprivate merge(child: WorkflowRouter<TConfig, TDeps>): void {\n\t\tif (child.definition !== this.definition) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot merge router for '${child.definition.name}' into router for '${this.definition.name}': definition mismatch`,\n\t\t\t);\n\t\t}\n\n\t\tthis.globalMiddleware.push(...child.globalMiddleware);\n\t\tthis.mergeStateBuilders(this.singleStateBuilders, child.singleStateBuilders);\n\t\tthis.mergeStateBuilders(this.multiStateBuilders, child.multiStateBuilders);\n\n\t\tfor (const [command, entry] of child.wildcardHandlers) {\n\t\t\tif (!this.wildcardHandlers.has(command)) {\n\t\t\t\tthis.wildcardHandlers.set(command, {\n\t\t\t\t\tinlineMiddleware: [...entry.inlineMiddleware],\n\t\t\t\t\thandler: entry.handler,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis.hookRegistry.merge(child.hookRegistry);\n\t}\n\n\tprivate mergeStateBuilders(\n\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\t\ttarget: Map<string, StateBuilder<TConfig, TDeps, any>>,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — builders store handlers for different state types\n\t\tsource: Map<string, StateBuilder<TConfig, TDeps, any>>,\n\t): void {\n\t\tfor (const [stateName, childBuilder] of source) {\n\t\t\tlet parentBuilder = target.get(stateName);\n\t\t\tif (!parentBuilder) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — state name is dynamic at runtime\n\t\t\t\tparentBuilder = new StateBuilder<TConfig, TDeps, any>();\n\t\t\t\ttarget.set(stateName, parentBuilder);\n\t\t\t}\n\t\t\tfor (const [command, entry] of childBuilder.handlers) {\n\t\t\t\tif (!parentBuilder.handlers.has(command)) {\n\t\t\t\t\tparentBuilder.handlers.set(command, {\n\t\t\t\t\t\tinlineMiddleware: [...entry.inlineMiddleware],\n\t\t\t\t\t\thandler: entry.handler,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tparentBuilder.middleware.push(...childBuilder.middleware);\n\t\t}\n\t}\n\n\t/** Registers handlers for one or more states. */\n\tstate<P extends StateNames<TConfig> | readonly StateNames<TConfig>[]>(\n\t\tname: P,\n\t\tsetup: (\n\t\t\tstate: StateBuilder<\n\t\t\t\tTConfig,\n\t\t\t\tTDeps,\n\t\t\t\tP extends readonly (infer S)[] ? S & StateNames<TConfig> : P & StateNames<TConfig>\n\t\t\t>,\n\t\t) => void,\n\t): this {\n\t\tconst names = Array.isArray(name) ? name : [name];\n\t\tconst isMulti = Array.isArray(name);\n\t\tconst routerMap = isMulti ? this.multiStateBuilders : this.singleStateBuilders;\n\n\t\tfor (const n of names as string[]) {\n\t\t\tlet router = routerMap.get(n);\n\t\t\tif (!router) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — state name is dynamic at runtime\n\t\t\t\trouter = new StateBuilder<TConfig, TDeps, any>();\n\t\t\t\trouterMap.set(n, router);\n\t\t\t}\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — setup callback expects a specific state type\n\t\t\tsetup(router as any);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/** Registers a lifecycle hook callback. */\n\ton(\n\t\tevent: \"dispatch:start\",\n\t\tcallback: (ctx: ReadonlyContext<TConfig, TDeps>) => void | Promise<void>,\n\t): this;\n\ton(\n\t\tevent: \"dispatch:end\",\n\t\tcallback: (\n\t\t\tctx: ReadonlyContext<TConfig, TDeps>,\n\t\t\tresult: DispatchResult<TConfig>,\n\t\t) => void | Promise<void>,\n\t): this;\n\ton(\n\t\tevent: \"transition\",\n\t\tcallback: (\n\t\t\tfrom: StateNames<TConfig>,\n\t\t\tto: StateNames<TConfig>,\n\t\t\tworkflow: Workflow<TConfig>,\n\t\t) => void | Promise<void>,\n\t): this;\n\ton(\n\t\tevent: \"error\",\n\t\tcallback: (\n\t\t\terror: PipelineError<TConfig>,\n\t\t\tctx: ReadonlyContext<TConfig, TDeps>,\n\t\t) => void | Promise<void>,\n\t): this;\n\ton(\n\t\tevent: \"event\",\n\t\tcallback: (\n\t\t\tevent: { type: EventNames<TConfig>; data: unknown },\n\t\t\tworkflow: Workflow<TConfig>,\n\t\t) => void | Promise<void>,\n\t): this;\n\t/** Registers a wildcard handler that matches any state. */\n\ton<C extends CommandNames<TConfig>>(\n\t\tstate: \"*\",\n\t\tcommand: C,\n\t\t...fns: [\n\t\t\t...AnyMiddleware[],\n\t\t\t(ctx: Context<TConfig, TDeps, StateNames<TConfig>, C>) => void | Promise<void>,\n\t\t]\n\t): this;\n\t// biome-ignore lint/suspicious/noExplicitAny: implementation signature must be loose to handle all overloads\n\ton(...args: any[]): this {\n\t\tconst first = args[0] as string;\n\n\t\tif (HOOK_EVENTS.has(first)) {\n\t\t\t// biome-ignore lint/complexity/noBannedTypes: callbacks have varying signatures per hook event\n\t\t\tthis.hookRegistry.add(first, args[1] as Function);\n\t\t\treturn this;\n\t\t}\n\n\t\tif (first === \"*\") {\n\t\t\tconst command = args[1] as string;\n\t\t\tconst fns = args.slice(2) as unknown[];\n\t\t\tif (fns.length === 0) throw new Error(\"on() requires at least a handler\");\n\t\t\tconst handler = fns.pop() as AnyHandler;\n\t\t\tconst inlineMiddleware = fns as AnyMiddleware[];\n\t\t\tconst wrappedHandler: AnyMiddleware = async (ctx, _next) => {\n\t\t\t\tawait handler(ctx);\n\t\t\t};\n\t\t\tthis.wildcardHandlers.set(command, {\n\t\t\t\tinlineMiddleware,\n\t\t\t\thandler: wrappedHandler,\n\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\tthrow new Error(`Unknown event or state: ${first}`);\n\t}\n\n\t/** Dispatches a command to the appropriate handler and returns the result. */\n\tasync dispatch(\n\t\tworkflow: Workflow<TConfig>,\n\t\tcommand: { type: CommandNames<TConfig>; payload: unknown },\n\t): Promise<DispatchResult<TConfig>> {\n\t\tif (!this.definition.hasState(workflow.state)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"router\",\n\t\t\t\t\tcode: \"UNKNOWN_STATE\",\n\t\t\t\t\tmessage: `Unknown state: ${workflow.state}`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst commandSchema = this.definition.getCommandSchema(command.type);\n\t\tconst payloadResult = commandSchema.safeParse(command.payload);\n\t\tif (!payloadResult.success) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"validation\",\n\t\t\t\t\tsource: \"command\",\n\t\t\t\t\tissues: payloadResult.error.issues,\n\t\t\t\t\tmessage: `Invalid command payload: ${payloadResult.error.issues.map((i) => i.message).join(\", \")}`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tconst validatedCommand = { type: command.type, payload: payloadResult.data };\n\n\t\tconst stateName = workflow.state;\n\t\tconst singleRouter = this.singleStateBuilders.get(stateName);\n\t\tconst multiRouter = this.multiStateBuilders.get(stateName);\n\t\tconst singleHandler = singleRouter?.handlers.get(command.type);\n\t\tconst multiHandler = multiRouter?.handlers.get(command.type);\n\t\tconst wildcardHandler = this.wildcardHandlers.get(command.type);\n\n\t\tlet routeEntry: HandlerEntry | undefined;\n\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — matched router's state type is dynamic\n\t\tlet matchedRouter: StateBuilder<TConfig, TDeps, any> | undefined;\n\n\t\tif (singleHandler) {\n\t\t\trouteEntry = singleHandler;\n\t\t\tmatchedRouter = singleRouter;\n\t\t} else if (multiHandler) {\n\t\t\trouteEntry = multiHandler;\n\t\t\tmatchedRouter = multiRouter;\n\t\t} else if (wildcardHandler) {\n\t\t\trouteEntry = wildcardHandler;\n\t\t\tmatchedRouter = undefined;\n\t\t}\n\n\t\tif (!routeEntry) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"router\",\n\t\t\t\t\tcode: \"NO_HANDLER\",\n\t\t\t\t\tmessage: `No handler for command '${command.type}' in state '${stateName}'`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst stateMiddleware: AnyMiddleware[] = [];\n\t\tif (matchedRouter) {\n\t\t\tif (singleRouter) stateMiddleware.push(...singleRouter.middleware);\n\t\t\tif (multiRouter && multiRouter !== singleRouter)\n\t\t\t\tstateMiddleware.push(...multiRouter.middleware);\n\t\t}\n\n\t\tconst chain: AnyMiddleware[] = [\n\t\t\t...this.globalMiddleware,\n\t\t\t...stateMiddleware,\n\t\t\t...routeEntry.inlineMiddleware,\n\t\t\trouteEntry.handler,\n\t\t];\n\n\t\tconst ctx = createContext<TConfig, TDeps>(\n\t\t\tthis.definition,\n\t\t\tworkflow,\n\t\t\tvalidatedCommand,\n\t\t\tthis.deps,\n\t\t);\n\n\t\t// Hook: dispatch:start\n\t\tawait this.hookRegistry.emit(\"dispatch:start\", this.onHookError, ctx);\n\n\t\ttry {\n\t\t\tconst composed = compose(chain);\n\t\t\tawait composed(ctx);\n\t\t\tconst result: DispatchResult<TConfig> = {\n\t\t\t\tok: true as const,\n\t\t\t\tworkflow: ctx.getWorkflowSnapshot(),\n\t\t\t\tevents: [...ctx.events],\n\t\t\t};\n\n\t\t\t// Hook: transition (if state changed)\n\t\t\tif (result.ok && result.workflow.state !== workflow.state) {\n\t\t\t\tawait this.hookRegistry.emit(\n\t\t\t\t\t\"transition\",\n\t\t\t\t\tthis.onHookError,\n\t\t\t\t\tworkflow.state,\n\t\t\t\t\tresult.workflow.state,\n\t\t\t\t\tresult.workflow,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Hook: event (for each emitted event)\n\t\t\tif (result.ok) {\n\t\t\t\tfor (const event of result.events) {\n\t\t\t\t\tawait this.hookRegistry.emit(\"event\", this.onHookError, event, result.workflow);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Hook: dispatch:end\n\t\t\tawait this.hookRegistry.emit(\"dispatch:end\", this.onHookError, ctx, result);\n\n\t\t\treturn result;\n\t\t} catch (err) {\n\t\t\tlet result: DispatchResult<TConfig>;\n\t\t\tif (err instanceof DomainErrorSignal) {\n\t\t\t\tresult = {\n\t\t\t\t\tok: false as const,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcategory: \"domain\" as const,\n\t\t\t\t\t\tcode: err.code as ErrorCodes<TConfig>,\n\t\t\t\t\t\tdata: err.data as ErrorData<TConfig, ErrorCodes<TConfig>>,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} else if (err instanceof ValidationError) {\n\t\t\t\tresult = {\n\t\t\t\t\tok: false as const,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcategory: \"validation\" as const,\n\t\t\t\t\t\tsource: err.source,\n\t\t\t\t\t\tissues: err.issues,\n\t\t\t\t\t\tmessage: err.message,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tthrow err;\n\t\t\t}\n\n\t\t\t// Hook: error\n\t\t\tawait this.hookRegistry.emit(\"error\", this.onHookError, result.error, ctx);\n\n\t\t\t// Hook: dispatch:end\n\t\t\tawait this.hookRegistry.emit(\"dispatch:end\", this.onHookError, ctx, result);\n\n\t\t\treturn result;\n\t\t}\n\t}\n}\n"],"mappings":"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","names":[]}
|