@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.js CHANGED
@@ -196,6 +196,66 @@ var getSteps = async (requester, workflowRunId, messageId, dispatchDebug) => {
196
196
  }
197
197
  }
198
198
  };
199
+ function normalizeCursor(response) {
200
+ const cursor = response.cursor;
201
+ return { ...response, cursor: cursor || void 0 };
202
+ }
203
+ var DEFAULT_BULK_COUNT = 100;
204
+ function buildBulkActionQueryParameters(request, options) {
205
+ const cursor = "cursor" in request ? request.cursor : void 0;
206
+ if ("all" in request) {
207
+ return { count: request.count ?? DEFAULT_BULK_COUNT, cursor };
208
+ }
209
+ if ("dlqIds" in request) {
210
+ const ids = request.dlqIds;
211
+ if (Array.isArray(ids) && ids.length === 0) {
212
+ throw new import_qstash2.QstashError(
213
+ "Empty dlqIds array provided. If you intend to target all DLQ messages, use { all: true } explicitly."
214
+ );
215
+ }
216
+ return { dlqIds: ids, cursor };
217
+ }
218
+ if ("workflowRunIds" in request && request.workflowRunIds) {
219
+ if (request.workflowRunIds.length === 0) {
220
+ throw new import_qstash2.QstashError(
221
+ "Empty workflowRunIds array provided. If you intend to target all workflow runs, use { all: true } explicitly."
222
+ );
223
+ }
224
+ return { workflowRunIds: request.workflowRunIds };
225
+ }
226
+ const filter = request.filter;
227
+ if (!filter) {
228
+ throw new import_qstash2.QstashError(
229
+ "No filter provided. Use { filter: { ... } } with at least one filter field, or { all: true }."
230
+ );
231
+ }
232
+ if (options?.translateWorkflowUrl) {
233
+ const { workflowUrlStartingWith, workflowUrl, ...rest } = filter;
234
+ if (workflowUrlStartingWith && workflowUrl) {
235
+ throw new import_qstash2.QstashError(
236
+ "workflowUrl and workflowUrlStartingWith are mutually exclusive. Use workflowUrl for exact match or workflowUrlStartingWith for prefix match."
237
+ );
238
+ }
239
+ const urlParams = {};
240
+ if (workflowUrlStartingWith) {
241
+ urlParams.workflowUrl = workflowUrlStartingWith;
242
+ } else if (workflowUrl) {
243
+ urlParams.workflowUrl = workflowUrl;
244
+ urlParams.workflowUrlExactMatch = true;
245
+ }
246
+ return {
247
+ ...rest,
248
+ ...urlParams,
249
+ count: request.count ?? DEFAULT_BULK_COUNT,
250
+ cursor
251
+ };
252
+ }
253
+ return {
254
+ ...filter,
255
+ count: request.count ?? DEFAULT_BULK_COUNT,
256
+ cursor
257
+ };
258
+ }
199
259
 
200
260
  // src/constants.ts
201
261
  var WORKFLOW_ID_HEADER = "Upstash-Workflow-RunId";
@@ -3800,7 +3860,19 @@ var serve = (routeFunction, options) => {
3800
3860
  var import_qstash12 = require("@upstash/qstash");
3801
3861
 
3802
3862
  // src/client/dlq.ts
3803
- var DLQ = class _DLQ {
3863
+ function buildResumeRestartHeaders(options) {
3864
+ const headers = {};
3865
+ if (options?.flowControl) {
3866
+ const { flowControlKey, flowControlValue } = prepareFlowControl(options.flowControl);
3867
+ headers["Upstash-Flow-Control-Key"] = flowControlKey;
3868
+ headers["Upstash-Flow-Control-Value"] = flowControlValue;
3869
+ }
3870
+ if (options?.retries !== void 0) {
3871
+ headers["Upstash-Retries"] = options.retries.toString();
3872
+ }
3873
+ return headers;
3874
+ }
3875
+ var DLQ = class {
3804
3876
  constructor(client) {
3805
3877
  this.client = client;
3806
3878
  }
@@ -3823,40 +3895,66 @@ var DLQ = class _DLQ {
3823
3895
  */
3824
3896
  async list(parameters) {
3825
3897
  const { cursor, count, filter } = parameters || {};
3826
- return await this.client.http.request({
3827
- path: ["v2", "dlq"],
3828
- method: "GET",
3829
- query: {
3830
- cursor,
3831
- count,
3832
- ...filter,
3833
- source: "workflow"
3834
- }
3835
- });
3898
+ return normalizeCursor(
3899
+ await this.client.http.request({
3900
+ path: ["v2", "dlq"],
3901
+ method: "GET",
3902
+ query: {
3903
+ cursor,
3904
+ count,
3905
+ ...filter,
3906
+ source: "workflow"
3907
+ }
3908
+ })
3909
+ );
3836
3910
  }
3837
- async resume(parameters) {
3838
- const { headers, queryParams } = _DLQ.handleDLQOptions(parameters);
3839
- const { workflowRuns } = await this.client.http.request({
3840
- path: ["v2", "workflows", "dlq", `resume?${queryParams}`],
3841
- headers,
3842
- method: "POST"
3843
- });
3844
- if (Array.isArray(parameters.dlqId)) {
3845
- return workflowRuns;
3911
+ async resume(request, options) {
3912
+ if (typeof request === "object" && !Array.isArray(request) && "dlqId" in request) {
3913
+ const { dlqId, flowControl, retries } = request;
3914
+ const dlqIds = Array.isArray(dlqId) ? dlqId : [dlqId];
3915
+ const { workflowRuns } = await this.client.http.request({
3916
+ path: ["v2", "workflows", "dlq", "resume"],
3917
+ query: { dlqIds },
3918
+ method: "POST",
3919
+ headers: buildResumeRestartHeaders({ flowControl, retries })
3920
+ });
3921
+ return Array.isArray(dlqId) ? workflowRuns : workflowRuns[0];
3846
3922
  }
3847
- return workflowRuns[0];
3923
+ if (typeof request === "string") request = [request];
3924
+ if (Array.isArray(request) && request.length === 0) return { workflowRuns: [] };
3925
+ const filters = Array.isArray(request) ? { dlqIds: request } : request;
3926
+ return normalizeCursor(
3927
+ await this.client.http.request({
3928
+ path: ["v2", "workflows", "dlq", "resume"],
3929
+ query: buildBulkActionQueryParameters(filters),
3930
+ method: "POST",
3931
+ headers: buildResumeRestartHeaders(options)
3932
+ })
3933
+ );
3848
3934
  }
3849
- async restart(parameters) {
3850
- const { headers, queryParams } = _DLQ.handleDLQOptions(parameters);
3851
- const { workflowRuns } = await this.client.http.request({
3852
- path: ["v2", "workflows", "dlq", `restart?${queryParams}`],
3853
- headers,
3854
- method: "POST"
3855
- });
3856
- if (Array.isArray(parameters.dlqId)) {
3857
- return workflowRuns;
3935
+ async restart(request, options) {
3936
+ if (typeof request === "object" && !Array.isArray(request) && "dlqId" in request) {
3937
+ const { dlqId, flowControl, retries } = request;
3938
+ const dlqIds = Array.isArray(dlqId) ? dlqId : [dlqId];
3939
+ const { workflowRuns } = await this.client.http.request({
3940
+ path: ["v2", "workflows", "dlq", "restart"],
3941
+ query: { dlqIds },
3942
+ method: "POST",
3943
+ headers: buildResumeRestartHeaders({ flowControl, retries })
3944
+ });
3945
+ return Array.isArray(dlqId) ? workflowRuns : workflowRuns[0];
3858
3946
  }
3859
- return workflowRuns[0];
3947
+ if (typeof request === "string") request = [request];
3948
+ if (Array.isArray(request) && request.length === 0) return { workflowRuns: [] };
3949
+ const filters = Array.isArray(request) ? { dlqIds: request } : request;
3950
+ return normalizeCursor(
3951
+ await this.client.http.request({
3952
+ path: ["v2", "workflows", "dlq", "restart"],
3953
+ query: buildBulkActionQueryParameters(filters),
3954
+ method: "POST",
3955
+ headers: buildResumeRestartHeaders(options)
3956
+ })
3957
+ );
3860
3958
  }
3861
3959
  /**
3862
3960
  * Retry the failure callback of a workflow run whose failureUrl/failureFunction
@@ -3873,35 +3971,36 @@ var DLQ = class _DLQ {
3873
3971
  return response;
3874
3972
  }
3875
3973
  /**
3876
- * Handles DLQ options and prepares headers and query parameters.
3974
+ * Delete DLQ messages.
3877
3975
  *
3878
- * @param options - DLQ resume/restart options
3879
- */
3880
- static handleDLQOptions(options) {
3881
- const { dlqId, flowControl, retries } = options;
3882
- const headers = {};
3883
- if (flowControl) {
3884
- const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
3885
- headers["Upstash-Flow-Control-Key"] = flowControlKey;
3886
- headers["Upstash-Flow-Control-Value"] = flowControlValue;
3887
- }
3888
- if (retries !== void 0) {
3889
- headers["Upstash-Retries"] = retries.toString();
3890
- }
3891
- return {
3892
- queryParams: _DLQ.getDlqIdQueryParameter(dlqId),
3893
- headers
3894
- };
3895
- }
3896
- /**
3897
- * Converts DLQ ID(s) to query parameter string.
3976
+ * Can be called with:
3977
+ * - A single dlqId: `delete("id")`
3978
+ * - An array of dlqIds: `delete(["id1", "id2"])`
3979
+ * - A filter object: `delete({ filter: { label: "my-label", fromDate: 1640995200000 } })`
3980
+ * - To target all entries: `delete({ all: true })`
3981
+ *
3982
+ * Processes up to `count` messages per call (defaults to 100).
3983
+ * Call in a loop until cursor is undefined to process all:
3898
3984
  *
3899
- * @param dlqId - Single DLQ ID or array of DLQ IDs
3985
+ * ```ts
3986
+ * let cursor: string | undefined;
3987
+ * do {
3988
+ * const result = await client.dlq.delete({ all: true, count: 100, cursor });
3989
+ * cursor = result.cursor;
3990
+ * } while (cursor);
3991
+ * ```
3900
3992
  */
3901
- static getDlqIdQueryParameter(dlqId) {
3902
- const dlqIds = Array.isArray(dlqId) ? dlqId : [dlqId];
3903
- const paramsArray = dlqIds.map((id) => ["dlqIds", id]);
3904
- return new URLSearchParams(paramsArray).toString();
3993
+ async delete(request) {
3994
+ if (typeof request === "string") request = [request];
3995
+ if (Array.isArray(request) && request.length === 0) return { deleted: 0 };
3996
+ const filters = Array.isArray(request) ? { dlqIds: request } : request;
3997
+ return normalizeCursor(
3998
+ await this.client.http.request({
3999
+ path: ["v2", "workflows", "dlq"],
4000
+ method: "DELETE",
4001
+ query: buildBulkActionQueryParameters(filters)
4002
+ })
4003
+ );
3905
4004
  }
3906
4005
  };
3907
4006
 
@@ -3911,82 +4010,25 @@ var Client4 = class {
3911
4010
  constructor(clientConfig) {
3912
4011
  this.client = new import_qstash12.Client(clientConfig);
3913
4012
  }
3914
- /**
3915
- * Cancel an ongoing workflow
3916
- *
3917
- * Returns true if workflow is canceled succesfully. Otherwise, throws error.
3918
- *
3919
- * There are multiple ways you can cancel workflows:
3920
- * - pass one or more workflow run ids to cancel them
3921
- * - pass a workflow url to cancel all runs starting with this url
3922
- * - cancel all pending or active workflow runs
3923
- *
3924
- * ### Cancel a set of workflow runs
3925
- *
3926
- * ```ts
3927
- * // cancel a single workflow
3928
- * await client.cancel({ ids: "<WORKFLOW_RUN_ID>" })
3929
- *
3930
- * // cancel a set of workflow runs
3931
- * await client.cancel({ ids: [
3932
- * "<WORKFLOW_RUN_ID_1>",
3933
- * "<WORKFLOW_RUN_ID_2>",
3934
- * ]})
3935
- * ```
3936
- *
3937
- * ### Cancel workflows starting with a url
3938
- *
3939
- * If you have an endpoint called `https://your-endpoint.com` and you
3940
- * want to cancel all workflow runs on it, you can use `urlStartingWith`.
3941
- *
3942
- * Note that this will cancel workflows in all endpoints under
3943
- * `https://your-endpoint.com`.
3944
- *
3945
- * ```ts
3946
- * await client.cancel({ urlStartingWith: "https://your-endpoint.com" })
3947
- * ```
3948
- *
3949
- * ### Cancel *all* workflows
3950
- *
3951
- * To cancel all pending and currently running workflows, you can
3952
- * do it like this:
3953
- *
3954
- * ```ts
3955
- * await client.cancel({ all: true })
3956
- * ```
3957
- *
3958
- * @param ids run id of the workflow to delete
3959
- * @param urlStartingWith cancel workflows starting with this url. Will be ignored
3960
- * if `ids` parameter is set.
3961
- * @param all set to true in order to cancel all workflows. Will be ignored
3962
- * if `ids` or `urlStartingWith` parameters are set.
3963
- * @returns true if workflow is succesfully deleted. Otherwise throws QStashError
3964
- */
3965
- async cancel({
3966
- ids,
3967
- urlStartingWith,
3968
- all
3969
- }) {
3970
- let body;
3971
- if (ids) {
3972
- const runIdArray = typeof ids === "string" ? [ids] : ids;
3973
- body = JSON.stringify({ workflowRunIds: runIdArray });
3974
- } else if (urlStartingWith) {
3975
- body = JSON.stringify({ workflowUrl: urlStartingWith });
3976
- } else if (all) {
3977
- body = "{}";
3978
- } else {
3979
- throw new TypeError("The `cancel` method cannot be called without any options.");
4013
+ async cancel(request) {
4014
+ if (typeof request === "object" && !Array.isArray(request) && ("ids" in request || "urlStartingWith" in request)) {
4015
+ const legacy = request;
4016
+ if (legacy.ids) {
4017
+ const ids = typeof legacy.ids === "string" ? [legacy.ids] : legacy.ids;
4018
+ return this.cancel(ids);
4019
+ }
4020
+ if (legacy.urlStartingWith) {
4021
+ return this.cancel({ filter: { workflowUrlStartingWith: legacy.urlStartingWith } });
4022
+ }
3980
4023
  }
3981
- const result = await this.client.http.request({
4024
+ if (typeof request === "string") request = [request];
4025
+ if (Array.isArray(request) && request.length === 0) return { cancelled: 0 };
4026
+ const filters = Array.isArray(request) ? { workflowRunIds: request } : request;
4027
+ return await this.client.http.request({
3982
4028
  path: ["v2", "workflows", "runs"],
3983
4029
  method: "DELETE",
3984
- body,
3985
- headers: {
3986
- "Content-Type": "application/json"
3987
- }
4030
+ query: buildBulkActionQueryParameters(filters, { translateWorkflowUrl: true })
3988
4031
  });
3989
- return result;
3990
4032
  }
3991
4033
  /**
3992
4034
  * Notify a workflow run waiting for an event
@@ -4110,33 +4152,17 @@ var Client4 = class {
4110
4152
  * ```
4111
4153
  */
4112
4154
  async logs(params) {
4113
- const { workflowRunId, cursor, count, state, workflowUrl, workflowCreatedAt } = params ?? {};
4114
- const urlParams = new URLSearchParams({ groupBy: "workflowRunId" });
4115
- if (workflowRunId) {
4116
- urlParams.append("workflowRunId", workflowRunId);
4117
- }
4118
- if (cursor) {
4119
- urlParams.append("cursor", cursor);
4120
- }
4121
- if (count) {
4122
- urlParams.append("count", count.toString());
4123
- }
4124
- if (state) {
4125
- urlParams.append("state", state);
4126
- }
4127
- if (workflowUrl) {
4128
- urlParams.append("workflowUrl", workflowUrl);
4129
- }
4130
- if (workflowCreatedAt) {
4131
- urlParams.append("workflowCreatedAt", workflowCreatedAt.toString());
4132
- }
4133
- if (params?.label) {
4134
- urlParams.append("label", params.label);
4135
- }
4136
- const result = await this.client.http.request({
4137
- path: ["v2", "workflows", `events?${urlParams.toString()}`]
4155
+ const { cursor, count, filter, ...legacyFilter } = params ?? {};
4156
+ return await this.client.http.request({
4157
+ path: ["v2", "workflows", "events"],
4158
+ query: {
4159
+ groupBy: "workflowRunId",
4160
+ ...legacyFilter,
4161
+ cursor,
4162
+ count,
4163
+ ...filter
4164
+ }
4138
4165
  });
4139
- return result;
4140
4166
  }
4141
4167
  get dlq() {
4142
4168
  return new DLQ(this.client);