neonctl 2.28.0 → 2.29.1
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/README.md +71 -71
- package/dist/analytics.js +35 -33
- package/dist/api.js +34 -34
- package/dist/auth.js +50 -44
- package/dist/cli.js +2 -2
- package/dist/commands/auth.js +58 -52
- package/dist/commands/bootstrap.js +115 -157
- package/dist/commands/branches.js +154 -147
- package/dist/commands/bucket.js +124 -118
- package/dist/commands/checkout.js +49 -49
- package/dist/commands/config.js +212 -88
- package/dist/commands/connection_string.js +62 -62
- package/dist/commands/data_api.js +96 -96
- package/dist/commands/databases.js +23 -23
- package/dist/commands/deploy.js +12 -12
- package/dist/commands/dev.js +114 -114
- package/dist/commands/env.js +43 -43
- package/dist/commands/functions.js +97 -98
- package/dist/commands/index.js +26 -26
- package/dist/commands/init.js +23 -22
- package/dist/commands/ip_allow.js +29 -29
- package/dist/commands/link.js +223 -166
- package/dist/commands/neon_auth.js +381 -363
- package/dist/commands/operations.js +11 -11
- package/dist/commands/orgs.js +8 -8
- package/dist/commands/projects.js +101 -99
- package/dist/commands/psql.js +31 -31
- package/dist/commands/roles.js +21 -21
- package/dist/commands/schema_diff.js +23 -23
- package/dist/commands/set_context.js +17 -17
- package/dist/commands/status.js +17 -17
- package/dist/commands/user.js +5 -5
- package/dist/commands/vpc_endpoints.js +50 -50
- package/dist/config.js +7 -7
- package/dist/config_format.js +5 -5
- package/dist/context.js +23 -16
- package/dist/current_branch_fast_path.js +6 -6
- package/dist/dev/env.js +34 -34
- package/dist/dev/functions.js +4 -4
- package/dist/dev/inputs.js +6 -6
- package/dist/dev/runtime.js +25 -25
- package/dist/env.js +14 -14
- package/dist/env_file.js +13 -13
- package/dist/errors.js +19 -19
- package/dist/functions_api.js +10 -10
- package/dist/help.js +15 -15
- package/dist/index.js +94 -92
- package/dist/log.js +2 -2
- package/dist/pkg.js +5 -5
- package/dist/psql/cli.js +4 -2
- package/dist/psql/command/cmd_cond.js +61 -61
- package/dist/psql/command/cmd_connect.js +159 -154
- package/dist/psql/command/cmd_copy.js +107 -97
- package/dist/psql/command/cmd_describe.js +368 -363
- package/dist/psql/command/cmd_format.js +276 -263
- package/dist/psql/command/cmd_io.js +269 -263
- package/dist/psql/command/cmd_lo.js +74 -66
- package/dist/psql/command/cmd_meta.js +148 -148
- package/dist/psql/command/cmd_misc.js +17 -17
- package/dist/psql/command/cmd_pipeline.js +142 -135
- package/dist/psql/command/cmd_restrict.js +25 -25
- package/dist/psql/command/cmd_show.js +183 -168
- package/dist/psql/command/dispatch.js +26 -26
- package/dist/psql/command/shared.js +14 -14
- package/dist/psql/complete/filenames.js +16 -16
- package/dist/psql/complete/index.js +4 -4
- package/dist/psql/complete/matcher.js +33 -32
- package/dist/psql/complete/psqlVars.js +173 -173
- package/dist/psql/complete/queries.js +5 -3
- package/dist/psql/complete/rules.js +900 -863
- package/dist/psql/core/common.js +136 -133
- package/dist/psql/core/help.js +343 -343
- package/dist/psql/core/mainloop.js +160 -153
- package/dist/psql/core/prompt.js +126 -123
- package/dist/psql/core/settings.js +111 -111
- package/dist/psql/core/sqlHelp.js +150 -150
- package/dist/psql/core/startup.js +211 -205
- package/dist/psql/core/syncVars.js +14 -14
- package/dist/psql/core/variables.js +24 -24
- package/dist/psql/describe/formatters.js +302 -289
- package/dist/psql/describe/processNamePattern.js +28 -28
- package/dist/psql/describe/queries.js +656 -651
- package/dist/psql/index.js +436 -411
- package/dist/psql/io/history.js +36 -36
- package/dist/psql/io/input.js +15 -15
- package/dist/psql/io/lineEditor/buffer.js +27 -25
- package/dist/psql/io/lineEditor/complete.js +15 -15
- package/dist/psql/io/lineEditor/filename.js +22 -22
- package/dist/psql/io/lineEditor/index.js +65 -62
- package/dist/psql/io/lineEditor/keymap.js +325 -318
- package/dist/psql/io/lineEditor/vt100.js +60 -60
- package/dist/psql/io/pgpass.js +18 -18
- package/dist/psql/io/pgservice.js +14 -14
- package/dist/psql/io/psqlrc.js +46 -46
- package/dist/psql/print/aligned.js +175 -166
- package/dist/psql/print/asciidoc.js +51 -51
- package/dist/psql/print/crosstab.js +34 -31
- package/dist/psql/print/csv.js +25 -22
- package/dist/psql/print/html.js +54 -54
- package/dist/psql/print/json.js +12 -12
- package/dist/psql/print/latex.js +118 -118
- package/dist/psql/print/pager.js +28 -26
- package/dist/psql/print/troff.js +48 -48
- package/dist/psql/print/unaligned.js +15 -14
- package/dist/psql/print/units.js +17 -17
- package/dist/psql/scanner/slash.js +48 -46
- package/dist/psql/scanner/sql.js +88 -84
- package/dist/psql/scanner/stringutils.js +21 -17
- package/dist/psql/types/index.js +7 -7
- package/dist/psql/types/scanner.js +8 -8
- package/dist/psql/wire/connection.js +341 -327
- package/dist/psql/wire/copy.js +7 -7
- package/dist/psql/wire/pipeline.js +26 -24
- package/dist/psql/wire/protocol.js +102 -102
- package/dist/psql/wire/sasl.js +62 -62
- package/dist/psql/wire/tls.js +79 -73
- package/dist/storage_api.js +15 -15
- package/dist/test_utils/fixtures.js +34 -31
- package/dist/test_utils/oauth_server.js +5 -5
- package/dist/utils/api_enums.js +13 -13
- package/dist/utils/branch_notice.js +5 -5
- package/dist/utils/branch_picker.js +26 -26
- package/dist/utils/compute_units.js +4 -4
- package/dist/utils/enrichers.js +20 -15
- package/dist/utils/esbuild.js +28 -28
- package/dist/utils/formats.js +1 -1
- package/dist/utils/middlewares.js +3 -3
- package/dist/utils/package_manager.js +68 -0
- package/dist/utils/point_in_time.js +12 -12
- package/dist/utils/psql.js +30 -30
- package/dist/utils/string.js +2 -2
- package/dist/utils/ui.js +9 -9
- package/dist/utils/zip.js +1 -1
- package/dist/writer.js +17 -17
- package/package.json +6 -7
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
const controlEvent = (b) => {
|
|
24
24
|
// ^A == 0x01 maps back to 'a'. Lowercase keeps things consistent.
|
|
25
25
|
const letter = String.fromCharCode(b + 0x60);
|
|
26
|
-
return { key:
|
|
26
|
+
return { key: "char", char: letter, ctrl: true };
|
|
27
27
|
};
|
|
28
28
|
/** Streaming decoder. Owns a small pending-byte buffer. */
|
|
29
29
|
export class Vt100Decoder {
|
|
@@ -102,7 +102,7 @@ export class Vt100Decoder {
|
|
|
102
102
|
this.utf8Bytes.length = 0;
|
|
103
103
|
this.utf8Expect = 0;
|
|
104
104
|
this.pending.shift();
|
|
105
|
-
return { key:
|
|
105
|
+
return { key: "unknown", raw: new Uint8Array([b]) };
|
|
106
106
|
}
|
|
107
107
|
this.utf8Bytes.push(b);
|
|
108
108
|
this.pending.shift();
|
|
@@ -111,27 +111,27 @@ export class Vt100Decoder {
|
|
|
111
111
|
const bytes = Uint8Array.from(this.utf8Bytes);
|
|
112
112
|
this.utf8Bytes.length = 0;
|
|
113
113
|
const decoded = utf8Decode(bytes);
|
|
114
|
-
return { key:
|
|
114
|
+
return { key: "char", char: decoded };
|
|
115
115
|
}
|
|
116
116
|
return null;
|
|
117
117
|
}
|
|
118
118
|
// ASCII printable.
|
|
119
119
|
if (b >= 0x20 && b <= 0x7e) {
|
|
120
120
|
this.pending.shift();
|
|
121
|
-
return { key:
|
|
121
|
+
return { key: "char", char: String.fromCharCode(b) };
|
|
122
122
|
}
|
|
123
123
|
// Common controls.
|
|
124
124
|
if (b === 0x09) {
|
|
125
125
|
this.pending.shift();
|
|
126
|
-
return { key:
|
|
126
|
+
return { key: "tab" };
|
|
127
127
|
}
|
|
128
128
|
if (b === 0x0a || b === 0x0d) {
|
|
129
129
|
this.pending.shift();
|
|
130
|
-
return { key:
|
|
130
|
+
return { key: "enter" };
|
|
131
131
|
}
|
|
132
132
|
if (b === 0x7f || b === 0x08) {
|
|
133
133
|
this.pending.shift();
|
|
134
|
-
return { key:
|
|
134
|
+
return { key: "backspace" };
|
|
135
135
|
}
|
|
136
136
|
if (b === 0x1b) {
|
|
137
137
|
// Escape: maybe alone, maybe the lead of a CSI/SS3/Meta sequence.
|
|
@@ -162,7 +162,7 @@ export class Vt100Decoder {
|
|
|
162
162
|
}
|
|
163
163
|
// Stray high byte. Emit unknown.
|
|
164
164
|
this.pending.shift();
|
|
165
|
-
return { key:
|
|
165
|
+
return { key: "unknown", raw: new Uint8Array([b]) };
|
|
166
166
|
}
|
|
167
167
|
/**
|
|
168
168
|
* Called when the head byte is 0x1b. Tries to consume an escape
|
|
@@ -181,7 +181,7 @@ export class Vt100Decoder {
|
|
|
181
181
|
if (this.pending.length === 1) {
|
|
182
182
|
if (this.escTimeoutMs === 0) {
|
|
183
183
|
this.pending.shift();
|
|
184
|
-
return { key:
|
|
184
|
+
return { key: "escape" };
|
|
185
185
|
}
|
|
186
186
|
// Already waiting? Don't re-arm the timer.
|
|
187
187
|
if (this.escPending)
|
|
@@ -193,7 +193,7 @@ export class Vt100Decoder {
|
|
|
193
193
|
if (this.escPending && this.pending[0] === 0x1b) {
|
|
194
194
|
this.pending.shift();
|
|
195
195
|
this.escPending = false;
|
|
196
|
-
this.onTimeoutEvent?.({ key:
|
|
196
|
+
this.onTimeoutEvent?.({ key: "escape" });
|
|
197
197
|
}
|
|
198
198
|
else {
|
|
199
199
|
this.escPending = false;
|
|
@@ -224,16 +224,16 @@ export class Vt100Decoder {
|
|
|
224
224
|
}
|
|
225
225
|
if (b1 === 0x7f) {
|
|
226
226
|
this.pending.splice(0, 2);
|
|
227
|
-
return { key:
|
|
227
|
+
return { key: "backspace", meta: true };
|
|
228
228
|
}
|
|
229
229
|
if (b1 >= 0x20 && b1 <= 0x7e) {
|
|
230
230
|
this.pending.splice(0, 2);
|
|
231
|
-
return { key:
|
|
231
|
+
return { key: "char", char: String.fromCharCode(b1), meta: true };
|
|
232
232
|
}
|
|
233
233
|
// Unknown Esc-X sequence; consume both and emit unknown.
|
|
234
234
|
const raw = Uint8Array.from(this.pending.slice(0, 2));
|
|
235
235
|
this.pending.splice(0, 2);
|
|
236
|
-
return { key:
|
|
236
|
+
return { key: "unknown", raw };
|
|
237
237
|
}
|
|
238
238
|
consumeCsi() {
|
|
239
239
|
// Format: ESC [ (parameter bytes 0x30..0x3f)* (intermediate bytes 0x20..0x2f)* (final byte 0x40..0x7e)
|
|
@@ -259,52 +259,52 @@ export class Vt100Decoder {
|
|
|
259
259
|
const paramStr = String.fromCharCode(...params);
|
|
260
260
|
consume();
|
|
261
261
|
switch (paramStr) {
|
|
262
|
-
case
|
|
263
|
-
case
|
|
264
|
-
return { key:
|
|
265
|
-
case
|
|
266
|
-
return { key:
|
|
267
|
-
case
|
|
268
|
-
return { key:
|
|
269
|
-
case
|
|
270
|
-
case
|
|
271
|
-
return { key:
|
|
272
|
-
case
|
|
273
|
-
return { key:
|
|
274
|
-
case
|
|
275
|
-
return { key:
|
|
276
|
-
case
|
|
277
|
-
return { key:
|
|
278
|
-
case
|
|
279
|
-
return { key:
|
|
262
|
+
case "1":
|
|
263
|
+
case "7":
|
|
264
|
+
return { key: "home" };
|
|
265
|
+
case "2":
|
|
266
|
+
return { key: "unknown" }; // Insert; we don't handle it.
|
|
267
|
+
case "3":
|
|
268
|
+
return { key: "delete" };
|
|
269
|
+
case "4":
|
|
270
|
+
case "8":
|
|
271
|
+
return { key: "end" };
|
|
272
|
+
case "5":
|
|
273
|
+
return { key: "pageup" };
|
|
274
|
+
case "6":
|
|
275
|
+
return { key: "pagedown" };
|
|
276
|
+
case "200":
|
|
277
|
+
return { key: "paste-start" };
|
|
278
|
+
case "201":
|
|
279
|
+
return { key: "paste-end" };
|
|
280
280
|
default:
|
|
281
|
-
return { key:
|
|
281
|
+
return { key: "unknown" };
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
// Letter finals (A/B/C/D/H/F).
|
|
285
285
|
// Param string may carry modifiers: e.g. "1;3" → Alt-arrow.
|
|
286
286
|
const paramStr = String.fromCharCode(...params);
|
|
287
287
|
consume();
|
|
288
|
-
const meta = paramStr.endsWith(
|
|
288
|
+
const meta = paramStr.endsWith(";3") || paramStr.endsWith(";7");
|
|
289
289
|
switch (final) {
|
|
290
290
|
case 0x41 /* 'A' */:
|
|
291
|
-
return meta ? { key:
|
|
291
|
+
return meta ? { key: "up", meta: true } : { key: "up" };
|
|
292
292
|
case 0x42 /* 'B' */:
|
|
293
|
-
return meta ? { key:
|
|
293
|
+
return meta ? { key: "down", meta: true } : { key: "down" };
|
|
294
294
|
case 0x43 /* 'C' */:
|
|
295
|
-
return meta ? { key:
|
|
295
|
+
return meta ? { key: "right", meta: true } : { key: "right" };
|
|
296
296
|
case 0x44 /* 'D' */:
|
|
297
|
-
return meta ? { key:
|
|
297
|
+
return meta ? { key: "left", meta: true } : { key: "left" };
|
|
298
298
|
case 0x48 /* 'H' */:
|
|
299
|
-
return { key:
|
|
299
|
+
return { key: "home" };
|
|
300
300
|
case 0x46 /* 'F' */:
|
|
301
|
-
return { key:
|
|
301
|
+
return { key: "end" };
|
|
302
302
|
case 0x5a /* 'Z' */:
|
|
303
303
|
// Shift-Tab; treat as plain Tab for now (no reverse cycling yet).
|
|
304
|
-
return { key:
|
|
304
|
+
return { key: "tab", meta: true };
|
|
305
305
|
default:
|
|
306
306
|
return {
|
|
307
|
-
key:
|
|
307
|
+
key: "unknown",
|
|
308
308
|
raw: Uint8Array.from(this.pending.slice(0, seqLen)),
|
|
309
309
|
};
|
|
310
310
|
}
|
|
@@ -313,51 +313,51 @@ export class Vt100Decoder {
|
|
|
313
313
|
/** Decode a small UTF-8 byte sequence (1..4 bytes) into a string. */
|
|
314
314
|
const utf8Decode = (bytes) => {
|
|
315
315
|
// Node provides TextDecoder; available on all supported runtimes (Node 18+).
|
|
316
|
-
return new TextDecoder(
|
|
316
|
+
return new TextDecoder("utf-8", { fatal: false }).decode(bytes);
|
|
317
317
|
};
|
|
318
318
|
/** Translate an SS3 final byte (after `ESC O`) into a key event. */
|
|
319
319
|
const ss3ToEvent = (b) => {
|
|
320
320
|
switch (b) {
|
|
321
321
|
case 0x41:
|
|
322
|
-
return { key:
|
|
322
|
+
return { key: "up" };
|
|
323
323
|
case 0x42:
|
|
324
|
-
return { key:
|
|
324
|
+
return { key: "down" };
|
|
325
325
|
case 0x43:
|
|
326
|
-
return { key:
|
|
326
|
+
return { key: "right" };
|
|
327
327
|
case 0x44:
|
|
328
|
-
return { key:
|
|
328
|
+
return { key: "left" };
|
|
329
329
|
case 0x48:
|
|
330
|
-
return { key:
|
|
330
|
+
return { key: "home" };
|
|
331
331
|
case 0x46:
|
|
332
|
-
return { key:
|
|
332
|
+
return { key: "end" };
|
|
333
333
|
default:
|
|
334
|
-
return { key:
|
|
334
|
+
return { key: "unknown", raw: new Uint8Array([0x1b, 0x4f, b]) };
|
|
335
335
|
}
|
|
336
336
|
};
|
|
337
337
|
// ---------------------------------------------------------------------------
|
|
338
338
|
// CSI output helpers
|
|
339
339
|
// ---------------------------------------------------------------------------
|
|
340
340
|
/** Move cursor up N rows. */
|
|
341
|
-
export const csiUp = (n) => (n > 0 ? `\x1b[${n}A` :
|
|
341
|
+
export const csiUp = (n) => (n > 0 ? `\x1b[${n}A` : "");
|
|
342
342
|
/** Move cursor down N rows. */
|
|
343
|
-
export const csiDown = (n) => (n > 0 ? `\x1b[${n}B` :
|
|
343
|
+
export const csiDown = (n) => (n > 0 ? `\x1b[${n}B` : "");
|
|
344
344
|
/** Move cursor right N columns. */
|
|
345
|
-
export const csiRight = (n) => (n > 0 ? `\x1b[${n}C` :
|
|
345
|
+
export const csiRight = (n) => (n > 0 ? `\x1b[${n}C` : "");
|
|
346
346
|
/** Move cursor left N columns. */
|
|
347
|
-
export const csiLeft = (n) => (n > 0 ? `\x1b[${n}D` :
|
|
347
|
+
export const csiLeft = (n) => (n > 0 ? `\x1b[${n}D` : "");
|
|
348
348
|
/** Move cursor to column N (1-based). */
|
|
349
349
|
export const csiToColumn = (col) => `\x1b[${col}G`;
|
|
350
350
|
/** Erase from cursor to end-of-line. */
|
|
351
|
-
export const csiEraseToEol = () =>
|
|
351
|
+
export const csiEraseToEol = () => "\x1b[K";
|
|
352
352
|
/** Erase entire screen and move cursor to home. */
|
|
353
|
-
export const csiClearScreen = () =>
|
|
353
|
+
export const csiClearScreen = () => "\x1b[2J\x1b[H";
|
|
354
354
|
/** Carriage return: move to column 1 without writing a newline. */
|
|
355
|
-
export const CR =
|
|
355
|
+
export const CR = "\r";
|
|
356
356
|
/** Newline (LF). */
|
|
357
|
-
export const LF =
|
|
357
|
+
export const LF = "\n";
|
|
358
358
|
/** Enable bracketed paste mode (DEC private mode 2004). */
|
|
359
|
-
export const enableBracketedPaste = () =>
|
|
359
|
+
export const enableBracketedPaste = () => "\x1b[?2004h";
|
|
360
360
|
/** Disable bracketed paste mode. */
|
|
361
|
-
export const disableBracketedPaste = () =>
|
|
361
|
+
export const disableBracketedPaste = () => "\x1b[?2004l";
|
|
362
362
|
/** Audible bell. */
|
|
363
|
-
export const BEL =
|
|
363
|
+
export const BEL = "\x07";
|
package/dist/psql/io/pgpass.js
CHANGED
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
* skip the file and emit a single warning to stderr. Windows skips the check
|
|
26
26
|
* entirely (libpq does the same — `geteuid` / `S_IRWXG` aren't portable).
|
|
27
27
|
*/
|
|
28
|
-
import { promises as fs } from
|
|
29
|
-
import * as os from
|
|
30
|
-
import * as path from
|
|
31
|
-
const isWindows = process.platform ===
|
|
28
|
+
import { promises as fs } from "node:fs";
|
|
29
|
+
import * as os from "node:os";
|
|
30
|
+
import * as path from "node:path";
|
|
31
|
+
const isWindows = process.platform === "win32";
|
|
32
32
|
/**
|
|
33
33
|
* Return the default `.pgpass` path:
|
|
34
34
|
*
|
|
@@ -46,13 +46,13 @@ export const defaultPgPassPath = (env = process.env) => {
|
|
|
46
46
|
if (isWindows) {
|
|
47
47
|
const appdata = env.APPDATA;
|
|
48
48
|
if (appdata !== undefined && appdata.length > 0) {
|
|
49
|
-
return path.join(appdata,
|
|
49
|
+
return path.join(appdata, "postgresql", "pgpass.conf");
|
|
50
50
|
}
|
|
51
51
|
// Fall through to homedir() if APPDATA isn't set — degrade gracefully on
|
|
52
52
|
// a minimally configured Windows session.
|
|
53
53
|
}
|
|
54
54
|
const home = env.HOME ?? os.homedir();
|
|
55
|
-
return path.join(home,
|
|
55
|
+
return path.join(home, ".pgpass");
|
|
56
56
|
};
|
|
57
57
|
/**
|
|
58
58
|
* Split a `.pgpass` line into its five fields, respecting `\:` and `\\`
|
|
@@ -67,9 +67,9 @@ export const defaultPgPassPath = (env = process.env) => {
|
|
|
67
67
|
*/
|
|
68
68
|
/** Un-escape `\X` → `X` (a trailing lone backslash is kept). */
|
|
69
69
|
const decodeBackslashes = (s) => {
|
|
70
|
-
let out =
|
|
70
|
+
let out = "";
|
|
71
71
|
for (let i = 0; i < s.length; i++) {
|
|
72
|
-
if (s[i] ===
|
|
72
|
+
if (s[i] === "\\" && i + 1 < s.length) {
|
|
73
73
|
out += s[i + 1];
|
|
74
74
|
i += 1;
|
|
75
75
|
continue;
|
|
@@ -87,17 +87,17 @@ const splitLine = (line) => {
|
|
|
87
87
|
// char-by-char comparison. The password is the returned secret, so it is
|
|
88
88
|
// fully decoded here.
|
|
89
89
|
const fields = [];
|
|
90
|
-
let current =
|
|
90
|
+
let current = "";
|
|
91
91
|
for (let i = 0; i < line.length; i++) {
|
|
92
92
|
const ch = line[i];
|
|
93
|
-
if (ch ===
|
|
94
|
-
current +=
|
|
93
|
+
if (ch === "\\" && i + 1 < line.length) {
|
|
94
|
+
current += "\\" + line[i + 1];
|
|
95
95
|
i += 1;
|
|
96
96
|
continue;
|
|
97
97
|
}
|
|
98
|
-
if (ch ===
|
|
98
|
+
if (ch === ":") {
|
|
99
99
|
fields.push(current);
|
|
100
|
-
current =
|
|
100
|
+
current = "";
|
|
101
101
|
continue;
|
|
102
102
|
}
|
|
103
103
|
current += ch;
|
|
@@ -136,7 +136,7 @@ export const loadPgPass = async (filePath, opts) => {
|
|
|
136
136
|
}
|
|
137
137
|
catch (err) {
|
|
138
138
|
const code = err.code;
|
|
139
|
-
if (code ===
|
|
139
|
+
if (code === "ENOENT" || code === "ENOTDIR")
|
|
140
140
|
return [];
|
|
141
141
|
return [];
|
|
142
142
|
}
|
|
@@ -148,17 +148,17 @@ export const loadPgPass = async (filePath, opts) => {
|
|
|
148
148
|
}
|
|
149
149
|
let raw;
|
|
150
150
|
try {
|
|
151
|
-
raw = await fs.readFile(resolved,
|
|
151
|
+
raw = await fs.readFile(resolved, "utf8");
|
|
152
152
|
}
|
|
153
153
|
catch {
|
|
154
154
|
return [];
|
|
155
155
|
}
|
|
156
156
|
const entries = [];
|
|
157
157
|
for (const line of raw.split(/\r?\n/)) {
|
|
158
|
-
const trimmed = line.replace(/^\s+/,
|
|
158
|
+
const trimmed = line.replace(/^\s+/, "");
|
|
159
159
|
if (trimmed.length === 0)
|
|
160
160
|
continue;
|
|
161
|
-
if (trimmed.startsWith(
|
|
161
|
+
if (trimmed.startsWith("#"))
|
|
162
162
|
continue;
|
|
163
163
|
const entry = splitLine(trimmed);
|
|
164
164
|
if (entry !== null)
|
|
@@ -171,7 +171,7 @@ export const loadPgPass = async (filePath, opts) => {
|
|
|
171
171
|
*/
|
|
172
172
|
const fieldMatches = (pattern, value) =>
|
|
173
173
|
// A bare `*` is the wildcard; `\*` decodes to a LITERAL `*` (review #21).
|
|
174
|
-
pattern ===
|
|
174
|
+
pattern === "*" || decodeBackslashes(pattern) === value;
|
|
175
175
|
/**
|
|
176
176
|
* Look up a password entry for the given `target`. Returns the first matching
|
|
177
177
|
* entry's password, or `undefined` if nothing matches.
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
* silently — libpq would also accept them and feed them to `PQconninfoParse`,
|
|
37
37
|
* which is responsible for the recognised-key gate.
|
|
38
38
|
*/
|
|
39
|
-
import { promises as fs } from
|
|
40
|
-
import * as os from
|
|
41
|
-
import * as path from
|
|
42
|
-
const isWindows = process.platform ===
|
|
39
|
+
import { promises as fs } from "node:fs";
|
|
40
|
+
import * as os from "node:os";
|
|
41
|
+
import * as path from "node:path";
|
|
42
|
+
const isWindows = process.platform === "win32";
|
|
43
43
|
/**
|
|
44
44
|
* Return the ordered list of candidate `pg_service.conf` paths to try. The
|
|
45
45
|
* caller stops at the first one that exists. Pure function — `env` defaults
|
|
@@ -56,25 +56,25 @@ export const defaultPgServiceFilePath = (env = process.env) => {
|
|
|
56
56
|
if (isWindows) {
|
|
57
57
|
const appdata = env.APPDATA;
|
|
58
58
|
if (appdata !== undefined && appdata.length > 0) {
|
|
59
|
-
out.push(path.join(appdata,
|
|
59
|
+
out.push(path.join(appdata, "postgresql", ".pg_service.conf"));
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
else {
|
|
63
63
|
const home = env.HOME ?? os.homedir();
|
|
64
64
|
if (home.length > 0) {
|
|
65
|
-
out.push(path.join(home,
|
|
65
|
+
out.push(path.join(home, ".pg_service.conf"));
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
// System-level: `$PGSYSCONFDIR/pg_service.conf`.
|
|
69
69
|
const sysDir = env.PGSYSCONFDIR;
|
|
70
70
|
if (sysDir !== undefined && sysDir.length > 0) {
|
|
71
|
-
out.push(path.join(sysDir,
|
|
71
|
+
out.push(path.join(sysDir, "pg_service.conf"));
|
|
72
72
|
}
|
|
73
73
|
// Platform-default system path. libpq's autoconf picks SYSCONFDIR at build
|
|
74
74
|
// time; for a portable TS implementation we use `/etc/pg_service.conf` on
|
|
75
75
|
// POSIX. Windows has no canonical equivalent.
|
|
76
76
|
if (!isWindows) {
|
|
77
|
-
out.push(
|
|
77
|
+
out.push("/etc/pg_service.conf");
|
|
78
78
|
}
|
|
79
79
|
return out;
|
|
80
80
|
};
|
|
@@ -101,10 +101,10 @@ export const parsePgServiceContent = (content) => {
|
|
|
101
101
|
const line = rawLine.trim();
|
|
102
102
|
if (line.length === 0)
|
|
103
103
|
continue;
|
|
104
|
-
if (line.startsWith(
|
|
104
|
+
if (line.startsWith("#"))
|
|
105
105
|
continue;
|
|
106
|
-
if (line.startsWith(
|
|
107
|
-
const close = line.indexOf(
|
|
106
|
+
if (line.startsWith("[")) {
|
|
107
|
+
const close = line.indexOf("]");
|
|
108
108
|
if (close < 0) {
|
|
109
109
|
// Malformed header — libpq aborts the file; we mirror by ending the
|
|
110
110
|
// current section so the bogus line doesn't bleed into it.
|
|
@@ -126,7 +126,7 @@ export const parsePgServiceContent = (content) => {
|
|
|
126
126
|
// resolve services that appear after the noise.
|
|
127
127
|
continue;
|
|
128
128
|
}
|
|
129
|
-
const eq = line.indexOf(
|
|
129
|
+
const eq = line.indexOf("=");
|
|
130
130
|
if (eq < 0)
|
|
131
131
|
continue;
|
|
132
132
|
const key = line.slice(0, eq).trim();
|
|
@@ -139,11 +139,11 @@ export const parsePgServiceContent = (content) => {
|
|
|
139
139
|
};
|
|
140
140
|
const readIfExists = async (filePath) => {
|
|
141
141
|
try {
|
|
142
|
-
return await fs.readFile(filePath,
|
|
142
|
+
return await fs.readFile(filePath, "utf8");
|
|
143
143
|
}
|
|
144
144
|
catch (err) {
|
|
145
145
|
const code = err.code;
|
|
146
|
-
if (code ===
|
|
146
|
+
if (code === "ENOENT" || code === "ENOTDIR")
|
|
147
147
|
return null;
|
|
148
148
|
// Permission / I/O errors silently degrade — libpq treats an unreadable
|
|
149
149
|
// service file the same as a missing one (the connection falls back to
|