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
@@ -32,16 +32,16 @@
32
32
  *
33
33
  * The set is registered in bulk via {@link registerPipelineCommands}.
34
34
  */
35
- import { writeErr } from './shared.js';
36
- import { alignedPrinter } from '../print/aligned.js';
37
- import { clearPipelineGateErrors } from './cmd_io.js';
35
+ import { alignedPrinter } from "../print/aligned.js";
36
+ import { clearPipelineGateErrors } from "./cmd_io.js";
37
+ import { writeErr } from "./shared.js";
38
38
  // ---------------------------------------------------------------------------
39
39
  // Settings stash. We can't add new fields to PsqlSettings (frozen WP-00) so
40
40
  // we attach Symbol-keyed state.
41
41
  // ---------------------------------------------------------------------------
42
- const BIND_STATE_KEY = Symbol.for('neonctl.psql.bindState');
43
- const PIPELINE_KEY = Symbol.for('neonctl.psql.pipeline');
44
- const PREPARED_BY_NAME_KEY = Symbol.for('neonctl.psql.preparedByName');
42
+ const BIND_STATE_KEY = Symbol.for("neonctl.psql.bindState");
43
+ const PIPELINE_KEY = Symbol.for("neonctl.psql.pipeline");
44
+ const PREPARED_BY_NAME_KEY = Symbol.for("neonctl.psql.preparedByName");
45
45
  const stashOf = (settings) => settings;
46
46
  /** Read (and clear) the pending bind params, if any. */
47
47
  export const consumeBindState = (settings) => {
@@ -128,9 +128,9 @@ const bumpCounter = (settings, name, delta) => {
128
128
  setCounter(settings, name, readCounter(settings, name) + delta);
129
129
  };
130
130
  const resetPipelineCounters = (settings) => {
131
- setCounter(settings, 'PIPELINE_COMMAND_COUNT', 0);
132
- setCounter(settings, 'PIPELINE_SYNC_COUNT', 0);
133
- setCounter(settings, 'PIPELINE_RESULT_COUNT', 0);
131
+ setCounter(settings, "PIPELINE_COMMAND_COUNT", 0);
132
+ setCounter(settings, "PIPELINE_SYNC_COUNT", 0);
133
+ setCounter(settings, "PIPELINE_RESULT_COUNT", 0);
134
134
  };
135
135
  /**
136
136
  * Wrap `Pipeline.execute` so each enqueued Execute message bumps
@@ -146,7 +146,7 @@ const resetPipelineCounters = (settings) => {
146
146
  const wrapSessionForCounters = (session, settings) => {
147
147
  const origExecute = session.execute.bind(session);
148
148
  session.execute = (name, maxRows) => {
149
- bumpCounter(settings, 'PIPELINE_COMMAND_COUNT', 1);
149
+ bumpCounter(settings, "PIPELINE_COMMAND_COUNT", 1);
150
150
  return origExecute(name, maxRows);
151
151
  };
152
152
  return session;
@@ -159,7 +159,7 @@ const errResult = (ctx, message) => {
159
159
  writeErr(`\\${ctx.cmdName}: ${message}\n`);
160
160
  // Tell mainloop the diagnostic is already on stderr so it doesn't add
161
161
  // a `psql: ERROR: <msg>` fallback line.
162
- return { status: 'error', errorWritten: true };
162
+ return { status: "error", errorWritten: true };
163
163
  };
164
164
  /**
165
165
  * Coerce any thrown / rejected value into a printable string. The
@@ -175,9 +175,9 @@ const errorToMessage = (err) => {
175
175
  if (err instanceof Error)
176
176
  return err.message;
177
177
  if (err !== null &&
178
- typeof err === 'object' &&
179
- 'message' in err &&
180
- typeof err.message === 'string') {
178
+ typeof err === "object" &&
179
+ "message" in err &&
180
+ typeof err.message === "string") {
181
181
  return err.message;
182
182
  }
183
183
  try {
@@ -200,7 +200,7 @@ const errorToMessage = (err) => {
200
200
  * the originating SQL position through `session.lastError`.
201
201
  */
202
202
  const renderPipelineError = (err) => {
203
- if (err === null || typeof err !== 'object') {
203
+ if (err === null || typeof err !== "object") {
204
204
  writeErr(`ERROR: ${errorToMessage(err)}\n`);
205
205
  return;
206
206
  }
@@ -211,11 +211,11 @@ const renderPipelineError = (err) => {
211
211
  // wording the regress baseline asserts for cascaded skips after a
212
212
  // preceding ErrorResponse.
213
213
  if (e.pipelineAborted) {
214
- writeErr(`${e.message ?? 'Pipeline aborted, command did not run'}\n`);
214
+ writeErr(`${e.message ?? "Pipeline aborted, command did not run"}\n`);
215
215
  return;
216
216
  }
217
- const severity = e.severity ?? 'ERROR';
218
- const message = e.message ?? '';
217
+ const severity = e.severity ?? "ERROR";
218
+ const message = e.message ?? "";
219
219
  writeErr(`${severity}: ${message}\n`);
220
220
  if (e.detail)
221
221
  writeErr(`DETAIL: ${e.detail}\n`);
@@ -227,7 +227,7 @@ const renderPipelineError = (err) => {
227
227
  const readAllArgs = (ctx) => {
228
228
  const out = [];
229
229
  for (;;) {
230
- const arg = ctx.nextArg('normal');
230
+ const arg = ctx.nextArg("normal");
231
231
  if (arg === null)
232
232
  break;
233
233
  out.push(arg);
@@ -238,26 +238,26 @@ const readAllArgs = (ctx) => {
238
238
  // \bind [VALUE ...]
239
239
  // ---------------------------------------------------------------------------
240
240
  export const cmdBind = {
241
- name: 'bind',
242
- helpKey: 'bind',
241
+ name: "bind",
242
+ helpKey: "bind",
243
243
  run(ctx) {
244
244
  const values = readAllArgs(ctx);
245
245
  stashOf(ctx.settings)[BIND_STATE_KEY] = {
246
- name: '',
246
+ name: "",
247
247
  values,
248
248
  byName: false,
249
249
  };
250
- return Promise.resolve({ status: 'ok' });
250
+ return Promise.resolve({ status: "ok" });
251
251
  },
252
252
  };
253
253
  // ---------------------------------------------------------------------------
254
254
  // \bind_named NAME [VALUE ...]
255
255
  // ---------------------------------------------------------------------------
256
256
  export const cmdBindNamed = {
257
- name: 'bind_named',
258
- helpKey: 'bind_named',
257
+ name: "bind_named",
258
+ helpKey: "bind_named",
259
259
  run(ctx) {
260
- const name = ctx.nextArg('normal');
260
+ const name = ctx.nextArg("normal");
261
261
  // Upstream `exec_command_bind_named` rejects only the missing-arg
262
262
  // case. `''` IS valid — it addresses the unnamed prepared statement
263
263
  // slot (set via `\parse ''`).
@@ -266,27 +266,27 @@ export const cmdBindNamed = {
266
266
  // follow-on `\g` falls back to `pset.last_query` (the previous
267
267
  // successful query) instead of executing against a stale handle.
268
268
  stashOf(ctx.settings)[BIND_STATE_KEY] = undefined;
269
- return Promise.resolve(errResult(ctx, 'missing required argument'));
269
+ return Promise.resolve(errResult(ctx, "missing required argument"));
270
270
  }
271
271
  const values = readAllArgs(ctx);
272
272
  stashOf(ctx.settings)[BIND_STATE_KEY] = { name, values, byName: true };
273
- return Promise.resolve({ status: 'ok' });
273
+ return Promise.resolve({ status: "ok" });
274
274
  },
275
275
  };
276
276
  // ---------------------------------------------------------------------------
277
277
  // \parse NAME — prepare current queryBuf as NAME.
278
278
  // ---------------------------------------------------------------------------
279
279
  export const cmdParse = {
280
- name: 'parse',
281
- helpKey: 'parse',
280
+ name: "parse",
281
+ helpKey: "parse",
282
282
  async run(ctx) {
283
- const name = ctx.nextArg('normal');
283
+ const name = ctx.nextArg("normal");
284
284
  // Upstream `exec_command_parse` rejects only the missing-arg case
285
285
  // with `missing required argument`. An explicit empty string `''`
286
286
  // IS valid — it's the "unnamed" prepared statement slot, addressable
287
287
  // later via `\bind_named ''`.
288
288
  if (name === null) {
289
- return errResult(ctx, 'missing required argument');
289
+ return errResult(ctx, "missing required argument");
290
290
  }
291
291
  // Upstream `exec_command_parse` passes the query buffer verbatim to
292
292
  // `PQsendPrepare`, with no trim — the server then stores the bytes
@@ -297,10 +297,10 @@ export const cmdParse = {
297
297
  // only buffer reports `no query buffer` like upstream does.
298
298
  const sql = ctx.queryBuf;
299
299
  if (sql.trim().length === 0) {
300
- return errResult(ctx, 'no query buffer');
300
+ return errResult(ctx, "no query buffer");
301
301
  }
302
302
  if (!ctx.settings.db) {
303
- return errResult(ctx, 'no connection to the server');
303
+ return errResult(ctx, "no connection to the server");
304
304
  }
305
305
  // In pipeline mode, route the Parse through the active session so
306
306
  // it gets queued behind the in-flight P/B/E ops (and the server
@@ -321,7 +321,7 @@ export const cmdParse = {
321
321
  // accounting. Test mocks that don't implement `parseSlot` fall
322
322
  // through to the plain `parse()` method.
323
323
  const session = pipelineActive.session;
324
- if (typeof session.parseSlot === 'function') {
324
+ if (typeof session.parseSlot === "function") {
325
325
  await session.parseSlot(name, sql, []);
326
326
  }
327
327
  else {
@@ -330,8 +330,8 @@ export const cmdParse = {
330
330
  ctx.settings.lastQuery = sql;
331
331
  // Upstream `exec_command_parse` bumps `pset.piped_commands` after
332
332
  // PQsendPrepare succeeds — the Parse is one queued command.
333
- bumpCounter(ctx.settings, 'PIPELINE_COMMAND_COUNT', 1);
334
- return { status: 'reset-buf', newBuf: '' };
333
+ bumpCounter(ctx.settings, "PIPELINE_COMMAND_COUNT", 1);
334
+ return { status: "reset-buf", newBuf: "" };
335
335
  }
336
336
  catch (err) {
337
337
  return errResult(ctx, errorToMessage(err));
@@ -352,7 +352,7 @@ export const cmdParse = {
352
352
  // "ERROR: there is no parameter $1" the conformance corpus
353
353
  // expects from `SELECT $1, $2` executed without bind params.
354
354
  ctx.settings.lastQuery = sql;
355
- return { status: 'reset-buf', newBuf: '' };
355
+ return { status: "reset-buf", newBuf: "" };
356
356
  }
357
357
  catch (err) {
358
358
  return errResult(ctx, errorToMessage(err));
@@ -363,17 +363,17 @@ export const cmdParse = {
363
363
  // \close_prepared NAME
364
364
  // ---------------------------------------------------------------------------
365
365
  export const cmdClosePrepared = {
366
- name: 'close_prepared',
367
- helpKey: 'close_prepared',
366
+ name: "close_prepared",
367
+ helpKey: "close_prepared",
368
368
  async run(ctx) {
369
- const name = ctx.nextArg('normal');
369
+ const name = ctx.nextArg("normal");
370
370
  // Empty string `''` is the valid unnamed prepared statement.
371
371
  if (name === null) {
372
- return errResult(ctx, 'missing required argument');
372
+ return errResult(ctx, "missing required argument");
373
373
  }
374
374
  const db = ctx.settings.db;
375
375
  if (!db) {
376
- return errResult(ctx, 'no connection to the server');
376
+ return errResult(ctx, "no connection to the server");
377
377
  }
378
378
  // Inside an open pipeline, upstream routes through
379
379
  // `PQsendClosePrepared` (queues a `Close('S', name)` behind the
@@ -391,7 +391,7 @@ export const cmdClosePrepared = {
391
391
  // that don't implement `closeSlot` fall through to plain
392
392
  // `close()`.
393
393
  const session = ps.session;
394
- if (typeof session.closeSlot === 'function') {
394
+ if (typeof session.closeSlot === "function") {
395
395
  await session.closeSlot(name);
396
396
  }
397
397
  else {
@@ -399,11 +399,11 @@ export const cmdClosePrepared = {
399
399
  }
400
400
  // Upstream `exec_command_close_prepared` bumps `piped_commands`
401
401
  // (PIPELINE_COMMAND_COUNT) after a successful PQsendClosePrepared.
402
- bumpCounter(ctx.settings, 'PIPELINE_COMMAND_COUNT', 1);
402
+ bumpCounter(ctx.settings, "PIPELINE_COMMAND_COUNT", 1);
403
403
  // Drop any cached binding so a later `\bind_named NAME \g`
404
404
  // errors cleanly instead of using a stale handle.
405
405
  dropPrepared(ctx.settings, name);
406
- return { status: 'ok' };
406
+ return { status: "ok" };
407
407
  }
408
408
  catch (err) {
409
409
  return errResult(ctx, errorToMessage(err));
@@ -425,13 +425,13 @@ export const cmdClosePrepared = {
425
425
  // implement the dedicated entry point. The real PgConnection
426
426
  // always provides closePreparedStatement; this branch only
427
427
  // fires under unit tests with bespoke Connection mocks.
428
- const stmt = await db.prepare(name, 'SELECT 1');
428
+ const stmt = await db.prepare(name, "SELECT 1");
429
429
  await stmt.close();
430
430
  }
431
431
  // Drop any cached binding so a later `\bind_named NAME \g` errors
432
432
  // cleanly instead of using a stale handle.
433
433
  dropPrepared(ctx.settings, name);
434
- return { status: 'ok' };
434
+ return { status: "ok" };
435
435
  }
436
436
  catch (err) {
437
437
  return errResult(ctx, errorToMessage(err));
@@ -442,11 +442,11 @@ export const cmdClosePrepared = {
442
442
  // \startpipeline / \endpipeline
443
443
  // ---------------------------------------------------------------------------
444
444
  export const cmdStartPipeline = {
445
- name: 'startpipeline',
446
- helpKey: 'startpipeline',
445
+ name: "startpipeline",
446
+ helpKey: "startpipeline",
447
447
  run(ctx) {
448
448
  if (!ctx.settings.db) {
449
- return Promise.resolve(errResult(ctx, 'no connection to the server'));
449
+ return Promise.resolve(errResult(ctx, "no connection to the server"));
450
450
  }
451
451
  // Vanilla psql 18.4 treats a duplicate `\startpipeline` as a silent
452
452
  // no-op (no warning on stdout OR stderr) — verified empirically:
@@ -455,7 +455,7 @@ export const cmdStartPipeline = {
455
455
  // lines. Our prior `errResult('pipeline already active')` was a
456
456
  // divergence; match upstream's quiet path.
457
457
  if (getPipelineState(ctx.settings) !== null) {
458
- return Promise.resolve({ status: 'ok' });
458
+ return Promise.resolve({ status: "ok" });
459
459
  }
460
460
  try {
461
461
  const session = wrapSessionForCounters(ctx.settings.db.pipeline(), ctx.settings);
@@ -464,11 +464,11 @@ export const cmdStartPipeline = {
464
464
  pending: [],
465
465
  drainedCount: 0,
466
466
  };
467
- ctx.settings.sendMode = 'extended-pipeline';
467
+ ctx.settings.sendMode = "extended-pipeline";
468
468
  // Upstream `exec_command_startpipeline` calls SetVariable for the three
469
469
  // counter vars (zeroing whatever the prior pipeline left behind).
470
470
  resetPipelineCounters(ctx.settings);
471
- return Promise.resolve({ status: 'ok' });
471
+ return Promise.resolve({ status: "ok" });
472
472
  }
473
473
  catch (err) {
474
474
  return Promise.resolve(errResult(ctx, errorToMessage(err)));
@@ -476,8 +476,8 @@ export const cmdStartPipeline = {
476
476
  },
477
477
  };
478
478
  export const cmdEndPipeline = {
479
- name: 'endpipeline',
480
- helpKey: 'endpipeline',
479
+ name: "endpipeline",
480
+ helpKey: "endpipeline",
481
481
  async run(ctx) {
482
482
  const ps = getPipelineState(ctx.settings);
483
483
  if (!ps) {
@@ -490,10 +490,10 @@ export const cmdEndPipeline = {
490
490
  // `errResult` (which would inject `\endpipeline: `) and write
491
491
  // the line directly.
492
492
  ctx.settings.lastErrorResult = {
493
- message: 'cannot send pipeline when not in pipeline mode',
493
+ message: "cannot send pipeline when not in pipeline mode",
494
494
  };
495
- writeErr('cannot send pipeline when not in pipeline mode\n');
496
- return { status: 'error', errorWritten: true };
495
+ writeErr("cannot send pipeline when not in pipeline mode\n");
496
+ return { status: "error", errorWritten: true };
497
497
  }
498
498
  try {
499
499
  // Snapshot how many slots were already surfaced by prior
@@ -522,10 +522,10 @@ export const cmdEndPipeline = {
522
522
  // "fetching results in chunked mode failed" wording in lieu of
523
523
  // (or in addition to) the regular Pipeline aborted line. Read
524
524
  // BEFORE end() resets the counters.
525
- const fetchCountActive = (ctx.settings.vars.get('FETCH_COUNT') ?? '0') !== '0';
525
+ const fetchCountActive = (ctx.settings.vars.get("FETCH_COUNT") ?? "0") !== "0";
526
526
  const sets = await ps.session.end();
527
527
  stashOf(ctx.settings)[PIPELINE_KEY] = undefined;
528
- ctx.settings.sendMode = 'extended-query';
528
+ ctx.settings.sendMode = "extended-query";
529
529
  // Upstream `exec_command_endpipeline` zeroes the counters once the
530
530
  // pipeline has drained — mirrors the empirical behaviour of vanilla
531
531
  // psql 18.4 where `\echo :PIPELINE_*` reads "0" after `\endpipeline`.
@@ -554,7 +554,7 @@ export const cmdEndPipeline = {
554
554
  const entries = settled.length > 0
555
555
  ? settled
556
556
  : sets.map((rs) => ({
557
- status: 'fulfilled',
557
+ status: "fulfilled",
558
558
  value: rs,
559
559
  }));
560
560
  // Pre-scan THIS slice (entries from `alreadyDrained` onward) for
@@ -570,12 +570,13 @@ export const cmdEndPipeline = {
570
570
  const sliceForError = entries.slice(alreadyDrained);
571
571
  const realFromSlice = (() => {
572
572
  for (const r of sliceForError) {
573
- if (r.status !== 'rejected')
573
+ if (r.status !== "rejected")
574
574
  continue;
575
575
  const reason = r.reason;
576
- const isAborted = typeof reason === 'object' &&
576
+ const isAborted = typeof reason === "object" &&
577
577
  reason !== null &&
578
- reason.pipelineAborted === true;
578
+ reason
579
+ .pipelineAborted === true;
579
580
  if (!isAborted)
580
581
  return reason;
581
582
  }
@@ -586,7 +587,7 @@ export const cmdEndPipeline = {
586
587
  const le = session.lastError;
587
588
  if (le === null || le === undefined)
588
589
  return null;
589
- if (typeof le === 'object' &&
590
+ if (typeof le === "object" &&
590
591
  le.pipelineAborted) {
591
592
  return null;
592
593
  }
@@ -594,7 +595,7 @@ export const cmdEndPipeline = {
594
595
  })();
595
596
  for (let i = alreadyDrained; i < entries.length; i++) {
596
597
  const r = entries[i];
597
- if (r.status === 'fulfilled') {
598
+ if (r.status === "fulfilled") {
598
599
  const rs = r.value;
599
600
  // Emit any NoticeResponse messages attached to this result
600
601
  // to stderr in the upstream libpq shape
@@ -622,8 +623,12 @@ export const cmdEndPipeline = {
622
623
  // Skip our internal Sync marker (empty `command`, see
623
624
  // wire/pipeline.ts) and DDL-style CommandComplete-only sets
624
625
  // (non-empty `command` but no fields and no rows).
625
- const isSyncOrPlaceholder = rs.fields.length === 0 && rs.command === '' && rs.rows.length === 0;
626
- const isCommandOnly = rs.fields.length === 0 && rs.rows.length === 0 && rs.command !== '';
626
+ const isSyncOrPlaceholder = rs.fields.length === 0 &&
627
+ rs.command === "" &&
628
+ rs.rows.length === 0;
629
+ const isCommandOnly = rs.fields.length === 0 &&
630
+ rs.rows.length === 0 &&
631
+ rs.command !== "";
627
632
  if (!isSyncOrPlaceholder && !isCommandOnly) {
628
633
  if (rs.fields.length === 0 && rs.rows.length > 0) {
629
634
  // 0-column tuples result: the aligned printer's
@@ -634,8 +639,8 @@ export const cmdEndPipeline = {
634
639
  // `\watch`-rejected SELECT output byte-for-byte.
635
640
  const tuplesOnly = ctx.settings.popt.topt.tuplesOnly;
636
641
  if (!tuplesOnly) {
637
- process.stdout.write('--\n');
638
- process.stdout.write(`(${rs.rows.length} ${rs.rows.length === 1 ? 'row' : 'rows'})\n\n`);
642
+ process.stdout.write("--\n");
643
+ process.stdout.write(`(${rs.rows.length} ${rs.rows.length === 1 ? "row" : "rows"})\n\n`);
639
644
  }
640
645
  }
641
646
  else {
@@ -653,9 +658,10 @@ export const cmdEndPipeline = {
653
658
  // `session.lastError` / `peekRealError` for the original
654
659
  // ERROR.
655
660
  const reason = r.reason;
656
- const isAborted = typeof reason === 'object' &&
661
+ const isAborted = typeof reason === "object" &&
657
662
  reason !== null &&
658
- reason.pipelineAborted === true;
663
+ reason
664
+ .pipelineAborted === true;
659
665
  // FETCH_COUNT-in-pipeline: upstream emits the chunked-mode
660
666
  // diagnostic in addition to the per-op line. Both go to
661
667
  // stderr; the chunked-mode line comes FIRST and addresses the
@@ -669,13 +675,13 @@ export const cmdEndPipeline = {
669
675
  // aborted, command did not run" is shown ONLY for the synthetic
670
676
  // queue-skip marker (no real error behind it).
671
677
  if (fetchCountActive) {
672
- writeErr('fetching results in chunked mode failed\n');
678
+ writeErr("fetching results in chunked mode failed\n");
673
679
  }
674
680
  if (isAborted && realLastError !== null) {
675
681
  renderPipelineError(realLastError);
676
682
  }
677
683
  else if (isAborted) {
678
- writeErr('Pipeline aborted, command did not run\n');
684
+ writeErr("Pipeline aborted, command did not run\n");
679
685
  }
680
686
  else {
681
687
  renderPipelineError(reason);
@@ -694,16 +700,16 @@ export const cmdEndPipeline = {
694
700
  // FETCH_COUNT was active, but still render the actual ERROR rather
695
701
  // than the synthetic "Pipeline aborted" line (review: minor).
696
702
  if (fetchCountActive) {
697
- writeErr('fetching results in chunked mode failed\n');
703
+ writeErr("fetching results in chunked mode failed\n");
698
704
  }
699
705
  renderPipelineError(lastErr);
700
706
  }
701
707
  }
702
- return { status: 'ok' };
708
+ return { status: "ok" };
703
709
  }
704
710
  catch (err) {
705
711
  stashOf(ctx.settings)[PIPELINE_KEY] = undefined;
706
- ctx.settings.sendMode = 'extended-query';
712
+ ctx.settings.sendMode = "extended-query";
707
713
  // Even on a failed `\endpipeline` (e.g. server hung up mid-drain),
708
714
  // mirror upstream and clear the counters — the pipeline state is
709
715
  // gone, so any non-zero value would be misleading. Same for the
@@ -718,12 +724,12 @@ export const cmdEndPipeline = {
718
724
  // \syncpipeline / \flushrequest / \flush
719
725
  // ---------------------------------------------------------------------------
720
726
  export const cmdSyncPipeline = {
721
- name: 'syncpipeline',
722
- helpKey: 'syncpipeline',
727
+ name: "syncpipeline",
728
+ helpKey: "syncpipeline",
723
729
  async run(ctx) {
724
730
  const ps = getPipelineState(ctx.settings);
725
731
  if (!ps)
726
- return errResult(ctx, 'no pipeline active');
732
+ return errResult(ctx, "no pipeline active");
727
733
  try {
728
734
  await ps.session.sync();
729
735
  // Upstream `exec_command_syncpipeline`:
@@ -732,11 +738,11 @@ export const cmdSyncPipeline = {
732
738
  // piped_syncs++;
733
739
  // The pending commands have transitioned to "queued results" on the
734
740
  // server, and Sync is itself counted as a piped command boundary.
735
- const queued = readCounter(ctx.settings, 'PIPELINE_COMMAND_COUNT');
736
- setCounter(ctx.settings, 'PIPELINE_COMMAND_COUNT', 0);
737
- bumpCounter(ctx.settings, 'PIPELINE_RESULT_COUNT', queued);
738
- bumpCounter(ctx.settings, 'PIPELINE_SYNC_COUNT', 1);
739
- return { status: 'ok' };
741
+ const queued = readCounter(ctx.settings, "PIPELINE_COMMAND_COUNT");
742
+ setCounter(ctx.settings, "PIPELINE_COMMAND_COUNT", 0);
743
+ bumpCounter(ctx.settings, "PIPELINE_RESULT_COUNT", queued);
744
+ bumpCounter(ctx.settings, "PIPELINE_SYNC_COUNT", 1);
745
+ return { status: "ok" };
740
746
  }
741
747
  catch (err) {
742
748
  return errResult(ctx, errorToMessage(err));
@@ -744,22 +750,22 @@ export const cmdSyncPipeline = {
744
750
  },
745
751
  };
746
752
  export const cmdFlushRequest = {
747
- name: 'flushrequest',
748
- helpKey: 'flushrequest',
753
+ name: "flushrequest",
754
+ helpKey: "flushrequest",
749
755
  async run(ctx) {
750
756
  const ps = getPipelineState(ctx.settings);
751
757
  if (!ps)
752
- return errResult(ctx, 'no pipeline active');
758
+ return errResult(ctx, "no pipeline active");
753
759
  try {
754
760
  await ps.session.flush();
755
761
  // Upstream `exec_command_flushrequest`:
756
762
  // piped_results += piped_commands;
757
763
  // piped_commands = 0;
758
764
  // The pending commands move to "queued results" but SYNC isn't issued.
759
- const queued = readCounter(ctx.settings, 'PIPELINE_COMMAND_COUNT');
760
- setCounter(ctx.settings, 'PIPELINE_COMMAND_COUNT', 0);
761
- bumpCounter(ctx.settings, 'PIPELINE_RESULT_COUNT', queued);
762
- return { status: 'ok' };
765
+ const queued = readCounter(ctx.settings, "PIPELINE_COMMAND_COUNT");
766
+ setCounter(ctx.settings, "PIPELINE_COMMAND_COUNT", 0);
767
+ bumpCounter(ctx.settings, "PIPELINE_RESULT_COUNT", queued);
768
+ return { status: "ok" };
763
769
  }
764
770
  catch (err) {
765
771
  return errResult(ctx, errorToMessage(err));
@@ -767,8 +773,8 @@ export const cmdFlushRequest = {
767
773
  },
768
774
  };
769
775
  export const cmdFlush = {
770
- name: 'flush',
771
- helpKey: 'flush',
776
+ name: "flush",
777
+ helpKey: "flush",
772
778
  run(ctx) {
773
779
  return cmdFlushRequest.run(ctx);
774
780
  },
@@ -777,8 +783,8 @@ export const cmdFlush = {
777
783
  // \sendpipeline — submit current buffer with stashed bind params.
778
784
  // ---------------------------------------------------------------------------
779
785
  export const cmdSendPipeline = {
780
- name: 'sendpipeline',
781
- helpKey: 'sendpipeline',
786
+ name: "sendpipeline",
787
+ helpKey: "sendpipeline",
782
788
  async run(ctx) {
783
789
  const ps = getPipelineState(ctx.settings);
784
790
  if (!ps) {
@@ -794,10 +800,10 @@ export const cmdSendPipeline = {
794
800
  // parameters from before the failed-outside-pipeline send.
795
801
  consumeBindState(ctx.settings);
796
802
  ctx.settings.lastErrorResult = {
797
- message: '\\sendpipeline not allowed outside of pipeline mode',
803
+ message: "\\sendpipeline not allowed outside of pipeline mode",
798
804
  };
799
- writeErr('\\sendpipeline not allowed outside of pipeline mode\n');
800
- return { status: 'error', errorWritten: true };
805
+ writeErr("\\sendpipeline not allowed outside of pipeline mode\n");
806
+ return { status: "error", errorWritten: true };
801
807
  }
802
808
  const bind = consumeBindState(ctx.settings);
803
809
  // Upstream `exec_command_sendpipeline` (in pipeline mode) requires
@@ -809,10 +815,10 @@ export const cmdSendPipeline = {
809
815
  // same diagnostic, so order matters here.
810
816
  if (bind === null) {
811
817
  ctx.settings.lastErrorResult = {
812
- message: '\\sendpipeline must be used after \\bind or \\bind_named',
818
+ message: "\\sendpipeline must be used after \\bind or \\bind_named",
813
819
  };
814
- writeErr('\\sendpipeline must be used after \\bind or \\bind_named\n');
815
- return { status: 'error', errorWritten: true };
820
+ writeErr("\\sendpipeline must be used after \\bind or \\bind_named\n");
821
+ return { status: "error", errorWritten: true };
816
822
  }
817
823
  const sql = ctx.queryBuf.trim();
818
824
  const stmtName = bind.name;
@@ -822,7 +828,7 @@ export const cmdSendPipeline = {
822
828
  // anonymous-`\bind` path still needs a buffer because we must
823
829
  // Parse the SQL first.
824
830
  if (!bind.byName && sql.length === 0) {
825
- return errResult(ctx, 'no query buffer');
831
+ return errResult(ctx, "no query buffer");
826
832
  }
827
833
  try {
828
834
  // We send the full P/B/E sequence without an intervening Sync — the
@@ -832,15 +838,15 @@ export const cmdSendPipeline = {
832
838
  // an unnamed Parse so the SQL is parsed on the server in this
833
839
  // batch.
834
840
  if (!bind.byName) {
835
- await ps.session.parse('', sql, []);
841
+ await ps.session.parse("", sql, []);
836
842
  }
837
843
  await ps.session.bind(stmtName, params);
838
844
  const exec = (async () => {
839
- await ps.session.execute('', 0);
845
+ await ps.session.execute("", 0);
840
846
  // PipelineSession.execute resolves with void on the public API; the
841
847
  // session internally tracks the ResultSet and surfaces it in end().
842
848
  return {
843
- command: '',
849
+ command: "",
844
850
  rowCount: null,
845
851
  oid: null,
846
852
  fields: [],
@@ -849,7 +855,7 @@ export const cmdSendPipeline = {
849
855
  };
850
856
  })();
851
857
  ps.pending.push(exec);
852
- return { status: 'reset-buf', newBuf: '' };
858
+ return { status: "reset-buf", newBuf: "" };
853
859
  }
854
860
  catch (err) {
855
861
  return errResult(ctx, errorToMessage(err));
@@ -860,11 +866,11 @@ export const cmdSendPipeline = {
860
866
  // \getresults [N] — drain N pending results (or all if N omitted).
861
867
  // ---------------------------------------------------------------------------
862
868
  export const cmdGetResults = {
863
- name: 'getresults',
864
- helpKey: 'getresults',
869
+ name: "getresults",
870
+ helpKey: "getresults",
865
871
  async run(ctx) {
866
872
  const ps = getPipelineState(ctx.settings);
867
- const arg = ctx.nextArg('normal');
873
+ const arg = ctx.nextArg("normal");
868
874
  // Upstream `exec_command_getresults` parses the optional count BEFORE
869
875
  // checking pipeline state, so an invalid count surfaces even when
870
876
  // there's no pipeline active. The wording matches upstream verbatim
@@ -873,7 +879,7 @@ export const cmdGetResults = {
873
879
  if (arg !== null && arg.length > 0) {
874
880
  const parsed = parseInt(arg, 10);
875
881
  if (!Number.isFinite(parsed) || parsed < 0) {
876
- return errResult(ctx, 'invalid number of requested results');
882
+ return errResult(ctx, "invalid number of requested results");
877
883
  }
878
884
  requested = parsed;
879
885
  }
@@ -883,8 +889,8 @@ export const cmdGetResults = {
883
889
  // outside of `\startpipeline / \endpipeline` brackets and right
884
890
  // after `\endpipeline`.
885
891
  if (!ps) {
886
- process.stdout.write('No pending results to get\n');
887
- return { status: 'ok' };
892
+ process.stdout.write("No pending results to get\n");
893
+ return { status: "ok" };
888
894
  }
889
895
  // Available items to drain = PIPELINE_SYNC_COUNT + PIPELINE_RESULT_COUNT.
890
896
  // Sync markers and data-result entries both occupy slots in libpq's
@@ -899,12 +905,12 @@ export const cmdGetResults = {
899
905
  // prints nothing on the first \getresults 1 (SyncMarker drained,
900
906
  // SYNC_COUNT: 2 → 1), the second prints nothing (SYNC_COUNT: 1 →
901
907
  // 0), and the third prints the SELECT result.
902
- const syncAvailable = readCounter(ctx.settings, 'PIPELINE_SYNC_COUNT');
903
- const resultAvailable = readCounter(ctx.settings, 'PIPELINE_RESULT_COUNT');
908
+ const syncAvailable = readCounter(ctx.settings, "PIPELINE_SYNC_COUNT");
909
+ const resultAvailable = readCounter(ctx.settings, "PIPELINE_RESULT_COUNT");
904
910
  const available = syncAvailable + resultAvailable;
905
911
  if (available === 0) {
906
- process.stdout.write('No pending results to get\n');
907
- return { status: 'ok' };
912
+ process.stdout.write("No pending results to get\n");
913
+ return { status: "ok" };
908
914
  }
909
915
  // `\getresults 0` and bare `\getresults` mean "all pending"
910
916
  // (upstream semantics).
@@ -953,12 +959,13 @@ export const cmdGetResults = {
953
959
  // one that should surface.
954
960
  const sliceErr = (() => {
955
961
  for (const r of settled) {
956
- if (r.status !== 'rejected')
962
+ if (r.status !== "rejected")
957
963
  continue;
958
964
  const reason = r.reason;
959
- const isAborted = typeof reason === 'object' &&
965
+ const isAborted = typeof reason === "object" &&
960
966
  reason !== null &&
961
- reason.pipelineAborted === true;
967
+ reason
968
+ .pipelineAborted === true;
962
969
  if (!isAborted)
963
970
  return reason;
964
971
  }
@@ -966,7 +973,7 @@ export const cmdGetResults = {
966
973
  })();
967
974
  const sessPeek = session;
968
975
  const realErr = sliceErr ??
969
- (typeof sessPeek.peekRealError === 'function'
976
+ (typeof sessPeek.peekRealError === "function"
970
977
  ? await sessPeek.peekRealError()
971
978
  : null);
972
979
  // Per upstream `\getresults`: emit AT MOST ONE error / aborted
@@ -986,7 +993,7 @@ export const cmdGetResults = {
986
993
  // the remainder to RESULT_COUNT post-walk.
987
994
  for (const r of settled) {
988
995
  walkedItems++;
989
- if (r.status !== 'fulfilled') {
996
+ if (r.status !== "fulfilled") {
990
997
  // Rejected promise — Parse / Bind / Execute / Close that the
991
998
  // server responded to with ErrorResponse, or a cascaded
992
999
  // pipelineAborted marker. Upstream `\getresults` walks
@@ -1000,10 +1007,10 @@ export const cmdGetResults = {
1000
1007
  resultsDrained++;
1001
1008
  if (!errorRenderedHere) {
1002
1009
  const reason = r.reason;
1003
- const isAborted = typeof reason === 'object' &&
1010
+ const isAborted = typeof reason === "object" &&
1004
1011
  reason !== null &&
1005
- reason.pipelineAborted ===
1006
- true;
1012
+ reason
1013
+ .pipelineAborted === true;
1007
1014
  if (isAborted && realErr !== null) {
1008
1015
  renderPipelineError(realErr);
1009
1016
  }
@@ -1033,7 +1040,7 @@ export const cmdGetResults = {
1033
1040
  // attribution is fixed up at the tail of this function based
1034
1041
  // on `syncAvailable`.
1035
1042
  if (rs.fields.length === 0 &&
1036
- rs.command === '' &&
1043
+ rs.command === "" &&
1037
1044
  rs.rows.length === 0) {
1038
1045
  syncsDrained++;
1039
1046
  continue;
@@ -1044,8 +1051,8 @@ export const cmdGetResults = {
1044
1051
  // `\endpipeline` (see comment there).
1045
1052
  const tuplesOnly = ctx.settings.popt.topt.tuplesOnly;
1046
1053
  if (!tuplesOnly) {
1047
- process.stdout.write('--\n');
1048
- process.stdout.write(`(${rs.rows.length} ${rs.rows.length === 1 ? 'row' : 'rows'})\n\n`);
1054
+ process.stdout.write("--\n");
1055
+ process.stdout.write(`(${rs.rows.length} ${rs.rows.length === 1 ? "row" : "rows"})\n\n`);
1049
1056
  }
1050
1057
  }
1051
1058
  else if (rs.fields.length > 0) {
@@ -1063,7 +1070,7 @@ export const cmdGetResults = {
1063
1070
  // `_externalDrained` check, which is only consulted by `end()`
1064
1071
  // to skip ALREADY-INSPECTED rejections).
1065
1072
  const sessMark = session;
1066
- if (typeof sessMark.markDrained === 'function') {
1073
+ if (typeof sessMark.markDrained === "function") {
1067
1074
  sessMark.markDrained(end);
1068
1075
  }
1069
1076
  // Once we surface a rejection inline here, also clear any sticky
@@ -1071,7 +1078,7 @@ export const cmdGetResults = {
1071
1078
  // `\endpipeline`'s fallback doesn't re-emit the same diagnostic.
1072
1079
  if (errorRenderedHere) {
1073
1080
  const sessAny = session;
1074
- if (typeof sessAny.clearLastError === 'function') {
1081
+ if (typeof sessAny.clearLastError === "function") {
1075
1082
  sessAny.clearLastError();
1076
1083
  }
1077
1084
  }
@@ -1104,9 +1111,9 @@ export const cmdGetResults = {
1104
1111
  // `\getresults 1` x5 after 4 commands + 1 sync drains the 5th
1105
1112
  // call silently against the SyncMarker; a 6th call would emit
1106
1113
  // "No pending results to get".
1107
- bumpCounter(ctx.settings, 'PIPELINE_SYNC_COUNT', -syncsDrained);
1108
- bumpCounter(ctx.settings, 'PIPELINE_RESULT_COUNT', -resultsDrained);
1109
- return { status: 'ok' };
1114
+ bumpCounter(ctx.settings, "PIPELINE_SYNC_COUNT", -syncsDrained);
1115
+ bumpCounter(ctx.settings, "PIPELINE_RESULT_COUNT", -resultsDrained);
1116
+ return { status: "ok" };
1110
1117
  }
1111
1118
  catch (err) {
1112
1119
  return errResult(ctx, errorToMessage(err));
@@ -1122,7 +1129,7 @@ export const cmdGetResults = {
1122
1129
  // module) continues to compile. Registration is left to `cmd_io.ts`'s
1123
1130
  // `registerIoCommands` so we don't double-register.
1124
1131
  // ---------------------------------------------------------------------------
1125
- export { cmdGdesc } from './cmd_io.js';
1132
+ export { cmdGdesc } from "./cmd_io.js";
1126
1133
  // ---------------------------------------------------------------------------
1127
1134
  // Registration entry point.
1128
1135
  // ---------------------------------------------------------------------------