neonctl 2.28.0 → 2.29.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.
Files changed (135) hide show
  1. package/README.md +2 -2
  2. package/dist/analytics.js +35 -33
  3. package/dist/api.js +34 -34
  4. package/dist/auth.js +50 -44
  5. package/dist/cli.js +2 -2
  6. package/dist/commands/auth.js +58 -52
  7. package/dist/commands/bootstrap.js +115 -157
  8. package/dist/commands/branches.js +154 -147
  9. package/dist/commands/bucket.js +124 -118
  10. package/dist/commands/checkout.js +49 -49
  11. package/dist/commands/config.js +212 -88
  12. package/dist/commands/connection_string.js +62 -62
  13. package/dist/commands/data_api.js +96 -96
  14. package/dist/commands/databases.js +23 -23
  15. package/dist/commands/deploy.js +12 -12
  16. package/dist/commands/dev.js +114 -114
  17. package/dist/commands/env.js +43 -43
  18. package/dist/commands/functions.js +97 -98
  19. package/dist/commands/index.js +26 -26
  20. package/dist/commands/init.js +23 -22
  21. package/dist/commands/ip_allow.js +29 -29
  22. package/dist/commands/link.js +223 -166
  23. package/dist/commands/neon_auth.js +381 -363
  24. package/dist/commands/operations.js +11 -11
  25. package/dist/commands/orgs.js +8 -8
  26. package/dist/commands/projects.js +101 -99
  27. package/dist/commands/psql.js +31 -31
  28. package/dist/commands/roles.js +21 -21
  29. package/dist/commands/schema_diff.js +23 -23
  30. package/dist/commands/set_context.js +17 -17
  31. package/dist/commands/status.js +17 -17
  32. package/dist/commands/user.js +5 -5
  33. package/dist/commands/vpc_endpoints.js +50 -50
  34. package/dist/config.js +7 -7
  35. package/dist/config_format.js +5 -5
  36. package/dist/context.js +23 -16
  37. package/dist/current_branch_fast_path.js +6 -6
  38. package/dist/dev/env.js +33 -33
  39. package/dist/dev/functions.js +4 -4
  40. package/dist/dev/inputs.js +6 -6
  41. package/dist/dev/runtime.js +25 -25
  42. package/dist/env.js +14 -14
  43. package/dist/env_file.js +13 -13
  44. package/dist/errors.js +19 -19
  45. package/dist/functions_api.js +10 -10
  46. package/dist/help.js +15 -15
  47. package/dist/index.js +94 -92
  48. package/dist/log.js +2 -2
  49. package/dist/pkg.js +5 -5
  50. package/dist/psql/cli.js +4 -2
  51. package/dist/psql/command/cmd_cond.js +61 -61
  52. package/dist/psql/command/cmd_connect.js +159 -154
  53. package/dist/psql/command/cmd_copy.js +107 -97
  54. package/dist/psql/command/cmd_describe.js +368 -363
  55. package/dist/psql/command/cmd_format.js +276 -263
  56. package/dist/psql/command/cmd_io.js +269 -263
  57. package/dist/psql/command/cmd_lo.js +74 -66
  58. package/dist/psql/command/cmd_meta.js +148 -148
  59. package/dist/psql/command/cmd_misc.js +17 -17
  60. package/dist/psql/command/cmd_pipeline.js +142 -135
  61. package/dist/psql/command/cmd_restrict.js +25 -25
  62. package/dist/psql/command/cmd_show.js +183 -168
  63. package/dist/psql/command/dispatch.js +26 -26
  64. package/dist/psql/command/shared.js +14 -14
  65. package/dist/psql/complete/filenames.js +16 -16
  66. package/dist/psql/complete/index.js +4 -4
  67. package/dist/psql/complete/matcher.js +33 -32
  68. package/dist/psql/complete/psqlVars.js +173 -173
  69. package/dist/psql/complete/queries.js +5 -3
  70. package/dist/psql/complete/rules.js +900 -863
  71. package/dist/psql/core/common.js +136 -133
  72. package/dist/psql/core/help.js +343 -343
  73. package/dist/psql/core/mainloop.js +160 -153
  74. package/dist/psql/core/prompt.js +126 -123
  75. package/dist/psql/core/settings.js +111 -111
  76. package/dist/psql/core/sqlHelp.js +150 -150
  77. package/dist/psql/core/startup.js +211 -205
  78. package/dist/psql/core/syncVars.js +14 -14
  79. package/dist/psql/core/variables.js +24 -24
  80. package/dist/psql/describe/formatters.js +302 -289
  81. package/dist/psql/describe/processNamePattern.js +28 -28
  82. package/dist/psql/describe/queries.js +656 -651
  83. package/dist/psql/index.js +436 -411
  84. package/dist/psql/io/history.js +36 -36
  85. package/dist/psql/io/input.js +15 -15
  86. package/dist/psql/io/lineEditor/buffer.js +27 -25
  87. package/dist/psql/io/lineEditor/complete.js +15 -15
  88. package/dist/psql/io/lineEditor/filename.js +22 -22
  89. package/dist/psql/io/lineEditor/index.js +65 -62
  90. package/dist/psql/io/lineEditor/keymap.js +325 -318
  91. package/dist/psql/io/lineEditor/vt100.js +60 -60
  92. package/dist/psql/io/pgpass.js +18 -18
  93. package/dist/psql/io/pgservice.js +14 -14
  94. package/dist/psql/io/psqlrc.js +46 -46
  95. package/dist/psql/print/aligned.js +175 -166
  96. package/dist/psql/print/asciidoc.js +51 -51
  97. package/dist/psql/print/crosstab.js +34 -31
  98. package/dist/psql/print/csv.js +25 -22
  99. package/dist/psql/print/html.js +54 -54
  100. package/dist/psql/print/json.js +12 -12
  101. package/dist/psql/print/latex.js +118 -118
  102. package/dist/psql/print/pager.js +28 -26
  103. package/dist/psql/print/troff.js +48 -48
  104. package/dist/psql/print/unaligned.js +15 -14
  105. package/dist/psql/print/units.js +17 -17
  106. package/dist/psql/scanner/slash.js +48 -46
  107. package/dist/psql/scanner/sql.js +88 -84
  108. package/dist/psql/scanner/stringutils.js +21 -17
  109. package/dist/psql/types/index.js +7 -7
  110. package/dist/psql/types/scanner.js +8 -8
  111. package/dist/psql/wire/connection.js +341 -327
  112. package/dist/psql/wire/copy.js +7 -7
  113. package/dist/psql/wire/pipeline.js +26 -24
  114. package/dist/psql/wire/protocol.js +102 -102
  115. package/dist/psql/wire/sasl.js +62 -62
  116. package/dist/psql/wire/tls.js +79 -73
  117. package/dist/storage_api.js +15 -15
  118. package/dist/test_utils/fixtures.js +34 -31
  119. package/dist/test_utils/oauth_server.js +5 -5
  120. package/dist/utils/api_enums.js +13 -13
  121. package/dist/utils/branch_notice.js +5 -5
  122. package/dist/utils/branch_picker.js +26 -26
  123. package/dist/utils/compute_units.js +4 -4
  124. package/dist/utils/enrichers.js +20 -15
  125. package/dist/utils/esbuild.js +28 -28
  126. package/dist/utils/formats.js +1 -1
  127. package/dist/utils/middlewares.js +3 -3
  128. package/dist/utils/package_manager.js +68 -0
  129. package/dist/utils/point_in_time.js +12 -12
  130. package/dist/utils/psql.js +30 -30
  131. package/dist/utils/string.js +2 -2
  132. package/dist/utils/ui.js +9 -9
  133. package/dist/utils/zip.js +1 -1
  134. package/dist/writer.js +17 -17
  135. package/package.json +6 -7
@@ -1,17 +1,17 @@
1
- import { PgConnection } from './wire/connection.js';
2
- import { applyEnvOverrides, defaultSettings } from './core/settings.js';
3
- import { createVarStore } from './core/variables.js';
4
- import { syncConnectionVars } from './core/syncVars.js';
5
- import { defaultRegistry } from './command/dispatch.js';
6
- import { createCondStack } from './command/cmd_cond.js';
7
- import { runMainLoop, EXIT_BADCONN, EXIT_FAILURE, EXIT_SUCCESS, EXIT_USER, } from './core/mainloop.js';
8
- import { applyStartupArgs, parseStartupArgs } from './core/startup.js';
9
- import { executeInputString, loadPsqlrc } from './io/psqlrc.js';
10
- import { loadPgPass } from './io/pgpass.js';
11
- import { loadPgServices } from './io/pgservice.js';
12
- import { promises as fs, existsSync } from 'node:fs';
13
- import * as os from 'node:os';
14
- import * as path from 'node:path';
1
+ import { existsSync, promises as fs } from "node:fs";
2
+ import * as os from "node:os";
3
+ import * as path from "node:path";
4
+ import { createCondStack } from "./command/cmd_cond.js";
5
+ import { defaultRegistry } from "./command/dispatch.js";
6
+ import { EXIT_BADCONN, EXIT_FAILURE, EXIT_SUCCESS, EXIT_USER, runMainLoop, } from "./core/mainloop.js";
7
+ import { applyEnvOverrides, defaultSettings } from "./core/settings.js";
8
+ import { applyStartupArgs, parseStartupArgs } from "./core/startup.js";
9
+ import { syncConnectionVars } from "./core/syncVars.js";
10
+ import { createVarStore } from "./core/variables.js";
11
+ import { loadPgPass } from "./io/pgpass.js";
12
+ import { loadPgServices } from "./io/pgservice.js";
13
+ import { executeInputString, loadPsqlrc } from "./io/psqlrc.js";
14
+ import { PgConnection } from "./wire/connection.js";
15
15
  /**
16
16
  * Embedded TypeScript psql entrypoint.
17
17
  *
@@ -27,7 +27,7 @@ export const runPsql = async (argv, stdio = {}) => {
27
27
  const stdin = stdio.stdin ?? process.stdin;
28
28
  const stdout = stdio.stdout ?? process.stdout;
29
29
  const stderr = stdio.stderr ?? process.stderr;
30
- const connectionUri = argv[0] ?? '';
30
+ const connectionUri = argv[0] ?? "";
31
31
  // Parse argv[0] in one of three shapes:
32
32
  // - URI scheme (`postgres://…` / `postgresql://…`): the URI-partial
33
33
  // parser handles authority, query, and `?service=…`.
@@ -45,10 +45,10 @@ export const runPsql = async (argv, stdio = {}) => {
45
45
  // ConnectOptions layers.
46
46
  let uriPartial = {};
47
47
  let uriService;
48
- if (connectionUri !== '' && looksLikeConnectionString(connectionUri)) {
48
+ if (connectionUri !== "" && looksLikeConnectionString(connectionUri)) {
49
49
  try {
50
- if (connectionUri.startsWith('postgres://') ||
51
- connectionUri.startsWith('postgresql://')) {
50
+ if (connectionUri.startsWith("postgres://") ||
51
+ connectionUri.startsWith("postgresql://")) {
52
52
  uriPartial = parseConnectionUriPartial(connectionUri);
53
53
  uriService = parseConnectionUriService(connectionUri);
54
54
  }
@@ -58,7 +58,8 @@ export const runPsql = async (argv, stdio = {}) => {
58
58
  // part of ConnectOptions); pull it out so the layered resolver
59
59
  // can look it up.
60
60
  const parsed = parseConninfo(connectionUri);
61
- if (typeof parsed._service === 'string' && parsed._service.length > 0) {
61
+ if (typeof parsed._service === "string" &&
62
+ parsed._service.length > 0) {
62
63
  uriService = parsed._service;
63
64
  }
64
65
  delete parsed._service;
@@ -72,11 +73,11 @@ export const runPsql = async (argv, stdio = {}) => {
72
73
  }
73
74
  // Parse psql args (argv[1..]). argv[0] is the connection URI consumed above.
74
75
  const parsed = parseStartupArgs(argv.slice(1));
75
- if ('kind' in parsed) {
76
- if (parsed.kind === 'help' || parsed.kind === 'version') {
76
+ if ("kind" in parsed) {
77
+ if (parsed.kind === "help" || parsed.kind === "version") {
77
78
  stdout.write(parsed.message);
78
- if (!parsed.message.endsWith('\n'))
79
- stdout.write('\n');
79
+ if (!parsed.message.endsWith("\n"))
80
+ stdout.write("\n");
80
81
  return EXIT_SUCCESS;
81
82
  }
82
83
  stderr.write(`psql: error: ${parsed.message}\n`);
@@ -212,7 +213,7 @@ const runPreActions = async (ctx, preActions, singleTransaction) => {
212
213
  // count as a "failed switch" for exit-code purposes.
213
214
  if (singleTransaction && settings.db) {
214
215
  try {
215
- await settings.db.execSimple('BEGIN');
216
+ await settings.db.execSimple("BEGIN");
216
217
  beganTransaction = true;
217
218
  }
218
219
  catch (err) {
@@ -224,10 +225,12 @@ const runPreActions = async (ctx, preActions, singleTransaction) => {
224
225
  for (const action of preActions) {
225
226
  if (connectionLost)
226
227
  break;
227
- if (action.kind === 'command') {
228
+ if (action.kind === "command") {
228
229
  let outcome;
229
230
  try {
230
- outcome = await executeInputString(action.sql, ctx, { print: true });
231
+ outcome = await executeInputString(action.sql, ctx, {
232
+ print: true,
233
+ });
231
234
  }
232
235
  catch (err) {
233
236
  // Defensive: executeInputString shouldn't throw, but if a downstream
@@ -266,7 +269,7 @@ const runPreActions = async (ctx, preActions, singleTransaction) => {
266
269
  // upstream, which only escalates to a stop when ON_ERROR_STOP fires).
267
270
  let contents;
268
271
  try {
269
- contents = await fs.readFile(action.path, 'utf8');
272
+ contents = await fs.readFile(action.path, "utf8");
270
273
  }
271
274
  catch (err) {
272
275
  const msg = err instanceof Error ? err.message : String(err);
@@ -280,7 +283,9 @@ const runPreActions = async (ctx, preActions, singleTransaction) => {
280
283
  }
281
284
  let outcome;
282
285
  try {
283
- outcome = await executeInputString(contents, ctx, { print: true });
286
+ outcome = await executeInputString(contents, ctx, {
287
+ print: true,
288
+ });
284
289
  }
285
290
  catch (err) {
286
291
  const msg = err instanceof Error ? err.message : String(err);
@@ -310,7 +315,7 @@ const runPreActions = async (ctx, preActions, singleTransaction) => {
310
315
  // and ON_ERROR_STOP fired, roll back. Otherwise commit — upstream commits
311
316
  // even when individual statements failed without ON_ERROR_STOP.
312
317
  if (beganTransaction && settings.db && !connectionLost) {
313
- const closing = earlyStopOnError ? 'ROLLBACK' : 'COMMIT';
318
+ const closing = earlyStopOnError ? "ROLLBACK" : "COMMIT";
314
319
  try {
315
320
  await settings.db.execSimple(closing);
316
321
  }
@@ -328,7 +333,7 @@ const runPreActions = async (ctx, preActions, singleTransaction) => {
328
333
  return status;
329
334
  };
330
335
  const writeStartupBanner = (connection, out) => {
331
- const serverVersion = connection.parameterStatus('server_version') ?? 'unknown';
336
+ const serverVersion = connection.parameterStatus("server_version") ?? "unknown";
332
337
  // Client identifier. Matches upstream's `psql (18.4, server X.Y)` shape
333
338
  // but signals that this is the embedded TS implementation so users can tell
334
339
  // when they're on the fallback path.
@@ -342,7 +347,7 @@ const writeStartupBanner = (connection, out) => {
342
347
  ];
343
348
  if (tls.alpn)
344
349
  parts.push(`ALPN: ${tls.alpn}`);
345
- out.write(`SSL connection (${parts.join(', ')})\n`);
350
+ out.write(`SSL connection (${parts.join(", ")})\n`);
346
351
  }
347
352
  out.write('Type "help" for help.\n\n');
348
353
  };
@@ -352,45 +357,45 @@ const writeStartupBanner = (connection, out) => {
352
357
  // recognize them as valid keys so callers don't get a spurious "unknown key"
353
358
  // rejection for a libpq-spec key they expect to work.
354
359
  const KNOWN_QUERY_KEYS = new Set([
355
- 'host',
356
- 'hostaddr',
357
- 'port',
358
- 'dbname',
359
- 'user',
360
- 'password',
361
- 'passfile',
362
- 'channel_binding',
363
- 'require_auth',
364
- 'connect_timeout',
365
- 'client_encoding',
366
- 'options',
367
- 'application_name',
368
- 'fallback_application_name',
369
- 'keepalives',
370
- 'keepalives_idle',
371
- 'keepalives_interval',
372
- 'keepalives_count',
373
- 'sslmode',
374
- 'sslnegotiation',
375
- 'sslcompression',
376
- 'sslcert',
377
- 'sslkey',
378
- 'sslcertmode',
379
- 'sslrootcert',
380
- 'sslcrl',
381
- 'sslcrldir',
382
- 'sslkeylogfile',
383
- 'sslsni',
384
- 'requirepeer',
385
- 'ssl_min_protocol_version',
386
- 'ssl_max_protocol_version',
387
- 'krbsrvname',
388
- 'gsslib',
389
- 'gssencmode',
390
- 'service',
391
- 'target_session_attrs',
392
- 'load_balance_hosts',
393
- 'replication',
360
+ "host",
361
+ "hostaddr",
362
+ "port",
363
+ "dbname",
364
+ "user",
365
+ "password",
366
+ "passfile",
367
+ "channel_binding",
368
+ "require_auth",
369
+ "connect_timeout",
370
+ "client_encoding",
371
+ "options",
372
+ "application_name",
373
+ "fallback_application_name",
374
+ "keepalives",
375
+ "keepalives_idle",
376
+ "keepalives_interval",
377
+ "keepalives_count",
378
+ "sslmode",
379
+ "sslnegotiation",
380
+ "sslcompression",
381
+ "sslcert",
382
+ "sslkey",
383
+ "sslcertmode",
384
+ "sslrootcert",
385
+ "sslcrl",
386
+ "sslcrldir",
387
+ "sslkeylogfile",
388
+ "sslsni",
389
+ "requirepeer",
390
+ "ssl_min_protocol_version",
391
+ "ssl_max_protocol_version",
392
+ "krbsrvname",
393
+ "gsslib",
394
+ "gssencmode",
395
+ "service",
396
+ "target_session_attrs",
397
+ "load_balance_hosts",
398
+ "replication",
394
399
  ]);
395
400
  /**
396
401
  * Tokenize a postgres connection URI into raw components.
@@ -405,33 +410,33 @@ const tokenizeConnectionUri = (uri) => {
405
410
  // Strip scheme. Only postgres:// and postgresql:// are accepted; libpq
406
411
  // rejects everything else with a "missing schema" error.
407
412
  let rest;
408
- if (uri.startsWith('postgresql://')) {
409
- rest = uri.slice('postgresql://'.length);
413
+ if (uri.startsWith("postgresql://")) {
414
+ rest = uri.slice("postgresql://".length);
410
415
  }
411
- else if (uri.startsWith('postgres://')) {
412
- rest = uri.slice('postgres://'.length);
416
+ else if (uri.startsWith("postgres://")) {
417
+ rest = uri.slice("postgres://".length);
413
418
  }
414
419
  else {
415
420
  throw new Error(`unsupported scheme in URI: ${uri}`);
416
421
  }
417
422
  // Split off query string.
418
- let query = '';
419
- const qIdx = rest.indexOf('?');
423
+ let query = "";
424
+ const qIdx = rest.indexOf("?");
420
425
  if (qIdx >= 0) {
421
426
  query = rest.slice(qIdx + 1);
422
427
  rest = rest.slice(0, qIdx);
423
428
  }
424
429
  // Split off path (database).
425
430
  let database;
426
- const pIdx = rest.indexOf('/');
431
+ const pIdx = rest.indexOf("/");
427
432
  if (pIdx >= 0) {
428
433
  const pathRaw = rest.slice(pIdx + 1);
429
- database = pathRaw === '' ? undefined : decodePercent(pathRaw);
434
+ database = pathRaw === "" ? undefined : decodePercent(pathRaw);
430
435
  rest = rest.slice(0, pIdx);
431
436
  }
432
437
  // What's left is the authority: [userinfo@][host[:port]]
433
438
  let userinfo;
434
- const atIdx = rest.lastIndexOf('@');
439
+ const atIdx = rest.lastIndexOf("@");
435
440
  if (atIdx >= 0) {
436
441
  userinfo = rest.slice(0, atIdx);
437
442
  rest = rest.slice(atIdx + 1);
@@ -439,7 +444,7 @@ const tokenizeConnectionUri = (uri) => {
439
444
  let user;
440
445
  let password;
441
446
  if (userinfo !== undefined) {
442
- const colon = userinfo.indexOf(':');
447
+ const colon = userinfo.indexOf(":");
443
448
  if (colon >= 0) {
444
449
  user = decodePercent(userinfo.slice(0, colon));
445
450
  password = decodePercent(userinfo.slice(colon + 1));
@@ -490,22 +495,22 @@ const tokenizeConnectionUri = (uri) => {
490
495
  * treat as no-host)
491
496
  */
492
497
  const splitAuthorityTuples = (rest, uri) => {
493
- if (rest === '')
494
- return [''];
498
+ if (rest === "")
499
+ return [""];
495
500
  const tuples = [];
496
501
  let start = 0;
497
502
  let i = 0;
498
503
  while (i < rest.length) {
499
504
  const ch = rest[i];
500
- if (ch === '[') {
501
- const closeIdx = rest.indexOf(']', i);
505
+ if (ch === "[") {
506
+ const closeIdx = rest.indexOf("]", i);
502
507
  if (closeIdx < 0) {
503
508
  throw new Error(`missing matching "]" in IPv6 host address: ${uri}`);
504
509
  }
505
510
  i = closeIdx + 1;
506
511
  continue;
507
512
  }
508
- if (ch === ',') {
513
+ if (ch === ",") {
509
514
  tuples.push(rest.slice(start, i));
510
515
  i += 1;
511
516
  start = i;
@@ -517,26 +522,26 @@ const splitAuthorityTuples = (rest, uri) => {
517
522
  return tuples;
518
523
  };
519
524
  const parseAuthorityTuple = (tuple, uri) => {
520
- if (tuple === '')
525
+ if (tuple === "")
521
526
  return {};
522
- if (tuple.startsWith('[')) {
523
- const closeIdx = tuple.indexOf(']');
527
+ if (tuple.startsWith("[")) {
528
+ const closeIdx = tuple.indexOf("]");
524
529
  if (closeIdx < 0) {
525
530
  throw new Error(`missing matching "]" in IPv6 host address: ${uri}`);
526
531
  }
527
532
  const host = tuple.slice(1, closeIdx);
528
- if (host === '') {
533
+ if (host === "") {
529
534
  throw new Error(`IPv6 host address may not be empty: ${uri}`);
530
535
  }
531
536
  const after = tuple.slice(closeIdx + 1);
532
- if (after === '')
537
+ if (after === "")
533
538
  return { host };
534
- if (after.startsWith(':')) {
539
+ if (after.startsWith(":")) {
535
540
  return { host, port: after.slice(1) };
536
541
  }
537
542
  throw new Error(`unexpected characters after IPv6 host address in URI: ${uri}`);
538
543
  }
539
- const colon = tuple.indexOf(':');
544
+ const colon = tuple.indexOf(":");
540
545
  if (colon >= 0) {
541
546
  return {
542
547
  host: decodePercent(tuple.slice(0, colon)),
@@ -547,12 +552,12 @@ const parseAuthorityTuple = (tuple, uri) => {
547
552
  };
548
553
  const parseQuery = (raw) => {
549
554
  const out = new Map();
550
- if (raw === '')
555
+ if (raw === "")
551
556
  return out;
552
- for (const segment of raw.split('&')) {
553
- if (segment === '')
557
+ for (const segment of raw.split("&")) {
558
+ if (segment === "")
554
559
  continue;
555
- const eq = segment.indexOf('=');
560
+ const eq = segment.indexOf("=");
556
561
  if (eq < 0) {
557
562
  // libpq: every query parameter must be `key=value`. Bare keys (no `=`)
558
563
  // are rejected. Matches the upstream 001_uri.pl `?zzz` and
@@ -563,12 +568,12 @@ const parseQuery = (raw) => {
563
568
  const valueRaw = segment.slice(eq + 1);
564
569
  // libpq rejects an extra `=` in either key or value; matches the
565
570
  // `?key=key=value` upstream case.
566
- if (valueRaw.includes('=')) {
571
+ if (valueRaw.includes("=")) {
567
572
  throw new Error(`extra "=" in query parameter "${decodePercent(keyRaw).trim()}"`);
568
573
  }
569
574
  const key = decodePercent(keyRaw).trim();
570
575
  const value = decodePercent(valueRaw).trim();
571
- if (key === '')
576
+ if (key === "")
572
577
  continue;
573
578
  if (!KNOWN_QUERY_KEYS.has(key)) {
574
579
  throw new Error(`invalid URI query parameter: "${key}"`);
@@ -594,7 +599,7 @@ const decodePercent = (s) => {
594
599
  catch {
595
600
  throw new Error(`invalid percent-encoded token in URI: ${s}`);
596
601
  }
597
- if (decoded.includes('\x00')) {
602
+ if (decoded.includes("\x00")) {
598
603
  throw new Error(`forbidden NUL byte (%00) in URI: ${s}`);
599
604
  }
600
605
  return decoded;
@@ -602,11 +607,11 @@ const decodePercent = (s) => {
602
607
  export const parseConnectionUri = (uri) => {
603
608
  const raw = tokenizeConnectionUri(uri);
604
609
  // libpq-style: query string can override authority components.
605
- const queryUser = raw.query.get('user');
606
- const queryPassword = raw.query.get('password');
607
- const queryPort = raw.query.get('port');
608
- const queryDbname = raw.query.get('dbname');
609
- const queryHost = raw.query.get('host');
610
+ const queryUser = raw.query.get("user");
611
+ const queryPassword = raw.query.get("password");
612
+ const queryPort = raw.query.get("port");
613
+ const queryDbname = raw.query.get("dbname");
614
+ const queryHost = raw.query.get("host");
610
615
  // Multi-host: either from the authority (`h1,h2,h3:5434`) or from
611
616
  // `?host=h1,h2,h3&port=5432,5433,5434`. Query-string overrides authority
612
617
  // (matching libpq: query params take precedence over URI structural
@@ -621,55 +626,55 @@ export const parseConnectionUri = (uri) => {
621
626
  });
622
627
  // Single-host fallbacks (preserve current behaviour for the `host` / `port`
623
628
  // surface — the wire layer prefers `hosts` when set).
624
- const host = hostsTuples.length > 0 && hostsTuples[0].host !== ''
629
+ const host = hostsTuples.length > 0 && hostsTuples[0].host !== ""
625
630
  ? hostsTuples[0].host
626
- : 'localhost';
631
+ : "localhost";
627
632
  const port = hostsTuples.length > 0 ? hostsTuples[0].port : 5432;
628
- const user = queryUser !== undefined && queryUser !== ''
633
+ const user = queryUser !== undefined && queryUser !== ""
629
634
  ? queryUser
630
- : raw.user !== undefined && raw.user !== ''
635
+ : raw.user !== undefined && raw.user !== ""
631
636
  ? raw.user
632
- : (process.env.USER ?? '');
637
+ : (process.env.USER ?? "");
633
638
  const password = queryPassword ?? raw.password;
634
639
  const database = queryDbname ?? raw.database ?? user;
635
- let ssl = normalizeSslMode(raw.query.get('sslmode') ?? null);
636
- const channelBinding = normalizeChannelBinding(raw.query.get('channel_binding') ?? null);
640
+ let ssl = normalizeSslMode(raw.query.get("sslmode") ?? null);
641
+ const channelBinding = normalizeChannelBinding(raw.query.get("channel_binding") ?? null);
637
642
  // GSSAPI is unsupported (no native Kerberos dep); validate+reject require.
638
- validateGssEncMode(raw.query.get('gssencmode') ?? null);
639
- const options = raw.query.get('options');
643
+ validateGssEncMode(raw.query.get("gssencmode") ?? null);
644
+ const options = raw.query.get("options");
640
645
  // Match upstream psql: default `application_name` to `'psql'` so users see
641
646
  // the expected value in `pg_stat_activity`. The neonctl-specific identifier
642
647
  // is still discoverable via the User-Agent the protocol layer sends.
643
- const applicationName = raw.query.get('application_name') ?? 'psql';
644
- const replication = normalizeReplication(raw.query.get('replication') ?? null);
645
- const targetSessionAttrs = normalizeTargetSessionAttrs(raw.query.get('target_session_attrs') ?? null);
646
- const loadBalanceHosts = normalizeLoadBalanceHosts(raw.query.get('load_balance_hosts') ?? null);
648
+ const applicationName = raw.query.get("application_name") ?? "psql";
649
+ const replication = normalizeReplication(raw.query.get("replication") ?? null);
650
+ const targetSessionAttrs = normalizeTargetSessionAttrs(raw.query.get("target_session_attrs") ?? null);
651
+ const loadBalanceHosts = normalizeLoadBalanceHosts(raw.query.get("load_balance_hosts") ?? null);
647
652
  // libpq PEM file paths. Empty string is treated as "not set" so a URI
648
653
  // like `?sslcert=` doesn't surface as an attempt to load `""` from disk.
649
- const sslcert = nonEmpty(raw.query.get('sslcert'));
650
- const sslkey = nonEmpty(raw.query.get('sslkey'));
651
- const sslcertmode = normalizeSslCertMode(raw.query.get('sslcertmode') ?? null);
652
- const sslnegotiation = normalizeSslNegotiation(raw.query.get('sslnegotiation') ?? null);
653
- const sslrootcert = nonEmpty(raw.query.get('sslrootcert'));
654
- const sslcrl = nonEmpty(raw.query.get('sslcrl'));
655
- const sslcrldir = nonEmpty(raw.query.get('sslcrldir'));
656
- const sslkeylogfile = nonEmpty(raw.query.get('sslkeylogfile'));
654
+ const sslcert = nonEmpty(raw.query.get("sslcert"));
655
+ const sslkey = nonEmpty(raw.query.get("sslkey"));
656
+ const sslcertmode = normalizeSslCertMode(raw.query.get("sslcertmode") ?? null);
657
+ const sslnegotiation = normalizeSslNegotiation(raw.query.get("sslnegotiation") ?? null);
658
+ const sslrootcert = nonEmpty(raw.query.get("sslrootcert"));
659
+ const sslcrl = nonEmpty(raw.query.get("sslcrl"));
660
+ const sslcrldir = nonEmpty(raw.query.get("sslcrldir"));
661
+ const sslkeylogfile = nonEmpty(raw.query.get("sslkeylogfile"));
657
662
  // libpq sslsni / keepalives toggles (0/1) + keepalives_idle (seconds) +
658
663
  // requirepeer (OS user, validated but not enforceable in Node).
659
- const sslsni = parseLibpqBool(nonEmpty(raw.query.get('sslsni')));
660
- const keepalives = parseLibpqBool(nonEmpty(raw.query.get('keepalives')));
661
- const keepalivesIdle = parseKeepalivesIdle(nonEmpty(raw.query.get('keepalives_idle')));
662
- const requirepeer = nonEmpty(raw.query.get('requirepeer'));
664
+ const sslsni = parseLibpqBool(nonEmpty(raw.query.get("sslsni")));
665
+ const keepalives = parseLibpqBool(nonEmpty(raw.query.get("keepalives")));
666
+ const keepalivesIdle = parseKeepalivesIdle(nonEmpty(raw.query.get("keepalives_idle")));
667
+ const requirepeer = nonEmpty(raw.query.get("requirepeer"));
663
668
  // libpq: `sslrootcert=system` raises the effective sslmode to verify-full.
664
669
  // verify-full is the strongest mode, so this only ever raises it.
665
- if (sslrootcert === 'system' && ssl !== 'verify-full') {
666
- ssl = 'verify-full';
670
+ if (sslrootcert === "system" && ssl !== "verify-full") {
671
+ ssl = "verify-full";
667
672
  }
668
673
  // libpq `hostaddr`: a fixed IP that bypasses DNS while `host` still drives
669
674
  // TLS SNI / cert verification. Empty string is "not set".
670
- const hostaddr = nonEmpty(raw.query.get('hostaddr'));
671
- const sslMinProtocolVersion = normalizeTlsProtocolVersion(nonEmpty(raw.query.get('ssl_min_protocol_version')), 'ssl_min_protocol_version');
672
- const sslMaxProtocolVersion = normalizeTlsProtocolVersion(nonEmpty(raw.query.get('ssl_max_protocol_version')), 'ssl_max_protocol_version');
675
+ const hostaddr = nonEmpty(raw.query.get("hostaddr"));
676
+ const sslMinProtocolVersion = normalizeTlsProtocolVersion(nonEmpty(raw.query.get("ssl_min_protocol_version")), "ssl_min_protocol_version");
677
+ const sslMaxProtocolVersion = normalizeTlsProtocolVersion(nonEmpty(raw.query.get("ssl_max_protocol_version")), "ssl_max_protocol_version");
673
678
  assertTlsProtocolRange(sslMinProtocolVersion, sslMaxProtocolVersion);
674
679
  assertTlsMaxProtocolSupported(sslMaxProtocolVersion);
675
680
  // libpq rejects `sslnegotiation=direct` paired with a weak sslmode. The URI
@@ -690,7 +695,12 @@ export const parseConnectionUri = (uri) => {
690
695
  ...(hostaddr !== undefined ? { hostaddr } : {}),
691
696
  ...(replication !== undefined ? { replication } : {}),
692
697
  ...(hostsTuples.length > 1
693
- ? { hosts: hostsTuples.map((t) => ({ host: t.host, port: t.port })) }
698
+ ? {
699
+ hosts: hostsTuples.map((t) => ({
700
+ host: t.host,
701
+ port: t.port,
702
+ })),
703
+ }
694
704
  : {}),
695
705
  ...(targetSessionAttrs !== undefined ? { targetSessionAttrs } : {}),
696
706
  ...(loadBalanceHosts !== undefined ? { loadBalanceHosts } : {}),
@@ -705,8 +715,12 @@ export const parseConnectionUri = (uri) => {
705
715
  ...(keepalives !== undefined ? { keepalives } : {}),
706
716
  ...(keepalivesIdle !== undefined ? { keepalivesIdle } : {}),
707
717
  ...(requirepeer !== undefined ? { requirepeer } : {}),
708
- ...(sslMinProtocolVersion !== undefined ? { sslMinProtocolVersion } : {}),
709
- ...(sslMaxProtocolVersion !== undefined ? { sslMaxProtocolVersion } : {}),
718
+ ...(sslMinProtocolVersion !== undefined
719
+ ? { sslMinProtocolVersion }
720
+ : {}),
721
+ ...(sslMaxProtocolVersion !== undefined
722
+ ? { sslMaxProtocolVersion }
723
+ : {}),
710
724
  };
711
725
  };
712
726
  /**
@@ -716,18 +730,18 @@ export const parseConnectionUri = (uri) => {
716
730
  * unrecognised so the caller falls back to libpq's default (enabled).
717
731
  */
718
732
  const parseLibpqBool = (raw) => {
719
- if (raw === undefined || raw === '')
733
+ if (raw === undefined || raw === "")
720
734
  return undefined;
721
735
  switch (raw.toLowerCase()) {
722
- case '1':
723
- case 'true':
724
- case 'yes':
725
- case 'on':
736
+ case "1":
737
+ case "true":
738
+ case "yes":
739
+ case "on":
726
740
  return true;
727
- case '0':
728
- case 'false':
729
- case 'no':
730
- case 'off':
741
+ case "0":
742
+ case "false":
743
+ case "no":
744
+ case "off":
731
745
  return false;
732
746
  default:
733
747
  return undefined;
@@ -739,12 +753,12 @@ const parseLibpqBool = (raw) => {
739
753
  * milliseconds for `socket.setKeepAlive`'s `initialDelay`).
740
754
  */
741
755
  const parseKeepalivesIdle = (raw) => {
742
- if (raw === undefined || raw === '')
756
+ if (raw === undefined || raw === "")
743
757
  return undefined;
744
758
  const n = Number.parseInt(raw, 10);
745
759
  return Number.isFinite(n) && n >= 0 ? n : undefined;
746
760
  };
747
- const nonEmpty = (v) => v === undefined || v === '' ? undefined : v;
761
+ const nonEmpty = (v) => v === undefined || v === "" ? undefined : v;
748
762
  /**
749
763
  * Resolve the final {host, port}[] list for a URI:
750
764
  *
@@ -764,10 +778,10 @@ const computeHostsTuples = (input) => {
764
778
  // Case A: ?host=… overrides the authority host(s). Port resolution still
765
779
  // prefers `?port=` (if supplied), but falls back to the authority port so
766
780
  // e.g. `postgres://:12345?host=/path/to/socket` keeps `port=12345`.
767
- if (queryHost !== undefined && queryHost !== '') {
768
- const hosts = queryHost.split(',').map((h) => h.trim());
769
- const portList = queryPort !== undefined && queryPort !== ''
770
- ? queryPort.split(',').map((p) => p.trim())
781
+ if (queryHost !== undefined && queryHost !== "") {
782
+ const hosts = queryHost.split(",").map((h) => h.trim());
783
+ const portList = queryPort !== undefined && queryPort !== ""
784
+ ? queryPort.split(",").map((p) => p.trim())
771
785
  : null;
772
786
  if (portList !== null &&
773
787
  portList.length !== 1 &&
@@ -790,8 +804,8 @@ const computeHostsTuples = (input) => {
790
804
  // Case B: authority carried a comma-list (`postgresql://h1,h2:5433/db`).
791
805
  // Query-string `?port=` can still broadcast or pair with this list.
792
806
  if (rawAuthorityHosts !== undefined && rawAuthorityHosts.length > 0) {
793
- const portList = queryPort !== undefined && queryPort !== ''
794
- ? queryPort.split(',').map((p) => p.trim())
807
+ const portList = queryPort !== undefined && queryPort !== ""
808
+ ? queryPort.split(",").map((p) => p.trim())
795
809
  : null;
796
810
  if (portList !== null &&
797
811
  portList.length !== 1 &&
@@ -809,11 +823,11 @@ const computeHostsTuples = (input) => {
809
823
  }
810
824
  // Case C: single-host. Honour `?port=` (single value) if provided.
811
825
  const portStr = queryPort ?? rawPort;
812
- const host = rawHost !== undefined && rawHost !== '' ? rawHost : '';
826
+ const host = rawHost !== undefined && rawHost !== "" ? rawHost : "";
813
827
  return [{ host, port: parsePort(portStr) }];
814
828
  };
815
829
  const parsePort = (raw) => {
816
- if (raw === undefined || raw === '')
830
+ if (raw === undefined || raw === "")
817
831
  return 5432;
818
832
  // `Number.parseInt` silently tolerates trailing junk (`parseInt("12345 12")`
819
833
  // === 12345), which would let an internal-whitespace value like the upstream
@@ -862,15 +876,15 @@ export const parseConninfo = (input) => {
862
876
  break;
863
877
  // Parse key: chars up to `=` or whitespace.
864
878
  const keyStart = i;
865
- while (i < n && input[i] !== '=' && !/\s/.test(input[i]))
879
+ while (i < n && input[i] !== "=" && !/\s/.test(input[i]))
866
880
  i += 1;
867
881
  const key = input.slice(keyStart, i).toLowerCase();
868
- if (key === '')
882
+ if (key === "")
869
883
  break;
870
884
  // Skip whitespace before `=`.
871
885
  while (i < n && /\s/.test(input[i]))
872
886
  i += 1;
873
- if (i >= n || input[i] !== '=') {
887
+ if (i >= n || input[i] !== "=") {
874
888
  throw new Error(`missing "=" after "${key}" in conninfo string`);
875
889
  }
876
890
  i += 1; // consume `=`
@@ -884,7 +898,7 @@ export const parseConninfo = (input) => {
884
898
  i += 1; // consume opening quote
885
899
  const parts = [];
886
900
  while (i < n && input[i] !== "'") {
887
- if (input[i] === '\\' && i + 1 < n) {
901
+ if (input[i] === "\\" && i + 1 < n) {
888
902
  parts.push(input[i + 1]);
889
903
  i += 2;
890
904
  }
@@ -897,7 +911,7 @@ export const parseConninfo = (input) => {
897
911
  throw new Error(`unterminated single quote in conninfo string for key "${key}"`);
898
912
  }
899
913
  i += 1; // consume closing quote
900
- value = parts.join('');
914
+ value = parts.join("");
901
915
  }
902
916
  else {
903
917
  const valStart = i;
@@ -942,12 +956,12 @@ export const parseConninfo = (input) => {
942
956
  };
943
957
  const applyConninfoPair = (out, key, value) => {
944
958
  switch (key) {
945
- case 'host': {
959
+ case "host": {
946
960
  // Multi-host: `host=h1,h2,h3`. Store the list aside; the post-pass
947
961
  // (finalizeConninfo) materialises it into `hosts` + matches up against
948
962
  // any `port=p1,p2,p3` list.
949
- if (value.includes(',')) {
950
- out._hostList = value.split(',').map((h) => h.trim());
963
+ if (value.includes(",")) {
964
+ out._hostList = value.split(",").map((h) => h.trim());
951
965
  out.host = out._hostList[0];
952
966
  }
953
967
  else {
@@ -956,9 +970,9 @@ const applyConninfoPair = (out, key, value) => {
956
970
  }
957
971
  return;
958
972
  }
959
- case 'port': {
960
- if (value.includes(',')) {
961
- out._portList = value.split(',').map((p) => p.trim());
973
+ case "port": {
974
+ if (value.includes(",")) {
975
+ out._portList = value.split(",").map((p) => p.trim());
962
976
  // First port still goes into the scalar slot for back-compat.
963
977
  out.port = parsePort(out._portList[0]);
964
978
  }
@@ -968,160 +982,161 @@ const applyConninfoPair = (out, key, value) => {
968
982
  }
969
983
  return;
970
984
  }
971
- case 'user':
985
+ case "user":
972
986
  out.user = value;
973
987
  return;
974
- case 'password':
988
+ case "password":
975
989
  out.password = value;
976
990
  return;
977
- case 'dbname':
991
+ case "dbname":
978
992
  out.database = value;
979
993
  return;
980
- case 'application_name':
994
+ case "application_name":
981
995
  out.applicationName = value;
982
996
  return;
983
- case 'sslmode':
997
+ case "sslmode":
984
998
  out.ssl = normalizeSslMode(value);
985
999
  return;
986
- case 'channel_binding': {
1000
+ case "channel_binding": {
987
1001
  const cb = normalizeChannelBinding(value);
988
1002
  if (cb !== undefined)
989
1003
  out.channelBinding = cb;
990
1004
  return;
991
1005
  }
992
- case 'require_auth': {
1006
+ case "require_auth": {
993
1007
  const ra = normalizeRequireAuth(value);
994
1008
  if (ra !== undefined)
995
1009
  out.requireAuth = ra;
996
1010
  return;
997
1011
  }
998
- case 'connect_timeout': {
1012
+ case "connect_timeout": {
999
1013
  const t = Number.parseInt(value, 10);
1000
1014
  if (Number.isFinite(t) && t >= 0) {
1001
1015
  out.connectTimeoutMs = t * 1000;
1002
1016
  }
1003
1017
  return;
1004
1018
  }
1005
- case 'client_encoding':
1019
+ case "client_encoding":
1006
1020
  out.clientEncoding = value;
1007
1021
  return;
1008
- case 'options':
1022
+ case "options":
1009
1023
  out.options = value;
1010
1024
  return;
1011
- case 'replication': {
1025
+ case "replication": {
1012
1026
  const rep = normalizeReplication(value);
1013
1027
  if (rep !== undefined)
1014
1028
  out.replication = rep;
1015
1029
  return;
1016
1030
  }
1017
- case 'target_session_attrs': {
1031
+ case "target_session_attrs": {
1018
1032
  const tsa = normalizeTargetSessionAttrs(value);
1019
1033
  if (tsa !== undefined)
1020
1034
  out.targetSessionAttrs = tsa;
1021
1035
  return;
1022
1036
  }
1023
- case 'load_balance_hosts': {
1037
+ case "load_balance_hosts": {
1024
1038
  const lbh = normalizeLoadBalanceHosts(value);
1025
1039
  if (lbh !== undefined)
1026
1040
  out.loadBalanceHosts = lbh;
1027
1041
  return;
1028
1042
  }
1029
- case 'gssencmode':
1043
+ case "gssencmode":
1030
1044
  // Unsupported (no GSSAPI); accept disable/prefer, reject require.
1031
1045
  validateGssEncMode(value);
1032
1046
  return;
1033
- case 'sslcert':
1034
- if (value !== '')
1047
+ case "sslcert":
1048
+ if (value !== "")
1035
1049
  out.sslcert = value;
1036
1050
  return;
1037
- case 'sslkey':
1038
- if (value !== '')
1051
+ case "sslkey":
1052
+ if (value !== "")
1039
1053
  out.sslkey = value;
1040
1054
  return;
1041
- case 'sslcertmode': {
1055
+ case "sslcertmode": {
1042
1056
  const cm = normalizeSslCertMode(value);
1043
1057
  if (cm !== undefined)
1044
1058
  out.sslcertmode = cm;
1045
1059
  return;
1046
1060
  }
1047
- case 'sslnegotiation': {
1061
+ case "sslnegotiation": {
1048
1062
  const sn = normalizeSslNegotiation(value);
1049
1063
  if (sn !== undefined)
1050
1064
  out.sslnegotiation = sn;
1051
1065
  return;
1052
1066
  }
1053
- case 'sslrootcert':
1054
- if (value !== '')
1067
+ case "sslrootcert":
1068
+ if (value !== "")
1055
1069
  out.sslrootcert = value;
1056
1070
  return;
1057
- case 'sslcrl':
1058
- if (value !== '')
1071
+ case "sslcrl":
1072
+ if (value !== "")
1059
1073
  out.sslcrl = value;
1060
1074
  return;
1061
- case 'sslcrldir':
1062
- if (value !== '')
1075
+ case "sslcrldir":
1076
+ if (value !== "")
1063
1077
  out.sslcrldir = value;
1064
1078
  return;
1065
- case 'sslkeylogfile':
1066
- if (value !== '')
1079
+ case "sslkeylogfile":
1080
+ if (value !== "")
1067
1081
  out.sslkeylogfile = value;
1068
1082
  return;
1069
- case 'hostaddr':
1070
- if (value !== '')
1083
+ case "hostaddr":
1084
+ if (value !== "")
1071
1085
  out.hostaddr = value;
1072
1086
  return;
1073
- case 'ssl_min_protocol_version': {
1074
- const v = normalizeTlsProtocolVersion(value === '' ? undefined : value, 'ssl_min_protocol_version');
1087
+ case "ssl_min_protocol_version": {
1088
+ const v = normalizeTlsProtocolVersion(value === "" ? undefined : value, "ssl_min_protocol_version");
1075
1089
  if (v !== undefined)
1076
1090
  out.sslMinProtocolVersion = v;
1077
1091
  return;
1078
1092
  }
1079
- case 'ssl_max_protocol_version': {
1080
- const v = normalizeTlsProtocolVersion(value === '' ? undefined : value, 'ssl_max_protocol_version');
1093
+ case "ssl_max_protocol_version": {
1094
+ const v = normalizeTlsProtocolVersion(value === "" ? undefined : value, "ssl_max_protocol_version");
1081
1095
  if (v !== undefined)
1082
1096
  out.sslMaxProtocolVersion = v;
1083
1097
  return;
1084
1098
  }
1085
- case 'sslsni': {
1099
+ case "sslsni": {
1086
1100
  const b = parseLibpqBool(value);
1087
1101
  if (b !== undefined)
1088
1102
  out.sslsni = b;
1089
1103
  return;
1090
1104
  }
1091
- case 'keepalives': {
1105
+ case "keepalives": {
1092
1106
  const b = parseLibpqBool(value);
1093
1107
  if (b !== undefined)
1094
1108
  out.keepalives = b;
1095
1109
  return;
1096
1110
  }
1097
- case 'keepalives_idle': {
1111
+ case "keepalives_idle": {
1098
1112
  const n = parseKeepalivesIdle(value);
1099
1113
  if (n !== undefined)
1100
1114
  out.keepalivesIdle = n;
1101
1115
  return;
1102
1116
  }
1103
- case 'requirepeer':
1104
- if (value !== '')
1117
+ case "requirepeer":
1118
+ if (value !== "")
1105
1119
  out.requirepeer = value;
1106
1120
  return;
1107
1121
  // Recognised libpq keys that we don't model — accept silently so we
1108
1122
  // don't reject legitimate connection strings. keepalives_interval /
1109
1123
  // keepalives_count have no Node net API equivalent (setKeepAlive only
1110
1124
  // exposes enable + initial delay) — recognised but cannot be applied.
1111
- case 'passfile':
1112
- case 'sslcompression':
1113
- case 'krbsrvname':
1114
- case 'gsslib':
1115
- case 'fallback_application_name':
1116
- case 'keepalives_interval':
1117
- case 'keepalives_count':
1125
+ case "passfile":
1126
+ case "sslcompression":
1127
+ case "krbsrvname":
1128
+ case "gsslib":
1129
+ case "fallback_application_name":
1130
+ case "keepalives_interval":
1131
+ case "keepalives_count":
1118
1132
  return;
1119
- case 'service': {
1133
+ case "service": {
1120
1134
  // Service name is NOT a ConnectOptions field — it's resolved by
1121
1135
  // the layered connect resolver in `core/startup.ts`. Stash it on
1122
1136
  // a private staging slot so the caller (`runPsql`) can extract it
1123
1137
  // alongside the URI-side `?service=…` parser.
1124
- out._service = value;
1138
+ out._service =
1139
+ value;
1125
1140
  return;
1126
1141
  }
1127
1142
  default:
@@ -1134,12 +1149,12 @@ const applyConninfoPair = (out, key, value) => {
1134
1149
  * `recognized_connection_string()` test.
1135
1150
  */
1136
1151
  export const looksLikeConnectionString = (s) => {
1137
- if (s.startsWith('postgresql://') || s.startsWith('postgres://'))
1152
+ if (s.startsWith("postgresql://") || s.startsWith("postgres://"))
1138
1153
  return true;
1139
1154
  // A bare key=value pair (or several) — conninfo. We require the `=` to
1140
1155
  // appear before any whitespace so values like "weird name" (a bareword
1141
1156
  // database name with a space) don't get misclassified.
1142
- const eq = s.indexOf('=');
1157
+ const eq = s.indexOf("=");
1143
1158
  if (eq < 0)
1144
1159
  return false;
1145
1160
  const head = s.slice(0, eq);
@@ -1152,15 +1167,15 @@ const normalizeSslMode = (raw) => {
1152
1167
  // downgrade. Mirrors libpq's `invalid sslmode value: "..."` and every
1153
1168
  // sibling validator (normalizeChannelBinding, normalizeSslCertMode, …).
1154
1169
  if (raw === null)
1155
- return 'prefer';
1170
+ return "prefer";
1156
1171
  const value = raw.toLowerCase();
1157
1172
  switch (value) {
1158
- case 'disable':
1159
- case 'allow':
1160
- case 'prefer':
1161
- case 'require':
1162
- case 'verify-ca':
1163
- case 'verify-full':
1173
+ case "disable":
1174
+ case "allow":
1175
+ case "prefer":
1176
+ case "require":
1177
+ case "verify-ca":
1178
+ case "verify-full":
1164
1179
  return value;
1165
1180
  default:
1166
1181
  throw new Error(`invalid sslmode value: "${raw}"`);
@@ -1173,14 +1188,14 @@ const normalizeSslMode = (raw) => {
1173
1188
  * keep the canonical mixed-case spelling Node's `tls` module expects for
1174
1189
  * `minVersion` / `maxVersion`.
1175
1190
  */
1176
- const TLS_PROTOCOL_VERSIONS = ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'];
1191
+ const TLS_PROTOCOL_VERSIONS = ["TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"];
1177
1192
  /**
1178
1193
  * Validate and canonicalise a `ssl_{min,max}_protocol_version` value. Returns
1179
1194
  * the canonical spelling (`TLSv1.2` etc.) or `undefined` for empty / unset.
1180
1195
  * Throws libpq's `invalid <key> value: "<raw>"` wording on a malformed value.
1181
1196
  */
1182
1197
  const normalizeTlsProtocolVersion = (raw, key) => {
1183
- if (raw === undefined || raw === '')
1198
+ if (raw === undefined || raw === "")
1184
1199
  return undefined;
1185
1200
  const match = TLS_PROTOCOL_VERSIONS.find((v) => v.toLowerCase() === raw.toLowerCase());
1186
1201
  if (match === undefined) {
@@ -1201,7 +1216,7 @@ const normalizeTlsProtocolVersion = (raw, key) => {
1201
1216
  * libpq's ordering.
1202
1217
  */
1203
1218
  const assertTlsMaxProtocolSupported = (max) => {
1204
- if (max === 'TLSv1' || max === 'TLSv1.1') {
1219
+ if (max === "TLSv1" || max === "TLSv1.1") {
1205
1220
  throw new Error(`ssl_max_protocol_version "${max}" is not supported by this ` +
1206
1221
  `runtime's TLS library — TLS 1.0/1.1 are disabled in Node's OpenSSL; ` +
1207
1222
  `the minimum negotiable version is TLSv1.2`);
@@ -1222,13 +1237,13 @@ const assertTlsProtocolRange = (min, max) => {
1222
1237
  }
1223
1238
  };
1224
1239
  const normalizeChannelBinding = (raw) => {
1225
- if (raw === null || raw === '')
1240
+ if (raw === null || raw === "")
1226
1241
  return undefined;
1227
1242
  const value = raw.toLowerCase();
1228
1243
  switch (value) {
1229
- case 'disable':
1230
- case 'prefer':
1231
- case 'require':
1244
+ case "disable":
1245
+ case "prefer":
1246
+ case "require":
1232
1247
  return value;
1233
1248
  default:
1234
1249
  // Mirror libpq's `invalid channel_binding value: "<raw>"`
@@ -1255,13 +1270,13 @@ const normalizeChannelBinding = (raw) => {
1255
1270
  * working against Neon.
1256
1271
  */
1257
1272
  const validateGssEncMode = (raw) => {
1258
- if (raw === null || raw === '')
1273
+ if (raw === null || raw === "")
1259
1274
  return;
1260
1275
  const value = raw.toLowerCase();
1261
- if (value === 'disable' || value === 'prefer')
1276
+ if (value === "disable" || value === "prefer")
1262
1277
  return;
1263
- if (value === 'require') {
1264
- throw new Error('gssencmode=require is not supported: this client has no GSSAPI support');
1278
+ if (value === "require") {
1279
+ throw new Error("gssencmode=require is not supported: this client has no GSSAPI support");
1265
1280
  }
1266
1281
  throw new Error(`invalid gssencmode value: "${raw}"`);
1267
1282
  };
@@ -1272,13 +1287,13 @@ const validateGssEncMode = (raw) => {
1272
1287
  * `invalid sslcertmode value: "<raw>"` diagnostic.
1273
1288
  */
1274
1289
  const normalizeSslCertMode = (raw) => {
1275
- if (raw === null || raw === '')
1290
+ if (raw === null || raw === "")
1276
1291
  return undefined;
1277
1292
  const value = raw.toLowerCase();
1278
1293
  switch (value) {
1279
- case 'disable':
1280
- case 'allow':
1281
- case 'require':
1294
+ case "disable":
1295
+ case "allow":
1296
+ case "require":
1282
1297
  return value;
1283
1298
  default:
1284
1299
  throw new Error(`invalid sslcertmode value: "${raw}"`);
@@ -1291,12 +1306,12 @@ const normalizeSslCertMode = (raw) => {
1291
1306
  * `invalid sslnegotiation value: "<raw>"` diagnostic.
1292
1307
  */
1293
1308
  const normalizeSslNegotiation = (raw) => {
1294
- if (raw === null || raw === '')
1309
+ if (raw === null || raw === "")
1295
1310
  return undefined;
1296
1311
  const value = raw.toLowerCase();
1297
1312
  switch (value) {
1298
- case 'postgres':
1299
- case 'direct':
1313
+ case "postgres":
1314
+ case "direct":
1300
1315
  return value;
1301
1316
  default:
1302
1317
  throw new Error(`invalid sslnegotiation value: "${raw}"`);
@@ -1310,21 +1325,21 @@ const normalizeSslNegotiation = (raw) => {
1310
1325
  * exact `pqConnectOptions2` wording. No-op unless `sslnegotiation` is `direct`.
1311
1326
  */
1312
1327
  const assertSslNegotiationModeCompatible = (ssl, sslnegotiation) => {
1313
- if (sslnegotiation !== 'direct')
1328
+ if (sslnegotiation !== "direct")
1314
1329
  return;
1315
- if (ssl === 'require' || ssl === 'verify-ca' || ssl === 'verify-full') {
1330
+ if (ssl === "require" || ssl === "verify-ca" || ssl === "verify-full") {
1316
1331
  return;
1317
1332
  }
1318
1333
  throw new Error(`weak sslmode "${ssl}" may not be used with sslnegotiation=direct`);
1319
1334
  };
1320
1335
  const VALID_REQUIRE_AUTH_METHODS = new Set([
1321
- 'password',
1322
- 'md5',
1323
- 'gss',
1324
- 'sspi',
1325
- 'scram-sha-256',
1326
- 'creds',
1327
- 'none',
1336
+ "password",
1337
+ "md5",
1338
+ "gss",
1339
+ "sspi",
1340
+ "scram-sha-256",
1341
+ "creds",
1342
+ "none",
1328
1343
  ]);
1329
1344
  /**
1330
1345
  * Parse libpq's `require_auth` value: a comma-separated list of method
@@ -1336,10 +1351,10 @@ const VALID_REQUIRE_AUTH_METHODS = new Set([
1336
1351
  * outer `psql: error: ...` channel.
1337
1352
  */
1338
1353
  const normalizeRequireAuth = (raw) => {
1339
- if (raw === null || raw === '')
1354
+ if (raw === null || raw === "")
1340
1355
  return undefined;
1341
1356
  const tokens = raw
1342
- .split(',')
1357
+ .split(",")
1343
1358
  .map((s) => s.trim())
1344
1359
  .filter((s) => s.length > 0);
1345
1360
  if (tokens.length === 0)
@@ -1347,7 +1362,7 @@ const normalizeRequireAuth = (raw) => {
1347
1362
  const methods = new Set();
1348
1363
  let polarity = null;
1349
1364
  for (const token of tokens) {
1350
- const isNeg = token.startsWith('!');
1365
+ const isNeg = token.startsWith("!");
1351
1366
  const name = (isNeg ? token.slice(1) : token).toLowerCase();
1352
1367
  if (!VALID_REQUIRE_AUTH_METHODS.has(name)) {
1353
1368
  throw new Error(`invalid require_auth method: "${token}"`);
@@ -1358,7 +1373,7 @@ const normalizeRequireAuth = (raw) => {
1358
1373
  else if (polarity !== isNeg) {
1359
1374
  // libpq wording: "negative require_auth method ... cannot be mixed
1360
1375
  // with non-negative methods". We use a slightly shorter form here.
1361
- throw new Error('require_auth methods cannot mix positive and negative entries');
1376
+ throw new Error("require_auth methods cannot mix positive and negative entries");
1362
1377
  }
1363
1378
  methods.add(name);
1364
1379
  }
@@ -1372,16 +1387,16 @@ const normalizeRequireAuth = (raw) => {
1372
1387
  * applies. Throws on unrecognised values, matching libpq behaviour.
1373
1388
  */
1374
1389
  const normalizeTargetSessionAttrs = (raw) => {
1375
- if (raw === null || raw === '')
1390
+ if (raw === null || raw === "")
1376
1391
  return undefined;
1377
1392
  const value = raw.toLowerCase();
1378
1393
  switch (value) {
1379
- case 'any':
1380
- case 'read-write':
1381
- case 'read-only':
1382
- case 'primary':
1383
- case 'standby':
1384
- case 'prefer-standby':
1394
+ case "any":
1395
+ case "read-write":
1396
+ case "read-only":
1397
+ case "primary":
1398
+ case "standby":
1399
+ case "prefer-standby":
1385
1400
  return value;
1386
1401
  default:
1387
1402
  throw new Error(`invalid value for "target_session_attrs": "${raw}"`);
@@ -1396,10 +1411,10 @@ const normalizeTargetSessionAttrs = (raw) => {
1396
1411
  * default ('disable') applies.
1397
1412
  */
1398
1413
  const normalizeLoadBalanceHosts = (raw) => {
1399
- if (raw === null || raw === '')
1414
+ if (raw === null || raw === "")
1400
1415
  return undefined;
1401
1416
  const value = raw.toLowerCase();
1402
- if (value === 'disable' || value === 'random')
1417
+ if (value === "disable" || value === "random")
1403
1418
  return value;
1404
1419
  throw new Error(`invalid value for "load_balance_hosts": "${raw}"`);
1405
1420
  };
@@ -1415,15 +1430,21 @@ const normalizeLoadBalanceHosts = (raw) => {
1415
1430
  * silently sending an unexpected startup-message parameter).
1416
1431
  */
1417
1432
  const normalizeReplication = (raw) => {
1418
- if (raw === null || raw === '')
1433
+ if (raw === null || raw === "")
1419
1434
  return undefined;
1420
1435
  const value = raw.toLowerCase();
1421
- if (value === 'database')
1422
- return 'database';
1423
- if (value === 'true' || value === 'on' || value === 'yes' || value === '1') {
1424
- return 'true';
1425
- }
1426
- if (value === 'false' || value === 'off' || value === 'no' || value === '0') {
1436
+ if (value === "database")
1437
+ return "database";
1438
+ if (value === "true" ||
1439
+ value === "on" ||
1440
+ value === "yes" ||
1441
+ value === "1") {
1442
+ return "true";
1443
+ }
1444
+ if (value === "false" ||
1445
+ value === "off" ||
1446
+ value === "no" ||
1447
+ value === "0") {
1427
1448
  return undefined;
1428
1449
  }
1429
1450
  throw new Error(`invalid value for "replication": "${raw}"`);
@@ -1455,8 +1476,8 @@ const normalizeReplication = (raw) => {
1455
1476
  */
1456
1477
  export const parseConnectionUriService = (uri) => {
1457
1478
  const raw = tokenizeConnectionUri(uri);
1458
- const value = raw.query.get('service');
1459
- return value === undefined || value === '' ? undefined : value;
1479
+ const value = raw.query.get("service");
1480
+ return value === undefined || value === "" ? undefined : value;
1460
1481
  };
1461
1482
  /**
1462
1483
  * Parse a URI into a `Partial<ConnectOptions>` containing only the fields
@@ -1475,11 +1496,11 @@ export const parseConnectionUriService = (uri) => {
1475
1496
  */
1476
1497
  export const parseConnectionUriPartial = (uri) => {
1477
1498
  const raw = tokenizeConnectionUri(uri);
1478
- const queryUser = raw.query.get('user');
1479
- const queryPassword = raw.query.get('password');
1480
- const queryPort = raw.query.get('port');
1481
- const queryDbname = raw.query.get('dbname');
1482
- const queryHost = raw.query.get('host');
1499
+ const queryUser = raw.query.get("user");
1500
+ const queryPassword = raw.query.get("password");
1501
+ const queryPort = raw.query.get("port");
1502
+ const queryDbname = raw.query.get("dbname");
1503
+ const queryHost = raw.query.get("host");
1483
1504
  // Multi-host: same resolution as the full parser, but we treat its absence
1484
1505
  // as "URI didn't say anything about hosts" rather than synthesising a
1485
1506
  // localhost default.
@@ -1497,26 +1518,30 @@ export const parseConnectionUriPartial = (uri) => {
1497
1518
  // about a port" so the service-file's port wins when we layer this
1498
1519
  // partial above the service layer. Mirrors libpq's behaviour for
1499
1520
  // `006_service.pl`'s `postgres:///?service=…` cases.
1500
- const portInUri = (raw.port !== undefined && raw.port !== '') ||
1501
- (queryPort !== undefined && queryPort !== '') ||
1502
- (raw.hosts?.some((t) => t.port !== undefined && t.port !== '') ?? false);
1521
+ const portInUri = (raw.port !== undefined && raw.port !== "") ||
1522
+ (queryPort !== undefined && queryPort !== "") ||
1523
+ (raw.hosts?.some((t) => t.port !== undefined && t.port !== "") ??
1524
+ false);
1503
1525
  const out = {};
1504
1526
  if (hostsTuples.length > 0) {
1505
1527
  // First tuple drives the single-host surface; the full multi-host list
1506
1528
  // is included only when the URI specified more than one. An empty-host
1507
1529
  // tuple (e.g. `postgres://:12345/`) means "explicit port, no host" —
1508
1530
  // we record the port but leave host to the next layer.
1509
- if (hostsTuples[0].host !== '')
1531
+ if (hostsTuples[0].host !== "")
1510
1532
  out.host = hostsTuples[0].host;
1511
1533
  if (portInUri && hostsTuples[0].port !== 0)
1512
1534
  out.port = hostsTuples[0].port;
1513
1535
  if (hostsTuples.length > 1) {
1514
- out.hosts = hostsTuples.map((t) => ({ host: t.host, port: t.port }));
1536
+ out.hosts = hostsTuples.map((t) => ({
1537
+ host: t.host,
1538
+ port: t.port,
1539
+ }));
1515
1540
  }
1516
1541
  }
1517
- const userExplicit = queryUser !== undefined && queryUser !== ''
1542
+ const userExplicit = queryUser !== undefined && queryUser !== ""
1518
1543
  ? queryUser
1519
- : raw.user !== undefined && raw.user !== ''
1544
+ : raw.user !== undefined && raw.user !== ""
1520
1545
  ? raw.user
1521
1546
  : undefined;
1522
1547
  if (userExplicit !== undefined)
@@ -1527,87 +1552,87 @@ export const parseConnectionUriPartial = (uri) => {
1527
1552
  const database = queryDbname ?? raw.database;
1528
1553
  if (database !== undefined)
1529
1554
  out.database = database;
1530
- const sslRaw = raw.query.get('sslmode');
1531
- if (sslRaw !== undefined && sslRaw !== '') {
1555
+ const sslRaw = raw.query.get("sslmode");
1556
+ if (sslRaw !== undefined && sslRaw !== "") {
1532
1557
  out.ssl = normalizeSslMode(sslRaw);
1533
1558
  }
1534
- const cb = normalizeChannelBinding(raw.query.get('channel_binding') ?? null);
1559
+ const cb = normalizeChannelBinding(raw.query.get("channel_binding") ?? null);
1535
1560
  if (cb !== undefined)
1536
1561
  out.channelBinding = cb;
1537
- const ra = normalizeRequireAuth(raw.query.get('require_auth') ?? null);
1562
+ const ra = normalizeRequireAuth(raw.query.get("require_auth") ?? null);
1538
1563
  if (ra !== undefined)
1539
1564
  out.requireAuth = ra;
1540
- const options = raw.query.get('options');
1541
- if (options !== undefined && options !== '')
1565
+ const options = raw.query.get("options");
1566
+ if (options !== undefined && options !== "")
1542
1567
  out.options = options;
1543
- const appName = raw.query.get('application_name');
1544
- if (appName !== undefined && appName !== '')
1568
+ const appName = raw.query.get("application_name");
1569
+ if (appName !== undefined && appName !== "")
1545
1570
  out.applicationName = appName;
1546
- const replication = normalizeReplication(raw.query.get('replication') ?? null);
1571
+ const replication = normalizeReplication(raw.query.get("replication") ?? null);
1547
1572
  if (replication !== undefined)
1548
1573
  out.replication = replication;
1549
- const targetSessionAttrs = normalizeTargetSessionAttrs(raw.query.get('target_session_attrs') ?? null);
1574
+ const targetSessionAttrs = normalizeTargetSessionAttrs(raw.query.get("target_session_attrs") ?? null);
1550
1575
  if (targetSessionAttrs !== undefined) {
1551
1576
  out.targetSessionAttrs = targetSessionAttrs;
1552
1577
  }
1553
- const loadBalanceHosts = normalizeLoadBalanceHosts(raw.query.get('load_balance_hosts') ?? null);
1578
+ const loadBalanceHosts = normalizeLoadBalanceHosts(raw.query.get("load_balance_hosts") ?? null);
1554
1579
  if (loadBalanceHosts !== undefined)
1555
1580
  out.loadBalanceHosts = loadBalanceHosts;
1556
- const sslcert = nonEmpty(raw.query.get('sslcert'));
1581
+ const sslcert = nonEmpty(raw.query.get("sslcert"));
1557
1582
  if (sslcert !== undefined)
1558
1583
  out.sslcert = sslcert;
1559
- const sslkey = nonEmpty(raw.query.get('sslkey'));
1584
+ const sslkey = nonEmpty(raw.query.get("sslkey"));
1560
1585
  if (sslkey !== undefined)
1561
1586
  out.sslkey = sslkey;
1562
- const sslcertmode = normalizeSslCertMode(raw.query.get('sslcertmode') ?? null);
1587
+ const sslcertmode = normalizeSslCertMode(raw.query.get("sslcertmode") ?? null);
1563
1588
  if (sslcertmode !== undefined)
1564
1589
  out.sslcertmode = sslcertmode;
1565
- const sslnegotiation = normalizeSslNegotiation(raw.query.get('sslnegotiation') ?? null);
1590
+ const sslnegotiation = normalizeSslNegotiation(raw.query.get("sslnegotiation") ?? null);
1566
1591
  if (sslnegotiation !== undefined)
1567
1592
  out.sslnegotiation = sslnegotiation;
1568
- const sslrootcert = nonEmpty(raw.query.get('sslrootcert'));
1593
+ const sslrootcert = nonEmpty(raw.query.get("sslrootcert"));
1569
1594
  if (sslrootcert !== undefined)
1570
1595
  out.sslrootcert = sslrootcert;
1571
- const sslcrl = nonEmpty(raw.query.get('sslcrl'));
1596
+ const sslcrl = nonEmpty(raw.query.get("sslcrl"));
1572
1597
  if (sslcrl !== undefined)
1573
1598
  out.sslcrl = sslcrl;
1574
- const sslcrldir = nonEmpty(raw.query.get('sslcrldir'));
1599
+ const sslcrldir = nonEmpty(raw.query.get("sslcrldir"));
1575
1600
  if (sslcrldir !== undefined)
1576
1601
  out.sslcrldir = sslcrldir;
1577
- const sslkeylogfile = nonEmpty(raw.query.get('sslkeylogfile'));
1602
+ const sslkeylogfile = nonEmpty(raw.query.get("sslkeylogfile"));
1578
1603
  if (sslkeylogfile !== undefined)
1579
1604
  out.sslkeylogfile = sslkeylogfile;
1580
- const sslsni = parseLibpqBool(nonEmpty(raw.query.get('sslsni')));
1605
+ const sslsni = parseLibpqBool(nonEmpty(raw.query.get("sslsni")));
1581
1606
  if (sslsni !== undefined)
1582
1607
  out.sslsni = sslsni;
1583
- const keepalives = parseLibpqBool(nonEmpty(raw.query.get('keepalives')));
1608
+ const keepalives = parseLibpqBool(nonEmpty(raw.query.get("keepalives")));
1584
1609
  if (keepalives !== undefined)
1585
1610
  out.keepalives = keepalives;
1586
- const keepalivesIdle = parseKeepalivesIdle(nonEmpty(raw.query.get('keepalives_idle')));
1611
+ const keepalivesIdle = parseKeepalivesIdle(nonEmpty(raw.query.get("keepalives_idle")));
1587
1612
  if (keepalivesIdle !== undefined)
1588
1613
  out.keepalivesIdle = keepalivesIdle;
1589
- const requirepeer = nonEmpty(raw.query.get('requirepeer'));
1614
+ const requirepeer = nonEmpty(raw.query.get("requirepeer"));
1590
1615
  if (requirepeer !== undefined)
1591
1616
  out.requirepeer = requirepeer;
1592
- const hostaddr = nonEmpty(raw.query.get('hostaddr'));
1617
+ const hostaddr = nonEmpty(raw.query.get("hostaddr"));
1593
1618
  if (hostaddr !== undefined)
1594
1619
  out.hostaddr = hostaddr;
1595
- const sslMin = normalizeTlsProtocolVersion(nonEmpty(raw.query.get('ssl_min_protocol_version')), 'ssl_min_protocol_version');
1620
+ const sslMin = normalizeTlsProtocolVersion(nonEmpty(raw.query.get("ssl_min_protocol_version")), "ssl_min_protocol_version");
1596
1621
  if (sslMin !== undefined)
1597
1622
  out.sslMinProtocolVersion = sslMin;
1598
- const sslMax = normalizeTlsProtocolVersion(nonEmpty(raw.query.get('ssl_max_protocol_version')), 'ssl_max_protocol_version');
1623
+ const sslMax = normalizeTlsProtocolVersion(nonEmpty(raw.query.get("ssl_max_protocol_version")), "ssl_max_protocol_version");
1599
1624
  if (sslMax !== undefined)
1600
1625
  out.sslMaxProtocolVersion = sslMax;
1601
1626
  assertTlsProtocolRange(out.sslMinProtocolVersion, out.sslMaxProtocolVersion);
1602
1627
  assertTlsMaxProtocolSupported(out.sslMaxProtocolVersion);
1603
- const connectTimeoutSec = raw.query.get('connect_timeout');
1604
- if (connectTimeoutSec !== undefined && connectTimeoutSec !== '') {
1628
+ const connectTimeoutSec = raw.query.get("connect_timeout");
1629
+ if (connectTimeoutSec !== undefined && connectTimeoutSec !== "") {
1605
1630
  const t = Number.parseInt(connectTimeoutSec, 10);
1606
1631
  if (Number.isFinite(t) && t >= 0)
1607
1632
  out.connectTimeoutMs = t * 1000;
1608
1633
  }
1609
- const clientEncoding = raw.query.get('client_encoding');
1610
- if (clientEncoding !== undefined && clientEncoding !== '') {
1634
+ const clientEncoding = raw.query.get("client_encoding");
1635
+ if (clientEncoding !== undefined && clientEncoding !== "") {
1611
1636
  out.clientEncoding = clientEncoding;
1612
1637
  }
1613
1638
  return out;
@@ -1615,25 +1640,25 @@ export const parseConnectionUriPartial = (uri) => {
1615
1640
  // Field map for PG* env vars. Order in the table is documentation; resolution
1616
1641
  // only depends on whether the var is set.
1617
1642
  const PG_ENV_FIELD_MAP = {
1618
- PGHOST: 'host',
1619
- PGHOSTADDR: 'hostaddr',
1620
- PGPORT: 'port',
1621
- PGUSER: 'user',
1622
- PGDATABASE: 'database',
1623
- PGPASSWORD: 'password',
1624
- PGAPPNAME: 'applicationName',
1625
- PGOPTIONS: 'options',
1626
- PGCLIENTENCODING: 'clientEncoding',
1627
- PGSSLMODE: 'ssl',
1628
- PGSSLROOTCERT: 'sslrootcert',
1629
- PGSSLCERT: 'sslcert',
1630
- PGSSLKEY: 'sslkey',
1631
- PGSSLCERTMODE: 'sslcertmode',
1632
- PGSSLNEGOTIATION: 'sslnegotiation',
1633
- PGSSLCRL: 'sslcrl',
1634
- PGSSLCRLDIR: 'sslcrldir',
1635
- PGSSLKEYLOGFILE: 'sslkeylogfile',
1636
- PGCHANNELBINDING: 'channelBinding',
1643
+ PGHOST: "host",
1644
+ PGHOSTADDR: "hostaddr",
1645
+ PGPORT: "port",
1646
+ PGUSER: "user",
1647
+ PGDATABASE: "database",
1648
+ PGPASSWORD: "password",
1649
+ PGAPPNAME: "applicationName",
1650
+ PGOPTIONS: "options",
1651
+ PGCLIENTENCODING: "clientEncoding",
1652
+ PGSSLMODE: "ssl",
1653
+ PGSSLROOTCERT: "sslrootcert",
1654
+ PGSSLCERT: "sslcert",
1655
+ PGSSLKEY: "sslkey",
1656
+ PGSSLCERTMODE: "sslcertmode",
1657
+ PGSSLNEGOTIATION: "sslnegotiation",
1658
+ PGSSLCRL: "sslcrl",
1659
+ PGSSLCRLDIR: "sslcrldir",
1660
+ PGSSLKEYLOGFILE: "sslkeylogfile",
1661
+ PGCHANNELBINDING: "channelBinding",
1637
1662
  };
1638
1663
  /**
1639
1664
  * Resolve the PG* env vars into a `Partial<ConnectOptions>`. Only set keys
@@ -1660,7 +1685,7 @@ export const envConnectionDefaults = (env) => {
1660
1685
  const out = {};
1661
1686
  const get = (k) => {
1662
1687
  const v = env[k];
1663
- return v !== undefined && v !== '' ? v : undefined;
1688
+ return v !== undefined && v !== "" ? v : undefined;
1664
1689
  };
1665
1690
  for (const [envName, field] of Object.entries(PG_ENV_FIELD_MAP)) {
1666
1691
  const value = get(envName);
@@ -1668,7 +1693,7 @@ export const envConnectionDefaults = (env) => {
1668
1693
  continue;
1669
1694
  applyEnvValue(out, field, value);
1670
1695
  }
1671
- const timeoutRaw = get('PGCONNECT_TIMEOUT');
1696
+ const timeoutRaw = get("PGCONNECT_TIMEOUT");
1672
1697
  if (timeoutRaw !== undefined) {
1673
1698
  const t = Number.parseInt(timeoutRaw, 10);
1674
1699
  if (Number.isFinite(t) && t >= 0)
@@ -1676,75 +1701,75 @@ export const envConnectionDefaults = (env) => {
1676
1701
  }
1677
1702
  // GSSAPI is unsupported; PGGSSENCMODE=require is rejected, disable/prefer
1678
1703
  // accepted-and-ignored. Same contract as the URI/conninfo `gssencmode`.
1679
- validateGssEncMode(get('PGGSSENCMODE') ?? null);
1704
+ validateGssEncMode(get("PGGSSENCMODE") ?? null);
1680
1705
  return out;
1681
1706
  };
1682
1707
  const applyEnvValue = (out, field, value) => {
1683
1708
  switch (field) {
1684
- case 'host':
1709
+ case "host":
1685
1710
  out.host = value;
1686
1711
  return;
1687
- case 'port': {
1712
+ case "port": {
1688
1713
  const p = Number.parseInt(value, 10);
1689
1714
  if (Number.isFinite(p) && p > 0 && p <= 65535)
1690
1715
  out.port = p;
1691
1716
  return;
1692
1717
  }
1693
- case 'user':
1718
+ case "user":
1694
1719
  out.user = value;
1695
1720
  return;
1696
- case 'database':
1721
+ case "database":
1697
1722
  out.database = value;
1698
1723
  return;
1699
- case 'password':
1724
+ case "password":
1700
1725
  out.password = value;
1701
1726
  return;
1702
- case 'applicationName':
1727
+ case "applicationName":
1703
1728
  out.applicationName = value;
1704
1729
  return;
1705
- case 'options':
1730
+ case "options":
1706
1731
  out.options = value;
1707
1732
  return;
1708
- case 'clientEncoding':
1733
+ case "clientEncoding":
1709
1734
  out.clientEncoding = value;
1710
1735
  return;
1711
- case 'ssl':
1736
+ case "ssl":
1712
1737
  out.ssl = normalizeSslMode(value);
1713
1738
  return;
1714
- case 'sslrootcert':
1739
+ case "sslrootcert":
1715
1740
  out.sslrootcert = value;
1716
1741
  return;
1717
- case 'sslcert':
1742
+ case "sslcert":
1718
1743
  out.sslcert = value;
1719
1744
  return;
1720
- case 'sslkey':
1745
+ case "sslkey":
1721
1746
  out.sslkey = value;
1722
1747
  return;
1723
- case 'sslcertmode': {
1748
+ case "sslcertmode": {
1724
1749
  const cm = normalizeSslCertMode(value);
1725
1750
  if (cm !== undefined)
1726
1751
  out.sslcertmode = cm;
1727
1752
  return;
1728
1753
  }
1729
- case 'sslnegotiation': {
1754
+ case "sslnegotiation": {
1730
1755
  const sn = normalizeSslNegotiation(value);
1731
1756
  if (sn !== undefined)
1732
1757
  out.sslnegotiation = sn;
1733
1758
  return;
1734
1759
  }
1735
- case 'sslcrl':
1760
+ case "sslcrl":
1736
1761
  out.sslcrl = value;
1737
1762
  return;
1738
- case 'sslcrldir':
1763
+ case "sslcrldir":
1739
1764
  out.sslcrldir = value;
1740
1765
  return;
1741
- case 'sslkeylogfile':
1766
+ case "sslkeylogfile":
1742
1767
  out.sslkeylogfile = value;
1743
1768
  return;
1744
- case 'hostaddr':
1769
+ case "hostaddr":
1745
1770
  out.hostaddr = value;
1746
1771
  return;
1747
- case 'channelBinding': {
1772
+ case "channelBinding": {
1748
1773
  const cb = normalizeChannelBinding(value);
1749
1774
  if (cb !== undefined)
1750
1775
  out.channelBinding = cb;
@@ -1778,12 +1803,12 @@ const applyEnvValue = (out, field, value) => {
1778
1803
  * surfaces an error (at TLS-load time, in the wire layer).
1779
1804
  */
1780
1805
  export const libpqConnectionDefaults = (env) => ({
1781
- host: 'localhost',
1806
+ host: "localhost",
1782
1807
  port: 5432,
1783
- user: env.USER ?? '',
1784
- database: '',
1785
- ssl: 'prefer',
1786
- applicationName: 'psql',
1808
+ user: env.USER ?? "",
1809
+ database: "",
1810
+ ssl: "prefer",
1811
+ applicationName: "psql",
1787
1812
  ...defaultClientCertDefaults(env),
1788
1813
  });
1789
1814
  /**
@@ -1802,13 +1827,13 @@ export const libpqConnectionDefaults = (env) => ({
1802
1827
  */
1803
1828
  export const defaultClientCertDefaults = (env) => {
1804
1829
  const home = env.HOME ?? os.homedir();
1805
- if (home === undefined || home === '')
1830
+ if (home === undefined || home === "")
1806
1831
  return {};
1807
1832
  const out = {};
1808
- const certPath = path.join(home, '.postgresql', 'postgresql.crt');
1833
+ const certPath = path.join(home, ".postgresql", "postgresql.crt");
1809
1834
  if (existsSync(certPath))
1810
1835
  out.sslcert = certPath;
1811
- const keyPath = path.join(home, '.postgresql', 'postgresql.key');
1836
+ const keyPath = path.join(home, ".postgresql", "postgresql.key");
1812
1837
  if (existsSync(keyPath))
1813
1838
  out.sslkey = keyPath;
1814
1839
  return out;
@@ -1827,130 +1852,130 @@ export const serviceEntryToConnectOptions = (entry) => {
1827
1852
  for (const [k, v] of Object.entries(entry)) {
1828
1853
  const key = k.toLowerCase();
1829
1854
  switch (key) {
1830
- case 'host':
1831
- if (v !== '')
1855
+ case "host":
1856
+ if (v !== "")
1832
1857
  out.host = v;
1833
1858
  break;
1834
- case 'port': {
1859
+ case "port": {
1835
1860
  const p = Number.parseInt(v, 10);
1836
1861
  if (Number.isFinite(p) && p > 0 && p <= 65535)
1837
1862
  out.port = p;
1838
1863
  break;
1839
1864
  }
1840
- case 'user':
1841
- if (v !== '')
1865
+ case "user":
1866
+ if (v !== "")
1842
1867
  out.user = v;
1843
1868
  break;
1844
- case 'dbname':
1845
- if (v !== '')
1869
+ case "dbname":
1870
+ if (v !== "")
1846
1871
  out.database = v;
1847
1872
  break;
1848
- case 'password':
1873
+ case "password":
1849
1874
  out.password = v;
1850
1875
  break;
1851
- case 'application_name':
1852
- if (v !== '')
1876
+ case "application_name":
1877
+ if (v !== "")
1853
1878
  out.applicationName = v;
1854
1879
  break;
1855
- case 'sslmode':
1856
- if (v !== '')
1880
+ case "sslmode":
1881
+ if (v !== "")
1857
1882
  out.ssl = normalizeSslMode(v);
1858
1883
  break;
1859
- case 'channel_binding': {
1884
+ case "channel_binding": {
1860
1885
  const cb = normalizeChannelBinding(v);
1861
1886
  if (cb !== undefined)
1862
1887
  out.channelBinding = cb;
1863
1888
  break;
1864
1889
  }
1865
- case 'require_auth': {
1890
+ case "require_auth": {
1866
1891
  const ra = normalizeRequireAuth(v);
1867
1892
  if (ra !== undefined)
1868
1893
  out.requireAuth = ra;
1869
1894
  break;
1870
1895
  }
1871
- case 'options':
1872
- if (v !== '')
1896
+ case "options":
1897
+ if (v !== "")
1873
1898
  out.options = v;
1874
1899
  break;
1875
- case 'client_encoding':
1876
- if (v !== '')
1900
+ case "client_encoding":
1901
+ if (v !== "")
1877
1902
  out.clientEncoding = v;
1878
1903
  break;
1879
- case 'sslcert':
1880
- if (v !== '')
1904
+ case "sslcert":
1905
+ if (v !== "")
1881
1906
  out.sslcert = v;
1882
1907
  break;
1883
- case 'sslkey':
1884
- if (v !== '')
1908
+ case "sslkey":
1909
+ if (v !== "")
1885
1910
  out.sslkey = v;
1886
1911
  break;
1887
- case 'sslcertmode': {
1912
+ case "sslcertmode": {
1888
1913
  const cm = normalizeSslCertMode(v);
1889
1914
  if (cm !== undefined)
1890
1915
  out.sslcertmode = cm;
1891
1916
  break;
1892
1917
  }
1893
- case 'sslnegotiation': {
1918
+ case "sslnegotiation": {
1894
1919
  const sn = normalizeSslNegotiation(v);
1895
1920
  if (sn !== undefined)
1896
1921
  out.sslnegotiation = sn;
1897
1922
  break;
1898
1923
  }
1899
- case 'sslrootcert':
1900
- if (v !== '')
1924
+ case "sslrootcert":
1925
+ if (v !== "")
1901
1926
  out.sslrootcert = v;
1902
1927
  break;
1903
- case 'sslcrl':
1904
- if (v !== '')
1928
+ case "sslcrl":
1929
+ if (v !== "")
1905
1930
  out.sslcrl = v;
1906
1931
  break;
1907
- case 'sslcrldir':
1908
- if (v !== '')
1932
+ case "sslcrldir":
1933
+ if (v !== "")
1909
1934
  out.sslcrldir = v;
1910
1935
  break;
1911
- case 'sslkeylogfile':
1912
- if (v !== '')
1936
+ case "sslkeylogfile":
1937
+ if (v !== "")
1913
1938
  out.sslkeylogfile = v;
1914
1939
  break;
1915
- case 'sslsni': {
1940
+ case "sslsni": {
1916
1941
  const b = parseLibpqBool(v);
1917
1942
  if (b !== undefined)
1918
1943
  out.sslsni = b;
1919
1944
  break;
1920
1945
  }
1921
- case 'keepalives': {
1946
+ case "keepalives": {
1922
1947
  const b = parseLibpqBool(v);
1923
1948
  if (b !== undefined)
1924
1949
  out.keepalives = b;
1925
1950
  break;
1926
1951
  }
1927
- case 'keepalives_idle': {
1952
+ case "keepalives_idle": {
1928
1953
  const n = parseKeepalivesIdle(v);
1929
1954
  if (n !== undefined)
1930
1955
  out.keepalivesIdle = n;
1931
1956
  break;
1932
1957
  }
1933
- case 'requirepeer':
1934
- if (v !== '')
1958
+ case "requirepeer":
1959
+ if (v !== "")
1935
1960
  out.requirepeer = v;
1936
1961
  break;
1937
- case 'hostaddr':
1938
- if (v !== '')
1962
+ case "hostaddr":
1963
+ if (v !== "")
1939
1964
  out.hostaddr = v;
1940
1965
  break;
1941
- case 'ssl_min_protocol_version': {
1942
- const pv = normalizeTlsProtocolVersion(v === '' ? undefined : v, 'ssl_min_protocol_version');
1966
+ case "ssl_min_protocol_version": {
1967
+ const pv = normalizeTlsProtocolVersion(v === "" ? undefined : v, "ssl_min_protocol_version");
1943
1968
  if (pv !== undefined)
1944
1969
  out.sslMinProtocolVersion = pv;
1945
1970
  break;
1946
1971
  }
1947
- case 'ssl_max_protocol_version': {
1948
- const pv = normalizeTlsProtocolVersion(v === '' ? undefined : v, 'ssl_max_protocol_version');
1972
+ case "ssl_max_protocol_version": {
1973
+ const pv = normalizeTlsProtocolVersion(v === "" ? undefined : v, "ssl_max_protocol_version");
1949
1974
  if (pv !== undefined)
1950
1975
  out.sslMaxProtocolVersion = pv;
1951
1976
  break;
1952
1977
  }
1953
- case 'connect_timeout': {
1978
+ case "connect_timeout": {
1954
1979
  const t = Number.parseInt(v, 10);
1955
1980
  if (Number.isFinite(t) && t >= 0)
1956
1981
  out.connectTimeoutMs = t * 1000;
@@ -1987,15 +2012,15 @@ export const mergeConnectOptions = (layers, defaults) => {
1987
2012
  // libpq: database defaults to the resolved user when no layer set it.
1988
2013
  // The default `database: ''` from `libpqConnectionDefaults` is the
1989
2014
  // sentinel for "nothing supplied".
1990
- if (out.database === '') {
2015
+ if (out.database === "") {
1991
2016
  out.database = out.user;
1992
2017
  }
1993
2018
  // libpq: `sslrootcert=system` raises the effective sslmode to verify-full
1994
2019
  // (it makes no sense to trust the public CA store without verifying the
1995
2020
  // chain AND the hostname). verify-full is the strongest mode, so this can
1996
2021
  // only ever raise — never downgrade — an explicitly requested mode.
1997
- if (out.sslrootcert === 'system' && out.ssl !== 'verify-full') {
1998
- out.ssl = 'verify-full';
2022
+ if (out.sslrootcert === "system" && out.ssl !== "verify-full") {
2023
+ out.ssl = "verify-full";
1999
2024
  }
2000
2025
  // libpq validates `sslnegotiation=direct` against the FINAL sslmode (after
2001
2026
  // any `sslrootcert=system` raise and cross-layer merge), rejecting a weak