@mastra/inngest 0.0.0-vnext-inngest-20250506123700
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/CHANGELOG.md +21 -0
- package/LICENSE.md +46 -0
- package/dist/_tsup-dts-rollup.d.cts +183 -0
- package/dist/_tsup-dts-rollup.d.ts +183 -0
- package/dist/index.cjs +693 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +687 -0
- package/docker-compose.yaml +10 -0
- package/package.json +50 -0
- package/src/index.test.ts +5338 -0
- package/src/index.ts +898 -0
- package/tsconfig.json +5 -0
- package/vitest.config.ts +8 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var vNext = require('@mastra/core/workflows/vNext');
|
|
4
|
+
var realtime = require('@inngest/realtime');
|
|
5
|
+
var hono = require('inngest/hono');
|
|
6
|
+
var di = require('@mastra/core/di');
|
|
7
|
+
var crypto = require('crypto');
|
|
8
|
+
|
|
9
|
+
// src/index.ts
|
|
10
|
+
function serve({ mastra, ingest }) {
|
|
11
|
+
const wfs = mastra.vnext_getWorkflows();
|
|
12
|
+
const functions = Object.values(wfs).flatMap((wf) => {
|
|
13
|
+
if (wf instanceof InngestWorkflow) {
|
|
14
|
+
return wf.getFunctions();
|
|
15
|
+
}
|
|
16
|
+
return [];
|
|
17
|
+
});
|
|
18
|
+
return hono.serve({
|
|
19
|
+
client: ingest,
|
|
20
|
+
functions
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
var InngestRun = class extends vNext.Run {
|
|
24
|
+
inngest;
|
|
25
|
+
#mastra;
|
|
26
|
+
constructor(params, inngest) {
|
|
27
|
+
super(params);
|
|
28
|
+
this.inngest = inngest;
|
|
29
|
+
this.#mastra = params.mastra;
|
|
30
|
+
}
|
|
31
|
+
async getRuns(eventId) {
|
|
32
|
+
const response = await fetch(`${this.inngest.apiBaseUrl}/v1/events/${eventId}/runs`, {
|
|
33
|
+
headers: {
|
|
34
|
+
Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const json = await response.json();
|
|
38
|
+
return json.data;
|
|
39
|
+
}
|
|
40
|
+
async getRunOutput(eventId) {
|
|
41
|
+
let runs = await this.getRuns(eventId);
|
|
42
|
+
while (runs?.[0]?.status !== "Completed") {
|
|
43
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
44
|
+
runs = await this.getRuns(eventId);
|
|
45
|
+
if (runs?.[0]?.status === "Failed" || runs?.[0]?.status === "Cancelled") {
|
|
46
|
+
throw new Error(`Function run ${runs?.[0]?.status}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return runs?.[0];
|
|
50
|
+
}
|
|
51
|
+
async start({
|
|
52
|
+
inputData,
|
|
53
|
+
runtimeContext
|
|
54
|
+
}) {
|
|
55
|
+
const eventOutput = await this.inngest.send({
|
|
56
|
+
name: `workflow.${this.workflowId}`,
|
|
57
|
+
data: {
|
|
58
|
+
inputData,
|
|
59
|
+
runId: this.runId
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
const eventId = eventOutput.ids[0];
|
|
63
|
+
if (!eventId) {
|
|
64
|
+
throw new Error("Event ID is not set");
|
|
65
|
+
}
|
|
66
|
+
const runOutput = await this.getRunOutput(eventId);
|
|
67
|
+
const result = runOutput?.output?.result;
|
|
68
|
+
if (result.status === "failed") {
|
|
69
|
+
result.error = new Error(result.error);
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
async resume(params) {
|
|
74
|
+
const steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
|
|
75
|
+
(step) => typeof step === "string" ? step : step?.id
|
|
76
|
+
);
|
|
77
|
+
const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
|
|
78
|
+
workflowName: this.workflowId,
|
|
79
|
+
runId: this.runId
|
|
80
|
+
});
|
|
81
|
+
const eventOutput = await this.inngest.send({
|
|
82
|
+
name: `workflow.${this.workflowId}`,
|
|
83
|
+
data: {
|
|
84
|
+
inputData: params.resumeData,
|
|
85
|
+
runId: this.runId,
|
|
86
|
+
stepResults: snapshot?.context,
|
|
87
|
+
resume: {
|
|
88
|
+
steps,
|
|
89
|
+
stepResults: snapshot?.context,
|
|
90
|
+
resumePayload: params.resumeData,
|
|
91
|
+
// @ts-ignore
|
|
92
|
+
resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
const eventId = eventOutput.ids[0];
|
|
97
|
+
if (!eventId) {
|
|
98
|
+
throw new Error("Event ID is not set");
|
|
99
|
+
}
|
|
100
|
+
const runOutput = await this.getRunOutput(eventId);
|
|
101
|
+
const result = runOutput?.output?.result;
|
|
102
|
+
if (result.status === "failed") {
|
|
103
|
+
result.error = new Error(result.error);
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
watch(cb) {
|
|
108
|
+
const streamPromise = realtime.subscribe(
|
|
109
|
+
{
|
|
110
|
+
channel: `workflow:${this.workflowId}:${this.runId}`,
|
|
111
|
+
topics: ["watch"],
|
|
112
|
+
app: this.inngest
|
|
113
|
+
},
|
|
114
|
+
(message) => {
|
|
115
|
+
cb(message.data);
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
return () => {
|
|
119
|
+
streamPromise.then((stream) => {
|
|
120
|
+
stream.cancel();
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
var InngestWorkflow = class _InngestWorkflow extends vNext.NewWorkflow {
|
|
126
|
+
#mastra;
|
|
127
|
+
inngest;
|
|
128
|
+
function;
|
|
129
|
+
constructor(params, inngest) {
|
|
130
|
+
super(params);
|
|
131
|
+
this.#mastra = params.mastra;
|
|
132
|
+
this.inngest = inngest;
|
|
133
|
+
}
|
|
134
|
+
__registerMastra(mastra) {
|
|
135
|
+
this.#mastra = mastra;
|
|
136
|
+
this.executionEngine.__registerMastra(mastra);
|
|
137
|
+
if (this.executionGraph.steps.length) {
|
|
138
|
+
for (const step of this.executionGraph.steps) {
|
|
139
|
+
if (step.type === "step" && step.step instanceof _InngestWorkflow) {
|
|
140
|
+
step.step.__registerMastra(mastra);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
createRun(options) {
|
|
146
|
+
const runIdToUse = options?.runId || crypto.randomUUID();
|
|
147
|
+
return new InngestRun(
|
|
148
|
+
{
|
|
149
|
+
workflowId: this.id,
|
|
150
|
+
runId: runIdToUse,
|
|
151
|
+
executionEngine: this.executionEngine,
|
|
152
|
+
executionGraph: this.executionGraph,
|
|
153
|
+
mastra: this.#mastra,
|
|
154
|
+
retryConfig: this.retryConfig
|
|
155
|
+
},
|
|
156
|
+
this.inngest
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
getFunction() {
|
|
160
|
+
if (this.function) {
|
|
161
|
+
return this.function;
|
|
162
|
+
}
|
|
163
|
+
this.function = this.inngest.createFunction(
|
|
164
|
+
// @ts-ignore
|
|
165
|
+
{ id: `workflow.${this.id}`, retries: this.retryConfig?.attempts ?? 0 },
|
|
166
|
+
{ event: `workflow.${this.id}` },
|
|
167
|
+
async ({ event, step, attempt, publish }) => {
|
|
168
|
+
let { inputData, runId, resume } = event.data;
|
|
169
|
+
if (!runId) {
|
|
170
|
+
runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
|
|
171
|
+
return crypto.randomUUID();
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
const emitter = {
|
|
175
|
+
emit: async (event2, data) => {
|
|
176
|
+
if (!publish) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
await publish({
|
|
181
|
+
channel: `workflow:${this.id}:${runId}`,
|
|
182
|
+
topic: "watch",
|
|
183
|
+
data
|
|
184
|
+
});
|
|
185
|
+
} catch (err) {
|
|
186
|
+
this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
|
|
191
|
+
const result = await engine.execute({
|
|
192
|
+
workflowId: this.id,
|
|
193
|
+
runId,
|
|
194
|
+
graph: this.executionGraph,
|
|
195
|
+
input: inputData,
|
|
196
|
+
emitter,
|
|
197
|
+
retryConfig: this.retryConfig,
|
|
198
|
+
runtimeContext: new di.RuntimeContext(),
|
|
199
|
+
// TODO
|
|
200
|
+
resume
|
|
201
|
+
});
|
|
202
|
+
return { result, runId };
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
return this.function;
|
|
206
|
+
}
|
|
207
|
+
getNestedFunctions(steps) {
|
|
208
|
+
return steps.flatMap((step) => {
|
|
209
|
+
if (step.type === "step" || step.type === "loop" || step.type === "foreach") {
|
|
210
|
+
if (step.step instanceof _InngestWorkflow) {
|
|
211
|
+
return [step.step.getFunction(), ...step.step.getNestedFunctions(step.step.executionGraph.steps)];
|
|
212
|
+
}
|
|
213
|
+
return [];
|
|
214
|
+
} else if (step.type === "parallel" || step.type === "conditional") {
|
|
215
|
+
return this.getNestedFunctions(step.steps);
|
|
216
|
+
}
|
|
217
|
+
return [];
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
getFunctions() {
|
|
221
|
+
return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
function cloneWorkflow(workflow, opts) {
|
|
225
|
+
const wf = new InngestWorkflow(
|
|
226
|
+
{
|
|
227
|
+
id: opts.id,
|
|
228
|
+
inputSchema: workflow.inputSchema,
|
|
229
|
+
outputSchema: workflow.outputSchema,
|
|
230
|
+
steps: workflow.stepDefs,
|
|
231
|
+
mastra: workflow.mastra
|
|
232
|
+
},
|
|
233
|
+
workflow.inngest
|
|
234
|
+
);
|
|
235
|
+
wf.setStepFlow(workflow.stepGraph);
|
|
236
|
+
wf.commit();
|
|
237
|
+
return wf;
|
|
238
|
+
}
|
|
239
|
+
function init(inngest) {
|
|
240
|
+
return {
|
|
241
|
+
createWorkflow(params) {
|
|
242
|
+
return new InngestWorkflow(params, inngest);
|
|
243
|
+
},
|
|
244
|
+
createStep: vNext.createStep,
|
|
245
|
+
cloneStep: vNext.cloneStep,
|
|
246
|
+
cloneWorkflow
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
|
|
250
|
+
inngestStep;
|
|
251
|
+
inngestAttempts;
|
|
252
|
+
constructor(mastra, inngestStep, inngestAttempts = 0) {
|
|
253
|
+
super({ mastra });
|
|
254
|
+
this.inngestStep = inngestStep;
|
|
255
|
+
this.inngestAttempts = inngestAttempts;
|
|
256
|
+
}
|
|
257
|
+
async fmtReturnValue(executionSpan, emitter, stepResults, lastOutput, error) {
|
|
258
|
+
const base = {
|
|
259
|
+
status: lastOutput.status,
|
|
260
|
+
steps: stepResults
|
|
261
|
+
};
|
|
262
|
+
if (lastOutput.status === "success") {
|
|
263
|
+
await emitter.emit("watch", {
|
|
264
|
+
type: "watch",
|
|
265
|
+
payload: {
|
|
266
|
+
workflowState: {
|
|
267
|
+
status: lastOutput.status,
|
|
268
|
+
steps: stepResults,
|
|
269
|
+
result: lastOutput.output
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
eventTimestamp: Date.now()
|
|
273
|
+
});
|
|
274
|
+
base.result = lastOutput.output;
|
|
275
|
+
} else if (lastOutput.status === "failed") {
|
|
276
|
+
base.error = error instanceof Error ? error?.stack ?? error.message : lastOutput?.error instanceof Error ? lastOutput.error.message : lastOutput.error ?? error ?? "Unknown error";
|
|
277
|
+
await emitter.emit("watch", {
|
|
278
|
+
type: "watch",
|
|
279
|
+
payload: {
|
|
280
|
+
workflowState: {
|
|
281
|
+
status: lastOutput.status,
|
|
282
|
+
steps: stepResults,
|
|
283
|
+
result: null,
|
|
284
|
+
error: base.error
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
eventTimestamp: Date.now()
|
|
288
|
+
});
|
|
289
|
+
} else if (lastOutput.status === "suspended") {
|
|
290
|
+
await emitter.emit("watch", {
|
|
291
|
+
type: "watch",
|
|
292
|
+
payload: {
|
|
293
|
+
workflowState: {
|
|
294
|
+
status: lastOutput.status,
|
|
295
|
+
steps: stepResults,
|
|
296
|
+
result: null,
|
|
297
|
+
error: null
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
eventTimestamp: Date.now()
|
|
301
|
+
});
|
|
302
|
+
const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
|
|
303
|
+
if (stepResult?.status === "suspended") {
|
|
304
|
+
const nestedPath = stepResult?.payload?.__workflow_meta?.path;
|
|
305
|
+
return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
|
|
306
|
+
}
|
|
307
|
+
return [];
|
|
308
|
+
});
|
|
309
|
+
base.suspended = suspendedStepIds;
|
|
310
|
+
}
|
|
311
|
+
executionSpan?.end();
|
|
312
|
+
return base;
|
|
313
|
+
}
|
|
314
|
+
async superExecuteStep({
|
|
315
|
+
workflowId,
|
|
316
|
+
runId,
|
|
317
|
+
step,
|
|
318
|
+
stepResults,
|
|
319
|
+
executionContext,
|
|
320
|
+
resume,
|
|
321
|
+
prevOutput,
|
|
322
|
+
emitter,
|
|
323
|
+
runtimeContext
|
|
324
|
+
}) {
|
|
325
|
+
return super.executeStep({
|
|
326
|
+
workflowId,
|
|
327
|
+
runId,
|
|
328
|
+
step,
|
|
329
|
+
stepResults,
|
|
330
|
+
executionContext,
|
|
331
|
+
resume,
|
|
332
|
+
prevOutput,
|
|
333
|
+
emitter,
|
|
334
|
+
runtimeContext
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
async executeStep({
|
|
338
|
+
step,
|
|
339
|
+
stepResults,
|
|
340
|
+
executionContext,
|
|
341
|
+
resume,
|
|
342
|
+
prevOutput,
|
|
343
|
+
emitter,
|
|
344
|
+
runtimeContext
|
|
345
|
+
}) {
|
|
346
|
+
await this.inngestStep.run(
|
|
347
|
+
`workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
|
|
348
|
+
async () => {
|
|
349
|
+
await emitter.emit("watch", {
|
|
350
|
+
type: "watch",
|
|
351
|
+
payload: {
|
|
352
|
+
currentStep: {
|
|
353
|
+
id: step.id,
|
|
354
|
+
status: "running"
|
|
355
|
+
},
|
|
356
|
+
workflowState: {
|
|
357
|
+
status: "running",
|
|
358
|
+
steps: {
|
|
359
|
+
...stepResults,
|
|
360
|
+
[step.id]: {
|
|
361
|
+
status: "running"
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
result: null,
|
|
365
|
+
error: null
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
eventTimestamp: Date.now()
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
);
|
|
372
|
+
if (step instanceof InngestWorkflow) {
|
|
373
|
+
const isResume = !!resume?.steps?.length;
|
|
374
|
+
let result;
|
|
375
|
+
let runId;
|
|
376
|
+
if (isResume) {
|
|
377
|
+
runId = stepResults[resume?.steps?.[0]]?.payload?.__workflow_meta?.runId ?? crypto.randomUUID();
|
|
378
|
+
const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
|
|
379
|
+
workflowName: step.id,
|
|
380
|
+
runId
|
|
381
|
+
});
|
|
382
|
+
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
383
|
+
function: step.getFunction(),
|
|
384
|
+
data: {
|
|
385
|
+
inputData: prevOutput,
|
|
386
|
+
runId,
|
|
387
|
+
resume: {
|
|
388
|
+
runId,
|
|
389
|
+
steps: resume.steps.slice(1),
|
|
390
|
+
stepResults: snapshot?.context,
|
|
391
|
+
resumePayload: resume.resumePayload,
|
|
392
|
+
// @ts-ignore
|
|
393
|
+
resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
result = invokeResp.result;
|
|
398
|
+
runId = invokeResp.runId;
|
|
399
|
+
} else {
|
|
400
|
+
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
401
|
+
function: step.getFunction(),
|
|
402
|
+
data: {
|
|
403
|
+
inputData: prevOutput
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
result = invokeResp.result;
|
|
407
|
+
runId = invokeResp.runId;
|
|
408
|
+
}
|
|
409
|
+
const res = await this.inngestStep.run(
|
|
410
|
+
`workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
|
|
411
|
+
async () => {
|
|
412
|
+
if (result.status === "failed") {
|
|
413
|
+
await emitter.emit("watch", {
|
|
414
|
+
type: "watch",
|
|
415
|
+
payload: {
|
|
416
|
+
currentStep: {
|
|
417
|
+
id: step.id,
|
|
418
|
+
status: "failed",
|
|
419
|
+
error: result?.error
|
|
420
|
+
},
|
|
421
|
+
workflowState: {
|
|
422
|
+
status: "running",
|
|
423
|
+
steps: stepResults,
|
|
424
|
+
result: null,
|
|
425
|
+
error: null
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
eventTimestamp: Date.now()
|
|
429
|
+
});
|
|
430
|
+
return { executionContext, result: { status: "failed", error: result?.error } };
|
|
431
|
+
} else if (result.status === "suspended") {
|
|
432
|
+
const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
|
|
433
|
+
const stepRes2 = stepResult;
|
|
434
|
+
return stepRes2?.status === "suspended";
|
|
435
|
+
});
|
|
436
|
+
for (const [stepName, stepResult] of suspendedSteps) {
|
|
437
|
+
const suspendPath = [stepName, ...stepResult?.payload?.__workflow_meta?.path ?? []];
|
|
438
|
+
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
439
|
+
await emitter.emit("watch", {
|
|
440
|
+
type: "watch",
|
|
441
|
+
payload: {
|
|
442
|
+
currentStep: {
|
|
443
|
+
id: step.id,
|
|
444
|
+
status: "suspended",
|
|
445
|
+
payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
|
|
446
|
+
},
|
|
447
|
+
workflowState: {
|
|
448
|
+
status: "running",
|
|
449
|
+
steps: stepResults,
|
|
450
|
+
result: null,
|
|
451
|
+
error: null
|
|
452
|
+
}
|
|
453
|
+
},
|
|
454
|
+
eventTimestamp: Date.now()
|
|
455
|
+
});
|
|
456
|
+
return {
|
|
457
|
+
executionContext,
|
|
458
|
+
result: {
|
|
459
|
+
status: "suspended",
|
|
460
|
+
payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
await emitter.emit("watch", {
|
|
465
|
+
type: "watch",
|
|
466
|
+
payload: {
|
|
467
|
+
currentStep: {
|
|
468
|
+
id: step.id,
|
|
469
|
+
status: "suspended",
|
|
470
|
+
payload: {}
|
|
471
|
+
},
|
|
472
|
+
workflowState: {
|
|
473
|
+
status: "running",
|
|
474
|
+
steps: stepResults,
|
|
475
|
+
result: null,
|
|
476
|
+
error: null
|
|
477
|
+
}
|
|
478
|
+
},
|
|
479
|
+
eventTimestamp: Date.now()
|
|
480
|
+
});
|
|
481
|
+
return {
|
|
482
|
+
executionContext,
|
|
483
|
+
result: {
|
|
484
|
+
status: "suspended",
|
|
485
|
+
payload: {}
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
await emitter.emit("watch", {
|
|
490
|
+
type: "watch",
|
|
491
|
+
payload: {
|
|
492
|
+
currentStep: {
|
|
493
|
+
id: step.id,
|
|
494
|
+
status: "success",
|
|
495
|
+
output: result?.result
|
|
496
|
+
},
|
|
497
|
+
workflowState: {
|
|
498
|
+
status: "running",
|
|
499
|
+
steps: stepResults,
|
|
500
|
+
result: null,
|
|
501
|
+
error: null
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
eventTimestamp: Date.now()
|
|
505
|
+
});
|
|
506
|
+
return { executionContext, result: { status: "success", output: result?.result } };
|
|
507
|
+
}
|
|
508
|
+
);
|
|
509
|
+
Object.assign(executionContext, res.executionContext);
|
|
510
|
+
return res.result;
|
|
511
|
+
}
|
|
512
|
+
const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
|
|
513
|
+
let execResults;
|
|
514
|
+
let suspended;
|
|
515
|
+
try {
|
|
516
|
+
const result = await step.execute({
|
|
517
|
+
mastra: this.mastra,
|
|
518
|
+
runtimeContext,
|
|
519
|
+
inputData: prevOutput,
|
|
520
|
+
resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
|
|
521
|
+
getInitData: () => stepResults?.input,
|
|
522
|
+
getStepResult: (step2) => {
|
|
523
|
+
const result2 = stepResults[step2.id];
|
|
524
|
+
if (result2?.status === "success") {
|
|
525
|
+
return result2.output;
|
|
526
|
+
}
|
|
527
|
+
return null;
|
|
528
|
+
},
|
|
529
|
+
suspend: async (suspendPayload) => {
|
|
530
|
+
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
531
|
+
suspended = { payload: suspendPayload };
|
|
532
|
+
},
|
|
533
|
+
resume: {
|
|
534
|
+
steps: resume?.steps?.slice(1) || [],
|
|
535
|
+
resumePayload: resume?.resumePayload,
|
|
536
|
+
// @ts-ignore
|
|
537
|
+
runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
|
|
538
|
+
},
|
|
539
|
+
emitter
|
|
540
|
+
});
|
|
541
|
+
execResults = { status: "success", output: result };
|
|
542
|
+
} catch (e) {
|
|
543
|
+
execResults = { status: "failed", error: e instanceof Error ? e.message : String(e) };
|
|
544
|
+
}
|
|
545
|
+
if (suspended) {
|
|
546
|
+
execResults = { status: "suspended", payload: suspended.payload };
|
|
547
|
+
}
|
|
548
|
+
if (execResults.status === "failed") {
|
|
549
|
+
if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
|
|
550
|
+
throw execResults.error;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
await emitter.emit("watch", {
|
|
554
|
+
type: "watch",
|
|
555
|
+
payload: {
|
|
556
|
+
currentStep: {
|
|
557
|
+
id: step.id,
|
|
558
|
+
status: execResults.status,
|
|
559
|
+
output: execResults.output
|
|
560
|
+
},
|
|
561
|
+
workflowState: {
|
|
562
|
+
status: "running",
|
|
563
|
+
steps: stepResults,
|
|
564
|
+
result: null,
|
|
565
|
+
error: null
|
|
566
|
+
}
|
|
567
|
+
},
|
|
568
|
+
eventTimestamp: Date.now()
|
|
569
|
+
});
|
|
570
|
+
return { result: execResults, executionContext, stepResults };
|
|
571
|
+
});
|
|
572
|
+
Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
|
|
573
|
+
Object.assign(stepResults, stepRes.stepResults);
|
|
574
|
+
return stepRes.result;
|
|
575
|
+
}
|
|
576
|
+
async persistStepUpdate({
|
|
577
|
+
workflowId,
|
|
578
|
+
runId,
|
|
579
|
+
stepResults,
|
|
580
|
+
executionContext
|
|
581
|
+
}) {
|
|
582
|
+
await this.inngestStep.run(
|
|
583
|
+
`workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
|
|
584
|
+
async () => {
|
|
585
|
+
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
586
|
+
workflowName: workflowId,
|
|
587
|
+
runId,
|
|
588
|
+
snapshot: {
|
|
589
|
+
runId,
|
|
590
|
+
value: {},
|
|
591
|
+
context: stepResults,
|
|
592
|
+
activePaths: [],
|
|
593
|
+
suspendedPaths: executionContext.suspendedPaths,
|
|
594
|
+
// @ts-ignore
|
|
595
|
+
timestamp: Date.now()
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
async executeConditional({
|
|
602
|
+
workflowId,
|
|
603
|
+
runId,
|
|
604
|
+
entry,
|
|
605
|
+
prevOutput,
|
|
606
|
+
prevStep,
|
|
607
|
+
stepResults,
|
|
608
|
+
resume,
|
|
609
|
+
executionContext,
|
|
610
|
+
emitter,
|
|
611
|
+
runtimeContext
|
|
612
|
+
}) {
|
|
613
|
+
let execResults;
|
|
614
|
+
const truthyIndexes = (await Promise.all(
|
|
615
|
+
entry.conditions.map(
|
|
616
|
+
(cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
|
|
617
|
+
try {
|
|
618
|
+
const result = await cond({
|
|
619
|
+
mastra: this.mastra,
|
|
620
|
+
runtimeContext,
|
|
621
|
+
inputData: prevOutput,
|
|
622
|
+
getInitData: () => stepResults?.input,
|
|
623
|
+
getStepResult: (step) => {
|
|
624
|
+
if (!step?.id) {
|
|
625
|
+
return null;
|
|
626
|
+
}
|
|
627
|
+
const result2 = stepResults[step.id];
|
|
628
|
+
if (result2?.status === "success") {
|
|
629
|
+
return result2.output;
|
|
630
|
+
}
|
|
631
|
+
return null;
|
|
632
|
+
},
|
|
633
|
+
// TODO: this function shouldn't have suspend probably?
|
|
634
|
+
suspend: async (_suspendPayload) => {
|
|
635
|
+
},
|
|
636
|
+
emitter
|
|
637
|
+
});
|
|
638
|
+
return result ? index : null;
|
|
639
|
+
} catch (e) {
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
})
|
|
643
|
+
)
|
|
644
|
+
)).filter((index) => index !== null);
|
|
645
|
+
const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
|
|
646
|
+
const results = await Promise.all(
|
|
647
|
+
stepsToRun.map(
|
|
648
|
+
(step, index) => this.executeEntry({
|
|
649
|
+
workflowId,
|
|
650
|
+
runId,
|
|
651
|
+
entry: step,
|
|
652
|
+
prevStep,
|
|
653
|
+
stepResults,
|
|
654
|
+
resume,
|
|
655
|
+
executionContext: {
|
|
656
|
+
workflowId,
|
|
657
|
+
runId,
|
|
658
|
+
executionPath: [...executionContext.executionPath, index],
|
|
659
|
+
suspendedPaths: executionContext.suspendedPaths,
|
|
660
|
+
retryConfig: executionContext.retryConfig,
|
|
661
|
+
executionSpan: executionContext.executionSpan
|
|
662
|
+
},
|
|
663
|
+
emitter,
|
|
664
|
+
runtimeContext
|
|
665
|
+
})
|
|
666
|
+
)
|
|
667
|
+
);
|
|
668
|
+
const hasFailed = results.find((result) => result.status === "failed");
|
|
669
|
+
const hasSuspended = results.find((result) => result.status === "suspended");
|
|
670
|
+
if (hasFailed) {
|
|
671
|
+
execResults = { status: "failed", error: hasFailed.error };
|
|
672
|
+
} else if (hasSuspended) {
|
|
673
|
+
execResults = { status: "suspended", payload: hasSuspended.payload };
|
|
674
|
+
} else {
|
|
675
|
+
execResults = {
|
|
676
|
+
status: "success",
|
|
677
|
+
output: results.reduce((acc, result, index) => {
|
|
678
|
+
if (result.status === "success") {
|
|
679
|
+
acc[stepsToRun[index].step.id] = result.output;
|
|
680
|
+
}
|
|
681
|
+
return acc;
|
|
682
|
+
}, {})
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
return execResults;
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
exports.InngestExecutionEngine = InngestExecutionEngine;
|
|
690
|
+
exports.InngestRun = InngestRun;
|
|
691
|
+
exports.InngestWorkflow = InngestWorkflow;
|
|
692
|
+
exports.init = init;
|
|
693
|
+
exports.serve = serve;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { serve } from './_tsup-dts-rollup.cjs';
|
|
2
|
+
export { init } from './_tsup-dts-rollup.cjs';
|
|
3
|
+
export { InngestRun } from './_tsup-dts-rollup.cjs';
|
|
4
|
+
export { InngestWorkflow } from './_tsup-dts-rollup.cjs';
|
|
5
|
+
export { InngestExecutionEngine } from './_tsup-dts-rollup.cjs';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { serve } from './_tsup-dts-rollup.js';
|
|
2
|
+
export { init } from './_tsup-dts-rollup.js';
|
|
3
|
+
export { InngestRun } from './_tsup-dts-rollup.js';
|
|
4
|
+
export { InngestWorkflow } from './_tsup-dts-rollup.js';
|
|
5
|
+
export { InngestExecutionEngine } from './_tsup-dts-rollup.js';
|