@upstash/workflow 0.2.0 → 0.2.1

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/index.js CHANGED
@@ -131,6 +131,11 @@ var BaseLazyStep = class {
131
131
  stepName;
132
132
  // will be set in the subclasses
133
133
  constructor(stepName) {
134
+ if (!stepName) {
135
+ throw new WorkflowError(
136
+ "A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
137
+ );
138
+ }
134
139
  this.stepName = stepName;
135
140
  }
136
141
  };
@@ -223,15 +228,17 @@ var LazyCallStep = class extends BaseLazyStep {
223
228
  method;
224
229
  body;
225
230
  headers;
226
- stepType = "Call";
227
231
  retries;
228
- constructor(stepName, url, method, body, headers, retries) {
232
+ timeout;
233
+ stepType = "Call";
234
+ constructor(stepName, url, method, body, headers, retries, timeout) {
229
235
  super(stepName);
230
236
  this.url = url;
231
237
  this.method = method;
232
238
  this.body = body;
233
239
  this.headers = headers;
234
240
  this.retries = retries;
241
+ this.timeout = timeout;
235
242
  }
236
243
  getPlanStep(concurrent, targetStep) {
237
244
  return {
@@ -843,7 +850,10 @@ var recreateUserHeaders = (headers) => {
843
850
  const pairs = headers.entries();
844
851
  for (const [header, value] of pairs) {
845
852
  const headerLowerCase = header.toLowerCase();
846
- if (!headerLowerCase.startsWith("upstash-workflow-") && !headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && headerLowerCase !== "cf-connecting-ip") {
853
+ if (!headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
854
+ !headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
855
+ headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
856
+ headerLowerCase !== "render-proxy-ttl") {
847
857
  filteredHeaders.append(header, value);
848
858
  }
849
859
  }
@@ -946,7 +956,7 @@ ${atob(callbackMessage.body ?? "")}`
946
956
  );
947
957
  }
948
958
  };
949
- var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step, failureUrl, retries, callRetries) => {
959
+ var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step, failureUrl, retries, callRetries, callTimeout) => {
950
960
  const baseHeaders = {
951
961
  [WORKFLOW_INIT_HEADER]: initHeaderValue,
952
962
  [WORKFLOW_ID_HEADER]: workflowRunId,
@@ -956,6 +966,9 @@ var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step
956
966
  if (!step?.callUrl) {
957
967
  baseHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
958
968
  }
969
+ if (callTimeout) {
970
+ baseHeaders[`Upstash-Timeout`] = callTimeout.toString();
971
+ }
959
972
  if (failureUrl) {
960
973
  baseHeaders[`Upstash-Failure-Callback-Forward-${WORKFLOW_FAILURE_HEADER}`] = "true";
961
974
  if (!step?.callUrl) {
@@ -1331,7 +1344,8 @@ var AutoExecutor = class _AutoExecutor {
1331
1344
  singleStep,
1332
1345
  this.context.failureUrl,
1333
1346
  this.context.retries,
1334
- lazyStep instanceof LazyCallStep ? lazyStep.retries : void 0
1347
+ lazyStep instanceof LazyCallStep ? lazyStep.retries : void 0,
1348
+ lazyStep instanceof LazyCallStep ? lazyStep.timeout : void 0
1335
1349
  );
1336
1350
  const willWait = singleStep.concurrent === NO_CONCURRENCY || singleStep.stepId === 0;
1337
1351
  singleStep.out = JSON.stringify(singleStep.out);
@@ -1681,6 +1695,7 @@ var WorkflowContext = class {
1681
1695
  * @param body call body
1682
1696
  * @param headers call headers
1683
1697
  * @param retries number of call retries. 0 by default
1698
+ * @param timeout max duration to wait for the endpoint to respond. in seconds.
1684
1699
  * @returns call result as {
1685
1700
  * status: number;
1686
1701
  * body: unknown;
@@ -1688,9 +1703,17 @@ var WorkflowContext = class {
1688
1703
  * }
1689
1704
  */
1690
1705
  async call(stepName, settings) {
1691
- const { url, method = "GET", body, headers = {}, retries = 0 } = settings;
1706
+ const { url, method = "GET", body, headers = {}, retries = 0, timeout } = settings;
1692
1707
  const result = await this.addStep(
1693
- new LazyCallStep(stepName, url, method, body, headers, retries)
1708
+ new LazyCallStep(
1709
+ stepName,
1710
+ url,
1711
+ method,
1712
+ body,
1713
+ headers,
1714
+ retries,
1715
+ timeout
1716
+ )
1694
1717
  );
1695
1718
  if (typeof result === "string") {
1696
1719
  try {
@@ -2090,7 +2113,7 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
2090
2113
  const workflowContext = new WorkflowContext({
2091
2114
  qstashClient,
2092
2115
  workflowRunId,
2093
- initialPayload: initialPayloadParser(decodeBase64(sourceBody)),
2116
+ initialPayload: sourceBody ? initialPayloadParser(decodeBase64(sourceBody)) : void 0,
2094
2117
  headers: recreateUserHeaders(new Headers(sourceHeader)),
2095
2118
  steps: [],
2096
2119
  url,
@@ -2132,10 +2155,23 @@ var processOptions = (options) => {
2132
2155
  baseUrl: environment.QSTASH_URL,
2133
2156
  token: environment.QSTASH_TOKEN
2134
2157
  }),
2135
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2136
- onStepFinish: (workflowRunId, _finishCondition) => new Response(JSON.stringify({ workflowRunId }), {
2137
- status: 200
2138
- }),
2158
+ onStepFinish: (workflowRunId, finishCondition) => {
2159
+ if (finishCondition === "auth-fail") {
2160
+ console.error(AUTH_FAIL_MESSAGE);
2161
+ return new Response(
2162
+ JSON.stringify({
2163
+ message: AUTH_FAIL_MESSAGE,
2164
+ workflowRunId
2165
+ }),
2166
+ {
2167
+ status: 400
2168
+ }
2169
+ );
2170
+ }
2171
+ return new Response(JSON.stringify({ workflowRunId }), {
2172
+ status: 200
2173
+ });
2174
+ },
2139
2175
  initialPayloadParser: (initialRequest) => {
2140
2176
  if (!initialRequest) {
2141
2177
  return void 0;
@@ -2177,6 +2213,7 @@ var determineUrls = async (request, url, baseUrl, failureFunction, failureUrl, d
2177
2213
  workflowFailureUrl
2178
2214
  };
2179
2215
  };
2216
+ var AUTH_FAIL_MESSAGE = `Failed to authenticate Workflow request. If this is unexpected, see the caveat https://upstash.com/docs/workflow/basics/caveats#avoid-non-deterministic-code-outside-context-run`;
2180
2217
 
2181
2218
  // src/serve/index.ts
2182
2219
  var serve = (routeFunction, options) => {
@@ -2253,7 +2290,11 @@ var serve = (routeFunction, options) => {
2253
2290
  await debug?.log("ERROR", "ERROR", { error: authCheck.error.message });
2254
2291
  throw authCheck.error;
2255
2292
  } else if (authCheck.value === "run-ended") {
2256
- return onStepFinish("no-workflow-id", "auth-fail");
2293
+ await debug?.log("ERROR", "ERROR", { error: AUTH_FAIL_MESSAGE });
2294
+ return onStepFinish(
2295
+ isFirstInvocation ? "no-workflow-id" : workflowContext.workflowRunId,
2296
+ "auth-fail"
2297
+ );
2257
2298
  }
2258
2299
  const callReturnCheck = await handleThirdPartyCallResult(
2259
2300
  request,
package/index.mjs CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  WorkflowError,
7
7
  WorkflowLogger,
8
8
  serve
9
- } from "./chunk-5R2BFC3N.mjs";
9
+ } from "./chunk-ADOBNR4O.mjs";
10
10
  export {
11
11
  Client,
12
12
  StepTypes,
package/nextjs.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { NextApiHandler } from 'next';
2
- import { R as RouteFunction, W as WorkflowServeOptions } from './types-Cki_MHrh.mjs';
2
+ import { R as RouteFunction, W as WorkflowServeOptions } from './types-Be4hC1mu.mjs';
3
3
  import '@upstash/qstash';
4
4
 
5
5
  /**
package/nextjs.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { NextApiHandler } from 'next';
2
- import { R as RouteFunction, W as WorkflowServeOptions } from './types-Cki_MHrh.js';
2
+ import { R as RouteFunction, W as WorkflowServeOptions } from './types-Be4hC1mu.js';
3
3
  import '@upstash/qstash';
4
4
 
5
5
  /**
package/nextjs.js CHANGED
@@ -119,6 +119,11 @@ var BaseLazyStep = class {
119
119
  stepName;
120
120
  // will be set in the subclasses
121
121
  constructor(stepName) {
122
+ if (!stepName) {
123
+ throw new WorkflowError(
124
+ "A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
125
+ );
126
+ }
122
127
  this.stepName = stepName;
123
128
  }
124
129
  };
@@ -211,15 +216,17 @@ var LazyCallStep = class extends BaseLazyStep {
211
216
  method;
212
217
  body;
213
218
  headers;
214
- stepType = "Call";
215
219
  retries;
216
- constructor(stepName, url, method, body, headers, retries) {
220
+ timeout;
221
+ stepType = "Call";
222
+ constructor(stepName, url, method, body, headers, retries, timeout) {
217
223
  super(stepName);
218
224
  this.url = url;
219
225
  this.method = method;
220
226
  this.body = body;
221
227
  this.headers = headers;
222
228
  this.retries = retries;
229
+ this.timeout = timeout;
223
230
  }
224
231
  getPlanStep(concurrent, targetStep) {
225
232
  return {
@@ -831,7 +838,10 @@ var recreateUserHeaders = (headers) => {
831
838
  const pairs = headers.entries();
832
839
  for (const [header, value] of pairs) {
833
840
  const headerLowerCase = header.toLowerCase();
834
- if (!headerLowerCase.startsWith("upstash-workflow-") && !headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && headerLowerCase !== "cf-connecting-ip") {
841
+ if (!headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
842
+ !headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
843
+ headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
844
+ headerLowerCase !== "render-proxy-ttl") {
835
845
  filteredHeaders.append(header, value);
836
846
  }
837
847
  }
@@ -934,7 +944,7 @@ ${atob(callbackMessage.body ?? "")}`
934
944
  );
935
945
  }
936
946
  };
937
- var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step, failureUrl, retries, callRetries) => {
947
+ var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step, failureUrl, retries, callRetries, callTimeout) => {
938
948
  const baseHeaders = {
939
949
  [WORKFLOW_INIT_HEADER]: initHeaderValue,
940
950
  [WORKFLOW_ID_HEADER]: workflowRunId,
@@ -944,6 +954,9 @@ var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step
944
954
  if (!step?.callUrl) {
945
955
  baseHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
946
956
  }
957
+ if (callTimeout) {
958
+ baseHeaders[`Upstash-Timeout`] = callTimeout.toString();
959
+ }
947
960
  if (failureUrl) {
948
961
  baseHeaders[`Upstash-Failure-Callback-Forward-${WORKFLOW_FAILURE_HEADER}`] = "true";
949
962
  if (!step?.callUrl) {
@@ -1319,7 +1332,8 @@ var AutoExecutor = class _AutoExecutor {
1319
1332
  singleStep,
1320
1333
  this.context.failureUrl,
1321
1334
  this.context.retries,
1322
- lazyStep instanceof LazyCallStep ? lazyStep.retries : void 0
1335
+ lazyStep instanceof LazyCallStep ? lazyStep.retries : void 0,
1336
+ lazyStep instanceof LazyCallStep ? lazyStep.timeout : void 0
1323
1337
  );
1324
1338
  const willWait = singleStep.concurrent === NO_CONCURRENCY || singleStep.stepId === 0;
1325
1339
  singleStep.out = JSON.stringify(singleStep.out);
@@ -1669,6 +1683,7 @@ var WorkflowContext = class {
1669
1683
  * @param body call body
1670
1684
  * @param headers call headers
1671
1685
  * @param retries number of call retries. 0 by default
1686
+ * @param timeout max duration to wait for the endpoint to respond. in seconds.
1672
1687
  * @returns call result as {
1673
1688
  * status: number;
1674
1689
  * body: unknown;
@@ -1676,9 +1691,17 @@ var WorkflowContext = class {
1676
1691
  * }
1677
1692
  */
1678
1693
  async call(stepName, settings) {
1679
- const { url, method = "GET", body, headers = {}, retries = 0 } = settings;
1694
+ const { url, method = "GET", body, headers = {}, retries = 0, timeout } = settings;
1680
1695
  const result = await this.addStep(
1681
- new LazyCallStep(stepName, url, method, body, headers, retries)
1696
+ new LazyCallStep(
1697
+ stepName,
1698
+ url,
1699
+ method,
1700
+ body,
1701
+ headers,
1702
+ retries,
1703
+ timeout
1704
+ )
1682
1705
  );
1683
1706
  if (typeof result === "string") {
1684
1707
  try {
@@ -2078,7 +2101,7 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
2078
2101
  const workflowContext = new WorkflowContext({
2079
2102
  qstashClient,
2080
2103
  workflowRunId,
2081
- initialPayload: initialPayloadParser(decodeBase64(sourceBody)),
2104
+ initialPayload: sourceBody ? initialPayloadParser(decodeBase64(sourceBody)) : void 0,
2082
2105
  headers: recreateUserHeaders(new Headers(sourceHeader)),
2083
2106
  steps: [],
2084
2107
  url,
@@ -2120,10 +2143,23 @@ var processOptions = (options) => {
2120
2143
  baseUrl: environment.QSTASH_URL,
2121
2144
  token: environment.QSTASH_TOKEN
2122
2145
  }),
2123
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2124
- onStepFinish: (workflowRunId, _finishCondition) => new Response(JSON.stringify({ workflowRunId }), {
2125
- status: 200
2126
- }),
2146
+ onStepFinish: (workflowRunId, finishCondition) => {
2147
+ if (finishCondition === "auth-fail") {
2148
+ console.error(AUTH_FAIL_MESSAGE);
2149
+ return new Response(
2150
+ JSON.stringify({
2151
+ message: AUTH_FAIL_MESSAGE,
2152
+ workflowRunId
2153
+ }),
2154
+ {
2155
+ status: 400
2156
+ }
2157
+ );
2158
+ }
2159
+ return new Response(JSON.stringify({ workflowRunId }), {
2160
+ status: 200
2161
+ });
2162
+ },
2127
2163
  initialPayloadParser: (initialRequest) => {
2128
2164
  if (!initialRequest) {
2129
2165
  return void 0;
@@ -2165,6 +2201,7 @@ var determineUrls = async (request, url, baseUrl, failureFunction, failureUrl, d
2165
2201
  workflowFailureUrl
2166
2202
  };
2167
2203
  };
2204
+ var AUTH_FAIL_MESSAGE = `Failed to authenticate Workflow request. If this is unexpected, see the caveat https://upstash.com/docs/workflow/basics/caveats#avoid-non-deterministic-code-outside-context-run`;
2168
2205
 
2169
2206
  // src/serve/index.ts
2170
2207
  var serve = (routeFunction, options) => {
@@ -2241,7 +2278,11 @@ var serve = (routeFunction, options) => {
2241
2278
  await debug?.log("ERROR", "ERROR", { error: authCheck.error.message });
2242
2279
  throw authCheck.error;
2243
2280
  } else if (authCheck.value === "run-ended") {
2244
- return onStepFinish("no-workflow-id", "auth-fail");
2281
+ await debug?.log("ERROR", "ERROR", { error: AUTH_FAIL_MESSAGE });
2282
+ return onStepFinish(
2283
+ isFirstInvocation ? "no-workflow-id" : workflowContext.workflowRunId,
2284
+ "auth-fail"
2285
+ );
2245
2286
  }
2246
2287
  const callReturnCheck = await handleThirdPartyCallResult(
2247
2288
  request,
@@ -2296,10 +2337,10 @@ var import_qstash6 = require("@upstash/qstash");
2296
2337
 
2297
2338
  // platforms/nextjs.ts
2298
2339
  var serve2 = (routeFunction, options) => {
2299
- const { handler: serveHandler } = serve(routeFunction, {
2300
- onStepFinish: (workflowRunId) => new Response(JSON.stringify({ workflowRunId }), { status: 200 }),
2301
- ...options
2302
- });
2340
+ const { handler: serveHandler } = serve(
2341
+ routeFunction,
2342
+ options
2343
+ );
2303
2344
  return {
2304
2345
  POST: async (request) => {
2305
2346
  return await serveHandler(request);
package/nextjs.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  serve
3
- } from "./chunk-5R2BFC3N.mjs";
3
+ } from "./chunk-ADOBNR4O.mjs";
4
4
 
5
5
  // platforms/nextjs.ts
6
6
  var serve2 = (routeFunction, options) => {
7
- const { handler: serveHandler } = serve(routeFunction, {
8
- onStepFinish: (workflowRunId) => new Response(JSON.stringify({ workflowRunId }), { status: 200 }),
9
- ...options
10
- });
7
+ const { handler: serveHandler } = serve(
8
+ routeFunction,
9
+ options
10
+ );
11
11
  return {
12
12
  POST: async (request) => {
13
13
  return await serveHandler(request);
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@upstash/workflow","version":"v0.2.0","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":{"@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.0","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.3","husky":"^9.1.6","next":"^14.2.14","prettier":"3.3.3","tsc":"^2.0.4","tsup":"^8.3.0","typescript":"^5.6.3","typescript-eslint":"^8.8.0"},"dependencies":{"@upstash/qstash":"^2.7.17"},"directories":{"example":"examples"}}
1
+ {"name":"@upstash/workflow","version":"v0.2.1","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":{"@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.0","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.3","husky":"^9.1.6","next":"^14.2.14","prettier":"3.3.3","tsc":"^2.0.4","tsup":"^8.3.0","typescript":"^5.6.3","typescript-eslint":"^8.8.0"},"dependencies":{"@upstash/qstash":"^2.7.17"},"directories":{"example":"examples"}}
package/solidjs.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { APIEvent } from '@solidjs/start/server';
2
- import { R as RouteFunction, W as WorkflowServeOptions } from './types-Cki_MHrh.mjs';
2
+ import { R as RouteFunction, W as WorkflowServeOptions } from './types-Be4hC1mu.mjs';
3
3
  import '@upstash/qstash';
4
4
 
5
5
  /**
package/solidjs.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { APIEvent } from '@solidjs/start/server';
2
- import { R as RouteFunction, W as WorkflowServeOptions } from './types-Cki_MHrh.js';
2
+ import { R as RouteFunction, W as WorkflowServeOptions } from './types-Be4hC1mu.js';
3
3
  import '@upstash/qstash';
4
4
 
5
5
  /**
package/solidjs.js CHANGED
@@ -118,6 +118,11 @@ var BaseLazyStep = class {
118
118
  stepName;
119
119
  // will be set in the subclasses
120
120
  constructor(stepName) {
121
+ if (!stepName) {
122
+ throw new WorkflowError(
123
+ "A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
124
+ );
125
+ }
121
126
  this.stepName = stepName;
122
127
  }
123
128
  };
@@ -210,15 +215,17 @@ var LazyCallStep = class extends BaseLazyStep {
210
215
  method;
211
216
  body;
212
217
  headers;
213
- stepType = "Call";
214
218
  retries;
215
- constructor(stepName, url, method, body, headers, retries) {
219
+ timeout;
220
+ stepType = "Call";
221
+ constructor(stepName, url, method, body, headers, retries, timeout) {
216
222
  super(stepName);
217
223
  this.url = url;
218
224
  this.method = method;
219
225
  this.body = body;
220
226
  this.headers = headers;
221
227
  this.retries = retries;
228
+ this.timeout = timeout;
222
229
  }
223
230
  getPlanStep(concurrent, targetStep) {
224
231
  return {
@@ -830,7 +837,10 @@ var recreateUserHeaders = (headers) => {
830
837
  const pairs = headers.entries();
831
838
  for (const [header, value] of pairs) {
832
839
  const headerLowerCase = header.toLowerCase();
833
- if (!headerLowerCase.startsWith("upstash-workflow-") && !headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && headerLowerCase !== "cf-connecting-ip") {
840
+ if (!headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
841
+ !headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
842
+ headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
843
+ headerLowerCase !== "render-proxy-ttl") {
834
844
  filteredHeaders.append(header, value);
835
845
  }
836
846
  }
@@ -933,7 +943,7 @@ ${atob(callbackMessage.body ?? "")}`
933
943
  );
934
944
  }
935
945
  };
936
- var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step, failureUrl, retries, callRetries) => {
946
+ var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step, failureUrl, retries, callRetries, callTimeout) => {
937
947
  const baseHeaders = {
938
948
  [WORKFLOW_INIT_HEADER]: initHeaderValue,
939
949
  [WORKFLOW_ID_HEADER]: workflowRunId,
@@ -943,6 +953,9 @@ var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step
943
953
  if (!step?.callUrl) {
944
954
  baseHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
945
955
  }
956
+ if (callTimeout) {
957
+ baseHeaders[`Upstash-Timeout`] = callTimeout.toString();
958
+ }
946
959
  if (failureUrl) {
947
960
  baseHeaders[`Upstash-Failure-Callback-Forward-${WORKFLOW_FAILURE_HEADER}`] = "true";
948
961
  if (!step?.callUrl) {
@@ -1318,7 +1331,8 @@ var AutoExecutor = class _AutoExecutor {
1318
1331
  singleStep,
1319
1332
  this.context.failureUrl,
1320
1333
  this.context.retries,
1321
- lazyStep instanceof LazyCallStep ? lazyStep.retries : void 0
1334
+ lazyStep instanceof LazyCallStep ? lazyStep.retries : void 0,
1335
+ lazyStep instanceof LazyCallStep ? lazyStep.timeout : void 0
1322
1336
  );
1323
1337
  const willWait = singleStep.concurrent === NO_CONCURRENCY || singleStep.stepId === 0;
1324
1338
  singleStep.out = JSON.stringify(singleStep.out);
@@ -1668,6 +1682,7 @@ var WorkflowContext = class {
1668
1682
  * @param body call body
1669
1683
  * @param headers call headers
1670
1684
  * @param retries number of call retries. 0 by default
1685
+ * @param timeout max duration to wait for the endpoint to respond. in seconds.
1671
1686
  * @returns call result as {
1672
1687
  * status: number;
1673
1688
  * body: unknown;
@@ -1675,9 +1690,17 @@ var WorkflowContext = class {
1675
1690
  * }
1676
1691
  */
1677
1692
  async call(stepName, settings) {
1678
- const { url, method = "GET", body, headers = {}, retries = 0 } = settings;
1693
+ const { url, method = "GET", body, headers = {}, retries = 0, timeout } = settings;
1679
1694
  const result = await this.addStep(
1680
- new LazyCallStep(stepName, url, method, body, headers, retries)
1695
+ new LazyCallStep(
1696
+ stepName,
1697
+ url,
1698
+ method,
1699
+ body,
1700
+ headers,
1701
+ retries,
1702
+ timeout
1703
+ )
1681
1704
  );
1682
1705
  if (typeof result === "string") {
1683
1706
  try {
@@ -2077,7 +2100,7 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
2077
2100
  const workflowContext = new WorkflowContext({
2078
2101
  qstashClient,
2079
2102
  workflowRunId,
2080
- initialPayload: initialPayloadParser(decodeBase64(sourceBody)),
2103
+ initialPayload: sourceBody ? initialPayloadParser(decodeBase64(sourceBody)) : void 0,
2081
2104
  headers: recreateUserHeaders(new Headers(sourceHeader)),
2082
2105
  steps: [],
2083
2106
  url,
@@ -2119,10 +2142,23 @@ var processOptions = (options) => {
2119
2142
  baseUrl: environment.QSTASH_URL,
2120
2143
  token: environment.QSTASH_TOKEN
2121
2144
  }),
2122
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2123
- onStepFinish: (workflowRunId, _finishCondition) => new Response(JSON.stringify({ workflowRunId }), {
2124
- status: 200
2125
- }),
2145
+ onStepFinish: (workflowRunId, finishCondition) => {
2146
+ if (finishCondition === "auth-fail") {
2147
+ console.error(AUTH_FAIL_MESSAGE);
2148
+ return new Response(
2149
+ JSON.stringify({
2150
+ message: AUTH_FAIL_MESSAGE,
2151
+ workflowRunId
2152
+ }),
2153
+ {
2154
+ status: 400
2155
+ }
2156
+ );
2157
+ }
2158
+ return new Response(JSON.stringify({ workflowRunId }), {
2159
+ status: 200
2160
+ });
2161
+ },
2126
2162
  initialPayloadParser: (initialRequest) => {
2127
2163
  if (!initialRequest) {
2128
2164
  return void 0;
@@ -2164,6 +2200,7 @@ var determineUrls = async (request, url, baseUrl, failureFunction, failureUrl, d
2164
2200
  workflowFailureUrl
2165
2201
  };
2166
2202
  };
2203
+ var AUTH_FAIL_MESSAGE = `Failed to authenticate Workflow request. If this is unexpected, see the caveat https://upstash.com/docs/workflow/basics/caveats#avoid-non-deterministic-code-outside-context-run`;
2167
2204
 
2168
2205
  // src/serve/index.ts
2169
2206
  var serve = (routeFunction, options) => {
@@ -2240,7 +2277,11 @@ var serve = (routeFunction, options) => {
2240
2277
  await debug?.log("ERROR", "ERROR", { error: authCheck.error.message });
2241
2278
  throw authCheck.error;
2242
2279
  } else if (authCheck.value === "run-ended") {
2243
- return onStepFinish("no-workflow-id", "auth-fail");
2280
+ await debug?.log("ERROR", "ERROR", { error: AUTH_FAIL_MESSAGE });
2281
+ return onStepFinish(
2282
+ isFirstInvocation ? "no-workflow-id" : workflowContext.workflowRunId,
2283
+ "auth-fail"
2284
+ );
2244
2285
  }
2245
2286
  const callReturnCheck = await handleThirdPartyCallResult(
2246
2287
  request,
package/solidjs.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  serve
3
- } from "./chunk-5R2BFC3N.mjs";
3
+ } from "./chunk-ADOBNR4O.mjs";
4
4
 
5
5
  // platforms/solidjs.ts
6
6
  var serve2 = (routeFunction, options) => {
package/svelte.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { RequestHandler } from '@sveltejs/kit';
2
- import { R as RouteFunction, W as WorkflowServeOptions } from './types-Cki_MHrh.mjs';
2
+ import { R as RouteFunction, W as WorkflowServeOptions } from './types-Be4hC1mu.mjs';
3
3
  import '@upstash/qstash';
4
4
 
5
5
  /**
package/svelte.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { RequestHandler } from '@sveltejs/kit';
2
- import { R as RouteFunction, W as WorkflowServeOptions } from './types-Cki_MHrh.js';
2
+ import { R as RouteFunction, W as WorkflowServeOptions } from './types-Be4hC1mu.js';
3
3
  import '@upstash/qstash';
4
4
 
5
5
  /**