@odunlamizo/node-river 1.0.5 → 1.0.6

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.
@@ -0,0 +1,54 @@
1
+ import { J as JobArgs, I as InsertOpts, a as InsertResult } from './insert-result-Bf0bAFvJ.js';
2
+
3
+ /**
4
+ * Common interface for all RiverQueue drivers (e.g., Postgres, Prisma, Sequelize, etc.).
5
+ * The generic parameter Tx must be set to the driver's transaction/session type.
6
+ */
7
+ interface Driver<Tx> {
8
+ /**
9
+ * Checks if the driver can connect to the database. Throws on failure.
10
+ */
11
+ verifyConnection(): Promise<void>;
12
+ /**
13
+ * Closes all database connections and cleans up resources.
14
+ */
15
+ close(): Promise<void>;
16
+ /**
17
+ * Inserts a new job into the queue using the provided arguments and options.
18
+ * @param args - The job arguments to insert.
19
+ * @param opts - Options for job insertion.
20
+ * @returns A promise that resolves to the result of the insertion operation,
21
+ * including the job and whether the insert was skipped due to uniqueness.
22
+ */
23
+ insert<T extends JobArgs>(args: T, opts: InsertOpts): Promise<InsertResult<T>>;
24
+ /**
25
+ * Inserts a new job into the queue within an existing transaction or session.
26
+ * The type of `tx` is driver-specific and should match the transaction/session type for the driver.
27
+ *
28
+ * @param tx - The transaction or session object to use for the insert.
29
+ * @param args - The job arguments to insert.
30
+ * @param opts - Options for job insertion.
31
+ * @returns A promise that resolves to the result of the insertion operation.
32
+ */
33
+ insertTx<T extends JobArgs>(tx: Tx, args: T, opts: InsertOpts): Promise<InsertResult<T>>;
34
+ /**
35
+ * Inserts multiple jobs in sequence within a single transaction.
36
+ * If any insert fails, all previous inserts in the batch are rolled back.
37
+ *
38
+ * @param jobs - Array of job argument and option pairs to insert.
39
+ * @returns Array of InsertResult objects for each job.
40
+ */
41
+ insertMany<T extends JobArgs>(jobs: {
42
+ args: T;
43
+ opts: InsertOpts;
44
+ }[]): Promise<InsertResult<T>[]>;
45
+ /**
46
+ * Starts and returns a new transaction or session object for the driver.
47
+ * The returned object should be used for transactional operations such as insertTx.
48
+ *
49
+ * @returns A promise that resolves to the driver's transaction/session object.
50
+ */
51
+ getTx(): Promise<Tx>;
52
+ }
53
+
54
+ export type { Driver as D };
@@ -0,0 +1,54 @@
1
+ import { J as JobArgs, I as InsertOpts, a as InsertResult } from './insert-result-Bf0bAFvJ.cjs';
2
+
3
+ /**
4
+ * Common interface for all RiverQueue drivers (e.g., Postgres, Prisma, Sequelize, etc.).
5
+ * The generic parameter Tx must be set to the driver's transaction/session type.
6
+ */
7
+ interface Driver<Tx> {
8
+ /**
9
+ * Checks if the driver can connect to the database. Throws on failure.
10
+ */
11
+ verifyConnection(): Promise<void>;
12
+ /**
13
+ * Closes all database connections and cleans up resources.
14
+ */
15
+ close(): Promise<void>;
16
+ /**
17
+ * Inserts a new job into the queue using the provided arguments and options.
18
+ * @param args - The job arguments to insert.
19
+ * @param opts - Options for job insertion.
20
+ * @returns A promise that resolves to the result of the insertion operation,
21
+ * including the job and whether the insert was skipped due to uniqueness.
22
+ */
23
+ insert<T extends JobArgs>(args: T, opts: InsertOpts): Promise<InsertResult<T>>;
24
+ /**
25
+ * Inserts a new job into the queue within an existing transaction or session.
26
+ * The type of `tx` is driver-specific and should match the transaction/session type for the driver.
27
+ *
28
+ * @param tx - The transaction or session object to use for the insert.
29
+ * @param args - The job arguments to insert.
30
+ * @param opts - Options for job insertion.
31
+ * @returns A promise that resolves to the result of the insertion operation.
32
+ */
33
+ insertTx<T extends JobArgs>(tx: Tx, args: T, opts: InsertOpts): Promise<InsertResult<T>>;
34
+ /**
35
+ * Inserts multiple jobs in sequence within a single transaction.
36
+ * If any insert fails, all previous inserts in the batch are rolled back.
37
+ *
38
+ * @param jobs - Array of job argument and option pairs to insert.
39
+ * @returns Array of InsertResult objects for each job.
40
+ */
41
+ insertMany<T extends JobArgs>(jobs: {
42
+ args: T;
43
+ opts: InsertOpts;
44
+ }[]): Promise<InsertResult<T>[]>;
45
+ /**
46
+ * Starts and returns a new transaction or session object for the driver.
47
+ * The returned object should be used for transactional operations such as insertTx.
48
+ *
49
+ * @returns A promise that resolves to the driver's transaction/session object.
50
+ */
51
+ getTx(): Promise<Tx>;
52
+ }
53
+
54
+ export type { Driver as D };
@@ -0,0 +1,224 @@
1
+ 'use strict';
2
+
3
+ var pg = require('pg');
4
+ var buffer = require('buffer');
5
+ var crypto = require('crypto');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var crypto__default = /*#__PURE__*/_interopDefault(crypto);
10
+
11
+ // src/drivers/pg/pg-driver.ts
12
+ var bitmaskToJobStates = (bitmask) => {
13
+ if (!bitmask || bitmask.length === 0) return null;
14
+ const allStates = [
15
+ "available" /* Available */,
16
+ // 7
17
+ "cancelled" /* Cancelled */,
18
+ // 6
19
+ "completed" /* Completed */,
20
+ // 5
21
+ "discarded" /* Discarded */,
22
+ // 4
23
+ "pending" /* Pending */,
24
+ // 3
25
+ "retryable" /* Retryable */,
26
+ // 2
27
+ "running" /* Running */,
28
+ // 1
29
+ "scheduled" /* Scheduled */
30
+ // 0
31
+ ];
32
+ const byte = bitmask[0];
33
+ return allStates.filter((_, i) => (byte & 1 << 7 - i) !== 0);
34
+ };
35
+ var mapToUniqueKey = (args, opts) => {
36
+ const uniqueOpts = opts.uniqueOpts;
37
+ if (!uniqueOpts) return void 0;
38
+ const keyParts = {};
39
+ if (!uniqueOpts.excludeKind) {
40
+ keyParts.kind = args.kind;
41
+ }
42
+ if (uniqueOpts.byArgs === true) {
43
+ keyParts.args = args;
44
+ } else if (Array.isArray(uniqueOpts.byArgs)) {
45
+ keyParts.args = Object.fromEntries(uniqueOpts.byArgs.sort().map((k) => [k, args[k]]));
46
+ }
47
+ if (uniqueOpts.byQueue) {
48
+ keyParts.queue = opts.queue;
49
+ }
50
+ if (uniqueOpts.byPeriod && opts.scheduledAt) {
51
+ const date = new Date(opts.scheduledAt);
52
+ const period = uniqueOpts.byPeriod;
53
+ const timestamp = Math.floor(date.getTime() / 1e3);
54
+ const rounded = timestamp - timestamp % period;
55
+ keyParts.period = rounded;
56
+ }
57
+ const hash = crypto__default.default.createHash("sha256").update(JSON.stringify(keyParts)).digest();
58
+ return buffer.Buffer.from(hash);
59
+ };
60
+
61
+ // src/drivers/pg/pg-driver.ts
62
+ var PgDriver = class {
63
+ /**
64
+ * Creates a new PgDriver instance.
65
+ * @param options - Options for configuring the RiverQueue pg driver connection pool. Fields include:
66
+ * - connectionString: Database connection string
67
+ * - connectionTimeoutMillis: Optional, connection timeout in milliseconds
68
+ * - idleTimeoutMillis: Optional, idle timeout in milliseconds
69
+ * - max: Optional, maximum number of clients in the pool
70
+ */
71
+ constructor(options) {
72
+ const config = { ...options };
73
+ this.pool = new pg.Pool(config);
74
+ }
75
+ async verifyConnection() {
76
+ try {
77
+ const client = await this.pool.connect();
78
+ try {
79
+ await client.query("SELECT 1");
80
+ } finally {
81
+ client.release();
82
+ }
83
+ } catch (error) {
84
+ throw new Error(
85
+ `Database connection failed: ${error instanceof Error ? error.message : String(error)}`
86
+ );
87
+ }
88
+ }
89
+ async close() {
90
+ await this.pool.end();
91
+ }
92
+ async insert(args, opts) {
93
+ const client = await this.pool.connect();
94
+ try {
95
+ return await this.insertTx(client, args, opts);
96
+ } finally {
97
+ client.release();
98
+ }
99
+ }
100
+ async insertTx(tx, args, opts) {
101
+ if (!opts.queue) {
102
+ throw new Error("Queue name is required in InsertOpts");
103
+ }
104
+ if (!opts.maxAttempts) {
105
+ throw new Error("maxAttempts is required in InsertOpts");
106
+ }
107
+ let uniqueKey;
108
+ if (opts.uniqueOpts) {
109
+ uniqueKey = mapToUniqueKey(args, opts);
110
+ }
111
+ if (uniqueKey) {
112
+ const stateList = opts.uniqueOpts?.byState || [];
113
+ let query2 = "SELECT * FROM river_job WHERE unique_key = $1";
114
+ let values2 = [uniqueKey];
115
+ if (stateList.length > 0) {
116
+ query2 += " AND state = ANY($2)";
117
+ values2.push(stateList);
118
+ }
119
+ query2 += " LIMIT 1";
120
+ const result2 = await tx.query(
121
+ query2,
122
+ values2
123
+ );
124
+ if (result2.rows.length > 0) {
125
+ const row2 = result2.rows[0];
126
+ return this.mapRowToInsertResult(row2, true);
127
+ }
128
+ }
129
+ const { kind, ...restArgs } = args;
130
+ const columns = ["kind", "args", "queue", "max_attempts"];
131
+ const values = [
132
+ kind,
133
+ JSON.stringify(restArgs),
134
+ opts.queue,
135
+ opts.maxAttempts
136
+ ];
137
+ if (opts.tags) {
138
+ columns.push("tags");
139
+ values.push(JSON.stringify(opts.tags));
140
+ }
141
+ if (opts.priority) {
142
+ columns.push("priority");
143
+ values.push(opts.priority);
144
+ }
145
+ if (opts.metadata) {
146
+ columns.push("metadata");
147
+ values.push(JSON.stringify(opts.metadata));
148
+ }
149
+ if (opts.scheduledAt) {
150
+ columns.push("scheduled_at");
151
+ values.push(
152
+ opts.scheduledAt instanceof Date ? opts.scheduledAt.toISOString() : opts.scheduledAt
153
+ );
154
+ }
155
+ if (uniqueKey) {
156
+ columns.push("unique_key");
157
+ values.push(uniqueKey);
158
+ }
159
+ const placeholders = columns.map((_, i) => `$${i + 1}`);
160
+ const query = `INSERT INTO river_job (${columns.join(", ")}) VALUES (${placeholders.join(", ")}) RETURNING
161
+ id,
162
+ state,
163
+ attempt,
164
+ max_attempts as "maxAttempts",
165
+ attempted_at as "attemptedAt",
166
+ created_at as "createdAt",
167
+ finalized_at as "finalizedAt",
168
+ scheduled_at as "scheduledAt",
169
+ priority,
170
+ args,
171
+ attempted_by as "attemptedBy",
172
+ errors,
173
+ kind,
174
+ metadata,
175
+ queue,
176
+ tags,
177
+ unique_key as "uniqueKey",
178
+ unique_states as "uniqueStates"`;
179
+ const result = await tx.query(
180
+ query,
181
+ values
182
+ );
183
+ const row = result.rows[0];
184
+ if (!row) return row;
185
+ return this.mapRowToInsertResult(row, false);
186
+ }
187
+ async insertMany(jobs) {
188
+ const client = await this.pool.connect();
189
+ try {
190
+ await client.query("BEGIN");
191
+ const results = [];
192
+ for (const job of jobs) {
193
+ results.push(await this.insertTx(client, job.args, job.opts));
194
+ }
195
+ await client.query("COMMIT");
196
+ return results;
197
+ } catch (error) {
198
+ await client.query("ROLLBACK");
199
+ throw error;
200
+ } finally {
201
+ client.release();
202
+ }
203
+ }
204
+ async getTx() {
205
+ return this.pool.connect();
206
+ }
207
+ /**
208
+ * Helper to map a DB row to a Job<T> and InsertResult.
209
+ */
210
+ mapRowToInsertResult(row, skipped) {
211
+ return {
212
+ job: {
213
+ ...row,
214
+ args: { ...row.args, kind: row.kind },
215
+ uniqueStates: bitmaskToJobStates(row.uniqueStates)
216
+ },
217
+ skipped
218
+ };
219
+ }
220
+ };
221
+
222
+ exports.PgDriver = PgDriver;
223
+ //# sourceMappingURL=index.cjs.map
224
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/utils/mappers.ts","../../../src/drivers/pg/pg-driver.ts"],"names":["crypto","Buffer","Pool","query","values","result","row"],"mappings":";;;;;;;;;;;AAUO,IAAM,kBAAA,GAAqB,CAAC,OAAA,KAA8C;AAC/E,EAAA,IAAI,CAAC,OAAA,IAAW,OAAA,CAAQ,MAAA,KAAW,GAAG,OAAO,IAAA;AAE7C,EAAA,MAAM,SAAA,GAAwB;AAAA,IAAA,WAAA;AAAA;AAAA,IAAA,WAAA;AAAA;AAAA,IAAA,WAAA;AAAA;AAAA,IAAA,WAAA;AAAA;AAAA,IAAA,SAAA;AAAA;AAAA,IAAA,WAAA;AAAA;AAAA,IAAA,SAAA;AAAA;AAAA,IAAA,WAAA;AAAA;AAAA,GAS9B;AACA,EAAA,MAAM,IAAA,GAAO,QAAQ,CAAC,CAAA;AAEtB,EAAA,OAAO,SAAA,CAAU,OAAO,CAAC,CAAA,EAAG,OAAO,IAAA,GAAQ,CAAA,IAAM,CAAA,GAAI,CAAA,MAAS,CAAC,CAAA;AACjE,CAAA;AASO,IAAM,cAAA,GAAiB,CAAC,IAAA,EAAe,IAAA,KAAyC;AACrF,EAAA,MAAM,aAAa,IAAA,CAAK,UAAA;AACxB,EAAA,IAAI,CAAC,YAAY,OAAO,MAAA;AAExB,EAAA,MAAM,WAAoC,EAAC;AAE3C,EAAA,IAAI,CAAC,WAAW,WAAA,EAAa;AAC3B,IAAA,QAAA,CAAS,OAAO,IAAA,CAAK,IAAA;AAAA,EACvB;AAEA,EAAA,IAAI,UAAA,CAAW,WAAW,IAAA,EAAM;AAC9B,IAAA,QAAA,CAAS,IAAA,GAAO,IAAA;AAAA,EAClB,CAAA,MAAA,IAAW,KAAA,CAAM,OAAA,CAAQ,UAAA,CAAW,MAAM,CAAA,EAAG;AAC3C,IAAA,QAAA,CAAS,OAAO,MAAA,CAAO,WAAA,CAAY,UAAA,CAAW,MAAA,CAAO,MAAK,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,EAAG,IAAA,CAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AAAA,EACtF;AAEA,EAAA,IAAI,WAAW,OAAA,EAAS;AACtB,IAAA,QAAA,CAAS,QAAQ,IAAA,CAAK,KAAA;AAAA,EACxB;AAEA,EAAA,IAAI,UAAA,CAAW,QAAA,IAAY,IAAA,CAAK,WAAA,EAAa;AAC3C,IAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,IAAA,CAAK,WAAW,CAAA;AACtC,IAAA,MAAM,SAAS,UAAA,CAAW,QAAA;AAC1B,IAAA,MAAM,YAAY,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,OAAA,KAAY,GAAI,CAAA;AAClD,IAAA,MAAM,OAAA,GAAU,YAAa,SAAA,GAAY,MAAA;AACzC,IAAA,QAAA,CAAS,MAAA,GAAS,OAAA;AAAA,EACpB;AAEA,EAAA,MAAM,IAAA,GAAOA,uBAAA,CAAO,UAAA,CAAW,QAAQ,CAAA,CAAE,MAAA,CAAO,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAC,CAAA,CAAE,MAAA,EAAO;AAEjF,EAAA,OAAOC,aAAA,CAAO,KAAK,IAAI,CAAA;AACzB,CAAA;;;ACzDA,IAAqB,WAArB,MAA4D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW1D,YAAY,OAAA,EAAkB;AAC5B,IAAA,MAAM,MAAA,GAAqB,EAAE,GAAG,OAAA,EAAQ;AACxC,IAAA,IAAA,CAAK,IAAA,GAAO,IAAIC,OAAA,CAAK,MAAM,CAAA;AAAA,EAC7B;AAAA,EAEA,MAAM,gBAAA,GAAkC;AACtC,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,IAAA,CAAK,OAAA,EAAQ;AACvC,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,CAAO,MAAM,UAAU,CAAA;AAAA,MAC/B,CAAA,SAAE;AACA,QAAA,MAAA,CAAO,OAAA,EAAQ;AAAA,MACjB;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,+BAA+B,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,OACvF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,KAAA,GAAuB;AAC3B,IAAA,MAAM,IAAA,CAAK,KAAK,GAAA,EAAI;AAAA,EACtB;AAAA,EAEA,MAAM,MAAA,CAA0B,IAAA,EAAS,IAAA,EAA4C;AACnF,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,IAAA,CAAK,OAAA,EAAQ;AACvC,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,IAAA,CAAK,QAAA,CAAS,MAAA,EAAQ,MAAM,IAAI,CAAA;AAAA,IAC/C,CAAA,SAAE;AACA,MAAA,MAAA,CAAO,OAAA,EAAQ;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,QAAA,CACJ,EAAA,EACA,IAAA,EACA,IAAA,EAC0B;AAC1B,IAAA,IAAI,CAAC,KAAK,KAAA,EAAO;AACf,MAAA,MAAM,IAAI,MAAM,sCAAsC,CAAA;AAAA,IACxD;AAEA,IAAA,IAAI,CAAC,KAAK,WAAA,EAAa;AACrB,MAAA,MAAM,IAAI,MAAM,uCAAuC,CAAA;AAAA,IACzD;AAEA,IAAA,IAAI,SAAA;AACJ,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA,SAAA,GAAY,cAAA,CAAe,MAAM,IAAI,CAAA;AAAA,IACvC;AAEA,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,UAAA,EAAY,OAAA,IAAW,EAAC;AAE/C,MAAA,IAAIC,MAAAA,GAAQ,+CAAA;AACZ,MAAA,IAAIC,OAAAA,GAAgC,CAAC,SAAS,CAAA;AAE9C,MAAA,IAAI,SAAA,CAAU,SAAS,CAAA,EAAG;AACxB,QAAAD,MAAAA,IAAS,sBAAA;AACT,QAAAC,OAAAA,CAAO,KAAK,SAAS,CAAA;AAAA,MACvB;AAEA,MAAAD,MAAAA,IAAS,UAAA;AAET,MAAA,MAAME,OAAAA,GAAS,MAAM,EAAA,CAAG,KAAA;AAAA,QACtBF,MAAAA;AAAA,QACAC;AAAA,OACF;AAEA,MAAA,IAAIC,OAAAA,CAAO,IAAA,CAAK,MAAA,GAAS,CAAA,EAAG;AAC1B,QAAA,MAAMC,IAAAA,GAAMD,OAAAA,CAAO,IAAA,CAAK,CAAC,CAAA;AAEzB,QAAA,OAAO,IAAA,CAAK,oBAAA,CAAqBC,IAAAA,EAAK,IAAI,CAAA;AAAA,MAC5C;AAAA,IACF;AAEA,IAAA,MAAM,EAAE,IAAA,EAAM,GAAG,QAAA,EAAS,GAAI,IAAA;AAC9B,IAAA,MAAM,OAAA,GAAU,CAAC,MAAA,EAAQ,MAAA,EAAQ,SAAS,cAAc,CAAA;AACxD,IAAA,MAAM,MAAA,GAAuC;AAAA,MAC3C,IAAA;AAAA,MACA,IAAA,CAAK,UAAU,QAAQ,CAAA;AAAA,MACvB,IAAA,CAAK,KAAA;AAAA,MACL,IAAA,CAAK;AAAA,KACP;AAEA,IAAA,IAAI,KAAK,IAAA,EAAM;AACb,MAAA,OAAA,CAAQ,KAAK,MAAM,CAAA;AACnB,MAAA,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,IACvC;AAEA,IAAA,IAAI,KAAK,QAAA,EAAU;AACjB,MAAA,OAAA,CAAQ,KAAK,UAAU,CAAA;AACvB,MAAA,MAAA,CAAO,IAAA,CAAK,KAAK,QAAQ,CAAA;AAAA,IAC3B;AAEA,IAAA,IAAI,KAAK,QAAA,EAAU;AACjB,MAAA,OAAA,CAAQ,KAAK,UAAU,CAAA;AACvB,MAAA,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,QAAQ,CAAC,CAAA;AAAA,IAC3C;AAEA,IAAA,IAAI,KAAK,WAAA,EAAa;AACpB,MAAA,OAAA,CAAQ,KAAK,cAAc,CAAA;AAC3B,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,KAAK,WAAA,YAAuB,IAAA,GAAO,KAAK,WAAA,CAAY,WAAA,KAAgB,IAAA,CAAK;AAAA,OAC3E;AAAA,IACF;AAEA,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,OAAA,CAAQ,KAAK,YAAY,CAAA;AACzB,MAAA,MAAA,CAAO,KAAK,SAAS,CAAA;AAAA,IACvB;AAEA,IAAA,MAAM,YAAA,GAAe,QAAQ,GAAA,CAAI,CAAC,GAAG,CAAA,KAAM,CAAA,CAAA,EAAI,CAAA,GAAI,CAAC,CAAA,CAAE,CAAA;AACtD,IAAA,MAAM,KAAA,GAAQ,CAAA,uBAAA,EAA0B,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA,UAAA,EAAa,YAAA,CAAa,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qCAAA,CAAA;AAmB9F,IAAA,MAAM,MAAA,GAAS,MAAM,EAAA,CAAG,KAAA;AAAA,MACtB,KAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA;AACzB,IAAA,IAAI,CAAC,KAAK,OAAO,GAAA;AAEjB,IAAA,OAAO,IAAA,CAAK,oBAAA,CAAqB,GAAA,EAAK,KAAK,CAAA;AAAA,EAC7C;AAAA,EAEA,MAAM,WACJ,IAAA,EAC4B;AAC5B,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,IAAA,CAAK,OAAA,EAAQ;AACvC,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,CAAO,MAAM,OAAO,CAAA;AAE1B,MAAA,MAAM,UAA6B,EAAC;AACpC,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,QAAA,OAAA,CAAQ,IAAA,CAAK,MAAM,IAAA,CAAK,QAAA,CAAS,QAAQ,GAAA,CAAI,IAAA,EAAM,GAAA,CAAI,IAAI,CAAC,CAAA;AAAA,MAC9D;AAEA,MAAA,MAAM,MAAA,CAAO,MAAM,QAAQ,CAAA;AAE3B,MAAA,OAAO,OAAA;AAAA,IACT,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,MAAA,CAAO,MAAM,UAAU,CAAA;AAE7B,MAAA,MAAM,KAAA;AAAA,IACR,CAAA,SAAE;AACA,MAAA,MAAA,CAAO,OAAA,EAAQ;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,KAAA,GAA6B;AACjC,IAAA,OAAO,IAAA,CAAK,KAAK,OAAA,EAAQ;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAA,CACN,KACA,OAAA,EACiB;AACjB,IAAA,OAAO;AAAA,MACL,GAAA,EAAK;AAAA,QACH,GAAG,GAAA;AAAA,QACH,MAAM,EAAE,GAAG,IAAI,IAAA,EAAM,IAAA,EAAM,IAAI,IAAA,EAAK;AAAA,QACpC,YAAA,EAAc,kBAAA,CAAmB,GAAA,CAAI,YAAY;AAAA,OACnD;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACF","file":"index.cjs","sourcesContent":["import { Buffer } from 'buffer';\nimport crypto from 'crypto';\nimport { InsertOpts, JobArgs, JobState } from '../types';\n\n/**\n * Converts a bit(8) Buffer to an array of JobState values using the bit order from river_job_state_in_bitmask.\n *\n * @param bitmask - The Buffer representing the job state bitmask.\n * @returns An array of JobState values corresponding to the set bits, or null if the bitmask is null.\n */\nexport const bitmaskToJobStates = (bitmask: Buffer | null): JobState[] | null => {\n if (!bitmask || bitmask.length === 0) return null;\n // Bit order: 7=available, 6=cancelled, 5=completed, 4=discarded, 3=pending, 2=retryable, 1=running, 0=scheduled\n const allStates: JobState[] = [\n JobState.Available, // 7\n JobState.Cancelled, // 6\n JobState.Completed, // 5\n JobState.Discarded, // 4\n JobState.Pending, // 3\n JobState.Retryable, // 2\n JobState.Running, // 1\n JobState.Scheduled, // 0\n ];\n const byte = bitmask[0];\n // Map bits 7..0 to allStates\n return allStates.filter((_, i) => (byte & (1 << (7 - i))) !== 0);\n};\n\n/**\n * Maps job args and unique options to a unique key buffer.\n *\n * @param args - The job arguments to use for uniqueness computation.\n * @param opts - The insertion options, including unique options.\n * @returns A Buffer containing the unique key, or undefined if no unique options are set.\n */\nexport const mapToUniqueKey = (args: JobArgs, opts: InsertOpts): Buffer | undefined => {\n const uniqueOpts = opts.uniqueOpts;\n if (!uniqueOpts) return undefined;\n\n const keyParts: Record<string, unknown> = {};\n\n if (!uniqueOpts.excludeKind) {\n keyParts.kind = args.kind;\n }\n\n if (uniqueOpts.byArgs === true) {\n keyParts.args = args;\n } else if (Array.isArray(uniqueOpts.byArgs)) {\n keyParts.args = Object.fromEntries(uniqueOpts.byArgs.sort().map((k) => [k, args[k]]));\n }\n\n if (uniqueOpts.byQueue) {\n keyParts.queue = opts.queue;\n }\n\n if (uniqueOpts.byPeriod && opts.scheduledAt) {\n const date = new Date(opts.scheduledAt);\n const period = uniqueOpts.byPeriod;\n const timestamp = Math.floor(date.getTime() / 1000);\n const rounded = timestamp - (timestamp % period);\n keyParts.period = rounded;\n }\n\n const hash = crypto.createHash('sha256').update(JSON.stringify(keyParts)).digest();\n\n return Buffer.from(hash);\n};\n","// RiverQueue driver implementation using the 'pg' library.\nimport { Buffer } from 'buffer';\nimport { Pool, PoolClient, PoolConfig } from 'pg';\nimport { InsertOpts, InsertResult, Job, JobArgs } from '../../types';\nimport { bitmaskToJobStates, mapToUniqueKey } from '../../utils';\nimport Driver from '../driver';\nimport Options from './pg-options';\n\n// Implements the RiverQueue Driver interface using the 'pg' library.\nexport default class PgDriver implements Driver<PoolClient> {\n private readonly pool: Pool;\n\n /**\n * Creates a new PgDriver instance.\n * @param options - Options for configuring the RiverQueue pg driver connection pool. Fields include:\n * - connectionString: Database connection string\n * - connectionTimeoutMillis: Optional, connection timeout in milliseconds\n * - idleTimeoutMillis: Optional, idle timeout in milliseconds\n * - max: Optional, maximum number of clients in the pool\n */\n constructor(options: Options) {\n const config: PoolConfig = { ...options };\n this.pool = new Pool(config);\n }\n\n async verifyConnection(): Promise<void> {\n try {\n const client = await this.pool.connect();\n try {\n await client.query('SELECT 1');\n } finally {\n client.release();\n }\n } catch (error) {\n throw new Error(\n `Database connection failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n async close(): Promise<void> {\n await this.pool.end();\n }\n\n async insert<T extends JobArgs>(args: T, opts: InsertOpts): Promise<InsertResult<T>> {\n const client = await this.pool.connect();\n try {\n return await this.insertTx(client, args, opts);\n } finally {\n client.release();\n }\n }\n\n async insertTx<T extends JobArgs>(\n tx: PoolClient,\n args: T,\n opts: InsertOpts,\n ): Promise<InsertResult<T>> {\n if (!opts.queue) {\n throw new Error('Queue name is required in InsertOpts');\n }\n\n if (!opts.maxAttempts) {\n throw new Error('maxAttempts is required in InsertOpts');\n }\n\n let uniqueKey: Buffer | undefined;\n if (opts.uniqueOpts) {\n uniqueKey = mapToUniqueKey(args, opts);\n }\n\n if (uniqueKey) {\n const stateList = opts.uniqueOpts?.byState || [];\n\n let query = 'SELECT * FROM river_job WHERE unique_key = $1';\n let values: (Buffer | string[])[] = [uniqueKey];\n\n if (stateList.length > 0) {\n query += ' AND state = ANY($2)';\n values.push(stateList);\n }\n\n query += ' LIMIT 1';\n\n const result = await tx.query<Omit<Job, 'uniqueStates'> & { uniqueStates: Buffer | null }>(\n query,\n values,\n );\n\n if (result.rows.length > 0) {\n const row = result.rows[0];\n\n return this.mapRowToInsertResult(row, true);\n }\n }\n\n const { kind, ...restArgs } = args;\n const columns = ['kind', 'args', 'queue', 'max_attempts'];\n const values: (string | number | Buffer)[] = [\n kind,\n JSON.stringify(restArgs),\n opts.queue,\n opts.maxAttempts,\n ];\n\n if (opts.tags) {\n columns.push('tags');\n values.push(JSON.stringify(opts.tags));\n }\n\n if (opts.priority) {\n columns.push('priority');\n values.push(opts.priority);\n }\n\n if (opts.metadata) {\n columns.push('metadata');\n values.push(JSON.stringify(opts.metadata));\n }\n\n if (opts.scheduledAt) {\n columns.push('scheduled_at');\n values.push(\n opts.scheduledAt instanceof Date ? opts.scheduledAt.toISOString() : opts.scheduledAt,\n );\n }\n\n if (uniqueKey) {\n columns.push('unique_key');\n values.push(uniqueKey);\n }\n\n const placeholders = columns.map((_, i) => `$${i + 1}`);\n const query = `INSERT INTO river_job (${columns.join(', ')}) VALUES (${placeholders.join(', ')}) RETURNING\n id,\n state,\n attempt,\n max_attempts as \"maxAttempts\",\n attempted_at as \"attemptedAt\",\n created_at as \"createdAt\",\n finalized_at as \"finalizedAt\",\n scheduled_at as \"scheduledAt\",\n priority,\n args,\n attempted_by as \"attemptedBy\",\n errors,\n kind,\n metadata,\n queue,\n tags,\n unique_key as \"uniqueKey\",\n unique_states as \"uniqueStates\"`;\n const result = await tx.query<Omit<Job, 'uniqueStates'> & { uniqueStates: Buffer | null }>(\n query,\n values,\n );\n\n const row = result.rows[0];\n if (!row) return row;\n\n return this.mapRowToInsertResult(row, false);\n }\n\n async insertMany<T extends JobArgs>(\n jobs: { args: T; opts: InsertOpts }[],\n ): Promise<InsertResult<T>[]> {\n const client = await this.pool.connect();\n try {\n await client.query('BEGIN');\n\n const results: InsertResult<T>[] = [];\n for (const job of jobs) {\n results.push(await this.insertTx(client, job.args, job.opts));\n }\n\n await client.query('COMMIT');\n\n return results;\n } catch (error) {\n await client.query('ROLLBACK');\n\n throw error;\n } finally {\n client.release();\n }\n }\n\n async getTx(): Promise<PoolClient> {\n return this.pool.connect();\n }\n\n /**\n * Helper to map a DB row to a Job<T> and InsertResult.\n */\n private mapRowToInsertResult<T extends JobArgs>(\n row: Omit<Job, 'uniqueStates'> & { uniqueStates: Buffer | null },\n skipped: boolean,\n ): InsertResult<T> {\n return {\n job: {\n ...row,\n args: { ...row.args, kind: row.kind } as T,\n uniqueStates: bitmaskToJobStates(row.uniqueStates),\n },\n skipped,\n };\n }\n}\n"]}
@@ -0,0 +1,46 @@
1
+ import { PoolClient } from 'pg';
2
+ import { J as JobArgs, I as InsertOpts, a as InsertResult } from '../../insert-result-Bf0bAFvJ.cjs';
3
+ import { D as Driver } from '../../driver-vSyPLsFq.cjs';
4
+ import 'buffer';
5
+
6
+ /**
7
+ * Options for configuring the RiverQueue pg driver connection pool.
8
+ */
9
+ interface PgDriverOptions {
10
+ /** Database connection string */
11
+ connectionString: string;
12
+ /** Optional: Connection timeout in milliseconds */
13
+ connectionTimeoutMillis?: number;
14
+ /** Optional: Idle timeout in milliseconds */
15
+ idleTimeoutMillis?: number;
16
+ /** Optional: Maximum number of clients in the pool */
17
+ max?: number;
18
+ }
19
+
20
+ declare class PgDriver implements Driver<PoolClient> {
21
+ private readonly pool;
22
+ /**
23
+ * Creates a new PgDriver instance.
24
+ * @param options - Options for configuring the RiverQueue pg driver connection pool. Fields include:
25
+ * - connectionString: Database connection string
26
+ * - connectionTimeoutMillis: Optional, connection timeout in milliseconds
27
+ * - idleTimeoutMillis: Optional, idle timeout in milliseconds
28
+ * - max: Optional, maximum number of clients in the pool
29
+ */
30
+ constructor(options: PgDriverOptions);
31
+ verifyConnection(): Promise<void>;
32
+ close(): Promise<void>;
33
+ insert<T extends JobArgs>(args: T, opts: InsertOpts): Promise<InsertResult<T>>;
34
+ insertTx<T extends JobArgs>(tx: PoolClient, args: T, opts: InsertOpts): Promise<InsertResult<T>>;
35
+ insertMany<T extends JobArgs>(jobs: {
36
+ args: T;
37
+ opts: InsertOpts;
38
+ }[]): Promise<InsertResult<T>[]>;
39
+ getTx(): Promise<PoolClient>;
40
+ /**
41
+ * Helper to map a DB row to a Job<T> and InsertResult.
42
+ */
43
+ private mapRowToInsertResult;
44
+ }
45
+
46
+ export { PgDriver, type PgDriverOptions };
@@ -0,0 +1,46 @@
1
+ import { PoolClient } from 'pg';
2
+ import { J as JobArgs, I as InsertOpts, a as InsertResult } from '../../insert-result-Bf0bAFvJ.js';
3
+ import { D as Driver } from '../../driver-okKFbSrB.js';
4
+ import 'buffer';
5
+
6
+ /**
7
+ * Options for configuring the RiverQueue pg driver connection pool.
8
+ */
9
+ interface PgDriverOptions {
10
+ /** Database connection string */
11
+ connectionString: string;
12
+ /** Optional: Connection timeout in milliseconds */
13
+ connectionTimeoutMillis?: number;
14
+ /** Optional: Idle timeout in milliseconds */
15
+ idleTimeoutMillis?: number;
16
+ /** Optional: Maximum number of clients in the pool */
17
+ max?: number;
18
+ }
19
+
20
+ declare class PgDriver implements Driver<PoolClient> {
21
+ private readonly pool;
22
+ /**
23
+ * Creates a new PgDriver instance.
24
+ * @param options - Options for configuring the RiverQueue pg driver connection pool. Fields include:
25
+ * - connectionString: Database connection string
26
+ * - connectionTimeoutMillis: Optional, connection timeout in milliseconds
27
+ * - idleTimeoutMillis: Optional, idle timeout in milliseconds
28
+ * - max: Optional, maximum number of clients in the pool
29
+ */
30
+ constructor(options: PgDriverOptions);
31
+ verifyConnection(): Promise<void>;
32
+ close(): Promise<void>;
33
+ insert<T extends JobArgs>(args: T, opts: InsertOpts): Promise<InsertResult<T>>;
34
+ insertTx<T extends JobArgs>(tx: PoolClient, args: T, opts: InsertOpts): Promise<InsertResult<T>>;
35
+ insertMany<T extends JobArgs>(jobs: {
36
+ args: T;
37
+ opts: InsertOpts;
38
+ }[]): Promise<InsertResult<T>[]>;
39
+ getTx(): Promise<PoolClient>;
40
+ /**
41
+ * Helper to map a DB row to a Job<T> and InsertResult.
42
+ */
43
+ private mapRowToInsertResult;
44
+ }
45
+
46
+ export { PgDriver, type PgDriverOptions };
@@ -0,0 +1,218 @@
1
+ import { Pool } from 'pg';
2
+ import { Buffer } from 'buffer';
3
+ import crypto from 'crypto';
4
+
5
+ // src/drivers/pg/pg-driver.ts
6
+ var bitmaskToJobStates = (bitmask) => {
7
+ if (!bitmask || bitmask.length === 0) return null;
8
+ const allStates = [
9
+ "available" /* Available */,
10
+ // 7
11
+ "cancelled" /* Cancelled */,
12
+ // 6
13
+ "completed" /* Completed */,
14
+ // 5
15
+ "discarded" /* Discarded */,
16
+ // 4
17
+ "pending" /* Pending */,
18
+ // 3
19
+ "retryable" /* Retryable */,
20
+ // 2
21
+ "running" /* Running */,
22
+ // 1
23
+ "scheduled" /* Scheduled */
24
+ // 0
25
+ ];
26
+ const byte = bitmask[0];
27
+ return allStates.filter((_, i) => (byte & 1 << 7 - i) !== 0);
28
+ };
29
+ var mapToUniqueKey = (args, opts) => {
30
+ const uniqueOpts = opts.uniqueOpts;
31
+ if (!uniqueOpts) return void 0;
32
+ const keyParts = {};
33
+ if (!uniqueOpts.excludeKind) {
34
+ keyParts.kind = args.kind;
35
+ }
36
+ if (uniqueOpts.byArgs === true) {
37
+ keyParts.args = args;
38
+ } else if (Array.isArray(uniqueOpts.byArgs)) {
39
+ keyParts.args = Object.fromEntries(uniqueOpts.byArgs.sort().map((k) => [k, args[k]]));
40
+ }
41
+ if (uniqueOpts.byQueue) {
42
+ keyParts.queue = opts.queue;
43
+ }
44
+ if (uniqueOpts.byPeriod && opts.scheduledAt) {
45
+ const date = new Date(opts.scheduledAt);
46
+ const period = uniqueOpts.byPeriod;
47
+ const timestamp = Math.floor(date.getTime() / 1e3);
48
+ const rounded = timestamp - timestamp % period;
49
+ keyParts.period = rounded;
50
+ }
51
+ const hash = crypto.createHash("sha256").update(JSON.stringify(keyParts)).digest();
52
+ return Buffer.from(hash);
53
+ };
54
+
55
+ // src/drivers/pg/pg-driver.ts
56
+ var PgDriver = class {
57
+ /**
58
+ * Creates a new PgDriver instance.
59
+ * @param options - Options for configuring the RiverQueue pg driver connection pool. Fields include:
60
+ * - connectionString: Database connection string
61
+ * - connectionTimeoutMillis: Optional, connection timeout in milliseconds
62
+ * - idleTimeoutMillis: Optional, idle timeout in milliseconds
63
+ * - max: Optional, maximum number of clients in the pool
64
+ */
65
+ constructor(options) {
66
+ const config = { ...options };
67
+ this.pool = new Pool(config);
68
+ }
69
+ async verifyConnection() {
70
+ try {
71
+ const client = await this.pool.connect();
72
+ try {
73
+ await client.query("SELECT 1");
74
+ } finally {
75
+ client.release();
76
+ }
77
+ } catch (error) {
78
+ throw new Error(
79
+ `Database connection failed: ${error instanceof Error ? error.message : String(error)}`
80
+ );
81
+ }
82
+ }
83
+ async close() {
84
+ await this.pool.end();
85
+ }
86
+ async insert(args, opts) {
87
+ const client = await this.pool.connect();
88
+ try {
89
+ return await this.insertTx(client, args, opts);
90
+ } finally {
91
+ client.release();
92
+ }
93
+ }
94
+ async insertTx(tx, args, opts) {
95
+ if (!opts.queue) {
96
+ throw new Error("Queue name is required in InsertOpts");
97
+ }
98
+ if (!opts.maxAttempts) {
99
+ throw new Error("maxAttempts is required in InsertOpts");
100
+ }
101
+ let uniqueKey;
102
+ if (opts.uniqueOpts) {
103
+ uniqueKey = mapToUniqueKey(args, opts);
104
+ }
105
+ if (uniqueKey) {
106
+ const stateList = opts.uniqueOpts?.byState || [];
107
+ let query2 = "SELECT * FROM river_job WHERE unique_key = $1";
108
+ let values2 = [uniqueKey];
109
+ if (stateList.length > 0) {
110
+ query2 += " AND state = ANY($2)";
111
+ values2.push(stateList);
112
+ }
113
+ query2 += " LIMIT 1";
114
+ const result2 = await tx.query(
115
+ query2,
116
+ values2
117
+ );
118
+ if (result2.rows.length > 0) {
119
+ const row2 = result2.rows[0];
120
+ return this.mapRowToInsertResult(row2, true);
121
+ }
122
+ }
123
+ const { kind, ...restArgs } = args;
124
+ const columns = ["kind", "args", "queue", "max_attempts"];
125
+ const values = [
126
+ kind,
127
+ JSON.stringify(restArgs),
128
+ opts.queue,
129
+ opts.maxAttempts
130
+ ];
131
+ if (opts.tags) {
132
+ columns.push("tags");
133
+ values.push(JSON.stringify(opts.tags));
134
+ }
135
+ if (opts.priority) {
136
+ columns.push("priority");
137
+ values.push(opts.priority);
138
+ }
139
+ if (opts.metadata) {
140
+ columns.push("metadata");
141
+ values.push(JSON.stringify(opts.metadata));
142
+ }
143
+ if (opts.scheduledAt) {
144
+ columns.push("scheduled_at");
145
+ values.push(
146
+ opts.scheduledAt instanceof Date ? opts.scheduledAt.toISOString() : opts.scheduledAt
147
+ );
148
+ }
149
+ if (uniqueKey) {
150
+ columns.push("unique_key");
151
+ values.push(uniqueKey);
152
+ }
153
+ const placeholders = columns.map((_, i) => `$${i + 1}`);
154
+ const query = `INSERT INTO river_job (${columns.join(", ")}) VALUES (${placeholders.join(", ")}) RETURNING
155
+ id,
156
+ state,
157
+ attempt,
158
+ max_attempts as "maxAttempts",
159
+ attempted_at as "attemptedAt",
160
+ created_at as "createdAt",
161
+ finalized_at as "finalizedAt",
162
+ scheduled_at as "scheduledAt",
163
+ priority,
164
+ args,
165
+ attempted_by as "attemptedBy",
166
+ errors,
167
+ kind,
168
+ metadata,
169
+ queue,
170
+ tags,
171
+ unique_key as "uniqueKey",
172
+ unique_states as "uniqueStates"`;
173
+ const result = await tx.query(
174
+ query,
175
+ values
176
+ );
177
+ const row = result.rows[0];
178
+ if (!row) return row;
179
+ return this.mapRowToInsertResult(row, false);
180
+ }
181
+ async insertMany(jobs) {
182
+ const client = await this.pool.connect();
183
+ try {
184
+ await client.query("BEGIN");
185
+ const results = [];
186
+ for (const job of jobs) {
187
+ results.push(await this.insertTx(client, job.args, job.opts));
188
+ }
189
+ await client.query("COMMIT");
190
+ return results;
191
+ } catch (error) {
192
+ await client.query("ROLLBACK");
193
+ throw error;
194
+ } finally {
195
+ client.release();
196
+ }
197
+ }
198
+ async getTx() {
199
+ return this.pool.connect();
200
+ }
201
+ /**
202
+ * Helper to map a DB row to a Job<T> and InsertResult.
203
+ */
204
+ mapRowToInsertResult(row, skipped) {
205
+ return {
206
+ job: {
207
+ ...row,
208
+ args: { ...row.args, kind: row.kind },
209
+ uniqueStates: bitmaskToJobStates(row.uniqueStates)
210
+ },
211
+ skipped
212
+ };
213
+ }
214
+ };
215
+
216
+ export { PgDriver };
217
+ //# sourceMappingURL=index.js.map
218
+ //# sourceMappingURL=index.js.map