Conversation
There was a problem hiding this comment.
Pull request overview
Adds bulk filtering capabilities to the workflow client and DLQ client APIs (date range, label, exact URL matching), plus supporting utilities and expanded test coverage to validate the new request shapes.
Changes:
- Introduces
toMsutility for convertingDate | number | stringinputs into millisecond timestamps for API payloads. - Extends
Client.cancelto support additional filters (label, from/to date) and exactworkflowUrlmatching, and to return a structured{ cancelled: number }response. - Extends DLQ APIs (
resume,restart,retryFailureFunction) and addsDLQ.delete, including new tests for these behaviors.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/client/utils.ts | Adds toMs helper used for date filter serialization. |
| src/client/types.ts | Adds WorkflowBulkFilters type to represent shared bulk filter inputs. |
| src/client/index.ts | Updates cancel to accept additional filters and exact URL matching; uses toMs for date conversion. |
| src/client/index.test.ts | Updates/expands workflow client tests for new cancel response + filter support and logs label query. |
| src/client/dlq.ts | Adds filter-based resume/restart overloads, updates response parsing, and introduces DLQ delete API. |
| src/client/dlq.test.ts | Expands DLQ tests for new response shapes, filter-based ops, and delete scenarios. |
Comments suppressed due to low confidence (1)
src/client/index.ts:83
- The JSDoc for
cancelstill states it returnstrue/"deleted", but the method now returns the QStash response object (e.g.{ cancelled: number }). Please update the@returnstext (and any surrounding wording like "delete") so the public API docs match the actual return type/behavior.
/**
* Cancel an ongoing workflow
*
* Returns true if workflow is canceled succesfully. Otherwise, throws error.
*
* There are multiple ways you can cancel workflows:
* - pass one or more workflow run ids to cancel them
* - pass a workflow url to cancel all runs starting with this url
* - cancel all pending or active workflow runs
*
* ### Cancel a set of workflow runs
*
* ```ts
* // cancel a single workflow
* await client.cancel({ ids: "<WORKFLOW_RUN_ID>" })
*
* // cancel a set of workflow runs
* await client.cancel({ ids: [
* "<WORKFLOW_RUN_ID_1>",
* "<WORKFLOW_RUN_ID_2>",
* ]})
* ```
*
* ### Cancel workflows starting with a url
*
* If you have an endpoint called `https://your-endpoint.com` and you
* want to cancel all workflow runs on it, you can use `urlStartingWith`.
*
* Note that this will cancel workflows in all endpoints under
* `https://your-endpoint.com`.
*
* ```ts
* await client.cancel({ urlStartingWith: "https://your-endpoint.com" })
* ```
*
* ### Cancel *all* workflows
*
* To cancel all pending and currently running workflows, you can
* do it like this:
*
* ```ts
* await client.cancel({ all: true })
* ```
*
* @param ids run id of the workflow to delete
* @param urlStartingWith cancel workflows starting with this url. Will be ignored
* if `ids` parameter is set.
* @param workflowUrl cancel workflows with this url.
* @param fromDate cancel workflows created after this date.
* @param toDate cancel workflows created before this date.
* @param label cancel workflows with this label.
* @param all set to true in order to cancel all workflows. Will be ignored
* if `ids` or `urlStartingWith` parameters are set.
* @returns true if workflow is succesfully deleted. Otherwise throws QStashError
*/
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…and default count
- Add legacy overload for cancel({ ids, urlStartingWith, all }) so
existing callers are not broken by the new signature
- Restore deprecated url and responseStatus fields on WorkflowDLQListFilters
…cancel filters Make workflowUrl mean exact match by default in cancel filters and add workflowUrlStartingWith for prefix-match behavior. This is consistent with how DLQ endpoints already treat workflowUrl.
There was a problem hiding this comment.
Pull request overview
This PR expands the workflow SDK’s bulk-action surface area by adding filter-based operations and a new DLQ delete method, while also standardizing pagination cursor handling and updating call sites/tests to the new APIs.
Changes:
- Extend
client.cancel()to support flexible filter combinations, new call signatures (id / ids array), and return{ cancelled: number }. - Add filter typing infrastructure (
filter-types.ts) and reuse it across workflow cancel + DLQ bulk actions; normalize empty-string cursors toundefined. - Expand DLQ capabilities:
resume()/restart()accept filters and options, and introducedlq.delete()with bulk/filter support; update tests accordingly.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/workflow-requests.test.ts | Updates workflow cancellation calls to new cancel() signatures. |
| src/serve/serve.test.ts | Updates client.cancel() usages to new single-id signature. |
| src/client/utils.ts | Adds cursor normalization + shared bulk query builder for cancel/DLQ endpoints. |
| src/client/types.ts | Makes WorkflowRunLogs.cursor optional; adds deprecated notice; introduces WorkflowBulkFilters. |
| src/client/index.ts | Implements new cancel() overloads/behavior and updates logs() to use query + cursor normalization. |
| src/client/index.test.ts | Updates mocked/live tests for new cancel return type and new logs behavior (cursor + label). |
| src/client/filter-types.ts | Introduces new filter/request types for cancel, DLQ list, DLQ bulk actions, and logs listing. |
| src/client/dlq.ts | Adds filter-based DLQ resume/restart, adds dlq.delete(), and normalizes cursor in responses. |
| src/client/dlq.test.ts | Updates and expands tests for DLQ list/resume/restart + adds coverage for dlq.delete(). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…param
- Add tests for resume/restart/delete with { dlqIds: [] } to verify
runtime guard throws instead of sending unscoped bulk requests
- Add live tests (skipped) for cancel/resume/restart/delete with { all: true }
- Remove `all=true` from query parameters in buildBulkActionQueryParameters;
only count param remains for bulk operations
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Enforce workflowUrl/workflowUrlStartingWith mutual exclusivity at
type level (CancelFilter union with never) and runtime (QstashError)
- Add explicit error in buildBulkActionQueryParameters when no filter
is provided (catches cancel({}) with a clear message)
- Remove unused WorkflowBulkFilters type from types.ts
- Remove normalizeCursor from logs() to preserve cursor: string contract
(server always returns "" for this endpoint, not undefined)
src/client/dlq.ts
Outdated
| }); | ||
|
|
||
| return response; | ||
| return workflowRuns[0]; |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 10 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ): Promise<{ cursor?: string; workflowRuns: DLQResumeRestartResponse[] }>; | ||
| /** @deprecated Use `resume(dlqId)` instead */ | ||
| async resume(request: DLQResumeRestartOptions<string>): Promise<DLQResumeRestartResponse>; | ||
| /** @deprecated Use `resume([dlqId1, dlqId2])` instead */ | ||
| async resume(request: DLQResumeRestartOptions<string[]>): Promise<DLQResumeRestartResponse[]>; | ||
| async resume( |
There was a problem hiding this comment.
DLQ.resume()/restart() now return { cursor?, workflowRuns } for the recommended call forms (resume("id"), resume([..]), filter/all), but the deprecated { dlqId } overloads return a different shape (single item / array). This makes the return type depend on calling style and creates a breaking change when migrating off the deprecated signature. Consider keeping the return shape consistent across overloads (e.g., only use the wrapper for filter/all bulk modes) or introducing a separate bulk API.
| ): Promise<{ cursor?: string; workflowRuns: DLQResumeRestartResponse[] }>; | |
| /** @deprecated Use `resume(dlqId)` instead */ | |
| async resume(request: DLQResumeRestartOptions<string>): Promise<DLQResumeRestartResponse>; | |
| /** @deprecated Use `resume([dlqId1, dlqId2])` instead */ | |
| async resume(request: DLQResumeRestartOptions<string[]>): Promise<DLQResumeRestartResponse[]>; | |
| async resume( | |
| ): Promise< | |
| | { cursor?: string; workflowRuns: DLQResumeRestartResponse[] } | |
| | DLQResumeRestartResponse | |
| | DLQResumeRestartResponse[] | |
| >; | |
| /** @deprecated Use `resume(dlqId)` instead */ | |
| async resume( | |
| request: DLQResumeRestartOptions<string> | |
| ): Promise< | |
| | { cursor?: string; workflowRuns: DLQResumeRestartResponse[] } | |
| | DLQResumeRestartResponse | |
| | DLQResumeRestartResponse[] | |
| >; | |
| /** @deprecated Use `resume([dlqId1, dlqId2])` instead */ | |
| async resume( | |
| request: DLQResumeRestartOptions<string[]> | |
| ): Promise< | |
| | { cursor?: string; workflowRuns: DLQResumeRestartResponse[] } | |
| | DLQResumeRestartResponse | |
| | DLQResumeRestartResponse[] | |
| >; | |
| async resume( |
…ry failure function
…WorkflowError in utils" This reverts commit 7092e56.
…wCreatedAt to WorkflowLogsListFilters
client.cancel()— New filter parametersPreviously: Only supported
ids,urlStartingWith, andall. Returnedvoid.Now: Supports additional filter parameters that can be combined. Returns
{ cancelled: number }.idsstring | string[]urlStartingWithstringworkflowUrl)workflowUrlstringurlStartingWith)fromDateDate | number | stringtoDateDate | number | stringlabelstringallbooleanworkflowUrlvsurlStartingWith:workflowUrlsendsworkflowUrlExactMatch: truein the request body. These two parameters are mutually exclusive.Filter-only cancel (no
ids/urlStartingWith/workflowUrl/all):client.logs()— Newlabelparameterclient.dlq.resume()— New filter-based overloadPreviously: Only accepted
{ dlqId: string | string[] }.Now: Also accepts a
WorkflowBulkFiltersobject (withoutdlqId):client.dlq.restart()— New filter-based overloadSame as
resume— now also acceptsWorkflowBulkFilters:client.dlq.delete()— New methodDelete DLQ messages by ID(s) or by filters. Returns
{ deleted: number }.WorkflowBulkFilters— New shared typeUsed by
dlq.resume(),dlq.restart(), anddlq.delete()for filter-based operations:fromDate/toDateacceptDateobjects, Unix timestamps (number), or numeric strings — all are converted to milliseconds.