@lucaapp/service-utils 5.8.0 → 5.10.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.
@@ -1,28 +1,205 @@
1
- export type Payment = {
1
+ import { SupportedCurrencies } from '../../money/supportedCurrencies';
2
+ /**
3
+ * JSON-serialisable value tree.
4
+ *
5
+ * Used for opaque payloads carried across the wire. Anything stored here
6
+ * must round-trip through `JSON.stringify` / `JSON.parse` without loss.
7
+ */
8
+ export type JsonValue = string | number | boolean | null | JsonValue[] | {
9
+ [key: string]: JsonValue;
10
+ };
11
+ /** Legacy 3-letter terminal status code from the original payment provider integration. */
12
+ export type RapydPaymentStatus = 'ACT' | 'CAN' | 'CLO' | 'ERR' | 'EXP' | 'NEW' | 'REV';
13
+ /** Provider-neutral payment lifecycle status. */
14
+ export type PaymentStatus = 'PAID' | 'NEW' | 'ACTIVE' | 'CANCELLED' | 'EXPIRED' | 'REFUNDED' | 'ERROR' | 'UNKNOWN';
15
+ /**
16
+ * Lifecycle timestamps shared by all payment events.
17
+ *
18
+ * Each timestamp marks the first time the payment entered the corresponding
19
+ * state. A null value means the state was never reached.
20
+ */
21
+ export type PaymentStatusTimings = {
22
+ /** Timestamp when the payment record was created (session start, NOT settlement). */
23
+ paymentCreatedAt: Date;
24
+ /** Payment record created; awaiting consumer action (e.g. order created, link sent, QR displayed). */
25
+ statusNewAt: Date | null;
26
+ /** Consumer engaged with the payment flow (e.g. opened a 3DS challenge, tapped a terminal, clicked the payment link). */
27
+ statusActiveAt: Date | null;
28
+ /** Provider authorised and captured the funds (online auth + capture or terminal sale complete). */
29
+ statusCompleteAt?: Date | null;
30
+ /** Cancelled by consumer or operator before completion. */
31
+ statusCanceledAt: Date | null;
32
+ /** Payment session expired before completion. */
33
+ statusExpiredAt: Date | null;
34
+ /** Provider returned an error or refused the payment. */
35
+ statusErrorAt: Date | null;
36
+ /** Authorised payment was reversed before settlement (e.g. chargeback pre-arbitration). */
37
+ statusReversedAt?: Date | null;
38
+ /** Projected or actual settlement date to the merchant balance. Null until the provider schedules settlement. */
39
+ settleAt?: Date | null;
40
+ };
41
+ /** Fields shared by both the legacy {@link Payment} event and the provider-neutral {@link PaymentEvent}. */
42
+ export type PaymentBase = {
43
+ /** Stable payment id. Uniquely identifies the payment across all systems. */
2
44
  uuid: string;
45
+ /** Merchant location id (UUID). */
3
46
  locationId: string;
47
+ /** Human-readable location name. Null when not provided. */
4
48
  locationName: string | null;
49
+ /** Table or seat identifier from the POS. Null for non-dine-in payments. */
5
50
  table: string | null;
51
+ /** Pre-created payment-request id. Null for spontaneous payments. */
6
52
  paymentRequestId: string | null;
7
- paymentCreatedAt: Date;
8
- paidAt: Date | null;
53
+ /** Short verifier token used by consumer-facing flows to prove ownership of the payment session. */
9
54
  paymentVerifier: string;
10
- totalAmount: number;
55
+ /** Net goods/services amount before tip, in the smallest currency subunit. */
11
56
  invoiceAmount: number;
57
+ /** Consumer-added gratuity, in the smallest currency subunit. Zero when no tip was given. */
12
58
  tipAmount: number;
59
+ } & PaymentStatusTimings;
60
+ /**
61
+ * Legacy payment event tied to the original provider integration.
62
+ *
63
+ * Kept for backward compatibility. New consumers should subscribe to
64
+ * {@link PaymentEvent}.
65
+ */
66
+ export type Payment = PaymentBase & {
67
+ /** Total paid by the consumer (= `invoiceAmount + tipAmount`), in the smallest currency subunit. Kept for legacy consumers. */
68
+ totalAmount: number;
69
+ /** Timestamp when the payment was marked paid. */
70
+ paidAt: Date | null;
71
+ /** @deprecated Legacy terminal "CLO" state. Use `statusCompleteAt`. */
72
+ statusClosedAt: Date | null;
73
+ /** Fixed processing fee, in the smallest currency subunit. */
13
74
  fixedFee: number;
75
+ /** Variable fee (commission + markup), in the smallest currency subunit. */
14
76
  variableFee: number;
77
+ /** Legacy provider payment id. */
15
78
  rapydPaymentId: string | null;
79
+ /** Legacy provider error code on failure. */
16
80
  rapydErrorCode: string | null;
81
+ /** Legacy provider error message on failure. */
17
82
  rapydErrorMessage: string | null;
18
- rapydPaymentStatus: 'ACT' | 'CAN' | 'CLO' | 'ERR' | 'EXP' | 'NEW' | 'REV';
83
+ /** Legacy 3-letter status code from the provider. */
84
+ rapydPaymentStatus: RapydPaymentStatus;
85
+ /** Legacy provider customer / saved-card alias. */
19
86
  rapydCustomerId: string | null;
87
+ /** Aggregated payout batch id. Null until the payment is included in a payout. */
20
88
  payoutId: string | null;
21
- statusActiveAt: Date | null;
22
- statusCanceledAt: Date | null;
23
- statusClosedAt: Date | null;
24
- statusErrorAt: Date | null;
25
- statusExpiredAt: Date | null;
26
- statusNewAt: Date | null;
27
- statusReversedAt?: Date | null;
89
+ };
90
+ /**
91
+ * Provider-neutral payment lifecycle event.
92
+ *
93
+ * Carries the full domain context needed for fiscalisation, receipt
94
+ * rendering, and downstream reconciliation. Wire format is JSON: monetary
95
+ * fields are integers in the smallest currency subunit and `currency`
96
+ * declares the unit.
97
+ */
98
+ export type PaymentEvent = PaymentBase & {
99
+ /** Checkout session id. Optional — some flows emit payment events without a checkout. */
100
+ checkoutId?: string;
101
+ /** Order id (e.g. POS / fiscalisation order reference). Absent for payments not tied to an order. */
102
+ orderId?: string;
103
+ /** Operator-added service charge / convenience fee, in the smallest currency subunit. Zero if none. */
104
+ surchargeAmount: number;
105
+ /** ISO 4217 code that applies to every monetary field on this event. Single-currency invariant. */
106
+ currency: SupportedCurrencies;
107
+ /** Lifecycle status at event-emission time. */
108
+ status: PaymentStatus;
109
+ /** Method identifier, e.g. `'CARD'`, `'CASH'`, `'WALLET'`. */
110
+ method: string;
111
+ /** True if `method` is a cash variant. Cash flows skip provider webhooks and short-circuit fiscalisation. */
112
+ isCash: boolean;
113
+ /** Origin service identifier (free-form short string). */
114
+ source: string;
115
+ /** Aggregated payout batch id. Null until included in a payout. */
116
+ payoutId?: string | null;
117
+ /** Provider-side identifiers, errors, and raw provider payload. Absent for cash. */
118
+ merchantDetails?: PaymentMerchantDetails;
119
+ /** Card-specific identifiers and terminal context. Absent for non-card methods. */
120
+ cardDetails?: PaymentCardDetails;
121
+ /** Per-item breakdown for fiscalisation and receipt rendering. */
122
+ lineItems?: PaymentEventLineItem[];
123
+ };
124
+ /** Amount the consumer actually pays = `invoiceAmount + tipAmount + surchargeAmount` (smallest currency subunit). */
125
+ export declare const consumerPayAmount: (event: PaymentEvent) => number;
126
+ /**
127
+ * Amount receivable by the operator before Luca / provider fees are
128
+ * deducted = `invoiceAmount + tipAmount` (smallest currency subunit).
129
+ *
130
+ * Surcharge is excluded — it covers the consumer-side fee, not operator
131
+ * revenue. Net payout to the operator is this minus the per-payment fees.
132
+ */
133
+ export declare const operatorReceivableAmount: (event: PaymentEvent) => number;
134
+ /**
135
+ * Provider-side metadata for a payment.
136
+ *
137
+ * All fields optional — populated by whichever provider handled the
138
+ * payment. Absent on cash and other non-provider flows.
139
+ */
140
+ export type PaymentMerchantDetails = {
141
+ /** Payment-processor identifier (lowercase short string). Null when not yet routed to a provider. */
142
+ provider?: string | null;
143
+ /** Provider's payment id. Null until the provider authorises. */
144
+ providerIdentifier?: string | null;
145
+ /** Machine-readable error / decline code from the provider. Null on success. */
146
+ providerErrorCode?: string | null;
147
+ /** Human-readable provider error detail. Null on success. */
148
+ providerErrorMessage?: string | null;
149
+ /** Raw provider payload (notification or response body). Used for audits and chargeback evidence. */
150
+ providerData?: {
151
+ [key: string]: JsonValue;
152
+ } | null;
153
+ /** Provider-facing merchant reference used to reconcile internal records against the provider's records. */
154
+ externalReference?: string | null;
155
+ };
156
+ /**
157
+ * Card and terminal context.
158
+ *
159
+ * Card fields populated for card payments; terminal/consumer fields
160
+ * populated when applicable, regardless of card vs. wallet.
161
+ */
162
+ export type PaymentCardDetails = {
163
+ /** Last 4 digits of the card. Null for non-card methods. */
164
+ last4?: string | null;
165
+ /** Provider authorisation code. Null until authorised. */
166
+ authCode?: string | null;
167
+ /** Saved-card alias for tokenised cards. Null for one-time payments. */
168
+ consumerAlias?: string | null;
169
+ /** Physical terminal id. Null for online / QR payments. */
170
+ terminalId?: string | null;
171
+ /** Consumer account id. Null for anonymous payments. */
172
+ consumerId?: string | null;
173
+ };
174
+ /**
175
+ * One billable line in the order, used for fiscalisation and receipt
176
+ * rendering.
177
+ *
178
+ * Sub-items represent components of a parent line (e.g. base drink + paid
179
+ * topping) and follow the same shape recursively. Amounts are integers in
180
+ * the smallest currency subunit.
181
+ */
182
+ export type PaymentEventLineItem = {
183
+ /** Stable line-item id. Omitted on synthetic sub-items that have no own row. */
184
+ uuid?: string;
185
+ /** POS-system menu item / SKU id. Null when not synced from the POS menu. */
186
+ posItemId?: string | null;
187
+ /** Display name (e.g. `'Espresso'`). May be omitted when the consumer can resolve it from `posItemId`. */
188
+ name?: string;
189
+ /** Number of units, e.g. `2` for two coffees. */
190
+ quantity: number;
191
+ /** Price for one unit, in the smallest currency subunit. */
192
+ pricePerUnit: number;
193
+ /** `quantity × pricePerUnit + Σ subItems.totalPrice`, in the smallest currency subunit. */
194
+ totalPrice: number;
195
+ /**
196
+ * VAT / sales-tax rate as a percentage value (e.g. `19` for 19%, `7` for
197
+ * 7%). NOT a decimal fraction — `0.19` would mean 0.19%. Null if
198
+ * tax-exempt or unknown.
199
+ */
200
+ taxPercentage?: number | null;
201
+ /** Item currency. Typically equals the parent payment currency. */
202
+ currency: SupportedCurrencies;
203
+ /** Recursive components of this line. Each sub-item follows the same shape. */
204
+ subItems?: PaymentEventLineItem[];
28
205
  };
@@ -1,2 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.operatorReceivableAmount = exports.consumerPayAmount = void 0;
4
+ /** Amount the consumer actually pays = `invoiceAmount + tipAmount + surchargeAmount` (smallest currency subunit). */
5
+ const consumerPayAmount = (event) => event.invoiceAmount + event.tipAmount + event.surchargeAmount;
6
+ exports.consumerPayAmount = consumerPayAmount;
7
+ /**
8
+ * Amount receivable by the operator before Luca / provider fees are
9
+ * deducted = `invoiceAmount + tipAmount` (smallest currency subunit).
10
+ *
11
+ * Surcharge is excluded — it covers the consumer-side fee, not operator
12
+ * revenue. Net payout to the operator is this minus the per-payment fees.
13
+ */
14
+ const operatorReceivableAmount = (event) => event.invoiceAmount + event.tipAmount;
15
+ exports.operatorReceivableAmount = operatorReceivableAmount;
@@ -82,5 +82,6 @@ declare const MessageIssuer: {
82
82
  "wsevent_backend-pos": Service;
83
83
  tokenization_job_item: Service;
84
84
  };
85
- export { KafkaTopic, MessageIssuer };
85
+ declare const MessageSignatureIssuers: Partial<Record<KafkaTopic, Service[]>>;
86
+ export { KafkaTopic, MessageIssuer, MessageSignatureIssuers };
86
87
  export type { MessageFormats };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MessageIssuer = exports.KafkaTopic = void 0;
3
+ exports.MessageSignatureIssuers = exports.MessageIssuer = exports.KafkaTopic = void 0;
4
4
  const serviceIdentity_1 = require("../serviceIdentity");
5
5
  var KafkaTopic;
6
6
  (function (KafkaTopic) {
@@ -48,3 +48,7 @@ const MessageIssuer = {
48
48
  [KafkaTopic.TOKENIZATION_JOB_ITEM]: serviceIdentity_1.Service.BACKEND_PAY,
49
49
  };
50
50
  exports.MessageIssuer = MessageIssuer;
51
+ const MessageSignatureIssuers = {
52
+ [KafkaTopic.PAYMENTS]: [serviceIdentity_1.Service.BACKEND_PAY, serviceIdentity_1.Service.BACKEND_TSE],
53
+ };
54
+ exports.MessageSignatureIssuers = MessageSignatureIssuers;
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  Object.defineProperty(exports, "__esModule", { value: true });
26
36
  exports.KafkaClient = void 0;
27
37
  const kafkajs_1 = require("kafkajs");
@@ -61,6 +71,18 @@ const messageAcknowledgedCounter = new metrics_1.metricsClient.Counter({
61
71
  const getIssuer = (kafkaTopic) => {
62
72
  return events_1.MessageIssuer[kafkaTopic].valueOf();
63
73
  };
74
+ const getAllowedSignatureIssuers = (kafkaTopic) => {
75
+ return (events_1.MessageSignatureIssuers[kafkaTopic] ?? [events_1.MessageIssuer[kafkaTopic]]).map(issuer => issuer.valueOf());
76
+ };
77
+ const headerToString = (header) => {
78
+ if (Array.isArray(header)) {
79
+ return headerToString(header[0]);
80
+ }
81
+ if (Buffer.isBuffer(header)) {
82
+ return header.toString();
83
+ }
84
+ return header;
85
+ };
64
86
  class KafkaClient {
65
87
  constructor(parentLogger, kafkaConfig, topicSecrets, serviceIdentity) {
66
88
  this.connect = async () => {
@@ -119,11 +141,15 @@ class KafkaClient {
119
141
  this.logger.info('Skipping signature verification (encryption disabled)');
120
142
  return;
121
143
  }
122
- if (!headers || !headers.signature) {
144
+ const signature = headerToString(headers?.signature);
145
+ if (!signature) {
123
146
  throw (0, utils_1.logAndGetError)(this.logger, 'Unable to verify signature. Expected header not present');
124
147
  }
125
- const issuer = getIssuer(kafkaTopic);
126
- const { signature } = headers;
148
+ const issuer = headerToString(headers?.signatureIssuer) ?? getIssuer(kafkaTopic);
149
+ const allowedIssuers = getAllowedSignatureIssuers(kafkaTopic);
150
+ if (!allowedIssuers.includes(issuer)) {
151
+ throw (0, utils_1.logAndGetError)(this.logger, `Unable to verify signature. Issuer ${issuer} is not allowed for topic=${kafkaTopic}`);
152
+ }
127
153
  const jwks = await this.serviceIdentity.getRemoteJWKS(issuer);
128
154
  if (!jwks) {
129
155
  throw (0, utils_1.logAndGetError)(this.logger, `Unable to find jwks for issuer=${issuer}`);
@@ -230,7 +256,10 @@ class KafkaClient {
230
256
  {
231
257
  key,
232
258
  value: encryptedValue,
233
- headers: { signature },
259
+ headers: {
260
+ signature,
261
+ signatureIssuer: this.serviceIdentity.identityName,
262
+ },
234
263
  },
235
264
  ],
236
265
  };
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  Object.defineProperty(exports, "__esModule", { value: true });
26
36
  exports.metricsClient = void 0;
27
37
  exports.metricsClient = __importStar(require("prom-client"));
@@ -1,20 +1,10 @@
1
1
  import { Api } from '../../api/api';
2
2
  import { PgBossService } from '../service';
3
+ import type { Middleware } from '../../api/types/middleware';
3
4
  /**
4
- * Mounts pg-boss dashboard API routes onto an Api instance.
5
- *
6
- * Endpoints:
7
- * - GET /queues — list queues with stats
8
- * - GET /queues/:name/jobs — list jobs in a queue
9
- * - GET /queues/:queue/jobs/:id — job detail
10
- * - POST /queues/:queue/jobs/:id/retry — retry a job
11
- * - POST /queues/:queue/jobs/:id/cancel — cancel a job
12
- * - DELETE /queues/:queue/jobs/:id — delete a job
13
- * - GET /schedules — list cron schedules
14
- * - POST /schedules — create a schedule
15
- * - PUT /schedules/:name — update a schedule
16
- * - DELETE /schedules/:name — delete a schedule
17
- * - POST /queues/:name/jobs — enqueue a new job
18
- * - GET /warnings — recent warnings
5
+ * Express path prefix for every pg-boss admin route. `Api.child()` only
6
+ * affects OpenAPI documentation, not the underlying express router, so the
7
+ * prefix MUST live on each path string to make routing work end-to-end.
19
8
  */
20
- export declare const mountPgBossApiRoutes: (api: Api, service: PgBossService) => void;
9
+ export declare const PGBOSS_API_PATH_PREFIX = "/support/pgboss";
10
+ export declare const mountPgBossApiRoutes: (api: Api, service: PgBossService, middlewares?: Middleware<any, any, any, any, any, any>[]) => void;
@@ -1,37 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.mountPgBossApiRoutes = void 0;
3
+ exports.mountPgBossApiRoutes = exports.PGBOSS_API_PATH_PREFIX = void 0;
4
4
  const send_1 = require("../../api/send");
5
5
  const response_1 = require("../../api/response");
6
6
  const routes_schema_1 = require("./routes.schema");
7
7
  /**
8
- * Mounts pg-boss dashboard API routes onto an Api instance.
9
- *
10
- * Endpoints:
11
- * - GET /queues — list queues with stats
12
- * - GET /queues/:name/jobs — list jobs in a queue
13
- * - GET /queues/:queue/jobs/:id — job detail
14
- * - POST /queues/:queue/jobs/:id/retry — retry a job
15
- * - POST /queues/:queue/jobs/:id/cancel — cancel a job
16
- * - DELETE /queues/:queue/jobs/:id — delete a job
17
- * - GET /schedules — list cron schedules
18
- * - POST /schedules — create a schedule
19
- * - PUT /schedules/:name — update a schedule
20
- * - DELETE /schedules/:name — delete a schedule
21
- * - POST /queues/:name/jobs — enqueue a new job
22
- * - GET /warnings — recent warnings
8
+ * Express path prefix for every pg-boss admin route. `Api.child()` only
9
+ * affects OpenAPI documentation, not the underlying express router, so the
10
+ * prefix MUST live on each path string to make routing work end-to-end.
23
11
  */
24
- const mountPgBossApiRoutes = (api, service) => {
12
+ exports.PGBOSS_API_PATH_PREFIX = '/support/pgboss';
13
+ const mountPgBossApiRoutes = (api, service,
14
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
+ middlewares) => {
25
16
  const pgBossApi = api.child({ tags: ['PgBoss'] });
26
- // GET /queues list queues with stats
27
- pgBossApi.get('/queues', 'List all queues with stats', {
17
+ const p = (path) => `${exports.PGBOSS_API_PATH_PREFIX}${path}`;
18
+ const mw = middlewares?.length ? { middlewares } : {};
19
+ pgBossApi.get(p('/queues'), 'List all queues with stats', {
20
+ ...mw,
28
21
  responses: [(0, response_1.okResponse)(routes_schema_1.queueStatsArraySchema)],
29
22
  }, async (_request, _context, respond) => {
30
23
  const stats = await service.getQueueStats();
31
24
  return respond((0, send_1.ok)(stats));
32
25
  });
33
- // GET /queues/:name/jobs list jobs in a queue
34
- pgBossApi.get('/queues/:name/jobs', 'List jobs in a queue', {
26
+ pgBossApi.get(p('/queues/:name/jobs'), 'List jobs in a queue', {
27
+ ...mw,
35
28
  responses: [(0, response_1.okResponse)(routes_schema_1.jobArraySchema)],
36
29
  schemas: {
37
30
  params: routes_schema_1.queueNameParamsSchema,
@@ -40,8 +33,8 @@ const mountPgBossApiRoutes = (api, service) => {
40
33
  const jobs = await service.listJobs(request.params.name);
41
34
  return respond((0, send_1.ok)(jobs));
42
35
  });
43
- // GET /queues/:queue/jobs/:id job detail
44
- pgBossApi.get('/queues/:queue/jobs/:id', 'Get job details', {
36
+ pgBossApi.get(p('/queues/:queue/jobs/:id'), 'Get job details', {
37
+ ...mw,
45
38
  responses: [(0, response_1.okResponse)(routes_schema_1.jobDetailSchema)],
46
39
  schemas: {
47
40
  params: routes_schema_1.queueJobParamsSchema,
@@ -54,8 +47,8 @@ const mountPgBossApiRoutes = (api, service) => {
54
47
  }
55
48
  return respond((0, send_1.ok)(job));
56
49
  });
57
- // POST /queues/:queue/jobs/:id/retry retry a failed job
58
- pgBossApi.post('/queues/:queue/jobs/:id/retry', 'Retry a failed job', {
50
+ pgBossApi.post(p('/queues/:queue/jobs/:id/retry'), 'Retry a failed job', {
51
+ ...mw,
59
52
  responses: [(0, response_1.okResponse)(routes_schema_1.successResponseSchema)],
60
53
  schemas: {
61
54
  params: routes_schema_1.queueJobParamsSchema,
@@ -65,8 +58,8 @@ const mountPgBossApiRoutes = (api, service) => {
65
58
  await service.retryJob(queue, id);
66
59
  return respond((0, send_1.ok)({ success: true, jobId: id }));
67
60
  });
68
- // POST /queues/:queue/jobs/:id/cancel cancel a job
69
- pgBossApi.post('/queues/:queue/jobs/:id/cancel', 'Cancel a job', {
61
+ pgBossApi.post(p('/queues/:queue/jobs/:id/cancel'), 'Cancel a job', {
62
+ ...mw,
70
63
  responses: [(0, response_1.okResponse)(routes_schema_1.successResponseSchema)],
71
64
  schemas: {
72
65
  params: routes_schema_1.queueJobParamsSchema,
@@ -76,8 +69,8 @@ const mountPgBossApiRoutes = (api, service) => {
76
69
  await service.cancelJob(queue, id);
77
70
  return respond((0, send_1.ok)({ success: true, jobId: id }));
78
71
  });
79
- // DELETE /queues/:queue/jobs/:id delete a job
80
- pgBossApi.delete('/queues/:queue/jobs/:id', 'Delete a job', {
72
+ pgBossApi.delete(p('/queues/:queue/jobs/:id'), 'Delete a job', {
73
+ ...mw,
81
74
  responses: [(0, response_1.okResponse)(routes_schema_1.successResponseSchema)],
82
75
  schemas: {
83
76
  params: routes_schema_1.queueJobParamsSchema,
@@ -87,15 +80,15 @@ const mountPgBossApiRoutes = (api, service) => {
87
80
  await service.deleteJob(queue, id);
88
81
  return respond((0, send_1.ok)({ success: true, deleted: id }));
89
82
  });
90
- // GET /schedules list cron schedules
91
- pgBossApi.get('/schedules', 'List all cron schedules', {
83
+ pgBossApi.get(p('/schedules'), 'List all cron schedules', {
84
+ ...mw,
92
85
  responses: [(0, response_1.okResponse)(routes_schema_1.scheduleArraySchema)],
93
86
  }, async (_request, _context, respond) => {
94
87
  const schedules = await service.getSchedules();
95
88
  return respond((0, send_1.ok)(schedules));
96
89
  });
97
- // POST /schedules create a cron schedule
98
- pgBossApi.post('/schedules', 'Create a cron schedule', {
90
+ pgBossApi.post(p('/schedules'), 'Create a cron schedule', {
91
+ ...mw,
99
92
  responses: [(0, response_1.createdResponse)(routes_schema_1.successResponseSchema)],
100
93
  schemas: {
101
94
  body: routes_schema_1.scheduleBodySchema,
@@ -105,8 +98,8 @@ const mountPgBossApiRoutes = (api, service) => {
105
98
  await service.createSchedule(name, cron, data, options);
106
99
  return respond((0, send_1.created)({ success: true, name }));
107
100
  });
108
- // PUT /schedules/:name update a cron schedule
109
- pgBossApi.put('/schedules/:name', 'Update a cron schedule', {
101
+ pgBossApi.put(p('/schedules/:name'), 'Update a cron schedule', {
102
+ ...mw,
110
103
  responses: [(0, response_1.okResponse)(routes_schema_1.successResponseSchema)],
111
104
  schemas: {
112
105
  params: routes_schema_1.scheduleNameParamsSchema,
@@ -117,8 +110,8 @@ const mountPgBossApiRoutes = (api, service) => {
117
110
  await service.updateSchedule(request.params.name, cron, data, options);
118
111
  return respond((0, send_1.ok)({ success: true, name: request.params.name }));
119
112
  });
120
- // DELETE /schedules/:name delete a cron schedule
121
- pgBossApi.delete('/schedules/:name', 'Delete a cron schedule', {
113
+ pgBossApi.delete(p('/schedules/:name'), 'Delete a cron schedule', {
114
+ ...mw,
122
115
  responses: [(0, response_1.okResponse)(routes_schema_1.successResponseSchema)],
123
116
  schemas: {
124
117
  params: routes_schema_1.scheduleNameParamsSchema,
@@ -127,8 +120,8 @@ const mountPgBossApiRoutes = (api, service) => {
127
120
  await service.deleteSchedule(request.params.name);
128
121
  return respond((0, send_1.ok)({ success: true, deleted: request.params.name }));
129
122
  });
130
- // POST /queues/:name/jobs enqueue a new job
131
- pgBossApi.post('/queues/:name/jobs', 'Enqueue a new job', {
123
+ pgBossApi.post(p('/queues/:name/jobs'), 'Enqueue a new job', {
124
+ ...mw,
132
125
  responses: [(0, response_1.createdResponse)(routes_schema_1.successResponseSchema)],
133
126
  schemas: {
134
127
  params: routes_schema_1.queueNameParamsSchema,
@@ -139,8 +132,8 @@ const mountPgBossApiRoutes = (api, service) => {
139
132
  const jobId = await service.enqueueJob(request.params.name, data, options);
140
133
  return respond((0, send_1.created)({ success: true, jobId: jobId ?? undefined }));
141
134
  });
142
- // GET /warnings recent warnings
143
- pgBossApi.get('/warnings', 'List recent warnings', {
135
+ pgBossApi.get(p('/warnings'), 'List recent warnings', {
136
+ ...mw,
144
137
  responses: [(0, response_1.okResponse)(routes_schema_1.warningArraySchema)],
145
138
  schemas: {
146
139
  query: routes_schema_1.warningsQuerySchema,
@@ -1,5 +1,5 @@
1
1
  import { PgBoss } from 'pg-boss';
2
- import type { SendOptions } from 'pg-boss';
2
+ import type { Job, SendOptions } from 'pg-boss';
3
3
  import type { Logger } from 'pino';
4
4
  import type { Sequelize, Transaction } from 'sequelize';
5
5
  /**
@@ -13,3 +13,11 @@ export declare const enqueueJob: (boss: PgBoss, queueName: string, data: object,
13
13
  * instead of calling internal SQL functions directly.
14
14
  */
15
15
  export declare const enqueueInTransaction: (boss: PgBoss, queueName: string, data: object, options: SendOptions, transaction: Transaction, sequelize: Sequelize) => Promise<string | null>;
16
+ /**
17
+ * Wrap a pg-boss worker handler so that, when the final retry attempt fails,
18
+ * a Mattermost DLQ alert is fired before the error is re-thrown.
19
+ *
20
+ * Requires the worker to be registered with `{ includeMetadata: true }` so
21
+ * `retryCount` and `retryLimit` are populated on each job.
22
+ */
23
+ export declare const withDlqAlerting: <T = object>(queueName: string, handler: (jobs: Job<T>[]) => Promise<void>, logger: Logger, mattermostWebhookUrl?: string) => ((jobs: Job<T>[]) => Promise<void>);
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.enqueueInTransaction = exports.enqueueJob = void 0;
3
+ exports.withDlqAlerting = exports.enqueueInTransaction = exports.enqueueJob = void 0;
4
+ const metrics_1 = require("./metrics");
4
5
  /**
5
6
  * Enqueue a job via pg-boss with logging.
6
7
  */
@@ -42,3 +43,29 @@ const enqueueInTransaction = async (boss, queueName, data, options, transaction,
42
43
  return boss.send(queueName, data, { ...options, db });
43
44
  };
44
45
  exports.enqueueInTransaction = enqueueInTransaction;
46
+ /**
47
+ * Wrap a pg-boss worker handler so that, when the final retry attempt fails,
48
+ * a Mattermost DLQ alert is fired before the error is re-thrown.
49
+ *
50
+ * Requires the worker to be registered with `{ includeMetadata: true }` so
51
+ * `retryCount` and `retryLimit` are populated on each job.
52
+ */
53
+ const withDlqAlerting = (queueName, handler, logger, mattermostWebhookUrl) => {
54
+ return async (jobs) => {
55
+ try {
56
+ await handler(jobs);
57
+ }
58
+ catch (error) {
59
+ const job = jobs[0];
60
+ const retryCount = job?.retryCount ?? 0;
61
+ const retryLimit = job?.retryLimit ?? 0;
62
+ const isFinalFailure = retryLimit > 0 && retryCount >= retryLimit;
63
+ if (isFinalFailure && mattermostWebhookUrl && job) {
64
+ const message = error instanceof Error ? error.message : String(error);
65
+ await (0, metrics_1.sendDlqAlert)(mattermostWebhookUrl, queueName, job.id, message, logger);
66
+ }
67
+ throw error;
68
+ }
69
+ };
70
+ };
71
+ exports.withDlqAlerting = withDlqAlerting;
@@ -2,28 +2,41 @@ import { PgBoss } from 'pg-boss';
2
2
  import type { Logger } from 'pino';
3
3
  import type { PgBossConfig } from './types';
4
4
  export { PgBoss };
5
+ export type { Job, SendOptions } from 'pg-boss';
5
6
  export type { PgBossConfig, QueueDefinition, WorkerRegistration, PgBossInstance, } from './types';
6
7
  export { PG_BOSS_DEFAULTS, buildPgBossDefaults } from './config';
7
8
  export { mountPgBossApiRoutes } from './controller/routes';
8
9
  export { PgBossService } from './service';
9
10
  export { registerPgBossMetrics } from './metrics';
10
- export { enqueueJob, enqueueInTransaction } from './helpers';
11
+ export { enqueueJob, enqueueInTransaction, withDlqAlerting } from './helpers';
11
12
  export { sendDlqAlert } from './metrics';
12
13
  export interface PgBossContext {
13
14
  boss: PgBoss;
14
15
  logger: Logger;
15
16
  config: Required<PgBossConfig>;
17
+ serviceName: string;
18
+ metricsInterval?: NodeJS.Timeout;
16
19
  }
17
20
  /**
18
21
  * Creates a pg-boss instance with error recovery (auto-restart on connection loss).
19
22
  * Issue #510 mitigation: on error, waits 5s then restarts.
20
23
  */
21
- export declare const createPgBoss: (config: PgBossConfig, logger: Logger) => PgBossContext;
24
+ export declare const createPgBoss: (config: PgBossConfig, logger: Logger, serviceName?: string) => PgBossContext;
22
25
  /**
23
- * Starts the pg-boss instance. Call after database is connected.
26
+ * Starts the pg-boss instance and registers Prometheus metrics polling.
27
+ * Call after database is connected.
24
28
  */
25
29
  export declare const startBoss: (ctx: PgBossContext) => Promise<void>;
26
30
  /**
27
- * Gracefully stops the pg-boss instance. Suitable as a shutdown handler.
31
+ * Gracefully stops the pg-boss instance and clears metrics polling.
32
+ * Suitable as a shutdown handler.
28
33
  */
29
34
  export declare const stopBoss: (ctx: PgBossContext) => Promise<void>;
35
+ /**
36
+ * Maps the legacy `deleteAfterDays` setting to pg-boss v12's
37
+ * per-queue `deleteAfterSeconds` option. Use this when calling
38
+ * `boss.createQueue(name, { ...defaultRetention(ctx), policy: 'singleton' })`.
39
+ */
40
+ export declare const defaultRetention: (ctx: PgBossContext) => {
41
+ deleteAfterSeconds: number;
42
+ };
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.stopBoss = exports.startBoss = exports.createPgBoss = exports.sendDlqAlert = exports.enqueueInTransaction = exports.enqueueJob = exports.registerPgBossMetrics = exports.PgBossService = exports.mountPgBossApiRoutes = exports.buildPgBossDefaults = exports.PG_BOSS_DEFAULTS = exports.PgBoss = void 0;
3
+ exports.defaultRetention = exports.stopBoss = exports.startBoss = exports.createPgBoss = exports.sendDlqAlert = exports.withDlqAlerting = exports.enqueueInTransaction = exports.enqueueJob = exports.registerPgBossMetrics = exports.PgBossService = exports.mountPgBossApiRoutes = exports.buildPgBossDefaults = exports.PG_BOSS_DEFAULTS = exports.PgBoss = void 0;
4
4
  const pg_boss_1 = require("pg-boss");
5
5
  Object.defineProperty(exports, "PgBoss", { enumerable: true, get: function () { return pg_boss_1.PgBoss; } });
6
6
  const config_1 = require("./config");
7
+ const metrics_1 = require("./metrics");
7
8
  var config_2 = require("./config");
8
9
  Object.defineProperty(exports, "PG_BOSS_DEFAULTS", { enumerable: true, get: function () { return config_2.PG_BOSS_DEFAULTS; } });
9
10
  Object.defineProperty(exports, "buildPgBossDefaults", { enumerable: true, get: function () { return config_2.buildPgBossDefaults; } });
@@ -11,24 +12,27 @@ var routes_1 = require("./controller/routes");
11
12
  Object.defineProperty(exports, "mountPgBossApiRoutes", { enumerable: true, get: function () { return routes_1.mountPgBossApiRoutes; } });
12
13
  var service_1 = require("./service");
13
14
  Object.defineProperty(exports, "PgBossService", { enumerable: true, get: function () { return service_1.PgBossService; } });
14
- var metrics_1 = require("./metrics");
15
- Object.defineProperty(exports, "registerPgBossMetrics", { enumerable: true, get: function () { return metrics_1.registerPgBossMetrics; } });
15
+ var metrics_2 = require("./metrics");
16
+ Object.defineProperty(exports, "registerPgBossMetrics", { enumerable: true, get: function () { return metrics_2.registerPgBossMetrics; } });
16
17
  var helpers_1 = require("./helpers");
17
18
  Object.defineProperty(exports, "enqueueJob", { enumerable: true, get: function () { return helpers_1.enqueueJob; } });
18
19
  Object.defineProperty(exports, "enqueueInTransaction", { enumerable: true, get: function () { return helpers_1.enqueueInTransaction; } });
19
- var metrics_2 = require("./metrics");
20
- Object.defineProperty(exports, "sendDlqAlert", { enumerable: true, get: function () { return metrics_2.sendDlqAlert; } });
20
+ Object.defineProperty(exports, "withDlqAlerting", { enumerable: true, get: function () { return helpers_1.withDlqAlerting; } });
21
+ var metrics_3 = require("./metrics");
22
+ Object.defineProperty(exports, "sendDlqAlert", { enumerable: true, get: function () { return metrics_3.sendDlqAlert; } });
21
23
  const RESTART_DELAY_MS = 5000;
24
+ const SECONDS_PER_DAY = 86_400;
22
25
  /**
23
26
  * Creates a pg-boss instance with error recovery (auto-restart on connection loss).
24
27
  * Issue #510 mitigation: on error, waits 5s then restarts.
25
28
  */
26
- const createPgBoss = (config, logger) => {
29
+ const createPgBoss = (config, logger, serviceName = config.schema) => {
27
30
  const resolvedConfig = (0, config_1.buildPgBossDefaults)(config);
28
31
  const boss = new pg_boss_1.PgBoss({
29
32
  connectionString: resolvedConfig.connectionString,
30
33
  schema: resolvedConfig.schema,
31
34
  application_name: resolvedConfig.applicationName,
35
+ max: resolvedConfig.maxConnectionPoolSize,
32
36
  migrate: true,
33
37
  });
34
38
  boss.on('error', (error) => {
@@ -38,27 +42,43 @@ const createPgBoss = (config, logger) => {
38
42
  boss.on('warning', warning => {
39
43
  logger.warn({ warning }, 'pg-boss warning');
40
44
  });
41
- return { boss, logger, config: resolvedConfig };
45
+ return { boss, logger, config: resolvedConfig, serviceName };
42
46
  };
43
47
  exports.createPgBoss = createPgBoss;
44
48
  /**
45
- * Starts the pg-boss instance. Call after database is connected.
49
+ * Starts the pg-boss instance and registers Prometheus metrics polling.
50
+ * Call after database is connected.
46
51
  */
47
52
  const startBoss = async (ctx) => {
48
53
  ctx.logger.info({ schema: ctx.config.schema }, 'Starting pg-boss');
49
54
  await ctx.boss.start();
55
+ ctx.metricsInterval = (0, metrics_1.registerPgBossMetrics)(ctx.boss, ctx.serviceName, ctx.logger, ctx.config.mattermostWebhookUrl || undefined);
50
56
  ctx.logger.info({ schema: ctx.config.schema }, 'pg-boss started successfully');
51
57
  };
52
58
  exports.startBoss = startBoss;
53
59
  /**
54
- * Gracefully stops the pg-boss instance. Suitable as a shutdown handler.
60
+ * Gracefully stops the pg-boss instance and clears metrics polling.
61
+ * Suitable as a shutdown handler.
55
62
  */
56
63
  const stopBoss = async (ctx) => {
57
64
  ctx.logger.info({ schema: ctx.config.schema }, 'Stopping pg-boss');
65
+ if (ctx.metricsInterval) {
66
+ clearInterval(ctx.metricsInterval);
67
+ ctx.metricsInterval = undefined;
68
+ }
58
69
  await ctx.boss.stop({ graceful: true, timeout: 30_000 });
59
70
  ctx.logger.info({ schema: ctx.config.schema }, 'pg-boss stopped');
60
71
  };
61
72
  exports.stopBoss = stopBoss;
73
+ /**
74
+ * Maps the legacy `deleteAfterDays` setting to pg-boss v12's
75
+ * per-queue `deleteAfterSeconds` option. Use this when calling
76
+ * `boss.createQueue(name, { ...defaultRetention(ctx), policy: 'singleton' })`.
77
+ */
78
+ const defaultRetention = (ctx) => ({
79
+ deleteAfterSeconds: ctx.config.deleteAfterDays * SECONDS_PER_DAY,
80
+ });
81
+ exports.defaultRetention = defaultRetention;
62
82
  const scheduleRestart = (boss, logger) => {
63
83
  setTimeout(async () => {
64
84
  try {
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
@@ -4,7 +4,7 @@ exports.manageJob = void 0;
4
4
  const manageJob = async (boss, logger, action, queueName, jobId) => {
5
5
  switch (action) {
6
6
  case 'retry':
7
- await boss.resume(queueName, jobId);
7
+ await boss.retry(queueName, jobId);
8
8
  break;
9
9
  case 'cancel':
10
10
  await boss.cancel(queueName, jobId);
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  Object.defineProperty(exports, "__esModule", { value: true });
26
36
  exports.normalizePhoneNumber = exports.getPhoneType = exports.getPhoneCountry = exports.parsePhone = exports.formatPhoneNumber = exports.tryParsePhoneNumber = exports.getFormattedPhoneNumber = exports.isValidMobilePhoneNumber = exports.isValidPhoneNumber = exports.OutputFormat = void 0;
27
37
  const max_1 = __importStar(require("libphonenumber-js/max"));
@@ -3,6 +3,7 @@ declare enum Service {
3
3
  BACKEND_PAY = "backend-pay",
4
4
  BACKEND_POS = "backend-pos",
5
5
  BACKEND_PUBSUB = "backend-pubsub",
6
+ BACKEND_TSE = "backend-tse",
6
7
  BACKEND_PYTHON = "backend-python",
7
8
  BACKEND_LINK = "backend-link",
8
9
  MASTRA = "mastra",
@@ -7,6 +7,7 @@ var Service;
7
7
  Service["BACKEND_PAY"] = "backend-pay";
8
8
  Service["BACKEND_POS"] = "backend-pos";
9
9
  Service["BACKEND_PUBSUB"] = "backend-pubsub";
10
+ Service["BACKEND_TSE"] = "backend-tse";
10
11
  Service["BACKEND_PYTHON"] = "backend-python";
11
12
  Service["BACKEND_LINK"] = "backend-link";
12
13
  Service["MASTRA"] = "mastra";
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucaapp/service-utils",
3
- "version": "5.8.0",
3
+ "version": "5.10.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [
@@ -15,7 +15,7 @@
15
15
  "test": "vitest run",
16
16
  "test:coverage": "vitest run --coverage",
17
17
  "test:ci": "VITEST_JUNIT_SUITE_NAME=service-utils CI=true vitest run --coverage",
18
- "audit": "sh ../../scripts/cached-audit.sh improved-yarn-audit --ignore-dev-deps"
18
+ "audit:osv": "yarn-osv-audit"
19
19
  },
20
20
  "dependencies": {
21
21
  "@apidevtools/swagger-parser": "10.0.3",
@@ -24,7 +24,7 @@
24
24
  "@aws-sdk/lib-storage": "^3.1035.0",
25
25
  "@hapi/boom": "^10.0.1",
26
26
  "@sentry/node": "^9.10.1",
27
- "@tsconfig/node22": "22.0.0",
27
+ "@tsconfig/node24": "24.0.0",
28
28
  "@types/express": "4.17.23",
29
29
  "@types/express-serve-static-core": "^4.17.43",
30
30
  "@types/node": "22.13.11",
@@ -74,12 +74,12 @@
74
74
  "eslint": "8.57.0",
75
75
  "eslint-plugin-prettier": "4.2.1",
76
76
  "eslint-plugin-vitest": "0.4.1",
77
- "improved-yarn-audit": "^3.0.4",
77
+ "yarn-osv-audit": "0.1.8",
78
78
  "prettier": "2.7.1",
79
79
  "semantic-release": "^25.0.3",
80
80
  "semantic-release-monorepo": "8.0.2",
81
- "supertest": "^6.3.3",
82
- "typescript": "5.5.3",
81
+ "supertest": "6.3.4",
82
+ "typescript": "6.0.2",
83
83
  "vite-tsconfig-paths": "4.3.2",
84
84
  "vitest": "4.1.1"
85
85
  },