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
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import which from "which";
|
|
3
|
+
import { log } from "../log.js";
|
|
4
|
+
// npm first so it's the default/preselected choice; the rest follow in rough
|
|
5
|
+
// popularity order.
|
|
6
|
+
export const PACKAGE_MANAGERS = [
|
|
7
|
+
"npm",
|
|
8
|
+
"pnpm",
|
|
9
|
+
"yarn",
|
|
10
|
+
"bun",
|
|
11
|
+
];
|
|
12
|
+
/**
|
|
13
|
+
* The package manager the CLI was invoked through, read from the
|
|
14
|
+
* `npm_config_user_agent` npm sets for `npm exec`/`npx`, `pnpm dlx`, `yarn
|
|
15
|
+
* dlx`, and `bunx` (so `pnpm dlx neonctl …` installs with pnpm). Returns
|
|
16
|
+
* undefined when there's nothing to infer from — e.g. a globally-installed
|
|
17
|
+
* `neon`/`neonctl` — so the caller can ask (or fall back) instead of silently
|
|
18
|
+
* assuming npm.
|
|
19
|
+
*/
|
|
20
|
+
export const detectPackageManager = () => {
|
|
21
|
+
const ua = process.env.npm_config_user_agent ?? "";
|
|
22
|
+
if (ua.startsWith("pnpm"))
|
|
23
|
+
return "pnpm";
|
|
24
|
+
if (ua.startsWith("yarn"))
|
|
25
|
+
return "yarn";
|
|
26
|
+
if (ua.startsWith("bun"))
|
|
27
|
+
return "bun";
|
|
28
|
+
if (ua.startsWith("npm"))
|
|
29
|
+
return "npm";
|
|
30
|
+
return undefined;
|
|
31
|
+
};
|
|
32
|
+
/** The package managers actually on PATH, in {@link PACKAGE_MANAGERS} order. */
|
|
33
|
+
export const installedPackageManagers = () => PACKAGE_MANAGERS.filter((pm) => which.sync(pm, { nothrow: true }) !== null);
|
|
34
|
+
/**
|
|
35
|
+
* Pick a package manager without prompting: the one the CLI was invoked through,
|
|
36
|
+
* else the first one installed, else npm. Used by non-interactive flows (e.g.
|
|
37
|
+
* `config init`) where there's no scaffold prompt to hang a picker off.
|
|
38
|
+
*/
|
|
39
|
+
export const resolvePackageManager = () => detectPackageManager() ?? installedPackageManagers()[0] ?? "npm";
|
|
40
|
+
/**
|
|
41
|
+
* The argv that adds `packages` as runtime dependencies with `pm`. npm spells it
|
|
42
|
+
* `install`; pnpm/yarn/bun use `add`.
|
|
43
|
+
*/
|
|
44
|
+
export const addDependenciesArgs = (pm, packages) => (pm === "npm" ? ["install", ...packages] : ["add", ...packages]);
|
|
45
|
+
/**
|
|
46
|
+
* Run a command inheriting our stdio so the user sees install / link output
|
|
47
|
+
* live and can answer any prompts the child raises. Resolves to whether it
|
|
48
|
+
* exited cleanly; a non-zero exit is reported but never throws — the caller
|
|
49
|
+
* decides whether to treat it as fatal.
|
|
50
|
+
*/
|
|
51
|
+
export const runCommand = (cmd, args, cwd) => new Promise((resolvePromise) => {
|
|
52
|
+
// npm/pnpm/yarn ship as .cmd shims on Windows, which need a shell to run.
|
|
53
|
+
const child = spawn(cmd, args, {
|
|
54
|
+
cwd,
|
|
55
|
+
stdio: "inherit",
|
|
56
|
+
shell: process.platform === "win32",
|
|
57
|
+
});
|
|
58
|
+
child.on("error", (err) => {
|
|
59
|
+
log.warning("Could not run `%s %s`: %s", cmd, args.join(" "), err instanceof Error ? err.message : String(err));
|
|
60
|
+
resolvePromise(false);
|
|
61
|
+
});
|
|
62
|
+
child.on("close", (code) => {
|
|
63
|
+
if (code !== 0) {
|
|
64
|
+
log.warning("`%s %s` exited with code %d.", cmd, args.join(" "), code);
|
|
65
|
+
}
|
|
66
|
+
resolvePromise(code === 0);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { branchIdResolve } from "./enrichers.js";
|
|
2
|
+
import { looksLikeLSN, looksLikeTimestamp } from "./formats.js";
|
|
3
3
|
export class PointInTimeParseError extends Error {
|
|
4
4
|
constructor(message) {
|
|
5
5
|
super(message);
|
|
6
|
-
this.name =
|
|
6
|
+
this.name = "PointInTimeParseError";
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
export const parsePITBranch = (input) => {
|
|
10
|
-
const splitIndex = input.lastIndexOf(
|
|
10
|
+
const splitIndex = input.lastIndexOf("@");
|
|
11
11
|
const sourceBranch = splitIndex === -1 ? input : input.slice(0, splitIndex);
|
|
12
12
|
const exactPIT = splitIndex === -1 ? null : input.slice(splitIndex + 1);
|
|
13
13
|
const result = {
|
|
14
14
|
branch: sourceBranch,
|
|
15
15
|
...(exactPIT === null
|
|
16
|
-
? { tag:
|
|
16
|
+
? { tag: "head" }
|
|
17
17
|
: looksLikeLSN(exactPIT)
|
|
18
|
-
? { tag:
|
|
19
|
-
: { tag:
|
|
18
|
+
? { tag: "lsn", lsn: exactPIT }
|
|
19
|
+
: { tag: "timestamp", timestamp: exactPIT }),
|
|
20
20
|
};
|
|
21
|
-
if (result.tag ===
|
|
21
|
+
if (result.tag === "timestamp") {
|
|
22
22
|
const timestamp = result.timestamp;
|
|
23
23
|
if (!looksLikeTimestamp(timestamp)) {
|
|
24
24
|
throw new PointInTimeParseError(`Invalid source branch format - ${input}`);
|
|
@@ -31,15 +31,15 @@ export const parsePITBranch = (input) => {
|
|
|
31
31
|
};
|
|
32
32
|
export const parsePointInTime = async ({ pointInTime, targetBranchId, projectId, api, }) => {
|
|
33
33
|
const parsedPIT = parsePITBranch(pointInTime);
|
|
34
|
-
let branchId =
|
|
35
|
-
if (parsedPIT.branch ===
|
|
34
|
+
let branchId = "";
|
|
35
|
+
if (parsedPIT.branch === "^self") {
|
|
36
36
|
branchId = targetBranchId;
|
|
37
37
|
}
|
|
38
|
-
else if (parsedPIT.branch ===
|
|
38
|
+
else if (parsedPIT.branch === "^parent") {
|
|
39
39
|
const { data } = await api.getProjectBranch(projectId, targetBranchId);
|
|
40
40
|
const { parent_id: parentId } = data.branch;
|
|
41
41
|
if (parentId == null) {
|
|
42
|
-
throw new PointInTimeParseError(
|
|
42
|
+
throw new PointInTimeParseError("Branch has no parent");
|
|
43
43
|
}
|
|
44
44
|
branchId = parentId;
|
|
45
45
|
}
|
package/dist/utils/psql.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { spawn } from
|
|
2
|
-
import which from
|
|
3
|
-
import { closeAnalytics, trackEvent } from
|
|
4
|
-
import { log } from
|
|
5
|
-
const FALLBACK_ENV =
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import which from "which";
|
|
3
|
+
import { closeAnalytics, trackEvent } from "../analytics.js";
|
|
4
|
+
import { log } from "../log.js";
|
|
5
|
+
const FALLBACK_ENV = "NEONCTL_PSQL_FALLBACK";
|
|
6
6
|
/** Max time we wait for the analytics flush before handing off to psql. */
|
|
7
7
|
const ANALYTICS_FLUSH_TIMEOUT_MS = 3000;
|
|
8
8
|
/**
|
|
@@ -12,28 +12,28 @@ const ANALYTICS_FLUSH_TIMEOUT_MS = 3000;
|
|
|
12
12
|
* cases rather than a misleading `false`.
|
|
13
13
|
*/
|
|
14
14
|
const planPsql = async (opts) => {
|
|
15
|
-
if (opts.mode ===
|
|
15
|
+
if (opts.mode === "ts") {
|
|
16
16
|
return {
|
|
17
|
-
implementation:
|
|
18
|
-
reason:
|
|
17
|
+
implementation: "ts",
|
|
18
|
+
reason: "forced_flag",
|
|
19
19
|
nativeAvailable: null,
|
|
20
20
|
nativePath: null,
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
-
if (process.env[FALLBACK_ENV] ===
|
|
23
|
+
if (process.env[FALLBACK_ENV] === "1") {
|
|
24
24
|
return {
|
|
25
|
-
implementation:
|
|
26
|
-
reason:
|
|
25
|
+
implementation: "ts",
|
|
26
|
+
reason: "forced_env",
|
|
27
27
|
nativeAvailable: null,
|
|
28
28
|
nativePath: null,
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
-
const nativePath = await which(
|
|
31
|
+
const nativePath = await which("psql", { nothrow: true });
|
|
32
32
|
const nativeAvailable = nativePath !== null;
|
|
33
|
-
if (opts.mode ===
|
|
33
|
+
if (opts.mode === "native") {
|
|
34
34
|
return {
|
|
35
|
-
implementation:
|
|
36
|
-
reason:
|
|
35
|
+
implementation: "native",
|
|
36
|
+
reason: "forced_native",
|
|
37
37
|
nativeAvailable,
|
|
38
38
|
nativePath,
|
|
39
39
|
};
|
|
@@ -41,14 +41,14 @@ const planPsql = async (opts) => {
|
|
|
41
41
|
// 'auto' (or unset): strict fallback — prefer native, TS only if missing.
|
|
42
42
|
return nativeAvailable
|
|
43
43
|
? {
|
|
44
|
-
implementation:
|
|
45
|
-
reason:
|
|
44
|
+
implementation: "native",
|
|
45
|
+
reason: "native_available",
|
|
46
46
|
nativeAvailable,
|
|
47
47
|
nativePath,
|
|
48
48
|
}
|
|
49
49
|
: {
|
|
50
|
-
implementation:
|
|
51
|
-
reason:
|
|
50
|
+
implementation: "ts",
|
|
51
|
+
reason: "fallback_no_native",
|
|
52
52
|
nativeAvailable,
|
|
53
53
|
nativePath,
|
|
54
54
|
};
|
|
@@ -64,7 +64,7 @@ const planPsql = async (opts) => {
|
|
|
64
64
|
* analytics is disabled (`--analytics false`), since the client is absent.
|
|
65
65
|
*/
|
|
66
66
|
const reportPsqlInvocation = async (plan) => {
|
|
67
|
-
trackEvent(
|
|
67
|
+
trackEvent("psql_invoked", {
|
|
68
68
|
implementation: plan.implementation,
|
|
69
69
|
reason: plan.reason,
|
|
70
70
|
nativeAvailable: plan.nativeAvailable,
|
|
@@ -72,11 +72,11 @@ const reportPsqlInvocation = async (plan) => {
|
|
|
72
72
|
await closeAnalytics({ timeout: ANALYTICS_FLUSH_TIMEOUT_MS });
|
|
73
73
|
};
|
|
74
74
|
const execNative = async (binary, connection_uri, args) => {
|
|
75
|
-
log.info(
|
|
75
|
+
log.info("Connecting to the database using psql...");
|
|
76
76
|
const child = spawn(binary, [connection_uri, ...args], {
|
|
77
|
-
stdio:
|
|
77
|
+
stdio: "inherit",
|
|
78
78
|
});
|
|
79
|
-
for (const signame of [
|
|
79
|
+
for (const signame of ["SIGINT", "SIGTERM"]) {
|
|
80
80
|
process.on(signame, (code) => {
|
|
81
81
|
if (!child.killed && code !== null) {
|
|
82
82
|
child.kill(code);
|
|
@@ -84,15 +84,15 @@ const execNative = async (binary, connection_uri, args) => {
|
|
|
84
84
|
});
|
|
85
85
|
}
|
|
86
86
|
return new Promise((_, reject) => {
|
|
87
|
-
child.on(
|
|
87
|
+
child.on("exit", (code) => {
|
|
88
88
|
process.exit(code === null ? 1 : code);
|
|
89
89
|
});
|
|
90
|
-
child.on(
|
|
90
|
+
child.on("error", reject);
|
|
91
91
|
});
|
|
92
92
|
};
|
|
93
93
|
const execTs = async (connection_uri, args) => {
|
|
94
|
-
log.info(
|
|
95
|
-
const { runPsql } = await import(
|
|
94
|
+
log.info("Connecting to the database using embedded psql (TypeScript)...");
|
|
95
|
+
const { runPsql } = await import("../psql/index.js");
|
|
96
96
|
const code = await runPsql([connection_uri, ...args], {
|
|
97
97
|
stdin: process.stdin,
|
|
98
98
|
stdout: process.stdout,
|
|
@@ -103,9 +103,9 @@ const execTs = async (connection_uri, args) => {
|
|
|
103
103
|
export const psql = async (connection_uri, args = [], opts = {}) => {
|
|
104
104
|
const plan = await planPsql(opts);
|
|
105
105
|
await reportPsqlInvocation(plan);
|
|
106
|
-
if (plan.implementation ===
|
|
107
|
-
if (plan.reason ===
|
|
108
|
-
log.info(
|
|
106
|
+
if (plan.implementation === "ts") {
|
|
107
|
+
if (plan.reason === "fallback_no_native") {
|
|
108
|
+
log.info("psql binary not found on PATH; falling back to embedded TypeScript psql");
|
|
109
109
|
}
|
|
110
110
|
return execTs(connection_uri, args);
|
|
111
111
|
}
|
package/dist/utils/string.js
CHANGED
package/dist/utils/ui.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
export const consumeNextMatching = (lines, matcher) => {
|
|
5
5
|
while (lines.length > 0) {
|
|
6
6
|
const line = lines.shift().trim();
|
|
7
|
-
if (line ===
|
|
7
|
+
if (line === "") {
|
|
8
8
|
continue;
|
|
9
9
|
}
|
|
10
10
|
if (matcher.test(line)) {
|
|
@@ -23,7 +23,7 @@ export const consumeBlockIfMatches = (lines, matcher) => {
|
|
|
23
23
|
return result;
|
|
24
24
|
}
|
|
25
25
|
let line = lines.shift();
|
|
26
|
-
while (line.trim() ===
|
|
26
|
+
while (line.trim() === "") {
|
|
27
27
|
line = lines.shift();
|
|
28
28
|
}
|
|
29
29
|
if (!matcher.test(line)) {
|
|
@@ -33,7 +33,7 @@ export const consumeBlockIfMatches = (lines, matcher) => {
|
|
|
33
33
|
result.push(line);
|
|
34
34
|
while (lines.length > 0) {
|
|
35
35
|
line = lines.shift();
|
|
36
|
-
if (line.trim() ===
|
|
36
|
+
if (line.trim() === "") {
|
|
37
37
|
break;
|
|
38
38
|
}
|
|
39
39
|
result.push(line);
|
|
@@ -42,18 +42,18 @@ export const consumeBlockIfMatches = (lines, matcher) => {
|
|
|
42
42
|
};
|
|
43
43
|
export const splitColumns = (line) => {
|
|
44
44
|
const result = line.trim().split(/\s{2,}/);
|
|
45
|
-
result[1] = result[1] ??
|
|
45
|
+
result[1] = result[1] ?? "";
|
|
46
46
|
if (result.length > 2) {
|
|
47
|
-
result[1] = result.slice(1).join(
|
|
47
|
+
result[1] = result.slice(1).join(" ");
|
|
48
48
|
}
|
|
49
49
|
return result;
|
|
50
50
|
};
|
|
51
51
|
export const drawPointer = (width) => {
|
|
52
52
|
const result = [];
|
|
53
|
-
result.push(
|
|
53
|
+
result.push("└");
|
|
54
54
|
for (let i = 0; i < width - 4; i++) {
|
|
55
|
-
result.push(
|
|
55
|
+
result.push("─");
|
|
56
56
|
}
|
|
57
|
-
result.push(
|
|
58
|
-
return result.join(
|
|
57
|
+
result.push(">");
|
|
58
|
+
return result.join("");
|
|
59
59
|
};
|
package/dist/utils/zip.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { zipSync } from
|
|
1
|
+
import { zipSync } from "fflate";
|
|
2
2
|
// Zip the esbuild output (index.mjs) into the archive the Functions deploy endpoint
|
|
3
3
|
// expects. Compression level 6 matches the previous bundler.
|
|
4
4
|
export const zipBundle = (entries) => zipSync(entries, { level: 6 });
|
package/dist/writer.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import Table from
|
|
3
|
-
import
|
|
4
|
-
import { isCi } from
|
|
5
|
-
import { isObject, toSnakeCase } from
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import Table from "cli-table";
|
|
3
|
+
import YAML from "yaml";
|
|
4
|
+
import { isCi } from "./env.js";
|
|
5
|
+
import { isObject, toSnakeCase } from "./utils/string.js";
|
|
6
6
|
const writeYaml = (chunks) => {
|
|
7
7
|
return YAML.stringify(chunks.length === 1
|
|
8
8
|
? chunks[0].data
|
|
@@ -20,21 +20,21 @@ const writeJson = (chunks) => {
|
|
|
20
20
|
])), null, 2);
|
|
21
21
|
};
|
|
22
22
|
const writeTable = (chunks, out) => {
|
|
23
|
-
chunks.forEach(({ data, config: { emptyMessage, fields, title, renderColumns = {} } }) => {
|
|
23
|
+
chunks.forEach(({ data, config: { emptyMessage, fields, title, renderColumns = {} }, }) => {
|
|
24
24
|
const arrayData = Array.isArray(data) ? data : [data];
|
|
25
25
|
if (!arrayData.length && emptyMessage) {
|
|
26
|
-
out.write(
|
|
26
|
+
out.write("\n" + emptyMessage + "\n");
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
|
-
const fieldsFiltered = fields.filter((field) => arrayData.some((item) => item[field] !== undefined && item[field] !==
|
|
29
|
+
const fieldsFiltered = fields.filter((field) => arrayData.some((item) => item[field] !== undefined && item[field] !== ""));
|
|
30
30
|
const table = new Table({
|
|
31
31
|
style: {
|
|
32
|
-
head: [
|
|
32
|
+
head: ["green"],
|
|
33
33
|
},
|
|
34
34
|
head: fieldsFiltered.map((field) => field
|
|
35
|
-
.split(
|
|
35
|
+
.split("_")
|
|
36
36
|
.map((word) => word[0].toUpperCase() + word.slice(1))
|
|
37
|
-
.join(
|
|
37
|
+
.join(" ")),
|
|
38
38
|
});
|
|
39
39
|
arrayData.forEach((item) => {
|
|
40
40
|
table.push(fieldsFiltered.map((field) => {
|
|
@@ -43,17 +43,17 @@ const writeTable = (chunks, out) => {
|
|
|
43
43
|
return renderColumns[field]?.(item);
|
|
44
44
|
}
|
|
45
45
|
return Array.isArray(value)
|
|
46
|
-
? value.join(
|
|
46
|
+
? value.join("\n")
|
|
47
47
|
: isObject(value)
|
|
48
48
|
? JSON.stringify(value, null, 2)
|
|
49
|
-
: (value ??
|
|
49
|
+
: (value ?? "");
|
|
50
50
|
}));
|
|
51
51
|
});
|
|
52
52
|
if (title) {
|
|
53
|
-
out.write((isCi() ? title : chalk.bold(title)) +
|
|
53
|
+
out.write((isCi() ? title : chalk.bold(title)) + "\n");
|
|
54
54
|
}
|
|
55
55
|
out.write(table.toString());
|
|
56
|
-
out.write(
|
|
56
|
+
out.write("\n");
|
|
57
57
|
});
|
|
58
58
|
};
|
|
59
59
|
/**
|
|
@@ -85,10 +85,10 @@ export const writer = (props) => {
|
|
|
85
85
|
if (args.length === 2) {
|
|
86
86
|
chunks.push({ data: args[0], config: args[1] });
|
|
87
87
|
}
|
|
88
|
-
if (props.output ==
|
|
88
|
+
if (props.output == "yaml") {
|
|
89
89
|
return out.write(writeYaml(chunks));
|
|
90
90
|
}
|
|
91
|
-
if (props.output ==
|
|
91
|
+
if (props.output == "json") {
|
|
92
92
|
return out.write(writeJson(chunks));
|
|
93
93
|
}
|
|
94
94
|
writeTable(chunks, out);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neonctl",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.29.0",
|
|
4
4
|
"description": "CLI tool for Neon Serverless Postgres",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"neon",
|
|
@@ -31,17 +31,11 @@
|
|
|
31
31
|
"package.json"
|
|
32
32
|
],
|
|
33
33
|
"engines": {
|
|
34
|
-
"node": ">=
|
|
34
|
+
"node": ">=22"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@hono/node-server": "2.0.4",
|
|
38
|
-
"@neondatabase/api-client": "2.7.1",
|
|
39
|
-
"@neondatabase/config": "0.8.0",
|
|
40
|
-
"@neondatabase/config-runtime": "0.8.0",
|
|
41
|
-
"@neondatabase/env": "0.7.0",
|
|
42
38
|
"@segment/analytics-node": "1.3.0",
|
|
43
|
-
"axios": "1.7.2",
|
|
44
|
-
"axios-debug-log": "1.0.0",
|
|
45
39
|
"chalk": "5.3.0",
|
|
46
40
|
"chokidar": "5.0.0",
|
|
47
41
|
"cli-table": "0.3.11",
|
|
@@ -53,9 +47,14 @@
|
|
|
53
47
|
"openid-client": "6.8.1",
|
|
54
48
|
"pg-protocol": "^1.14.0",
|
|
55
49
|
"prompts": "2.4.2",
|
|
50
|
+
"undici": "^8.5.0",
|
|
56
51
|
"which": "3.0.1",
|
|
57
52
|
"yaml": "2.4.5",
|
|
58
|
-
"yargs": "17.7.2"
|
|
53
|
+
"yargs": "17.7.2",
|
|
54
|
+
"@neon/sdk": "0.1.0",
|
|
55
|
+
"@neon/config": "0.8.1",
|
|
56
|
+
"@neon/config-runtime": "0.8.1",
|
|
57
|
+
"@neon/env": "0.8.1"
|
|
59
58
|
},
|
|
60
59
|
"optionalDependencies": {
|
|
61
60
|
"esbuild": "0.28.0"
|
|
@@ -83,7 +82,6 @@
|
|
|
83
82
|
"node-pty": "1.1.0",
|
|
84
83
|
"oauth2-mock-server": "8.1.0",
|
|
85
84
|
"openapi-types": "12.1.3",
|
|
86
|
-
"prettier": "3.3.3",
|
|
87
85
|
"rollup": "3.29.4",
|
|
88
86
|
"strip-ansi": "7.1.0",
|
|
89
87
|
"tsx": "4.22.3",
|
|
@@ -115,8 +113,8 @@
|
|
|
115
113
|
"build": "pnpm generateParams && pnpm clean && tsc -p tsconfig.build.json && cp src/*.html ./dist",
|
|
116
114
|
"bundle": "node pkg.js",
|
|
117
115
|
"typecheck": "tsc --noEmit",
|
|
118
|
-
"lint": "pnpm typecheck && eslint src
|
|
119
|
-
"lint:fix": "pnpm typecheck && eslint src --fix
|
|
116
|
+
"lint": "pnpm typecheck && eslint src",
|
|
117
|
+
"lint:fix": "pnpm typecheck && eslint src --fix",
|
|
120
118
|
"test": "pnpm build && vitest run",
|
|
121
119
|
"test:ci": "pnpm build && vitest run",
|
|
122
120
|
"test:conformance": "vitest run --config tests/psql-conformance/vitest.config.ts"
|