neonctl 2.27.1 → 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 (136) hide show
  1. package/README.md +35 -3
  2. package/dist/analytics.js +52 -34
  3. package/dist/api.js +643 -13
  4. package/dist/auth.js +50 -44
  5. package/dist/cli.js +8 -1
  6. package/dist/commands/auth.js +64 -51
  7. package/dist/commands/bootstrap.js +115 -157
  8. package/dist/commands/branches.js +160 -150
  9. package/dist/commands/bucket.js +183 -146
  10. package/dist/commands/checkout.js +51 -51
  11. package/dist/commands/config.js +228 -82
  12. package/dist/commands/connection_string.js +62 -62
  13. package/dist/commands/data_api.js +100 -101
  14. package/dist/commands/databases.js +29 -26
  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 +101 -104
  19. package/dist/commands/index.js +27 -25
  20. package/dist/commands/init.js +23 -22
  21. package/dist/commands/ip_allow.js +29 -29
  22. package/dist/commands/link.js +232 -182
  23. package/dist/commands/neon_auth.js +385 -370
  24. package/dist/commands/operations.js +11 -11
  25. package/dist/commands/orgs.js +8 -8
  26. package/dist/commands/projects.js +103 -101
  27. package/dist/commands/psql.js +31 -31
  28. package/dist/commands/roles.js +27 -24
  29. package/dist/commands/schema_diff.js +25 -26
  30. package/dist/commands/set_context.js +17 -17
  31. package/dist/commands/status.js +40 -0
  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 +37 -14
  37. package/dist/current_branch_fast_path.js +55 -0
  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 +68 -5
  45. package/dist/functions_api.js +10 -10
  46. package/dist/help.js +15 -15
  47. package/dist/index.js +110 -107
  48. package/dist/log.js +2 -2
  49. package/dist/parameters.gen.js +14 -14
  50. package/dist/pkg.js +5 -5
  51. package/dist/psql/cli.js +4 -2
  52. package/dist/psql/command/cmd_cond.js +61 -61
  53. package/dist/psql/command/cmd_connect.js +159 -154
  54. package/dist/psql/command/cmd_copy.js +107 -97
  55. package/dist/psql/command/cmd_describe.js +368 -363
  56. package/dist/psql/command/cmd_format.js +276 -263
  57. package/dist/psql/command/cmd_io.js +269 -263
  58. package/dist/psql/command/cmd_lo.js +74 -66
  59. package/dist/psql/command/cmd_meta.js +148 -148
  60. package/dist/psql/command/cmd_misc.js +17 -17
  61. package/dist/psql/command/cmd_pipeline.js +142 -135
  62. package/dist/psql/command/cmd_restrict.js +25 -25
  63. package/dist/psql/command/cmd_show.js +183 -168
  64. package/dist/psql/command/dispatch.js +26 -26
  65. package/dist/psql/command/shared.js +14 -14
  66. package/dist/psql/complete/filenames.js +16 -16
  67. package/dist/psql/complete/index.js +4 -4
  68. package/dist/psql/complete/matcher.js +33 -32
  69. package/dist/psql/complete/psqlVars.js +173 -173
  70. package/dist/psql/complete/queries.js +5 -3
  71. package/dist/psql/complete/rules.js +900 -863
  72. package/dist/psql/core/common.js +136 -133
  73. package/dist/psql/core/help.js +343 -343
  74. package/dist/psql/core/mainloop.js +160 -153
  75. package/dist/psql/core/prompt.js +126 -123
  76. package/dist/psql/core/settings.js +111 -111
  77. package/dist/psql/core/sqlHelp.js +150 -150
  78. package/dist/psql/core/startup.js +211 -205
  79. package/dist/psql/core/syncVars.js +14 -14
  80. package/dist/psql/core/variables.js +24 -24
  81. package/dist/psql/describe/formatters.js +302 -289
  82. package/dist/psql/describe/processNamePattern.js +28 -28
  83. package/dist/psql/describe/queries.js +656 -651
  84. package/dist/psql/index.js +436 -411
  85. package/dist/psql/io/history.js +36 -36
  86. package/dist/psql/io/input.js +15 -15
  87. package/dist/psql/io/lineEditor/buffer.js +27 -25
  88. package/dist/psql/io/lineEditor/complete.js +15 -15
  89. package/dist/psql/io/lineEditor/filename.js +22 -22
  90. package/dist/psql/io/lineEditor/index.js +65 -62
  91. package/dist/psql/io/lineEditor/keymap.js +325 -318
  92. package/dist/psql/io/lineEditor/vt100.js +60 -60
  93. package/dist/psql/io/pgpass.js +18 -18
  94. package/dist/psql/io/pgservice.js +14 -14
  95. package/dist/psql/io/psqlrc.js +46 -46
  96. package/dist/psql/print/aligned.js +175 -166
  97. package/dist/psql/print/asciidoc.js +51 -51
  98. package/dist/psql/print/crosstab.js +34 -31
  99. package/dist/psql/print/csv.js +25 -22
  100. package/dist/psql/print/html.js +54 -54
  101. package/dist/psql/print/json.js +12 -12
  102. package/dist/psql/print/latex.js +118 -118
  103. package/dist/psql/print/pager.js +28 -26
  104. package/dist/psql/print/troff.js +48 -48
  105. package/dist/psql/print/unaligned.js +15 -14
  106. package/dist/psql/print/units.js +17 -17
  107. package/dist/psql/scanner/slash.js +48 -46
  108. package/dist/psql/scanner/sql.js +88 -84
  109. package/dist/psql/scanner/stringutils.js +21 -17
  110. package/dist/psql/types/index.js +7 -7
  111. package/dist/psql/types/scanner.js +8 -8
  112. package/dist/psql/wire/connection.js +341 -327
  113. package/dist/psql/wire/copy.js +7 -7
  114. package/dist/psql/wire/pipeline.js +26 -24
  115. package/dist/psql/wire/protocol.js +102 -102
  116. package/dist/psql/wire/sasl.js +62 -62
  117. package/dist/psql/wire/tls.js +79 -73
  118. package/dist/storage_api.js +22 -23
  119. package/dist/test_utils/fixtures.js +74 -41
  120. package/dist/test_utils/oauth_server.js +5 -5
  121. package/dist/utils/api_enums.js +33 -0
  122. package/dist/utils/branch_notice.js +5 -5
  123. package/dist/utils/branch_picker.js +26 -26
  124. package/dist/utils/compute_units.js +4 -4
  125. package/dist/utils/enrichers.js +28 -16
  126. package/dist/utils/esbuild.js +28 -28
  127. package/dist/utils/formats.js +1 -1
  128. package/dist/utils/middlewares.js +3 -3
  129. package/dist/utils/package_manager.js +68 -0
  130. package/dist/utils/point_in_time.js +12 -12
  131. package/dist/utils/psql.js +30 -30
  132. package/dist/utils/string.js +2 -2
  133. package/dist/utils/ui.js +9 -9
  134. package/dist/utils/zip.js +1 -1
  135. package/dist/writer.js +17 -17
  136. package/package.json +10 -12
@@ -24,23 +24,23 @@
24
24
  * Server signature verification uses `crypto.timingSafeEqual` to avoid
25
25
  * leaking timing information about the comparison result.
26
26
  */
27
- import { createHash, createHmac, pbkdf2Sync, randomBytes as nodeRandomBytes, timingSafeEqual, } from 'node:crypto';
27
+ import { createHash, createHmac, randomBytes as nodeRandomBytes, pbkdf2Sync, timingSafeEqual, } from "node:crypto";
28
28
  export class SaslMechanismError extends Error {
29
29
  constructor(message) {
30
30
  super(message);
31
- this.name = 'SaslMechanismError';
31
+ this.name = "SaslMechanismError";
32
32
  }
33
33
  }
34
34
  export class SaslVerificationError extends Error {
35
35
  constructor(message) {
36
36
  super(message);
37
- this.name = 'SaslVerificationError';
37
+ this.name = "SaslVerificationError";
38
38
  }
39
39
  }
40
40
  export class SaslProtocolError extends Error {
41
41
  constructor(message) {
42
42
  super(message);
43
- this.name = 'SaslProtocolError';
43
+ this.name = "SaslProtocolError";
44
44
  }
45
45
  }
46
46
  export function createScramClient(opts) {
@@ -49,9 +49,9 @@ export function createScramClient(opts) {
49
49
  // 18 raw bytes => 24 base64 chars; same width as upstream pg.
50
50
  // Commas are not part of the base64 alphabet, so the nonce is automatically
51
51
  // SCRAM-safe (RFC 5802 §5.1 forbids `,` in `r=`).
52
- const clientNonce = rng(18).toString('base64');
52
+ const clientNonce = rng(18).toString("base64");
53
53
  const internal = {
54
- state: 'init',
54
+ state: "init",
55
55
  mechanism,
56
56
  clientNonce,
57
57
  gs2Header,
@@ -69,15 +69,15 @@ export function createScramClient(opts) {
69
69
  };
70
70
  }
71
71
  function chooseMechanism(advertised, channelBinding) {
72
- const hasPlus = advertised.includes('SCRAM-SHA-256-PLUS');
73
- const hasPlain = advertised.includes('SCRAM-SHA-256');
72
+ const hasPlus = advertised.includes("SCRAM-SHA-256-PLUS");
73
+ const hasPlain = advertised.includes("SCRAM-SHA-256");
74
74
  if (channelBinding && hasPlus) {
75
- const gs2 = 'p=tls-server-end-point,,';
75
+ const gs2 = "p=tls-server-end-point,,";
76
76
  return {
77
- mechanism: 'SCRAM-SHA-256-PLUS',
77
+ mechanism: "SCRAM-SHA-256-PLUS",
78
78
  gs2Header: gs2,
79
79
  cbindInput: Buffer.concat([
80
- Buffer.from(gs2, 'utf8'),
80
+ Buffer.from(gs2, "utf8"),
81
81
  channelBinding.data,
82
82
  ]),
83
83
  };
@@ -86,96 +86,96 @@ function chooseMechanism(advertised, channelBinding) {
86
86
  // Client has channel-binding data but server doesn't advertise PLUS: per
87
87
  // RFC 5802 §6 the client must signal this with `y` so a downgrade attack
88
88
  // is detected (the server, if PLUS-capable, would have advertised it).
89
- const gs2 = channelBinding ? 'y,,' : 'n,,';
89
+ const gs2 = channelBinding ? "y,," : "n,,";
90
90
  return {
91
- mechanism: 'SCRAM-SHA-256',
91
+ mechanism: "SCRAM-SHA-256",
92
92
  gs2Header: gs2,
93
- cbindInput: Buffer.from(gs2, 'utf8'),
93
+ cbindInput: Buffer.from(gs2, "utf8"),
94
94
  };
95
95
  }
96
- throw new SaslMechanismError(`SASL: server offered [${advertised.join(', ')}] but only SCRAM-SHA-256 and SCRAM-SHA-256-PLUS are supported`);
96
+ throw new SaslMechanismError(`SASL: server offered [${advertised.join(", ")}] but only SCRAM-SHA-256 and SCRAM-SHA-256-PLUS are supported`);
97
97
  }
98
98
  function start(s) {
99
- if (s.state !== 'init') {
99
+ if (s.state !== "init") {
100
100
  throw new SaslProtocolError(`SASL: start() called in state ${s.state}`);
101
101
  }
102
102
  // n=,r=<nonce> — the username field is empty because PostgreSQL ignores it
103
103
  // (the actual user was sent in StartupMessage) and an empty `n=` matches
104
104
  // libpq's wire output. Note pg sends `n=*` instead; both interoperate.
105
105
  const clientFirstBare = `n=,r=${s.clientNonce}`;
106
- const clientFirstMessage = Buffer.from(s.gs2Header + clientFirstBare, 'utf8');
107
- s.state = 'sent-first';
106
+ const clientFirstMessage = Buffer.from(s.gs2Header + clientFirstBare, "utf8");
107
+ s.state = "sent-first";
108
108
  return { mechanism: s.mechanism, clientFirstMessage };
109
109
  }
110
110
  function continueSession(s, serverFirst) {
111
- if (s.state !== 'sent-first') {
111
+ if (s.state !== "sent-first") {
112
112
  throw new SaslProtocolError(`SASL: continue() called in state ${s.state}`);
113
113
  }
114
- const serverFirstStr = serverFirst.toString('utf8');
114
+ const serverFirstStr = serverFirst.toString("utf8");
115
115
  const parsed = parseServerFirst(serverFirstStr);
116
116
  if (!parsed.nonce.startsWith(s.clientNonce)) {
117
- throw new SaslProtocolError('SASL: server nonce does not start with client nonce');
117
+ throw new SaslProtocolError("SASL: server nonce does not start with client nonce");
118
118
  }
119
119
  if (parsed.nonce.length === s.clientNonce.length) {
120
- throw new SaslProtocolError('SASL: server nonce is too short');
120
+ throw new SaslProtocolError("SASL: server nonce is too short");
121
121
  }
122
122
  const clientFirstBare = `n=,r=${s.clientNonce}`;
123
123
  const serverFirstString = `r=${parsed.nonce},s=${parsed.salt},i=${String(parsed.iteration)}`;
124
124
  // c=<base64 of GS2 header || optional CB data>
125
- const channelBindingB64 = s.cbindInput.toString('base64');
125
+ const channelBindingB64 = s.cbindInput.toString("base64");
126
126
  const clientFinalWithoutProof = `c=${channelBindingB64},r=${parsed.nonce}`;
127
127
  const authMessage = `${clientFirstBare},${serverFirstString},${clientFinalWithoutProof}`;
128
- const saltBytes = Buffer.from(parsed.salt, 'base64');
128
+ const saltBytes = Buffer.from(parsed.salt, "base64");
129
129
  // SASLprep the password before PBKDF2 (RFC 5802 §2.2). Our impl is minimal;
130
130
  // see saslprep() comment for the deviation from full RFC 4013.
131
131
  const normalizedPassword = saslprep(s.password);
132
- const saltedPassword = pbkdf2Sync(Buffer.from(normalizedPassword, 'utf8'), saltBytes, parsed.iteration, 32, 'sha256');
133
- const clientKey = hmac(saltedPassword, 'Client Key');
132
+ const saltedPassword = pbkdf2Sync(Buffer.from(normalizedPassword, "utf8"), saltBytes, parsed.iteration, 32, "sha256");
133
+ const clientKey = hmac(saltedPassword, "Client Key");
134
134
  const storedKey = sha256(clientKey);
135
135
  const clientSignature = hmac(storedKey, authMessage);
136
136
  const clientProof = xor(clientKey, clientSignature);
137
- const serverKey = hmac(saltedPassword, 'Server Key');
137
+ const serverKey = hmac(saltedPassword, "Server Key");
138
138
  s.serverSignature = hmac(serverKey, authMessage);
139
- s.state = 'sent-final';
140
- return Buffer.from(`${clientFinalWithoutProof},p=${clientProof.toString('base64')}`, 'utf8');
139
+ s.state = "sent-final";
140
+ return Buffer.from(`${clientFinalWithoutProof},p=${clientProof.toString("base64")}`, "utf8");
141
141
  }
142
142
  function finishSession(s, serverFinal) {
143
- if (s.state !== 'sent-final') {
143
+ if (s.state !== "sent-final") {
144
144
  throw new SaslProtocolError(`SASL: finish() called in state ${s.state}`);
145
145
  }
146
146
  if (s.serverSignature === null) {
147
147
  // Defensive: should be impossible because state machine guards it.
148
- throw new SaslProtocolError('SASL: no server signature recorded');
148
+ throw new SaslProtocolError("SASL: no server signature recorded");
149
149
  }
150
- const parsed = parseServerFinal(serverFinal.toString('utf8'));
151
- const received = Buffer.from(parsed.serverSignature, 'base64');
150
+ const parsed = parseServerFinal(serverFinal.toString("utf8"));
151
+ const received = Buffer.from(parsed.serverSignature, "base64");
152
152
  // Constant-time comparison: defeats timing side channels that could let an
153
153
  // attacker (with control over `v=`) learn the prefix of our derived signature.
154
154
  if (received.length !== s.serverSignature.length ||
155
155
  !timingSafeEqual(received, s.serverSignature)) {
156
- throw new SaslVerificationError('SASL: server signature does not match — possible MITM or wrong password');
156
+ throw new SaslVerificationError("SASL: server signature does not match — possible MITM or wrong password");
157
157
  }
158
- s.state = 'done';
158
+ s.state = "done";
159
159
  }
160
160
  function parseServerFirst(text) {
161
161
  const attrs = parseAttributePairs(text);
162
- const nonce = attrs.get('r');
162
+ const nonce = attrs.get("r");
163
163
  if (!nonce) {
164
- throw new SaslProtocolError('SASL: server-first missing `r=` (nonce)');
164
+ throw new SaslProtocolError("SASL: server-first missing `r=` (nonce)");
165
165
  }
166
166
  if (!isPrintableChars(nonce)) {
167
- throw new SaslProtocolError('SASL: server-first nonce contains non-printable characters');
167
+ throw new SaslProtocolError("SASL: server-first nonce contains non-printable characters");
168
168
  }
169
- const salt = attrs.get('s');
169
+ const salt = attrs.get("s");
170
170
  if (!salt) {
171
- throw new SaslProtocolError('SASL: server-first missing `s=` (salt)');
171
+ throw new SaslProtocolError("SASL: server-first missing `s=` (salt)");
172
172
  }
173
173
  if (!isBase64(salt)) {
174
- throw new SaslProtocolError('SASL: server-first salt is not base64');
174
+ throw new SaslProtocolError("SASL: server-first salt is not base64");
175
175
  }
176
- const iterStr = attrs.get('i');
176
+ const iterStr = attrs.get("i");
177
177
  if (!iterStr) {
178
- throw new SaslProtocolError('SASL: server-first missing `i=` (iterations)');
178
+ throw new SaslProtocolError("SASL: server-first missing `i=` (iterations)");
179
179
  }
180
180
  if (!/^[1-9][0-9]*$/.test(iterStr)) {
181
181
  throw new SaslProtocolError(`SASL: server-first iteration count is not a positive integer: ${iterStr}`);
@@ -184,23 +184,23 @@ function parseServerFirst(text) {
184
184
  }
185
185
  function parseServerFinal(text) {
186
186
  const attrs = parseAttributePairs(text);
187
- const errorAttr = attrs.get('e');
187
+ const errorAttr = attrs.get("e");
188
188
  if (errorAttr) {
189
189
  throw new SaslVerificationError(`SASL: server-final returned error: ${errorAttr}`);
190
190
  }
191
- const v = attrs.get('v');
191
+ const v = attrs.get("v");
192
192
  if (!v) {
193
- throw new SaslProtocolError('SASL: server-final missing `v=` (server signature)');
193
+ throw new SaslProtocolError("SASL: server-final missing `v=` (server signature)");
194
194
  }
195
195
  if (!isBase64(v)) {
196
- throw new SaslProtocolError('SASL: server-final `v=` is not base64');
196
+ throw new SaslProtocolError("SASL: server-final `v=` is not base64");
197
197
  }
198
198
  return { serverSignature: v };
199
199
  }
200
200
  function parseAttributePairs(text) {
201
201
  const out = new Map();
202
- for (const pair of text.split(',')) {
203
- if (pair.length < 2 || pair[1] !== '=') {
202
+ for (const pair of text.split(",")) {
203
+ if (pair.length < 2 || pair[1] !== "=") {
204
204
  throw new SaslProtocolError(`SASL: malformed attribute pair: ${JSON.stringify(pair)}`);
205
205
  }
206
206
  const key = pair[0];
@@ -232,12 +232,12 @@ function isBase64(text) {
232
232
  // Crypto helpers
233
233
  // ---------------------------------------------------------------------------
234
234
  function hmac(key, msg) {
235
- const h = createHmac('sha256', key);
235
+ const h = createHmac("sha256", key);
236
236
  h.update(msg);
237
237
  return h.digest();
238
238
  }
239
239
  function sha256(data) {
240
- return createHash('sha256').update(data).digest();
240
+ return createHash("sha256").update(data).digest();
241
241
  }
242
242
  function xor(a, b) {
243
243
  if (a.length !== b.length) {
@@ -276,21 +276,21 @@ function xor(a, b) {
276
276
  // string so the source file stays ASCII-only and so we sidestep ESLint's
277
277
  // `no-irregular-whitespace` and `no-misleading-character-class` rules —
278
278
  // those only inspect raw regex literals, not dynamically-built patterns.
279
- const NON_ASCII_SPACE_RE = new RegExp('[' + '\u00A0\u1680' + '\u2000-\u200B' + '\u202F\u205F\u3000' + ']', 'g');
279
+ const NON_ASCII_SPACE_RE = new RegExp("[" + "\u00A0\u1680" + "\u2000-\u200B" + "\u202F\u205F\u3000" + "]", "g");
280
280
  // Combining marks and ZWJ are intentionally in this class; RFC 3454 Table B.1
281
281
  // strips them precisely because they combine with neighbouring code points.
282
282
  /* eslint-disable no-misleading-character-class */
283
- const MAPPED_TO_NOTHING_RE = new RegExp('[' +
284
- '\u00AD\u034F\u1806' +
285
- '\u180B-\u180D' +
286
- '\u200C\u200D\u2060' +
287
- '\uFE00-\uFE0F' +
288
- '\uFEFF' +
289
- ']', 'g');
283
+ const MAPPED_TO_NOTHING_RE = new RegExp("[" +
284
+ "\u00AD\u034F\u1806" +
285
+ "\u180B-\u180D" +
286
+ "\u200C\u200D\u2060" +
287
+ "\uFE00-\uFE0F" +
288
+ "\uFEFF" +
289
+ "]", "g");
290
290
  /* eslint-enable no-misleading-character-class */
291
291
  function saslprep(password) {
292
292
  return password
293
- .replace(NON_ASCII_SPACE_RE, ' ')
294
- .replace(MAPPED_TO_NOTHING_RE, '')
295
- .normalize('NFKC');
293
+ .replace(NON_ASCII_SPACE_RE, " ")
294
+ .replace(MAPPED_TO_NOTHING_RE, "")
295
+ .normalize("NFKC");
296
296
  }