@rytejs/core 0.5.0 → 0.7.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.
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/reactor/index.ts
21
+ var reactor_exports = {};
22
+ __export(reactor_exports, {
23
+ Reactors: () => Reactors,
24
+ createReactors: () => createReactors
25
+ });
26
+ module.exports = __toCommonJS(reactor_exports);
27
+
28
+ // src/reactor/reactors.ts
29
+ var Reactors = class {
30
+ registrations = [];
31
+ on(router, event, handler) {
32
+ this.registrations.push({
33
+ definitionName: router.definition.name,
34
+ eventType: event,
35
+ handler
36
+ });
37
+ return this;
38
+ }
39
+ resolve(router, workflowId, events) {
40
+ const definitionName = router.definition.name;
41
+ const commands = [];
42
+ for (const event of events) {
43
+ for (const reg of this.registrations) {
44
+ if (reg.definitionName !== definitionName) continue;
45
+ if (reg.eventType !== event.type) continue;
46
+ const result = reg.handler({
47
+ event: { type: event.type, data: event.data },
48
+ workflowId
49
+ });
50
+ if (result === null) continue;
51
+ if (Array.isArray(result)) {
52
+ commands.push(...result);
53
+ } else {
54
+ commands.push(result);
55
+ }
56
+ }
57
+ }
58
+ return commands;
59
+ }
60
+ };
61
+ function createReactors() {
62
+ return new Reactors();
63
+ }
64
+ // Annotate the CommonJS export names for ESM import in node:
65
+ 0 && (module.exports = {
66
+ Reactors,
67
+ createReactors
68
+ });
69
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/reactor/index.ts","../../src/reactor/reactors.ts"],"sourcesContent":["export { createReactors, Reactors } from \"./reactors.js\";\nexport type { ReactorCommand, ReactorContext } from \"./types.js\";\n","import type { WorkflowRouter } from \"../router.js\";\nimport type { EventNames, WorkflowConfig } from \"../types.js\";\nimport type { ReactorCommand, ReactorContext } from \"./types.js\";\n\ntype AnyHandler = (ctx: {\n\t// biome-ignore lint/suspicious/noExplicitAny: internal type erasure for heterogeneous handler storage\n\tevent: { type: string; data: any };\n\tworkflowId: string;\n}) => ReactorCommand | ReactorCommand[] | null;\n\ninterface Registration {\n\tdefinitionName: string;\n\teventType: string;\n\thandler: AnyHandler;\n}\n\nexport class Reactors {\n\tprivate readonly registrations: Registration[] = [];\n\n\ton<TConfig extends WorkflowConfig, TEvent extends EventNames<TConfig>>(\n\t\trouter: WorkflowRouter<TConfig>,\n\t\tevent: TEvent,\n\t\thandler: (ctx: ReactorContext<TConfig, TEvent>) => ReactorCommand | ReactorCommand[] | null,\n\t): this {\n\t\tthis.registrations.push({\n\t\t\tdefinitionName: router.definition.name,\n\t\t\teventType: event as string,\n\t\t\thandler: handler as AnyHandler,\n\t\t});\n\t\treturn this;\n\t}\n\n\tresolve(\n\t\t// biome-ignore lint/suspicious/noExplicitAny: accepts any router for type-erased resolution\n\t\trouter: WorkflowRouter<any>,\n\t\tworkflowId: string,\n\t\tevents: Array<{ type: string; data: unknown }>,\n\t): ReactorCommand[] {\n\t\tconst definitionName = router.definition.name;\n\t\tconst commands: ReactorCommand[] = [];\n\n\t\tfor (const event of events) {\n\t\t\tfor (const reg of this.registrations) {\n\t\t\t\tif (reg.definitionName !== definitionName) continue;\n\t\t\t\tif (reg.eventType !== event.type) continue;\n\n\t\t\t\tconst result = reg.handler({\n\t\t\t\t\tevent: { type: event.type, data: event.data },\n\t\t\t\t\tworkflowId,\n\t\t\t\t});\n\n\t\t\t\tif (result === null) continue;\n\t\t\t\tif (Array.isArray(result)) {\n\t\t\t\t\tcommands.push(...result);\n\t\t\t\t} else {\n\t\t\t\t\tcommands.push(result);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn commands;\n\t}\n}\n\nexport function createReactors(): Reactors {\n\treturn new Reactors();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACgBO,IAAM,WAAN,MAAe;AAAA,EACJ,gBAAgC,CAAC;AAAA,EAElD,GACC,QACA,OACA,SACO;AACP,SAAK,cAAc,KAAK;AAAA,MACvB,gBAAgB,OAAO,WAAW;AAAA,MAClC,WAAW;AAAA,MACX;AAAA,IACD,CAAC;AACD,WAAO;AAAA,EACR;AAAA,EAEA,QAEC,QACA,YACA,QACmB;AACnB,UAAM,iBAAiB,OAAO,WAAW;AACzC,UAAM,WAA6B,CAAC;AAEpC,eAAW,SAAS,QAAQ;AAC3B,iBAAW,OAAO,KAAK,eAAe;AACrC,YAAI,IAAI,mBAAmB,eAAgB;AAC3C,YAAI,IAAI,cAAc,MAAM,KAAM;AAElC,cAAM,SAAS,IAAI,QAAQ;AAAA,UAC1B,OAAO,EAAE,MAAM,MAAM,MAAM,MAAM,MAAM,KAAK;AAAA,UAC5C;AAAA,QACD,CAAC;AAED,YAAI,WAAW,KAAM;AACrB,YAAI,MAAM,QAAQ,MAAM,GAAG;AAC1B,mBAAS,KAAK,GAAG,MAAM;AAAA,QACxB,OAAO;AACN,mBAAS,KAAK,MAAM;AAAA,QACrB;AAAA,MACD;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AACD;AAEO,SAAS,iBAA2B;AAC1C,SAAO,IAAI,SAAS;AACrB;","names":[]}
@@ -0,0 +1,31 @@
1
+ import { c as WorkflowRouter } from '../plugin-DHS8yUmS.cjs';
2
+ import { W as WorkflowConfig, g as EventNames, f as EventData } from '../snapshot-D5iZubCz.cjs';
3
+ import 'zod';
4
+
5
+ interface ReactorCommand {
6
+ workflowId: string;
7
+ routerName: string;
8
+ command: {
9
+ type: string;
10
+ payload: unknown;
11
+ };
12
+ }
13
+ interface ReactorContext<TConfig extends WorkflowConfig, TEvent extends EventNames<TConfig>> {
14
+ event: {
15
+ type: TEvent;
16
+ data: EventData<TConfig, TEvent>;
17
+ };
18
+ workflowId: string;
19
+ }
20
+
21
+ declare class Reactors {
22
+ private readonly registrations;
23
+ on<TConfig extends WorkflowConfig, TEvent extends EventNames<TConfig>>(router: WorkflowRouter<TConfig>, event: TEvent, handler: (ctx: ReactorContext<TConfig, TEvent>) => ReactorCommand | ReactorCommand[] | null): this;
24
+ resolve(router: WorkflowRouter<any>, workflowId: string, events: Array<{
25
+ type: string;
26
+ data: unknown;
27
+ }>): ReactorCommand[];
28
+ }
29
+ declare function createReactors(): Reactors;
30
+
31
+ export { type ReactorCommand, type ReactorContext, Reactors, createReactors };
@@ -0,0 +1,31 @@
1
+ import { c as WorkflowRouter } from '../plugin-DHN3Pk52.js';
2
+ import { W as WorkflowConfig, g as EventNames, f as EventData } from '../snapshot-D5iZubCz.js';
3
+ import 'zod';
4
+
5
+ interface ReactorCommand {
6
+ workflowId: string;
7
+ routerName: string;
8
+ command: {
9
+ type: string;
10
+ payload: unknown;
11
+ };
12
+ }
13
+ interface ReactorContext<TConfig extends WorkflowConfig, TEvent extends EventNames<TConfig>> {
14
+ event: {
15
+ type: TEvent;
16
+ data: EventData<TConfig, TEvent>;
17
+ };
18
+ workflowId: string;
19
+ }
20
+
21
+ declare class Reactors {
22
+ private readonly registrations;
23
+ on<TConfig extends WorkflowConfig, TEvent extends EventNames<TConfig>>(router: WorkflowRouter<TConfig>, event: TEvent, handler: (ctx: ReactorContext<TConfig, TEvent>) => ReactorCommand | ReactorCommand[] | null): this;
24
+ resolve(router: WorkflowRouter<any>, workflowId: string, events: Array<{
25
+ type: string;
26
+ data: unknown;
27
+ }>): ReactorCommand[];
28
+ }
29
+ declare function createReactors(): Reactors;
30
+
31
+ export { type ReactorCommand, type ReactorContext, Reactors, createReactors };
@@ -0,0 +1,41 @@
1
+ // src/reactor/reactors.ts
2
+ var Reactors = class {
3
+ registrations = [];
4
+ on(router, event, handler) {
5
+ this.registrations.push({
6
+ definitionName: router.definition.name,
7
+ eventType: event,
8
+ handler
9
+ });
10
+ return this;
11
+ }
12
+ resolve(router, workflowId, events) {
13
+ const definitionName = router.definition.name;
14
+ const commands = [];
15
+ for (const event of events) {
16
+ for (const reg of this.registrations) {
17
+ if (reg.definitionName !== definitionName) continue;
18
+ if (reg.eventType !== event.type) continue;
19
+ const result = reg.handler({
20
+ event: { type: event.type, data: event.data },
21
+ workflowId
22
+ });
23
+ if (result === null) continue;
24
+ if (Array.isArray(result)) {
25
+ commands.push(...result);
26
+ } else {
27
+ commands.push(result);
28
+ }
29
+ }
30
+ }
31
+ return commands;
32
+ }
33
+ };
34
+ function createReactors() {
35
+ return new Reactors();
36
+ }
37
+ export {
38
+ Reactors,
39
+ createReactors
40
+ };
41
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/reactor/reactors.ts"],"sourcesContent":["import type { WorkflowRouter } from \"../router.js\";\nimport type { EventNames, WorkflowConfig } from \"../types.js\";\nimport type { ReactorCommand, ReactorContext } from \"./types.js\";\n\ntype AnyHandler = (ctx: {\n\t// biome-ignore lint/suspicious/noExplicitAny: internal type erasure for heterogeneous handler storage\n\tevent: { type: string; data: any };\n\tworkflowId: string;\n}) => ReactorCommand | ReactorCommand[] | null;\n\ninterface Registration {\n\tdefinitionName: string;\n\teventType: string;\n\thandler: AnyHandler;\n}\n\nexport class Reactors {\n\tprivate readonly registrations: Registration[] = [];\n\n\ton<TConfig extends WorkflowConfig, TEvent extends EventNames<TConfig>>(\n\t\trouter: WorkflowRouter<TConfig>,\n\t\tevent: TEvent,\n\t\thandler: (ctx: ReactorContext<TConfig, TEvent>) => ReactorCommand | ReactorCommand[] | null,\n\t): this {\n\t\tthis.registrations.push({\n\t\t\tdefinitionName: router.definition.name,\n\t\t\teventType: event as string,\n\t\t\thandler: handler as AnyHandler,\n\t\t});\n\t\treturn this;\n\t}\n\n\tresolve(\n\t\t// biome-ignore lint/suspicious/noExplicitAny: accepts any router for type-erased resolution\n\t\trouter: WorkflowRouter<any>,\n\t\tworkflowId: string,\n\t\tevents: Array<{ type: string; data: unknown }>,\n\t): ReactorCommand[] {\n\t\tconst definitionName = router.definition.name;\n\t\tconst commands: ReactorCommand[] = [];\n\n\t\tfor (const event of events) {\n\t\t\tfor (const reg of this.registrations) {\n\t\t\t\tif (reg.definitionName !== definitionName) continue;\n\t\t\t\tif (reg.eventType !== event.type) continue;\n\n\t\t\t\tconst result = reg.handler({\n\t\t\t\t\tevent: { type: event.type, data: event.data },\n\t\t\t\t\tworkflowId,\n\t\t\t\t});\n\n\t\t\t\tif (result === null) continue;\n\t\t\t\tif (Array.isArray(result)) {\n\t\t\t\t\tcommands.push(...result);\n\t\t\t\t} else {\n\t\t\t\t\tcommands.push(result);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn commands;\n\t}\n}\n\nexport function createReactors(): Reactors {\n\treturn new Reactors();\n}\n"],"mappings":";AAgBO,IAAM,WAAN,MAAe;AAAA,EACJ,gBAAgC,CAAC;AAAA,EAElD,GACC,QACA,OACA,SACO;AACP,SAAK,cAAc,KAAK;AAAA,MACvB,gBAAgB,OAAO,WAAW;AAAA,MAClC,WAAW;AAAA,MACX;AAAA,IACD,CAAC;AACD,WAAO;AAAA,EACR;AAAA,EAEA,QAEC,QACA,YACA,QACmB;AACnB,UAAM,iBAAiB,OAAO,WAAW;AACzC,UAAM,WAA6B,CAAC;AAEpC,eAAW,SAAS,QAAQ;AAC3B,iBAAW,OAAO,KAAK,eAAe;AACrC,YAAI,IAAI,mBAAmB,eAAgB;AAC3C,YAAI,IAAI,cAAc,MAAM,KAAM;AAElC,cAAM,SAAS,IAAI,QAAQ;AAAA,UAC1B,OAAO,EAAE,MAAM,MAAM,MAAM,MAAM,MAAM,KAAK;AAAA,UAC5C;AAAA,QACD,CAAC;AAED,YAAI,WAAW,KAAM;AACrB,YAAI,MAAM,QAAQ,MAAM,GAAG;AAC1B,mBAAS,KAAK,GAAG,MAAM;AAAA,QACxB,OAAO;AACN,mBAAS,KAAK,MAAM;AAAA,QACrB;AAAA,MACD;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AACD;AAEO,SAAS,iBAA2B;AAC1C,SAAO,IAAI,SAAS;AACrB;","names":[]}
@@ -0,0 +1,165 @@
1
+ import { ZodType, z } from 'zod';
2
+
3
+ /**
4
+ * Shape of the configuration object passed to {@link defineWorkflow}.
5
+ * Exported for internal package use only — not re-exported from index.ts.
6
+ */
7
+ interface WorkflowConfigInput {
8
+ /** Optional version number for schema migrations. Defaults to 1. */
9
+ modelVersion?: number;
10
+ /** Record of state names to Zod schemas defining their data shape. */
11
+ states: Record<string, ZodType>;
12
+ /** Record of command names to Zod schemas defining their payload shape. */
13
+ commands: Record<string, ZodType>;
14
+ /** Record of event names to Zod schemas defining their data shape. */
15
+ events: Record<string, ZodType>;
16
+ /** Record of error codes to Zod schemas defining their data shape. */
17
+ errors: Record<string, ZodType>;
18
+ }
19
+ /**
20
+ * Workflow configuration with pre-resolved types for IDE completion.
21
+ *
22
+ * Extends {@link WorkflowConfigInput} with a `_resolved` phantom type that
23
+ * caches `z.infer` results. This exists because Zod v4's `z.infer` uses
24
+ * conditional types that TypeScript defers in deep generic chains, breaking
25
+ * IDE autocomplete. The `_resolved` property is never set at runtime — it is
26
+ * populated at the type level by {@link defineWorkflow}'s return type.
27
+ */
28
+ interface WorkflowConfig extends WorkflowConfigInput {
29
+ _resolved: {
30
+ states: Record<string, unknown>;
31
+ commands: Record<string, unknown>;
32
+ events: Record<string, unknown>;
33
+ errors: Record<string, unknown>;
34
+ };
35
+ }
36
+ type StateNames<T extends WorkflowConfig> = keyof T["states"] & string;
37
+ type CommandNames<T extends WorkflowConfig> = keyof T["commands"] & string;
38
+ type EventNames<T extends WorkflowConfig> = keyof T["events"] & string;
39
+ type ErrorCodes<T extends WorkflowConfig> = keyof T["errors"] & string;
40
+ /** Forces TypeScript to flatten a type for better IDE autocomplete. */
41
+ type Prettify<T> = {
42
+ [K in keyof T]: T[K];
43
+ } & {};
44
+ /** Resolves the data type for a given state from pre-computed types. */
45
+ type StateData<T extends WorkflowConfig, S extends StateNames<T>> = Prettify<T["_resolved"]["states"][S]>;
46
+ /** Resolves the payload type for a given command from pre-computed types. */
47
+ type CommandPayload<T extends WorkflowConfig, C extends CommandNames<T>> = Prettify<T["_resolved"]["commands"][C]>;
48
+ /** Resolves the data type for a given event from pre-computed types. */
49
+ type EventData<T extends WorkflowConfig, E extends EventNames<T>> = Prettify<T["_resolved"]["events"][E]>;
50
+ /** Resolves the data type for a given error code from pre-computed types. */
51
+ type ErrorData<T extends WorkflowConfig, C extends ErrorCodes<T>> = Prettify<T["_resolved"]["errors"][C]>;
52
+ /** Workflow narrowed to a specific known state. */
53
+ interface WorkflowOf<TConfig extends WorkflowConfig, S extends StateNames<TConfig>> {
54
+ /** Unique workflow instance identifier. */
55
+ readonly id: string;
56
+ /** Name of the workflow definition this instance belongs to. */
57
+ readonly definitionName: string;
58
+ /** Current state name. */
59
+ readonly state: S;
60
+ /** State data, typed according to the state's Zod schema. */
61
+ readonly data: StateData<TConfig, S>;
62
+ /** Timestamp of workflow creation. */
63
+ readonly createdAt: Date;
64
+ /** Timestamp of last state change. */
65
+ readonly updatedAt: Date;
66
+ }
67
+ /** Discriminated union of all possible workflow states — checking .state narrows .data. */
68
+ type Workflow<TConfig extends WorkflowConfig = WorkflowConfig> = {
69
+ [S in StateNames<TConfig>]: WorkflowOf<TConfig, S>;
70
+ }[StateNames<TConfig>];
71
+ /** Discriminated union of all pipeline error types on `category`. */
72
+ type PipelineError<TConfig extends WorkflowConfig = WorkflowConfig> = {
73
+ category: "validation";
74
+ source: "command" | "state" | "event" | "transition" | "restore";
75
+ issues: z.core.$ZodIssue[];
76
+ message: string;
77
+ } | {
78
+ category: "domain";
79
+ code: ErrorCodes<TConfig>;
80
+ data: ErrorData<TConfig, ErrorCodes<TConfig>>;
81
+ } | {
82
+ category: "router";
83
+ code: "NO_HANDLER" | "UNKNOWN_STATE";
84
+ message: string;
85
+ } | {
86
+ category: "unexpected";
87
+ error: unknown;
88
+ message: string;
89
+ } | {
90
+ category: "dependency";
91
+ name: string;
92
+ error: unknown;
93
+ message: string;
94
+ };
95
+ /** Return type of {@link WorkflowRouter.dispatch}. Discriminated union on `ok`. */
96
+ type DispatchResult<TConfig extends WorkflowConfig = WorkflowConfig> = {
97
+ ok: true;
98
+ workflow: Workflow<TConfig>;
99
+ events: Array<{
100
+ type: EventNames<TConfig>;
101
+ data: unknown;
102
+ }>;
103
+ } | {
104
+ ok: false;
105
+ error: PipelineError<TConfig>;
106
+ };
107
+ /**
108
+ * Thrown internally when Zod validation fails during dispatch.
109
+ * Caught by the router and returned as a validation error in {@link DispatchResult}.
110
+ *
111
+ * @param source - Which validation stage failed
112
+ * @param issues - Array of Zod validation issues
113
+ */
114
+ declare class ValidationError extends Error {
115
+ readonly source: "command" | "state" | "event" | "transition" | "restore";
116
+ readonly issues: z.core.$ZodIssue[];
117
+ constructor(source: "command" | "state" | "event" | "transition" | "restore", issues: z.core.$ZodIssue[]);
118
+ }
119
+ /**
120
+ * Thrown internally when a handler calls `ctx.error()`.
121
+ * Caught by the router and returned as a domain error in {@link DispatchResult}.
122
+ *
123
+ * @param code - The error code string
124
+ * @param data - The error data payload
125
+ */
126
+ declare class DomainErrorSignal extends Error {
127
+ readonly code: string;
128
+ readonly data: unknown;
129
+ constructor(code: string, data: unknown);
130
+ }
131
+ /**
132
+ * Thrown internally when a proxied dependency call fails.
133
+ * Caught by the router and returned as a dependency error in {@link DispatchResult}.
134
+ *
135
+ * @param depName - The top-level dependency key (e.g. "db", "stripe")
136
+ * @param error - The original error thrown by the dependency
137
+ */
138
+ /** Extracts the WorkflowConfig type from a WorkflowRouter instance. */
139
+ type ConfigOf<R> = R extends {
140
+ definition: {
141
+ config: infer C;
142
+ };
143
+ } ? C : never;
144
+
145
+ /** A plain, JSON-safe representation of a workflow's state for serialization and storage. */
146
+ interface WorkflowSnapshot<TConfig extends WorkflowConfig = WorkflowConfig> {
147
+ /** Unique workflow instance identifier. */
148
+ readonly id: string;
149
+ /** Name of the workflow definition. */
150
+ readonly definitionName: string;
151
+ /** Current state name. */
152
+ readonly state: StateNames<TConfig>;
153
+ /** State data (untyped — validated on {@link WorkflowDefinition.deserialize}). */
154
+ readonly data: unknown;
155
+ /** ISO 8601 timestamp of workflow creation. */
156
+ readonly createdAt: string;
157
+ /** ISO 8601 timestamp of last state change. */
158
+ readonly updatedAt: string;
159
+ /** Schema version number for migration support. */
160
+ readonly modelVersion: number;
161
+ /** Optimistic concurrency version. Starts at 1, increments on each successful save. */
162
+ readonly version: number;
163
+ }
164
+
165
+ export { type CommandNames as C, type DispatchResult as D, type ErrorCodes as E, type PipelineError as P, type StateNames as S, ValidationError as V, type WorkflowConfig as W, type WorkflowSnapshot as a, type CommandPayload as b, type ConfigOf as c, DomainErrorSignal as d, type ErrorData as e, type EventData as f, type EventNames as g, type StateData as h, type Workflow as i, type WorkflowOf as j, type WorkflowConfigInput as k };
@@ -0,0 +1,165 @@
1
+ import { ZodType, z } from 'zod';
2
+
3
+ /**
4
+ * Shape of the configuration object passed to {@link defineWorkflow}.
5
+ * Exported for internal package use only — not re-exported from index.ts.
6
+ */
7
+ interface WorkflowConfigInput {
8
+ /** Optional version number for schema migrations. Defaults to 1. */
9
+ modelVersion?: number;
10
+ /** Record of state names to Zod schemas defining their data shape. */
11
+ states: Record<string, ZodType>;
12
+ /** Record of command names to Zod schemas defining their payload shape. */
13
+ commands: Record<string, ZodType>;
14
+ /** Record of event names to Zod schemas defining their data shape. */
15
+ events: Record<string, ZodType>;
16
+ /** Record of error codes to Zod schemas defining their data shape. */
17
+ errors: Record<string, ZodType>;
18
+ }
19
+ /**
20
+ * Workflow configuration with pre-resolved types for IDE completion.
21
+ *
22
+ * Extends {@link WorkflowConfigInput} with a `_resolved` phantom type that
23
+ * caches `z.infer` results. This exists because Zod v4's `z.infer` uses
24
+ * conditional types that TypeScript defers in deep generic chains, breaking
25
+ * IDE autocomplete. The `_resolved` property is never set at runtime — it is
26
+ * populated at the type level by {@link defineWorkflow}'s return type.
27
+ */
28
+ interface WorkflowConfig extends WorkflowConfigInput {
29
+ _resolved: {
30
+ states: Record<string, unknown>;
31
+ commands: Record<string, unknown>;
32
+ events: Record<string, unknown>;
33
+ errors: Record<string, unknown>;
34
+ };
35
+ }
36
+ type StateNames<T extends WorkflowConfig> = keyof T["states"] & string;
37
+ type CommandNames<T extends WorkflowConfig> = keyof T["commands"] & string;
38
+ type EventNames<T extends WorkflowConfig> = keyof T["events"] & string;
39
+ type ErrorCodes<T extends WorkflowConfig> = keyof T["errors"] & string;
40
+ /** Forces TypeScript to flatten a type for better IDE autocomplete. */
41
+ type Prettify<T> = {
42
+ [K in keyof T]: T[K];
43
+ } & {};
44
+ /** Resolves the data type for a given state from pre-computed types. */
45
+ type StateData<T extends WorkflowConfig, S extends StateNames<T>> = Prettify<T["_resolved"]["states"][S]>;
46
+ /** Resolves the payload type for a given command from pre-computed types. */
47
+ type CommandPayload<T extends WorkflowConfig, C extends CommandNames<T>> = Prettify<T["_resolved"]["commands"][C]>;
48
+ /** Resolves the data type for a given event from pre-computed types. */
49
+ type EventData<T extends WorkflowConfig, E extends EventNames<T>> = Prettify<T["_resolved"]["events"][E]>;
50
+ /** Resolves the data type for a given error code from pre-computed types. */
51
+ type ErrorData<T extends WorkflowConfig, C extends ErrorCodes<T>> = Prettify<T["_resolved"]["errors"][C]>;
52
+ /** Workflow narrowed to a specific known state. */
53
+ interface WorkflowOf<TConfig extends WorkflowConfig, S extends StateNames<TConfig>> {
54
+ /** Unique workflow instance identifier. */
55
+ readonly id: string;
56
+ /** Name of the workflow definition this instance belongs to. */
57
+ readonly definitionName: string;
58
+ /** Current state name. */
59
+ readonly state: S;
60
+ /** State data, typed according to the state's Zod schema. */
61
+ readonly data: StateData<TConfig, S>;
62
+ /** Timestamp of workflow creation. */
63
+ readonly createdAt: Date;
64
+ /** Timestamp of last state change. */
65
+ readonly updatedAt: Date;
66
+ }
67
+ /** Discriminated union of all possible workflow states — checking .state narrows .data. */
68
+ type Workflow<TConfig extends WorkflowConfig = WorkflowConfig> = {
69
+ [S in StateNames<TConfig>]: WorkflowOf<TConfig, S>;
70
+ }[StateNames<TConfig>];
71
+ /** Discriminated union of all pipeline error types on `category`. */
72
+ type PipelineError<TConfig extends WorkflowConfig = WorkflowConfig> = {
73
+ category: "validation";
74
+ source: "command" | "state" | "event" | "transition" | "restore";
75
+ issues: z.core.$ZodIssue[];
76
+ message: string;
77
+ } | {
78
+ category: "domain";
79
+ code: ErrorCodes<TConfig>;
80
+ data: ErrorData<TConfig, ErrorCodes<TConfig>>;
81
+ } | {
82
+ category: "router";
83
+ code: "NO_HANDLER" | "UNKNOWN_STATE";
84
+ message: string;
85
+ } | {
86
+ category: "unexpected";
87
+ error: unknown;
88
+ message: string;
89
+ } | {
90
+ category: "dependency";
91
+ name: string;
92
+ error: unknown;
93
+ message: string;
94
+ };
95
+ /** Return type of {@link WorkflowRouter.dispatch}. Discriminated union on `ok`. */
96
+ type DispatchResult<TConfig extends WorkflowConfig = WorkflowConfig> = {
97
+ ok: true;
98
+ workflow: Workflow<TConfig>;
99
+ events: Array<{
100
+ type: EventNames<TConfig>;
101
+ data: unknown;
102
+ }>;
103
+ } | {
104
+ ok: false;
105
+ error: PipelineError<TConfig>;
106
+ };
107
+ /**
108
+ * Thrown internally when Zod validation fails during dispatch.
109
+ * Caught by the router and returned as a validation error in {@link DispatchResult}.
110
+ *
111
+ * @param source - Which validation stage failed
112
+ * @param issues - Array of Zod validation issues
113
+ */
114
+ declare class ValidationError extends Error {
115
+ readonly source: "command" | "state" | "event" | "transition" | "restore";
116
+ readonly issues: z.core.$ZodIssue[];
117
+ constructor(source: "command" | "state" | "event" | "transition" | "restore", issues: z.core.$ZodIssue[]);
118
+ }
119
+ /**
120
+ * Thrown internally when a handler calls `ctx.error()`.
121
+ * Caught by the router and returned as a domain error in {@link DispatchResult}.
122
+ *
123
+ * @param code - The error code string
124
+ * @param data - The error data payload
125
+ */
126
+ declare class DomainErrorSignal extends Error {
127
+ readonly code: string;
128
+ readonly data: unknown;
129
+ constructor(code: string, data: unknown);
130
+ }
131
+ /**
132
+ * Thrown internally when a proxied dependency call fails.
133
+ * Caught by the router and returned as a dependency error in {@link DispatchResult}.
134
+ *
135
+ * @param depName - The top-level dependency key (e.g. "db", "stripe")
136
+ * @param error - The original error thrown by the dependency
137
+ */
138
+ /** Extracts the WorkflowConfig type from a WorkflowRouter instance. */
139
+ type ConfigOf<R> = R extends {
140
+ definition: {
141
+ config: infer C;
142
+ };
143
+ } ? C : never;
144
+
145
+ /** A plain, JSON-safe representation of a workflow's state for serialization and storage. */
146
+ interface WorkflowSnapshot<TConfig extends WorkflowConfig = WorkflowConfig> {
147
+ /** Unique workflow instance identifier. */
148
+ readonly id: string;
149
+ /** Name of the workflow definition. */
150
+ readonly definitionName: string;
151
+ /** Current state name. */
152
+ readonly state: StateNames<TConfig>;
153
+ /** State data (untyped — validated on {@link WorkflowDefinition.deserialize}). */
154
+ readonly data: unknown;
155
+ /** ISO 8601 timestamp of workflow creation. */
156
+ readonly createdAt: string;
157
+ /** ISO 8601 timestamp of last state change. */
158
+ readonly updatedAt: string;
159
+ /** Schema version number for migration support. */
160
+ readonly modelVersion: number;
161
+ /** Optimistic concurrency version. Starts at 1, increments on each successful save. */
162
+ readonly version: number;
163
+ }
164
+
165
+ export { type CommandNames as C, type DispatchResult as D, type ErrorCodes as E, type PipelineError as P, type StateNames as S, ValidationError as V, type WorkflowConfig as W, type WorkflowSnapshot as a, type CommandPayload as b, type ConfigOf as c, DomainErrorSignal as d, type ErrorData as e, type EventData as f, type EventNames as g, type StateData as h, type Workflow as i, type WorkflowOf as j, type WorkflowConfigInput as k };
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/store/index.ts
21
+ var store_exports = {};
22
+ __export(store_exports, {
23
+ ConcurrencyConflictError: () => ConcurrencyConflictError,
24
+ memoryStore: () => memoryStore
25
+ });
26
+ module.exports = __toCommonJS(store_exports);
27
+
28
+ // src/store/errors.ts
29
+ var ConcurrencyConflictError = class extends Error {
30
+ constructor(workflowId, expectedVersion, actualVersion) {
31
+ super(
32
+ `Concurrency conflict for workflow "${workflowId}": expected version ${expectedVersion}, actual ${actualVersion}`
33
+ );
34
+ this.workflowId = workflowId;
35
+ this.expectedVersion = expectedVersion;
36
+ this.actualVersion = actualVersion;
37
+ }
38
+ name = "ConcurrencyConflictError";
39
+ };
40
+
41
+ // src/store/memory-store.ts
42
+ function memoryStore() {
43
+ const data = /* @__PURE__ */ new Map();
44
+ return {
45
+ async load(id) {
46
+ return data.get(id) ?? null;
47
+ },
48
+ async save(options) {
49
+ const { id, snapshot, expectedVersion } = options;
50
+ const existing = data.get(id);
51
+ const currentVersion = existing?.version ?? 0;
52
+ if (currentVersion !== expectedVersion) {
53
+ throw new ConcurrencyConflictError(id, expectedVersion, currentVersion);
54
+ }
55
+ const newVersion = currentVersion + 1;
56
+ data.set(id, {
57
+ snapshot: { ...snapshot, version: newVersion },
58
+ version: newVersion
59
+ });
60
+ }
61
+ };
62
+ }
63
+ // Annotate the CommonJS export names for ESM import in node:
64
+ 0 && (module.exports = {
65
+ ConcurrencyConflictError,
66
+ memoryStore
67
+ });
68
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/store/index.ts","../../src/store/errors.ts","../../src/store/memory-store.ts"],"sourcesContent":["export { ConcurrencyConflictError } from \"./errors.js\";\nexport { memoryStore } from \"./memory-store.js\";\nexport type {\n\tSaveOptions,\n\tStoreAdapter,\n\tStoredWorkflow,\n} from \"./types.js\";\n","export class ConcurrencyConflictError extends Error {\n\treadonly name = \"ConcurrencyConflictError\";\n\n\tconstructor(\n\t\treadonly workflowId: string,\n\t\treadonly expectedVersion: number,\n\t\treadonly actualVersion: number,\n\t) {\n\t\tsuper(\n\t\t\t`Concurrency conflict for workflow \"${workflowId}\": expected version ${expectedVersion}, actual ${actualVersion}`,\n\t\t);\n\t}\n}\n","import { ConcurrencyConflictError } from \"./errors.js\";\nimport type { SaveOptions, StoreAdapter, StoredWorkflow } from \"./types.js\";\n\nexport function memoryStore(): StoreAdapter {\n\tconst data = new Map<string, StoredWorkflow>();\n\n\treturn {\n\t\tasync load(id) {\n\t\t\treturn data.get(id) ?? null;\n\t\t},\n\n\t\tasync save(options: SaveOptions) {\n\t\t\tconst { id, snapshot, expectedVersion } = options;\n\t\t\tconst existing = data.get(id);\n\t\t\tconst currentVersion = existing?.version ?? 0;\n\n\t\t\tif (currentVersion !== expectedVersion) {\n\t\t\t\tthrow new ConcurrencyConflictError(id, expectedVersion, currentVersion);\n\t\t\t}\n\n\t\t\tconst newVersion = currentVersion + 1;\n\t\t\tdata.set(id, {\n\t\t\t\tsnapshot: { ...snapshot, version: newVersion },\n\t\t\t\tversion: newVersion,\n\t\t\t});\n\t\t},\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,2BAAN,cAAuC,MAAM;AAAA,EAGnD,YACU,YACA,iBACA,eACR;AACD;AAAA,MACC,sCAAsC,UAAU,uBAAuB,eAAe,YAAY,aAAa;AAAA,IAChH;AANS;AACA;AACA;AAAA,EAKV;AAAA,EAVS,OAAO;AAWjB;;;ACTO,SAAS,cAA4B;AAC3C,QAAM,OAAO,oBAAI,IAA4B;AAE7C,SAAO;AAAA,IACN,MAAM,KAAK,IAAI;AACd,aAAO,KAAK,IAAI,EAAE,KAAK;AAAA,IACxB;AAAA,IAEA,MAAM,KAAK,SAAsB;AAChC,YAAM,EAAE,IAAI,UAAU,gBAAgB,IAAI;AAC1C,YAAM,WAAW,KAAK,IAAI,EAAE;AAC5B,YAAM,iBAAiB,UAAU,WAAW;AAE5C,UAAI,mBAAmB,iBAAiB;AACvC,cAAM,IAAI,yBAAyB,IAAI,iBAAiB,cAAc;AAAA,MACvE;AAEA,YAAM,aAAa,iBAAiB;AACpC,WAAK,IAAI,IAAI;AAAA,QACZ,UAAU,EAAE,GAAG,UAAU,SAAS,WAAW;AAAA,QAC7C,SAAS;AAAA,MACV,CAAC;AAAA,IACF;AAAA,EACD;AACD;","names":[]}
@@ -0,0 +1,16 @@
1
+ import { a as StoreAdapter } from '../types-BtMTMoOZ.cjs';
2
+ export { b as SaveOptions, S as StoredWorkflow } from '../types-BtMTMoOZ.cjs';
3
+ import '../snapshot-D5iZubCz.cjs';
4
+ import 'zod';
5
+
6
+ declare class ConcurrencyConflictError extends Error {
7
+ readonly workflowId: string;
8
+ readonly expectedVersion: number;
9
+ readonly actualVersion: number;
10
+ readonly name = "ConcurrencyConflictError";
11
+ constructor(workflowId: string, expectedVersion: number, actualVersion: number);
12
+ }
13
+
14
+ declare function memoryStore(): StoreAdapter;
15
+
16
+ export { ConcurrencyConflictError, StoreAdapter, memoryStore };
@@ -0,0 +1,16 @@
1
+ import { a as StoreAdapter } from '../types-C0nlrs5c.js';
2
+ export { b as SaveOptions, S as StoredWorkflow } from '../types-C0nlrs5c.js';
3
+ import '../snapshot-D5iZubCz.js';
4
+ import 'zod';
5
+
6
+ declare class ConcurrencyConflictError extends Error {
7
+ readonly workflowId: string;
8
+ readonly expectedVersion: number;
9
+ readonly actualVersion: number;
10
+ readonly name = "ConcurrencyConflictError";
11
+ constructor(workflowId: string, expectedVersion: number, actualVersion: number);
12
+ }
13
+
14
+ declare function memoryStore(): StoreAdapter;
15
+
16
+ export { ConcurrencyConflictError, StoreAdapter, memoryStore };
@@ -0,0 +1,31 @@
1
+ import {
2
+ ConcurrencyConflictError
3
+ } from "../chunk-ZFRIE42B.js";
4
+
5
+ // src/store/memory-store.ts
6
+ function memoryStore() {
7
+ const data = /* @__PURE__ */ new Map();
8
+ return {
9
+ async load(id) {
10
+ return data.get(id) ?? null;
11
+ },
12
+ async save(options) {
13
+ const { id, snapshot, expectedVersion } = options;
14
+ const existing = data.get(id);
15
+ const currentVersion = existing?.version ?? 0;
16
+ if (currentVersion !== expectedVersion) {
17
+ throw new ConcurrencyConflictError(id, expectedVersion, currentVersion);
18
+ }
19
+ const newVersion = currentVersion + 1;
20
+ data.set(id, {
21
+ snapshot: { ...snapshot, version: newVersion },
22
+ version: newVersion
23
+ });
24
+ }
25
+ };
26
+ }
27
+ export {
28
+ ConcurrencyConflictError,
29
+ memoryStore
30
+ };
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/store/memory-store.ts"],"sourcesContent":["import { ConcurrencyConflictError } from \"./errors.js\";\nimport type { SaveOptions, StoreAdapter, StoredWorkflow } from \"./types.js\";\n\nexport function memoryStore(): StoreAdapter {\n\tconst data = new Map<string, StoredWorkflow>();\n\n\treturn {\n\t\tasync load(id) {\n\t\t\treturn data.get(id) ?? null;\n\t\t},\n\n\t\tasync save(options: SaveOptions) {\n\t\t\tconst { id, snapshot, expectedVersion } = options;\n\t\t\tconst existing = data.get(id);\n\t\t\tconst currentVersion = existing?.version ?? 0;\n\n\t\t\tif (currentVersion !== expectedVersion) {\n\t\t\t\tthrow new ConcurrencyConflictError(id, expectedVersion, currentVersion);\n\t\t\t}\n\n\t\t\tconst newVersion = currentVersion + 1;\n\t\t\tdata.set(id, {\n\t\t\t\tsnapshot: { ...snapshot, version: newVersion },\n\t\t\t\tversion: newVersion,\n\t\t\t});\n\t\t},\n\t};\n}\n"],"mappings":";;;;;AAGO,SAAS,cAA4B;AAC3C,QAAM,OAAO,oBAAI,IAA4B;AAE7C,SAAO;AAAA,IACN,MAAM,KAAK,IAAI;AACd,aAAO,KAAK,IAAI,EAAE,KAAK;AAAA,IACxB;AAAA,IAEA,MAAM,KAAK,SAAsB;AAChC,YAAM,EAAE,IAAI,UAAU,gBAAgB,IAAI;AAC1C,YAAM,WAAW,KAAK,IAAI,EAAE;AAC5B,YAAM,iBAAiB,UAAU,WAAW;AAE5C,UAAI,mBAAmB,iBAAiB;AACvC,cAAM,IAAI,yBAAyB,IAAI,iBAAiB,cAAc;AAAA,MACvE;AAEA,YAAM,aAAa,iBAAiB;AACpC,WAAK,IAAI,IAAI;AAAA,QACZ,UAAU,EAAE,GAAG,UAAU,SAAS,WAAW;AAAA,QAC7C,SAAS;AAAA,MACV,CAAC;AAAA,IACF;AAAA,EACD;AACD;","names":[]}