@upstash/workflow 0.2.13 → 0.2.15

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,7 +94,7 @@ 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.13";
97
+ var VERSION = "v0.2.15";
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";
@@ -132,6 +132,16 @@ var WorkflowAbort = class extends Error {
132
132
  this.cancelWorkflow = cancelWorkflow;
133
133
  }
134
134
  };
135
+ var WorkflowNonRetryableError = class extends WorkflowAbort {
136
+ /**
137
+ * @param message error message to be displayed
138
+ */
139
+ constructor(message) {
140
+ super("fail", void 0, false);
141
+ this.name = "WorkflowNonRetryableError";
142
+ if (message) this.message = message;
143
+ }
144
+ };
135
145
  var formatWorkflowError = (error) => {
136
146
  return error instanceof Error ? {
137
147
  error: error.name,
@@ -602,59 +612,72 @@ var StepTypes = [
602
612
 
603
613
  // src/workflow-requests.ts
604
614
  var import_qstash3 = require("@upstash/qstash");
605
- var triggerFirstInvocation = async ({
606
- workflowContext,
607
- useJSONContent,
608
- telemetry,
609
- debug,
610
- invokeCount,
611
- delay
612
- }) => {
613
- const { headers } = getHeaders({
614
- initHeaderValue: "true",
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
626
- });
627
- if (workflowContext.headers.get("content-type")) {
628
- headers["content-type"] = workflowContext.headers.get("content-type");
629
- }
630
- if (useJSONContent) {
631
- headers["content-type"] = "application/json";
632
- }
633
- try {
634
- const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
635
- const result = await workflowContext.qstashClient.publish({
636
- headers,
637
- method: "POST",
638
- body,
639
- url: workflowContext.url,
640
- delay
641
- });
642
- if (result.deduplicated) {
643
- await debug?.log("WARN", "SUBMIT_FIRST_INVOCATION", {
644
- message: `Workflow run ${workflowContext.workflowRunId} already exists. A new one isn't created.`,
615
+ var triggerFirstInvocation = async (params) => {
616
+ const firstInvocationParams = Array.isArray(params) ? params : [params];
617
+ const workflowContextClient = firstInvocationParams[0].workflowContext.qstashClient;
618
+ const invocationBatch = firstInvocationParams.map(
619
+ ({ workflowContext, useJSONContent, telemetry, invokeCount, delay }) => {
620
+ const { headers } = getHeaders({
621
+ initHeaderValue: "true",
622
+ workflowConfig: {
623
+ workflowRunId: workflowContext.workflowRunId,
624
+ workflowUrl: workflowContext.url,
625
+ failureUrl: workflowContext.failureUrl,
626
+ retries: workflowContext.retries,
627
+ telemetry,
628
+ flowControl: workflowContext.flowControl,
629
+ useJSONContent: useJSONContent ?? false
630
+ },
631
+ invokeCount: invokeCount ?? 0,
632
+ userHeaders: workflowContext.headers
633
+ });
634
+ if (workflowContext.headers.get("content-type")) {
635
+ headers["content-type"] = workflowContext.headers.get("content-type");
636
+ }
637
+ if (useJSONContent) {
638
+ headers["content-type"] = "application/json";
639
+ }
640
+ const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
641
+ return {
645
642
  headers,
646
- requestPayload: workflowContext.requestPayload,
643
+ method: "POST",
644
+ body,
647
645
  url: workflowContext.url,
648
- messageId: result.messageId
649
- });
646
+ delay
647
+ };
648
+ }
649
+ );
650
+ try {
651
+ const results = await workflowContextClient.batch(invocationBatch);
652
+ const invocationStatuses = [];
653
+ for (let i = 0; i < results.length; i++) {
654
+ const result = results[i];
655
+ const invocationParams = firstInvocationParams[i];
656
+ if (result.deduplicated) {
657
+ await invocationParams.debug?.log("WARN", "SUBMIT_FIRST_INVOCATION", {
658
+ message: `Workflow run ${invocationParams.workflowContext.workflowRunId} already exists. A new one isn't created.`,
659
+ headers: invocationBatch[i].headers,
660
+ requestPayload: invocationParams.workflowContext.requestPayload,
661
+ url: invocationParams.workflowContext.url,
662
+ messageId: result.messageId
663
+ });
664
+ invocationStatuses.push("workflow-run-already-exists");
665
+ } else {
666
+ await invocationParams.debug?.log("SUBMIT", "SUBMIT_FIRST_INVOCATION", {
667
+ headers: invocationBatch[i].headers,
668
+ requestPayload: invocationParams.workflowContext.requestPayload,
669
+ url: invocationParams.workflowContext.url,
670
+ messageId: result.messageId
671
+ });
672
+ invocationStatuses.push("success");
673
+ }
674
+ }
675
+ const hasAnyDeduplicated = invocationStatuses.some(
676
+ (status) => status === "workflow-run-already-exists"
677
+ );
678
+ if (hasAnyDeduplicated) {
650
679
  return ok("workflow-run-already-exists");
651
680
  } else {
652
- await debug?.log("SUBMIT", "SUBMIT_FIRST_INVOCATION", {
653
- headers,
654
- requestPayload: workflowContext.requestPayload,
655
- url: workflowContext.url,
656
- messageId: result.messageId
657
- });
658
681
  return ok("success");
659
682
  }
660
683
  } catch (error) {
@@ -683,6 +706,8 @@ var triggerRouteFunction = async ({
683
706
  return ok("workflow-was-finished");
684
707
  } else if (!(error_ instanceof WorkflowAbort)) {
685
708
  return err(error_);
709
+ } else if (error_ instanceof WorkflowNonRetryableError) {
710
+ return ok(error_);
686
711
  } else if (error_.cancelWorkflow) {
687
712
  await onCancel();
688
713
  return ok("workflow-finished");
@@ -844,7 +869,7 @@ ${atob(callbackMessage.body ?? "")}`
844
869
  var getTelemetryHeaders = (telemetry) => {
845
870
  return {
846
871
  [TELEMETRY_HEADER_SDK]: telemetry.sdk,
847
- [TELEMETRY_HEADER_FRAMEWORK]: telemetry.framework,
872
+ [TELEMETRY_HEADER_FRAMEWORK]: telemetry.framework ?? "unknown",
848
873
  [TELEMETRY_HEADER_RUNTIME]: telemetry.runtime ?? "unknown"
849
874
  };
850
875
  };
@@ -1144,7 +1169,7 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1144
1169
  return { header, status, body };
1145
1170
  }
1146
1171
  }
1147
- static applicationHeaders = /* @__PURE__ */ new Set([
1172
+ static applicationContentTypes = [
1148
1173
  "application/json",
1149
1174
  "application/xml",
1150
1175
  "application/javascript",
@@ -1153,12 +1178,12 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1153
1178
  "application/ld+json",
1154
1179
  "application/rss+xml",
1155
1180
  "application/atom+xml"
1156
- ]);
1181
+ ];
1157
1182
  static isText = (contentTypeHeader) => {
1158
1183
  if (!contentTypeHeader) {
1159
1184
  return false;
1160
1185
  }
1161
- if (_LazyCallStep.applicationHeaders.has(contentTypeHeader)) {
1186
+ if (_LazyCallStep.applicationContentTypes.some((type) => contentTypeHeader.includes(type))) {
1162
1187
  return true;
1163
1188
  }
1164
1189
  if (contentTypeHeader.startsWith("text/")) {
@@ -2956,10 +2981,10 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2956
2981
  throw new WorkflowAbort(_DisabledWorkflowContext.disabledMessage);
2957
2982
  }
2958
2983
  /**
2959
- * overwrite cancel method to do nothing
2984
+ * overwrite cancel method to throw WorkflowAbort with the disabledMessage
2960
2985
  */
2961
2986
  async cancel() {
2962
- return;
2987
+ throw new WorkflowAbort(_DisabledWorkflowContext.disabledMessage);
2963
2988
  }
2964
2989
  /**
2965
2990
  * copies the passed context to create a DisabledWorkflowContext. Then, runs the
@@ -2991,7 +3016,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2991
3016
  try {
2992
3017
  await routeFunction(disabledContext);
2993
3018
  } catch (error) {
2994
- if (error instanceof WorkflowAbort && error.stepName === this.disabledMessage) {
3019
+ if (error instanceof WorkflowAbort && error.stepName === this.disabledMessage || error instanceof WorkflowNonRetryableError) {
2995
3020
  return ok("step-found");
2996
3021
  }
2997
3022
  return err(error);
@@ -3212,6 +3237,13 @@ var processOptions = (options) => {
3212
3237
  status: 400
3213
3238
  }
3214
3239
  );
3240
+ } else if (finishCondition instanceof WorkflowNonRetryableError) {
3241
+ return new Response(JSON.stringify(formatWorkflowError(finishCondition)), {
3242
+ headers: {
3243
+ "Upstash-NonRetryable-Error": "true"
3244
+ },
3245
+ status: 489
3246
+ });
3215
3247
  }
3216
3248
  return new Response(JSON.stringify({ workflowRunId }), {
3217
3249
  status: 200
@@ -3404,6 +3436,9 @@ var serveBase = (routeFunction, telemetry, options) => {
3404
3436
  },
3405
3437
  debug
3406
3438
  });
3439
+ if (result.isOk() && result.value instanceof WorkflowNonRetryableError) {
3440
+ return onStepFinish(workflowRunId, result.value);
3441
+ }
3407
3442
  if (result.isErr()) {
3408
3443
  await debug?.log("ERROR", "ERROR", { error: result.error.message });
3409
3444
  throw result.error;
package/nextjs.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-XVNSBBDC.mjs";
5
+ } from "./chunk-AC5CQCN3.mjs";
6
6
 
7
7
  // platforms/nextjs.ts
8
8
  var appTelemetry = {
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@upstash/workflow","version":"v0.2.13","description":"Durable, Reliable and Performant Serverless Functions","main":"./index.js","module":"./index.mjs","types":"./index.d.ts","files":["./*"],"exports":{".":{"import":"./index.mjs","require":"./index.js"},"./dist/nextjs":{"import":"./nextjs.mjs","require":"./nextjs.js"},"./nextjs":{"import":"./nextjs.mjs","require":"./nextjs.js"},"./h3":{"import":"./h3.mjs","require":"./h3.js"},"./svelte":{"import":"./svelte.mjs","require":"./svelte.js"},"./solidjs":{"import":"./solidjs.mjs","require":"./solidjs.js"},"./workflow":{"import":"./workflow.mjs","require":"./workflow.js"},"./hono":{"import":"./hono.mjs","require":"./hono.js"},"./cloudflare":{"import":"./cloudflare.mjs","require":"./cloudflare.js"},"./astro":{"import":"./astro.mjs","require":"./astro.js"},"./express":{"import":"./express.mjs","require":"./express.js"}},"scripts":{"build":"tsup && cp README.md ./dist/ && cp package.json ./dist/ && cp LICENSE ./dist/","test":"bun test src","fmt":"prettier --write .","lint":"tsc && eslint \"{src,platforms}/**/*.{js,ts,tsx}\" --quiet --fix","check-exports":"bun run build && cd dist && attw -P"},"repository":{"type":"git","url":"git+https://github.com/upstash/workflow-ts.git"},"keywords":["upstash","qstash","workflow","serverless"],"author":"Cahid Arda Oz","license":"MIT","bugs":{"url":"https://github.com/upstash/workflow-ts/issues"},"homepage":"https://github.com/upstash/workflow-ts#readme","devDependencies":{"@ai-sdk/anthropic":"^1.1.15","@commitlint/cli":"^19.5.0","@commitlint/config-conventional":"^19.5.0","@eslint/js":"^9.11.1","@solidjs/start":"^1.0.8","@sveltejs/kit":"^2.6.1","@types/bun":"^1.1.10","@types/express":"^5.0.1","astro":"^4.16.7","eslint":"^9.11.1","eslint-plugin-unicorn":"^55.0.0","express":"^4.21.1","globals":"^15.10.0","h3":"^1.12.0","hono":"^4.6.20","husky":"^9.1.6","next":"^14.2.14","prettier":"3.3.3","tsup":"^8.3.0","typescript":"^5.7.2","typescript-eslint":"^8.18.0"},"dependencies":{"@ai-sdk/openai":"^1.2.1","@upstash/qstash":"^2.8.1","ai":"^4.1.54","zod":"^3.24.1"},"directories":{"example":"examples"}}
1
+ {"name":"@upstash/workflow","version":"v0.2.15","description":"Durable, Reliable and Performant Serverless Functions","main":"./index.js","module":"./index.mjs","types":"./index.d.ts","files":["./*"],"exports":{".":{"import":"./index.mjs","require":"./index.js"},"./dist/nextjs":{"import":"./nextjs.mjs","require":"./nextjs.js"},"./nextjs":{"import":"./nextjs.mjs","require":"./nextjs.js"},"./h3":{"import":"./h3.mjs","require":"./h3.js"},"./svelte":{"import":"./svelte.mjs","require":"./svelte.js"},"./solidjs":{"import":"./solidjs.mjs","require":"./solidjs.js"},"./workflow":{"import":"./workflow.mjs","require":"./workflow.js"},"./hono":{"import":"./hono.mjs","require":"./hono.js"},"./cloudflare":{"import":"./cloudflare.mjs","require":"./cloudflare.js"},"./astro":{"import":"./astro.mjs","require":"./astro.js"},"./express":{"import":"./express.mjs","require":"./express.js"}},"scripts":{"build":"tsup && cp README.md ./dist/ && cp package.json ./dist/ && cp LICENSE ./dist/","test":"bun test src","fmt":"prettier --write .","lint":"tsc && eslint \"{src,platforms}/**/*.{js,ts,tsx}\" --quiet --fix","check-exports":"bun run build && cd dist && attw -P"},"repository":{"type":"git","url":"git+https://github.com/upstash/workflow-ts.git"},"keywords":["upstash","qstash","workflow","serverless"],"author":"Cahid Arda Oz","license":"MIT","bugs":{"url":"https://github.com/upstash/workflow-ts/issues"},"homepage":"https://github.com/upstash/workflow-ts#readme","devDependencies":{"@ai-sdk/anthropic":"^1.1.15","@commitlint/cli":"^19.5.0","@commitlint/config-conventional":"^19.5.0","@eslint/js":"^9.11.1","@solidjs/start":"^1.0.8","@sveltejs/kit":"^2.6.1","@types/bun":"^1.1.10","@types/express":"^5.0.1","astro":"^4.16.7","eslint":"^9.11.1","eslint-plugin-unicorn":"^55.0.0","express":"^4.21.1","globals":"^15.10.0","h3":"^1.12.0","hono":"^4.6.20","husky":"^9.1.6","next":"^14.2.14","prettier":"3.3.3","tsup":"^8.3.0","typescript":"^5.7.2","typescript-eslint":"^8.18.0"},"dependencies":{"@ai-sdk/openai":"^1.2.1","@upstash/qstash":"^2.8.1","ai":"^4.1.54","zod":"^3.24.1"},"directories":{"example":"examples"}}
@@ -1,4 +1,4 @@
1
- import { k as PublicServeOptions, R as RouteFunction, t as InvokableWorkflow } from './types-C1WIgVLA.mjs';
1
+ import { n as PublicServeOptions, R as RouteFunction, w as InvokableWorkflow } from './types-Dd-3bPoU.mjs';
2
2
 
3
3
  type OmitOptionsInServeMany<TOptions> = Omit<TOptions, "env" | "url" | "schema" | "initialPayloadParser">;
4
4
  declare const serveManyBase: <THandler extends (...params: any[]) => any, TOptions extends OmitOptionsInServeMany<PublicServeOptions> = OmitOptionsInServeMany<PublicServeOptions>, TServeParams extends [routeFunction: RouteFunction<any, any>, options: TOptions] = [routeFunction: RouteFunction<any, any>, options: TOptions]>({ workflows, getUrl, serveMethod, options, }: {
@@ -1,4 +1,4 @@
1
- import { k as PublicServeOptions, R as RouteFunction, t as InvokableWorkflow } from './types-C1WIgVLA.js';
1
+ import { n as PublicServeOptions, R as RouteFunction, w as InvokableWorkflow } from './types-Dd-3bPoU.js';
2
2
 
3
3
  type OmitOptionsInServeMany<TOptions> = Omit<TOptions, "env" | "url" | "schema" | "initialPayloadParser">;
4
4
  declare const serveManyBase: <THandler extends (...params: any[]) => any, TOptions extends OmitOptionsInServeMany<PublicServeOptions> = OmitOptionsInServeMany<PublicServeOptions>, TServeParams extends [routeFunction: RouteFunction<any, any>, options: TOptions] = [routeFunction: RouteFunction<any, any>, options: TOptions]>({ workflows, getUrl, serveMethod, options, }: {
package/solidjs.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { APIEvent } from '@solidjs/start/server';
2
- import { R as RouteFunction, k as PublicServeOptions } from './types-C1WIgVLA.mjs';
2
+ import { R as RouteFunction, n as PublicServeOptions } from './types-Dd-3bPoU.mjs';
3
3
  import '@upstash/qstash';
4
4
  import 'zod';
5
5
  import 'ai';
package/solidjs.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { APIEvent } from '@solidjs/start/server';
2
- import { R as RouteFunction, k as PublicServeOptions } from './types-C1WIgVLA.js';
2
+ import { R as RouteFunction, n as PublicServeOptions } from './types-Dd-3bPoU.js';
3
3
  import '@upstash/qstash';
4
4
  import 'zod';
5
5
  import 'ai';
package/solidjs.js CHANGED
@@ -89,7 +89,7 @@ var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
89
89
  var DEFAULT_CONTENT_TYPE = "application/json";
90
90
  var NO_CONCURRENCY = 1;
91
91
  var DEFAULT_RETRIES = 3;
92
- var VERSION = "v0.2.13";
92
+ var VERSION = "v0.2.15";
93
93
  var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
94
94
  var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
95
95
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
@@ -127,6 +127,16 @@ var WorkflowAbort = class extends Error {
127
127
  this.cancelWorkflow = cancelWorkflow;
128
128
  }
129
129
  };
130
+ var WorkflowNonRetryableError = class extends WorkflowAbort {
131
+ /**
132
+ * @param message error message to be displayed
133
+ */
134
+ constructor(message) {
135
+ super("fail", void 0, false);
136
+ this.name = "WorkflowNonRetryableError";
137
+ if (message) this.message = message;
138
+ }
139
+ };
130
140
  var formatWorkflowError = (error) => {
131
141
  return error instanceof Error ? {
132
142
  error: error.name,
@@ -597,59 +607,72 @@ var StepTypes = [
597
607
 
598
608
  // src/workflow-requests.ts
599
609
  var import_qstash3 = require("@upstash/qstash");
600
- var triggerFirstInvocation = async ({
601
- workflowContext,
602
- useJSONContent,
603
- telemetry,
604
- debug,
605
- invokeCount,
606
- delay
607
- }) => {
608
- const { headers } = getHeaders({
609
- initHeaderValue: "true",
610
- workflowConfig: {
611
- workflowRunId: workflowContext.workflowRunId,
612
- workflowUrl: workflowContext.url,
613
- failureUrl: workflowContext.failureUrl,
614
- retries: workflowContext.retries,
615
- telemetry,
616
- flowControl: workflowContext.flowControl,
617
- useJSONContent: useJSONContent ?? false
618
- },
619
- invokeCount: invokeCount ?? 0,
620
- userHeaders: workflowContext.headers
621
- });
622
- if (workflowContext.headers.get("content-type")) {
623
- headers["content-type"] = workflowContext.headers.get("content-type");
624
- }
625
- if (useJSONContent) {
626
- headers["content-type"] = "application/json";
627
- }
628
- try {
629
- const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
630
- const result = await workflowContext.qstashClient.publish({
631
- headers,
632
- method: "POST",
633
- body,
634
- url: workflowContext.url,
635
- delay
636
- });
637
- if (result.deduplicated) {
638
- await debug?.log("WARN", "SUBMIT_FIRST_INVOCATION", {
639
- message: `Workflow run ${workflowContext.workflowRunId} already exists. A new one isn't created.`,
610
+ var triggerFirstInvocation = async (params) => {
611
+ const firstInvocationParams = Array.isArray(params) ? params : [params];
612
+ const workflowContextClient = firstInvocationParams[0].workflowContext.qstashClient;
613
+ const invocationBatch = firstInvocationParams.map(
614
+ ({ workflowContext, useJSONContent, telemetry, invokeCount, delay }) => {
615
+ const { headers } = getHeaders({
616
+ initHeaderValue: "true",
617
+ workflowConfig: {
618
+ workflowRunId: workflowContext.workflowRunId,
619
+ workflowUrl: workflowContext.url,
620
+ failureUrl: workflowContext.failureUrl,
621
+ retries: workflowContext.retries,
622
+ telemetry,
623
+ flowControl: workflowContext.flowControl,
624
+ useJSONContent: useJSONContent ?? false
625
+ },
626
+ invokeCount: invokeCount ?? 0,
627
+ userHeaders: workflowContext.headers
628
+ });
629
+ if (workflowContext.headers.get("content-type")) {
630
+ headers["content-type"] = workflowContext.headers.get("content-type");
631
+ }
632
+ if (useJSONContent) {
633
+ headers["content-type"] = "application/json";
634
+ }
635
+ const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
636
+ return {
640
637
  headers,
641
- requestPayload: workflowContext.requestPayload,
638
+ method: "POST",
639
+ body,
642
640
  url: workflowContext.url,
643
- messageId: result.messageId
644
- });
641
+ delay
642
+ };
643
+ }
644
+ );
645
+ try {
646
+ const results = await workflowContextClient.batch(invocationBatch);
647
+ const invocationStatuses = [];
648
+ for (let i = 0; i < results.length; i++) {
649
+ const result = results[i];
650
+ const invocationParams = firstInvocationParams[i];
651
+ if (result.deduplicated) {
652
+ await invocationParams.debug?.log("WARN", "SUBMIT_FIRST_INVOCATION", {
653
+ message: `Workflow run ${invocationParams.workflowContext.workflowRunId} already exists. A new one isn't created.`,
654
+ headers: invocationBatch[i].headers,
655
+ requestPayload: invocationParams.workflowContext.requestPayload,
656
+ url: invocationParams.workflowContext.url,
657
+ messageId: result.messageId
658
+ });
659
+ invocationStatuses.push("workflow-run-already-exists");
660
+ } else {
661
+ await invocationParams.debug?.log("SUBMIT", "SUBMIT_FIRST_INVOCATION", {
662
+ headers: invocationBatch[i].headers,
663
+ requestPayload: invocationParams.workflowContext.requestPayload,
664
+ url: invocationParams.workflowContext.url,
665
+ messageId: result.messageId
666
+ });
667
+ invocationStatuses.push("success");
668
+ }
669
+ }
670
+ const hasAnyDeduplicated = invocationStatuses.some(
671
+ (status) => status === "workflow-run-already-exists"
672
+ );
673
+ if (hasAnyDeduplicated) {
645
674
  return ok("workflow-run-already-exists");
646
675
  } else {
647
- await debug?.log("SUBMIT", "SUBMIT_FIRST_INVOCATION", {
648
- headers,
649
- requestPayload: workflowContext.requestPayload,
650
- url: workflowContext.url,
651
- messageId: result.messageId
652
- });
653
676
  return ok("success");
654
677
  }
655
678
  } catch (error) {
@@ -678,6 +701,8 @@ var triggerRouteFunction = async ({
678
701
  return ok("workflow-was-finished");
679
702
  } else if (!(error_ instanceof WorkflowAbort)) {
680
703
  return err(error_);
704
+ } else if (error_ instanceof WorkflowNonRetryableError) {
705
+ return ok(error_);
681
706
  } else if (error_.cancelWorkflow) {
682
707
  await onCancel();
683
708
  return ok("workflow-finished");
@@ -839,7 +864,7 @@ ${atob(callbackMessage.body ?? "")}`
839
864
  var getTelemetryHeaders = (telemetry) => {
840
865
  return {
841
866
  [TELEMETRY_HEADER_SDK]: telemetry.sdk,
842
- [TELEMETRY_HEADER_FRAMEWORK]: telemetry.framework,
867
+ [TELEMETRY_HEADER_FRAMEWORK]: telemetry.framework ?? "unknown",
843
868
  [TELEMETRY_HEADER_RUNTIME]: telemetry.runtime ?? "unknown"
844
869
  };
845
870
  };
@@ -1139,7 +1164,7 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1139
1164
  return { header, status, body };
1140
1165
  }
1141
1166
  }
1142
- static applicationHeaders = /* @__PURE__ */ new Set([
1167
+ static applicationContentTypes = [
1143
1168
  "application/json",
1144
1169
  "application/xml",
1145
1170
  "application/javascript",
@@ -1148,12 +1173,12 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1148
1173
  "application/ld+json",
1149
1174
  "application/rss+xml",
1150
1175
  "application/atom+xml"
1151
- ]);
1176
+ ];
1152
1177
  static isText = (contentTypeHeader) => {
1153
1178
  if (!contentTypeHeader) {
1154
1179
  return false;
1155
1180
  }
1156
- if (_LazyCallStep.applicationHeaders.has(contentTypeHeader)) {
1181
+ if (_LazyCallStep.applicationContentTypes.some((type) => contentTypeHeader.includes(type))) {
1157
1182
  return true;
1158
1183
  }
1159
1184
  if (contentTypeHeader.startsWith("text/")) {
@@ -2890,10 +2915,10 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2890
2915
  throw new WorkflowAbort(_DisabledWorkflowContext.disabledMessage);
2891
2916
  }
2892
2917
  /**
2893
- * overwrite cancel method to do nothing
2918
+ * overwrite cancel method to throw WorkflowAbort with the disabledMessage
2894
2919
  */
2895
2920
  async cancel() {
2896
- return;
2921
+ throw new WorkflowAbort(_DisabledWorkflowContext.disabledMessage);
2897
2922
  }
2898
2923
  /**
2899
2924
  * copies the passed context to create a DisabledWorkflowContext. Then, runs the
@@ -2925,7 +2950,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2925
2950
  try {
2926
2951
  await routeFunction(disabledContext);
2927
2952
  } catch (error) {
2928
- if (error instanceof WorkflowAbort && error.stepName === this.disabledMessage) {
2953
+ if (error instanceof WorkflowAbort && error.stepName === this.disabledMessage || error instanceof WorkflowNonRetryableError) {
2929
2954
  return ok("step-found");
2930
2955
  }
2931
2956
  return err(error);
@@ -3146,6 +3171,13 @@ var processOptions = (options) => {
3146
3171
  status: 400
3147
3172
  }
3148
3173
  );
3174
+ } else if (finishCondition instanceof WorkflowNonRetryableError) {
3175
+ return new Response(JSON.stringify(formatWorkflowError(finishCondition)), {
3176
+ headers: {
3177
+ "Upstash-NonRetryable-Error": "true"
3178
+ },
3179
+ status: 489
3180
+ });
3149
3181
  }
3150
3182
  return new Response(JSON.stringify({ workflowRunId }), {
3151
3183
  status: 200
@@ -3338,6 +3370,9 @@ var serveBase = (routeFunction, telemetry, options) => {
3338
3370
  },
3339
3371
  debug
3340
3372
  });
3373
+ if (result.isOk() && result.value instanceof WorkflowNonRetryableError) {
3374
+ return onStepFinish(workflowRunId, result.value);
3375
+ }
3341
3376
  if (result.isErr()) {
3342
3377
  await debug?.log("ERROR", "ERROR", { error: result.error.message });
3343
3378
  throw result.error;
package/solidjs.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase
4
- } from "./chunk-XVNSBBDC.mjs";
4
+ } from "./chunk-AC5CQCN3.mjs";
5
5
 
6
6
  // platforms/solidjs.ts
7
7
  var serve = (routeFunction, options) => {
package/svelte.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _sveltejs_kit from '@sveltejs/kit';
2
2
  import { RequestHandler } from '@sveltejs/kit';
3
- import { R as RouteFunction, k as PublicServeOptions, t as InvokableWorkflow } from './types-C1WIgVLA.mjs';
4
- import { s as serveManyBase } from './serve-many-BF71QZHQ.mjs';
3
+ import { R as RouteFunction, n as PublicServeOptions, w as InvokableWorkflow } from './types-Dd-3bPoU.mjs';
4
+ import { s as serveManyBase } from './serve-many-AFwJPR3S.mjs';
5
5
  import '@upstash/qstash';
6
6
  import 'zod';
7
7
  import 'ai';
package/svelte.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _sveltejs_kit from '@sveltejs/kit';
2
2
  import { RequestHandler } from '@sveltejs/kit';
3
- import { R as RouteFunction, k as PublicServeOptions, t as InvokableWorkflow } from './types-C1WIgVLA.js';
4
- import { s as serveManyBase } from './serve-many-BMlN2PAB.js';
3
+ import { R as RouteFunction, n as PublicServeOptions, w as InvokableWorkflow } from './types-Dd-3bPoU.js';
4
+ import { s as serveManyBase } from './serve-many-AaKSQyi7.js';
5
5
  import '@upstash/qstash';
6
6
  import 'zod';
7
7
  import 'ai';