@zizq-labs/zizq 0.4.2 → 0.5.0

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/dist/client.d.ts CHANGED
@@ -34,7 +34,7 @@ import { type Dispatcher } from "undici";
34
34
  import { Job, JobPage, ErrorRecord, ErrorPage, CronGroup, CronEntry } from "./resources.ts";
35
35
  import { JobQuery, type JobQueryOptions } from "./query.ts";
36
36
  import { CronHandle } from "./cron.ts";
37
- export type { JobStatus, SortDirection, UniqueScope, BackoffConfig, RetentionConfig, EnqueueOptions, EnqueueInput, FailureOptions, UpdateJobOptions, Format, TakeOptions, ListJobsOptions, ListErrorsOptions, UpdateAllJobsOptions, JobFilter, DeleteAllJobsOptions, CronEntryInput, ReplaceCronGroupOptions, } from "./types.ts";
37
+ export type { JobStatus, SortDirection, UniqueScope, BackoffConfig, RetentionConfig, EnqueueOptions, EnqueueInput, FailureOptions, UpdateJobOptions, Format, TakeOptions, ListJobsOptions, ListErrorsOptions, UpdateAllJobsOptions, JobFilter, DeleteAllJobsOptions, CronEntryInput, RangeBounds, RangeFilter, ReplaceCronGroupOptions, } from "./types.ts";
38
38
  import type { EnqueueOptions, EnqueueInput, FailureOptions, UpdateJobOptions, Format, TakeOptions, ListJobsOptions, ListErrorsOptions, UpdateAllJobsOptions, JobFilter, DeleteAllJobsOptions, CronEntryInput, ReplaceCronGroupOptions } from "./types.ts";
39
39
  export { Job, JobPage, ErrorRecord, ErrorPage, CronGroup, CronEntry, type JobData, type ErrorRecordData, type CronGroupData, type CronEntryData, } from "./resources.ts";
40
40
  /** Response shape for `GET /health`. */
package/dist/client.js CHANGED
@@ -367,7 +367,7 @@ export class Client {
367
367
  async deleteAllJobs(options = {}) {
368
368
  assertOnlyKeys("deleteAllJobs", options, ["where"]);
369
369
  const where = options.where ?? {};
370
- assertOnlyKeys("deleteAllJobs.where", where, ["id", "status", "queue", "type", "filter"]);
370
+ assertOnlyKeys("deleteAllJobs.where", where, ["id", "status", "queue", "type", "filter", "priority", "readyAt", "attempts"]);
371
371
  // Build the filter params, then short-circuit if any array filter resolved
372
372
  // to empty — an empty filter matches nothing, and we don't want to
373
373
  // accidentally delete everything.
@@ -417,7 +417,7 @@ export class Client {
417
417
  * ```
418
418
  */
419
419
  async countJobs(where = {}) {
420
- assertOnlyKeys("countJobs", where, ["id", "status", "queue", "type", "filter"]);
420
+ assertOnlyKeys("countJobs", where, ["id", "status", "queue", "type", "filter", "priority", "readyAt", "attempts"]);
421
421
  const params = buildJobFilter(where);
422
422
  if (isEmptyFilter(params))
423
423
  return 0;
@@ -468,7 +468,7 @@ export class Client {
468
468
  async updateAllJobs(options) {
469
469
  assertOnlyKeys("updateAllJobs", options, ["where", "apply"]);
470
470
  const where = options.where ?? {};
471
- assertOnlyKeys("updateAllJobs.where", where, ["id", "status", "queue", "type", "filter"]);
471
+ assertOnlyKeys("updateAllJobs.where", where, ["id", "status", "queue", "type", "filter", "priority", "readyAt", "attempts"]);
472
472
  // Same empty-filter short-circuit as deleteAllJobs.
473
473
  const params = buildJobFilter(where);
474
474
  if (isEmptyFilter(params))
@@ -1059,6 +1059,42 @@ function isEmptyFilter(params) {
1059
1059
  params.get("queue") === "" ||
1060
1060
  params.get("type") === "");
1061
1061
  }
1062
+ /**
1063
+ * Encode a {@link RangeFilter} value into the server's query syntax.
1064
+ *
1065
+ * The four accepted shapes:
1066
+ *
1067
+ * - `number` (e.g. `50`) -> `"50"`
1068
+ * - `{ min, max }` -> `"min..max"`
1069
+ * - `{ min }` -> `"min.."`
1070
+ * - `{ max }` -> `"..max"`
1071
+ *
1072
+ * Returns `undefined` for `null`/`undefined` so the caller can skip
1073
+ * setting the param. Throws `TypeError` for any other shape (e.g. arrays,
1074
+ * strings, objects with unknown keys).
1075
+ */
1076
+ function encodeRange(value) {
1077
+ if (value == null)
1078
+ return undefined;
1079
+ if (typeof value === "number") {
1080
+ if (!Number.isFinite(value)) {
1081
+ throw new TypeError(`range filter value must be a finite number, got ${value}`);
1082
+ }
1083
+ return String(value);
1084
+ }
1085
+ if (typeof value !== "object" || Array.isArray(value)) {
1086
+ throw new TypeError(`range filter must be a number or { min?, max? } object, got ${typeof value}`);
1087
+ }
1088
+ const { min, max } = value;
1089
+ for (const [key, bound] of [["min", min], ["max", max]]) {
1090
+ if (bound != null && (typeof bound !== "number" || !Number.isFinite(bound))) {
1091
+ throw new TypeError(`range filter "${key}" must be a finite number, got ${typeof bound}`);
1092
+ }
1093
+ }
1094
+ const lo = min != null ? String(min) : "";
1095
+ const hi = max != null ? String(max) : "";
1096
+ return `${lo}..${hi}`;
1097
+ }
1062
1098
  /**
1063
1099
  * Populate a {@link URLSearchParams} with the standard job filter fields.
1064
1100
  */
@@ -1073,6 +1109,15 @@ function buildJobFilter(where, params = new URLSearchParams()) {
1073
1109
  params.set("type", toCommaList(where.type));
1074
1110
  if (where.filter != null)
1075
1111
  params.set("filter", where.filter);
1112
+ const priority = encodeRange(where.priority);
1113
+ if (priority != null)
1114
+ params.set("priority", priority);
1115
+ const readyAt = encodeRange(where.readyAt);
1116
+ if (readyAt != null)
1117
+ params.set("ready_at", readyAt);
1118
+ const attempts = encodeRange(where.attempts);
1119
+ if (attempts != null)
1120
+ params.set("attempts", attempts);
1076
1121
  return params;
1077
1122
  }
1078
1123
  /**
package/dist/query.d.ts CHANGED
@@ -19,7 +19,7 @@
19
19
  *
20
20
  * @module
21
21
  */
22
- import type { Client, JobStatus, SortDirection, UpdateJobOptions } from "./client.ts";
22
+ import type { Client, JobStatus, RangeFilter, SortDirection, UpdateJobOptions } from "./client.ts";
23
23
  import type { Job, JobPage, ErrorRecord, ErrorPage } from "./resources.ts";
24
24
  /**
25
25
  * Base class for lazy, async-iterable collections.
@@ -73,6 +73,12 @@ export interface JobQueryOptions {
73
73
  status?: JobStatus | JobStatus[];
74
74
  /** jq expression applied to the payload. */
75
75
  jqFilter?: string;
76
+ /** Priority filter — exact value or `{min, max}` inclusive range. */
77
+ priority?: RangeFilter;
78
+ /** `readyAt` filter (ms since epoch) — exact value or `{min, max}` range. */
79
+ readyAt?: RangeFilter;
80
+ /** Failure count filter — exact value or `{min, max}` inclusive range. */
81
+ attempts?: RangeFilter;
76
82
  /** Sort order. Default: "asc" (oldest first). */
77
83
  order?: SortDirection;
78
84
  /** Maximum total number of jobs to return across all pages. */
@@ -145,6 +151,9 @@ export declare class JobQuery extends Lazy<Job> {
145
151
  private _type?;
146
152
  private _status?;
147
153
  private _jqFilter?;
154
+ private _priority?;
155
+ private _readyAt?;
156
+ private _attempts?;
148
157
  private _order?;
149
158
  private _limit?;
150
159
  private _pageSize?;
@@ -172,6 +181,47 @@ export declare class JobQuery extends Lazy<Job> {
172
181
  * Add a jq payload filter. Combines with any existing filter via `and`.
173
182
  */
174
183
  addJqFilter(jqFilter: string): JobQuery;
184
+ /**
185
+ * Filter by priority. Replaces any existing priority filter.
186
+ *
187
+ * Accepts an exact value (`50`) or a `{min, max}` range with inclusive
188
+ * bounds. Omit either side for an unbounded end. Lower numbers are
189
+ * higher priority.
190
+ *
191
+ * @example
192
+ * client.jobs().byPriority(0); // exact match
193
+ * client.jobs().byPriority({ min: 0, max: 100 }); // bounded range
194
+ * client.jobs().byPriority({ min: 100 }); // 100 or higher
195
+ * client.jobs().byPriority({ max: 100 }); // 100 or lower
196
+ */
197
+ byPriority(priority: RangeFilter | undefined): JobQuery;
198
+ /**
199
+ * Filter by `readyAt` (ms since epoch). Replaces any existing filter.
200
+ *
201
+ * Accepts an exact value or a `{min, max}` range with inclusive bounds.
202
+ * Use `Date.prototype.getTime()` to derive ms from a `Date` instance.
203
+ *
204
+ * @example
205
+ * // Eligible to run by now.
206
+ * client.jobs().byReadyAt({ max: Date.now() });
207
+ *
208
+ * // Within the next hour.
209
+ * client.jobs().byReadyAt({ min: Date.now(), max: Date.now() + 3_600_000 });
210
+ */
211
+ byReadyAt(readyAt: RangeFilter | undefined): JobQuery;
212
+ /**
213
+ * Filter by failure count. Replaces any existing attempts filter.
214
+ *
215
+ * Accepts an exact value or a `{min, max}` range with inclusive bounds.
216
+ * `0` selects jobs that have never failed; `{ min: 1 }` selects anything
217
+ * that has failed at least once.
218
+ *
219
+ * @example
220
+ * client.jobs().byAttempts(0); // never failed
221
+ * client.jobs().byAttempts({ min: 1 }); // has failed
222
+ * client.jobs().byAttempts({ min: 1, max: 3 }); // 1, 2, or 3 failures
223
+ */
224
+ byAttempts(attempts: RangeFilter | undefined): JobQuery;
175
225
  /**
176
226
  * Constrain results by an exact payload match.
177
227
  *
package/dist/query.js CHANGED
@@ -161,6 +161,9 @@ export class JobQuery extends Lazy {
161
161
  _type;
162
162
  _status;
163
163
  _jqFilter;
164
+ _priority;
165
+ _readyAt;
166
+ _attempts;
164
167
  _order;
165
168
  _limit;
166
169
  _pageSize;
@@ -173,6 +176,9 @@ export class JobQuery extends Lazy {
173
176
  this._type = options.type;
174
177
  this._status = options.status;
175
178
  this._jqFilter = options.jqFilter;
179
+ this._priority = options.priority;
180
+ this._readyAt = options.readyAt;
181
+ this._attempts = options.attempts;
176
182
  this._order = options.order;
177
183
  this._limit = options.limit;
178
184
  this._pageSize = options.pageSize;
@@ -222,6 +228,53 @@ export class JobQuery extends Lazy {
222
228
  jqFilter: concat(this._jqFilter, `(${jqFilter})`).join(" and "),
223
229
  });
224
230
  }
231
+ /**
232
+ * Filter by priority. Replaces any existing priority filter.
233
+ *
234
+ * Accepts an exact value (`50`) or a `{min, max}` range with inclusive
235
+ * bounds. Omit either side for an unbounded end. Lower numbers are
236
+ * higher priority.
237
+ *
238
+ * @example
239
+ * client.jobs().byPriority(0); // exact match
240
+ * client.jobs().byPriority({ min: 0, max: 100 }); // bounded range
241
+ * client.jobs().byPriority({ min: 100 }); // 100 or higher
242
+ * client.jobs().byPriority({ max: 100 }); // 100 or lower
243
+ */
244
+ byPriority(priority) {
245
+ return this.rebuild({ priority });
246
+ }
247
+ /**
248
+ * Filter by `readyAt` (ms since epoch). Replaces any existing filter.
249
+ *
250
+ * Accepts an exact value or a `{min, max}` range with inclusive bounds.
251
+ * Use `Date.prototype.getTime()` to derive ms from a `Date` instance.
252
+ *
253
+ * @example
254
+ * // Eligible to run by now.
255
+ * client.jobs().byReadyAt({ max: Date.now() });
256
+ *
257
+ * // Within the next hour.
258
+ * client.jobs().byReadyAt({ min: Date.now(), max: Date.now() + 3_600_000 });
259
+ */
260
+ byReadyAt(readyAt) {
261
+ return this.rebuild({ readyAt });
262
+ }
263
+ /**
264
+ * Filter by failure count. Replaces any existing attempts filter.
265
+ *
266
+ * Accepts an exact value or a `{min, max}` range with inclusive bounds.
267
+ * `0` selects jobs that have never failed; `{ min: 1 }` selects anything
268
+ * that has failed at least once.
269
+ *
270
+ * @example
271
+ * client.jobs().byAttempts(0); // never failed
272
+ * client.jobs().byAttempts({ min: 1 }); // has failed
273
+ * client.jobs().byAttempts({ min: 1, max: 3 }); // 1, 2, or 3 failures
274
+ */
275
+ byAttempts(attempts) {
276
+ return this.rebuild({ attempts });
277
+ }
225
278
  /**
226
279
  * Constrain results by an exact payload match.
227
280
  *
@@ -453,6 +506,9 @@ export class JobQuery extends Lazy {
453
506
  type: this._type,
454
507
  status: this._status,
455
508
  filter: this._jqFilter,
509
+ priority: this._priority,
510
+ readyAt: this._readyAt,
511
+ attempts: this._attempts,
456
512
  order: this._order,
457
513
  limit: effectivePageSize,
458
514
  });
@@ -474,6 +530,9 @@ export class JobQuery extends Lazy {
474
530
  type: this._type,
475
531
  status: this._status,
476
532
  filter: this._jqFilter,
533
+ priority: this._priority,
534
+ readyAt: this._readyAt,
535
+ attempts: this._attempts,
477
536
  };
478
537
  }
479
538
  rebuild(overrides) {
@@ -483,6 +542,9 @@ export class JobQuery extends Lazy {
483
542
  type: this._type,
484
543
  status: this._status,
485
544
  jqFilter: this._jqFilter,
545
+ priority: this._priority,
546
+ readyAt: this._readyAt,
547
+ attempts: this._attempts,
486
548
  order: this._order,
487
549
  limit: this._limit,
488
550
  pageSize: this._pageSize,
package/dist/types.d.ts CHANGED
@@ -161,6 +161,32 @@ export interface TakeOptions {
161
161
  /** AbortSignal to cancel the streaming connection. */
162
162
  signal?: AbortSignal;
163
163
  }
164
+ /**
165
+ * A range with inclusive bounds. Omit either side for an unbounded end.
166
+ *
167
+ * Used by the `priority`, `readyAt`, and `attempts` filter fields. An
168
+ * empty object (`{}`) is treated as a fully unbounded range.
169
+ */
170
+ export interface RangeBounds {
171
+ /** Lower bound, inclusive. Omit for no lower bound. */
172
+ min?: number;
173
+ /** Upper bound, inclusive. Omit for no upper bound. */
174
+ max?: number;
175
+ }
176
+ /**
177
+ * A range filter that matches either a single value or a span of values.
178
+ *
179
+ * Pass a bare `number` for an exact match. Pass an object with `min` and/or
180
+ * `max` for a range — both bounds are **inclusive**. Omit either side for
181
+ * an unbounded end.
182
+ *
183
+ * @example
184
+ * priority: 50 // exactly 50
185
+ * priority: { min: 0, max: 100 } // 0..100 inclusive
186
+ * priority: { min: 50 } // 50 or higher
187
+ * priority: { max: 100 } // 100 or lower
188
+ */
189
+ export type RangeFilter = number | RangeBounds;
164
190
  /** Options for listing jobs with cursor-based pagination. */
165
191
  export interface ListJobsOptions {
166
192
  /** Cursor: start after this job ID (exclusive). */
@@ -177,6 +203,21 @@ export interface ListJobsOptions {
177
203
  type?: string | string[];
178
204
  /** Filter by job ID. Accepts a single value or an array. */
179
205
  id?: string | string[];
206
+ /**
207
+ * Filter by priority. Accepts an exact value or a `{min, max}` range
208
+ * with inclusive bounds. Lower numbers are higher priority.
209
+ */
210
+ priority?: RangeFilter;
211
+ /**
212
+ * Filter by `readyAt` (milliseconds since the Unix epoch). Accepts an
213
+ * exact value or a `{min, max}` range with inclusive bounds.
214
+ */
215
+ readyAt?: RangeFilter;
216
+ /**
217
+ * Filter by failure count. Accepts an exact value or a `{min, max}`
218
+ * range with inclusive bounds. `0` selects jobs that have never failed.
219
+ */
220
+ attempts?: RangeFilter;
180
221
  /** jq expression to filter jobs by payload. */
181
222
  filter?: string;
182
223
  }
@@ -211,6 +252,21 @@ export interface JobFilter {
211
252
  queue?: string | string[];
212
253
  /** Filter by job type. Accepts a single value or an array. */
213
254
  type?: string | string[];
255
+ /**
256
+ * Filter by priority. Accepts an exact value or a `{min, max}` range
257
+ * with inclusive bounds. Lower numbers are higher priority.
258
+ */
259
+ priority?: RangeFilter;
260
+ /**
261
+ * Filter by `readyAt` (milliseconds since the Unix epoch). Accepts an
262
+ * exact value or a `{min, max}` range with inclusive bounds.
263
+ */
264
+ readyAt?: RangeFilter;
265
+ /**
266
+ * Filter by failure count. Accepts an exact value or a `{min, max}`
267
+ * range with inclusive bounds. `0` selects jobs that have never failed.
268
+ */
269
+ attempts?: RangeFilter;
214
270
  /** jq expression to filter jobs by payload. */
215
271
  filter?: string;
216
272
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zizq-labs/zizq",
3
- "version": "0.4.2",
3
+ "version": "0.5.0",
4
4
  "description": "Node.js client for the Zizq job queue server",
5
5
  "homepage": "https://zizq.io",
6
6
  "repository": {