@upstash/workflow 1.2.0 → 1.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.mjs CHANGED
@@ -8,20 +8,34 @@ import {
8
8
  WorkflowMiddleware,
9
9
  WorkflowNonRetryableError,
10
10
  WorkflowRetryAfterError,
11
+ buildBulkActionQueryParameters,
11
12
  getWorkflowRunId,
12
13
  loggingMiddleware,
13
14
  makeGetWaitersRequest,
14
15
  makeNotifyRequest,
16
+ normalizeCursor,
15
17
  prepareFlowControl,
16
18
  serve,
17
19
  triggerFirstInvocation
18
- } from "./chunk-V5ZUHMAF.mjs";
20
+ } from "./chunk-THS5AX2D.mjs";
19
21
 
20
22
  // src/client/index.ts
21
23
  import { Client as QStashClient } from "@upstash/qstash";
22
24
 
23
25
  // src/client/dlq.ts
24
- var DLQ = class _DLQ {
26
+ function buildResumeRestartHeaders(options) {
27
+ const headers = {};
28
+ if (options?.flowControl) {
29
+ const { flowControlKey, flowControlValue } = prepareFlowControl(options.flowControl);
30
+ headers["Upstash-Flow-Control-Key"] = flowControlKey;
31
+ headers["Upstash-Flow-Control-Value"] = flowControlValue;
32
+ }
33
+ if (options?.retries !== void 0) {
34
+ headers["Upstash-Retries"] = options.retries.toString();
35
+ }
36
+ return headers;
37
+ }
38
+ var DLQ = class {
25
39
  constructor(client) {
26
40
  this.client = client;
27
41
  }
@@ -44,40 +58,66 @@ var DLQ = class _DLQ {
44
58
  */
45
59
  async list(parameters) {
46
60
  const { cursor, count, filter } = parameters || {};
47
- return await this.client.http.request({
48
- path: ["v2", "dlq"],
49
- method: "GET",
50
- query: {
51
- cursor,
52
- count,
53
- ...filter,
54
- source: "workflow"
55
- }
56
- });
61
+ return normalizeCursor(
62
+ await this.client.http.request({
63
+ path: ["v2", "dlq"],
64
+ method: "GET",
65
+ query: {
66
+ cursor,
67
+ count,
68
+ ...filter,
69
+ source: "workflow"
70
+ }
71
+ })
72
+ );
57
73
  }
58
- async resume(parameters) {
59
- const { headers, queryParams } = _DLQ.handleDLQOptions(parameters);
60
- const { workflowRuns } = await this.client.http.request({
61
- path: ["v2", "workflows", "dlq", `resume?${queryParams}`],
62
- headers,
63
- method: "POST"
64
- });
65
- if (Array.isArray(parameters.dlqId)) {
66
- return workflowRuns;
74
+ async resume(request, options) {
75
+ if (typeof request === "object" && !Array.isArray(request) && "dlqId" in request) {
76
+ const { dlqId, flowControl, retries } = request;
77
+ const dlqIds = Array.isArray(dlqId) ? dlqId : [dlqId];
78
+ const { workflowRuns } = await this.client.http.request({
79
+ path: ["v2", "workflows", "dlq", "resume"],
80
+ query: { dlqIds },
81
+ method: "POST",
82
+ headers: buildResumeRestartHeaders({ flowControl, retries })
83
+ });
84
+ return Array.isArray(dlqId) ? workflowRuns : workflowRuns[0];
67
85
  }
68
- return workflowRuns[0];
86
+ if (typeof request === "string") request = [request];
87
+ if (Array.isArray(request) && request.length === 0) return { workflowRuns: [] };
88
+ const filters = Array.isArray(request) ? { dlqIds: request } : request;
89
+ return normalizeCursor(
90
+ await this.client.http.request({
91
+ path: ["v2", "workflows", "dlq", "resume"],
92
+ query: buildBulkActionQueryParameters(filters),
93
+ method: "POST",
94
+ headers: buildResumeRestartHeaders(options)
95
+ })
96
+ );
69
97
  }
70
- async restart(parameters) {
71
- const { headers, queryParams } = _DLQ.handleDLQOptions(parameters);
72
- const { workflowRuns } = await this.client.http.request({
73
- path: ["v2", "workflows", "dlq", `restart?${queryParams}`],
74
- headers,
75
- method: "POST"
76
- });
77
- if (Array.isArray(parameters.dlqId)) {
78
- return workflowRuns;
98
+ async restart(request, options) {
99
+ if (typeof request === "object" && !Array.isArray(request) && "dlqId" in request) {
100
+ const { dlqId, flowControl, retries } = request;
101
+ const dlqIds = Array.isArray(dlqId) ? dlqId : [dlqId];
102
+ const { workflowRuns } = await this.client.http.request({
103
+ path: ["v2", "workflows", "dlq", "restart"],
104
+ query: { dlqIds },
105
+ method: "POST",
106
+ headers: buildResumeRestartHeaders({ flowControl, retries })
107
+ });
108
+ return Array.isArray(dlqId) ? workflowRuns : workflowRuns[0];
79
109
  }
80
- return workflowRuns[0];
110
+ if (typeof request === "string") request = [request];
111
+ if (Array.isArray(request) && request.length === 0) return { workflowRuns: [] };
112
+ const filters = Array.isArray(request) ? { dlqIds: request } : request;
113
+ return normalizeCursor(
114
+ await this.client.http.request({
115
+ path: ["v2", "workflows", "dlq", "restart"],
116
+ query: buildBulkActionQueryParameters(filters),
117
+ method: "POST",
118
+ headers: buildResumeRestartHeaders(options)
119
+ })
120
+ );
81
121
  }
82
122
  /**
83
123
  * Retry the failure callback of a workflow run whose failureUrl/failureFunction
@@ -94,35 +134,36 @@ var DLQ = class _DLQ {
94
134
  return response;
95
135
  }
96
136
  /**
97
- * Handles DLQ options and prepares headers and query parameters.
137
+ * Delete DLQ messages.
98
138
  *
99
- * @param options - DLQ resume/restart options
100
- */
101
- static handleDLQOptions(options) {
102
- const { dlqId, flowControl, retries } = options;
103
- const headers = {};
104
- if (flowControl) {
105
- const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
106
- headers["Upstash-Flow-Control-Key"] = flowControlKey;
107
- headers["Upstash-Flow-Control-Value"] = flowControlValue;
108
- }
109
- if (retries !== void 0) {
110
- headers["Upstash-Retries"] = retries.toString();
111
- }
112
- return {
113
- queryParams: _DLQ.getDlqIdQueryParameter(dlqId),
114
- headers
115
- };
116
- }
117
- /**
118
- * Converts DLQ ID(s) to query parameter string.
139
+ * Can be called with:
140
+ * - A single dlqId: `delete("id")`
141
+ * - An array of dlqIds: `delete(["id1", "id2"])`
142
+ * - A filter object: `delete({ filter: { label: "my-label", fromDate: 1640995200000 } })`
143
+ * - To target all entries: `delete({ all: true })`
144
+ *
145
+ * Processes up to `count` messages per call (defaults to 100).
146
+ * Call in a loop until cursor is undefined to process all:
119
147
  *
120
- * @param dlqId - Single DLQ ID or array of DLQ IDs
148
+ * ```ts
149
+ * let cursor: string | undefined;
150
+ * do {
151
+ * const result = await client.dlq.delete({ all: true, count: 100, cursor });
152
+ * cursor = result.cursor;
153
+ * } while (cursor);
154
+ * ```
121
155
  */
122
- static getDlqIdQueryParameter(dlqId) {
123
- const dlqIds = Array.isArray(dlqId) ? dlqId : [dlqId];
124
- const paramsArray = dlqIds.map((id) => ["dlqIds", id]);
125
- return new URLSearchParams(paramsArray).toString();
156
+ async delete(request) {
157
+ if (typeof request === "string") request = [request];
158
+ if (Array.isArray(request) && request.length === 0) return { deleted: 0 };
159
+ const filters = Array.isArray(request) ? { dlqIds: request } : request;
160
+ return normalizeCursor(
161
+ await this.client.http.request({
162
+ path: ["v2", "workflows", "dlq"],
163
+ method: "DELETE",
164
+ query: buildBulkActionQueryParameters(filters)
165
+ })
166
+ );
126
167
  }
127
168
  };
128
169
 
@@ -132,82 +173,25 @@ var Client = class {
132
173
  constructor(clientConfig) {
133
174
  this.client = new QStashClient(clientConfig);
134
175
  }
135
- /**
136
- * Cancel an ongoing workflow
137
- *
138
- * Returns true if workflow is canceled succesfully. Otherwise, throws error.
139
- *
140
- * There are multiple ways you can cancel workflows:
141
- * - pass one or more workflow run ids to cancel them
142
- * - pass a workflow url to cancel all runs starting with this url
143
- * - cancel all pending or active workflow runs
144
- *
145
- * ### Cancel a set of workflow runs
146
- *
147
- * ```ts
148
- * // cancel a single workflow
149
- * await client.cancel({ ids: "<WORKFLOW_RUN_ID>" })
150
- *
151
- * // cancel a set of workflow runs
152
- * await client.cancel({ ids: [
153
- * "<WORKFLOW_RUN_ID_1>",
154
- * "<WORKFLOW_RUN_ID_2>",
155
- * ]})
156
- * ```
157
- *
158
- * ### Cancel workflows starting with a url
159
- *
160
- * If you have an endpoint called `https://your-endpoint.com` and you
161
- * want to cancel all workflow runs on it, you can use `urlStartingWith`.
162
- *
163
- * Note that this will cancel workflows in all endpoints under
164
- * `https://your-endpoint.com`.
165
- *
166
- * ```ts
167
- * await client.cancel({ urlStartingWith: "https://your-endpoint.com" })
168
- * ```
169
- *
170
- * ### Cancel *all* workflows
171
- *
172
- * To cancel all pending and currently running workflows, you can
173
- * do it like this:
174
- *
175
- * ```ts
176
- * await client.cancel({ all: true })
177
- * ```
178
- *
179
- * @param ids run id of the workflow to delete
180
- * @param urlStartingWith cancel workflows starting with this url. Will be ignored
181
- * if `ids` parameter is set.
182
- * @param all set to true in order to cancel all workflows. Will be ignored
183
- * if `ids` or `urlStartingWith` parameters are set.
184
- * @returns true if workflow is succesfully deleted. Otherwise throws QStashError
185
- */
186
- async cancel({
187
- ids,
188
- urlStartingWith,
189
- all
190
- }) {
191
- let body;
192
- if (ids) {
193
- const runIdArray = typeof ids === "string" ? [ids] : ids;
194
- body = JSON.stringify({ workflowRunIds: runIdArray });
195
- } else if (urlStartingWith) {
196
- body = JSON.stringify({ workflowUrl: urlStartingWith });
197
- } else if (all) {
198
- body = "{}";
199
- } else {
200
- throw new TypeError("The `cancel` method cannot be called without any options.");
176
+ async cancel(request) {
177
+ if (typeof request === "object" && !Array.isArray(request) && ("ids" in request || "urlStartingWith" in request)) {
178
+ const legacy = request;
179
+ if (legacy.ids) {
180
+ const ids = typeof legacy.ids === "string" ? [legacy.ids] : legacy.ids;
181
+ return this.cancel(ids);
182
+ }
183
+ if (legacy.urlStartingWith) {
184
+ return this.cancel({ filter: { workflowUrlStartingWith: legacy.urlStartingWith } });
185
+ }
201
186
  }
202
- const result = await this.client.http.request({
187
+ if (typeof request === "string") request = [request];
188
+ if (Array.isArray(request) && request.length === 0) return { cancelled: 0 };
189
+ const filters = Array.isArray(request) ? { workflowRunIds: request } : request;
190
+ return await this.client.http.request({
203
191
  path: ["v2", "workflows", "runs"],
204
192
  method: "DELETE",
205
- body,
206
- headers: {
207
- "Content-Type": "application/json"
208
- }
193
+ query: buildBulkActionQueryParameters(filters, { translateWorkflowUrl: true })
209
194
  });
210
- return result;
211
195
  }
212
196
  /**
213
197
  * Notify a workflow run waiting for an event
@@ -331,33 +315,17 @@ var Client = class {
331
315
  * ```
332
316
  */
333
317
  async logs(params) {
334
- const { workflowRunId, cursor, count, state, workflowUrl, workflowCreatedAt } = params ?? {};
335
- const urlParams = new URLSearchParams({ groupBy: "workflowRunId" });
336
- if (workflowRunId) {
337
- urlParams.append("workflowRunId", workflowRunId);
338
- }
339
- if (cursor) {
340
- urlParams.append("cursor", cursor);
341
- }
342
- if (count) {
343
- urlParams.append("count", count.toString());
344
- }
345
- if (state) {
346
- urlParams.append("state", state);
347
- }
348
- if (workflowUrl) {
349
- urlParams.append("workflowUrl", workflowUrl);
350
- }
351
- if (workflowCreatedAt) {
352
- urlParams.append("workflowCreatedAt", workflowCreatedAt.toString());
353
- }
354
- if (params?.label) {
355
- urlParams.append("label", params.label);
356
- }
357
- const result = await this.client.http.request({
358
- path: ["v2", "workflows", `events?${urlParams.toString()}`]
318
+ const { cursor, count, filter, ...legacyFilter } = params ?? {};
319
+ return await this.client.http.request({
320
+ path: ["v2", "workflows", "events"],
321
+ query: {
322
+ groupBy: "workflowRunId",
323
+ ...legacyFilter,
324
+ cursor,
325
+ count,
326
+ ...filter
327
+ }
359
328
  });
360
- return result;
361
329
  }
362
330
  get dlq() {
363
331
  return new DLQ(this.client);
package/nextjs.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-V5ZUHMAF.mjs";
5
+ } from "./chunk-THS5AX2D.mjs";
6
6
 
7
7
  // platforms/nextjs.ts
8
8
  var appTelemetry = {
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@upstash/workflow","version":"1.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"},"./tanstack":{"import":"./tanstack.mjs","require":"./tanstack.js"},"./react-router":{"import":"./react-router.mjs","require":"./react-router.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@github.com:upstash/workflow-js.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.6","astro":"^4.16.7","eslint":"^9.11.1","eslint-plugin-unicorn":"^55.0.0","express":"^5.1.0","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":{"@upstash/qstash":"^2.10.1"},"directories":{"example":"examples"},"peerDependencies":{"zod":"^3.25.0 || ^4.0.0"}}
1
+ {"name":"@upstash/workflow","version":"1.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"},"./tanstack":{"import":"./tanstack.mjs","require":"./tanstack.js"},"./react-router":{"import":"./react-router.mjs","require":"./react-router.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@github.com:upstash/workflow-js.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.6","astro":"^4.16.7","eslint":"^9.11.1","eslint-plugin-unicorn":"^55.0.0","express":"^5.1.0","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":{"@upstash/qstash":"^2.10.1"},"directories":{"example":"examples"},"peerDependencies":{"zod":"^3.25.0 || ^4.0.0"}}
package/react-router.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-V5ZUHMAF.mjs";
5
+ } from "./chunk-THS5AX2D.mjs";
6
6
 
7
7
  // platforms/react-router.ts
8
8
  var telemetry = {
package/solidjs.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase
4
- } from "./chunk-V5ZUHMAF.mjs";
4
+ } from "./chunk-THS5AX2D.mjs";
5
5
 
6
6
  // platforms/solidjs.ts
7
7
  var serve = (routeFunction, options) => {
package/svelte.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-V5ZUHMAF.mjs";
5
+ } from "./chunk-THS5AX2D.mjs";
6
6
 
7
7
  // platforms/svelte.ts
8
8
  var telemetry = {
package/tanstack.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-V5ZUHMAF.mjs";
5
+ } from "./chunk-THS5AX2D.mjs";
6
6
 
7
7
  // platforms/tanstack.ts
8
8
  var telemetry = {