@upstash/workflow 1.3.3 → 1.4.0

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/tanstack.js CHANGED
@@ -26,6 +26,9 @@ __export(tanstack_exports, {
26
26
  });
27
27
  module.exports = __toCommonJS(tanstack_exports);
28
28
 
29
+ // src/serve/index.ts
30
+ var import_qstash12 = require("@upstash/qstash");
31
+
29
32
  // src/client/utils.ts
30
33
  var import_qstash2 = require("@upstash/qstash");
31
34
 
@@ -781,6 +784,10 @@ var triggerFirstInvocation = async (params) => {
781
784
  workflowConfig: {
782
785
  workflowRunId: workflowContext.workflowRunId,
783
786
  workflowUrl: workflowContext.url,
787
+ // the run doesn't exist yet, so the trigger time is sent when the creation time
788
+ // is not known. serve and client.trigger set it on the context already, so a
789
+ // retry of this request carries the same value and is deduplicated.
790
+ workflowRunCreatedAt: workflowContext.workflowRunCreatedAt || Date.now(),
784
791
  failureUrl,
785
792
  retries,
786
793
  retryDelay,
@@ -884,7 +891,10 @@ var triggerWorkflowDelete = async (workflowContext, result, cancel = false, disp
884
891
  path: ["v2", "workflows", "runs", `${workflowContext.workflowRunId}?cancel=${cancel}`],
885
892
  method: "DELETE",
886
893
  parseResponseAsJson: false,
887
- body: JSON.stringify(result)
894
+ body: JSON.stringify(result),
895
+ // with the creation time, QStash deletes the run only if it is the same run.
896
+ // a late delete of a previous run can't delete a new run with the same id.
897
+ headers: workflowContext.workflowRunCreatedAt ? { [WORKFLOW_CREATED_AT_HEADER]: workflowContext.workflowRunCreatedAt.toString() } : void 0
888
898
  });
889
899
  await dispatchDebug?.("onInfo", {
890
900
  info: `Workflow run ${workflowContext.workflowRunId} deleted from QStash successfully.`
@@ -961,6 +971,7 @@ ${atob(callbackMessage.body ?? "")}`
961
971
  const concurrentString = request.headers.get("Upstash-Workflow-Concurrent");
962
972
  const contentType = request.headers.get("Upstash-Workflow-ContentType");
963
973
  const invokeCount = request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER);
974
+ const workflowRunCreatedAt = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
964
975
  if (!(workflowRunId && stepIdString && stepName && StepTypes.includes(stepType) && concurrentString && contentType)) {
965
976
  throw new Error(
966
977
  `Missing info in callback message source header: ${JSON.stringify({
@@ -978,6 +989,7 @@ ${atob(callbackMessage.body ?? "")}`
978
989
  workflowConfig: {
979
990
  workflowRunId,
980
991
  workflowUrl,
992
+ workflowRunCreatedAt: Number(workflowRunCreatedAt ?? "0"),
981
993
  telemetry: telemetry2
982
994
  },
983
995
  invokeCount: Number(invokeCount)
@@ -1125,6 +1137,7 @@ var BaseLazyStep = class _BaseLazyStep {
1125
1137
  workflowConfig: {
1126
1138
  workflowRunId: context.workflowRunId,
1127
1139
  workflowUrl: context.url,
1140
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
1128
1141
  useJSONContent: false,
1129
1142
  telemetry: telemetry2
1130
1143
  },
@@ -1452,6 +1465,8 @@ var LazyWaitEventStep = class extends BaseLazyStep {
1452
1465
  ) : {},
1453
1466
  // note: using WORKFLOW_ID_HEADER doesn't work, because Runid -> RunId:
1454
1467
  "Upstash-Workflow-Runid": [context.workflowRunId],
1468
+ // same for WORKFLOW_CREATED_AT_HEADER, because Createdat -> CreatedAt:
1469
+ ...context.workflowRunCreatedAt ? { "Upstash-Workflow-Createdat": [context.workflowRunCreatedAt.toString()] } : {},
1455
1470
  [WORKFLOW_INIT_HEADER]: ["false"],
1456
1471
  [WORKFLOW_URL_HEADER]: [context.url],
1457
1472
  "Upstash-Workflow-CallType": ["step"]
@@ -1554,6 +1569,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1554
1569
  workflowConfig: {
1555
1570
  workflowRunId: context.workflowRunId,
1556
1571
  workflowUrl: context.url,
1572
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
1557
1573
  telemetry: telemetry2,
1558
1574
  useJSONContent: false
1559
1575
  },
@@ -1563,6 +1579,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1563
1579
  invokerHeaders[key] = value;
1564
1580
  });
1565
1581
  invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
1582
+ if (context.workflowRunCreatedAt) {
1583
+ invokerHeaders["Upstash-Workflow-Createdat"] = context.workflowRunCreatedAt.toString();
1584
+ }
1566
1585
  const request = {
1567
1586
  body: stringifyBody(this.params.body),
1568
1587
  headers: Object.fromEntries(
@@ -1591,6 +1610,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1591
1610
  workflowConfig: {
1592
1611
  workflowRunId: getWorkflowRunId(workflowRunId),
1593
1612
  workflowUrl: newUrl,
1613
+ // the invoked run doesn't exist yet, so the creation time of the invoker run is sent.
1614
+ // it separates the invocations made by different runs of the invoker.
1615
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
1594
1616
  retries,
1595
1617
  retryDelay,
1596
1618
  telemetry: telemetry2,
@@ -1755,6 +1777,9 @@ var WorkflowHeaders = class {
1755
1777
  [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
1756
1778
  ...this.workflowConfig.telemetry ? getTelemetryHeaders(this.workflowConfig.telemetry) : {}
1757
1779
  };
1780
+ if (this.workflowConfig.workflowRunCreatedAt) {
1781
+ this.headers.rawHeaders[WORKFLOW_CREATED_AT_HEADER] = this.workflowConfig.workflowRunCreatedAt.toString();
1782
+ }
1758
1783
  if (this.stepInfo?.lazyStep.stepType !== "Call") {
1759
1784
  this.headers.rawHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
1760
1785
  }
@@ -1914,6 +1939,7 @@ var submitParallelSteps = async ({
1914
1939
  workflowConfig: {
1915
1940
  workflowRunId: context.workflowRunId,
1916
1941
  workflowUrl: context.url,
1942
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
1917
1943
  telemetry: telemetry2
1918
1944
  },
1919
1945
  invokeCount
@@ -3415,7 +3441,13 @@ var createRegionalHandler = (environment, receiverConfig, region, clientOptions)
3415
3441
  const client = new import_qstash11.Client({
3416
3442
  ...clientOptions,
3417
3443
  baseUrl: clientEnv.QSTASH_URL,
3418
- token: clientEnv.QSTASH_TOKEN
3444
+ token: clientEnv.QSTASH_TOKEN,
3445
+ // Mirror the receiver's dev-mode decision so a single QSTASH_DEV=true points
3446
+ // the client at the local dev server too. Without this the QStash Client
3447
+ // re-derives dev mode from its own process.env, which is blind to the
3448
+ // Cloudflare worker `env` binding that actually carries QSTASH_DEV there.
3449
+ // An explicit devMode in the user's client config still wins.
3450
+ devMode: clientOptions?.devMode ?? isQStashDevModeEnabled(environment)
3419
3451
  });
3420
3452
  const receiver = getReceiver(environment, receiverConfig, region);
3421
3453
  return { client, receiver };
@@ -3465,7 +3497,9 @@ var getQStashHandlers = ({
3465
3497
  client: qstashClientOption && "http" in qstashClientOption ? qstashClientOption : new import_qstash11.Client({
3466
3498
  ...qstashClientOption,
3467
3499
  baseUrl: environment.QSTASH_URL,
3468
- token: environment.QSTASH_TOKEN
3500
+ token: environment.QSTASH_TOKEN,
3501
+ // Mirror the receiver's dev-mode decision (see createRegionalHandler).
3502
+ devMode: qstashClientOption?.devMode ?? isQStashDevModeEnabled(environment)
3469
3503
  }),
3470
3504
  receiver: getReceiver(environment, receiverConfig)
3471
3505
  }
@@ -3804,7 +3838,8 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
3804
3838
  const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
3805
3839
  const retried = Number(request.headers.get(WORKFLOW_RETRIED_HEADER) ?? "0");
3806
3840
  const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
3807
- const workflowRunCreatedAt = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
3841
+ const workflowRunCreatedAtHeader = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
3842
+ const workflowRunCreatedAt = workflowRunCreatedAtHeader ? Number(workflowRunCreatedAtHeader) : isFirstInvocation ? Date.now() : 0;
3808
3843
  const workflowContext = new WorkflowContext({
3809
3844
  qstashClient: regionalClient,
3810
3845
  workflowRunId,
@@ -3817,7 +3852,7 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
3817
3852
  invokeCount,
3818
3853
  label,
3819
3854
  retried,
3820
- workflowRunCreatedAt: Number(workflowRunCreatedAt),
3855
+ workflowRunCreatedAt,
3821
3856
  middlewareManager
3822
3857
  });
3823
3858
  const authCheck = await DisabledWorkflowContext.tryAuthentication(
@@ -3940,12 +3975,14 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
3940
3975
  };
3941
3976
 
3942
3977
  // platforms/tanstack.ts
3978
+ var import_qstash13 = require("@upstash/qstash");
3943
3979
  var telemetry = {
3944
3980
  sdk: SDK_TELEMETRY,
3945
3981
  framework: "tanstack",
3946
3982
  runtime: `node@${process.version}`
3947
3983
  };
3948
3984
  function serve(routeFunction, options) {
3985
+ void (0, import_qstash13.startDevServer)();
3949
3986
  const POST = (tanstackContext) => {
3950
3987
  const { handler } = serveBase(
3951
3988
  routeFunction,
package/tanstack.mjs CHANGED
@@ -2,15 +2,17 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-WEQGCISK.mjs";
5
+ } from "./chunk-DRHEHWMS.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,