@upstash/workflow 0.2.11 → 0.2.13

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/nextjs.js CHANGED
@@ -94,11 +94,12 @@ var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
94
94
  var DEFAULT_CONTENT_TYPE = "application/json";
95
95
  var NO_CONCURRENCY = 1;
96
96
  var DEFAULT_RETRIES = 3;
97
- var VERSION = "v0.2.7";
97
+ var VERSION = "v0.2.13";
98
98
  var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
99
99
  var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
100
100
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
101
101
  var TELEMETRY_HEADER_RUNTIME = "Upstash-Telemetry-Runtime";
102
+ var TELEMETRY_HEADER_AGENT = "Upstash-Telemetry-Agent";
102
103
 
103
104
  // src/error.ts
104
105
  var import_qstash2 = require("@upstash/qstash");
@@ -137,10 +138,16 @@ var formatWorkflowError = (error) => {
137
138
  message: error.message
138
139
  } : {
139
140
  error: "Error",
140
- message: "An error occured while executing workflow."
141
+ message: `An error occured while executing workflow: '${typeof error === "string" ? error : JSON.stringify(error)}'`
141
142
  };
142
143
  };
143
144
 
145
+ // src/context/auto-executor.ts
146
+ var import_qstash5 = require("@upstash/qstash");
147
+
148
+ // src/qstash/headers.ts
149
+ var import_qstash4 = require("@upstash/qstash");
150
+
144
151
  // src/utils.ts
145
152
  var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
146
153
  var NANOID_LENGTH = 21;
@@ -166,574 +173,231 @@ function decodeBase64(base64) {
166
173
  }
167
174
  }
168
175
 
169
- // src/context/steps.ts
170
- var BaseLazyStep = class _BaseLazyStep {
171
- stepName;
172
- constructor(stepName) {
173
- if (!stepName) {
174
- throw new WorkflowError(
175
- "A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
176
- );
177
- }
178
- this.stepName = stepName;
176
+ // node_modules/neverthrow/dist/index.es.js
177
+ var defaultErrorConfig = {
178
+ withStackTrace: false
179
+ };
180
+ var createNeverThrowError = (message, result, config = defaultErrorConfig) => {
181
+ const data = result.isOk() ? { type: "Ok", value: result.value } : { type: "Err", value: result.error };
182
+ const maybeStack = config.withStackTrace ? new Error().stack : void 0;
183
+ return {
184
+ data,
185
+ message,
186
+ stack: maybeStack
187
+ };
188
+ };
189
+ function __awaiter(thisArg, _arguments, P, generator) {
190
+ function adopt(value) {
191
+ return value instanceof P ? value : new P(function(resolve) {
192
+ resolve(value);
193
+ });
179
194
  }
180
- /**
181
- * parse the out field of a step result.
182
- *
183
- * will be called when returning the steps to the context from auto executor
184
- *
185
- * @param out field of the step
186
- * @returns parsed out field
187
- */
188
- parseOut(out) {
189
- if (out === void 0) {
190
- if (this.allowUndefinedOut) {
191
- return void 0;
192
- } else {
193
- throw new WorkflowError(
194
- `Error while parsing output of ${this.stepType} step. Expected a string, but got: undefined`
195
- );
195
+ return new (P || (P = Promise))(function(resolve, reject) {
196
+ function fulfilled(value) {
197
+ try {
198
+ step(generator.next(value));
199
+ } catch (e) {
200
+ reject(e);
196
201
  }
197
202
  }
198
- if (typeof out === "object") {
199
- if (this.stepType !== "Wait") {
200
- console.warn(
201
- `Error while parsing ${this.stepType} step output. Expected a string, but got object. Please reach out to Upstash Support.`
202
- );
203
- return out;
203
+ function rejected(value) {
204
+ try {
205
+ step(generator["throw"](value));
206
+ } catch (e) {
207
+ reject(e);
204
208
  }
205
- return {
206
- ...out,
207
- eventData: _BaseLazyStep.tryParsing(out.eventData)
208
- };
209
209
  }
210
- if (typeof out !== "string") {
211
- throw new WorkflowError(
212
- `Error while parsing output of ${this.stepType} step. Expected a string or undefined, but got: ${typeof out}`
213
- );
210
+ function step(result) {
211
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
214
212
  }
215
- return this.safeParseOut(out);
216
- }
217
- safeParseOut(out) {
218
- return _BaseLazyStep.tryParsing(out);
213
+ step((generator = generator.apply(thisArg, [])).next());
214
+ });
215
+ }
216
+ function __values(o) {
217
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
218
+ if (m) return m.call(o);
219
+ if (o && typeof o.length === "number") return {
220
+ next: function() {
221
+ if (o && i >= o.length) o = void 0;
222
+ return { value: o && o[i++], done: !o };
223
+ }
224
+ };
225
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
226
+ }
227
+ function __await(v) {
228
+ return this instanceof __await ? (this.v = v, this) : new __await(v);
229
+ }
230
+ function __asyncGenerator(thisArg, _arguments, generator) {
231
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
232
+ var g = generator.apply(thisArg, _arguments || []), i, q = [];
233
+ return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {
234
+ return this;
235
+ }, i;
236
+ function verb(n) {
237
+ if (g[n]) i[n] = function(v) {
238
+ return new Promise(function(a, b) {
239
+ q.push([n, v, a, b]) > 1 || resume(n, v);
240
+ });
241
+ };
219
242
  }
220
- static tryParsing(stepOut) {
243
+ function resume(n, v) {
221
244
  try {
222
- return JSON.parse(stepOut);
223
- } catch {
224
- return stepOut;
245
+ step(g[n](v));
246
+ } catch (e) {
247
+ settle(q[0][3], e);
225
248
  }
226
249
  }
227
- };
228
- var LazyFunctionStep = class extends BaseLazyStep {
229
- stepFunction;
230
- stepType = "Run";
231
- allowUndefinedOut = true;
232
- constructor(stepName, stepFunction) {
233
- super(stepName);
234
- this.stepFunction = stepFunction;
250
+ function step(r) {
251
+ r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r);
235
252
  }
236
- getPlanStep(concurrent, targetStep) {
237
- return {
238
- stepId: 0,
239
- stepName: this.stepName,
240
- stepType: this.stepType,
241
- concurrent,
242
- targetStep
243
- };
253
+ function fulfill(value) {
254
+ resume("next", value);
244
255
  }
245
- async getResultStep(concurrent, stepId) {
246
- let result = this.stepFunction();
247
- if (result instanceof Promise) {
248
- result = await result;
249
- }
250
- return {
251
- stepId,
252
- stepName: this.stepName,
253
- stepType: this.stepType,
254
- out: result,
255
- concurrent
256
- };
256
+ function reject(value) {
257
+ resume("throw", value);
257
258
  }
258
- };
259
- var LazySleepStep = class extends BaseLazyStep {
260
- sleep;
261
- stepType = "SleepFor";
262
- allowUndefinedOut = true;
263
- constructor(stepName, sleep) {
264
- super(stepName);
265
- this.sleep = sleep;
259
+ function settle(f, v) {
260
+ if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]);
266
261
  }
267
- getPlanStep(concurrent, targetStep) {
268
- return {
269
- stepId: 0,
270
- stepName: this.stepName,
271
- stepType: this.stepType,
272
- sleepFor: this.sleep,
273
- concurrent,
274
- targetStep
262
+ }
263
+ function __asyncDelegator(o) {
264
+ var i, p;
265
+ return i = {}, verb("next"), verb("throw", function(e) {
266
+ throw e;
267
+ }), verb("return"), i[Symbol.iterator] = function() {
268
+ return this;
269
+ }, i;
270
+ function verb(n, f) {
271
+ i[n] = o[n] ? function(v) {
272
+ return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v;
273
+ } : f;
274
+ }
275
+ }
276
+ function __asyncValues(o) {
277
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
278
+ var m = o[Symbol.asyncIterator], i;
279
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {
280
+ return this;
281
+ }, i);
282
+ function verb(n) {
283
+ i[n] = o[n] && function(v) {
284
+ return new Promise(function(resolve, reject) {
285
+ v = o[n](v), settle(resolve, reject, v.done, v.value);
286
+ });
275
287
  };
276
288
  }
277
- async getResultStep(concurrent, stepId) {
278
- return await Promise.resolve({
279
- stepId,
280
- stepName: this.stepName,
281
- stepType: this.stepType,
282
- sleepFor: this.sleep,
283
- concurrent
284
- });
289
+ function settle(resolve, reject, d, v) {
290
+ Promise.resolve(v).then(function(v2) {
291
+ resolve({ value: v2, done: d });
292
+ }, reject);
285
293
  }
286
- };
287
- var LazySleepUntilStep = class extends BaseLazyStep {
288
- sleepUntil;
289
- stepType = "SleepUntil";
290
- allowUndefinedOut = true;
291
- constructor(stepName, sleepUntil) {
292
- super(stepName);
293
- this.sleepUntil = sleepUntil;
294
+ }
295
+ var ResultAsync = class _ResultAsync {
296
+ constructor(res) {
297
+ this._promise = res;
294
298
  }
295
- getPlanStep(concurrent, targetStep) {
296
- return {
297
- stepId: 0,
298
- stepName: this.stepName,
299
- stepType: this.stepType,
300
- sleepUntil: this.sleepUntil,
301
- concurrent,
302
- targetStep
303
- };
299
+ static fromSafePromise(promise) {
300
+ const newPromise = promise.then((value) => new Ok(value));
301
+ return new _ResultAsync(newPromise);
304
302
  }
305
- async getResultStep(concurrent, stepId) {
306
- return await Promise.resolve({
307
- stepId,
308
- stepName: this.stepName,
309
- stepType: this.stepType,
310
- sleepUntil: this.sleepUntil,
311
- concurrent
312
- });
303
+ static fromPromise(promise, errorFn) {
304
+ const newPromise = promise.then((value) => new Ok(value)).catch((e) => new Err(errorFn(e)));
305
+ return new _ResultAsync(newPromise);
313
306
  }
314
- safeParseOut() {
315
- return void 0;
307
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
308
+ static fromThrowable(fn, errorFn) {
309
+ return (...args) => {
310
+ return new _ResultAsync((() => __awaiter(this, void 0, void 0, function* () {
311
+ try {
312
+ return new Ok(yield fn(...args));
313
+ } catch (error) {
314
+ return new Err(errorFn ? errorFn(error) : error);
315
+ }
316
+ }))());
317
+ };
316
318
  }
317
- };
318
- var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
319
- url;
320
- method;
321
- body;
322
- headers;
323
- retries;
324
- timeout;
325
- flowControl;
326
- stepType = "Call";
327
- allowUndefinedOut = false;
328
- constructor(stepName, url, method, body, headers, retries, timeout, flowControl) {
329
- super(stepName);
330
- this.url = url;
331
- this.method = method;
332
- this.body = body;
333
- this.headers = headers;
334
- this.retries = retries;
335
- this.timeout = timeout;
336
- this.flowControl = flowControl;
337
- }
338
- getPlanStep(concurrent, targetStep) {
339
- return {
340
- stepId: 0,
341
- stepName: this.stepName,
342
- stepType: this.stepType,
343
- concurrent,
344
- targetStep
345
- };
319
+ static combine(asyncResultList) {
320
+ return combineResultAsyncList(asyncResultList);
346
321
  }
347
- async getResultStep(concurrent, stepId) {
348
- return await Promise.resolve({
349
- stepId,
350
- stepName: this.stepName,
351
- stepType: this.stepType,
352
- concurrent,
353
- callUrl: this.url,
354
- callMethod: this.method,
355
- callBody: this.body,
356
- callHeaders: this.headers
357
- });
322
+ static combineWithAllErrors(asyncResultList) {
323
+ return combineResultAsyncListWithAllErrors(asyncResultList);
358
324
  }
359
- safeParseOut(out) {
360
- const { header, status, body } = JSON.parse(out);
361
- const responseHeaders = new Headers(header);
362
- if (_LazyCallStep.isText(responseHeaders.get("content-type"))) {
363
- const bytes = new Uint8Array(out.length);
364
- for (let i = 0; i < out.length; i++) {
365
- bytes[i] = out.charCodeAt(i);
325
+ map(f) {
326
+ return new _ResultAsync(this._promise.then((res) => __awaiter(this, void 0, void 0, function* () {
327
+ if (res.isErr()) {
328
+ return new Err(res.error);
366
329
  }
367
- const processedResult = new TextDecoder().decode(bytes);
368
- const newBody = JSON.parse(processedResult).body;
369
- return {
370
- status,
371
- header,
372
- body: BaseLazyStep.tryParsing(newBody)
373
- };
374
- } else {
375
- return { header, status, body };
376
- }
377
- }
378
- static applicationHeaders = /* @__PURE__ */ new Set([
379
- "application/json",
380
- "application/xml",
381
- "application/javascript",
382
- "application/x-www-form-urlencoded",
383
- "application/xhtml+xml",
384
- "application/ld+json",
385
- "application/rss+xml",
386
- "application/atom+xml"
387
- ]);
388
- static isText = (contentTypeHeader) => {
389
- if (!contentTypeHeader) {
390
- return false;
391
- }
392
- if (_LazyCallStep.applicationHeaders.has(contentTypeHeader)) {
393
- return true;
394
- }
395
- if (contentTypeHeader.startsWith("text/")) {
396
- return true;
397
- }
398
- return false;
399
- };
400
- };
401
- var LazyWaitForEventStep = class extends BaseLazyStep {
402
- eventId;
403
- timeout;
404
- stepType = "Wait";
405
- allowUndefinedOut = false;
406
- constructor(stepName, eventId, timeout) {
407
- super(stepName);
408
- this.eventId = eventId;
409
- this.timeout = timeout;
330
+ return new Ok(yield f(res.value));
331
+ })));
410
332
  }
411
- getPlanStep(concurrent, targetStep) {
412
- return {
413
- stepId: 0,
414
- stepName: this.stepName,
415
- stepType: this.stepType,
416
- waitEventId: this.eventId,
417
- timeout: this.timeout,
418
- concurrent,
419
- targetStep
420
- };
333
+ andThrough(f) {
334
+ return new _ResultAsync(this._promise.then((res) => __awaiter(this, void 0, void 0, function* () {
335
+ if (res.isErr()) {
336
+ return new Err(res.error);
337
+ }
338
+ const newRes = yield f(res.value);
339
+ if (newRes.isErr()) {
340
+ return new Err(newRes.error);
341
+ }
342
+ return new Ok(res.value);
343
+ })));
421
344
  }
422
- async getResultStep(concurrent, stepId) {
423
- return await Promise.resolve({
424
- stepId,
425
- stepName: this.stepName,
426
- stepType: this.stepType,
427
- waitEventId: this.eventId,
428
- timeout: this.timeout,
429
- concurrent
430
- });
345
+ andTee(f) {
346
+ return new _ResultAsync(this._promise.then((res) => __awaiter(this, void 0, void 0, function* () {
347
+ if (res.isErr()) {
348
+ return new Err(res.error);
349
+ }
350
+ try {
351
+ yield f(res.value);
352
+ } catch (e) {
353
+ }
354
+ return new Ok(res.value);
355
+ })));
431
356
  }
432
- safeParseOut(out) {
433
- const result = JSON.parse(out);
434
- return {
435
- ...result,
436
- eventData: BaseLazyStep.tryParsing(result.eventData)
437
- };
357
+ mapErr(f) {
358
+ return new _ResultAsync(this._promise.then((res) => __awaiter(this, void 0, void 0, function* () {
359
+ if (res.isOk()) {
360
+ return new Ok(res.value);
361
+ }
362
+ return new Err(yield f(res.error));
363
+ })));
438
364
  }
439
- };
440
- var LazyNotifyStep = class extends LazyFunctionStep {
441
- stepType = "Notify";
442
- constructor(stepName, eventId, eventData, requester) {
443
- super(stepName, async () => {
444
- const notifyResponse = await makeNotifyRequest(requester, eventId, eventData);
445
- return {
446
- eventId,
447
- eventData,
448
- notifyResponse
449
- };
450
- });
365
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
366
+ andThen(f) {
367
+ return new _ResultAsync(this._promise.then((res) => {
368
+ if (res.isErr()) {
369
+ return new Err(res.error);
370
+ }
371
+ const newValue = f(res.value);
372
+ return newValue instanceof _ResultAsync ? newValue._promise : newValue;
373
+ }));
451
374
  }
452
- safeParseOut(out) {
453
- const result = JSON.parse(out);
454
- return {
455
- ...result,
456
- eventData: BaseLazyStep.tryParsing(result.eventData)
457
- };
375
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
376
+ orElse(f) {
377
+ return new _ResultAsync(this._promise.then((res) => __awaiter(this, void 0, void 0, function* () {
378
+ if (res.isErr()) {
379
+ return f(res.error);
380
+ }
381
+ return new Ok(res.value);
382
+ })));
458
383
  }
459
- };
460
- var LazyInvokeStep = class extends BaseLazyStep {
461
- stepType = "Invoke";
462
- params;
463
- allowUndefinedOut = false;
464
- constructor(stepName, {
465
- workflow,
466
- body,
467
- headers = {},
468
- workflowRunId,
469
- retries,
470
- flowControl
471
- }) {
472
- super(stepName);
473
- this.params = {
474
- workflow,
475
- body,
476
- headers,
477
- workflowRunId: getWorkflowRunId(workflowRunId),
478
- retries,
479
- flowControl
480
- };
384
+ match(ok2, _err) {
385
+ return this._promise.then((res) => res.match(ok2, _err));
481
386
  }
482
- getPlanStep(concurrent, targetStep) {
483
- return {
484
- stepId: 0,
485
- stepName: this.stepName,
486
- stepType: this.stepType,
487
- concurrent,
488
- targetStep
489
- };
387
+ unwrapOr(t) {
388
+ return this._promise.then((res) => res.unwrapOr(t));
490
389
  }
491
390
  /**
492
- * won't be used as it's the server who will add the result step
493
- * in Invoke step.
391
+ * Emulates Rust's `?` operator in `safeTry`'s body. See also `safeTry`.
494
392
  */
495
- getResultStep(concurrent, stepId) {
496
- return Promise.resolve({
497
- stepId,
498
- stepName: this.stepName,
499
- stepType: this.stepType,
500
- concurrent
393
+ safeUnwrap() {
394
+ return __asyncGenerator(this, arguments, function* safeUnwrap_1() {
395
+ return yield __await(yield __await(yield* __asyncDelegator(__asyncValues(yield __await(this._promise.then((res) => res.safeUnwrap()))))));
501
396
  });
502
397
  }
503
- safeParseOut(out) {
504
- const result = JSON.parse(out);
505
- return {
506
- ...result,
507
- body: BaseLazyStep.tryParsing(result.body)
508
- };
509
- }
510
- };
511
-
512
- // node_modules/neverthrow/dist/index.es.js
513
- var defaultErrorConfig = {
514
- withStackTrace: false
515
- };
516
- var createNeverThrowError = (message, result, config = defaultErrorConfig) => {
517
- const data = result.isOk() ? { type: "Ok", value: result.value } : { type: "Err", value: result.error };
518
- const maybeStack = config.withStackTrace ? new Error().stack : void 0;
519
- return {
520
- data,
521
- message,
522
- stack: maybeStack
523
- };
524
- };
525
- function __awaiter(thisArg, _arguments, P, generator) {
526
- function adopt(value) {
527
- return value instanceof P ? value : new P(function(resolve) {
528
- resolve(value);
529
- });
530
- }
531
- return new (P || (P = Promise))(function(resolve, reject) {
532
- function fulfilled(value) {
533
- try {
534
- step(generator.next(value));
535
- } catch (e) {
536
- reject(e);
537
- }
538
- }
539
- function rejected(value) {
540
- try {
541
- step(generator["throw"](value));
542
- } catch (e) {
543
- reject(e);
544
- }
545
- }
546
- function step(result) {
547
- result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
548
- }
549
- step((generator = generator.apply(thisArg, [])).next());
550
- });
551
- }
552
- function __values(o) {
553
- var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
554
- if (m) return m.call(o);
555
- if (o && typeof o.length === "number") return {
556
- next: function() {
557
- if (o && i >= o.length) o = void 0;
558
- return { value: o && o[i++], done: !o };
559
- }
560
- };
561
- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
562
- }
563
- function __await(v) {
564
- return this instanceof __await ? (this.v = v, this) : new __await(v);
565
- }
566
- function __asyncGenerator(thisArg, _arguments, generator) {
567
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
568
- var g = generator.apply(thisArg, _arguments || []), i, q = [];
569
- return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {
570
- return this;
571
- }, i;
572
- function verb(n) {
573
- if (g[n]) i[n] = function(v) {
574
- return new Promise(function(a, b) {
575
- q.push([n, v, a, b]) > 1 || resume(n, v);
576
- });
577
- };
578
- }
579
- function resume(n, v) {
580
- try {
581
- step(g[n](v));
582
- } catch (e) {
583
- settle(q[0][3], e);
584
- }
585
- }
586
- function step(r) {
587
- r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r);
588
- }
589
- function fulfill(value) {
590
- resume("next", value);
591
- }
592
- function reject(value) {
593
- resume("throw", value);
594
- }
595
- function settle(f, v) {
596
- if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]);
597
- }
598
- }
599
- function __asyncDelegator(o) {
600
- var i, p;
601
- return i = {}, verb("next"), verb("throw", function(e) {
602
- throw e;
603
- }), verb("return"), i[Symbol.iterator] = function() {
604
- return this;
605
- }, i;
606
- function verb(n, f) {
607
- i[n] = o[n] ? function(v) {
608
- return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v;
609
- } : f;
610
- }
611
- }
612
- function __asyncValues(o) {
613
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
614
- var m = o[Symbol.asyncIterator], i;
615
- return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {
616
- return this;
617
- }, i);
618
- function verb(n) {
619
- i[n] = o[n] && function(v) {
620
- return new Promise(function(resolve, reject) {
621
- v = o[n](v), settle(resolve, reject, v.done, v.value);
622
- });
623
- };
624
- }
625
- function settle(resolve, reject, d, v) {
626
- Promise.resolve(v).then(function(v2) {
627
- resolve({ value: v2, done: d });
628
- }, reject);
629
- }
630
- }
631
- var ResultAsync = class _ResultAsync {
632
- constructor(res) {
633
- this._promise = res;
634
- }
635
- static fromSafePromise(promise) {
636
- const newPromise = promise.then((value) => new Ok(value));
637
- return new _ResultAsync(newPromise);
638
- }
639
- static fromPromise(promise, errorFn) {
640
- const newPromise = promise.then((value) => new Ok(value)).catch((e) => new Err(errorFn(e)));
641
- return new _ResultAsync(newPromise);
642
- }
643
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
644
- static fromThrowable(fn, errorFn) {
645
- return (...args) => {
646
- return new _ResultAsync((() => __awaiter(this, void 0, void 0, function* () {
647
- try {
648
- return new Ok(yield fn(...args));
649
- } catch (error) {
650
- return new Err(errorFn ? errorFn(error) : error);
651
- }
652
- }))());
653
- };
654
- }
655
- static combine(asyncResultList) {
656
- return combineResultAsyncList(asyncResultList);
657
- }
658
- static combineWithAllErrors(asyncResultList) {
659
- return combineResultAsyncListWithAllErrors(asyncResultList);
660
- }
661
- map(f) {
662
- return new _ResultAsync(this._promise.then((res) => __awaiter(this, void 0, void 0, function* () {
663
- if (res.isErr()) {
664
- return new Err(res.error);
665
- }
666
- return new Ok(yield f(res.value));
667
- })));
668
- }
669
- andThrough(f) {
670
- return new _ResultAsync(this._promise.then((res) => __awaiter(this, void 0, void 0, function* () {
671
- if (res.isErr()) {
672
- return new Err(res.error);
673
- }
674
- const newRes = yield f(res.value);
675
- if (newRes.isErr()) {
676
- return new Err(newRes.error);
677
- }
678
- return new Ok(res.value);
679
- })));
680
- }
681
- andTee(f) {
682
- return new _ResultAsync(this._promise.then((res) => __awaiter(this, void 0, void 0, function* () {
683
- if (res.isErr()) {
684
- return new Err(res.error);
685
- }
686
- try {
687
- yield f(res.value);
688
- } catch (e) {
689
- }
690
- return new Ok(res.value);
691
- })));
692
- }
693
- mapErr(f) {
694
- return new _ResultAsync(this._promise.then((res) => __awaiter(this, void 0, void 0, function* () {
695
- if (res.isOk()) {
696
- return new Ok(res.value);
697
- }
698
- return new Err(yield f(res.error));
699
- })));
700
- }
701
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
702
- andThen(f) {
703
- return new _ResultAsync(this._promise.then((res) => {
704
- if (res.isErr()) {
705
- return new Err(res.error);
706
- }
707
- const newValue = f(res.value);
708
- return newValue instanceof _ResultAsync ? newValue._promise : newValue;
709
- }));
710
- }
711
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
712
- orElse(f) {
713
- return new _ResultAsync(this._promise.then((res) => __awaiter(this, void 0, void 0, function* () {
714
- if (res.isErr()) {
715
- return f(res.error);
716
- }
717
- return new Ok(res.value);
718
- })));
719
- }
720
- match(ok2, _err) {
721
- return this._promise.then((res) => res.match(ok2, _err));
722
- }
723
- unwrapOr(t) {
724
- return this._promise.then((res) => res.unwrapOr(t));
725
- }
726
- /**
727
- * Emulates Rust's `?` operator in `safeTry`'s body. See also `safeTry`.
728
- */
729
- safeUnwrap() {
730
- return __asyncGenerator(this, arguments, function* safeUnwrap_1() {
731
- return yield __await(yield __await(yield* __asyncDelegator(__asyncValues(yield __await(this._promise.then((res) => res.safeUnwrap()))))));
732
- });
733
- }
734
- // Makes ResultAsync implement PromiseLike<Result>
735
- then(successCallback, failureCallback) {
736
- return this._promise.then(successCallback, failureCallback);
398
+ // Makes ResultAsync implement PromiseLike<Result>
399
+ then(successCallback, failureCallback) {
400
+ return this._promise.then(successCallback, failureCallback);
737
401
  }
738
402
  };
739
403
  var errAsync = (err2) => new ResultAsync(Promise.resolve(new Err(err2)));
@@ -943,18 +607,22 @@ var triggerFirstInvocation = async ({
943
607
  useJSONContent,
944
608
  telemetry,
945
609
  debug,
946
- invokeCount
610
+ invokeCount,
611
+ delay
947
612
  }) => {
948
613
  const { headers } = getHeaders({
949
614
  initHeaderValue: "true",
950
- workflowRunId: workflowContext.workflowRunId,
951
- workflowUrl: workflowContext.url,
952
- userHeaders: workflowContext.headers,
953
- failureUrl: workflowContext.failureUrl,
954
- retries: workflowContext.retries,
955
- telemetry,
956
- invokeCount,
957
- flowControl: workflowContext.flowControl
615
+ workflowConfig: {
616
+ workflowRunId: workflowContext.workflowRunId,
617
+ workflowUrl: workflowContext.url,
618
+ failureUrl: workflowContext.failureUrl,
619
+ retries: workflowContext.retries,
620
+ telemetry,
621
+ flowControl: workflowContext.flowControl,
622
+ useJSONContent: useJSONContent ?? false
623
+ },
624
+ invokeCount: invokeCount ?? 0,
625
+ userHeaders: workflowContext.headers
958
626
  });
959
627
  if (workflowContext.headers.get("content-type")) {
960
628
  headers["content-type"] = workflowContext.headers.get("content-type");
@@ -968,7 +636,8 @@ var triggerFirstInvocation = async ({
968
636
  headers,
969
637
  method: "POST",
970
638
  body,
971
- url: workflowContext.url
639
+ url: workflowContext.url,
640
+ delay
972
641
  });
973
642
  if (result.deduplicated) {
974
643
  await debug?.log("WARN", "SUBMIT_FIRST_INVOCATION", {
@@ -1124,14 +793,16 @@ ${atob(callbackMessage.body ?? "")}`
1124
793
  const userHeaders = recreateUserHeaders(request.headers);
1125
794
  const { headers: requestHeaders } = getHeaders({
1126
795
  initHeaderValue: "false",
1127
- workflowRunId,
1128
- workflowUrl,
796
+ workflowConfig: {
797
+ workflowRunId,
798
+ workflowUrl,
799
+ failureUrl,
800
+ retries,
801
+ telemetry,
802
+ flowControl
803
+ },
1129
804
  userHeaders,
1130
- failureUrl,
1131
- retries,
1132
- telemetry,
1133
- invokeCount: Number(invokeCount),
1134
- flowControl
805
+ invokeCount: Number(invokeCount)
1135
806
  });
1136
807
  const callResponse = {
1137
808
  status: callbackMessage.status,
@@ -1177,329 +848,899 @@ var getTelemetryHeaders = (telemetry) => {
1177
848
  [TELEMETRY_HEADER_RUNTIME]: telemetry.runtime ?? "unknown"
1178
849
  };
1179
850
  };
1180
- var getHeaders = ({
1181
- initHeaderValue,
1182
- workflowRunId,
1183
- workflowUrl,
1184
- userHeaders,
1185
- failureUrl,
1186
- retries,
1187
- step,
1188
- callRetries,
1189
- callTimeout,
1190
- telemetry,
1191
- invokeCount,
1192
- flowControl,
1193
- callFlowControl
1194
- }) => {
1195
- const callHeaders = new Headers(step?.callHeaders);
1196
- const contentType = (callHeaders.get("content-type") ? callHeaders.get("content-type") : userHeaders?.get("Content-Type") ? userHeaders.get("Content-Type") : void 0) ?? DEFAULT_CONTENT_TYPE;
1197
- const baseHeaders = {
1198
- [WORKFLOW_INIT_HEADER]: initHeaderValue,
1199
- [WORKFLOW_ID_HEADER]: workflowRunId,
1200
- [WORKFLOW_URL_HEADER]: workflowUrl,
1201
- [WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody",
1202
- [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
1203
- "content-type": contentType,
1204
- ...telemetry ? getTelemetryHeaders(telemetry) : {}
1205
- };
1206
- if (invokeCount !== void 0 && !step?.callUrl) {
1207
- baseHeaders[`Upstash-Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`] = invokeCount.toString();
1208
- }
1209
- if (!step?.callUrl) {
1210
- baseHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
1211
- }
1212
- if (callTimeout) {
1213
- baseHeaders[`Upstash-Timeout`] = callTimeout.toString();
1214
- }
1215
- if (failureUrl) {
1216
- baseHeaders[`Upstash-Failure-Callback-Forward-${WORKFLOW_FAILURE_HEADER}`] = "true";
1217
- baseHeaders[`Upstash-Failure-Callback-Forward-Upstash-Workflow-Failure-Callback`] = "true";
1218
- baseHeaders["Upstash-Failure-Callback-Workflow-Runid"] = workflowRunId;
1219
- baseHeaders["Upstash-Failure-Callback-Workflow-Init"] = "false";
1220
- baseHeaders["Upstash-Failure-Callback-Workflow-Url"] = workflowUrl;
1221
- baseHeaders["Upstash-Failure-Callback-Workflow-Calltype"] = "failureCall";
1222
- if (retries !== void 0) {
1223
- baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
1224
- }
1225
- if (flowControl) {
1226
- const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
1227
- baseHeaders["Upstash-Failure-Callback-Flow-Control-Key"] = flowControlKey;
1228
- baseHeaders["Upstash-Failure-Callback-Flow-Control-Value"] = flowControlValue;
1229
- }
1230
- if (!step?.callUrl) {
1231
- baseHeaders["Upstash-Failure-Callback"] = failureUrl;
1232
- }
1233
- }
1234
- if (step?.callUrl) {
1235
- baseHeaders["Upstash-Retries"] = callRetries?.toString() ?? "0";
1236
- baseHeaders[WORKFLOW_FEATURE_HEADER] = "WF_NoDelete,InitialBody";
1237
- if (retries !== void 0) {
1238
- baseHeaders["Upstash-Callback-Retries"] = retries.toString();
1239
- baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
1240
- }
1241
- if (callFlowControl) {
1242
- const { flowControlKey, flowControlValue } = prepareFlowControl(callFlowControl);
1243
- baseHeaders["Upstash-Flow-Control-Key"] = flowControlKey;
1244
- baseHeaders["Upstash-Flow-Control-Value"] = flowControlValue;
1245
- }
1246
- if (flowControl) {
1247
- const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
1248
- baseHeaders["Upstash-Callback-Flow-Control-Key"] = flowControlKey;
1249
- baseHeaders["Upstash-Callback-Flow-Control-Value"] = flowControlValue;
851
+ var verifyRequest = async (body, signature, verifier) => {
852
+ if (!verifier) {
853
+ return;
854
+ }
855
+ try {
856
+ if (!signature) {
857
+ throw new Error("`Upstash-Signature` header is not passed.");
1250
858
  }
1251
- } else {
1252
- if (flowControl) {
1253
- const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
1254
- baseHeaders["Upstash-Flow-Control-Key"] = flowControlKey;
1255
- baseHeaders["Upstash-Flow-Control-Value"] = flowControlValue;
859
+ const isValid = await verifier.verify({
860
+ body,
861
+ signature
862
+ });
863
+ if (!isValid) {
864
+ throw new Error("Signature in `Upstash-Signature` header is not valid");
865
+ }
866
+ } catch (error) {
867
+ throw new WorkflowError(
868
+ `Failed to verify that the Workflow request comes from QStash: ${error}
869
+
870
+ If signature is missing, trigger the workflow endpoint by publishing your request to QStash instead of calling it directly.
871
+
872
+ If you want to disable QStash Verification, you should clear env variables QSTASH_CURRENT_SIGNING_KEY and QSTASH_NEXT_SIGNING_KEY`
873
+ );
874
+ }
875
+ };
876
+
877
+ // src/context/steps.ts
878
+ var BaseLazyStep = class _BaseLazyStep {
879
+ stepName;
880
+ constructor(stepName) {
881
+ if (!stepName) {
882
+ throw new WorkflowError(
883
+ "A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
884
+ );
885
+ }
886
+ if (typeof stepName !== "string") {
887
+ console.warn(
888
+ "Workflow Warning: A workflow step name must be a string. In a future release, this will throw an error."
889
+ );
890
+ }
891
+ this.stepName = stepName;
892
+ }
893
+ /**
894
+ * parse the out field of a step result.
895
+ *
896
+ * will be called when returning the steps to the context from auto executor
897
+ *
898
+ * @param out field of the step
899
+ * @returns parsed out field
900
+ */
901
+ parseOut(out) {
902
+ if (out === void 0) {
903
+ if (this.allowUndefinedOut) {
904
+ return void 0;
905
+ } else {
906
+ throw new WorkflowError(
907
+ `Error while parsing output of ${this.stepType} step. Expected a string, but got: undefined`
908
+ );
909
+ }
910
+ }
911
+ if (typeof out === "object") {
912
+ if (this.stepType !== "Wait") {
913
+ console.warn(
914
+ `Error while parsing ${this.stepType} step output. Expected a string, but got object. Please reach out to Upstash Support.`
915
+ );
916
+ return out;
917
+ }
918
+ return {
919
+ ...out,
920
+ eventData: _BaseLazyStep.tryParsing(out.eventData)
921
+ };
922
+ }
923
+ if (typeof out !== "string") {
924
+ throw new WorkflowError(
925
+ `Error while parsing output of ${this.stepType} step. Expected a string or undefined, but got: ${typeof out}`
926
+ );
927
+ }
928
+ return this.safeParseOut(out);
929
+ }
930
+ safeParseOut(out) {
931
+ return _BaseLazyStep.tryParsing(out);
932
+ }
933
+ static tryParsing(stepOut) {
934
+ try {
935
+ return JSON.parse(stepOut);
936
+ } catch {
937
+ return stepOut;
938
+ }
939
+ }
940
+ getBody({ step }) {
941
+ step.out = JSON.stringify(step.out);
942
+ return JSON.stringify(step);
943
+ }
944
+ getHeaders({ context, telemetry, invokeCount, step }) {
945
+ return getHeaders({
946
+ initHeaderValue: "false",
947
+ workflowConfig: {
948
+ workflowRunId: context.workflowRunId,
949
+ workflowUrl: context.url,
950
+ failureUrl: context.failureUrl,
951
+ retries: context.retries,
952
+ useJSONContent: false,
953
+ telemetry,
954
+ flowControl: context.flowControl
955
+ },
956
+ userHeaders: context.headers,
957
+ invokeCount,
958
+ stepInfo: {
959
+ step,
960
+ lazyStep: this
961
+ }
962
+ });
963
+ }
964
+ async submitStep({ context, body, headers }) {
965
+ return await context.qstashClient.batch([
966
+ {
967
+ body,
968
+ headers,
969
+ method: "POST",
970
+ url: context.url
971
+ }
972
+ ]);
973
+ }
974
+ };
975
+ var LazyFunctionStep = class extends BaseLazyStep {
976
+ stepFunction;
977
+ stepType = "Run";
978
+ allowUndefinedOut = true;
979
+ constructor(stepName, stepFunction) {
980
+ super(stepName);
981
+ this.stepFunction = stepFunction;
982
+ }
983
+ getPlanStep(concurrent, targetStep) {
984
+ return {
985
+ stepId: 0,
986
+ stepName: this.stepName,
987
+ stepType: this.stepType,
988
+ concurrent,
989
+ targetStep
990
+ };
991
+ }
992
+ async getResultStep(concurrent, stepId) {
993
+ let result = this.stepFunction();
994
+ if (result instanceof Promise) {
995
+ result = await result;
996
+ }
997
+ return {
998
+ stepId,
999
+ stepName: this.stepName,
1000
+ stepType: this.stepType,
1001
+ out: result,
1002
+ concurrent
1003
+ };
1004
+ }
1005
+ };
1006
+ var LazySleepStep = class extends BaseLazyStep {
1007
+ sleep;
1008
+ stepType = "SleepFor";
1009
+ allowUndefinedOut = true;
1010
+ constructor(stepName, sleep) {
1011
+ super(stepName);
1012
+ this.sleep = sleep;
1013
+ }
1014
+ getPlanStep(concurrent, targetStep) {
1015
+ return {
1016
+ stepId: 0,
1017
+ stepName: this.stepName,
1018
+ stepType: this.stepType,
1019
+ sleepFor: this.sleep,
1020
+ concurrent,
1021
+ targetStep
1022
+ };
1023
+ }
1024
+ async getResultStep(concurrent, stepId) {
1025
+ return await Promise.resolve({
1026
+ stepId,
1027
+ stepName: this.stepName,
1028
+ stepType: this.stepType,
1029
+ sleepFor: this.sleep,
1030
+ concurrent
1031
+ });
1032
+ }
1033
+ async submitStep({ context, body, headers, isParallel }) {
1034
+ return await context.qstashClient.batch([
1035
+ {
1036
+ body,
1037
+ headers,
1038
+ method: "POST",
1039
+ url: context.url,
1040
+ delay: isParallel ? void 0 : this.sleep
1041
+ }
1042
+ ]);
1043
+ }
1044
+ };
1045
+ var LazySleepUntilStep = class extends BaseLazyStep {
1046
+ sleepUntil;
1047
+ stepType = "SleepUntil";
1048
+ allowUndefinedOut = true;
1049
+ constructor(stepName, sleepUntil) {
1050
+ super(stepName);
1051
+ this.sleepUntil = sleepUntil;
1052
+ }
1053
+ getPlanStep(concurrent, targetStep) {
1054
+ return {
1055
+ stepId: 0,
1056
+ stepName: this.stepName,
1057
+ stepType: this.stepType,
1058
+ sleepUntil: this.sleepUntil,
1059
+ concurrent,
1060
+ targetStep
1061
+ };
1062
+ }
1063
+ async getResultStep(concurrent, stepId) {
1064
+ return await Promise.resolve({
1065
+ stepId,
1066
+ stepName: this.stepName,
1067
+ stepType: this.stepType,
1068
+ sleepUntil: this.sleepUntil,
1069
+ concurrent
1070
+ });
1071
+ }
1072
+ safeParseOut() {
1073
+ return void 0;
1074
+ }
1075
+ async submitStep({ context, body, headers, isParallel }) {
1076
+ return await context.qstashClient.batch([
1077
+ {
1078
+ body,
1079
+ headers,
1080
+ method: "POST",
1081
+ url: context.url,
1082
+ notBefore: isParallel ? void 0 : this.sleepUntil
1083
+ }
1084
+ ]);
1085
+ }
1086
+ };
1087
+ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1088
+ url;
1089
+ method;
1090
+ body;
1091
+ headers;
1092
+ retries;
1093
+ timeout;
1094
+ flowControl;
1095
+ stepType = "Call";
1096
+ allowUndefinedOut = false;
1097
+ constructor(stepName, url, method, body, headers, retries, timeout, flowControl) {
1098
+ super(stepName);
1099
+ this.url = url;
1100
+ this.method = method;
1101
+ this.body = body;
1102
+ this.headers = headers;
1103
+ this.retries = retries;
1104
+ this.timeout = timeout;
1105
+ this.flowControl = flowControl;
1106
+ }
1107
+ getPlanStep(concurrent, targetStep) {
1108
+ return {
1109
+ stepId: 0,
1110
+ stepName: this.stepName,
1111
+ stepType: this.stepType,
1112
+ concurrent,
1113
+ targetStep
1114
+ };
1115
+ }
1116
+ async getResultStep(concurrent, stepId) {
1117
+ return await Promise.resolve({
1118
+ stepId,
1119
+ stepName: this.stepName,
1120
+ stepType: this.stepType,
1121
+ concurrent,
1122
+ callUrl: this.url,
1123
+ callMethod: this.method,
1124
+ callBody: this.body,
1125
+ callHeaders: this.headers
1126
+ });
1127
+ }
1128
+ safeParseOut(out) {
1129
+ const { header, status, body } = JSON.parse(out);
1130
+ const responseHeaders = new Headers(header);
1131
+ if (_LazyCallStep.isText(responseHeaders.get("content-type"))) {
1132
+ const bytes = new Uint8Array(out.length);
1133
+ for (let i = 0; i < out.length; i++) {
1134
+ bytes[i] = out.charCodeAt(i);
1135
+ }
1136
+ const processedResult = new TextDecoder().decode(bytes);
1137
+ const newBody = JSON.parse(processedResult).body;
1138
+ return {
1139
+ status,
1140
+ header,
1141
+ body: BaseLazyStep.tryParsing(newBody)
1142
+ };
1143
+ } else {
1144
+ return { header, status, body };
1145
+ }
1146
+ }
1147
+ static applicationHeaders = /* @__PURE__ */ new Set([
1148
+ "application/json",
1149
+ "application/xml",
1150
+ "application/javascript",
1151
+ "application/x-www-form-urlencoded",
1152
+ "application/xhtml+xml",
1153
+ "application/ld+json",
1154
+ "application/rss+xml",
1155
+ "application/atom+xml"
1156
+ ]);
1157
+ static isText = (contentTypeHeader) => {
1158
+ if (!contentTypeHeader) {
1159
+ return false;
1160
+ }
1161
+ if (_LazyCallStep.applicationHeaders.has(contentTypeHeader)) {
1162
+ return true;
1256
1163
  }
1257
- if (retries !== void 0) {
1258
- baseHeaders["Upstash-Retries"] = retries.toString();
1259
- baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
1164
+ if (contentTypeHeader.startsWith("text/")) {
1165
+ return true;
1166
+ }
1167
+ return false;
1168
+ };
1169
+ getBody({ step }) {
1170
+ if (!step.callUrl) {
1171
+ throw new WorkflowError("Incompatible step received in LazyCallStep.getBody");
1260
1172
  }
1173
+ return JSON.stringify(step.callBody);
1261
1174
  }
1262
- if (userHeaders) {
1263
- for (const header of userHeaders.keys()) {
1264
- if (step?.callHeaders) {
1265
- baseHeaders[`Upstash-Callback-Forward-${header}`] = userHeaders.get(header);
1266
- } else {
1267
- baseHeaders[`Upstash-Forward-${header}`] = userHeaders.get(header);
1268
- }
1269
- baseHeaders[`Upstash-Failure-Callback-Forward-${header}`] = userHeaders.get(header);
1175
+ getHeaders({ context, telemetry, invokeCount, step }) {
1176
+ const { headers, contentType } = super.getHeaders({ context, telemetry, invokeCount, step });
1177
+ headers["Upstash-Retries"] = this.retries.toString();
1178
+ headers[WORKFLOW_FEATURE_HEADER] = "WF_NoDelete,InitialBody";
1179
+ if (this.flowControl) {
1180
+ const { flowControlKey, flowControlValue } = prepareFlowControl(this.flowControl);
1181
+ headers["Upstash-Flow-Control-Key"] = flowControlKey;
1182
+ headers["Upstash-Flow-Control-Value"] = flowControlValue;
1183
+ }
1184
+ if (this.timeout) {
1185
+ headers["Upstash-Timeout"] = this.timeout.toString();
1270
1186
  }
1271
- }
1272
- if (step?.callHeaders) {
1273
1187
  const forwardedHeaders = Object.fromEntries(
1274
- Object.entries(step.callHeaders).map(([header, value]) => [
1275
- `Upstash-Forward-${header}`,
1276
- value
1277
- ])
1188
+ Object.entries(this.headers).map(([header, value]) => [`Upstash-Forward-${header}`, value])
1278
1189
  );
1279
1190
  return {
1280
1191
  headers: {
1281
- ...baseHeaders,
1192
+ ...headers,
1282
1193
  ...forwardedHeaders,
1283
- "Upstash-Callback": workflowUrl,
1284
- "Upstash-Callback-Workflow-RunId": workflowRunId,
1194
+ "Upstash-Callback": context.url,
1195
+ "Upstash-Callback-Workflow-RunId": context.workflowRunId,
1285
1196
  "Upstash-Callback-Workflow-CallType": "fromCallback",
1286
1197
  "Upstash-Callback-Workflow-Init": "false",
1287
- "Upstash-Callback-Workflow-Url": workflowUrl,
1198
+ "Upstash-Callback-Workflow-Url": context.url,
1288
1199
  "Upstash-Callback-Feature-Set": "LazyFetch,InitialBody",
1289
1200
  "Upstash-Callback-Forward-Upstash-Workflow-Callback": "true",
1290
1201
  "Upstash-Callback-Forward-Upstash-Workflow-StepId": step.stepId.toString(),
1291
- "Upstash-Callback-Forward-Upstash-Workflow-StepName": step.stepName,
1292
- "Upstash-Callback-Forward-Upstash-Workflow-StepType": step.stepType,
1202
+ "Upstash-Callback-Forward-Upstash-Workflow-StepName": this.stepName,
1203
+ "Upstash-Callback-Forward-Upstash-Workflow-StepType": this.stepType,
1293
1204
  "Upstash-Callback-Forward-Upstash-Workflow-Concurrent": step.concurrent.toString(),
1294
1205
  "Upstash-Callback-Forward-Upstash-Workflow-ContentType": contentType,
1295
- [`Upstash-Callback-Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`]: (invokeCount ?? 0).toString(),
1296
1206
  "Upstash-Workflow-CallType": "toCallback"
1207
+ },
1208
+ contentType
1209
+ };
1210
+ }
1211
+ async submitStep({ context, headers }) {
1212
+ return await context.qstashClient.batch([
1213
+ {
1214
+ headers,
1215
+ body: JSON.stringify(this.body),
1216
+ method: this.method,
1217
+ url: this.url
1297
1218
  }
1219
+ ]);
1220
+ }
1221
+ };
1222
+ var LazyWaitForEventStep = class extends BaseLazyStep {
1223
+ eventId;
1224
+ timeout;
1225
+ stepType = "Wait";
1226
+ allowUndefinedOut = false;
1227
+ constructor(stepName, eventId, timeout) {
1228
+ super(stepName);
1229
+ this.eventId = eventId;
1230
+ this.timeout = timeout;
1231
+ }
1232
+ getPlanStep(concurrent, targetStep) {
1233
+ return {
1234
+ stepId: 0,
1235
+ stepName: this.stepName,
1236
+ stepType: this.stepType,
1237
+ waitEventId: this.eventId,
1238
+ timeout: this.timeout,
1239
+ concurrent,
1240
+ targetStep
1298
1241
  };
1299
1242
  }
1300
- if (step?.waitEventId) {
1243
+ async getResultStep(concurrent, stepId) {
1244
+ return await Promise.resolve({
1245
+ stepId,
1246
+ stepName: this.stepName,
1247
+ stepType: this.stepType,
1248
+ waitEventId: this.eventId,
1249
+ timeout: this.timeout,
1250
+ concurrent
1251
+ });
1252
+ }
1253
+ safeParseOut(out) {
1254
+ const result = JSON.parse(out);
1301
1255
  return {
1302
- headers: {
1303
- ...baseHeaders,
1304
- "Upstash-Workflow-CallType": "step"
1305
- },
1306
- timeoutHeaders: {
1307
- // to include user headers:
1308
- ...Object.fromEntries(
1309
- Object.entries(baseHeaders).map(([header, value]) => [header, [value]])
1310
- ),
1311
- // to include telemetry headers:
1312
- ...telemetry ? Object.fromEntries(
1313
- Object.entries(getTelemetryHeaders(telemetry)).map(([header, value]) => [
1314
- header,
1315
- [value]
1316
- ])
1317
- ) : {},
1318
- // note: using WORKFLOW_ID_HEADER doesn't work, because Runid -> RunId:
1319
- "Upstash-Workflow-Runid": [workflowRunId],
1320
- [WORKFLOW_INIT_HEADER]: ["false"],
1321
- [WORKFLOW_URL_HEADER]: [workflowUrl],
1322
- "Upstash-Workflow-CallType": ["step"]
1256
+ ...result,
1257
+ eventData: BaseLazyStep.tryParsing(result.eventData)
1258
+ };
1259
+ }
1260
+ getHeaders({ context, telemetry, invokeCount, step }) {
1261
+ const headers = super.getHeaders({ context, telemetry, invokeCount, step });
1262
+ headers.headers["Upstash-Workflow-CallType"] = "step";
1263
+ return headers;
1264
+ }
1265
+ getBody({ context, step, headers, telemetry }) {
1266
+ if (!step.waitEventId) {
1267
+ throw new WorkflowError("Incompatible step received in LazyWaitForEventStep.getBody");
1268
+ }
1269
+ const timeoutHeaders = {
1270
+ // to include user headers:
1271
+ ...Object.fromEntries(Object.entries(headers).map(([header, value]) => [header, [value]])),
1272
+ // to include telemetry headers:
1273
+ ...telemetry ? Object.fromEntries(
1274
+ Object.entries(getTelemetryHeaders(telemetry)).map(([header, value]) => [
1275
+ header,
1276
+ [value]
1277
+ ])
1278
+ ) : {},
1279
+ // note: using WORKFLOW_ID_HEADER doesn't work, because Runid -> RunId:
1280
+ "Upstash-Workflow-Runid": [context.workflowRunId],
1281
+ [WORKFLOW_INIT_HEADER]: ["false"],
1282
+ [WORKFLOW_URL_HEADER]: [context.url],
1283
+ "Upstash-Workflow-CallType": ["step"]
1284
+ };
1285
+ const waitBody = {
1286
+ url: context.url,
1287
+ timeout: step.timeout,
1288
+ timeoutBody: void 0,
1289
+ timeoutUrl: context.url,
1290
+ timeoutHeaders,
1291
+ step: {
1292
+ stepId: step.stepId,
1293
+ stepType: "Wait",
1294
+ stepName: step.stepName,
1295
+ concurrent: step.concurrent,
1296
+ targetStep: step.targetStep
1323
1297
  }
1324
1298
  };
1299
+ return JSON.stringify(waitBody);
1300
+ }
1301
+ async submitStep({ context, body, headers }) {
1302
+ const result = await context.qstashClient.http.request({
1303
+ path: ["v2", "wait", this.eventId],
1304
+ body,
1305
+ headers,
1306
+ method: "POST",
1307
+ parseResponseAsJson: false
1308
+ });
1309
+ return [result];
1325
1310
  }
1326
- return { headers: baseHeaders };
1327
1311
  };
1328
- var verifyRequest = async (body, signature, verifier) => {
1329
- if (!verifier) {
1330
- return;
1312
+ var LazyNotifyStep = class extends LazyFunctionStep {
1313
+ stepType = "Notify";
1314
+ constructor(stepName, eventId, eventData, requester) {
1315
+ super(stepName, async () => {
1316
+ const notifyResponse = await makeNotifyRequest(requester, eventId, eventData);
1317
+ return {
1318
+ eventId,
1319
+ eventData,
1320
+ notifyResponse
1321
+ };
1322
+ });
1331
1323
  }
1332
- try {
1333
- if (!signature) {
1334
- throw new Error("`Upstash-Signature` header is not passed.");
1324
+ safeParseOut(out) {
1325
+ const result = JSON.parse(out);
1326
+ return {
1327
+ ...result,
1328
+ eventData: BaseLazyStep.tryParsing(result.eventData)
1329
+ };
1330
+ }
1331
+ };
1332
+ var LazyInvokeStep = class extends BaseLazyStep {
1333
+ stepType = "Invoke";
1334
+ params;
1335
+ allowUndefinedOut = false;
1336
+ /**
1337
+ * workflow id of the invoked workflow
1338
+ */
1339
+ workflowId;
1340
+ constructor(stepName, {
1341
+ workflow,
1342
+ body,
1343
+ headers = {},
1344
+ workflowRunId,
1345
+ retries,
1346
+ flowControl
1347
+ }) {
1348
+ super(stepName);
1349
+ this.params = {
1350
+ workflow,
1351
+ body,
1352
+ headers,
1353
+ workflowRunId: getWorkflowRunId(workflowRunId),
1354
+ retries,
1355
+ flowControl
1356
+ };
1357
+ const { workflowId } = workflow;
1358
+ if (!workflowId) {
1359
+ throw new WorkflowError("You can only invoke workflow which has a workflowId");
1335
1360
  }
1336
- const isValid = await verifier.verify({
1361
+ this.workflowId = workflowId;
1362
+ }
1363
+ getPlanStep(concurrent, targetStep) {
1364
+ return {
1365
+ stepId: 0,
1366
+ stepName: this.stepName,
1367
+ stepType: this.stepType,
1368
+ concurrent,
1369
+ targetStep
1370
+ };
1371
+ }
1372
+ /**
1373
+ * won't be used as it's the server who will add the result step
1374
+ * in Invoke step.
1375
+ */
1376
+ getResultStep(concurrent, stepId) {
1377
+ return Promise.resolve({
1378
+ stepId,
1379
+ stepName: this.stepName,
1380
+ stepType: this.stepType,
1381
+ concurrent
1382
+ });
1383
+ }
1384
+ safeParseOut(out) {
1385
+ const result = JSON.parse(out);
1386
+ return {
1387
+ ...result,
1388
+ body: BaseLazyStep.tryParsing(result.body)
1389
+ };
1390
+ }
1391
+ getBody({ context, step, telemetry, invokeCount }) {
1392
+ const { headers: invokerHeaders } = getHeaders({
1393
+ initHeaderValue: "false",
1394
+ workflowConfig: {
1395
+ workflowRunId: context.workflowRunId,
1396
+ workflowUrl: context.url,
1397
+ failureUrl: context.failureUrl,
1398
+ retries: context.retries,
1399
+ telemetry,
1400
+ flowControl: context.flowControl,
1401
+ useJSONContent: false
1402
+ },
1403
+ userHeaders: context.headers,
1404
+ invokeCount
1405
+ });
1406
+ invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
1407
+ const request = {
1408
+ body: JSON.stringify(this.params.body),
1409
+ headers: Object.fromEntries(
1410
+ Object.entries(invokerHeaders).map((pairs) => [pairs[0], [pairs[1]]])
1411
+ ),
1412
+ workflowRunId: context.workflowRunId,
1413
+ workflowUrl: context.url,
1414
+ step
1415
+ };
1416
+ return JSON.stringify(request);
1417
+ }
1418
+ getHeaders({ context, telemetry, invokeCount }) {
1419
+ const {
1420
+ workflow,
1421
+ headers = {},
1422
+ workflowRunId = getWorkflowRunId(),
1423
+ retries,
1424
+ flowControl
1425
+ } = this.params;
1426
+ const newUrl = context.url.replace(/[^/]+$/, this.workflowId);
1427
+ const {
1428
+ retries: workflowRetries,
1429
+ failureFunction,
1430
+ failureUrl,
1431
+ useJSONContent,
1432
+ flowControl: workflowFlowControl
1433
+ } = workflow.options;
1434
+ const { headers: triggerHeaders, contentType } = getHeaders({
1435
+ initHeaderValue: "true",
1436
+ workflowConfig: {
1437
+ workflowRunId,
1438
+ workflowUrl: newUrl,
1439
+ retries: retries ?? workflowRetries,
1440
+ telemetry,
1441
+ failureUrl: failureFunction ? newUrl : failureUrl,
1442
+ flowControl: flowControl ?? workflowFlowControl,
1443
+ useJSONContent: useJSONContent ?? false
1444
+ },
1445
+ invokeCount: invokeCount + 1,
1446
+ userHeaders: new Headers(headers)
1447
+ });
1448
+ triggerHeaders["Upstash-Workflow-Invoke"] = "true";
1449
+ return { headers: triggerHeaders, contentType };
1450
+ }
1451
+ async submitStep({ context, body, headers }) {
1452
+ const newUrl = context.url.replace(/[^/]+$/, this.workflowId);
1453
+ const result = await context.qstashClient.publish({
1454
+ headers,
1455
+ method: "POST",
1337
1456
  body,
1338
- signature
1457
+ url: newUrl
1339
1458
  });
1340
- if (!isValid) {
1341
- throw new Error("Signature in `Upstash-Signature` header is not valid");
1342
- }
1343
- } catch (error) {
1344
- throw new WorkflowError(
1345
- `Failed to verify that the Workflow request comes from QStash: ${error}
1459
+ return [result];
1460
+ }
1461
+ };
1346
1462
 
1347
- If signature is missing, trigger the workflow endpoint by publishing your request to QStash instead of calling it directly.
1463
+ // src/agents/constants.ts
1464
+ var AGENT_NAME_HEADER = "upstash-agent-name";
1465
+ var MANAGER_AGENT_PROMPT = `You are an agent orchestrating other AI Agents.
1348
1466
 
1349
- If you want to disable QStash Verification, you should clear env variables QSTASH_CURRENT_SIGNING_KEY and QSTASH_NEXT_SIGNING_KEY`
1467
+ These other agents have tools available to them.
1468
+
1469
+ Given a prompt, utilize these agents to address requests.
1470
+
1471
+ Don't always call all the agents provided to you at the same time. You can call one and use it's response to call another.
1472
+
1473
+ Avoid calling the same agent twice in one turn. Instead, prefer to call it once but provide everything
1474
+ you need from that agent.
1475
+ `;
1476
+
1477
+ // src/qstash/headers.ts
1478
+ var WorkflowHeaders = class {
1479
+ userHeaders;
1480
+ workflowConfig;
1481
+ invokeCount;
1482
+ initHeaderValue;
1483
+ stepInfo;
1484
+ headers;
1485
+ constructor({
1486
+ userHeaders,
1487
+ workflowConfig,
1488
+ invokeCount,
1489
+ initHeaderValue,
1490
+ stepInfo
1491
+ }) {
1492
+ this.userHeaders = userHeaders;
1493
+ this.workflowConfig = workflowConfig;
1494
+ this.invokeCount = invokeCount;
1495
+ this.initHeaderValue = initHeaderValue;
1496
+ this.stepInfo = stepInfo;
1497
+ this.headers = {
1498
+ rawHeaders: {},
1499
+ workflowHeaders: {},
1500
+ failureHeaders: {}
1501
+ };
1502
+ }
1503
+ getHeaders() {
1504
+ this.addBaseHeaders();
1505
+ this.addRetries();
1506
+ this.addFlowControl();
1507
+ this.addUserHeaders();
1508
+ this.addInvokeCount();
1509
+ this.addFailureUrl();
1510
+ const contentType = this.addContentType();
1511
+ return this.prefixHeaders(contentType);
1512
+ }
1513
+ addBaseHeaders() {
1514
+ this.headers.rawHeaders = {
1515
+ ...this.headers.rawHeaders,
1516
+ [WORKFLOW_INIT_HEADER]: this.initHeaderValue,
1517
+ [WORKFLOW_ID_HEADER]: this.workflowConfig.workflowRunId,
1518
+ [WORKFLOW_URL_HEADER]: this.workflowConfig.workflowUrl,
1519
+ [WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody",
1520
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
1521
+ ...this.workflowConfig.telemetry ? getTelemetryHeaders(this.workflowConfig.telemetry) : {},
1522
+ ...this.workflowConfig.telemetry && this.stepInfo?.lazyStep instanceof LazyCallStep && this.stepInfo.lazyStep.headers[AGENT_NAME_HEADER] ? { [TELEMETRY_HEADER_AGENT]: "true" } : {}
1523
+ };
1524
+ if (this.stepInfo?.lazyStep.stepType !== "Call") {
1525
+ this.headers.rawHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
1526
+ }
1527
+ }
1528
+ addInvokeCount() {
1529
+ if (this.invokeCount === void 0 || this.invokeCount === 0) {
1530
+ return;
1531
+ }
1532
+ const invokeCount = this.invokeCount.toString();
1533
+ this.headers.workflowHeaders[`Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`] = invokeCount;
1534
+ if (this.workflowConfig.failureUrl) {
1535
+ this.headers.failureHeaders[`Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`] = invokeCount;
1536
+ }
1537
+ if (this.stepInfo?.lazyStep instanceof LazyCallStep) {
1538
+ this.headers.rawHeaders[`Upstash-Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`] = invokeCount;
1539
+ }
1540
+ }
1541
+ addRetries() {
1542
+ if (this.workflowConfig.retries === void 0 || this.workflowConfig.retries === DEFAULT_RETRIES) {
1543
+ return;
1544
+ }
1545
+ const retries = this.workflowConfig.retries.toString();
1546
+ this.headers.workflowHeaders["Retries"] = retries;
1547
+ if (this.workflowConfig.failureUrl) {
1548
+ this.headers.failureHeaders["Retries"] = retries;
1549
+ }
1550
+ }
1551
+ addFlowControl() {
1552
+ if (!this.workflowConfig.flowControl) {
1553
+ return;
1554
+ }
1555
+ const { flowControlKey, flowControlValue } = prepareFlowControl(
1556
+ this.workflowConfig.flowControl
1557
+ );
1558
+ this.headers.workflowHeaders["Flow-Control-Key"] = flowControlKey;
1559
+ this.headers.workflowHeaders["Flow-Control-Value"] = flowControlValue;
1560
+ if (this.workflowConfig.failureUrl) {
1561
+ this.headers.failureHeaders["Flow-Control-Key"] = flowControlKey;
1562
+ this.headers.failureHeaders["Flow-Control-Value"] = flowControlValue;
1563
+ }
1564
+ }
1565
+ addUserHeaders() {
1566
+ for (const [key, value] of this.userHeaders.entries()) {
1567
+ const forwardKey = `Forward-${key}`;
1568
+ this.headers.workflowHeaders[forwardKey] = value;
1569
+ if (this.workflowConfig.failureUrl) {
1570
+ this.headers.failureHeaders[forwardKey] = value;
1571
+ }
1572
+ }
1573
+ }
1574
+ addFailureUrl() {
1575
+ if (!this.workflowConfig.failureUrl) {
1576
+ return;
1577
+ }
1578
+ this.headers.workflowHeaders["Failure-Callback"] = this.workflowConfig.failureUrl;
1579
+ this.headers.failureHeaders[`Forward-${WORKFLOW_FAILURE_HEADER}`] = "true";
1580
+ this.headers.failureHeaders[`Forward-Upstash-Workflow-Failure-Callback`] = "true";
1581
+ this.headers.failureHeaders["Workflow-Runid"] = this.workflowConfig.workflowRunId;
1582
+ this.headers.failureHeaders["Workflow-Init"] = "false";
1583
+ this.headers.failureHeaders["Workflow-Url"] = this.workflowConfig.workflowUrl;
1584
+ this.headers.failureHeaders["Workflow-Calltype"] = "failureCall";
1585
+ this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody";
1586
+ if (this.workflowConfig.retries !== void 0 && this.workflowConfig.retries !== DEFAULT_RETRIES) {
1587
+ this.headers.failureHeaders["Retries"] = this.workflowConfig.retries.toString();
1588
+ }
1589
+ }
1590
+ addContentType() {
1591
+ if (this.workflowConfig.useJSONContent) {
1592
+ this.headers.rawHeaders["content-type"] = "application/json";
1593
+ return "application/json";
1594
+ }
1595
+ const callHeaders = new Headers(
1596
+ this.stepInfo?.lazyStep instanceof LazyCallStep ? this.stepInfo.lazyStep.headers : {}
1350
1597
  );
1598
+ const contentType = (callHeaders.get("content-type") ? callHeaders.get("content-type") : this.userHeaders?.get("Content-Type") ? this.userHeaders.get("Content-Type") : void 0) ?? DEFAULT_CONTENT_TYPE;
1599
+ this.headers.rawHeaders["content-type"] = contentType;
1600
+ return contentType;
1601
+ }
1602
+ prefixHeaders(contentType) {
1603
+ const { rawHeaders, workflowHeaders, failureHeaders } = this.headers;
1604
+ const isCall = this.stepInfo?.lazyStep.stepType === "Call";
1605
+ return {
1606
+ headers: {
1607
+ ...rawHeaders,
1608
+ ...addPrefixToHeaders(workflowHeaders, isCall ? "Upstash-Callback-" : "Upstash-"),
1609
+ ...addPrefixToHeaders(failureHeaders, "Upstash-Failure-Callback-"),
1610
+ ...isCall ? addPrefixToHeaders(failureHeaders, "Upstash-Callback-Failure-Callback-") : {}
1611
+ },
1612
+ contentType
1613
+ };
1351
1614
  }
1352
1615
  };
1616
+ function addPrefixToHeaders(headers, prefix) {
1617
+ const prefixedHeaders = {};
1618
+ for (const [key, value] of Object.entries(headers)) {
1619
+ prefixedHeaders[`${prefix}${key}`] = value;
1620
+ }
1621
+ return prefixedHeaders;
1622
+ }
1353
1623
  var prepareFlowControl = (flowControl) => {
1354
1624
  const parallelism = flowControl.parallelism?.toString();
1355
- const rate = flowControl.ratePerSecond?.toString();
1625
+ const rate = (flowControl.rate ?? flowControl.ratePerSecond)?.toString();
1626
+ const period = typeof flowControl.period === "number" ? `${flowControl.period}s` : flowControl.period;
1356
1627
  const controlValue = [
1357
1628
  parallelism ? `parallelism=${parallelism}` : void 0,
1358
- rate ? `rate=${rate}` : void 0
1629
+ rate ? `rate=${rate}` : void 0,
1630
+ period ? `period=${period}` : void 0
1359
1631
  ].filter(Boolean);
1360
1632
  if (controlValue.length === 0) {
1361
- throw new import_qstash3.QstashError("Provide at least one of parallelism or ratePerSecond for flowControl");
1633
+ throw new import_qstash4.QstashError("Provide at least one of parallelism or ratePerSecond for flowControl");
1362
1634
  }
1363
1635
  return {
1364
1636
  flowControlKey: flowControl.key,
1365
1637
  flowControlValue: controlValue.join(", ")
1366
1638
  };
1367
1639
  };
1368
-
1369
- // src/context/auto-executor.ts
1370
- var import_qstash4 = require("@upstash/qstash");
1371
-
1372
- // src/serve/serve-many.ts
1373
- var getWorkflowId = (url) => {
1374
- const components = url.split("/");
1375
- const lastComponent = components[components.length - 1];
1376
- return lastComponent.split("?")[0];
1640
+ var getHeaders = (params) => {
1641
+ const workflowHeaders = new WorkflowHeaders(params);
1642
+ return workflowHeaders.getHeaders();
1377
1643
  };
1378
- var serveManyBase = ({
1379
- workflows,
1380
- getUrl,
1381
- serveMethod,
1382
- options
1644
+
1645
+ // src/qstash/submit-steps.ts
1646
+ var submitParallelSteps = async ({
1647
+ context,
1648
+ steps,
1649
+ initialStepCount,
1650
+ invokeCount,
1651
+ telemetry,
1652
+ debug
1383
1653
  }) => {
1384
- const workflowIds = [];
1385
- const workflowMap = Object.fromEntries(
1386
- Object.entries(workflows).map((workflow) => {
1387
- const workflowId = workflow[0];
1388
- if (workflowIds.includes(workflowId)) {
1389
- throw new WorkflowError(
1390
- `Duplicate workflow name found: '${workflowId}'. Please set different workflow names in serveMany.`
1391
- );
1392
- }
1393
- if (workflowId.includes("/")) {
1394
- throw new WorkflowError(
1395
- `Invalid workflow name found: '${workflowId}'. Workflow name cannot contain '/'.`
1396
- );
1397
- }
1398
- workflowIds.push(workflowId);
1399
- workflow[1].workflowId = workflowId;
1400
- workflow[1].options = {
1401
- ...options,
1402
- ...workflow[1].options
1654
+ const planSteps = steps.map(
1655
+ (step, index) => step.getPlanStep(steps.length, initialStepCount + index)
1656
+ );
1657
+ await debug?.log("SUBMIT", "SUBMIT_STEP", {
1658
+ length: planSteps.length,
1659
+ steps: planSteps
1660
+ });
1661
+ const result = await context.qstashClient.batch(
1662
+ planSteps.map((planStep) => {
1663
+ const { headers } = getHeaders({
1664
+ initHeaderValue: "false",
1665
+ workflowConfig: {
1666
+ workflowRunId: context.workflowRunId,
1667
+ workflowUrl: context.url,
1668
+ failureUrl: context.failureUrl,
1669
+ retries: context.retries,
1670
+ flowControl: context.flowControl,
1671
+ telemetry
1672
+ },
1673
+ userHeaders: context.headers,
1674
+ invokeCount
1675
+ });
1676
+ return {
1677
+ headers,
1678
+ method: "POST",
1679
+ url: context.url,
1680
+ body: JSON.stringify(planStep),
1681
+ notBefore: planStep.sleepUntil,
1682
+ delay: planStep.sleepFor
1403
1683
  };
1404
- const params = [workflow[1].routeFunction, workflow[1].options];
1405
- const handler = serveMethod(...params);
1406
- return [workflowId, handler];
1407
1684
  })
1408
1685
  );
1409
- return {
1410
- handler: async (...params) => {
1411
- const url = getUrl(...params);
1412
- const pickedWorkflowId = getWorkflowId(url);
1413
- if (!pickedWorkflowId) {
1414
- return new Response(
1415
- `Unexpected request in serveMany. workflowId not set. Please update the URL of your request.`,
1416
- {
1417
- status: 404
1418
- }
1419
- );
1420
- }
1421
- const workflow = workflowMap[pickedWorkflowId];
1422
- if (!workflow) {
1423
- return new Response(
1424
- `No workflows in serveMany found for '${pickedWorkflowId}'. Please update the URL of your request.`,
1425
- {
1426
- status: 404
1427
- }
1428
- );
1429
- }
1430
- return await workflow(...params);
1431
- }
1432
- };
1686
+ await debug?.log("INFO", "SUBMIT_STEP", {
1687
+ messageIds: result.map((message) => {
1688
+ return {
1689
+ message: message.messageId
1690
+ };
1691
+ })
1692
+ });
1693
+ throw new WorkflowAbort(planSteps[0].stepName, planSteps[0]);
1433
1694
  };
1434
- var invokeWorkflow = async ({
1435
- settings,
1436
- invokeStep,
1695
+ var submitSingleStep = async ({
1437
1696
  context,
1697
+ lazyStep,
1698
+ stepId,
1438
1699
  invokeCount,
1439
- telemetry
1700
+ concurrency,
1701
+ telemetry,
1702
+ debug
1440
1703
  }) => {
1441
- const {
1442
- body,
1443
- workflow,
1444
- headers = {},
1445
- workflowRunId = getWorkflowRunId(),
1446
- retries,
1447
- flowControl
1448
- } = settings;
1449
- const { workflowId } = workflow;
1450
- const {
1451
- retries: workflowRetries,
1452
- failureFunction,
1453
- failureUrl,
1454
- useJSONContent,
1455
- flowControl: workflowFlowControl
1456
- } = workflow.options;
1457
- if (!workflowId) {
1458
- throw new WorkflowError("You can only invoke workflow which has a workflowId");
1459
- }
1460
- const { headers: invokerHeaders } = getHeaders({
1461
- initHeaderValue: "false",
1462
- workflowRunId: context.workflowRunId,
1463
- workflowUrl: context.url,
1464
- userHeaders: context.headers,
1465
- failureUrl: context.failureUrl,
1466
- retries: context.retries,
1467
- telemetry,
1704
+ const resultStep = await lazyStep.getResultStep(concurrency, stepId);
1705
+ await debug?.log("INFO", "RUN_SINGLE", {
1706
+ fromRequest: false,
1707
+ step: resultStep,
1708
+ stepCount: stepId
1709
+ });
1710
+ const { headers } = lazyStep.getHeaders({
1711
+ context,
1712
+ step: resultStep,
1468
1713
  invokeCount,
1469
- flowControl: context.flowControl
1714
+ telemetry
1470
1715
  });
1471
- invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
1472
- const newUrl = context.url.replace(/[^/]+$/, workflowId);
1473
- const { headers: triggerHeaders } = getHeaders({
1474
- initHeaderValue: "true",
1475
- workflowRunId,
1476
- workflowUrl: newUrl,
1477
- userHeaders: new Headers(headers),
1478
- retries: retries ?? workflowRetries,
1479
- telemetry,
1480
- failureUrl: failureFunction ? newUrl : failureUrl,
1481
- invokeCount: invokeCount + 1,
1482
- flowControl: flowControl ?? workflowFlowControl
1716
+ const body = lazyStep.getBody({
1717
+ context,
1718
+ step: resultStep,
1719
+ headers,
1720
+ invokeCount,
1721
+ telemetry
1483
1722
  });
1484
- triggerHeaders["Upstash-Workflow-Invoke"] = "true";
1485
- if (useJSONContent) {
1486
- triggerHeaders["content-type"] = "application/json";
1487
- }
1488
- const request = {
1489
- body: JSON.stringify(body),
1490
- headers: Object.fromEntries(
1491
- Object.entries(invokerHeaders).map((pairs) => [pairs[0], [pairs[1]]])
1492
- ),
1493
- workflowRunId: context.workflowRunId,
1494
- workflowUrl: context.url,
1495
- step: invokeStep
1496
- };
1497
- await context.qstashClient.publish({
1498
- headers: triggerHeaders,
1499
- method: "POST",
1500
- body: JSON.stringify(request),
1501
- url: newUrl
1723
+ await debug?.log("SUBMIT", "SUBMIT_STEP", {
1724
+ length: 1,
1725
+ steps: [resultStep]
1726
+ });
1727
+ const submitResult = await lazyStep.submitStep({
1728
+ context,
1729
+ body,
1730
+ headers,
1731
+ isParallel: concurrency !== NO_CONCURRENCY,
1732
+ invokeCount,
1733
+ step: resultStep,
1734
+ telemetry
1735
+ });
1736
+ await debug?.log("INFO", "SUBMIT_STEP", {
1737
+ messageIds: submitResult.map((message) => {
1738
+ return {
1739
+ message: message.messageId
1740
+ };
1741
+ })
1502
1742
  });
1743
+ return resultStep;
1503
1744
  };
1504
1745
 
1505
1746
  // src/context/auto-executor.ts
@@ -1606,14 +1847,16 @@ var AutoExecutor = class _AutoExecutor {
1606
1847
  });
1607
1848
  return lazyStep.parseOut(step.out);
1608
1849
  }
1609
- const resultStep = await lazyStep.getResultStep(NO_CONCURRENCY, this.stepCount);
1610
- await this.debug?.log("INFO", "RUN_SINGLE", {
1611
- fromRequest: false,
1612
- step: resultStep,
1613
- stepCount: this.stepCount
1850
+ const resultStep = await submitSingleStep({
1851
+ context: this.context,
1852
+ lazyStep,
1853
+ stepId: this.stepCount,
1854
+ invokeCount: this.invokeCount,
1855
+ concurrency: 1,
1856
+ telemetry: this.telemetry,
1857
+ debug: this.debug
1614
1858
  });
1615
- await this.submitStepsToQStash([resultStep], [lazyStep]);
1616
- return resultStep.out;
1859
+ throw new WorkflowAbort(lazyStep.stepName, resultStep);
1617
1860
  }
1618
1861
  /**
1619
1862
  * Runs steps in parallel.
@@ -1641,10 +1884,14 @@ var AutoExecutor = class _AutoExecutor {
1641
1884
  });
1642
1885
  switch (parallelCallState) {
1643
1886
  case "first": {
1644
- const planSteps = parallelSteps.map(
1645
- (parallelStep, index) => parallelStep.getPlanStep(parallelSteps.length, initialStepCount + index)
1646
- );
1647
- await this.submitStepsToQStash(planSteps, parallelSteps);
1887
+ await submitParallelSteps({
1888
+ context: this.context,
1889
+ steps: parallelSteps,
1890
+ initialStepCount,
1891
+ invokeCount: this.invokeCount,
1892
+ telemetry: this.telemetry,
1893
+ debug: this.debug
1894
+ });
1648
1895
  break;
1649
1896
  }
1650
1897
  case "partial": {
@@ -1658,13 +1905,18 @@ var AutoExecutor = class _AutoExecutor {
1658
1905
  validateStep(parallelSteps[stepIndex], planStep);
1659
1906
  try {
1660
1907
  const parallelStep = parallelSteps[stepIndex];
1661
- const resultStep = await parallelStep.getResultStep(
1662
- parallelSteps.length,
1663
- planStep.targetStep
1664
- );
1665
- await this.submitStepsToQStash([resultStep], [parallelStep]);
1908
+ const resultStep = await submitSingleStep({
1909
+ context: this.context,
1910
+ lazyStep: parallelStep,
1911
+ stepId: planStep.targetStep,
1912
+ invokeCount: this.invokeCount,
1913
+ concurrency: parallelSteps.length,
1914
+ telemetry: this.telemetry,
1915
+ debug: this.debug
1916
+ });
1917
+ throw new WorkflowAbort(parallelStep.stepName, resultStep);
1666
1918
  } catch (error) {
1667
- if (error instanceof WorkflowAbort || error instanceof import_qstash4.QstashError && error.status === 400) {
1919
+ if (error instanceof WorkflowAbort || error instanceof import_qstash5.QstashError && error.status === 400) {
1668
1920
  throw error;
1669
1921
  }
1670
1922
  throw new WorkflowError(
@@ -1720,128 +1972,6 @@ var AutoExecutor = class _AutoExecutor {
1720
1972
  return "discard";
1721
1973
  }
1722
1974
  }
1723
- /**
1724
- * sends the steps to QStash as batch
1725
- *
1726
- * @param steps steps to send
1727
- */
1728
- async submitStepsToQStash(steps, lazySteps) {
1729
- if (steps.length === 0) {
1730
- throw new WorkflowError(
1731
- `Unable to submit steps to QStash. Provided list is empty. Current step: ${this.stepCount}`
1732
- );
1733
- }
1734
- await this.debug?.log("SUBMIT", "SUBMIT_STEP", {
1735
- length: steps.length,
1736
- steps
1737
- });
1738
- if (steps[0].waitEventId && steps.length === 1) {
1739
- const waitStep = steps[0];
1740
- const { headers, timeoutHeaders } = getHeaders({
1741
- initHeaderValue: "false",
1742
- workflowRunId: this.context.workflowRunId,
1743
- workflowUrl: this.context.url,
1744
- userHeaders: this.context.headers,
1745
- step: waitStep,
1746
- failureUrl: this.context.failureUrl,
1747
- retries: this.context.retries,
1748
- telemetry: this.telemetry,
1749
- invokeCount: this.invokeCount,
1750
- flowControl: this.context.flowControl
1751
- });
1752
- const waitBody = {
1753
- url: this.context.url,
1754
- timeout: waitStep.timeout,
1755
- timeoutBody: void 0,
1756
- timeoutUrl: this.context.url,
1757
- timeoutHeaders,
1758
- step: {
1759
- stepId: waitStep.stepId,
1760
- stepType: "Wait",
1761
- stepName: waitStep.stepName,
1762
- concurrent: waitStep.concurrent,
1763
- targetStep: waitStep.targetStep
1764
- }
1765
- };
1766
- await this.context.qstashClient.http.request({
1767
- path: ["v2", "wait", waitStep.waitEventId],
1768
- body: JSON.stringify(waitBody),
1769
- headers,
1770
- method: "POST",
1771
- parseResponseAsJson: false
1772
- });
1773
- throw new WorkflowAbort(waitStep.stepName, waitStep);
1774
- }
1775
- if (steps.length === 1 && lazySteps[0] instanceof LazyInvokeStep) {
1776
- const invokeStep = steps[0];
1777
- const lazyInvokeStep = lazySteps[0];
1778
- await invokeWorkflow({
1779
- settings: lazyInvokeStep.params,
1780
- invokeStep,
1781
- context: this.context,
1782
- invokeCount: this.invokeCount,
1783
- telemetry: this.telemetry
1784
- });
1785
- throw new WorkflowAbort(invokeStep.stepName, invokeStep);
1786
- }
1787
- const result = await this.context.qstashClient.batch(
1788
- steps.map((singleStep, index) => {
1789
- const lazyStep = lazySteps[index];
1790
- const { headers } = getHeaders({
1791
- initHeaderValue: "false",
1792
- workflowRunId: this.context.workflowRunId,
1793
- workflowUrl: this.context.url,
1794
- userHeaders: this.context.headers,
1795
- step: singleStep,
1796
- failureUrl: this.context.failureUrl,
1797
- retries: this.context.retries,
1798
- callRetries: lazyStep instanceof LazyCallStep ? lazyStep.retries : void 0,
1799
- callTimeout: lazyStep instanceof LazyCallStep ? lazyStep.timeout : void 0,
1800
- telemetry: this.telemetry,
1801
- invokeCount: this.invokeCount,
1802
- flowControl: this.context.flowControl,
1803
- callFlowControl: lazyStep instanceof LazyCallStep ? lazyStep.flowControl : void 0
1804
- });
1805
- const willWait = singleStep.concurrent === NO_CONCURRENCY || singleStep.stepId === 0;
1806
- singleStep.out = JSON.stringify(singleStep.out);
1807
- return singleStep.callUrl && lazyStep instanceof LazyCallStep ? (
1808
- // if the step is a third party call, we call the third party
1809
- // url (singleStep.callUrl) and pass information about the workflow
1810
- // in the headers (handled in getHeaders). QStash makes the request
1811
- // to callUrl and returns the result to Workflow endpoint.
1812
- // handleThirdPartyCallResult method sends the result of the third
1813
- // party call to QStash.
1814
- {
1815
- headers,
1816
- method: singleStep.callMethod,
1817
- body: JSON.stringify(singleStep.callBody),
1818
- url: singleStep.callUrl
1819
- }
1820
- ) : (
1821
- // if the step is not a third party call, we use workflow
1822
- // endpoint (context.url) as URL when calling QStash. QStash
1823
- // calls us back with the updated steps list.
1824
- {
1825
- headers,
1826
- method: "POST",
1827
- body: JSON.stringify(singleStep),
1828
- url: this.context.url,
1829
- notBefore: willWait ? singleStep.sleepUntil : void 0,
1830
- delay: willWait ? singleStep.sleepFor : void 0
1831
- }
1832
- );
1833
- })
1834
- );
1835
- const _result = result;
1836
- await this.debug?.log("INFO", "SUBMIT_STEP", {
1837
- messageIds: _result.map((message) => {
1838
- return {
1839
- message: message.messageId
1840
- };
1841
- })
1842
- });
1843
- throw new WorkflowAbort(steps[0].stepName, steps[0]);
1844
- }
1845
1975
  /**
1846
1976
  * Get the promise by executing the lazt steps list. If there is a single
1847
1977
  * step, we call `runSingle`. Otherwise `runParallel` is called.
@@ -1915,7 +2045,7 @@ var sortSteps = (steps) => {
1915
2045
  };
1916
2046
 
1917
2047
  // src/context/api/anthropic.ts
1918
- var import_qstash5 = require("@upstash/qstash");
2048
+ var import_qstash6 = require("@upstash/qstash");
1919
2049
 
1920
2050
  // src/context/provider.ts
1921
2051
  var getProviderInfo = (api) => {
@@ -1979,7 +2109,7 @@ var AnthropicAPI = class extends BaseWorkflowApi {
1979
2109
  return await this.callApi(stepName, {
1980
2110
  api: {
1981
2111
  name: "llm",
1982
- provider: (0, import_qstash5.anthropic)({ token })
2112
+ provider: (0, import_qstash6.anthropic)({ token })
1983
2113
  },
1984
2114
  ...parameters
1985
2115
  });
@@ -1987,12 +2117,12 @@ var AnthropicAPI = class extends BaseWorkflowApi {
1987
2117
  };
1988
2118
 
1989
2119
  // src/context/api/openai.ts
1990
- var import_qstash6 = require("@upstash/qstash");
2120
+ var import_qstash7 = require("@upstash/qstash");
1991
2121
  var OpenAIAPI = class extends BaseWorkflowApi {
1992
2122
  async call(stepName, settings) {
1993
2123
  const { token, organization, operation, baseURL, ...parameters } = settings;
1994
2124
  const useOpenAI = baseURL === void 0;
1995
- const provider = useOpenAI ? (0, import_qstash6.openai)({ token, organization }) : (0, import_qstash6.custom)({ baseUrl: baseURL, token });
2125
+ const provider = useOpenAI ? (0, import_qstash7.openai)({ token, organization }) : (0, import_qstash7.custom)({ baseUrl: baseURL, token });
1996
2126
  return await this.callApi(stepName, {
1997
2127
  api: {
1998
2128
  name: "llm",
@@ -2004,14 +2134,14 @@ var OpenAIAPI = class extends BaseWorkflowApi {
2004
2134
  };
2005
2135
 
2006
2136
  // src/context/api/resend.ts
2007
- var import_qstash7 = require("@upstash/qstash");
2137
+ var import_qstash8 = require("@upstash/qstash");
2008
2138
  var ResendAPI = class extends BaseWorkflowApi {
2009
2139
  async call(stepName, settings) {
2010
2140
  const { token, batch = false, ...parameters } = settings;
2011
2141
  return await this.callApi(stepName, {
2012
2142
  api: {
2013
2143
  name: "email",
2014
- provider: (0, import_qstash7.resend)({ token, batch })
2144
+ provider: (0, import_qstash8.resend)({ token, batch })
2015
2145
  },
2016
2146
  ...parameters
2017
2147
  });
@@ -2037,65 +2167,58 @@ var WorkflowApi = class extends BaseWorkflowApi {
2037
2167
  }
2038
2168
  };
2039
2169
 
2040
- // src/agents/adapters.ts
2170
+ // src/agents/index.ts
2041
2171
  var import_openai2 = require("@ai-sdk/openai");
2042
- var import_ai = require("ai");
2043
-
2044
- // src/agents/constants.ts
2045
- var AGENT_NAME_HEADER = "upstash-agent-name";
2046
- var MANAGER_AGENT_PROMPT = `You are an agent orchestrating other AI Agents.
2047
-
2048
- These other agents have tools available to them.
2049
-
2050
- Given a prompt, utilize these agents to address requests.
2051
-
2052
- Don't always call all the agents provided to you at the same time. You can call one and use it's response to call another.
2053
-
2054
- Avoid calling the same agent twice in one turn. Instead, prefer to call it once but provide everything
2055
- you need from that agent.
2056
- `;
2057
2172
 
2058
2173
  // src/agents/adapters.ts
2059
- var createWorkflowOpenAI = (context, config) => {
2060
- const { baseURL, apiKey } = config ?? {};
2061
- return (0, import_openai2.createOpenAI)({
2062
- baseURL,
2063
- apiKey,
2064
- compatibility: "strict",
2065
- fetch: async (input, init) => {
2066
- try {
2067
- const headers = init?.headers ? Object.fromEntries(new Headers(init.headers).entries()) : {};
2068
- const body = init?.body ? JSON.parse(init.body) : void 0;
2069
- const agentName = headers[AGENT_NAME_HEADER];
2070
- const stepName = agentName ? `Call Agent ${agentName}` : "Call Agent";
2071
- const responseInfo = await context.call(stepName, {
2072
- url: input.toString(),
2073
- method: init?.method,
2074
- headers,
2075
- body
2076
- });
2077
- const responseHeaders = new Headers(
2078
- Object.entries(responseInfo.header).reduce(
2079
- (acc, [key, values]) => {
2080
- acc[key] = values.join(", ");
2081
- return acc;
2082
- },
2083
- {}
2084
- )
2085
- );
2086
- return new Response(JSON.stringify(responseInfo.body), {
2087
- status: responseInfo.status,
2088
- headers: responseHeaders
2089
- });
2090
- } catch (error) {
2091
- if (error instanceof Error && error.name === "WorkflowAbort") {
2092
- throw error;
2093
- } else {
2094
- console.error("Error in fetch implementation:", error);
2095
- throw error;
2096
- }
2097
- }
2174
+ var import_ai = require("ai");
2175
+ var fetchWithContextCall = async (context, agentCallParams, ...params) => {
2176
+ const [input, init] = params;
2177
+ try {
2178
+ const headers = init?.headers ? Object.fromEntries(new Headers(init.headers).entries()) : {};
2179
+ const body = init?.body ? JSON.parse(init.body) : void 0;
2180
+ const agentName = headers[AGENT_NAME_HEADER];
2181
+ const stepName = agentName ? `Call Agent ${agentName}` : "Call Agent";
2182
+ const responseInfo = await context.call(stepName, {
2183
+ url: input.toString(),
2184
+ method: init?.method,
2185
+ headers,
2186
+ body,
2187
+ timeout: agentCallParams?.timeout,
2188
+ retries: agentCallParams?.retries,
2189
+ flowControl: agentCallParams?.flowControl
2190
+ });
2191
+ const responseHeaders = new Headers(
2192
+ Object.entries(responseInfo.header).reduce(
2193
+ (acc, [key, values]) => {
2194
+ acc[key] = values.join(", ");
2195
+ return acc;
2196
+ },
2197
+ {}
2198
+ )
2199
+ );
2200
+ return new Response(JSON.stringify(responseInfo.body), {
2201
+ status: responseInfo.status,
2202
+ headers: responseHeaders
2203
+ });
2204
+ } catch (error) {
2205
+ if (error instanceof Error && error.name === "WorkflowAbort") {
2206
+ throw error;
2207
+ } else {
2208
+ console.error("Error in fetch implementation:", error);
2209
+ throw error;
2098
2210
  }
2211
+ }
2212
+ };
2213
+ var createWorkflowModel = ({
2214
+ context,
2215
+ provider,
2216
+ providerParams,
2217
+ agentCallParams
2218
+ }) => {
2219
+ return provider({
2220
+ fetch: (...params) => fetchWithContextCall(context, agentCallParams, ...params),
2221
+ ...providerParams
2099
2222
  });
2100
2223
  };
2101
2224
  var wrapTools = ({
@@ -2334,10 +2457,85 @@ var WorkflowAgents = class {
2334
2457
  */
2335
2458
  openai(...params) {
2336
2459
  const [model, settings] = params;
2337
- const { baseURL, apiKey, ...otherSettings } = settings ?? {};
2338
- const openai2 = createWorkflowOpenAI(this.context, { baseURL, apiKey });
2339
- return openai2(model, otherSettings);
2460
+ const { baseURL, apiKey, callSettings, ...otherSettings } = settings ?? {};
2461
+ const openaiModel = this.AISDKModel({
2462
+ context: this.context,
2463
+ provider: import_openai2.createOpenAI,
2464
+ providerParams: { baseURL, apiKey, compatibility: "strict" },
2465
+ agentCallParams: callSettings
2466
+ });
2467
+ return openaiModel(model, otherSettings);
2468
+ }
2469
+ AISDKModel = createWorkflowModel;
2470
+ };
2471
+
2472
+ // src/serve/serve-many.ts
2473
+ var getWorkflowId = (url) => {
2474
+ const components = url.split("/");
2475
+ const lastComponent = components[components.length - 1];
2476
+ return lastComponent.split("?")[0];
2477
+ };
2478
+ var serveManyBase = ({
2479
+ workflows,
2480
+ getUrl,
2481
+ serveMethod,
2482
+ options
2483
+ }) => {
2484
+ const workflowIds = [];
2485
+ const workflowMap = Object.fromEntries(
2486
+ Object.entries(workflows).map((workflow) => {
2487
+ const workflowId = workflow[0];
2488
+ if (workflowIds.includes(workflowId)) {
2489
+ throw new WorkflowError(
2490
+ `Duplicate workflow name found: '${workflowId}'. Please set different workflow names in serveMany.`
2491
+ );
2492
+ }
2493
+ if (workflowId.includes("/")) {
2494
+ throw new WorkflowError(
2495
+ `Invalid workflow name found: '${workflowId}'. Workflow name cannot contain '/'.`
2496
+ );
2497
+ }
2498
+ workflowIds.push(workflowId);
2499
+ workflow[1].workflowId = workflowId;
2500
+ workflow[1].options = {
2501
+ ...options,
2502
+ ...workflow[1].options
2503
+ };
2504
+ const params = [workflow[1].routeFunction, workflow[1].options];
2505
+ const handler = serveMethod(...params);
2506
+ return [workflowId, handler];
2507
+ })
2508
+ );
2509
+ return {
2510
+ handler: async (...params) => {
2511
+ const url = getUrl(...params);
2512
+ const pickedWorkflowId = getWorkflowId(url);
2513
+ if (!pickedWorkflowId) {
2514
+ return new Response(
2515
+ `Unexpected request in serveMany. workflowId not set. Please update the URL of your request.`,
2516
+ {
2517
+ status: 404
2518
+ }
2519
+ );
2520
+ }
2521
+ const workflow = workflowMap[pickedWorkflowId];
2522
+ if (!workflow) {
2523
+ return new Response(
2524
+ `No workflows in serveMany found for '${pickedWorkflowId}'. Please update the URL of your request.`,
2525
+ {
2526
+ status: 404
2527
+ }
2528
+ );
2529
+ }
2530
+ return await workflow(...params);
2531
+ }
2532
+ };
2533
+ };
2534
+ var getNewUrlFromWorkflowId = (url, workflowId) => {
2535
+ if (!workflowId) {
2536
+ throw new WorkflowError("You can only call workflow which has a workflowId");
2340
2537
  }
2538
+ return url.replace(/[^/]+$/, workflowId);
2341
2539
  };
2342
2540
 
2343
2541
  // src/context/context.ts
@@ -2561,60 +2759,42 @@ var WorkflowContext = class {
2561
2759
  }
2562
2760
  await this.addStep(new LazySleepUntilStep(stepName, time));
2563
2761
  }
2564
- /**
2565
- * Makes a third party call through QStash in order to make a
2566
- * network call without consuming any runtime.
2567
- *
2568
- * ```ts
2569
- * const { status, body } = await context.call<string>(
2570
- * "post call step",
2571
- * {
2572
- * url: "https://www.some-endpoint.com/api",
2573
- * method: "POST",
2574
- * body: "my-payload"
2575
- * }
2576
- * );
2577
- * ```
2578
- *
2579
- * tries to parse the result of the request as JSON. If it's
2580
- * not a JSON which can be parsed, simply returns the response
2581
- * body as it is.
2582
- *
2583
- * @param stepName
2584
- * @param url url to call
2585
- * @param method call method. "GET" by default.
2586
- * @param body call body
2587
- * @param headers call headers
2588
- * @param retries number of call retries. 0 by default
2589
- * @param timeout max duration to wait for the endpoint to respond. in seconds.
2590
- * @returns call result as {
2591
- * status: number;
2592
- * body: unknown;
2593
- * header: Record<string, string[]>
2594
- * }
2595
- */
2596
2762
  async call(stepName, settings) {
2597
- const {
2598
- url,
2599
- method = "GET",
2600
- body: requestBody,
2601
- headers = {},
2602
- retries = 0,
2603
- timeout,
2604
- flowControl
2605
- } = settings;
2606
- return await this.addStep(
2607
- new LazyCallStep(
2763
+ let callStep;
2764
+ if ("workflow" in settings) {
2765
+ const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2766
+ callStep = new LazyCallStep(
2767
+ stepName,
2768
+ url,
2769
+ "POST",
2770
+ settings.body,
2771
+ settings.headers || {},
2772
+ settings.retries || 0,
2773
+ settings.timeout,
2774
+ settings.flowControl ?? settings.workflow.options.flowControl
2775
+ );
2776
+ } else {
2777
+ const {
2778
+ url,
2779
+ method = "GET",
2780
+ body,
2781
+ headers = {},
2782
+ retries = 0,
2783
+ timeout,
2784
+ flowControl
2785
+ } = settings;
2786
+ callStep = new LazyCallStep(
2608
2787
  stepName,
2609
2788
  url,
2610
2789
  method,
2611
- requestBody,
2790
+ body,
2612
2791
  headers,
2613
2792
  retries,
2614
2793
  timeout,
2615
2794
  flowControl
2616
- )
2617
- );
2795
+ );
2796
+ }
2797
+ return await this.addStep(callStep);
2618
2798
  }
2619
2799
  /**
2620
2800
  * Pauses workflow execution until a specific event occurs or a timeout is reached.
@@ -2762,7 +2942,7 @@ var WorkflowLogger = class _WorkflowLogger {
2762
2942
  };
2763
2943
 
2764
2944
  // src/serve/authorization.ts
2765
- var import_qstash8 = require("@upstash/qstash");
2945
+ var import_qstash9 = require("@upstash/qstash");
2766
2946
  var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowContext {
2767
2947
  static disabledMessage = "disabled-qstash-worklfow-run";
2768
2948
  disabled = true;
@@ -2794,7 +2974,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2794
2974
  */
2795
2975
  static async tryAuthentication(routeFunction, context) {
2796
2976
  const disabledContext = new _DisabledWorkflowContext({
2797
- qstashClient: new import_qstash8.Client({
2977
+ qstashClient: new import_qstash9.Client({
2798
2978
  baseUrl: "disabled-client",
2799
2979
  token: "disabled-client"
2800
2980
  }),
@@ -3008,15 +3188,15 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
3008
3188
  };
3009
3189
 
3010
3190
  // src/serve/options.ts
3011
- var import_qstash9 = require("@upstash/qstash");
3012
3191
  var import_qstash10 = require("@upstash/qstash");
3192
+ var import_qstash11 = require("@upstash/qstash");
3013
3193
  var processOptions = (options) => {
3014
3194
  const environment = options?.env ?? (typeof process === "undefined" ? {} : process.env);
3015
3195
  const receiverEnvironmentVariablesSet = Boolean(
3016
3196
  environment.QSTASH_CURRENT_SIGNING_KEY && environment.QSTASH_NEXT_SIGNING_KEY
3017
3197
  );
3018
3198
  return {
3019
- qstashClient: new import_qstash10.Client({
3199
+ qstashClient: new import_qstash11.Client({
3020
3200
  baseUrl: environment.QSTASH_URL,
3021
3201
  token: environment.QSTASH_TOKEN
3022
3202
  }),
@@ -3051,7 +3231,7 @@ var processOptions = (options) => {
3051
3231
  throw error;
3052
3232
  }
3053
3233
  },
3054
- receiver: receiverEnvironmentVariablesSet ? new import_qstash9.Receiver({
3234
+ receiver: receiverEnvironmentVariablesSet ? new import_qstash10.Receiver({
3055
3235
  currentSigningKey: environment.QSTASH_CURRENT_SIGNING_KEY,
3056
3236
  nextSigningKey: environment.QSTASH_NEXT_SIGNING_KEY
3057
3237
  }) : void 0,
@@ -3060,6 +3240,7 @@ var processOptions = (options) => {
3060
3240
  retries: DEFAULT_RETRIES,
3061
3241
  useJSONContent: false,
3062
3242
  disableTelemetry: false,
3243
+ onError: console.error,
3063
3244
  ...options
3064
3245
  };
3065
3246
  };
@@ -3109,7 +3290,8 @@ var serveBase = (routeFunction, telemetry, options) => {
3109
3290
  retries,
3110
3291
  useJSONContent,
3111
3292
  disableTelemetry,
3112
- flowControl
3293
+ flowControl,
3294
+ onError
3113
3295
  } = processOptions(options);
3114
3296
  telemetry = disableTelemetry ? void 0 : telemetry;
3115
3297
  const debug = WorkflowLogger.getLogger(verbose);
@@ -3238,8 +3420,19 @@ var serveBase = (routeFunction, telemetry, options) => {
3238
3420
  try {
3239
3421
  return await handler(request);
3240
3422
  } catch (error) {
3241
- console.error(error);
3242
- return new Response(JSON.stringify(formatWorkflowError(error)), {
3423
+ const formattedError = formatWorkflowError(error);
3424
+ try {
3425
+ onError?.(error);
3426
+ } catch (onErrorError) {
3427
+ const formattedOnErrorError = formatWorkflowError(onErrorError);
3428
+ const errorMessage = `Error while running onError callback: '${formattedOnErrorError.message}'.
3429
+ Original error: '${formattedError.message}'`;
3430
+ console.error(errorMessage);
3431
+ return new Response(errorMessage, {
3432
+ status: 500
3433
+ });
3434
+ }
3435
+ return new Response(JSON.stringify(formattedError), {
3243
3436
  status: 500
3244
3437
  });
3245
3438
  }