@venturekit/runtime 0.0.0-dev.20260312012510 → 0.0.0-dev.20260329102450
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 +1 -1
- package/dist/config/env.d.ts +62 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +98 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/secrets.d.ts +67 -0
- package/dist/config/secrets.d.ts.map +1 -0
- package/dist/config/secrets.js +132 -0
- package/dist/config/secrets.js.map +1 -0
- package/dist/handler/adapter.d.ts.map +1 -0
- package/dist/{adapter.js → handler/adapter.js} +5 -44
- package/dist/handler/adapter.js.map +1 -0
- package/dist/{context.d.ts → handler/context.d.ts} +44 -3
- package/dist/handler/context.d.ts.map +1 -0
- package/dist/{context.js → handler/context.js} +9 -9
- package/dist/handler/context.js.map +1 -0
- package/dist/handler/errors.d.ts.map +1 -0
- package/dist/{errors.js → handler/errors.js} +11 -25
- package/dist/handler/errors.js.map +1 -0
- package/dist/{handler.d.ts → handler/handler.d.ts} +36 -3
- package/dist/handler/handler.d.ts.map +1 -0
- package/dist/{handler.js → handler/handler.js} +59 -23
- package/dist/handler/handler.js.map +1 -0
- package/dist/handler/response.d.ts.map +1 -0
- package/dist/{response.js → handler/response.js} +9 -17
- package/dist/handler/response.js.map +1 -0
- package/dist/handler/task-handler.d.ts +192 -0
- package/dist/handler/task-handler.d.ts.map +1 -0
- package/dist/handler/task-handler.js +262 -0
- package/dist/handler/task-handler.js.map +1 -0
- package/dist/index.d.ts +33 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -48
- package/dist/index.js.map +1 -1
- package/dist/{logger.d.ts → logging/logger.d.ts} +1 -1
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/{logger.js → logging/logger.js} +8 -16
- package/dist/logging/logger.js.map +1 -0
- package/dist/logging/tracing.d.ts +51 -0
- package/dist/logging/tracing.d.ts.map +1 -0
- package/dist/logging/tracing.js +77 -0
- package/dist/logging/tracing.js.map +1 -0
- package/dist/middleware/middleware.d.ts +120 -0
- package/dist/middleware/middleware.d.ts.map +1 -0
- package/dist/middleware/middleware.js +270 -0
- package/dist/middleware/middleware.js.map +1 -0
- package/dist/middleware/rate-limit-store.d.ts +153 -0
- package/dist/middleware/rate-limit-store.d.ts.map +1 -0
- package/dist/middleware/rate-limit-store.js +182 -0
- package/dist/middleware/rate-limit-store.js.map +1 -0
- package/dist/openapi/openapi.d.ts +147 -0
- package/dist/openapi/openapi.d.ts.map +1 -0
- package/dist/openapi/openapi.js +235 -0
- package/dist/openapi/openapi.js.map +1 -0
- package/dist/openapi.d.ts +10 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +9 -0
- package/dist/openapi.js.map +1 -0
- package/dist/patterns/circuit-breaker.d.ts +78 -0
- package/dist/patterns/circuit-breaker.d.ts.map +1 -0
- package/dist/patterns/circuit-breaker.js +113 -0
- package/dist/patterns/circuit-breaker.js.map +1 -0
- package/dist/patterns/idempotency.d.ts +175 -0
- package/dist/patterns/idempotency.d.ts.map +1 -0
- package/dist/patterns/idempotency.js +305 -0
- package/dist/patterns/idempotency.js.map +1 -0
- package/dist/patterns/invoke.d.ts +279 -0
- package/dist/patterns/invoke.d.ts.map +1 -0
- package/dist/patterns/invoke.js +581 -0
- package/dist/patterns/invoke.js.map +1 -0
- package/dist/patterns/saga.d.ts +391 -0
- package/dist/patterns/saga.d.ts.map +1 -0
- package/dist/patterns/saga.js +556 -0
- package/dist/patterns/saga.js.map +1 -0
- package/dist/patterns.d.ts +17 -0
- package/dist/patterns.d.ts.map +1 -0
- package/dist/patterns.js +17 -0
- package/dist/patterns.js.map +1 -0
- package/dist/rate-limit.d.ts +16 -0
- package/dist/rate-limit.d.ts.map +1 -0
- package/dist/rate-limit.js +15 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/secrets.d.ts +11 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +10 -0
- package/dist/secrets.js.map +1 -0
- package/dist/testing/test-utils.d.ts +99 -0
- package/dist/testing/test-utils.d.ts.map +1 -0
- package/dist/testing/test-utils.js +153 -0
- package/dist/testing/test-utils.js.map +1 -0
- package/dist/testing.d.ts +10 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +9 -0
- package/dist/testing.js.map +1 -0
- package/dist/ws/ws.d.ts +139 -0
- package/dist/ws/ws.d.ts.map +1 -0
- package/dist/ws/ws.js +294 -0
- package/dist/ws/ws.js.map +1 -0
- package/dist/ws.d.ts +5 -133
- package/dist/ws.d.ts.map +1 -1
- package/dist/ws.js +4 -291
- package/dist/ws.js.map +1 -1
- package/package.json +47 -5
- package/dist/adapter.d.ts.map +0 -1
- package/dist/adapter.js.map +0 -1
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/handler.d.ts.map +0 -1
- package/dist/handler.js.map +0 -1
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/middleware.d.ts +0 -47
- package/dist/middleware.d.ts.map +0 -1
- package/dist/middleware.js +0 -147
- package/dist/middleware.js.map +0 -1
- package/dist/response.d.ts.map +0 -1
- package/dist/response.js.map +0 -1
- /package/dist/{adapter.d.ts → handler/adapter.d.ts} +0 -0
- /package/dist/{errors.d.ts → handler/errors.d.ts} +0 -0
- /package/dist/{response.d.ts → handler/response.d.ts} +0 -0
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VentureKit Saga Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Distributed transaction coordination using the Saga pattern.
|
|
5
|
+
* Supports sequential and parallel steps, automatic rollback on failure,
|
|
6
|
+
* DynamoDB state persistence, resume from failure, and idempotent execution.
|
|
7
|
+
*
|
|
8
|
+
* ## Quick Start
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { saga } from '@venturekit/runtime';
|
|
11
|
+
*
|
|
12
|
+
* const createOrder = saga('create-order', [
|
|
13
|
+
* { name: 'reserve-inventory', execute: reserveInventory, compensate: releaseInventory },
|
|
14
|
+
* { name: 'charge-payment', execute: chargeCard, compensate: refundCharge },
|
|
15
|
+
* { name: 'send-confirmation', execute: sendEmail },
|
|
16
|
+
* ]);
|
|
17
|
+
*
|
|
18
|
+
* const result = await createOrder.run({ items: [...], total: 99 });
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* ## Parallel Steps
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const checkout = saga('checkout', [
|
|
24
|
+
* parallel('validate', [
|
|
25
|
+
* { name: 'check-inventory', execute: checkStock },
|
|
26
|
+
* { name: 'verify-payment', execute: verifyCard },
|
|
27
|
+
* ]),
|
|
28
|
+
* { name: 'charge-payment', execute: chargeCard, compensate: refundCharge },
|
|
29
|
+
* ]);
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
import { generateId } from '../logging/tracing.js';
|
|
33
|
+
/**
|
|
34
|
+
* Helper to create a parallel step group.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* saga('checkout', [
|
|
39
|
+
* parallel('validate', [
|
|
40
|
+
* { name: 'check-stock', execute: checkStock },
|
|
41
|
+
* { name: 'verify-card', execute: verifyCard },
|
|
42
|
+
* ]),
|
|
43
|
+
* { name: 'charge', execute: charge, compensate: refund },
|
|
44
|
+
* ]);
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export function parallel(name, steps) {
|
|
48
|
+
return { name, type: 'parallel', steps };
|
|
49
|
+
}
|
|
50
|
+
/** Type guard: is this entry a parallel group? */
|
|
51
|
+
function isParallelGroup(entry) {
|
|
52
|
+
return entry.type === 'parallel';
|
|
53
|
+
}
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Saga orchestrator
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
/**
|
|
58
|
+
* Define a saga orchestrator.
|
|
59
|
+
*
|
|
60
|
+
* @param name - Saga name (used in logs and state records)
|
|
61
|
+
* @param steps - Ordered list of steps (sequential or parallel groups)
|
|
62
|
+
* @param options - Saga options (store, tracing, callbacks)
|
|
63
|
+
*
|
|
64
|
+
* @example Sequential steps
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const createOrder = saga('create-order', [
|
|
67
|
+
* {
|
|
68
|
+
* name: 'reserve-inventory',
|
|
69
|
+
* execute: async (ctx) => {
|
|
70
|
+
* const reservation = await reserveInventory(ctx.items);
|
|
71
|
+
* return { ...ctx, reservationId: reservation.id };
|
|
72
|
+
* },
|
|
73
|
+
* compensate: async (ctx) => {
|
|
74
|
+
* await releaseInventory(ctx.reservationId);
|
|
75
|
+
* },
|
|
76
|
+
* },
|
|
77
|
+
* {
|
|
78
|
+
* name: 'charge-payment',
|
|
79
|
+
* execute: async (ctx) => {
|
|
80
|
+
* const charge = await chargeCard(ctx.paymentMethod, ctx.total);
|
|
81
|
+
* return { ...ctx, chargeId: charge.id };
|
|
82
|
+
* },
|
|
83
|
+
* compensate: async (ctx) => {
|
|
84
|
+
* await refundCharge(ctx.chargeId);
|
|
85
|
+
* },
|
|
86
|
+
* },
|
|
87
|
+
* {
|
|
88
|
+
* name: 'send-confirmation',
|
|
89
|
+
* execute: async (ctx) => {
|
|
90
|
+
* await sendEmail(ctx.email, 'Order confirmed');
|
|
91
|
+
* return ctx;
|
|
92
|
+
* },
|
|
93
|
+
* },
|
|
94
|
+
* ]);
|
|
95
|
+
*
|
|
96
|
+
* const result = await createOrder.run({ items: [...], paymentMethod: 'pm_xxx' });
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @example Parallel + sequential
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const checkout = saga('checkout', [
|
|
102
|
+
* parallel('validate', [
|
|
103
|
+
* { name: 'check-stock', execute: checkStock },
|
|
104
|
+
* { name: 'verify-card', execute: verifyCard },
|
|
105
|
+
* ]),
|
|
106
|
+
* { name: 'charge', execute: charge, compensate: refund },
|
|
107
|
+
* { name: 'email', execute: sendConfirmation },
|
|
108
|
+
* ]);
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* @example Resume from failure
|
|
112
|
+
* ```typescript
|
|
113
|
+
* const store = await createDefaultSagaStore();
|
|
114
|
+
* const mySaga = saga('order', steps, { store });
|
|
115
|
+
*
|
|
116
|
+
* // First attempt — fails at step 2
|
|
117
|
+
* const first = await mySaga.run(ctx, { id: 'order-123' });
|
|
118
|
+
*
|
|
119
|
+
* // Fix the issue, then resume — skips already-completed steps
|
|
120
|
+
* const second = await mySaga.resume('order-123');
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export function saga(name, steps, options = {}) {
|
|
124
|
+
const { store, traceId: defaultTraceId, onStepComplete, onCompensating, onFailed } = options;
|
|
125
|
+
/** Flatten a step entry into its individual steps (for compensation tracking) */
|
|
126
|
+
function flattenEntry(entry) {
|
|
127
|
+
return isParallelGroup(entry) ? entry.steps : [entry];
|
|
128
|
+
}
|
|
129
|
+
/** Build a log prefix with traceId when available */
|
|
130
|
+
function logPrefix(tid) {
|
|
131
|
+
return tid ? `[saga:${name}][trace:${tid}]` : `[saga:${name}]`;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Execute a single step entry (sequential step or parallel group).
|
|
135
|
+
* Returns the updated context and per-step results.
|
|
136
|
+
*/
|
|
137
|
+
async function executeEntry(entry, context, stepResults, tid) {
|
|
138
|
+
if (isParallelGroup(entry)) {
|
|
139
|
+
// Execute all steps in the group concurrently
|
|
140
|
+
const results = await Promise.all(entry.steps.map(async (step) => {
|
|
141
|
+
if (step.async) {
|
|
142
|
+
console.log(`${logPrefix(tid)} firing async parallel step: ${step.name}`);
|
|
143
|
+
step.execute(context).catch((err) => {
|
|
144
|
+
console.error(`${logPrefix(tid)} async parallel step failed (ignored): ${step.name} — ${err}`);
|
|
145
|
+
});
|
|
146
|
+
stepResults[step.name] = { name: step.name, output: context, async: true };
|
|
147
|
+
return context;
|
|
148
|
+
}
|
|
149
|
+
console.log(`${logPrefix(tid)} executing parallel step: ${step.name}`);
|
|
150
|
+
const output = await step.execute(context);
|
|
151
|
+
stepResults[step.name] = { name: step.name, output, async: false };
|
|
152
|
+
return output;
|
|
153
|
+
}));
|
|
154
|
+
// Shallow-merge all results onto the input context
|
|
155
|
+
let merged = { ...context };
|
|
156
|
+
for (const result of results) {
|
|
157
|
+
merged = { ...merged, ...result };
|
|
158
|
+
}
|
|
159
|
+
return merged;
|
|
160
|
+
}
|
|
161
|
+
// Async (fire-and-forget) step
|
|
162
|
+
if (entry.async) {
|
|
163
|
+
console.log(`${logPrefix(tid)} firing async step: ${entry.name}`);
|
|
164
|
+
entry.execute(context).catch((err) => {
|
|
165
|
+
console.error(`${logPrefix(tid)} async step failed (ignored): ${entry.name} — ${err}`);
|
|
166
|
+
});
|
|
167
|
+
stepResults[entry.name] = { name: entry.name, output: context, async: true };
|
|
168
|
+
return context;
|
|
169
|
+
}
|
|
170
|
+
// Sequential step
|
|
171
|
+
console.log(`${logPrefix(tid)} executing step: ${entry.name}`);
|
|
172
|
+
const output = await entry.execute(context);
|
|
173
|
+
stepResults[entry.name] = { name: entry.name, output, async: false };
|
|
174
|
+
return output;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Compensate a list of completed entries in reverse order.
|
|
178
|
+
* For parallel groups, compensate all sub-steps concurrently.
|
|
179
|
+
*/
|
|
180
|
+
async function compensateEntries(completedEntries, context, record, reason, tid) {
|
|
181
|
+
for (let i = completedEntries.length - 1; i >= 0; i--) {
|
|
182
|
+
const { entry, completedSubSteps } = completedEntries[i];
|
|
183
|
+
if (isParallelGroup(entry)) {
|
|
184
|
+
// Compensate completed sub-steps concurrently
|
|
185
|
+
const subCompensations = entry.steps
|
|
186
|
+
.filter((s) => completedSubSteps.includes(s.name) && s.compensate)
|
|
187
|
+
.map(async (s) => {
|
|
188
|
+
onCompensating?.({
|
|
189
|
+
name: s.name, index: i, context, reason,
|
|
190
|
+
sagaId: record.id, sagaName: name,
|
|
191
|
+
});
|
|
192
|
+
console.log(`${logPrefix(tid)} compensating parallel step: ${s.name}`);
|
|
193
|
+
return s.compensate(context);
|
|
194
|
+
});
|
|
195
|
+
await Promise.all(subCompensations);
|
|
196
|
+
}
|
|
197
|
+
else if (entry.compensate) {
|
|
198
|
+
onCompensating?.({
|
|
199
|
+
name: entry.name, index: i, context, reason,
|
|
200
|
+
sagaId: record.id, sagaName: name,
|
|
201
|
+
});
|
|
202
|
+
console.log(`${logPrefix(tid)} compensating step: ${entry.name}`);
|
|
203
|
+
await entry.compensate(context);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
name,
|
|
209
|
+
steps,
|
|
210
|
+
/**
|
|
211
|
+
* Execute the saga from the beginning or resume a previously failed saga.
|
|
212
|
+
*
|
|
213
|
+
* @param initialContext - Starting context for the saga
|
|
214
|
+
* @param runOptions - Optional ID (for idempotency) and traceId
|
|
215
|
+
*/
|
|
216
|
+
async run(initialContext, runOptions = {}) {
|
|
217
|
+
const tid = runOptions.traceId
|
|
218
|
+
|| defaultTraceId
|
|
219
|
+
|| generateId();
|
|
220
|
+
const id = runOptions.id || `saga-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
221
|
+
// Check if this saga was previously attempted (resume support)
|
|
222
|
+
let existingRecord = null;
|
|
223
|
+
if (store) {
|
|
224
|
+
existingRecord = await store.get(id);
|
|
225
|
+
}
|
|
226
|
+
const isResume = existingRecord !== null
|
|
227
|
+
&& (existingRecord.status === 'failed' || existingRecord.status === 'compensated');
|
|
228
|
+
const record = {
|
|
229
|
+
id,
|
|
230
|
+
name,
|
|
231
|
+
status: 'running',
|
|
232
|
+
currentStep: 0,
|
|
233
|
+
context: isResume ? existingRecord.context : initialContext,
|
|
234
|
+
completedSteps: isResume ? [...existingRecord.completedSteps] : [],
|
|
235
|
+
traceId: tid,
|
|
236
|
+
startedAt: isResume ? existingRecord.startedAt : Date.now(),
|
|
237
|
+
attempts: isResume ? (existingRecord.attempts ?? 1) + 1 : 1,
|
|
238
|
+
};
|
|
239
|
+
if (store) {
|
|
240
|
+
if (isResume) {
|
|
241
|
+
await store.update(id, {
|
|
242
|
+
status: 'running',
|
|
243
|
+
error: undefined,
|
|
244
|
+
completedAt: undefined,
|
|
245
|
+
traceId: tid,
|
|
246
|
+
attempts: record.attempts,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
await store.save(record);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
console.log(`${logPrefix(tid)} started (id=${id}, attempt=${record.attempts}${isResume ? ', resumed' : ''})`);
|
|
254
|
+
let context = record.context;
|
|
255
|
+
// Track which entries were completed (for compensation on failure)
|
|
256
|
+
const completedEntries = [];
|
|
257
|
+
// Per-step results map
|
|
258
|
+
const stepResults = {};
|
|
259
|
+
try {
|
|
260
|
+
for (let i = 0; i < steps.length; i++) {
|
|
261
|
+
const entry = steps[i];
|
|
262
|
+
const entrySteps = flattenEntry(entry);
|
|
263
|
+
const entryStepNames = entrySteps.map((s) => s.name);
|
|
264
|
+
record.currentStep = i;
|
|
265
|
+
// Idempotent resume: skip entries whose steps are all already completed
|
|
266
|
+
const allCompleted = entryStepNames.every((n) => record.completedSteps.includes(n));
|
|
267
|
+
if (isResume && allCompleted) {
|
|
268
|
+
console.log(`${logPrefix(tid)} skipping completed entry: ${isParallelGroup(entry) ? entry.name : entry.name}`);
|
|
269
|
+
completedEntries.push({ entry, completedSubSteps: entryStepNames });
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
if (store) {
|
|
273
|
+
await store.update(id, { currentStep: i, status: 'running' });
|
|
274
|
+
}
|
|
275
|
+
const stepStart = Date.now();
|
|
276
|
+
context = await executeEntry(entry, context, stepResults, tid);
|
|
277
|
+
const stepDurationMs = Date.now() - stepStart;
|
|
278
|
+
// Track completion
|
|
279
|
+
for (const sn of entryStepNames) {
|
|
280
|
+
if (!record.completedSteps.includes(sn)) {
|
|
281
|
+
record.completedSteps.push(sn);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
record.context = context;
|
|
285
|
+
completedEntries.push({ entry, completedSubSteps: entryStepNames });
|
|
286
|
+
if (isParallelGroup(entry)) {
|
|
287
|
+
for (const s of entry.steps) {
|
|
288
|
+
onStepComplete?.({
|
|
289
|
+
name: s.name, index: i, context, durationMs: stepDurationMs,
|
|
290
|
+
async: s.async ?? false, sagaId: id, sagaName: name,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
onStepComplete?.({
|
|
296
|
+
name: entry.name, index: i, context, durationMs: stepDurationMs,
|
|
297
|
+
async: entry.async ?? false, sagaId: id, sagaName: name,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
if (store) {
|
|
301
|
+
await store.update(id, {
|
|
302
|
+
completedSteps: record.completedSteps,
|
|
303
|
+
context: context,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// All steps completed
|
|
308
|
+
record.status = 'completed';
|
|
309
|
+
record.completedAt = Date.now();
|
|
310
|
+
if (store) {
|
|
311
|
+
await store.update(id, { status: 'completed', completedAt: record.completedAt });
|
|
312
|
+
}
|
|
313
|
+
console.log(`${logPrefix(tid)} completed (id=${id})`);
|
|
314
|
+
return { success: true, context, record, steps: stepResults };
|
|
315
|
+
}
|
|
316
|
+
catch (executeError) {
|
|
317
|
+
const error = executeError instanceof Error ? executeError : new Error(String(executeError));
|
|
318
|
+
console.error(`${logPrefix(tid)} step failed: ${error.message}`);
|
|
319
|
+
record.status = 'compensating';
|
|
320
|
+
record.error = error.message;
|
|
321
|
+
if (store) {
|
|
322
|
+
await store.update(id, { status: 'compensating', error: error.message });
|
|
323
|
+
}
|
|
324
|
+
// Compensate completed entries in reverse
|
|
325
|
+
try {
|
|
326
|
+
await compensateEntries(completedEntries, context, record, error, tid);
|
|
327
|
+
record.status = 'compensated';
|
|
328
|
+
record.completedAt = Date.now();
|
|
329
|
+
if (store) {
|
|
330
|
+
await store.update(id, { status: 'compensated', completedAt: record.completedAt });
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
catch (compensateError) {
|
|
334
|
+
const compErr = compensateError instanceof Error ? compensateError : new Error(String(compensateError));
|
|
335
|
+
record.status = 'failed';
|
|
336
|
+
record.error = `Compensation failed: ${compErr.message} (original: ${error.message})`;
|
|
337
|
+
if (store) {
|
|
338
|
+
await store.update(id, { status: 'failed', error: record.error });
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
console.error(`${logPrefix(tid)} ${record.status} (id=${id})`);
|
|
342
|
+
onFailed?.({
|
|
343
|
+
error, record, context,
|
|
344
|
+
failedStep: steps[record.currentStep]
|
|
345
|
+
? (isParallelGroup(steps[record.currentStep]) ? steps[record.currentStep].name : steps[record.currentStep].name)
|
|
346
|
+
: undefined,
|
|
347
|
+
durationMs: Date.now() - record.startedAt,
|
|
348
|
+
});
|
|
349
|
+
return { success: false, context, record, steps: stepResults };
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
/**
|
|
353
|
+
* Resume a previously failed or compensated saga.
|
|
354
|
+
* Requires a store to be configured.
|
|
355
|
+
* Skips steps that were already completed in the previous attempt.
|
|
356
|
+
*
|
|
357
|
+
* @param sagaId - The saga execution ID to resume
|
|
358
|
+
* @param runOptions - Optional traceId override
|
|
359
|
+
*/
|
|
360
|
+
async resume(sagaId, runOptions = {}) {
|
|
361
|
+
if (!store) {
|
|
362
|
+
throw new Error('Cannot resume saga without a store. Pass a store in saga options.');
|
|
363
|
+
}
|
|
364
|
+
const existing = await store.get(sagaId);
|
|
365
|
+
if (!existing) {
|
|
366
|
+
throw new Error(`Saga ${sagaId} not found in store`);
|
|
367
|
+
}
|
|
368
|
+
if (existing.status !== 'failed' && existing.status !== 'compensated') {
|
|
369
|
+
throw new Error(`Saga ${sagaId} is in '${existing.status}' state and cannot be resumed. Only 'failed' or 'compensated' sagas can be resumed.`);
|
|
370
|
+
}
|
|
371
|
+
return this.run(existing.context, {
|
|
372
|
+
id: sagaId,
|
|
373
|
+
traceId: runOptions.traceId,
|
|
374
|
+
});
|
|
375
|
+
},
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
// ---------------------------------------------------------------------------
|
|
379
|
+
// In-memory saga store (dev / testing)
|
|
380
|
+
// ---------------------------------------------------------------------------
|
|
381
|
+
/**
|
|
382
|
+
* In-memory saga store (for development/testing).
|
|
383
|
+
*
|
|
384
|
+
* **WARNING:** State is lost when the process restarts.
|
|
385
|
+
* For production, use `createDynamoDBSagaStore()`.
|
|
386
|
+
*/
|
|
387
|
+
export function createMemorySagaStore() {
|
|
388
|
+
const records = new Map();
|
|
389
|
+
return {
|
|
390
|
+
async save(record) {
|
|
391
|
+
records.set(record.id, { ...record });
|
|
392
|
+
},
|
|
393
|
+
async update(id, updates) {
|
|
394
|
+
const existing = records.get(id);
|
|
395
|
+
if (existing) {
|
|
396
|
+
records.set(id, { ...existing, ...updates });
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
async get(id) {
|
|
400
|
+
return records.get(id) ?? null;
|
|
401
|
+
},
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Create a DynamoDB-backed saga state store.
|
|
406
|
+
*
|
|
407
|
+
* Persists saga execution state so sagas can be resumed after failure,
|
|
408
|
+
* tracked in logs, and audited.
|
|
409
|
+
*
|
|
410
|
+
* ### DynamoDB Table Schema
|
|
411
|
+
*
|
|
412
|
+
* The table must have:
|
|
413
|
+
* - **Partition key:** `pk` (String) — the saga execution ID
|
|
414
|
+
* - **TTL attribute:** `ttl` (Number) — epoch seconds for auto-cleanup
|
|
415
|
+
*
|
|
416
|
+
* @example
|
|
417
|
+
* ```typescript
|
|
418
|
+
* import { saga, createDynamoDBSagaStore } from '@venturekit/runtime';
|
|
419
|
+
*
|
|
420
|
+
* const store = await createDynamoDBSagaStore();
|
|
421
|
+
* const mySaga = saga('create-order', steps, { store });
|
|
422
|
+
*
|
|
423
|
+
* const result = await mySaga.run(ctx, { id: 'order-123' });
|
|
424
|
+
*
|
|
425
|
+
* // If failed, resume later:
|
|
426
|
+
* const resumed = await mySaga.resume('order-123');
|
|
427
|
+
* ```
|
|
428
|
+
*/
|
|
429
|
+
export async function createDynamoDBSagaStore(options = {}) {
|
|
430
|
+
const tableName = options.tableName
|
|
431
|
+
|| process.env.VENTURE_SAGA_TABLE
|
|
432
|
+
|| 'venturekit-sagas';
|
|
433
|
+
const ttlSeconds = options.ttlSeconds ?? 604800; // 7 days
|
|
434
|
+
const region = options.region || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1';
|
|
435
|
+
const { DynamoDBClient, PutItemCommand, UpdateItemCommand, GetItemCommand } = await import('@aws-sdk/client-dynamodb');
|
|
436
|
+
const client = new DynamoDBClient({ region });
|
|
437
|
+
function serialize(record) {
|
|
438
|
+
const ttl = Math.ceil(Date.now() / 1000) + ttlSeconds;
|
|
439
|
+
return {
|
|
440
|
+
pk: { S: record.id },
|
|
441
|
+
name: { S: record.name },
|
|
442
|
+
status: { S: record.status },
|
|
443
|
+
currentStep: { N: String(record.currentStep) },
|
|
444
|
+
context: { S: JSON.stringify(record.context) },
|
|
445
|
+
completedSteps: { SS: record.completedSteps.length > 0 ? record.completedSteps : ['__empty__'] },
|
|
446
|
+
startedAt: { N: String(record.startedAt) },
|
|
447
|
+
attempts: { N: String(record.attempts ?? 1) },
|
|
448
|
+
ttl: { N: String(ttl) },
|
|
449
|
+
...(record.error ? { error: { S: record.error } } : {}),
|
|
450
|
+
...(record.traceId ? { traceId: { S: record.traceId } } : {}),
|
|
451
|
+
...(record.completedAt ? { completedAt: { N: String(record.completedAt) } } : {}),
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
function deserialize(item) {
|
|
455
|
+
const completedSteps = item.completedSteps?.SS
|
|
456
|
+
? item.completedSteps.SS.filter((s) => s !== '__empty__')
|
|
457
|
+
: [];
|
|
458
|
+
return {
|
|
459
|
+
id: item.pk.S,
|
|
460
|
+
name: item.name.S,
|
|
461
|
+
status: item.status.S,
|
|
462
|
+
currentStep: parseInt(item.currentStep.N, 10),
|
|
463
|
+
context: JSON.parse(item.context.S),
|
|
464
|
+
completedSteps,
|
|
465
|
+
startedAt: parseInt(item.startedAt.N, 10),
|
|
466
|
+
attempts: parseInt(item.attempts?.N ?? '1', 10),
|
|
467
|
+
error: item.error?.S,
|
|
468
|
+
traceId: item.traceId?.S,
|
|
469
|
+
completedAt: item.completedAt?.N ? parseInt(item.completedAt.N, 10) : undefined,
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
return {
|
|
473
|
+
async save(record) {
|
|
474
|
+
await client.send(new PutItemCommand({
|
|
475
|
+
TableName: tableName,
|
|
476
|
+
Item: serialize(record),
|
|
477
|
+
}));
|
|
478
|
+
},
|
|
479
|
+
async update(id, updates) {
|
|
480
|
+
const expressionParts = [];
|
|
481
|
+
const names = {};
|
|
482
|
+
const values = {};
|
|
483
|
+
let counter = 0;
|
|
484
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
485
|
+
if (value === undefined)
|
|
486
|
+
continue;
|
|
487
|
+
counter++;
|
|
488
|
+
const attrName = `#a${counter}`;
|
|
489
|
+
const attrValue = `:v${counter}`;
|
|
490
|
+
names[attrName] = key;
|
|
491
|
+
if (key === 'completedSteps') {
|
|
492
|
+
const arr = value;
|
|
493
|
+
values[attrValue] = { SS: arr.length > 0 ? arr : ['__empty__'] };
|
|
494
|
+
}
|
|
495
|
+
else if (key === 'context') {
|
|
496
|
+
values[attrValue] = { S: JSON.stringify(value) };
|
|
497
|
+
}
|
|
498
|
+
else if (typeof value === 'number') {
|
|
499
|
+
values[attrValue] = { N: String(value) };
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
values[attrValue] = { S: String(value) };
|
|
503
|
+
}
|
|
504
|
+
expressionParts.push(`${attrName} = ${attrValue}`);
|
|
505
|
+
}
|
|
506
|
+
// Update TTL on every write
|
|
507
|
+
counter++;
|
|
508
|
+
names[`#a${counter}`] = 'ttl';
|
|
509
|
+
values[`:v${counter}`] = { N: String(Math.ceil(Date.now() / 1000) + ttlSeconds) };
|
|
510
|
+
expressionParts.push(`#a${counter} = :v${counter}`);
|
|
511
|
+
if (expressionParts.length === 0)
|
|
512
|
+
return;
|
|
513
|
+
await client.send(new UpdateItemCommand({
|
|
514
|
+
TableName: tableName,
|
|
515
|
+
Key: { pk: { S: id } },
|
|
516
|
+
UpdateExpression: `SET ${expressionParts.join(', ')}`,
|
|
517
|
+
ExpressionAttributeNames: names,
|
|
518
|
+
ExpressionAttributeValues: values,
|
|
519
|
+
}));
|
|
520
|
+
},
|
|
521
|
+
async get(id) {
|
|
522
|
+
const result = await client.send(new GetItemCommand({
|
|
523
|
+
TableName: tableName,
|
|
524
|
+
Key: { pk: { S: id } },
|
|
525
|
+
}));
|
|
526
|
+
if (!result.Item)
|
|
527
|
+
return null;
|
|
528
|
+
return deserialize(result.Item);
|
|
529
|
+
},
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Create a saga store with sensible defaults.
|
|
534
|
+
*
|
|
535
|
+
* - In production (Lambda): uses DynamoDB for distributed state persistence
|
|
536
|
+
* - In local dev: uses in-memory store
|
|
537
|
+
*
|
|
538
|
+
* @example
|
|
539
|
+
* ```typescript
|
|
540
|
+
* import { saga, createDefaultSagaStore } from '@venturekit/runtime';
|
|
541
|
+
*
|
|
542
|
+
* const store = await createDefaultSagaStore();
|
|
543
|
+
* const mySaga = saga('create-order', steps, { store });
|
|
544
|
+
* ```
|
|
545
|
+
*/
|
|
546
|
+
export async function createDefaultSagaStore(options = {}) {
|
|
547
|
+
const isLocal = !process.env.AWS_LAMBDA_FUNCTION_NAME && !process.env.AWS_EXECUTION_ENV;
|
|
548
|
+
if (isLocal || options.forceMemory) {
|
|
549
|
+
return createMemorySagaStore();
|
|
550
|
+
}
|
|
551
|
+
return createDynamoDBSagaStore({
|
|
552
|
+
tableName: options.tableName,
|
|
553
|
+
ttlSeconds: options.ttlSeconds,
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
//# sourceMappingURL=saga.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"saga.js","sourceRoot":"","sources":["../../src/patterns/saga.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @venturekit/runtime/patterns
|
|
3
|
+
*
|
|
4
|
+
* Advanced patterns: invoke, saga, circuit-breaker, idempotency.
|
|
5
|
+
* Requires AWS SDK peer dependencies when using DynamoDB/Lambda-backed stores.
|
|
6
|
+
*
|
|
7
|
+
* Import via: `import { invoke, saga } from '@venturekit/runtime/patterns'`
|
|
8
|
+
*/
|
|
9
|
+
export { createInvoker, defaultFunctionNameResolver, createLambdaInvoker, createLocalInvoker, resolveFunctionName, invoke, invokeDirect, configureCircuitBreaker, } from './patterns/invoke.js';
|
|
10
|
+
export type { InvokeMode, InvokeOptions, InvokeResult, LambdaInvoker, FunctionNameResolver, FunctionInvokeTarget, FunctionInvokeOptions, DirectInvokeOptions, DirectInvokeResult, } from './patterns/invoke.js';
|
|
11
|
+
export { createCircuitBreaker, } from './patterns/circuit-breaker.js';
|
|
12
|
+
export type { CircuitBreaker, CircuitBreakerOptions, CircuitState, } from './patterns/circuit-breaker.js';
|
|
13
|
+
export { saga, parallel, createMemorySagaStore, createDynamoDBSagaStore, createDefaultSagaStore, } from './patterns/saga.js';
|
|
14
|
+
export type { SagaStep, SagaStepEntry, ParallelStepGroup, SagaStatus, SagaRecord, SagaStore, StepResult, SagaResult, SagaOptions, SagaRunOptions, SagaStepEvent, SagaCompensateEvent, SagaFailedEvent, DynamoDBSagaStoreOptions, DefaultSagaStoreOptions, } from './patterns/saga.js';
|
|
15
|
+
export { idempotencyMiddleware, IdempotencyConflictError, MissingIdempotencyKeyError, createMemoryIdempotencyStore, createDynamoDBIdempotencyStore, createDefaultIdempotencyStore, headerKeyExtractor, bodyFieldKeyExtractor, } from './patterns/idempotency.js';
|
|
16
|
+
export type { IdempotencyRecord, IdempotencyStore, IdempotencyKeyExtractor, IdempotencyOptions, DynamoDBIdempotencyStoreOptions, DefaultIdempotencyStoreOptions, } from './patterns/idempotency.js';
|
|
17
|
+
//# sourceMappingURL=patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../src/patterns.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EACL,aAAa,EACb,2BAA2B,EAC3B,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,MAAM,EACN,YAAY,EACZ,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,UAAU,EACV,aAAa,EACb,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EACV,cAAc,EACd,qBAAqB,EACrB,YAAY,GACb,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EACL,IAAI,EACJ,QAAQ,EACR,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,QAAQ,EACR,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,UAAU,EACV,WAAW,EACX,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,0BAA0B,EAC1B,4BAA4B,EAC5B,8BAA8B,EAC9B,6BAA6B,EAC7B,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,+BAA+B,EAC/B,8BAA8B,GAC/B,MAAM,2BAA2B,CAAC"}
|
package/dist/patterns.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @venturekit/runtime/patterns
|
|
3
|
+
*
|
|
4
|
+
* Advanced patterns: invoke, saga, circuit-breaker, idempotency.
|
|
5
|
+
* Requires AWS SDK peer dependencies when using DynamoDB/Lambda-backed stores.
|
|
6
|
+
*
|
|
7
|
+
* Import via: `import { invoke, saga } from '@venturekit/runtime/patterns'`
|
|
8
|
+
*/
|
|
9
|
+
// Lambda-to-Lambda invocation
|
|
10
|
+
export { createInvoker, defaultFunctionNameResolver, createLambdaInvoker, createLocalInvoker, resolveFunctionName, invoke, invokeDirect, configureCircuitBreaker, } from './patterns/invoke.js';
|
|
11
|
+
// Circuit Breaker
|
|
12
|
+
export { createCircuitBreaker, } from './patterns/circuit-breaker.js';
|
|
13
|
+
// Saga
|
|
14
|
+
export { saga, parallel, createMemorySagaStore, createDynamoDBSagaStore, createDefaultSagaStore, } from './patterns/saga.js';
|
|
15
|
+
// Idempotency
|
|
16
|
+
export { idempotencyMiddleware, IdempotencyConflictError, MissingIdempotencyKeyError, createMemoryIdempotencyStore, createDynamoDBIdempotencyStore, createDefaultIdempotencyStore, headerKeyExtractor, bodyFieldKeyExtractor, } from './patterns/idempotency.js';
|
|
17
|
+
//# sourceMappingURL=patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.js","sourceRoot":"","sources":["../src/patterns.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,8BAA8B;AAC9B,OAAO,EACL,aAAa,EACb,2BAA2B,EAC3B,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,MAAM,EACN,YAAY,EACZ,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAa9B,kBAAkB;AAClB,OAAO,EACL,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AAOvC,OAAO;AACP,OAAO,EACL,IAAI,EACJ,QAAQ,EACR,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAmB5B,cAAc;AACd,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,0BAA0B,EAC1B,4BAA4B,EAC5B,8BAA8B,EAC9B,6BAA6B,EAC7B,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @venturekit/runtime/rate-limit
|
|
3
|
+
*
|
|
4
|
+
* DynamoDB-backed rate limit stores for production use.
|
|
5
|
+
* Requires @aws-sdk/client-dynamodb.
|
|
6
|
+
*
|
|
7
|
+
* For in-memory stores (local dev), use the core import:
|
|
8
|
+
* `import { createMemoryRateLimitStore } from '@venturekit/runtime'`
|
|
9
|
+
*
|
|
10
|
+
* Import via: `import { createDynamoDBRateLimitStore } from '@venturekit/runtime/rate-limit'`
|
|
11
|
+
*/
|
|
12
|
+
export { createDynamoDBRateLimitStore, createDefaultRateLimiter, } from './middleware/rate-limit-store.js';
|
|
13
|
+
export type { DynamoDBRateLimitStoreOptions, DefaultRateLimiterOptions, } from './middleware/rate-limit-store.js';
|
|
14
|
+
export { createMemoryRateLimitStore, RATE_LIMIT_PRESETS, } from './middleware/rate-limit-store.js';
|
|
15
|
+
export type { RateLimitPreset, RateLimitPresetConfig, } from './middleware/rate-limit-store.js';
|
|
16
|
+
//# sourceMappingURL=rate-limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,4BAA4B,EAC5B,wBAAwB,GACzB,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EACV,6BAA6B,EAC7B,yBAAyB,GAC1B,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EACL,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EACV,eAAe,EACf,qBAAqB,GACtB,MAAM,kCAAkC,CAAC"}
|