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/README.md
CHANGED
|
@@ -361,7 +361,7 @@ neonctl env pull
|
|
|
361
361
|
neonctl env pull --branch preview --file .env.preview
|
|
362
362
|
```
|
|
363
363
|
|
|
364
|
-
If you'd rather not keep env vars on disk, inject them at runtime instead with `neon-env run -- <your dev command>` (from `@
|
|
364
|
+
If you'd rather not keep env vars on disk, inject them at runtime instead with `neon-env run -- <your dev command>` (from `@neon/env`) or `neonctl dev`, and pass `--no-env-pull` to `link` / `checkout`.
|
|
365
365
|
|
|
366
366
|
**Where `.neon` lives**: `link` writes `.neon` into the **current working directory** by default. If an existing `.neon` is found in any parent directory, that file is reused — so commands run from a sub-directory of a linked project still pick up the project's context. To pin the location explicitly, pass `--context-file <path>`.
|
|
367
367
|
|
|
@@ -373,7 +373,7 @@ Describe a branch's desired state in a `neon.ts` policy and reconcile it from th
|
|
|
373
373
|
|
|
374
374
|
```ts
|
|
375
375
|
// neon.ts
|
|
376
|
-
import { defineConfig } from '@
|
|
376
|
+
import { defineConfig } from '@neon/config/v1';
|
|
377
377
|
|
|
378
378
|
export default defineConfig({
|
|
379
379
|
// Static: what exists on every branch (drives the typed env).
|
|
@@ -388,12 +388,15 @@ export default defineConfig({
|
|
|
388
388
|
});
|
|
389
389
|
```
|
|
390
390
|
|
|
391
|
-
Three sub-commands plus
|
|
391
|
+
Three sub-commands plus two top-level aliases drive it:
|
|
392
392
|
|
|
393
393
|
```bash
|
|
394
394
|
# Inspect the branch's live Neon state (read-only — never mutates)
|
|
395
395
|
neon config status
|
|
396
396
|
|
|
397
|
+
# `neon status` is an alias for `neon config status`
|
|
398
|
+
neon status
|
|
399
|
+
|
|
397
400
|
# Dry-run diff: show exactly what `apply` would change
|
|
398
401
|
neon config plan
|
|
399
402
|
|
|
@@ -419,6 +422,35 @@ The branch is chosen with `--branch <id|name>`; without it the project's default
|
|
|
419
422
|
|
|
420
423
|
**Output**: `status` prints the project, branch, and reverse-engineered config; `plan` / `apply` print the planned/applied changes and any conflicts as tables. Pass `--output json` (or `--output yaml`) to emit the full machine-readable result (`PushResult`) for piping into other tools or CI.
|
|
421
424
|
|
|
425
|
+
**`config status --current-branch`** (alias `neon status --current-branch`) prints _only_ the branch pinned in the local `.neon` file — no network, no auth, no analytics — and exits non-zero when none is pinned. This behavior lets it safely drive a shell prompt. Example [starship](https://starship.rs) segment:
|
|
426
|
+
|
|
427
|
+
```toml
|
|
428
|
+
[custom.neon]
|
|
429
|
+
description = "Current Neon database branch"
|
|
430
|
+
format = "[$symbol$output]($style) "
|
|
431
|
+
style = "bold green"
|
|
432
|
+
# `symbol` below uses a Nerd Font glyph; swap it for a plain
|
|
433
|
+
# label/emoji if you don't have a Nerd Font installed.
|
|
434
|
+
symbol = " "
|
|
435
|
+
command = "neon status --current-branch"
|
|
436
|
+
# Starship evaluates this on EVERY prompt render. To keep prompts instant
|
|
437
|
+
# everywhere outside a Neon project, do a zero-subprocess walk-up for an
|
|
438
|
+
# ancestor `.neon` first (the same walk the CLI does, stopping at $HOME and /).
|
|
439
|
+
# Only when one is found do we invoke the CLI, whose exit code is the real
|
|
440
|
+
# gate: non-zero (no branch pinned) hides the segment cleanly.
|
|
441
|
+
when = '''
|
|
442
|
+
d="$PWD"
|
|
443
|
+
while [ "$d" != "$HOME" ] && [ "$d" != / ]; do
|
|
444
|
+
if [ -e "$d/.neon" ]; then
|
|
445
|
+
neon status --current-branch >/dev/null 2>&1
|
|
446
|
+
exit $?
|
|
447
|
+
fi
|
|
448
|
+
d=$(dirname "$d")
|
|
449
|
+
done
|
|
450
|
+
exit 1
|
|
451
|
+
'''
|
|
452
|
+
```
|
|
453
|
+
|
|
422
454
|
```bash
|
|
423
455
|
# CI gate: fail the build if the branch has drifted from the policy
|
|
424
456
|
neon config plan --project-id polished-snowflake-12345678 --output json
|
package/dist/analytics.js
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
import { readFileSync } from
|
|
2
|
-
import { join } from
|
|
3
|
-
import { Analytics } from
|
|
4
|
-
import {
|
|
5
|
-
import { CREDENTIALS_FILE } from
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
const WRITE_KEY =
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { Analytics } from "@segment/analytics-node";
|
|
4
|
+
import { getApiClient, isNeonApiError } from "./api.js";
|
|
5
|
+
import { CREDENTIALS_FILE } from "./config.js";
|
|
6
|
+
import { isCurrentBranchProbe } from "./context.js";
|
|
7
|
+
import { getGithubEnvVars, isCi } from "./env.js";
|
|
8
|
+
import { log } from "./log.js";
|
|
9
|
+
import pkg from "./pkg.js";
|
|
10
|
+
const WRITE_KEY = "3SQXn5ejjXWLEJ8xU2PRYhAotLtTaeeV";
|
|
11
|
+
/**
|
|
12
|
+
* Raw-argv fallback for the offline `--current-branch` probe. The init
|
|
13
|
+
* middleware runs before validation, where the parsed `currentBranch` flag may
|
|
14
|
+
* not be populated yet, so we also scan `process.argv` directly to be safe.
|
|
15
|
+
*/
|
|
16
|
+
const hasCurrentBranchArgv = () => process.argv.includes("--current-branch");
|
|
11
17
|
let client;
|
|
12
18
|
let clientInitialized = false;
|
|
13
|
-
let userId =
|
|
19
|
+
let userId = "";
|
|
14
20
|
/**
|
|
15
21
|
* Phase 1: Run before validation so the Segment client exists if any
|
|
16
22
|
* middleware (e.g. auth) fails. Enables sendError() in the fail handler.
|
|
@@ -20,14 +26,21 @@ export const initAnalyticsClientMiddleware = (args) => {
|
|
|
20
26
|
if (!args.analytics || clientInitialized) {
|
|
21
27
|
return;
|
|
22
28
|
}
|
|
29
|
+
// The offline `--current-branch` probe must make zero network calls. This
|
|
30
|
+
// middleware runs before validation, so guard on the raw argv too (in case
|
|
31
|
+
// the parsed `currentBranch` flag isn't populated this early): never create
|
|
32
|
+
// the Segment client, which keeps trackEvent/closeAnalytics no-ops downstream.
|
|
33
|
+
if (isCurrentBranchProbe(args) || hasCurrentBranchArgv()) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
23
36
|
clientInitialized = true;
|
|
24
37
|
client = new Analytics({
|
|
25
38
|
writeKey: WRITE_KEY,
|
|
26
|
-
host:
|
|
39
|
+
host: "https://track.neon.tech",
|
|
27
40
|
});
|
|
28
|
-
log.debug(
|
|
41
|
+
log.debug("Initialized CLI analytics client");
|
|
29
42
|
client.identify({
|
|
30
|
-
userId:
|
|
43
|
+
userId: "anonymous",
|
|
31
44
|
});
|
|
32
45
|
};
|
|
33
46
|
/**
|
|
@@ -38,13 +51,18 @@ export const analyticsMiddleware = async (args) => {
|
|
|
38
51
|
if (!client || !args.analytics) {
|
|
39
52
|
return;
|
|
40
53
|
}
|
|
54
|
+
if (isCurrentBranchProbe(args)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
41
57
|
try {
|
|
42
58
|
const credentialsPath = join(args.configDir, CREDENTIALS_FILE);
|
|
43
|
-
const credentials = readFileSync(credentialsPath, {
|
|
59
|
+
const credentials = readFileSync(credentialsPath, {
|
|
60
|
+
encoding: "utf-8",
|
|
61
|
+
});
|
|
44
62
|
userId = JSON.parse(credentials).user_id;
|
|
45
63
|
}
|
|
46
64
|
catch (err) {
|
|
47
|
-
log.debug(
|
|
65
|
+
log.debug("Failed to read credentials file", err);
|
|
48
66
|
}
|
|
49
67
|
try {
|
|
50
68
|
if (args.apiKey) {
|
|
@@ -59,25 +77,25 @@ export const analyticsMiddleware = async (args) => {
|
|
|
59
77
|
args.authMethod = authDetails.auth_method;
|
|
60
78
|
args.authData = authDetails.auth_data;
|
|
61
79
|
// Get user id if not org api key
|
|
62
|
-
if (!userId && authDetails.auth_method !==
|
|
80
|
+
if (!userId && authDetails.auth_method !== "api_key_org") {
|
|
63
81
|
const resp = await apiClient?.getCurrentUserInfo?.();
|
|
64
82
|
userId = resp?.data?.id;
|
|
65
83
|
}
|
|
66
84
|
}
|
|
67
85
|
else {
|
|
68
86
|
args.accountId = userId;
|
|
69
|
-
args.authMethod =
|
|
87
|
+
args.authMethod = "oauth";
|
|
70
88
|
}
|
|
71
89
|
}
|
|
72
90
|
catch (err) {
|
|
73
|
-
log.debug(
|
|
91
|
+
log.debug("Failed to get user id from api", err);
|
|
74
92
|
}
|
|
75
93
|
client.identify({
|
|
76
|
-
userId: userId?.toString() ??
|
|
94
|
+
userId: userId?.toString() ?? "anonymous",
|
|
77
95
|
});
|
|
78
96
|
client.track({
|
|
79
|
-
userId: userId ||
|
|
80
|
-
event:
|
|
97
|
+
userId: userId || "anonymous",
|
|
98
|
+
event: "CLI Started",
|
|
81
99
|
properties: getAnalyticsEventProperties(args),
|
|
82
100
|
context: {
|
|
83
101
|
direct: true,
|
|
@@ -86,35 +104,35 @@ export const analyticsMiddleware = async (args) => {
|
|
|
86
104
|
};
|
|
87
105
|
export const closeAnalytics = async (opts) => {
|
|
88
106
|
if (client) {
|
|
89
|
-
log.debug(
|
|
107
|
+
log.debug("Flushing CLI analytics");
|
|
90
108
|
// `timeout` bounds how long we wait for in-flight events to flush so a
|
|
91
109
|
// slow / unreachable track.neon.tech can't hang a short-lived command
|
|
92
110
|
// (e.g. the psql launch path, which flushes here before process.exit).
|
|
93
111
|
await client.closeAndFlush(opts);
|
|
94
|
-
log.debug(
|
|
112
|
+
log.debug("Flushed CLI analytics");
|
|
95
113
|
}
|
|
96
114
|
};
|
|
97
115
|
export const sendError = (err, errCode) => {
|
|
98
116
|
if (!client) {
|
|
99
117
|
return;
|
|
100
118
|
}
|
|
101
|
-
const
|
|
102
|
-
const requestId =
|
|
119
|
+
const apiError = isNeonApiError(err) ? err : undefined;
|
|
120
|
+
const requestId = apiError?.headers?.["x-neon-ret-request-id"];
|
|
103
121
|
if (requestId) {
|
|
104
|
-
log.debug(
|
|
122
|
+
log.debug("Failed request ID: %s", requestId);
|
|
105
123
|
}
|
|
106
124
|
client.track({
|
|
107
|
-
event:
|
|
108
|
-
userId: userId ||
|
|
125
|
+
event: "CLI Error",
|
|
126
|
+
userId: userId || "anonymous",
|
|
109
127
|
properties: {
|
|
110
128
|
message: err.message,
|
|
111
129
|
stack: err.stack,
|
|
112
130
|
errCode,
|
|
113
|
-
statusCode:
|
|
131
|
+
statusCode: apiError?.status,
|
|
114
132
|
requestId: requestId,
|
|
115
133
|
},
|
|
116
134
|
});
|
|
117
|
-
log.debug(
|
|
135
|
+
log.debug("Sent CLI error event: %s", errCode);
|
|
118
136
|
};
|
|
119
137
|
export const trackEvent = (event, properties) => {
|
|
120
138
|
if (!client) {
|
|
@@ -122,14 +140,14 @@ export const trackEvent = (event, properties) => {
|
|
|
122
140
|
}
|
|
123
141
|
client.track({
|
|
124
142
|
event,
|
|
125
|
-
userId: userId ||
|
|
143
|
+
userId: userId || "anonymous",
|
|
126
144
|
properties,
|
|
127
145
|
});
|
|
128
|
-
log.debug(
|
|
146
|
+
log.debug("Sent CLI event: %s", event);
|
|
129
147
|
};
|
|
130
148
|
export const getAnalyticsEventProperties = (args) => ({
|
|
131
149
|
version: pkg.version,
|
|
132
|
-
command: args._.join(
|
|
150
|
+
command: args._.join(" "),
|
|
133
151
|
flags: {
|
|
134
152
|
output: args.output,
|
|
135
153
|
},
|