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.
- package/README.md +35 -3
- package/dist/analytics.js +52 -34
- package/dist/api.js +643 -13
- package/dist/auth.js +50 -44
- package/dist/cli.js +8 -1
- package/dist/commands/auth.js +64 -51
- package/dist/commands/bootstrap.js +115 -157
- package/dist/commands/branches.js +160 -150
- package/dist/commands/bucket.js +183 -146
- package/dist/commands/checkout.js +51 -51
- package/dist/commands/config.js +228 -82
- package/dist/commands/connection_string.js +62 -62
- package/dist/commands/data_api.js +100 -101
- package/dist/commands/databases.js +29 -26
- package/dist/commands/deploy.js +12 -12
- package/dist/commands/dev.js +114 -114
- package/dist/commands/env.js +43 -43
- package/dist/commands/functions.js +101 -104
- package/dist/commands/index.js +27 -25
- package/dist/commands/init.js +23 -22
- package/dist/commands/ip_allow.js +29 -29
- package/dist/commands/link.js +232 -182
- package/dist/commands/neon_auth.js +385 -370
- package/dist/commands/operations.js +11 -11
- package/dist/commands/orgs.js +8 -8
- package/dist/commands/projects.js +103 -101
- package/dist/commands/psql.js +31 -31
- package/dist/commands/roles.js +27 -24
- package/dist/commands/schema_diff.js +25 -26
- package/dist/commands/set_context.js +17 -17
- package/dist/commands/status.js +40 -0
- package/dist/commands/user.js +5 -5
- package/dist/commands/vpc_endpoints.js +50 -50
- package/dist/config.js +7 -7
- package/dist/config_format.js +5 -5
- package/dist/context.js +37 -14
- package/dist/current_branch_fast_path.js +55 -0
- package/dist/dev/env.js +33 -33
- package/dist/dev/functions.js +4 -4
- package/dist/dev/inputs.js +6 -6
- package/dist/dev/runtime.js +25 -25
- package/dist/env.js +14 -14
- package/dist/env_file.js +13 -13
- package/dist/errors.js +68 -5
- package/dist/functions_api.js +10 -10
- package/dist/help.js +15 -15
- package/dist/index.js +110 -107
- package/dist/log.js +2 -2
- package/dist/parameters.gen.js +14 -14
- package/dist/pkg.js +5 -5
- package/dist/psql/cli.js +4 -2
- package/dist/psql/command/cmd_cond.js +61 -61
- package/dist/psql/command/cmd_connect.js +159 -154
- package/dist/psql/command/cmd_copy.js +107 -97
- package/dist/psql/command/cmd_describe.js +368 -363
- package/dist/psql/command/cmd_format.js +276 -263
- package/dist/psql/command/cmd_io.js +269 -263
- package/dist/psql/command/cmd_lo.js +74 -66
- package/dist/psql/command/cmd_meta.js +148 -148
- package/dist/psql/command/cmd_misc.js +17 -17
- package/dist/psql/command/cmd_pipeline.js +142 -135
- package/dist/psql/command/cmd_restrict.js +25 -25
- package/dist/psql/command/cmd_show.js +183 -168
- package/dist/psql/command/dispatch.js +26 -26
- package/dist/psql/command/shared.js +14 -14
- package/dist/psql/complete/filenames.js +16 -16
- package/dist/psql/complete/index.js +4 -4
- package/dist/psql/complete/matcher.js +33 -32
- package/dist/psql/complete/psqlVars.js +173 -173
- package/dist/psql/complete/queries.js +5 -3
- package/dist/psql/complete/rules.js +900 -863
- package/dist/psql/core/common.js +136 -133
- package/dist/psql/core/help.js +343 -343
- package/dist/psql/core/mainloop.js +160 -153
- package/dist/psql/core/prompt.js +126 -123
- package/dist/psql/core/settings.js +111 -111
- package/dist/psql/core/sqlHelp.js +150 -150
- package/dist/psql/core/startup.js +211 -205
- package/dist/psql/core/syncVars.js +14 -14
- package/dist/psql/core/variables.js +24 -24
- package/dist/psql/describe/formatters.js +302 -289
- package/dist/psql/describe/processNamePattern.js +28 -28
- package/dist/psql/describe/queries.js +656 -651
- package/dist/psql/index.js +436 -411
- package/dist/psql/io/history.js +36 -36
- package/dist/psql/io/input.js +15 -15
- package/dist/psql/io/lineEditor/buffer.js +27 -25
- package/dist/psql/io/lineEditor/complete.js +15 -15
- package/dist/psql/io/lineEditor/filename.js +22 -22
- package/dist/psql/io/lineEditor/index.js +65 -62
- package/dist/psql/io/lineEditor/keymap.js +325 -318
- package/dist/psql/io/lineEditor/vt100.js +60 -60
- package/dist/psql/io/pgpass.js +18 -18
- package/dist/psql/io/pgservice.js +14 -14
- package/dist/psql/io/psqlrc.js +46 -46
- package/dist/psql/print/aligned.js +175 -166
- package/dist/psql/print/asciidoc.js +51 -51
- package/dist/psql/print/crosstab.js +34 -31
- package/dist/psql/print/csv.js +25 -22
- package/dist/psql/print/html.js +54 -54
- package/dist/psql/print/json.js +12 -12
- package/dist/psql/print/latex.js +118 -118
- package/dist/psql/print/pager.js +28 -26
- package/dist/psql/print/troff.js +48 -48
- package/dist/psql/print/unaligned.js +15 -14
- package/dist/psql/print/units.js +17 -17
- package/dist/psql/scanner/slash.js +48 -46
- package/dist/psql/scanner/sql.js +88 -84
- package/dist/psql/scanner/stringutils.js +21 -17
- package/dist/psql/types/index.js +7 -7
- package/dist/psql/types/scanner.js +8 -8
- package/dist/psql/wire/connection.js +341 -327
- package/dist/psql/wire/copy.js +7 -7
- package/dist/psql/wire/pipeline.js +26 -24
- package/dist/psql/wire/protocol.js +102 -102
- package/dist/psql/wire/sasl.js +62 -62
- package/dist/psql/wire/tls.js +79 -73
- package/dist/storage_api.js +22 -23
- package/dist/test_utils/fixtures.js +74 -41
- package/dist/test_utils/oauth_server.js +5 -5
- package/dist/utils/api_enums.js +33 -0
- package/dist/utils/branch_notice.js +5 -5
- package/dist/utils/branch_picker.js +26 -26
- package/dist/utils/compute_units.js +4 -4
- package/dist/utils/enrichers.js +28 -16
- package/dist/utils/esbuild.js +28 -28
- package/dist/utils/formats.js +1 -1
- package/dist/utils/middlewares.js +3 -3
- package/dist/utils/package_manager.js +68 -0
- package/dist/utils/point_in_time.js +12 -12
- package/dist/utils/psql.js +30 -30
- package/dist/utils/string.js +2 -2
- package/dist/utils/ui.js +9 -9
- package/dist/utils/zip.js +1 -1
- package/dist/writer.js +17 -17
- package/package.json +10 -12
package/dist/api.js
CHANGED
|
@@ -1,17 +1,194 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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 (
|
|
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
|
+
};
|