@upstash/workflow 1.3.2 → 1.4.0-rc

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.
Files changed (50) hide show
  1. package/astro.d.mts +3 -2
  2. package/astro.d.ts +3 -2
  3. package/astro.js +595 -140
  4. package/astro.mjs +3 -1
  5. package/{chunk-ICDNN4UW.mjs → chunk-UH6O5IJY.mjs} +751 -281
  6. package/cloudflare.d.mts +3 -2
  7. package/cloudflare.d.ts +3 -2
  8. package/cloudflare.js +595 -140
  9. package/cloudflare.mjs +3 -1
  10. package/express.d.mts +3 -2
  11. package/express.d.ts +3 -2
  12. package/express.js +596 -140
  13. package/express.mjs +4 -1
  14. package/h3.d.mts +3 -2
  15. package/h3.d.ts +3 -2
  16. package/h3.js +595 -140
  17. package/h3.mjs +3 -1
  18. package/hono.d.mts +3 -2
  19. package/hono.d.ts +3 -2
  20. package/hono.js +595 -140
  21. package/hono.mjs +3 -1
  22. package/index.d.mts +64 -17
  23. package/index.d.ts +64 -17
  24. package/index.js +652 -150
  25. package/index.mjs +49 -11
  26. package/nextjs.d.mts +3 -2
  27. package/nextjs.d.ts +3 -2
  28. package/nextjs.js +596 -140
  29. package/nextjs.mjs +4 -1
  30. package/package.json +1 -1
  31. package/react-router.d.mts +3 -2
  32. package/react-router.d.ts +3 -2
  33. package/react-router.js +595 -140
  34. package/react-router.mjs +3 -1
  35. package/{serve-many-iJF1IUXk.d.ts → serve-many-BCtZg31b.d.ts} +1 -1
  36. package/{serve-many-CG3BFvO3.d.mts → serve-many-CbIV7145.d.mts} +1 -1
  37. package/solidjs.d.mts +2 -1
  38. package/solidjs.d.ts +2 -1
  39. package/solidjs.js +595 -140
  40. package/solidjs.mjs +3 -1
  41. package/svelte.d.mts +3 -2
  42. package/svelte.d.ts +3 -2
  43. package/svelte.js +595 -140
  44. package/svelte.mjs +3 -1
  45. package/tanstack.d.mts +3 -2
  46. package/tanstack.d.ts +3 -2
  47. package/tanstack.js +595 -140
  48. package/tanstack.mjs +3 -1
  49. package/{types-CekOpKvz.d.ts → types-ffLPVG5_.d.mts} +248 -8
  50. package/{types-CekOpKvz.d.mts → types-ffLPVG5_.d.ts} +248 -8
package/tanstack.mjs CHANGED
@@ -2,15 +2,17 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-ICDNN4UW.mjs";
5
+ } from "./chunk-UH6O5IJY.mjs";
6
6
 
7
7
  // platforms/tanstack.ts
8
+ import { startDevServer } from "@upstash/qstash";
8
9
  var telemetry = {
9
10
  sdk: SDK_TELEMETRY,
10
11
  framework: "tanstack",
11
12
  runtime: `node@${process.version}`
12
13
  };
13
14
  function serve(routeFunction, options) {
15
+ void startDevServer();
14
16
  const POST = (tanstackContext) => {
15
17
  const { handler } = serveBase(
16
18
  routeFunction,
@@ -1,5 +1,6 @@
1
1
  import { QstashError, PublishRequest, HTTPMethods as HTTPMethods$1, FlowControl, Client, Receiver } from '@upstash/qstash';
2
2
  import { z } from 'zod';
3
+ import { Ok, Err } from 'neverthrow';
3
4
 
4
5
  /**
5
6
  * Error raised during Workflow execution
@@ -170,7 +171,14 @@ type HeadersResponse = {
170
171
  type StepParams = {
171
172
  context: WorkflowContext;
172
173
  } & Pick<HeaderParams, "telemetry"> & Required<Pick<HeaderParams, "step" | "invokeCount">>;
173
- type GetHeaderParams = StepParams;
174
+ type GetHeaderParams = StepParams & {
175
+ /**
176
+ * step-level settings to apply to the message being published. Set
177
+ * when the next step has settings and this step's submission is what
178
+ * will produce the delivery that executes it.
179
+ */
180
+ stepSettings?: StepSettings;
181
+ };
174
182
  type GetBodyParams = StepParams & Omit<HeadersResponse, "contentType">;
175
183
  type SubmitStepParams = StepParams & Pick<HeadersResponse, "headers"> & {
176
184
  body: string;
@@ -188,7 +196,27 @@ declare abstract class BaseLazyStep<TResult = unknown> {
188
196
  abstract readonly stepType: StepType;
189
197
  protected abstract readonly allowUndefinedOut: boolean;
190
198
  protected readonly context: WorkflowContext;
191
- constructor(context: WorkflowContext, stepName: string);
199
+ /**
200
+ * step-level settings (flow control, retries etc.) which override the
201
+ * settings the workflow run was triggered with, for this step only.
202
+ */
203
+ readonly stepSettings?: StepSettings;
204
+ /**
205
+ * whether this step's result can be submitted after the route function
206
+ * has moved on, instead of right away.
207
+ *
208
+ * Enabled for steps whose `getResultStep` produces the final `out` —
209
+ * which is not the same as "needs no server round trip":
210
+ * `LazyCreateWebhookStep` builds its result in `getBody` and returns
211
+ * `out: undefined` from `getResultStep`, so deferring it would hand
212
+ * `undefined` to the route function.
213
+ *
214
+ * Deferring lets the route function continue and reveal the next step,
215
+ * so that step's settings can ride on this step's submission instead
216
+ * of needing a step config request of their own.
217
+ */
218
+ readonly supportsDeferredSubmission: boolean;
219
+ constructor(context: WorkflowContext, stepName: string, stepSettings?: StepSettings);
192
220
  /**
193
221
  * plan step to submit when step will run parallel with other
194
222
  * steps (parallel call state `first`)
@@ -219,7 +247,7 @@ declare abstract class BaseLazyStep<TResult = unknown> {
219
247
  protected handleUndefinedOut(step: Step): TResult;
220
248
  protected static tryParsing(stepOut: unknown): any;
221
249
  getBody({ step }: GetBodyParams): string;
222
- getHeaders({ context, telemetry, invokeCount, step }: GetHeaderParams): HeadersResponse;
250
+ getHeaders({ context, telemetry, invokeCount, step, stepSettings, }: GetHeaderParams): HeadersResponse;
223
251
  submitStep({ context, body, headers }: SubmitStepParams): Promise<{
224
252
  messageId: string;
225
253
  }[]>;
@@ -236,6 +264,63 @@ type WaitForWebhookResponse = {
236
264
  request: undefined;
237
265
  };
238
266
 
267
+ /**
268
+ * The configuration QStash applied to the delivery in hand.
269
+ *
270
+ * Reported on every delivery through the `Upstash-Flow-Control-*`,
271
+ * `Upstash-Retries` and `Upstash-Retry-Delay` headers. For an ordinary delivery this is the configuration the run was triggered with; for a
272
+ * step-configured delivery it is that step's own configuration, which
273
+ * delivery is meant to execute.
274
+ */
275
+ type EffectiveConfig = {
276
+ /**
277
+ * flow control applied to this delivery, if any
278
+ */
279
+ flowControl?: NormalizedFlowControl;
280
+ /**
281
+ * retry limit of this delivery, or undefined when QStash did not
282
+ * report one (a version which predates the header)
283
+ */
284
+ retries?: number;
285
+ /**
286
+ * retry delay expression applied to this delivery, if any
287
+ */
288
+ retryDelay?: string;
289
+ /**
290
+ * whether the message of this delivery was published with step-level
291
+ * settings (the guard marker).
292
+ */
293
+ hasStepConfig: boolean;
294
+ };
295
+ /**
296
+ * Flow control reduced to a form both sides of the protocol agree on.
297
+ *
298
+ * Needed because the SDK and QStash format the same values differently:
299
+ * the SDK joins the control value with ", " and writes durations
300
+ * (`period=1m`), QStash joins with "," and writes whole seconds
301
+ * (`period=60`). `rate` and `ratePerSecond` are aliases on the SDK side.
302
+ * Comparing the header strings would report a mismatch for values which
303
+ * are in fact identical, so both sides are parsed into this shape first.
304
+ */
305
+ type NormalizedFlowControl = {
306
+ key: string;
307
+ parallelism: number;
308
+ rate: number;
309
+ /**
310
+ * period in whole seconds
311
+ */
312
+ period: number;
313
+ };
314
+
315
+ /**
316
+ * What came of submitting the step being held, if one was.
317
+ */
318
+ type PendingStepOutcome = {
319
+ result: "submitted-step";
320
+ abort: WorkflowAbort;
321
+ } | {
322
+ result: "no-pending-step";
323
+ };
239
324
  declare class AutoExecutor {
240
325
  private context;
241
326
  private promises;
@@ -250,6 +335,25 @@ declare class AutoExecutor {
250
335
  stepCount: number;
251
336
  planStepCount: number;
252
337
  protected executingStep: string | false;
338
+ /**
339
+ * an executed step whose result hasn't been submitted to QStash yet.
340
+ *
341
+ * Set when a step which can produce its result in-process executes. The
342
+ * submission waits so that the route function can continue and reveal
343
+ * what comes next: if that is a single step with step-level settings,
344
+ * the settings ride on this submission and no step config request is
345
+ * needed, since the delivery of the submission is what executes it.
346
+ *
347
+ * Flushed when the next step is reached (see `addStep`) or when the
348
+ * route function ends (see `flushPendingStep` in `serve`).
349
+ */
350
+ private pendingStep?;
351
+ /**
352
+ * configuration QStash applied to the delivery being handled. A step
353
+ * with step-level settings is settled by comparing its settings against
354
+ * this.
355
+ */
356
+ private readonly effectiveConfig;
253
357
  /**
254
358
  * @param context workflow context
255
359
  * @param steps list of steps
@@ -257,8 +361,10 @@ declare class AutoExecutor {
257
361
  * @param dispatchLifecycle lifecycle event dispatcher
258
362
  * @param telemetry optional telemetry information
259
363
  * @param invokeCount optional invoke count
364
+ * @param effectiveConfig configuration QStash applied to the delivery
365
+ * being handled
260
366
  */
261
- constructor(context: WorkflowContext, steps: Step[], dispatchDebug: DispatchDebug, dispatchLifecycle: DispatchLifecycle, telemetry?: Telemetry, invokeCount?: number);
367
+ constructor(context: WorkflowContext, steps: Step[], dispatchDebug: DispatchDebug, dispatchLifecycle: DispatchLifecycle, telemetry?: Telemetry, invokeCount?: number, effectiveConfig?: EffectiveConfig);
262
368
  /**
263
369
  * Adds the step function to the list of step functions to run in
264
370
  * parallel. After adding the function, defers the execution, so
@@ -300,6 +406,31 @@ declare class AutoExecutor {
300
406
  * @returns step result
301
407
  */
302
408
  protected runSingle<TResult>(lazyStep: BaseLazyStep<TResult>): Promise<TResult>;
409
+ /**
410
+ * Submits the result of the step being held, if there is one, and
411
+ * returns the abort the caller has to throw to end the invocation.
412
+ *
413
+ * Returns undefined when no step is being held, which is the caller's
414
+ * signal that there is nothing to end. Throws instead of returning
415
+ * when the submission itself fails, so that error reaches the caller
416
+ * rather than an abort claiming the step was submitted.
417
+ *
418
+ * Callers which arrive while a submission is already under way (the
419
+ * steps of a parallel group, added together) wait for that one and get
420
+ * the same abort, rather than submitting a second time.
421
+ *
422
+ * The next step's settings are attached whenever it has any, without
423
+ * checking them against the current delivery: the executor only knows
424
+ * the configuration of the delivery in hand, which inside a
425
+ * delivery is the *previous* step's, so such a check would be wrong
426
+ * exactly when two steps with settings follow each other.
427
+ *
428
+ * @param nextStepSettings step-level settings of the next step
429
+ * @returns `submitted-step` with the abort which ends this invocation,
430
+ * or `no-pending-step` when nothing was held and there is nothing to
431
+ * end
432
+ */
433
+ submitPendingStep(nextStepSettings?: StepSettings): Promise<Ok<PendingStepOutcome, never> | Err<never, Error>>;
303
434
  /**
304
435
  * Runs steps in parallel.
305
436
  *
@@ -715,7 +846,41 @@ declare class WorkflowContext<TInitialPayload = unknown> {
715
846
  * `1` on the first retry, `2` on the second, and so on.
716
847
  */
717
848
  readonly retried: number;
718
- constructor({ qstashClient, workflowRunId, workflowRunCreatedAt, headers, steps, url, initialPayload, env, telemetry, invokeCount, label, retried, middlewareManager, }: {
849
+ /**
850
+ * Configuration QStash applied to the request being handled.
851
+ *
852
+ * This is the configuration of *this delivery*, not of the run: it is
853
+ * the configuration the run was triggered with, except inside the
854
+ * delivery which executes a step that has step-level settings, where
855
+ * it is that step's settings. The fields below expose it; the executor
856
+ * gets it directly rather than reaching through the context.
857
+ */
858
+ private readonly effectiveConfig;
859
+ /**
860
+ * Flow control QStash applied to the request being handled, if any.
861
+ *
862
+ * This is the flow control of the request in hand, which is the one the
863
+ * run was triggered with except inside a step carrying its own.
864
+ */
865
+ get flowControl(): NormalizedFlowControl | undefined;
866
+ /**
867
+ * Retry limit QStash applied to the request being handled, if it
868
+ * reported one.
869
+ *
870
+ * Not to be confused with {@link retried}, which is how many retries
871
+ * have already happened.
872
+ *
873
+ * @see {@link flowControl} for what "the request being handled" means
874
+ */
875
+ get retries(): number | undefined;
876
+ /**
877
+ * Retry delay expression QStash applied to the request being handled,
878
+ * if any.
879
+ *
880
+ * @see {@link flowControl} for what "the request being handled" means
881
+ */
882
+ get retryDelay(): string | undefined;
883
+ constructor({ qstashClient, workflowRunId, workflowRunCreatedAt, headers, steps, url, initialPayload, env, telemetry, invokeCount, label, retried, middlewareManager, effectiveConfig, }: {
719
884
  qstashClient: WorkflowClient;
720
885
  workflowRunId: string;
721
886
  workflowRunCreatedAt: number;
@@ -729,6 +894,12 @@ declare class WorkflowContext<TInitialPayload = unknown> {
729
894
  label?: string | string[];
730
895
  retried?: number;
731
896
  middlewareManager?: MiddlewareManager<TInitialPayload>;
897
+ /**
898
+ * configuration QStash applied to the delivery being handled, read
899
+ * from its headers. Defaults to no flow control and no retries,
900
+ * which is what a context created outside a delivery observes.
901
+ */
902
+ effectiveConfig?: EffectiveConfig;
732
903
  });
733
904
  /**
734
905
  * Executes a workflow step
@@ -753,11 +924,28 @@ declare class WorkflowContext<TInitialPayload = unknown> {
753
924
  * ])
754
925
  * ```
755
926
  *
927
+ * Step-level settings can be passed as a third argument, overriding
928
+ * the settings the workflow run was triggered with for this step only:
929
+ *
930
+ * ```typescript
931
+ * const result = await context.run(
932
+ * "step 1",
933
+ * () => {
934
+ * return "result"
935
+ * },
936
+ * {
937
+ * flowControl: { key: "custom-key", parallelism: 3 },
938
+ * retries: 5,
939
+ * }
940
+ * )
941
+ * ```
942
+ *
756
943
  * @param stepName name of the step
757
944
  * @param stepFunction step function to be executed
945
+ * @param stepSettings step-level settings for this step
758
946
  * @returns result of the step function
759
947
  */
760
- run<TResult>(stepName: string, stepFunction: StepFunction<TResult>): Promise<TResult>;
948
+ run<TResult>(stepName: string, stepFunction: StepFunction<TResult>, stepSettings?: StepSettings): Promise<TResult>;
761
949
  /**
762
950
  * Stops the execution for the duration provided.
763
951
  *
@@ -1003,7 +1191,7 @@ type Step<TResult = unknown, TBody = unknown> = {
1003
1191
  type RawStep = {
1004
1192
  messageId: string;
1005
1193
  body: string;
1006
- callType: "step" | "toCallback" | "fromCallback";
1194
+ callType: "step" | "toCallback" | "fromCallback" | "stepConfig";
1007
1195
  };
1008
1196
  type SyncStepFunction<TResult> = () => TResult;
1009
1197
  type AsyncStepFunction<TResult> = () => Promise<TResult>;
@@ -1215,6 +1403,58 @@ interface WaitEventOptions {
1215
1403
  */
1216
1404
  timeout?: number | Duration;
1217
1405
  }
1406
+ /**
1407
+ * Step-level settings which override the workflow run settings
1408
+ * passed in `client.trigger` for the execution of a single step.
1409
+ *
1410
+ * Passed as the third argument of `context.run`:
1411
+ *
1412
+ * ```ts
1413
+ * const result = await context.run(
1414
+ * "step",
1415
+ * () => { ... },
1416
+ * { flowControl: { key: "custom-key", parallelism: 3 }, retries: 5 }
1417
+ * );
1418
+ * ```
1419
+ *
1420
+ * The settings must be applied to the request whose delivery executes
1421
+ * the step:
1422
+ *
1423
+ * - a step running in parallel with others carries its settings on its
1424
+ * own plan step, whose delivery is what executes the step. No extra
1425
+ * request is made.
1426
+ * - otherwise, the SDK can only learn about the step once the workflow
1427
+ * function has been replayed, which happens in a delivery that was
1428
+ * published before the step was known. So instead of executing the
1429
+ * step in that delivery, a hidden request carrying the
1430
+ * settings is published and the step executes when QStash delivers it.
1431
+ * This costs one extra message and one extra endpoint invocation per
1432
+ * step which carries settings. QStash hides the request from the
1433
+ * step logs.
1434
+ */
1435
+ type StepSettings = {
1436
+ /**
1437
+ * Settings for controlling the number of active requests
1438
+ * and number of requests per second with the same key
1439
+ * while executing this step.
1440
+ *
1441
+ * Overrides the flow control settings passed when triggering
1442
+ * the workflow for this step only.
1443
+ */
1444
+ flowControl?: FlowControl;
1445
+ /**
1446
+ * Number of times QStash will retry the delivery which executes
1447
+ * this step.
1448
+ *
1449
+ * Overrides the retries passed when triggering the workflow for
1450
+ * this step only.
1451
+ */
1452
+ retries?: number;
1453
+ /**
1454
+ * Delay between retries of the delivery which executes this step.
1455
+ */
1456
+ retryDelay?: string;
1457
+ };
1218
1458
  type CallSettings = {
1219
1459
  url: string;
1220
1460
  method?: HTTPMethods$1;
@@ -1342,4 +1582,4 @@ type InvokableWorkflow<TInitialPayload, TResult> = {
1342
1582
  useJSONContent?: boolean;
1343
1583
  };
1344
1584
 
1345
- export { type AsyncStepFunction as A, type CallResponse as C, type DetailedFinishCondition as D, type ExclusiveValidationOptions as E, type FailureFunctionPayload as F, type HeaderParams as H, type InvokableWorkflow as I, type LazyInvokeStepParams as L, type NotifyResponse as N, type ParallelCallState as P, type QStashClientExtraConfig as Q, type RawStep as R, type StepType as S, type Telemetry as T, WorkflowMiddleware as W, type WorkflowClient as a, type WorkflowReceiver as b, type RouteFunction as c, type WorkflowServeOptions as d, type Waiter as e, type CallSettings as f, type Duration as g, type FinishCondition as h, type InvokeStepResponse as i, type InvokeWorkflowRequest as j, type NotifyStepResponse as k, type RequiredExceptFields as l, type Step as m, type StepFunction as n, StepTypes as o, type SyncStepFunction as p, type WaitEventOptions as q, type WaitRequest as r, type WaitStepResponse as s, WorkflowAbort as t, WorkflowContext as u, WorkflowError as v, WorkflowNonRetryableError as w, WorkflowRetryAfterError as x };
1585
+ export { type AsyncStepFunction as A, type CallResponse as C, type DetailedFinishCondition as D, type ExclusiveValidationOptions as E, type FailureFunctionPayload as F, type HeaderParams as H, type InvokableWorkflow as I, type LazyInvokeStepParams as L, type NotifyResponse as N, type ParallelCallState as P, type QStashClientExtraConfig as Q, type RawStep as R, type StepType as S, type Telemetry as T, WorkflowMiddleware as W, type WorkflowClient as a, type WorkflowReceiver as b, type RouteFunction as c, type WorkflowServeOptions as d, type Waiter as e, type CallSettings as f, type Duration as g, type FinishCondition as h, type InvokeStepResponse as i, type InvokeWorkflowRequest as j, type NotifyStepResponse as k, type RequiredExceptFields as l, type Step as m, type StepFunction as n, type StepSettings as o, StepTypes as p, type SyncStepFunction as q, type WaitEventOptions as r, type WaitRequest as s, type WaitStepResponse as t, WorkflowAbort as u, WorkflowContext as v, WorkflowError as w, WorkflowNonRetryableError as x, WorkflowRetryAfterError as y };