@rivetkit/workflow-engine 2.1.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +203 -0
- package/dist/schemas/v1.ts +781 -0
- package/dist/tsup/chunk-GJ66YE5W.cjs +3441 -0
- package/dist/tsup/chunk-GJ66YE5W.cjs.map +1 -0
- package/dist/tsup/chunk-JWHWQBZP.js +3441 -0
- package/dist/tsup/chunk-JWHWQBZP.js.map +1 -0
- package/dist/tsup/index.cjs +93 -0
- package/dist/tsup/index.cjs.map +1 -0
- package/dist/tsup/index.d.cts +884 -0
- package/dist/tsup/index.d.ts +884 -0
- package/dist/tsup/index.js +93 -0
- package/dist/tsup/index.js.map +1 -0
- package/dist/tsup/testing.cjs +316 -0
- package/dist/tsup/testing.cjs.map +1 -0
- package/dist/tsup/testing.d.cts +52 -0
- package/dist/tsup/testing.d.ts +52 -0
- package/dist/tsup/testing.js +316 -0
- package/dist/tsup/testing.js.map +1 -0
- package/package.json +70 -0
- package/schemas/serde.ts +609 -0
- package/schemas/v1.bare +203 -0
- package/schemas/versioned.ts +107 -0
- package/src/context.ts +1845 -0
- package/src/driver.ts +103 -0
- package/src/errors.ts +170 -0
- package/src/index.ts +907 -0
- package/src/keys.ts +277 -0
- package/src/location.ts +168 -0
- package/src/storage.ts +364 -0
- package/src/testing.ts +292 -0
- package/src/types.ts +508 -0
- package/src/utils.ts +48 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CancelledError,
|
|
3
|
+
CriticalError,
|
|
4
|
+
DEFAULT_LOOP_COMMIT_INTERVAL,
|
|
5
|
+
DEFAULT_LOOP_HISTORY_EVERY,
|
|
6
|
+
DEFAULT_LOOP_HISTORY_KEEP,
|
|
7
|
+
DEFAULT_MAX_RETRIES,
|
|
8
|
+
DEFAULT_RETRY_BACKOFF_BASE,
|
|
9
|
+
DEFAULT_RETRY_BACKOFF_MAX,
|
|
10
|
+
DEFAULT_STEP_TIMEOUT,
|
|
11
|
+
EntryInProgressError,
|
|
12
|
+
EvictedError,
|
|
13
|
+
HistoryDivergedError,
|
|
14
|
+
JoinError,
|
|
15
|
+
Loop,
|
|
16
|
+
MessageWaitError,
|
|
17
|
+
RaceError,
|
|
18
|
+
RollbackCheckpointError,
|
|
19
|
+
RollbackError,
|
|
20
|
+
SleepError,
|
|
21
|
+
StepExhaustedError,
|
|
22
|
+
StepFailedError,
|
|
23
|
+
WorkflowContextImpl,
|
|
24
|
+
appendLoopIteration,
|
|
25
|
+
appendName,
|
|
26
|
+
compareKeys,
|
|
27
|
+
createEntry,
|
|
28
|
+
createHistorySnapshot,
|
|
29
|
+
createStorage,
|
|
30
|
+
deleteEntriesWithPrefix,
|
|
31
|
+
emptyLocation,
|
|
32
|
+
flush,
|
|
33
|
+
generateId,
|
|
34
|
+
getEntry,
|
|
35
|
+
getOrCreateMetadata,
|
|
36
|
+
isLocationPrefix,
|
|
37
|
+
isLoopIterationMarker,
|
|
38
|
+
keyStartsWith,
|
|
39
|
+
keyToHex,
|
|
40
|
+
loadMetadata,
|
|
41
|
+
loadStorage,
|
|
42
|
+
locationToKey,
|
|
43
|
+
locationsEqual,
|
|
44
|
+
parentLocation,
|
|
45
|
+
registerName,
|
|
46
|
+
resolveName,
|
|
47
|
+
runWorkflow,
|
|
48
|
+
setEntry,
|
|
49
|
+
sleep
|
|
50
|
+
} from "./chunk-JWHWQBZP.js";
|
|
51
|
+
|
|
52
|
+
// src/testing.ts
|
|
53
|
+
var InMemoryWorkflowMessageDriver = class {
|
|
54
|
+
#messages = [];
|
|
55
|
+
#waiters = /* @__PURE__ */ new Set();
|
|
56
|
+
async addMessage(message) {
|
|
57
|
+
this.#messages.push(message);
|
|
58
|
+
this.#notifyWaiters(message.name);
|
|
59
|
+
}
|
|
60
|
+
async receiveMessages(opts) {
|
|
61
|
+
const limitedCount = Math.max(1, opts.count);
|
|
62
|
+
const nameSet = opts.names && opts.names.length > 0 ? new Set(opts.names) : void 0;
|
|
63
|
+
const selected = [];
|
|
64
|
+
for (let i = 0; i < this.#messages.length && selected.length < limitedCount; i++) {
|
|
65
|
+
const message = this.#messages[i];
|
|
66
|
+
if (nameSet && !nameSet.has(message.name)) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
selected.push({ message, index: i });
|
|
70
|
+
}
|
|
71
|
+
if (selected.length === 0) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
if (!opts.completable) {
|
|
75
|
+
for (let i = selected.length - 1; i >= 0; i--) {
|
|
76
|
+
this.#messages.splice(selected[i].index, 1);
|
|
77
|
+
}
|
|
78
|
+
return selected.map((entry) => entry.message);
|
|
79
|
+
}
|
|
80
|
+
return selected.map((entry) => {
|
|
81
|
+
const { message } = entry;
|
|
82
|
+
return {
|
|
83
|
+
...message,
|
|
84
|
+
complete: async () => {
|
|
85
|
+
await this.completeMessage(message.id);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
async completeMessage(messageId) {
|
|
91
|
+
const index = this.#messages.findIndex((message) => message.id === messageId);
|
|
92
|
+
if (index !== -1) {
|
|
93
|
+
this.#messages.splice(index, 1);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async waitForMessages(messageNames, abortSignal) {
|
|
97
|
+
if (abortSignal.aborted) {
|
|
98
|
+
throw new EvictedError();
|
|
99
|
+
}
|
|
100
|
+
const nameSet = messageNames.length > 0 ? new Set(messageNames) : void 0;
|
|
101
|
+
if (this.#messages.some(
|
|
102
|
+
(message) => nameSet ? nameSet.has(message.name) : true
|
|
103
|
+
)) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
await new Promise((resolve, reject) => {
|
|
107
|
+
const waiter = {
|
|
108
|
+
nameSet,
|
|
109
|
+
resolve: () => {
|
|
110
|
+
this.#removeWaiter(waiter);
|
|
111
|
+
resolve();
|
|
112
|
+
},
|
|
113
|
+
reject: (error) => {
|
|
114
|
+
this.#removeWaiter(waiter);
|
|
115
|
+
reject(error);
|
|
116
|
+
},
|
|
117
|
+
abortSignal,
|
|
118
|
+
onAbort: () => {
|
|
119
|
+
waiter.reject(new EvictedError());
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
abortSignal.addEventListener("abort", waiter.onAbort, { once: true });
|
|
123
|
+
this.#waiters.add(waiter);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
#removeWaiter(waiter) {
|
|
127
|
+
if (this.#waiters.delete(waiter)) {
|
|
128
|
+
waiter.abortSignal.removeEventListener("abort", waiter.onAbort);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
#notifyWaiters(name) {
|
|
132
|
+
for (const waiter of [...this.#waiters]) {
|
|
133
|
+
if (waiter.nameSet && !waiter.nameSet.has(name)) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
waiter.resolve();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
clear() {
|
|
140
|
+
this.#messages = [];
|
|
141
|
+
for (const waiter of [...this.#waiters]) {
|
|
142
|
+
waiter.reject(new Error("cleared"));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
var InMemoryDriver = class {
|
|
147
|
+
// Map from hex-encoded key to { originalKey, value }
|
|
148
|
+
kv = /* @__PURE__ */ new Map();
|
|
149
|
+
alarms = /* @__PURE__ */ new Map();
|
|
150
|
+
#inMemoryMessageDriver = new InMemoryWorkflowMessageDriver();
|
|
151
|
+
/** Simulated latency per operation (ms) */
|
|
152
|
+
latency = 10;
|
|
153
|
+
/** How often the worker polls for work */
|
|
154
|
+
workerPollInterval = 100;
|
|
155
|
+
messageDriver = this.#inMemoryMessageDriver;
|
|
156
|
+
async get(key) {
|
|
157
|
+
await sleep(this.latency);
|
|
158
|
+
const entry = this.kv.get(keyToHex(key));
|
|
159
|
+
return (entry == null ? void 0 : entry.value) ?? null;
|
|
160
|
+
}
|
|
161
|
+
async set(key, value) {
|
|
162
|
+
await sleep(this.latency);
|
|
163
|
+
this.kv.set(keyToHex(key), { key, value });
|
|
164
|
+
}
|
|
165
|
+
async delete(key) {
|
|
166
|
+
await sleep(this.latency);
|
|
167
|
+
this.kv.delete(keyToHex(key));
|
|
168
|
+
}
|
|
169
|
+
async deletePrefix(prefix) {
|
|
170
|
+
await sleep(this.latency);
|
|
171
|
+
for (const [hexKey, entry] of this.kv) {
|
|
172
|
+
if (keyStartsWith(entry.key, prefix)) {
|
|
173
|
+
this.kv.delete(hexKey);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async list(prefix) {
|
|
178
|
+
await sleep(this.latency);
|
|
179
|
+
const results = [];
|
|
180
|
+
for (const entry of this.kv.values()) {
|
|
181
|
+
if (keyStartsWith(entry.key, prefix)) {
|
|
182
|
+
results.push({ key: entry.key, value: entry.value });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return results.sort((a, b) => compareKeys(a.key, b.key));
|
|
186
|
+
}
|
|
187
|
+
async batch(writes) {
|
|
188
|
+
await sleep(this.latency);
|
|
189
|
+
for (const { key, value } of writes) {
|
|
190
|
+
this.kv.set(keyToHex(key), { key, value });
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async setAlarm(workflowId, wakeAt) {
|
|
194
|
+
await sleep(this.latency);
|
|
195
|
+
this.alarms.set(workflowId, wakeAt);
|
|
196
|
+
}
|
|
197
|
+
async clearAlarm(workflowId) {
|
|
198
|
+
await sleep(this.latency);
|
|
199
|
+
this.alarms.delete(workflowId);
|
|
200
|
+
}
|
|
201
|
+
async waitForMessages(messageNames, abortSignal) {
|
|
202
|
+
const driver = this.messageDriver;
|
|
203
|
+
if (driver.waitForMessages) {
|
|
204
|
+
await driver.waitForMessages(messageNames, abortSignal);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
while (true) {
|
|
208
|
+
if (abortSignal.aborted) {
|
|
209
|
+
throw new EvictedError();
|
|
210
|
+
}
|
|
211
|
+
const messages = await this.messageDriver.receiveMessages({
|
|
212
|
+
names: messageNames.length > 0 ? messageNames : void 0,
|
|
213
|
+
count: 1,
|
|
214
|
+
completable: true
|
|
215
|
+
});
|
|
216
|
+
if (messages.length > 0) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
await sleep(Math.max(1, this.latency));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Get the alarm time for a workflow (for testing).
|
|
224
|
+
*/
|
|
225
|
+
getAlarm(workflowId) {
|
|
226
|
+
return this.alarms.get(workflowId);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Check if any alarms are due and return their workflow IDs.
|
|
230
|
+
*/
|
|
231
|
+
getDueAlarms() {
|
|
232
|
+
const now = Date.now();
|
|
233
|
+
const due = [];
|
|
234
|
+
for (const [workflowId, wakeAt] of this.alarms) {
|
|
235
|
+
if (wakeAt <= now) {
|
|
236
|
+
due.push(workflowId);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return due;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Clear all data (for testing).
|
|
243
|
+
*/
|
|
244
|
+
clear() {
|
|
245
|
+
this.kv.clear();
|
|
246
|
+
this.alarms.clear();
|
|
247
|
+
this.#inMemoryMessageDriver.clear();
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Get a snapshot of all data (for testing/debugging).
|
|
251
|
+
*/
|
|
252
|
+
snapshot() {
|
|
253
|
+
const kvSnapshot = {};
|
|
254
|
+
for (const [hexKey, entry] of this.kv) {
|
|
255
|
+
kvSnapshot[hexKey] = entry.value;
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
kv: kvSnapshot,
|
|
259
|
+
alarms: Object.fromEntries(this.alarms)
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Get all hex-encoded keys (for testing).
|
|
264
|
+
*/
|
|
265
|
+
keys() {
|
|
266
|
+
return [...this.kv.keys()];
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
export {
|
|
270
|
+
CancelledError,
|
|
271
|
+
CriticalError,
|
|
272
|
+
DEFAULT_LOOP_COMMIT_INTERVAL,
|
|
273
|
+
DEFAULT_LOOP_HISTORY_EVERY,
|
|
274
|
+
DEFAULT_LOOP_HISTORY_KEEP,
|
|
275
|
+
DEFAULT_MAX_RETRIES,
|
|
276
|
+
DEFAULT_RETRY_BACKOFF_BASE,
|
|
277
|
+
DEFAULT_RETRY_BACKOFF_MAX,
|
|
278
|
+
DEFAULT_STEP_TIMEOUT,
|
|
279
|
+
EntryInProgressError,
|
|
280
|
+
EvictedError,
|
|
281
|
+
HistoryDivergedError,
|
|
282
|
+
InMemoryDriver,
|
|
283
|
+
JoinError,
|
|
284
|
+
Loop,
|
|
285
|
+
MessageWaitError,
|
|
286
|
+
RaceError,
|
|
287
|
+
RollbackCheckpointError,
|
|
288
|
+
RollbackError,
|
|
289
|
+
SleepError,
|
|
290
|
+
StepExhaustedError,
|
|
291
|
+
StepFailedError,
|
|
292
|
+
WorkflowContextImpl,
|
|
293
|
+
appendLoopIteration,
|
|
294
|
+
appendName,
|
|
295
|
+
createEntry,
|
|
296
|
+
createHistorySnapshot,
|
|
297
|
+
createStorage,
|
|
298
|
+
deleteEntriesWithPrefix,
|
|
299
|
+
emptyLocation,
|
|
300
|
+
flush,
|
|
301
|
+
generateId,
|
|
302
|
+
getEntry,
|
|
303
|
+
getOrCreateMetadata,
|
|
304
|
+
isLocationPrefix,
|
|
305
|
+
isLoopIterationMarker,
|
|
306
|
+
loadMetadata,
|
|
307
|
+
loadStorage,
|
|
308
|
+
locationToKey,
|
|
309
|
+
locationsEqual,
|
|
310
|
+
parentLocation,
|
|
311
|
+
registerName,
|
|
312
|
+
resolveName,
|
|
313
|
+
runWorkflow,
|
|
314
|
+
setEntry
|
|
315
|
+
};
|
|
316
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/testing.ts"],"sourcesContent":["import type { EngineDriver, KVEntry, KVWrite } from \"./driver.js\";\nimport { EvictedError } from \"./errors.js\";\nimport { compareKeys, keyStartsWith, keyToHex } from \"./keys.js\";\nimport type { Message, WorkflowMessageDriver } from \"./types.js\";\nimport { sleep } from \"./utils.js\";\n\ninterface Waiter {\n\tnameSet?: Set<string>;\n\tresolve: () => void;\n\treject: (error: Error) => void;\n\tabortSignal: AbortSignal;\n\tonAbort: () => void;\n}\n\nclass InMemoryWorkflowMessageDriver implements WorkflowMessageDriver {\n\t#messages: Message[] = [];\n\t#waiters = new Set<Waiter>();\n\n\tasync addMessage(message: Message): Promise<void> {\n\t\tthis.#messages.push(message);\n\t\tthis.#notifyWaiters(message.name);\n\t}\n\n\tasync receiveMessages(opts: {\n\t\tnames?: readonly string[];\n\t\tcount: number;\n\t\tcompletable: boolean;\n\t}): Promise<Message[]> {\n\t\tconst limitedCount = Math.max(1, opts.count);\n\t\tconst nameSet =\n\t\t\topts.names && opts.names.length > 0\n\t\t\t\t? new Set(opts.names)\n\t\t\t\t: undefined;\n\t\tconst selected: Array<{ message: Message; index: number }> = [];\n\n\t\tfor (let i = 0; i < this.#messages.length && selected.length < limitedCount; i++) {\n\t\t\tconst message = this.#messages[i];\n\t\t\tif (nameSet && !nameSet.has(message.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tselected.push({ message, index: i });\n\t\t}\n\n\t\tif (selected.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif (!opts.completable) {\n\t\t\tfor (let i = selected.length - 1; i >= 0; i--) {\n\t\t\t\tthis.#messages.splice(selected[i].index, 1);\n\t\t\t}\n\t\t\treturn selected.map((entry) => entry.message);\n\t\t}\n\n\t\treturn selected.map((entry) => {\n\t\t\tconst { message } = entry;\n\t\t\treturn {\n\t\t\t\t...message,\n\t\t\t\tcomplete: async () => {\n\t\t\t\t\tawait this.completeMessage(message.id);\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\t}\n\n\tasync completeMessage(messageId: string): Promise<void> {\n\t\tconst index = this.#messages.findIndex((message) => message.id === messageId);\n\t\tif (index !== -1) {\n\t\t\tthis.#messages.splice(index, 1);\n\t\t}\n\t}\n\n\tasync waitForMessages(\n\t\tmessageNames: string[],\n\t\tabortSignal: AbortSignal,\n\t): Promise<void> {\n\t\tif (abortSignal.aborted) {\n\t\t\tthrow new EvictedError();\n\t\t}\n\n\t\tconst nameSet = messageNames.length > 0 ? new Set(messageNames) : undefined;\n\t\tif (\n\t\t\tthis.#messages.some((message) =>\n\t\t\t\tnameSet ? nameSet.has(message.name) : true,\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst waiter: Waiter = {\n\t\t\t\tnameSet,\n\t\t\t\tresolve: () => {\n\t\t\t\t\tthis.#removeWaiter(waiter);\n\t\t\t\t\tresolve();\n\t\t\t\t},\n\t\t\t\treject: (error) => {\n\t\t\t\t\tthis.#removeWaiter(waiter);\n\t\t\t\t\treject(error);\n\t\t\t\t},\n\t\t\t\tabortSignal,\n\t\t\t\tonAbort: () => {\n\t\t\t\t\twaiter.reject(new EvictedError());\n\t\t\t\t},\n\t\t\t};\n\t\t\tabortSignal.addEventListener(\"abort\", waiter.onAbort, { once: true });\n\t\t\tthis.#waiters.add(waiter);\n\t\t});\n\t}\n\n\t#removeWaiter(waiter: Waiter): void {\n\t\tif (this.#waiters.delete(waiter)) {\n\t\t\twaiter.abortSignal.removeEventListener(\"abort\", waiter.onAbort);\n\t\t}\n\t}\n\n\t#notifyWaiters(name: string): void {\n\t\tfor (const waiter of [...this.#waiters]) {\n\t\t\tif (waiter.nameSet && !waiter.nameSet.has(name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\twaiter.resolve();\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis.#messages = [];\n\t\tfor (const waiter of [...this.#waiters]) {\n\t\t\twaiter.reject(new Error(\"cleared\"));\n\t\t}\n\t}\n}\n\n/**\n * In-memory implementation of EngineDriver for testing.\n * Uses binary keys (Uint8Array) with hex encoding for internal Map storage.\n */\nexport class InMemoryDriver implements EngineDriver {\n\t// Map from hex-encoded key to { originalKey, value }\n\tprivate kv = new Map<string, { key: Uint8Array; value: Uint8Array }>();\n\tprivate alarms = new Map<string, number>();\n\t#inMemoryMessageDriver = new InMemoryWorkflowMessageDriver();\n\n\t/** Simulated latency per operation (ms) */\n\tlatency = 10;\n\n\t/** How often the worker polls for work */\n\tworkerPollInterval = 100;\n\tmessageDriver: WorkflowMessageDriver = this.#inMemoryMessageDriver;\n\n\tasync get(key: Uint8Array): Promise<Uint8Array | null> {\n\t\tawait sleep(this.latency);\n\t\tconst entry = this.kv.get(keyToHex(key));\n\t\treturn entry?.value ?? null;\n\t}\n\n\tasync set(key: Uint8Array, value: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.kv.set(keyToHex(key), { key, value });\n\t}\n\n\tasync delete(key: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.kv.delete(keyToHex(key));\n\t}\n\n\tasync deletePrefix(prefix: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tif (keyStartsWith(entry.key, prefix)) {\n\t\t\t\tthis.kv.delete(hexKey);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync list(prefix: Uint8Array): Promise<KVEntry[]> {\n\t\tawait sleep(this.latency);\n\t\tconst results: KVEntry[] = [];\n\t\tfor (const entry of this.kv.values()) {\n\t\t\tif (keyStartsWith(entry.key, prefix)) {\n\t\t\t\tresults.push({ key: entry.key, value: entry.value });\n\t\t\t}\n\t\t}\n\t\t// Sort by key lexicographically\n\t\treturn results.sort((a, b) => compareKeys(a.key, b.key));\n\t}\n\n\tasync batch(writes: KVWrite[]): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const { key, value } of writes) {\n\t\t\tthis.kv.set(keyToHex(key), { key, value });\n\t\t}\n\t}\n\n\tasync setAlarm(workflowId: string, wakeAt: number): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.alarms.set(workflowId, wakeAt);\n\t}\n\n\tasync clearAlarm(workflowId: string): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.alarms.delete(workflowId);\n\t}\n\n\tasync waitForMessages(\n\t\tmessageNames: string[],\n\t\tabortSignal: AbortSignal,\n\t): Promise<void> {\n\t\tconst driver = this.messageDriver as WorkflowMessageDriver & {\n\t\t\twaitForMessages?: (\n\t\t\t\tmessageNames: string[],\n\t\t\t\tabortSignal: AbortSignal,\n\t\t\t) => Promise<void>;\n\t\t};\n\t\tif (driver.waitForMessages) {\n\t\t\tawait driver.waitForMessages(messageNames, abortSignal);\n\t\t\treturn;\n\t\t}\n\n\t\twhile (true) {\n\t\t\tif (abortSignal.aborted) {\n\t\t\t\tthrow new EvictedError();\n\t\t\t}\n\t\t\tconst messages = await this.messageDriver.receiveMessages({\n\t\t\t\tnames: messageNames.length > 0 ? messageNames : undefined,\n\t\t\t\tcount: 1,\n\t\t\t\tcompletable: true,\n\t\t\t});\n\t\t\tif (messages.length > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait sleep(Math.max(1, this.latency));\n\t\t}\n\t}\n\n\t/**\n\t * Get the alarm time for a workflow (for testing).\n\t */\n\tgetAlarm(workflowId: string): number | undefined {\n\t\treturn this.alarms.get(workflowId);\n\t}\n\n\t/**\n\t * Check if any alarms are due and return their workflow IDs.\n\t */\n\tgetDueAlarms(): string[] {\n\t\tconst now = Date.now();\n\t\tconst due: string[] = [];\n\t\tfor (const [workflowId, wakeAt] of this.alarms) {\n\t\t\tif (wakeAt <= now) {\n\t\t\t\tdue.push(workflowId);\n\t\t\t}\n\t\t}\n\t\treturn due;\n\t}\n\n\t/**\n\t * Clear all data (for testing).\n\t */\n\tclear(): void {\n\t\tthis.kv.clear();\n\t\tthis.alarms.clear();\n\t\tthis.#inMemoryMessageDriver.clear();\n\t}\n\n\t/**\n\t * Get a snapshot of all data (for testing/debugging).\n\t */\n\tsnapshot(): {\n\t\tkv: Record<string, Uint8Array>;\n\t\talarms: Record<string, number>;\n\t} {\n\t\tconst kvSnapshot: Record<string, Uint8Array> = {};\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tkvSnapshot[hexKey] = entry.value;\n\t\t}\n\t\treturn {\n\t\t\tkv: kvSnapshot,\n\t\t\talarms: Object.fromEntries(this.alarms),\n\t\t};\n\t}\n\n\t/**\n\t * Get all hex-encoded keys (for testing).\n\t */\n\tkeys(): string[] {\n\t\treturn [...this.kv.keys()];\n\t}\n}\n\n// Re-export main exports for convenience\nexport * from \"./index.js\";\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rivetkit/workflow-engine",
|
|
3
|
+
"version": "2.1.0-rc.1",
|
|
4
|
+
"description": "Durable workflow engine with reentrant execution",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"workflow",
|
|
8
|
+
"durable",
|
|
9
|
+
"reentrant",
|
|
10
|
+
"stateful"
|
|
11
|
+
],
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"src",
|
|
15
|
+
"schemas",
|
|
16
|
+
"package.json"
|
|
17
|
+
],
|
|
18
|
+
"type": "module",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./dist/tsup/index.d.ts",
|
|
23
|
+
"default": "./dist/tsup/index.js"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./dist/tsup/index.d.cts",
|
|
27
|
+
"default": "./dist/tsup/index.cjs"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"./testing": {
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/tsup/testing.d.ts",
|
|
33
|
+
"default": "./dist/tsup/testing.js"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/tsup/testing.d.cts",
|
|
37
|
+
"default": "./dist/tsup/testing.cjs"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18.0.0"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@rivetkit/bare-ts": "^0.6.2",
|
|
46
|
+
"cbor-x": "^1.6.0",
|
|
47
|
+
"fdb-tuple": "^1.0.0",
|
|
48
|
+
"pino": "^9.6.0",
|
|
49
|
+
"vbare": "^0.0.4"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@bare-ts/tools": "^0.13.0",
|
|
53
|
+
"commander": "^12.0.0",
|
|
54
|
+
"tsx": "^4.7.0",
|
|
55
|
+
"@biomejs/biome": "^2.2.3",
|
|
56
|
+
"@types/node": "^22.13.1",
|
|
57
|
+
"tsup": "^8.4.0",
|
|
58
|
+
"typescript": "^5.7.3",
|
|
59
|
+
"vitest": "^3.1.1"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "pnpm run compile:bare && tsup src/index.ts src/testing.ts",
|
|
63
|
+
"compile:bare": "tsx scripts/compile-bare.ts compile schemas/v1.bare -o dist/schemas/v1.ts",
|
|
64
|
+
"check-types": "tsc --noEmit",
|
|
65
|
+
"lint": "biome check .",
|
|
66
|
+
"lint:fix": "biome check --write .",
|
|
67
|
+
"test": "vitest run",
|
|
68
|
+
"test:watch": "vitest"
|
|
69
|
+
}
|
|
70
|
+
}
|