@lucaapp/service-utils 5.14.0 → 5.15.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.
@@ -162,6 +162,7 @@ options, tags, debug) => {
162
162
  headers: headersSchema ? [headersSchema] : [],
163
163
  },
164
164
  responses: responseMap,
165
+ ...(options.operationId && { operationId: options.operationId }),
165
166
  });
166
167
  };
167
168
  exports.registerEndpoint = registerEndpoint;
@@ -20,4 +20,5 @@ export type EndpointOptions<TResponseSchemas extends ReadonlyArray<EndpointRespo
20
20
  middlewares?: TMiddlewares;
21
21
  responses: TResponseSchemas;
22
22
  errors?: Record<string, number>;
23
+ operationId?: string;
23
24
  };
@@ -2,8 +2,9 @@ import { PgBoss } from 'pg-boss';
2
2
  /**
3
3
  * List jobs in a queue with mandatory pagination.
4
4
  *
5
- * pg-boss `findJobs` does not support limit/offset directly, so we slice
6
- * client-side. Callers must pass `limit` (clamped to MAX_LIMIT) and
7
- * `offset` to avoid loading 1M rows into memory.
5
+ * pg-boss `findJobs` does not support limit/offset or ORDER BY directly, so we
6
+ * sort client-side (actionable states first, then newest-first within each
7
+ * group) before slicing. Without this, active/created jobs in queues with
8
+ * >100 completed entries would never appear in the default page.
8
9
  */
9
10
  export declare const listJobs: (boss: PgBoss, queueName: string, limit?: number, offset?: number) => Promise<Record<string, unknown>[]>;
@@ -3,18 +3,37 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.listJobs = void 0;
4
4
  const DEFAULT_LIMIT = 100;
5
5
  const MAX_LIMIT = 1000;
6
+ // Actionable states surface first so they are never buried by completed volume.
7
+ // pg-boss ENUM order: created < retry < active < completed < cancelled < failed
8
+ const STATE_PRIORITY = {
9
+ active: 0,
10
+ created: 1,
11
+ retry: 2,
12
+ failed: 3,
13
+ cancelled: 4,
14
+ completed: 5,
15
+ };
6
16
  /**
7
17
  * List jobs in a queue with mandatory pagination.
8
18
  *
9
- * pg-boss `findJobs` does not support limit/offset directly, so we slice
10
- * client-side. Callers must pass `limit` (clamped to MAX_LIMIT) and
11
- * `offset` to avoid loading 1M rows into memory.
19
+ * pg-boss `findJobs` does not support limit/offset or ORDER BY directly, so we
20
+ * sort client-side (actionable states first, then newest-first within each
21
+ * group) before slicing. Without this, active/created jobs in queues with
22
+ * >100 completed entries would never appear in the default page.
12
23
  */
13
24
  const listJobs = async (boss, queueName, limit = DEFAULT_LIMIT, offset = 0) => {
14
25
  const cappedLimit = Math.min(Math.max(limit, 1), MAX_LIMIT);
15
26
  const safeOffset = Math.max(offset, 0);
16
27
  const jobs = await boss.findJobs(queueName);
17
28
  return jobs
29
+ .sort((a, b) => {
30
+ const pa = STATE_PRIORITY[a.state] ?? 99;
31
+ const pb = STATE_PRIORITY[b.state] ?? 99;
32
+ if (pa !== pb)
33
+ return pa - pb;
34
+ return (new Date(b.createdOn).getTime() -
35
+ new Date(a.createdOn).getTime());
36
+ })
18
37
  .slice(safeOffset, safeOffset + cappedLimit)
19
38
  .map(job => ({ ...job }));
20
39
  };
@@ -38,7 +38,7 @@ declare class ServiceIdentity {
38
38
  private readonly jwksCache;
39
39
  private readonly keyCache;
40
40
  private readonly axiosClient;
41
- constructor(identityName: string, identityKid: string, identityPrivateKey: string, identityPublicKey: string, debug?: boolean);
41
+ constructor(identityName: string, identityKid: string, identityPrivateKey: string, identityPublicKey: string, debug?: boolean, timeoutMs?: number);
42
42
  getRemoteJWKS: (service: string) => RemoteJWKS;
43
43
  private getJwtVerifyOptions;
44
44
  getIdentityPublicKey: () => Promise<jose.KeyLike>;
@@ -68,7 +68,7 @@ class ServiceIdentityError extends Error {
68
68
  }
69
69
  exports.ServiceIdentityError = ServiceIdentityError;
70
70
  class ServiceIdentity {
71
- constructor(identityName, identityKid, identityPrivateKey, identityPublicKey, debug = false) {
71
+ constructor(identityName, identityKid, identityPrivateKey, identityPublicKey, debug = false, timeoutMs = 60_000) {
72
72
  this.jwksCache = {};
73
73
  this.keyCache = {};
74
74
  this.getRemoteJWKS = (service) => {
@@ -199,7 +199,7 @@ class ServiceIdentity {
199
199
  this.identityKid = identityKid;
200
200
  this.identityPrivateKey = identityPrivateKey;
201
201
  this.identityPublicKey = identityPublicKey;
202
- this.axiosClient = axios_1.default.create({ proxy: false });
202
+ this.axiosClient = axios_1.default.create({ proxy: false, timeout: timeoutMs });
203
203
  // Configure axios-retry to handle 429 and respect Retry-After header
204
204
  (0, axios_retry_1.default)(this.axiosClient, {
205
205
  retries: 3,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucaapp/service-utils",
3
- "version": "5.14.0",
3
+ "version": "5.15.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [