@nicnocquee/dataqueue 1.21.0 → 1.22.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/cli.cjs +6 -0
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +64 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -2
- package/dist/index.d.ts +20 -2
- package/dist/index.js +60 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +6 -0
- package/src/db-util.test.ts +56 -1
- package/src/db-util.ts +77 -6
- package/src/types.ts +20 -1
package/src/db-util.ts
CHANGED
|
@@ -1,31 +1,102 @@
|
|
|
1
1
|
import { Pool } from 'pg';
|
|
2
2
|
import { JobQueueConfig } from './types.js';
|
|
3
3
|
import { parse } from 'pg-connection-string';
|
|
4
|
+
import fs from 'fs';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Helper to load a PEM string or file. Only values starting with 'file://' are loaded from file.
|
|
8
|
+
*/
|
|
9
|
+
function loadPemOrFile(value?: string): string | undefined {
|
|
10
|
+
if (!value) return undefined;
|
|
11
|
+
if (value.startsWith('file://')) {
|
|
12
|
+
const filePath = value.slice(7);
|
|
13
|
+
return fs.readFileSync(filePath, 'utf8');
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Create a database connection pool with flexible SSL certificate loading.
|
|
20
|
+
*
|
|
21
|
+
* SSL config example (for local file paths):
|
|
22
|
+
* ssl: {
|
|
23
|
+
* ca: process.env.PGSSLROOTCERT, // PEM string or 'file://...'
|
|
24
|
+
* cert: process.env.PGSSLCERT, // optional, PEM string or 'file://...'
|
|
25
|
+
* key: process.env.PGSSLKEY, // optional, PEM string or 'file://...'
|
|
26
|
+
* rejectUnauthorized: true
|
|
27
|
+
* }
|
|
28
|
+
*/
|
|
6
29
|
export const createPool = (config: JobQueueConfig['databaseConfig']): Pool => {
|
|
7
30
|
let searchPath: string | undefined;
|
|
31
|
+
let ssl: any = undefined;
|
|
32
|
+
let customCA: string | undefined;
|
|
33
|
+
let sslmode: string | undefined;
|
|
34
|
+
|
|
8
35
|
if (config.connectionString) {
|
|
9
|
-
// Parse the connection string to extract search_path from query params
|
|
10
36
|
try {
|
|
11
37
|
const url = new URL(config.connectionString);
|
|
12
38
|
searchPath = url.searchParams.get('search_path') || undefined;
|
|
39
|
+
sslmode = url.searchParams.get('sslmode') || undefined;
|
|
40
|
+
if (sslmode === 'no-verify') {
|
|
41
|
+
ssl = { rejectUnauthorized: false };
|
|
42
|
+
}
|
|
13
43
|
} catch (e) {
|
|
14
|
-
// fallback: try pg-connection-string parse (for non-standard URLs)
|
|
15
44
|
const parsed = parse(config.connectionString);
|
|
16
45
|
if (parsed.options) {
|
|
17
|
-
// options might look like '-c search_path=myschema'
|
|
18
46
|
const match = parsed.options.match(/search_path=([^\s]+)/);
|
|
19
47
|
if (match) {
|
|
20
48
|
searchPath = match[1];
|
|
21
49
|
}
|
|
22
50
|
}
|
|
51
|
+
sslmode = typeof parsed.sslmode === 'string' ? parsed.sslmode : undefined;
|
|
52
|
+
if (sslmode === 'no-verify') {
|
|
53
|
+
ssl = { rejectUnauthorized: false };
|
|
54
|
+
}
|
|
23
55
|
}
|
|
24
56
|
}
|
|
25
57
|
|
|
26
|
-
|
|
58
|
+
// Flexible SSL loading: only support file:// for file loading
|
|
59
|
+
if (config.ssl) {
|
|
60
|
+
if (typeof config.ssl.ca === 'string') {
|
|
61
|
+
customCA = config.ssl.ca;
|
|
62
|
+
} else if (typeof process.env.PGSSLROOTCERT === 'string') {
|
|
63
|
+
customCA = process.env.PGSSLROOTCERT;
|
|
64
|
+
} else {
|
|
65
|
+
customCA = undefined;
|
|
66
|
+
}
|
|
67
|
+
const caValue =
|
|
68
|
+
typeof customCA === 'string' ? loadPemOrFile(customCA) : undefined;
|
|
69
|
+
ssl = {
|
|
70
|
+
...ssl,
|
|
71
|
+
...(caValue ? { ca: caValue } : {}),
|
|
72
|
+
cert: loadPemOrFile(
|
|
73
|
+
typeof config.ssl.cert === 'string'
|
|
74
|
+
? config.ssl.cert
|
|
75
|
+
: process.env.PGSSLCERT,
|
|
76
|
+
),
|
|
77
|
+
key: loadPemOrFile(
|
|
78
|
+
typeof config.ssl.key === 'string'
|
|
79
|
+
? config.ssl.key
|
|
80
|
+
: process.env.PGSSLKEY,
|
|
81
|
+
),
|
|
82
|
+
rejectUnauthorized:
|
|
83
|
+
config.ssl.rejectUnauthorized !== undefined
|
|
84
|
+
? config.ssl.rejectUnauthorized
|
|
85
|
+
: true,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Warn if both sslmode (any value) and a custom CA are set
|
|
90
|
+
if (sslmode && customCA) {
|
|
91
|
+
const warning = `\n\n\x1b[33m**************************************************\n\u26A0\uFE0F WARNING: SSL CONFIGURATION ISSUE\n**************************************************\nBoth sslmode ('${sslmode}') is set in the connection string\nand a custom CA is provided (via config.ssl.ca or PGSSLROOTCERT).\nThis combination may cause connection failures or unexpected behavior.\n\nRecommended: Remove sslmode from the connection string when using a custom CA.\n**************************************************\x1b[0m\n`;
|
|
92
|
+
console.warn(warning);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const pool = new Pool({
|
|
96
|
+
...config,
|
|
97
|
+
...(ssl ? { ssl } : {}),
|
|
98
|
+
});
|
|
27
99
|
|
|
28
|
-
// If search_path is specified, set it for every new connection
|
|
29
100
|
if (searchPath) {
|
|
30
101
|
pool.on('connect', (client) => {
|
|
31
102
|
client.query(`SET search_path TO ${searchPath}`);
|
package/src/types.ts
CHANGED
|
@@ -164,6 +164,25 @@ export interface Processor {
|
|
|
164
164
|
start: () => Promise<number>;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
export interface DatabaseSSLConfig {
|
|
168
|
+
/**
|
|
169
|
+
* CA certificate as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
|
|
170
|
+
*/
|
|
171
|
+
ca?: string;
|
|
172
|
+
/**
|
|
173
|
+
* Client certificate as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
|
|
174
|
+
*/
|
|
175
|
+
cert?: string;
|
|
176
|
+
/**
|
|
177
|
+
* Client private key as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
|
|
178
|
+
*/
|
|
179
|
+
key?: string;
|
|
180
|
+
/**
|
|
181
|
+
* Whether to reject unauthorized certificates (default: true)
|
|
182
|
+
*/
|
|
183
|
+
rejectUnauthorized?: boolean;
|
|
184
|
+
}
|
|
185
|
+
|
|
167
186
|
export interface JobQueueConfig {
|
|
168
187
|
databaseConfig: {
|
|
169
188
|
connectionString?: string;
|
|
@@ -172,7 +191,7 @@ export interface JobQueueConfig {
|
|
|
172
191
|
database?: string;
|
|
173
192
|
user?: string;
|
|
174
193
|
password?: string;
|
|
175
|
-
ssl?:
|
|
194
|
+
ssl?: DatabaseSSLConfig;
|
|
176
195
|
};
|
|
177
196
|
verbose?: boolean;
|
|
178
197
|
}
|