@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.
- package/README.md +10 -4
- package/dist/chunk-YTJGSTKG.js +19 -0
- package/dist/chunk-YTJGSTKG.js.map +1 -0
- package/dist/chunk-ZFRIE42B.js +17 -0
- package/dist/chunk-ZFRIE42B.js.map +1 -0
- package/dist/executor/index.cjs +185 -0
- package/dist/executor/index.cjs.map +1 -0
- package/dist/executor/index.d.cts +69 -0
- package/dist/executor/index.d.ts +69 -0
- package/dist/executor/index.js +137 -0
- package/dist/executor/index.js.map +1 -0
- package/dist/index.cjs +142 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -397
- package/dist/index.d.ts +7 -397
- package/dist/index.js +142 -25
- package/dist/index.js.map +1 -1
- package/dist/plugin-DHN3Pk52.d.ts +339 -0
- package/dist/plugin-DHS8yUmS.d.cts +339 -0
- package/dist/reactor/index.cjs +69 -0
- package/dist/reactor/index.cjs.map +1 -0
- package/dist/reactor/index.d.cts +31 -0
- package/dist/reactor/index.d.ts +31 -0
- package/dist/reactor/index.js +41 -0
- package/dist/reactor/index.js.map +1 -0
- package/dist/snapshot-D5iZubCz.d.cts +165 -0
- package/dist/snapshot-D5iZubCz.d.ts +165 -0
- package/dist/store/index.cjs +68 -0
- package/dist/store/index.cjs.map +1 -0
- package/dist/store/index.d.cts +16 -0
- package/dist/store/index.d.ts +16 -0
- package/dist/store/index.js +31 -0
- package/dist/store/index.js.map +1 -0
- package/dist/types-BtMTMoOZ.d.cts +21 -0
- package/dist/types-C0nlrs5c.d.ts +21 -0
- package/package.json +23 -6
package/README.md
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/helico-tech/rytejs/master/docs/public/logo.svg" width="120" alt="Ryte" />
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<h1 align="center">@rytejs/core</h1>
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
<p align="center">Type-safe workflow engine with Zod validation and middleware pipelines.</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://github.com/helico-tech/rytejs/actions/workflows/ci.yml"><img src="https://github.com/helico-tech/rytejs/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/@rytejs/core"><img src="https://img.shields.io/npm/v/@rytejs/core" alt="npm" /></a>
|
|
12
|
+
</p>
|
|
7
13
|
|
|
8
14
|
## Why Ryte?
|
|
9
15
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/compose.ts
|
|
2
|
+
function compose(middleware) {
|
|
3
|
+
return async (ctx) => {
|
|
4
|
+
let index = -1;
|
|
5
|
+
async function dispatch(i) {
|
|
6
|
+
if (i <= index) throw new Error("next() called multiple times");
|
|
7
|
+
index = i;
|
|
8
|
+
const fn = middleware[i];
|
|
9
|
+
if (!fn) return;
|
|
10
|
+
await fn(ctx, () => dispatch(i + 1));
|
|
11
|
+
}
|
|
12
|
+
await dispatch(0);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
compose
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=chunk-YTJGSTKG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/compose.ts"],"sourcesContent":["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"],"mappings":";AAGO,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;","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/store/errors.ts
|
|
2
|
+
var ConcurrencyConflictError = class extends Error {
|
|
3
|
+
constructor(workflowId, expectedVersion, actualVersion) {
|
|
4
|
+
super(
|
|
5
|
+
`Concurrency conflict for workflow "${workflowId}": expected version ${expectedVersion}, actual ${actualVersion}`
|
|
6
|
+
);
|
|
7
|
+
this.workflowId = workflowId;
|
|
8
|
+
this.expectedVersion = expectedVersion;
|
|
9
|
+
this.actualVersion = actualVersion;
|
|
10
|
+
}
|
|
11
|
+
name = "ConcurrencyConflictError";
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
ConcurrencyConflictError
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=chunk-ZFRIE42B.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/store/errors.ts"],"sourcesContent":["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"],"mappings":";AAAO,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;","names":[]}
|
|
@@ -0,0 +1,185 @@
|
|
|
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/executor/index.ts
|
|
21
|
+
var executor_exports = {};
|
|
22
|
+
__export(executor_exports, {
|
|
23
|
+
WorkflowExecutor: () => WorkflowExecutor
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(executor_exports);
|
|
26
|
+
|
|
27
|
+
// src/compose.ts
|
|
28
|
+
function compose(middleware) {
|
|
29
|
+
return async (ctx) => {
|
|
30
|
+
let index = -1;
|
|
31
|
+
async function dispatch(i) {
|
|
32
|
+
if (i <= index) throw new Error("next() called multiple times");
|
|
33
|
+
index = i;
|
|
34
|
+
const fn = middleware[i];
|
|
35
|
+
if (!fn) return;
|
|
36
|
+
await fn(ctx, () => dispatch(i + 1));
|
|
37
|
+
}
|
|
38
|
+
await dispatch(0);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/store/errors.ts
|
|
43
|
+
var ConcurrencyConflictError = class extends Error {
|
|
44
|
+
constructor(workflowId, expectedVersion, actualVersion) {
|
|
45
|
+
super(
|
|
46
|
+
`Concurrency conflict for workflow "${workflowId}": expected version ${expectedVersion}, actual ${actualVersion}`
|
|
47
|
+
);
|
|
48
|
+
this.workflowId = workflowId;
|
|
49
|
+
this.expectedVersion = expectedVersion;
|
|
50
|
+
this.actualVersion = actualVersion;
|
|
51
|
+
}
|
|
52
|
+
name = "ConcurrencyConflictError";
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// src/executor/executor.ts
|
|
56
|
+
var WorkflowExecutor = class {
|
|
57
|
+
constructor(router, store) {
|
|
58
|
+
this.router = router;
|
|
59
|
+
this.store = store;
|
|
60
|
+
}
|
|
61
|
+
middleware = [];
|
|
62
|
+
use(middleware) {
|
|
63
|
+
this.middleware.push(middleware);
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
async execute(id, command, options) {
|
|
67
|
+
const stored = await this.store.load(id);
|
|
68
|
+
if (!stored) {
|
|
69
|
+
return { ok: false, error: { category: "not_found", id } };
|
|
70
|
+
}
|
|
71
|
+
if (options?.expectedVersion !== void 0 && options.expectedVersion !== stored.version) {
|
|
72
|
+
return {
|
|
73
|
+
ok: false,
|
|
74
|
+
error: {
|
|
75
|
+
category: "conflict",
|
|
76
|
+
id,
|
|
77
|
+
expectedVersion: options.expectedVersion,
|
|
78
|
+
actualVersion: stored.version
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const ctx = {
|
|
83
|
+
id,
|
|
84
|
+
command,
|
|
85
|
+
stored,
|
|
86
|
+
result: null,
|
|
87
|
+
snapshot: null,
|
|
88
|
+
events: []
|
|
89
|
+
};
|
|
90
|
+
try {
|
|
91
|
+
const chain = [...this.middleware, this.dispatchHandler()];
|
|
92
|
+
await compose(chain)(ctx);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
return {
|
|
95
|
+
ok: false,
|
|
96
|
+
error: {
|
|
97
|
+
category: "unexpected",
|
|
98
|
+
error: err,
|
|
99
|
+
message: err instanceof Error ? err.message : String(err)
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (ctx.snapshot) {
|
|
104
|
+
const newVersion = stored.version + 1;
|
|
105
|
+
const savedSnapshot = { ...ctx.snapshot, version: newVersion };
|
|
106
|
+
try {
|
|
107
|
+
await this.store.save({
|
|
108
|
+
id,
|
|
109
|
+
snapshot: ctx.snapshot,
|
|
110
|
+
expectedVersion: stored.version,
|
|
111
|
+
events: ctx.events
|
|
112
|
+
});
|
|
113
|
+
} catch (err) {
|
|
114
|
+
if (err instanceof ConcurrencyConflictError) {
|
|
115
|
+
return {
|
|
116
|
+
ok: false,
|
|
117
|
+
error: {
|
|
118
|
+
category: "conflict",
|
|
119
|
+
id,
|
|
120
|
+
expectedVersion: stored.version,
|
|
121
|
+
actualVersion: err.actualVersion
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
ok: false,
|
|
127
|
+
error: {
|
|
128
|
+
category: "unexpected",
|
|
129
|
+
error: err,
|
|
130
|
+
message: err instanceof Error ? err.message : String(err)
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
ok: true,
|
|
136
|
+
snapshot: savedSnapshot,
|
|
137
|
+
version: newVersion,
|
|
138
|
+
events: ctx.events
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
if (ctx.result && !ctx.result.ok) {
|
|
142
|
+
return { ok: false, error: ctx.result.error };
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
ok: false,
|
|
146
|
+
error: {
|
|
147
|
+
category: "unexpected",
|
|
148
|
+
error: new Error("Pipeline completed without setting snapshot or error"),
|
|
149
|
+
message: "Pipeline completed without setting snapshot or error"
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
dispatchHandler() {
|
|
154
|
+
const definition = this.router.definition;
|
|
155
|
+
const router = this.router;
|
|
156
|
+
return async (ctx, _next) => {
|
|
157
|
+
const restoreResult = definition.deserialize(ctx.stored.snapshot);
|
|
158
|
+
if (!restoreResult.ok) {
|
|
159
|
+
ctx.result = {
|
|
160
|
+
ok: false,
|
|
161
|
+
error: {
|
|
162
|
+
category: "restore",
|
|
163
|
+
id: ctx.id,
|
|
164
|
+
issues: restoreResult.error.issues
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const dispatchResult = await router.dispatch(restoreResult.workflow, ctx.command);
|
|
170
|
+
ctx.result = dispatchResult;
|
|
171
|
+
if (dispatchResult.ok) {
|
|
172
|
+
ctx.snapshot = definition.serialize(dispatchResult.workflow);
|
|
173
|
+
ctx.events = dispatchResult.events.map((e) => ({
|
|
174
|
+
type: e.type,
|
|
175
|
+
data: e.data
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
182
|
+
0 && (module.exports = {
|
|
183
|
+
WorkflowExecutor
|
|
184
|
+
});
|
|
185
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/executor/index.ts","../../src/compose.ts","../../src/store/errors.ts","../../src/executor/executor.ts"],"sourcesContent":["export { WorkflowExecutor } from \"./executor.js\";\nexport type {\n\tExecutionResult,\n\tExecutorContext,\n\tExecutorError,\n\tExecutorMiddleware,\n} from \"./types.js\";\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","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 { compose } from \"../compose.js\";\nimport type { WorkflowRouter } from \"../router.js\";\nimport type { WorkflowSnapshot } from \"../snapshot.js\";\nimport { ConcurrencyConflictError } from \"../store/errors.js\";\nimport type { StoreAdapter } from \"../store/types.js\";\nimport type { WorkflowConfig } from \"../types.js\";\nimport type { ExecutionResult, ExecutorContext, ExecutorMiddleware } from \"./types.js\";\n\nexport class WorkflowExecutor<TConfig extends WorkflowConfig> {\n\tprivate readonly middleware: ExecutorMiddleware[] = [];\n\n\tconstructor(\n\t\tpublic readonly router: WorkflowRouter<TConfig>,\n\t\tprivate readonly store: StoreAdapter,\n\t) {}\n\n\tuse(middleware: ExecutorMiddleware): this {\n\t\tthis.middleware.push(middleware);\n\t\treturn this;\n\t}\n\n\tasync execute(\n\t\tid: string,\n\t\tcommand: { type: string; payload: unknown },\n\t\toptions?: { expectedVersion?: number },\n\t): Promise<ExecutionResult> {\n\t\t// 1. Load\n\t\tconst stored = await this.store.load(id);\n\t\tif (!stored) {\n\t\t\treturn { ok: false, error: { category: \"not_found\", id } };\n\t\t}\n\n\t\t// 2. Optimistic version check\n\t\tif (options?.expectedVersion !== undefined && options.expectedVersion !== stored.version) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"conflict\",\n\t\t\t\t\tid,\n\t\t\t\t\texpectedVersion: options.expectedVersion,\n\t\t\t\t\tactualVersion: stored.version,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// 3. Build context\n\t\tconst ctx: ExecutorContext = {\n\t\t\tid,\n\t\t\tcommand,\n\t\t\tstored,\n\t\t\tresult: null,\n\t\t\tsnapshot: null,\n\t\t\tevents: [],\n\t\t};\n\n\t\t// 4. Run pipeline\n\t\ttry {\n\t\t\tconst chain = [...this.middleware, this.dispatchHandler()];\n\t\t\tawait compose(chain)(ctx);\n\t\t} catch (err) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"unexpected\",\n\t\t\t\t\terror: err,\n\t\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// 5. Save if dispatch succeeded\n\t\tif (ctx.snapshot) {\n\t\t\tconst newVersion = stored.version + 1;\n\t\t\tconst savedSnapshot = { ...ctx.snapshot, version: newVersion };\n\n\t\t\ttry {\n\t\t\t\tawait this.store.save({\n\t\t\t\t\tid,\n\t\t\t\t\tsnapshot: ctx.snapshot,\n\t\t\t\t\texpectedVersion: stored.version,\n\t\t\t\t\tevents: ctx.events,\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tif (err instanceof ConcurrencyConflictError) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: false,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcategory: \"conflict\",\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\texpectedVersion: stored.version,\n\t\t\t\t\t\t\tactualVersion: err.actualVersion,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcategory: \"unexpected\",\n\t\t\t\t\t\terror: err,\n\t\t\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tok: true,\n\t\t\t\tsnapshot: savedSnapshot,\n\t\t\t\tversion: newVersion,\n\t\t\t\tevents: ctx.events,\n\t\t\t};\n\t\t}\n\n\t\t// 6. Dispatch failed — return the error\n\t\tif (ctx.result && !ctx.result.ok) {\n\t\t\treturn { ok: false, error: ctx.result.error };\n\t\t}\n\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: {\n\t\t\t\tcategory: \"unexpected\",\n\t\t\t\terror: new Error(\"Pipeline completed without setting snapshot or error\"),\n\t\t\t\tmessage: \"Pipeline completed without setting snapshot or error\",\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate dispatchHandler(): ExecutorMiddleware {\n\t\tconst definition = this.router.definition;\n\t\tconst router = this.router;\n\n\t\treturn async (ctx, _next) => {\n\t\t\tconst restoreResult = definition.deserialize(ctx.stored.snapshot);\n\t\t\tif (!restoreResult.ok) {\n\t\t\t\tctx.result = {\n\t\t\t\t\tok: false as const,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcategory: \"restore\" as const,\n\t\t\t\t\t\tid: ctx.id,\n\t\t\t\t\t\tissues: restoreResult.error.issues,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// as never: type erasure — executor holds WorkflowConfig base type,\n\t\t\t// but dispatch validates commands against Zod schemas at runtime\n\t\t\tconst dispatchResult = await router.dispatch(restoreResult.workflow, ctx.command as never);\n\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — DispatchResult<TConfig> assigned to DispatchResult<WorkflowConfig>\n\t\t\tctx.result = dispatchResult as any;\n\n\t\t\tif (dispatchResult.ok) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — TConfig narrows WorkflowSnapshot but ctx.snapshot is unparameterized\n\t\t\t\tctx.snapshot = definition.serialize(dispatchResult.workflow) as any as WorkflowSnapshot;\n\t\t\t\tctx.events = (dispatchResult.events as Array<{ type: string; data: unknown }>).map((e) => ({\n\t\t\t\t\ttype: e.type,\n\t\t\t\t\tdata: e.data,\n\t\t\t\t}));\n\t\t\t}\n\t\t};\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { c as WorkflowRouter } from '../plugin-DHS8yUmS.cjs';
|
|
2
|
+
import { S as StoredWorkflow, a as StoreAdapter } from '../types-BtMTMoOZ.cjs';
|
|
3
|
+
import { a as WorkflowSnapshot, P as PipelineError, W as WorkflowConfig, D as DispatchResult } from '../snapshot-D5iZubCz.cjs';
|
|
4
|
+
import 'zod';
|
|
5
|
+
|
|
6
|
+
interface ExecutorContext {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly command: {
|
|
9
|
+
type: string;
|
|
10
|
+
payload: unknown;
|
|
11
|
+
};
|
|
12
|
+
readonly stored: StoredWorkflow;
|
|
13
|
+
result: DispatchResult<WorkflowConfig> | {
|
|
14
|
+
ok: false;
|
|
15
|
+
error: ExecutorError;
|
|
16
|
+
} | null;
|
|
17
|
+
snapshot: WorkflowSnapshot | null;
|
|
18
|
+
events: Array<{
|
|
19
|
+
type: string;
|
|
20
|
+
data: unknown;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
type ExecutorMiddleware = (ctx: ExecutorContext, next: () => Promise<void>) => Promise<void>;
|
|
24
|
+
type ExecutorError = {
|
|
25
|
+
category: "not_found";
|
|
26
|
+
id: string;
|
|
27
|
+
} | {
|
|
28
|
+
category: "conflict";
|
|
29
|
+
id: string;
|
|
30
|
+
expectedVersion: number;
|
|
31
|
+
actualVersion: number;
|
|
32
|
+
} | {
|
|
33
|
+
category: "restore";
|
|
34
|
+
id: string;
|
|
35
|
+
issues: unknown[];
|
|
36
|
+
} | {
|
|
37
|
+
category: "unexpected";
|
|
38
|
+
error: unknown;
|
|
39
|
+
message: string;
|
|
40
|
+
};
|
|
41
|
+
type ExecutionResult = {
|
|
42
|
+
ok: true;
|
|
43
|
+
snapshot: WorkflowSnapshot;
|
|
44
|
+
version: number;
|
|
45
|
+
events: Array<{
|
|
46
|
+
type: string;
|
|
47
|
+
data: unknown;
|
|
48
|
+
}>;
|
|
49
|
+
} | {
|
|
50
|
+
ok: false;
|
|
51
|
+
error: PipelineError<WorkflowConfig> | ExecutorError;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
declare class WorkflowExecutor<TConfig extends WorkflowConfig> {
|
|
55
|
+
readonly router: WorkflowRouter<TConfig>;
|
|
56
|
+
private readonly store;
|
|
57
|
+
private readonly middleware;
|
|
58
|
+
constructor(router: WorkflowRouter<TConfig>, store: StoreAdapter);
|
|
59
|
+
use(middleware: ExecutorMiddleware): this;
|
|
60
|
+
execute(id: string, command: {
|
|
61
|
+
type: string;
|
|
62
|
+
payload: unknown;
|
|
63
|
+
}, options?: {
|
|
64
|
+
expectedVersion?: number;
|
|
65
|
+
}): Promise<ExecutionResult>;
|
|
66
|
+
private dispatchHandler;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { type ExecutionResult, type ExecutorContext, type ExecutorError, type ExecutorMiddleware, WorkflowExecutor };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { c as WorkflowRouter } from '../plugin-DHN3Pk52.js';
|
|
2
|
+
import { S as StoredWorkflow, a as StoreAdapter } from '../types-C0nlrs5c.js';
|
|
3
|
+
import { a as WorkflowSnapshot, P as PipelineError, W as WorkflowConfig, D as DispatchResult } from '../snapshot-D5iZubCz.js';
|
|
4
|
+
import 'zod';
|
|
5
|
+
|
|
6
|
+
interface ExecutorContext {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly command: {
|
|
9
|
+
type: string;
|
|
10
|
+
payload: unknown;
|
|
11
|
+
};
|
|
12
|
+
readonly stored: StoredWorkflow;
|
|
13
|
+
result: DispatchResult<WorkflowConfig> | {
|
|
14
|
+
ok: false;
|
|
15
|
+
error: ExecutorError;
|
|
16
|
+
} | null;
|
|
17
|
+
snapshot: WorkflowSnapshot | null;
|
|
18
|
+
events: Array<{
|
|
19
|
+
type: string;
|
|
20
|
+
data: unknown;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
type ExecutorMiddleware = (ctx: ExecutorContext, next: () => Promise<void>) => Promise<void>;
|
|
24
|
+
type ExecutorError = {
|
|
25
|
+
category: "not_found";
|
|
26
|
+
id: string;
|
|
27
|
+
} | {
|
|
28
|
+
category: "conflict";
|
|
29
|
+
id: string;
|
|
30
|
+
expectedVersion: number;
|
|
31
|
+
actualVersion: number;
|
|
32
|
+
} | {
|
|
33
|
+
category: "restore";
|
|
34
|
+
id: string;
|
|
35
|
+
issues: unknown[];
|
|
36
|
+
} | {
|
|
37
|
+
category: "unexpected";
|
|
38
|
+
error: unknown;
|
|
39
|
+
message: string;
|
|
40
|
+
};
|
|
41
|
+
type ExecutionResult = {
|
|
42
|
+
ok: true;
|
|
43
|
+
snapshot: WorkflowSnapshot;
|
|
44
|
+
version: number;
|
|
45
|
+
events: Array<{
|
|
46
|
+
type: string;
|
|
47
|
+
data: unknown;
|
|
48
|
+
}>;
|
|
49
|
+
} | {
|
|
50
|
+
ok: false;
|
|
51
|
+
error: PipelineError<WorkflowConfig> | ExecutorError;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
declare class WorkflowExecutor<TConfig extends WorkflowConfig> {
|
|
55
|
+
readonly router: WorkflowRouter<TConfig>;
|
|
56
|
+
private readonly store;
|
|
57
|
+
private readonly middleware;
|
|
58
|
+
constructor(router: WorkflowRouter<TConfig>, store: StoreAdapter);
|
|
59
|
+
use(middleware: ExecutorMiddleware): this;
|
|
60
|
+
execute(id: string, command: {
|
|
61
|
+
type: string;
|
|
62
|
+
payload: unknown;
|
|
63
|
+
}, options?: {
|
|
64
|
+
expectedVersion?: number;
|
|
65
|
+
}): Promise<ExecutionResult>;
|
|
66
|
+
private dispatchHandler;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { type ExecutionResult, type ExecutorContext, type ExecutorError, type ExecutorMiddleware, WorkflowExecutor };
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
compose
|
|
3
|
+
} from "../chunk-YTJGSTKG.js";
|
|
4
|
+
import {
|
|
5
|
+
ConcurrencyConflictError
|
|
6
|
+
} from "../chunk-ZFRIE42B.js";
|
|
7
|
+
|
|
8
|
+
// src/executor/executor.ts
|
|
9
|
+
var WorkflowExecutor = class {
|
|
10
|
+
constructor(router, store) {
|
|
11
|
+
this.router = router;
|
|
12
|
+
this.store = store;
|
|
13
|
+
}
|
|
14
|
+
middleware = [];
|
|
15
|
+
use(middleware) {
|
|
16
|
+
this.middleware.push(middleware);
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
async execute(id, command, options) {
|
|
20
|
+
const stored = await this.store.load(id);
|
|
21
|
+
if (!stored) {
|
|
22
|
+
return { ok: false, error: { category: "not_found", id } };
|
|
23
|
+
}
|
|
24
|
+
if (options?.expectedVersion !== void 0 && options.expectedVersion !== stored.version) {
|
|
25
|
+
return {
|
|
26
|
+
ok: false,
|
|
27
|
+
error: {
|
|
28
|
+
category: "conflict",
|
|
29
|
+
id,
|
|
30
|
+
expectedVersion: options.expectedVersion,
|
|
31
|
+
actualVersion: stored.version
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const ctx = {
|
|
36
|
+
id,
|
|
37
|
+
command,
|
|
38
|
+
stored,
|
|
39
|
+
result: null,
|
|
40
|
+
snapshot: null,
|
|
41
|
+
events: []
|
|
42
|
+
};
|
|
43
|
+
try {
|
|
44
|
+
const chain = [...this.middleware, this.dispatchHandler()];
|
|
45
|
+
await compose(chain)(ctx);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
return {
|
|
48
|
+
ok: false,
|
|
49
|
+
error: {
|
|
50
|
+
category: "unexpected",
|
|
51
|
+
error: err,
|
|
52
|
+
message: err instanceof Error ? err.message : String(err)
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (ctx.snapshot) {
|
|
57
|
+
const newVersion = stored.version + 1;
|
|
58
|
+
const savedSnapshot = { ...ctx.snapshot, version: newVersion };
|
|
59
|
+
try {
|
|
60
|
+
await this.store.save({
|
|
61
|
+
id,
|
|
62
|
+
snapshot: ctx.snapshot,
|
|
63
|
+
expectedVersion: stored.version,
|
|
64
|
+
events: ctx.events
|
|
65
|
+
});
|
|
66
|
+
} catch (err) {
|
|
67
|
+
if (err instanceof ConcurrencyConflictError) {
|
|
68
|
+
return {
|
|
69
|
+
ok: false,
|
|
70
|
+
error: {
|
|
71
|
+
category: "conflict",
|
|
72
|
+
id,
|
|
73
|
+
expectedVersion: stored.version,
|
|
74
|
+
actualVersion: err.actualVersion
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
ok: false,
|
|
80
|
+
error: {
|
|
81
|
+
category: "unexpected",
|
|
82
|
+
error: err,
|
|
83
|
+
message: err instanceof Error ? err.message : String(err)
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
ok: true,
|
|
89
|
+
snapshot: savedSnapshot,
|
|
90
|
+
version: newVersion,
|
|
91
|
+
events: ctx.events
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (ctx.result && !ctx.result.ok) {
|
|
95
|
+
return { ok: false, error: ctx.result.error };
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
ok: false,
|
|
99
|
+
error: {
|
|
100
|
+
category: "unexpected",
|
|
101
|
+
error: new Error("Pipeline completed without setting snapshot or error"),
|
|
102
|
+
message: "Pipeline completed without setting snapshot or error"
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
dispatchHandler() {
|
|
107
|
+
const definition = this.router.definition;
|
|
108
|
+
const router = this.router;
|
|
109
|
+
return async (ctx, _next) => {
|
|
110
|
+
const restoreResult = definition.deserialize(ctx.stored.snapshot);
|
|
111
|
+
if (!restoreResult.ok) {
|
|
112
|
+
ctx.result = {
|
|
113
|
+
ok: false,
|
|
114
|
+
error: {
|
|
115
|
+
category: "restore",
|
|
116
|
+
id: ctx.id,
|
|
117
|
+
issues: restoreResult.error.issues
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const dispatchResult = await router.dispatch(restoreResult.workflow, ctx.command);
|
|
123
|
+
ctx.result = dispatchResult;
|
|
124
|
+
if (dispatchResult.ok) {
|
|
125
|
+
ctx.snapshot = definition.serialize(dispatchResult.workflow);
|
|
126
|
+
ctx.events = dispatchResult.events.map((e) => ({
|
|
127
|
+
type: e.type,
|
|
128
|
+
data: e.data
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
export {
|
|
135
|
+
WorkflowExecutor
|
|
136
|
+
};
|
|
137
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/executor/executor.ts"],"sourcesContent":["import { compose } from \"../compose.js\";\nimport type { WorkflowRouter } from \"../router.js\";\nimport type { WorkflowSnapshot } from \"../snapshot.js\";\nimport { ConcurrencyConflictError } from \"../store/errors.js\";\nimport type { StoreAdapter } from \"../store/types.js\";\nimport type { WorkflowConfig } from \"../types.js\";\nimport type { ExecutionResult, ExecutorContext, ExecutorMiddleware } from \"./types.js\";\n\nexport class WorkflowExecutor<TConfig extends WorkflowConfig> {\n\tprivate readonly middleware: ExecutorMiddleware[] = [];\n\n\tconstructor(\n\t\tpublic readonly router: WorkflowRouter<TConfig>,\n\t\tprivate readonly store: StoreAdapter,\n\t) {}\n\n\tuse(middleware: ExecutorMiddleware): this {\n\t\tthis.middleware.push(middleware);\n\t\treturn this;\n\t}\n\n\tasync execute(\n\t\tid: string,\n\t\tcommand: { type: string; payload: unknown },\n\t\toptions?: { expectedVersion?: number },\n\t): Promise<ExecutionResult> {\n\t\t// 1. Load\n\t\tconst stored = await this.store.load(id);\n\t\tif (!stored) {\n\t\t\treturn { ok: false, error: { category: \"not_found\", id } };\n\t\t}\n\n\t\t// 2. Optimistic version check\n\t\tif (options?.expectedVersion !== undefined && options.expectedVersion !== stored.version) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"conflict\",\n\t\t\t\t\tid,\n\t\t\t\t\texpectedVersion: options.expectedVersion,\n\t\t\t\t\tactualVersion: stored.version,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// 3. Build context\n\t\tconst ctx: ExecutorContext = {\n\t\t\tid,\n\t\t\tcommand,\n\t\t\tstored,\n\t\t\tresult: null,\n\t\t\tsnapshot: null,\n\t\t\tevents: [],\n\t\t};\n\n\t\t// 4. Run pipeline\n\t\ttry {\n\t\t\tconst chain = [...this.middleware, this.dispatchHandler()];\n\t\t\tawait compose(chain)(ctx);\n\t\t} catch (err) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"unexpected\",\n\t\t\t\t\terror: err,\n\t\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// 5. Save if dispatch succeeded\n\t\tif (ctx.snapshot) {\n\t\t\tconst newVersion = stored.version + 1;\n\t\t\tconst savedSnapshot = { ...ctx.snapshot, version: newVersion };\n\n\t\t\ttry {\n\t\t\t\tawait this.store.save({\n\t\t\t\t\tid,\n\t\t\t\t\tsnapshot: ctx.snapshot,\n\t\t\t\t\texpectedVersion: stored.version,\n\t\t\t\t\tevents: ctx.events,\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tif (err instanceof ConcurrencyConflictError) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: false,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcategory: \"conflict\",\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\texpectedVersion: stored.version,\n\t\t\t\t\t\t\tactualVersion: err.actualVersion,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcategory: \"unexpected\",\n\t\t\t\t\t\terror: err,\n\t\t\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tok: true,\n\t\t\t\tsnapshot: savedSnapshot,\n\t\t\t\tversion: newVersion,\n\t\t\t\tevents: ctx.events,\n\t\t\t};\n\t\t}\n\n\t\t// 6. Dispatch failed — return the error\n\t\tif (ctx.result && !ctx.result.ok) {\n\t\t\treturn { ok: false, error: ctx.result.error };\n\t\t}\n\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: {\n\t\t\t\tcategory: \"unexpected\",\n\t\t\t\terror: new Error(\"Pipeline completed without setting snapshot or error\"),\n\t\t\t\tmessage: \"Pipeline completed without setting snapshot or error\",\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate dispatchHandler(): ExecutorMiddleware {\n\t\tconst definition = this.router.definition;\n\t\tconst router = this.router;\n\n\t\treturn async (ctx, _next) => {\n\t\t\tconst restoreResult = definition.deserialize(ctx.stored.snapshot);\n\t\t\tif (!restoreResult.ok) {\n\t\t\t\tctx.result = {\n\t\t\t\t\tok: false as const,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcategory: \"restore\" as const,\n\t\t\t\t\t\tid: ctx.id,\n\t\t\t\t\t\tissues: restoreResult.error.issues,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// as never: type erasure — executor holds WorkflowConfig base type,\n\t\t\t// but dispatch validates commands against Zod schemas at runtime\n\t\t\tconst dispatchResult = await router.dispatch(restoreResult.workflow, ctx.command as never);\n\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — DispatchResult<TConfig> assigned to DispatchResult<WorkflowConfig>\n\t\t\tctx.result = dispatchResult as any;\n\n\t\t\tif (dispatchResult.ok) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type erasure — TConfig narrows WorkflowSnapshot but ctx.snapshot is unparameterized\n\t\t\t\tctx.snapshot = definition.serialize(dispatchResult.workflow) as any as WorkflowSnapshot;\n\t\t\t\tctx.events = (dispatchResult.events as Array<{ type: string; data: unknown }>).map((e) => ({\n\t\t\t\t\ttype: e.type,\n\t\t\t\t\tdata: e.data,\n\t\t\t\t}));\n\t\t\t}\n\t\t};\n\t}\n}\n"],"mappings":"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","names":[]}
|