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
package/dist/api.js CHANGED
@@ -1,17 +1,194 @@
1
- import { createApiClient } from '@neondatabase/api-client';
2
- import { isAxiosError } from 'axios';
3
- import { log } from './log.js';
4
- import pkg from './pkg.js';
5
- export const getApiClient = ({ apiKey, apiHost }) => createApiClient({
6
- apiKey,
7
- baseURL: apiHost,
8
- timeout: 60000,
9
- headers: {
10
- 'User-Agent': `neonctl v${pkg.version}`,
11
- },
12
- });
1
+ // Thin fetch-based client layer over `@neon/sdk` (the official, fetch-native
2
+ // Neon SDK). neonctl was originally built on the axios-based
3
+ // `@neondatabase/api-client`, whose generated `Api` object exposes one
4
+ // positional method per endpoint and resolves to an `AxiosResponse`. This module
5
+ // reproduces exactly the subset of `Api` methods neonctl uses, backed by the
6
+ // tree-shakeable `@neon/sdk/raw` functions, and returns a small
7
+ // `{ data, status, headers }` envelope the call sites destructure.
8
+ //
9
+ // On a non-2xx response (or a network/timeout failure) it throws a single typed
10
+ // {@link NeonApiError}; every call site narrows failures with
11
+ // {@link isNeonApiError} and reads `error.status` / `error.data`. There is no
12
+ // axios anywhere in neonctl: requests go through the global `fetch`, and this is
13
+ // the one place HTTP errors are shaped.
14
+ import { Readable } from "node:stream";
15
+ import * as raw from "@neon/sdk/raw";
16
+ import { createClient, createConfig } from "@neon/sdk/raw";
17
+ import { EnvHttpProxyAgent, setGlobalDispatcher } from "undici";
18
+ import { log } from "./log.js";
19
+ import pkg from "./pkg.js";
20
+ // Node's global `fetch` (undici) ignores HTTP_PROXY / HTTPS_PROXY / NO_PROXY,
21
+ // whereas the axios-based client neonctl used previously honored them. Restore
22
+ // that behaviour by installing a proxy-aware global dispatcher — but only when a
23
+ // proxy is actually configured, so the default (no-proxy) path stays untouched.
24
+ // This covers every `fetch` neonctl makes, including the direct S3 upload.
25
+ const PROXY_ENV_VARS = [
26
+ "HTTP_PROXY",
27
+ "http_proxy",
28
+ "HTTPS_PROXY",
29
+ "https_proxy",
30
+ "ALL_PROXY",
31
+ "all_proxy",
32
+ ];
33
+ if (PROXY_ENV_VARS.some((name) => process.env[name])) {
34
+ setGlobalDispatcher(new EnvHttpProxyAgent());
35
+ }
36
+ const DEFAULT_API_HOST = "https://console.neon.tech/api/v2";
37
+ const REQUEST_TIMEOUT_MS = 60000;
38
+ const USER_AGENT = `neonctl v${pkg.version}`;
39
+ /** Mirrors the api-client `ContentType` enum used by the `request()` escape hatch. */
40
+ export var ContentType;
41
+ (function (ContentType) {
42
+ ContentType["Json"] = "application/json";
43
+ ContentType["FormData"] = "multipart/form-data";
44
+ ContentType["UrlEncoded"] = "application/x-www-form-urlencoded";
45
+ ContentType["Text"] = "text/plain";
46
+ })(ContentType || (ContentType = {}));
47
+ /**
48
+ * The single error type thrown by the neonctl API layer. It carries the HTTP
49
+ * status and parsed body for a non-2xx response, or a `code` (e.g. `ETIMEDOUT`)
50
+ * for a network/timeout failure. Call sites narrow with {@link isNeonApiError}
51
+ * and read `status` / `data` rather than reaching into an axios-shaped object.
52
+ */
53
+ export class NeonApiError extends Error {
54
+ constructor(message, init = {}) {
55
+ super(message);
56
+ this.name = "NeonApiError";
57
+ this.status = init.status;
58
+ this.statusText = init.statusText;
59
+ this.data = init.data;
60
+ this.headers = init.headers;
61
+ this.requestPath = init.requestPath;
62
+ this.code = init.code;
63
+ }
64
+ }
65
+ /** Narrow an unknown error to a {@link NeonApiError}. */
66
+ export function isNeonApiError(err) {
67
+ return err instanceof NeonApiError;
68
+ }
69
+ /** Extract a `message` string from a parsed error body, if present. */
70
+ export function messageFromBody(body) {
71
+ if (body && typeof body === "object" && "message" in body) {
72
+ const message = body.message;
73
+ if (typeof message === "string")
74
+ return message;
75
+ }
76
+ return undefined;
77
+ }
78
+ /** Extract a machine-readable `code` string from a parsed error body, if present. */
79
+ export function codeFromBody(body) {
80
+ if (body && typeof body === "object" && "code" in body) {
81
+ const code = body.code;
82
+ if (typeof code === "string")
83
+ return code;
84
+ }
85
+ return undefined;
86
+ }
87
+ /**
88
+ * Adapt a WHATWG `ReadableStream` (what `fetch` gives us as `response.body`) to
89
+ * a Node `Readable`, so callers can `pipeline()` the body straight to disk. Done
90
+ * by hand rather than `Readable.fromWeb` to sidestep the DOM-vs-`node:stream/web`
91
+ * `ReadableStream` type friction without an unsafe cast.
92
+ */
93
+ function webStreamToNodeReadable(body) {
94
+ const reader = body.getReader();
95
+ return new Readable({
96
+ async read() {
97
+ try {
98
+ const { done, value } = await reader.read();
99
+ this.push(done ? null : Buffer.from(value));
100
+ }
101
+ catch (err) {
102
+ this.destroy(err instanceof Error ? err : new Error(String(err)));
103
+ }
104
+ },
105
+ });
106
+ }
107
+ function headersToObject(headers) {
108
+ const out = {};
109
+ headers.forEach((value, key) => {
110
+ out[key] = value;
111
+ });
112
+ return out;
113
+ }
114
+ function isAbortError(err) {
115
+ return (err instanceof Error &&
116
+ (err.name === "AbortError" || err.name === "TimeoutError"));
117
+ }
118
+ /**
119
+ * Walk an error's `cause` chain to find the underlying socket/DNS `code` (e.g.
120
+ * `ECONNREFUSED`, `ENOTFOUND`) — `fetch` surfaces these as the `cause` of a bare
121
+ * `TypeError: fetch failed`. Preserving the code lets `isNetworkError` classify
122
+ * the resulting {@link NeonApiError} as a connectivity failure.
123
+ */
124
+ function readSocketCode(err) {
125
+ let current = err;
126
+ for (let depth = 0; depth < 6 && current != null; depth++) {
127
+ if (typeof current === "object" && "code" in current) {
128
+ const code = current.code;
129
+ if (typeof code === "string")
130
+ return code;
131
+ }
132
+ current = current.cause;
133
+ }
134
+ return undefined;
135
+ }
136
+ /** Build a {@link NeonApiError} from a non-2xx `Response` and its parsed body. */
137
+ function httpError(response, body) {
138
+ let requestPath;
139
+ try {
140
+ requestPath = new URL(response.url).pathname;
141
+ }
142
+ catch {
143
+ // response.url may be empty in some runtimes; the path is best-effort.
144
+ }
145
+ return new NeonApiError(messageFromBody(body) ??
146
+ `Request failed with status code ${response.status}`, {
147
+ status: response.status,
148
+ statusText: response.statusText,
149
+ data: body,
150
+ headers: headersToObject(response.headers),
151
+ requestPath,
152
+ });
153
+ }
154
+ /**
155
+ * Translate a thrown `fetch` failure into a {@link NeonApiError}. A request
156
+ * timeout uses `ECONNABORTED` (matching the old axios behaviour, and excluded
157
+ * from `isNetworkError`'s connectivity codes so it's still reported as a
158
+ * timeout). A connection failure keeps its real socket code (e.g.
159
+ * `ECONNREFUSED`) so `isNetworkError` recognises it as a connectivity problem.
160
+ */
161
+ function networkError(err) {
162
+ if (isAbortError(err)) {
163
+ return new NeonApiError("Request timed out", { code: "ECONNABORTED" });
164
+ }
165
+ return new NeonApiError(err instanceof Error ? err.message : String(err), {
166
+ code: readSocketCode(err) ?? "ENETWORK",
167
+ });
168
+ }
169
+ /**
170
+ * `fetch` with neonctl's request timeout applied (preserving any caller signal)
171
+ * and lightweight debug logging of the request line + response status — the
172
+ * fetch-native replacement for the old `axios-debug-log` wiring.
173
+ */
174
+ const timedFetch = async (input, init) => {
175
+ const timeout = AbortSignal.timeout(REQUEST_TIMEOUT_MS);
176
+ const signal = init?.signal
177
+ ? AbortSignal.any([init.signal, timeout])
178
+ : timeout;
179
+ const method = init?.method ?? (input instanceof Request ? input.method : "GET");
180
+ const url = input instanceof Request ? input.url : String(input);
181
+ log.debug("%s %s", method.toUpperCase(), url);
182
+ const response = await fetch(input, { ...init, signal });
183
+ log.debug("%d %s", response.status, response.statusText);
184
+ return response;
185
+ };
13
186
  const RETRY_COUNT = 5;
14
187
  const RETRY_DELAY = 3000;
188
+ /**
189
+ * Retry a call while the API answers 423 (Locked) — Neon's "a prior mutation on
190
+ * this resource is still in flight" signal.
191
+ */
15
192
  export const retryOnLock = async (fn) => {
16
193
  let attempt = 0;
17
194
  let errOut;
@@ -21,7 +198,7 @@ export const retryOnLock = async (fn) => {
21
198
  }
22
199
  catch (err) {
23
200
  errOut = err;
24
- if (isAxiosError(err) && err.response?.status === 423) {
201
+ if (isNeonApiError(err) && err.status === 423) {
25
202
  attempt++;
26
203
  log.info(`Resource is locked. Waiting ${RETRY_DELAY}ms before retrying...`);
27
204
  await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY));
@@ -33,3 +210,456 @@ export const retryOnLock = async (fn) => {
33
210
  }
34
211
  throw errOut;
35
212
  };
213
+ function buildUrl(apiHost, path, query) {
214
+ const url = new URL(`${apiHost.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`);
215
+ if (query) {
216
+ for (const [key, value] of Object.entries(query)) {
217
+ if (value === undefined || value === null)
218
+ continue;
219
+ url.searchParams.set(key, String(value));
220
+ }
221
+ }
222
+ return url.toString();
223
+ }
224
+ async function readJsonBody(response) {
225
+ const text = await response.text();
226
+ if (text.trim() === "")
227
+ return undefined;
228
+ try {
229
+ return JSON.parse(text);
230
+ }
231
+ catch {
232
+ // Match axios' `responseType: 'json'` behaviour: a body that isn't valid
233
+ // JSON is surfaced as the raw string rather than coerced into an object, so
234
+ // callers' `body?.message` checks correctly see "no structured message".
235
+ return text;
236
+ }
237
+ }
238
+ export const getApiClient = ({ apiKey, apiHost }) => {
239
+ const baseUrl = apiHost ?? DEFAULT_API_HOST;
240
+ const client = createClient(createConfig({
241
+ auth: () => apiKey,
242
+ baseUrl,
243
+ fetch: timedFetch,
244
+ headers: { "User-Agent": USER_AGENT },
245
+ }));
246
+ /** Await a raw call, unwrap to a `{ data, status, headers }` envelope, or throw {@link NeonApiError}. */
247
+ async function call(run) {
248
+ let result;
249
+ try {
250
+ result = await run();
251
+ }
252
+ catch (err) {
253
+ throw networkError(err);
254
+ }
255
+ const response = result.response;
256
+ if (!response) {
257
+ throw networkError(result.error ?? new Error("No response from Neon API"));
258
+ }
259
+ if (!response.ok) {
260
+ throw httpError(response, result.error ?? result.data);
261
+ }
262
+ return {
263
+ data: result.data,
264
+ status: response.status,
265
+ statusText: response.statusText,
266
+ headers: headersToObject(response.headers),
267
+ };
268
+ }
269
+ /**
270
+ * Low-level request used by the object-storage and functions helpers for
271
+ * endpoints not (yet) modeled as typed SDK functions. Mirrors the api-client
272
+ * `HttpClient.request()`: `format: 'json'` parses the body, `format: 'stream'`
273
+ * returns a Node `Readable`, and `type: ContentType.FormData` sends multipart.
274
+ */
275
+ async function request(params) {
276
+ const url = buildUrl(baseUrl, params.path, params.query);
277
+ const headers = { "User-Agent": USER_AGENT };
278
+ if (params.secure !== false) {
279
+ headers.Authorization = `Bearer ${apiKey}`;
280
+ }
281
+ let payload;
282
+ if (params.body instanceof FormData ||
283
+ params.type === ContentType.FormData) {
284
+ payload = params.body;
285
+ }
286
+ else if (params.body !== undefined) {
287
+ headers["Content-Type"] = ContentType.Json;
288
+ payload = JSON.stringify(params.body);
289
+ }
290
+ let response;
291
+ try {
292
+ response = await timedFetch(url, {
293
+ method: params.method,
294
+ headers,
295
+ ...(payload !== undefined ? { body: payload } : {}),
296
+ });
297
+ }
298
+ catch (err) {
299
+ throw networkError(err);
300
+ }
301
+ if (!response.ok) {
302
+ // For a streamed download the error body arrives as a stream too; hand it
303
+ // back as a Node `Readable` so the caller can drain it for a message.
304
+ const errorBody = params.format === "stream" && response.body
305
+ ? webStreamToNodeReadable(response.body)
306
+ : await readJsonBody(response);
307
+ throw httpError(response, errorBody);
308
+ }
309
+ let data;
310
+ if (params.format === "stream") {
311
+ data = response.body
312
+ ? webStreamToNodeReadable(response.body)
313
+ : undefined;
314
+ }
315
+ else {
316
+ data = await readJsonBody(response);
317
+ }
318
+ return {
319
+ data: data,
320
+ status: response.status,
321
+ statusText: response.statusText,
322
+ headers: headersToObject(response.headers),
323
+ };
324
+ }
325
+ return {
326
+ request,
327
+ // ─── Account / user ──────────────────────────────────────────────────
328
+ getCurrentUserInfo: () => call(() => raw.getCurrentUserInfo({ client })),
329
+ getCurrentUserOrganizations: () => call(() => raw.getCurrentUserOrganizations({ client })),
330
+ getAuthDetails: () => call(() => raw.getAuthDetails({ client })),
331
+ getActiveRegions: () => call(() => raw.getActiveRegions({ client })),
332
+ // ─── Projects ────────────────────────────────────────────────────────
333
+ listProjects: (query = {}) => call(() => raw.listProjects({ client, query })),
334
+ listSharedProjects: (query = {}) => call(() => raw.listSharedProjects({
335
+ client,
336
+ query: {
337
+ ...(query.cursor !== undefined
338
+ ? { cursor: query.cursor }
339
+ : {}),
340
+ ...(query.limit !== undefined
341
+ ? { limit: query.limit }
342
+ : {}),
343
+ ...(query.search !== undefined
344
+ ? { search: query.search }
345
+ : {}),
346
+ },
347
+ })),
348
+ getProject: (projectId) => call(() => raw.getProject({ client, path: { project_id: projectId } })),
349
+ createProject: (data) => call(() => raw.createProject({ client, body: data })),
350
+ updateProject: (projectId, data) => call(() => raw.updateProject({
351
+ client,
352
+ path: { project_id: projectId },
353
+ body: data,
354
+ })),
355
+ deleteProject: (projectId) => call(() => raw.deleteProject({ client, path: { project_id: projectId } })),
356
+ recoverProject: (projectId) => call(() => raw.recoverProject({ client, path: { project_id: projectId } })),
357
+ listProjectOperations: ({ projectId, ...query }) => call(() => raw.listProjectOperations({
358
+ client,
359
+ path: { project_id: projectId },
360
+ query,
361
+ })),
362
+ // ─── Branches ────────────────────────────────────────────────────────
363
+ listProjectBranches: ({ projectId, ...query }) => call(() => raw.listProjectBranches({
364
+ client,
365
+ path: { project_id: projectId },
366
+ query,
367
+ })),
368
+ createProjectBranch: (projectId, data) => call(() => raw.createProjectBranch({
369
+ client,
370
+ path: { project_id: projectId },
371
+ ...(data !== undefined ? { body: data } : {}),
372
+ })),
373
+ getProjectBranch: (projectId, branchId) => call(() => raw.getProjectBranch({
374
+ client,
375
+ path: { project_id: projectId, branch_id: branchId },
376
+ })),
377
+ updateProjectBranch: (projectId, branchId, data) => call(() => raw.updateProjectBranch({
378
+ client,
379
+ path: { project_id: projectId, branch_id: branchId },
380
+ body: data,
381
+ })),
382
+ deleteProjectBranch: (projectId, branchId) => call(() => raw.deleteProjectBranch({
383
+ client,
384
+ path: { project_id: projectId, branch_id: branchId },
385
+ })),
386
+ restoreProjectBranch: (projectId, branchId, data) => call(() => raw.restoreProjectBranch({
387
+ client,
388
+ path: { project_id: projectId, branch_id: branchId },
389
+ body: data,
390
+ })),
391
+ setDefaultProjectBranch: (projectId, branchId) => call(() => raw.setDefaultProjectBranch({
392
+ client,
393
+ path: { project_id: projectId, branch_id: branchId },
394
+ })),
395
+ getProjectBranchSchema: ({ projectId, branchId, ...query }) => call(() => raw.getProjectBranchSchema({
396
+ client,
397
+ path: { project_id: projectId, branch_id: branchId },
398
+ query,
399
+ })),
400
+ listProjectBranchEndpoints: (projectId, branchId) => call(() => raw.listProjectBranchEndpoints({
401
+ client,
402
+ path: { project_id: projectId, branch_id: branchId },
403
+ })),
404
+ createProjectEndpoint: (projectId, data) => call(() => raw.createProjectEndpoint({
405
+ client,
406
+ path: { project_id: projectId },
407
+ body: data,
408
+ })),
409
+ // ─── Databases ───────────────────────────────────────────────────────
410
+ listProjectBranchDatabases: (projectId, branchId) => call(() => raw.listProjectBranchDatabases({
411
+ client,
412
+ path: { project_id: projectId, branch_id: branchId },
413
+ })),
414
+ createProjectBranchDatabase: (projectId, branchId, data) => call(() => raw.createProjectBranchDatabase({
415
+ client,
416
+ path: { project_id: projectId, branch_id: branchId },
417
+ body: data,
418
+ })),
419
+ deleteProjectBranchDatabase: (projectId, branchId, databaseName) => call(() => raw.deleteProjectBranchDatabase({
420
+ client,
421
+ path: {
422
+ project_id: projectId,
423
+ branch_id: branchId,
424
+ database_name: databaseName,
425
+ },
426
+ })),
427
+ // ─── Roles ───────────────────────────────────────────────────────────
428
+ listProjectBranchRoles: (projectId, branchId) => call(() => raw.listProjectBranchRoles({
429
+ client,
430
+ path: { project_id: projectId, branch_id: branchId },
431
+ })),
432
+ createProjectBranchRole: (projectId, branchId, data) => call(() => raw.createProjectBranchRole({
433
+ client,
434
+ path: { project_id: projectId, branch_id: branchId },
435
+ body: data,
436
+ })),
437
+ deleteProjectBranchRole: (projectId, branchId, roleName) => call(() => raw.deleteProjectBranchRole({
438
+ client,
439
+ path: {
440
+ project_id: projectId,
441
+ branch_id: branchId,
442
+ role_name: roleName,
443
+ },
444
+ })),
445
+ getProjectBranchRolePassword: (projectId, branchId, roleName) => call(() => raw.getProjectBranchRolePassword({
446
+ client,
447
+ path: {
448
+ project_id: projectId,
449
+ branch_id: branchId,
450
+ role_name: roleName,
451
+ },
452
+ })),
453
+ // ─── Data API ────────────────────────────────────────────────────────
454
+ createProjectBranchDataApi: (projectId, branchId, databaseName, data) => call(() => raw.createProjectBranchDataApi({
455
+ client,
456
+ path: {
457
+ project_id: projectId,
458
+ branch_id: branchId,
459
+ database_name: databaseName,
460
+ },
461
+ body: data,
462
+ })),
463
+ updateProjectBranchDataApi: (projectId, branchId, databaseName, data) => call(() => raw.updateProjectBranchDataApi({
464
+ client,
465
+ path: {
466
+ project_id: projectId,
467
+ branch_id: branchId,
468
+ database_name: databaseName,
469
+ },
470
+ body: data,
471
+ })),
472
+ deleteProjectBranchDataApi: (projectId, branchId, databaseName) => call(() => raw.deleteProjectBranchDataApi({
473
+ client,
474
+ path: {
475
+ project_id: projectId,
476
+ branch_id: branchId,
477
+ database_name: databaseName,
478
+ },
479
+ })),
480
+ getProjectBranchDataApi: (projectId, branchId, databaseName) => call(() => raw.getProjectBranchDataApi({
481
+ client,
482
+ path: {
483
+ project_id: projectId,
484
+ branch_id: branchId,
485
+ database_name: databaseName,
486
+ },
487
+ })),
488
+ // ─── VPC endpoints (project + organization) ──────────────────────────
489
+ listProjectVpcEndpoints: (projectId) => call(() => raw.listProjectVpcEndpoints({
490
+ client,
491
+ path: { project_id: projectId },
492
+ })),
493
+ assignProjectVpcEndpoint: (projectId, vpcEndpointId, data) => call(() => raw.assignProjectVpcEndpoint({
494
+ client,
495
+ path: {
496
+ project_id: projectId,
497
+ vpc_endpoint_id: vpcEndpointId,
498
+ },
499
+ body: data,
500
+ })),
501
+ deleteProjectVpcEndpoint: (projectId, vpcEndpointId) => call(() => raw.deleteProjectVpcEndpoint({
502
+ client,
503
+ path: {
504
+ project_id: projectId,
505
+ vpc_endpoint_id: vpcEndpointId,
506
+ },
507
+ })),
508
+ listOrganizationVpcEndpoints: (orgId, regionId) => call(() => raw.listOrganizationVpcEndpoints({
509
+ client,
510
+ path: { org_id: orgId, region_id: regionId },
511
+ })),
512
+ getOrganizationVpcEndpointDetails: (orgId, regionId, vpcEndpointId) => call(() => raw.getOrganizationVpcEndpointDetails({
513
+ client,
514
+ path: {
515
+ org_id: orgId,
516
+ region_id: regionId,
517
+ vpc_endpoint_id: vpcEndpointId,
518
+ },
519
+ })),
520
+ assignOrganizationVpcEndpoint: (orgId, regionId, vpcEndpointId, data) => call(() => raw.assignOrganizationVpcEndpoint({
521
+ client,
522
+ path: {
523
+ org_id: orgId,
524
+ region_id: regionId,
525
+ vpc_endpoint_id: vpcEndpointId,
526
+ },
527
+ body: data,
528
+ })),
529
+ deleteOrganizationVpcEndpoint: (orgId, regionId, vpcEndpointId) => call(() => raw.deleteOrganizationVpcEndpoint({
530
+ client,
531
+ path: {
532
+ org_id: orgId,
533
+ region_id: regionId,
534
+ vpc_endpoint_id: vpcEndpointId,
535
+ },
536
+ })),
537
+ // ─── Neon Auth ───────────────────────────────────────────────────────
538
+ getNeonAuth: (projectId, branchId) => call(() => raw.getNeonAuth({
539
+ client,
540
+ path: { project_id: projectId, branch_id: branchId },
541
+ })),
542
+ createNeonAuth: (projectId, branchId, data) => call(() => raw.createNeonAuth({
543
+ client,
544
+ path: { project_id: projectId, branch_id: branchId },
545
+ body: data,
546
+ })),
547
+ disableNeonAuth: (projectId, branchId, data) => call(() => raw.disableNeonAuth({
548
+ client,
549
+ path: { project_id: projectId, branch_id: branchId },
550
+ body: data,
551
+ })),
552
+ listBranchNeonAuthOauthProviders: (projectId, branchId) => call(() => raw.listBranchNeonAuthOauthProviders({
553
+ client,
554
+ path: { project_id: projectId, branch_id: branchId },
555
+ })),
556
+ addBranchNeonAuthOauthProvider: (projectId, branchId, data) => call(() => raw.addBranchNeonAuthOauthProvider({
557
+ client,
558
+ path: { project_id: projectId, branch_id: branchId },
559
+ body: data,
560
+ })),
561
+ updateBranchNeonAuthOauthProvider: (projectId, branchId, oauthProviderId, data) => call(() => raw.updateBranchNeonAuthOauthProvider({
562
+ client,
563
+ path: {
564
+ project_id: projectId,
565
+ branch_id: branchId,
566
+ oauth_provider_id: oauthProviderId,
567
+ },
568
+ body: data,
569
+ })),
570
+ deleteBranchNeonAuthOauthProvider: (projectId, branchId, oauthProviderId) => call(() => raw.deleteBranchNeonAuthOauthProvider({
571
+ client,
572
+ path: {
573
+ project_id: projectId,
574
+ branch_id: branchId,
575
+ oauth_provider_id: oauthProviderId,
576
+ },
577
+ })),
578
+ listBranchNeonAuthTrustedDomains: (projectId, branchId) => call(() => raw.listBranchNeonAuthTrustedDomains({
579
+ client,
580
+ path: { project_id: projectId, branch_id: branchId },
581
+ })),
582
+ addBranchNeonAuthTrustedDomain: (projectId, branchId, data) => call(() => raw.addBranchNeonAuthTrustedDomain({
583
+ client,
584
+ path: { project_id: projectId, branch_id: branchId },
585
+ body: data,
586
+ })),
587
+ deleteBranchNeonAuthTrustedDomain: (projectId, branchId, data) => call(() => raw.deleteBranchNeonAuthTrustedDomain({
588
+ client,
589
+ path: { project_id: projectId, branch_id: branchId },
590
+ body: data,
591
+ })),
592
+ getNeonAuthAllowLocalhost: (projectId, branchId) => call(() => raw.getNeonAuthAllowLocalhost({
593
+ client,
594
+ path: { project_id: projectId, branch_id: branchId },
595
+ })),
596
+ updateNeonAuthAllowLocalhost: (projectId, branchId, data) => call(() => raw.updateNeonAuthAllowLocalhost({
597
+ client,
598
+ path: { project_id: projectId, branch_id: branchId },
599
+ body: data,
600
+ })),
601
+ getNeonAuthEmailAndPasswordConfig: (projectId, branchId) => call(() => raw.getNeonAuthEmailAndPasswordConfig({
602
+ client,
603
+ path: { project_id: projectId, branch_id: branchId },
604
+ })),
605
+ updateNeonAuthEmailAndPasswordConfig: (projectId, branchId, data) => call(() => raw.updateNeonAuthEmailAndPasswordConfig({
606
+ client,
607
+ path: { project_id: projectId, branch_id: branchId },
608
+ body: data,
609
+ })),
610
+ getNeonAuthEmailProvider: (projectId, branchId) => call(() => raw.getNeonAuthEmailProvider({
611
+ client,
612
+ path: { project_id: projectId, branch_id: branchId },
613
+ })),
614
+ updateNeonAuthEmailProvider: (projectId, branchId, data) => call(() => raw.updateNeonAuthEmailProvider({
615
+ client,
616
+ path: { project_id: projectId, branch_id: branchId },
617
+ body: data,
618
+ })),
619
+ sendNeonAuthTestEmail: (projectId, branchId, data) => call(() => raw.sendNeonAuthTestEmail({
620
+ client,
621
+ path: { project_id: projectId, branch_id: branchId },
622
+ body: data,
623
+ })),
624
+ getNeonAuthPluginConfigs: (projectId, branchId) => call(() => raw.getNeonAuthPluginConfigs({
625
+ client,
626
+ path: { project_id: projectId, branch_id: branchId },
627
+ })),
628
+ updateNeonAuthOrganizationPlugin: (projectId, branchId, data) => call(() => raw.updateNeonAuthOrganizationPlugin({
629
+ client,
630
+ path: { project_id: projectId, branch_id: branchId },
631
+ body: data,
632
+ })),
633
+ getNeonAuthWebhookConfig: (projectId, branchId) => call(() => raw.getNeonAuthWebhookConfig({
634
+ client,
635
+ path: { project_id: projectId, branch_id: branchId },
636
+ })),
637
+ updateNeonAuthWebhookConfig: (projectId, branchId, data) => call(() => raw.updateNeonAuthWebhookConfig({
638
+ client,
639
+ path: { project_id: projectId, branch_id: branchId },
640
+ body: data,
641
+ })),
642
+ createBranchNeonAuthNewUser: (projectId, branchId, data) => call(() => raw.createBranchNeonAuthNewUser({
643
+ client,
644
+ path: { project_id: projectId, branch_id: branchId },
645
+ body: data,
646
+ })),
647
+ deleteBranchNeonAuthUser: (projectId, branchId, authUserId) => call(() => raw.deleteBranchNeonAuthUser({
648
+ client,
649
+ path: {
650
+ project_id: projectId,
651
+ branch_id: branchId,
652
+ auth_user_id: authUserId,
653
+ },
654
+ })),
655
+ updateNeonAuthUserRole: (projectId, branchId, authUserId, data) => call(() => raw.updateNeonAuthUserRole({
656
+ client,
657
+ path: {
658
+ project_id: projectId,
659
+ branch_id: branchId,
660
+ auth_user_id: authUserId,
661
+ },
662
+ body: data,
663
+ })),
664
+ };
665
+ };