neon 8.0.9 → 8.0.10
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/dist/_chunks/{env-ur81YnUp.js → env-BWqJqBDJ.js} +1 -1
- package/dist/_chunks/{env-C3uXp-nh.js → env-HYNFtxu5.js} +25 -6
- package/dist/commands/dev.js +2 -2
- package/dist/commands/env.js +12 -16
- package/dist/commands/env_output.js +64 -0
- package/dist/commands/link.js +5 -12
- package/dist/commands/link_output.js +2 -62
- package/dist/dev/env.js +1 -1
- package/dist/env_services.js +1 -1
- package/dist/utils/ai_gateway_notice.js +2 -1
- package/dist/utils/hooks.js +1 -1
- package/package.json +5 -5
|
@@ -2,7 +2,7 @@ import { log } from "../log.js";
|
|
|
2
2
|
import { getCliName } from "../utils/cli_name.js";
|
|
3
3
|
import { declaredNeonServices } from "../config_services.js";
|
|
4
4
|
import { loadProjectConfig } from "../project.js";
|
|
5
|
-
import { a as defaultAiGatewayCredential, c as fetchEnvKeysState, d as isLiveCredential, h as toEntries, i as credentialName, l as functionBaseUrlKey, m as resolveBranchPolicy, n as createApiFromOptions, o as defaultStorageCredential, p as policyEnvKeys, r as credentialEnvKeys, t as NEON_ENV_VAR_KEYS, u as isFunctionBaseUrlKey } from "./env-
|
|
5
|
+
import { a as defaultAiGatewayCredential, c as fetchEnvKeysState, d as isLiveCredential, h as toEntries, i as credentialName, l as functionBaseUrlKey, m as resolveBranchPolicy, n as createApiFromOptions, o as defaultStorageCredential, p as policyEnvKeys, r as credentialEnvKeys, t as NEON_ENV_VAR_KEYS, u as isFunctionBaseUrlKey } from "./env-HYNFtxu5.js";
|
|
6
6
|
import { ENV_PULL_SERVICES, envKeysForSelection, serviceForEnvKey, servicesForEnvKeys } from "../env_services.js";
|
|
7
7
|
import { formatInstallCommand, resolvePackageManager } from "../utils/package_manager.js";
|
|
8
8
|
import { ErrorCode, createNeonApiFromOptions, isPlatformError } from "@neon/config";
|
|
@@ -96,6 +96,22 @@ function parseFunctionBaseUrlKey(key) {
|
|
|
96
96
|
function isFunctionBaseUrlKey(key) {
|
|
97
97
|
return parseFunctionBaseUrlKey(key) !== null;
|
|
98
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Starts a read now and keeps an unread rejection from crashing the process; the caller
|
|
101
|
+
* awaits it (and sees the error) when its turn comes. The read is called synchronously and
|
|
102
|
+
* its own promise returned, so errors surface in the same order as a direct call; a
|
|
103
|
+
* synchronous throw becomes the returned rejection.
|
|
104
|
+
*/
|
|
105
|
+
function started(read) {
|
|
106
|
+
let promise;
|
|
107
|
+
try {
|
|
108
|
+
promise = read();
|
|
109
|
+
} catch (error) {
|
|
110
|
+
promise = Promise.reject(error);
|
|
111
|
+
}
|
|
112
|
+
promise.catch(() => void 0);
|
|
113
|
+
return promise;
|
|
114
|
+
}
|
|
99
115
|
/** Fail loudly when selected-key dependency planning and execution disagree. */
|
|
100
116
|
function requiredValue(value, description) {
|
|
101
117
|
if (value === null) throw new Error(`fetchEnv: missing ${description}.`);
|
|
@@ -142,8 +158,11 @@ async function fetchEnvKeysState(config, options, keys, policy) {
|
|
|
142
158
|
wants
|
|
143
159
|
});
|
|
144
160
|
const wantsAnyFunctionUrl = selection === null || selectedFunctionKeys.length > 0;
|
|
161
|
+
const storageEnabled = (desired.preview?.buckets.length ?? 0) > 0;
|
|
162
|
+
const wantsStorage = storageEnabled && (wants(K.storage.accessKeyId) || wants(K.storage.secretAccessKey) || wants(K.storage.endpoint) || wants(K.storage.region));
|
|
145
163
|
const functionsRead = functionUrlMode === "all-live" && wantsAnyFunctionUrl && options.listedFunctions === void 0 ? listFunctionInvocationUrls(api, projectId, branch.id) : null;
|
|
146
164
|
functionsRead?.catch(() => void 0);
|
|
165
|
+
const storageRead = wantsStorage ? started(() => api.getProjectBranchStorage(projectId, branch.id)) : null;
|
|
147
166
|
const needsUnpooled = wantsUnpooled || gatewayEnabled && wants(K.aiGateway.baseUrl) || constructSlugs.length > 0;
|
|
148
167
|
const needsConnectionTarget = wantsPooled || needsUnpooled;
|
|
149
168
|
const needsDatabase = needsConnectionTarget || wantsDataApi;
|
|
@@ -193,8 +212,6 @@ async function fetchEnvKeysState(config, options, keys, policy) {
|
|
|
193
212
|
}
|
|
194
213
|
result.dataApi = { url: dataApiSnapshot.url };
|
|
195
214
|
}
|
|
196
|
-
const storageEnabled = (desired.preview?.buckets.length ?? 0) > 0;
|
|
197
|
-
const wantsStorage = storageEnabled && (wants(K.storage.accessKeyId) || wants(K.storage.secretAccessKey) || wants(K.storage.endpoint) || wants(K.storage.region));
|
|
198
215
|
const wantsGateway = gatewayEnabled && (wants(K.aiGateway.apiKey) || wants(K.aiGateway.baseUrl));
|
|
199
216
|
const wantsStorageCredential = storageEnabled && (wants(K.storage.accessKeyId) || wants(K.storage.secretAccessKey));
|
|
200
217
|
const wantsGatewayCredential = gatewayEnabled && wants(K.aiGateway.apiKey);
|
|
@@ -202,7 +219,7 @@ async function fetchEnvKeysState(config, options, keys, policy) {
|
|
|
202
219
|
if (wantsStorage || wantsGateway) {
|
|
203
220
|
let storage = null;
|
|
204
221
|
if (wantsStorage) {
|
|
205
|
-
storage = await
|
|
222
|
+
storage = await requiredValue(storageRead, "storage read");
|
|
206
223
|
if (!storage) throw new PlatformError(ErrorCode.NotFound, [`fetchEnv: branch policy declares object storage (buckets) but storage is not enabled on branch ${branch.name} (${branch.id}).`, "Enable it via `apply(config, { projectId, branchId })` (or in the Neon Console) — then re-run fetchEnv. Or remove buckets."].join(" "), { details: {
|
|
207
224
|
projectId,
|
|
208
225
|
branchId: branch.id
|
|
@@ -407,12 +424,14 @@ async function resolveBranchCredentialSecrets(args) {
|
|
|
407
424
|
secretAccessKey: "",
|
|
408
425
|
apiToken: ""
|
|
409
426
|
};
|
|
410
|
-
|
|
411
|
-
|
|
427
|
+
const storageReveal = needsStorage && storageDefault ? started(() => args.api.revealCredential(args.projectId, args.branchId, storageDefault.tokenId)) : null;
|
|
428
|
+
const gatewayReveal = needsGateway && gatewayDefault ? started(() => args.api.revealCredential(args.projectId, args.branchId, gatewayDefault.tokenId)) : null;
|
|
429
|
+
if (storageReveal) {
|
|
430
|
+
const revealed = await storageReveal;
|
|
412
431
|
secrets.accessKeyId = revealed.tokenId;
|
|
413
432
|
secrets.secretAccessKey = revealed.s3SecretAccessKey;
|
|
414
433
|
}
|
|
415
|
-
if (
|
|
434
|
+
if (gatewayReveal) secrets.apiToken = (await gatewayReveal).apiToken;
|
|
416
435
|
const missingStorage = needsStorage && storageDefault === null;
|
|
417
436
|
const missingGateway = needsGateway && gatewayDefault === null;
|
|
418
437
|
if (missingStorage || missingGateway) {
|
package/dist/commands/dev.js
CHANGED
|
@@ -3,10 +3,10 @@ import { log } from "../log.js";
|
|
|
3
3
|
import { isClaimableEnvTarget } from "../claimable/state.js";
|
|
4
4
|
import { getCliName } from "../utils/cli_name.js";
|
|
5
5
|
import { readEnvFile, resolveEnvFilePath } from "../env_file.js";
|
|
6
|
-
import { l as functionBaseUrlKey } from "../_chunks/env-
|
|
6
|
+
import { l as functionBaseUrlKey } from "../_chunks/env-HYNFtxu5.js";
|
|
7
7
|
import { branchIdResolve } from "../utils/enrichers.js";
|
|
8
8
|
import { bundleEntry } from "../utils/esbuild.js";
|
|
9
|
-
import { a as resolveDevEnv } from "../_chunks/env-
|
|
9
|
+
import { a as resolveDevEnv } from "../_chunks/env-BWqJqBDJ.js";
|
|
10
10
|
import { findConfigFunctionBySource, resolveFunctionsFromConfig } from "../dev/functions.js";
|
|
11
11
|
import { resolveWatchInputs } from "../dev/inputs.js";
|
|
12
12
|
import { existsSync, mkdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
package/dist/commands/env.js
CHANGED
|
@@ -5,12 +5,13 @@ import { isClaimableEnvTarget } from "../claimable/state.js";
|
|
|
5
5
|
import { getCliName } from "../utils/cli_name.js";
|
|
6
6
|
import { deprecatedServiceMessage, parseServices, servicesFlagValue, servicesOption } from "../neon_services.js";
|
|
7
7
|
import { mergeEnvFile, readEnvFile, resolveEnvFilePath } from "../env_file.js";
|
|
8
|
-
import { t as NEON_ENV_VAR_KEYS, u as isFunctionBaseUrlKey } from "../_chunks/env-
|
|
8
|
+
import { t as NEON_ENV_VAR_KEYS, u as isFunctionBaseUrlKey } from "../_chunks/env-HYNFtxu5.js";
|
|
9
9
|
import { ENV_PULL_KEY_HELP, ENV_PULL_SERVICES, envKeysForSelection, envPullFlagValue, ownedEnvServiceKeys, parseEnvPullKeys } from "../env_services.js";
|
|
10
10
|
import { fillSingleProject, resolveBranchRef } from "../utils/enrichers.js";
|
|
11
11
|
import { warnAiGateway } from "../utils/ai_gateway_notice.js";
|
|
12
12
|
import { announceTargetBranch } from "../utils/branch_notice.js";
|
|
13
|
-
import { i as dropClaimableUnsupported, o as resolveNeonEnvVars } from "../_chunks/env-
|
|
13
|
+
import { i as dropClaimableUnsupported, o as resolveNeonEnvVars } from "../_chunks/env-BWqJqBDJ.js";
|
|
14
|
+
import { formatPulledEnv } from "./env_output.js";
|
|
14
15
|
import { existsSync } from "node:fs";
|
|
15
16
|
import chalk from "chalk";
|
|
16
17
|
//#region src/commands/env.ts
|
|
@@ -167,15 +168,13 @@ const pull = async (props, opts = {}) => {
|
|
|
167
168
|
return { status: "empty" };
|
|
168
169
|
}
|
|
169
170
|
const { written, removed } = mergeEnvFile(targetPath, neonVars, { managedKeys: managedKeysFor(selectedKeys, unreachedButCurrent(skipped, existingEnv, branchId), existingEnv, props.services !== void 0 ? selectionServices : void 0, props.envKeys !== void 0 ? selectionEnvKeys : void 0) });
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
}
|
|
171
|
+
process.stderr.write(formatPulledEnv({
|
|
172
|
+
status: "written",
|
|
173
|
+
written,
|
|
174
|
+
removed,
|
|
175
|
+
file: targetPath,
|
|
176
|
+
...credential && credential.keys.length > 0 ? { credential } : {}
|
|
177
|
+
}, cwd));
|
|
179
178
|
if (!fileExisted) ensureGitignored(targetPath);
|
|
180
179
|
const gatewayBaseUrl = neonVars.NEON_AI_GATEWAY_BASE_URL;
|
|
181
180
|
const gatewayToken = neonVars.NEON_AI_GATEWAY_TOKEN;
|
|
@@ -254,16 +253,13 @@ const pickSelectedVars = (vars, selectedKeys, services) => {
|
|
|
254
253
|
* command's primary effect and has already succeeded by the time this runs, so a pull failure
|
|
255
254
|
* degrades to a warning rather than failing the command.
|
|
256
255
|
*/
|
|
257
|
-
const autoPullEnvAfterPin = async (props, branch
|
|
256
|
+
const autoPullEnvAfterPin = async (props, branch) => {
|
|
258
257
|
if (!props.envPull) {
|
|
259
258
|
log.info(chalk.dim(ENV_PULL_SKIPPED_HINT));
|
|
260
259
|
return { status: "skipped" };
|
|
261
260
|
}
|
|
262
261
|
try {
|
|
263
|
-
return await pull(props, {
|
|
264
|
-
...branch ? { branch } : {},
|
|
265
|
-
...opts.report === false ? { report: false } : {}
|
|
266
|
-
});
|
|
262
|
+
return await pull(props, branch ? { branch } : {});
|
|
267
263
|
} catch (err) {
|
|
268
264
|
const message = err instanceof Error ? err.message : String(err);
|
|
269
265
|
log.warning(`Branch pinned, but pulling its Neon env vars failed: %s
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { NEON_SERVICES, NEON_SERVICE_LABELS } from "../neon_services.js";
|
|
2
|
+
import { u as isFunctionBaseUrlKey } from "../_chunks/env-HYNFtxu5.js";
|
|
3
|
+
import { BRANCH_ENV_KEY, ENV_PULL_KEYS, serviceForEnvKey } from "../env_services.js";
|
|
4
|
+
import { isAbsolute, relative } from "node:path";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
//#region src/commands/env_output.ts
|
|
7
|
+
/** Wide enough for the longest label ("Object Storage") plus a gutter, so blocks align. */
|
|
8
|
+
const LABEL_WIDTH = 16;
|
|
9
|
+
const row = (label, value) => ` ${label.padEnd(LABEL_WIDTH)}${value}`;
|
|
10
|
+
/** Relative to `cwd` when the file is inside it, else absolute with the home directory as `~`. */
|
|
11
|
+
const displayPath = (file, cwd) => {
|
|
12
|
+
const rel = relative(cwd, file);
|
|
13
|
+
if (rel !== "" && !rel.startsWith("..") && !isAbsolute(rel)) return rel;
|
|
14
|
+
const home = homedir();
|
|
15
|
+
return file.startsWith(`${home}/`) ? `~${file.slice(home.length)}` : file;
|
|
16
|
+
};
|
|
17
|
+
const BRANCH_GROUP = "Branch";
|
|
18
|
+
const OTHER_GROUP = "Other";
|
|
19
|
+
const GROUP_ORDER = [
|
|
20
|
+
NEON_SERVICE_LABELS.postgres,
|
|
21
|
+
BRANCH_GROUP,
|
|
22
|
+
...NEON_SERVICES.filter((service) => service !== "postgres").map((service) => NEON_SERVICE_LABELS[service]),
|
|
23
|
+
OTHER_GROUP
|
|
24
|
+
];
|
|
25
|
+
const groupOf = (key) => {
|
|
26
|
+
if (key === BRANCH_ENV_KEY) return BRANCH_GROUP;
|
|
27
|
+
if (isFunctionBaseUrlKey(key)) return NEON_SERVICE_LABELS.functions;
|
|
28
|
+
const pullKey = ENV_PULL_KEYS.find((candidate) => candidate === key);
|
|
29
|
+
const service = pullKey ? serviceForEnvKey(pullKey) : null;
|
|
30
|
+
return service ? NEON_SERVICE_LABELS[service] : OTHER_GROUP;
|
|
31
|
+
};
|
|
32
|
+
/** Canonical key order, so a row reads the same whether a key was rewritten or reused. */
|
|
33
|
+
const keyRank = (key) => {
|
|
34
|
+
const index = ENV_PULL_KEYS.findIndex((candidate) => candidate === key);
|
|
35
|
+
return index === -1 ? ENV_PULL_KEYS.length : index;
|
|
36
|
+
};
|
|
37
|
+
const byKeyRank = (a, b) => keyRank(a) - keyRank(b) || a.localeCompare(b);
|
|
38
|
+
const groupKeys = (keys) => {
|
|
39
|
+
const groups = /* @__PURE__ */ new Map();
|
|
40
|
+
for (const key of [...keys].sort(byKeyRank)) {
|
|
41
|
+
const group = groupOf(key);
|
|
42
|
+
groups.set(group, [...groups.get(group) ?? [], key]);
|
|
43
|
+
}
|
|
44
|
+
return groups;
|
|
45
|
+
};
|
|
46
|
+
const formatPulledEnv = (outcome, cwd) => {
|
|
47
|
+
const fresh = new Set(outcome.credential?.fresh ?? []);
|
|
48
|
+
const count = outcome.written.length;
|
|
49
|
+
const lines = [`Pulled ${count} Neon variable${count === 1 ? "" : "s"} into ${displayPath(outcome.file, cwd)}`];
|
|
50
|
+
const groups = groupKeys(outcome.written);
|
|
51
|
+
for (const group of GROUP_ORDER) {
|
|
52
|
+
const keys = groups.get(group);
|
|
53
|
+
if (!keys) continue;
|
|
54
|
+
lines.push(row(group, keys.map((key) => fresh.has(key) ? `${key}*` : key).join(", ")));
|
|
55
|
+
}
|
|
56
|
+
if (outcome.removed.length > 0) lines.push(row("Removed", `${outcome.removed.join(", ")} (not produced by this pull)`));
|
|
57
|
+
if (fresh.size > 0) lines.push(" * new credential value");
|
|
58
|
+
const credential = outcome.credential;
|
|
59
|
+
if (credential?.issued && credential.revoked.length > 0) lines.push(`Revoked the credential it replaced (${credential.revoked.join(", ")}).`);
|
|
60
|
+
else if (credential?.issued && credential.superseded.length > 0) lines.push(`Left the credential it replaced live (${credential.superseded.join(", ")}): an explicitly scoped pull can't tell which other variables still use it. Revoke it in the Neon Console if nothing does.`);
|
|
61
|
+
return `${lines.join("\n")}\n`;
|
|
62
|
+
};
|
|
63
|
+
//#endregion
|
|
64
|
+
export { displayPath, formatPulledEnv, row };
|
package/dist/commands/link.js
CHANGED
|
@@ -15,7 +15,7 @@ import { looksLikeBranchId } from "../utils/formats.js";
|
|
|
15
15
|
import { listAllProjectBranches } from "../utils/enrichers.js";
|
|
16
16
|
import { autoPullEnvAfterPin } from "./env.js";
|
|
17
17
|
import { initCmd } from "./config.js";
|
|
18
|
-
import { formatLinkSummary
|
|
18
|
+
import { formatLinkSummary } from "./link_output.js";
|
|
19
19
|
import { REGIONS } from "./projects.js";
|
|
20
20
|
import prompts from "prompts";
|
|
21
21
|
//#region src/commands/link.ts
|
|
@@ -856,11 +856,6 @@ const createProject = async (props, args) => {
|
|
|
856
856
|
const printSummary = (props, summary) => {
|
|
857
857
|
process.stdout.write(`${formatLinkSummary(summary, props.cwd ?? process.cwd())}\n`);
|
|
858
858
|
};
|
|
859
|
-
/** The env block `link` prints under its summary, once the bundled pull has written the file. */
|
|
860
|
-
const printPulledEnv = (props, result) => {
|
|
861
|
-
if (result.status !== "written") return;
|
|
862
|
-
process.stdout.write(formatPulledEnv(result, props.cwd ?? process.cwd()));
|
|
863
|
-
};
|
|
864
859
|
/**
|
|
865
860
|
* Print the link summary, then run the bundled `env pull` so a completed `link` ends with
|
|
866
861
|
* the pinned branch's connection string on disk. `--no-checks` skips the pull because
|
|
@@ -871,14 +866,13 @@ const finalizeLink = async (props, summary) => {
|
|
|
871
866
|
printSummary(props, summary);
|
|
872
867
|
if (!summary.branch || !summary.projectId || summary.noChecks) return;
|
|
873
868
|
const { config: _offerConfig, ...rest } = props;
|
|
874
|
-
|
|
869
|
+
await autoPullEnvAfterPin({
|
|
875
870
|
...rest,
|
|
876
871
|
...props.cwd ? { cwd: props.cwd } : {},
|
|
877
872
|
projectId: summary.projectId,
|
|
878
873
|
branch: summary.branch,
|
|
879
874
|
envPull: props.envPull
|
|
880
|
-
}, summary.branchRef
|
|
881
|
-
printPulledEnv(props, pulled);
|
|
875
|
+
}, summary.branchRef);
|
|
882
876
|
};
|
|
883
877
|
/**
|
|
884
878
|
* Interactive `link` finalize: the shared {@link finalizeLink} (summary + env
|
|
@@ -919,13 +913,12 @@ const maybeOfferConfigInit = async (props, summary) => {
|
|
|
919
913
|
});
|
|
920
914
|
if (summary.branch && summary.projectId) {
|
|
921
915
|
const { config: _offerConfig, ...rest } = props;
|
|
922
|
-
|
|
916
|
+
await autoPullEnvAfterPin({
|
|
923
917
|
...rest,
|
|
924
918
|
projectId: summary.projectId,
|
|
925
919
|
branch: summary.branch,
|
|
926
920
|
envPull: props.envPull
|
|
927
|
-
}, summary.branchRef
|
|
928
|
-
printPulledEnv(props, pulled);
|
|
921
|
+
}, summary.branchRef);
|
|
929
922
|
}
|
|
930
923
|
};
|
|
931
924
|
const onPromptState = (state) => {
|
|
@@ -1,19 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { u as isFunctionBaseUrlKey } from "../_chunks/env-C3uXp-nh.js";
|
|
3
|
-
import { BRANCH_ENV_KEY, ENV_PULL_KEYS, serviceForEnvKey } from "../env_services.js";
|
|
4
|
-
import { isAbsolute, relative } from "node:path";
|
|
5
|
-
import { homedir } from "node:os";
|
|
1
|
+
import { displayPath, row } from "./env_output.js";
|
|
6
2
|
//#region src/commands/link_output.ts
|
|
7
|
-
/** Wide enough for the longest label ("Object Storage") plus a gutter, so both blocks align. */
|
|
8
|
-
const LABEL_WIDTH = 16;
|
|
9
|
-
const row = (label, value) => ` ${label.padEnd(LABEL_WIDTH)}${value}`;
|
|
10
|
-
/** Relative to `cwd` when the file is inside it, else absolute with the home directory as `~`. */
|
|
11
|
-
const displayPath = (file, cwd) => {
|
|
12
|
-
const rel = relative(cwd, file);
|
|
13
|
-
if (rel !== "" && !rel.startsWith("..") && !isAbsolute(rel)) return rel;
|
|
14
|
-
const home = homedir();
|
|
15
|
-
return file.startsWith(`${home}/`) ? `~${file.slice(home.length)}` : file;
|
|
16
|
-
};
|
|
17
3
|
const formatLinkSummary = (summary, cwd) => {
|
|
18
4
|
const lines = [];
|
|
19
5
|
if (summary.created) lines.push(`Created project ${summary.projectName ?? summary.projectId}${summary.regionId ? ` in ${summary.regionId}` : ""}`);
|
|
@@ -27,51 +13,5 @@ const formatLinkSummary = (summary, cwd) => {
|
|
|
27
13
|
}
|
|
28
14
|
return `${lines.join("\n")}\n`;
|
|
29
15
|
};
|
|
30
|
-
const BRANCH_GROUP = "Branch";
|
|
31
|
-
const OTHER_GROUP = "Other";
|
|
32
|
-
const GROUP_ORDER = [
|
|
33
|
-
NEON_SERVICE_LABELS.postgres,
|
|
34
|
-
BRANCH_GROUP,
|
|
35
|
-
...NEON_SERVICES.filter((service) => service !== "postgres").map((service) => NEON_SERVICE_LABELS[service]),
|
|
36
|
-
OTHER_GROUP
|
|
37
|
-
];
|
|
38
|
-
const groupOf = (key) => {
|
|
39
|
-
if (key === BRANCH_ENV_KEY) return BRANCH_GROUP;
|
|
40
|
-
if (isFunctionBaseUrlKey(key)) return NEON_SERVICE_LABELS.functions;
|
|
41
|
-
const pullKey = ENV_PULL_KEYS.find((candidate) => candidate === key);
|
|
42
|
-
const service = pullKey ? serviceForEnvKey(pullKey) : null;
|
|
43
|
-
return service ? NEON_SERVICE_LABELS[service] : OTHER_GROUP;
|
|
44
|
-
};
|
|
45
|
-
/** Canonical key order, so a row reads the same whether a key was rewritten or reused. */
|
|
46
|
-
const keyRank = (key) => {
|
|
47
|
-
const index = ENV_PULL_KEYS.findIndex((candidate) => candidate === key);
|
|
48
|
-
return index === -1 ? ENV_PULL_KEYS.length : index;
|
|
49
|
-
};
|
|
50
|
-
const byKeyRank = (a, b) => keyRank(a) - keyRank(b) || a.localeCompare(b);
|
|
51
|
-
const groupKeys = (keys) => {
|
|
52
|
-
const groups = /* @__PURE__ */ new Map();
|
|
53
|
-
for (const key of [...keys].sort(byKeyRank)) {
|
|
54
|
-
const group = groupOf(key);
|
|
55
|
-
groups.set(group, [...groups.get(group) ?? [], key]);
|
|
56
|
-
}
|
|
57
|
-
return groups;
|
|
58
|
-
};
|
|
59
|
-
const formatPulledEnv = (outcome, cwd) => {
|
|
60
|
-
const fresh = new Set(outcome.credential?.fresh ?? []);
|
|
61
|
-
const count = outcome.written.length;
|
|
62
|
-
const lines = [`Pulled ${count} Neon variable${count === 1 ? "" : "s"} into ${displayPath(outcome.file, cwd)}`];
|
|
63
|
-
const groups = groupKeys(outcome.written);
|
|
64
|
-
for (const group of GROUP_ORDER) {
|
|
65
|
-
const keys = groups.get(group);
|
|
66
|
-
if (!keys) continue;
|
|
67
|
-
lines.push(row(group, keys.map((key) => fresh.has(key) ? `${key}*` : key).join(", ")));
|
|
68
|
-
}
|
|
69
|
-
if (outcome.removed.length > 0) lines.push(row("Removed", `${outcome.removed.join(", ")} (not enabled on this branch)`));
|
|
70
|
-
if (fresh.size > 0) lines.push(" * new credential value");
|
|
71
|
-
const credential = outcome.credential;
|
|
72
|
-
if (credential?.issued && credential.revoked.length > 0) lines.push(`Revoked the credential it replaced (${credential.revoked.join(", ")}).`);
|
|
73
|
-
else if (credential?.issued && credential.superseded.length > 0) lines.push(`Left the credential it replaced live (${credential.superseded.join(", ")}): an explicitly scoped pull can't tell which other variables still use it. Revoke it in the Neon Console if nothing does.`);
|
|
74
|
-
return `${lines.join("\n")}\n`;
|
|
75
|
-
};
|
|
76
16
|
//#endregion
|
|
77
|
-
export {
|
|
17
|
+
export { formatLinkSummary };
|
package/dist/dev/env.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as resolveDevEnv, i as dropClaimableUnsupported, n as MissingBranchContextError, o as resolveNeonEnvVars, r as ServiceNotOnBranchError, t as DevEnvMismatchError } from "../_chunks/env-
|
|
1
|
+
import { a as resolveDevEnv, i as dropClaimableUnsupported, n as MissingBranchContextError, o as resolveNeonEnvVars, r as ServiceNotOnBranchError, t as DevEnvMismatchError } from "../_chunks/env-BWqJqBDJ.js";
|
|
2
2
|
export { DevEnvMismatchError, MissingBranchContextError, ServiceNotOnBranchError, dropClaimableUnsupported, resolveDevEnv, resolveNeonEnvVars };
|
package/dist/env_services.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NEON_SERVICES } from "./neon_services.js";
|
|
2
|
-
import { f as parseFunctionBaseUrlKey, t as NEON_ENV_VAR_KEYS, u as isFunctionBaseUrlKey } from "./_chunks/env-
|
|
2
|
+
import { f as parseFunctionBaseUrlKey, t as NEON_ENV_VAR_KEYS, u as isFunctionBaseUrlKey } from "./_chunks/env-HYNFtxu5.js";
|
|
3
3
|
//#region src/env_services.ts
|
|
4
4
|
const ENV_PULL_SERVICES = NEON_SERVICES;
|
|
5
5
|
const ENV_PULL_KEYS = [
|
|
@@ -131,11 +131,12 @@ const assertAiGatewayProvisionable = async (params) => {
|
|
|
131
131
|
* fetching the plan or catalog is swallowed so it can never break the underlying command.
|
|
132
132
|
*/
|
|
133
133
|
const warnAiGateway = async (params) => {
|
|
134
|
+
const modelsRead = params.gateway ? fetchGatewayModelIds(params.gateway.baseUrl, params.gateway.token) : null;
|
|
134
135
|
try {
|
|
135
136
|
const { data } = await params.apiClient.getProject(params.projectId);
|
|
136
137
|
const subscriptionType = data.project.owner?.subscription_type;
|
|
137
138
|
const orgId = data.project.org_id ?? void 0;
|
|
138
|
-
const modelIds =
|
|
139
|
+
const modelIds = modelsRead ? await modelsRead ?? void 0 : void 0;
|
|
139
140
|
const notice = buildAiGatewayNotice({
|
|
140
141
|
subscriptionType,
|
|
141
142
|
modelIds,
|
package/dist/utils/hooks.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { log } from "../log.js";
|
|
2
2
|
import { loadProjectConfig } from "../project.js";
|
|
3
|
-
import { s as fetchEnvKeys } from "../_chunks/env-
|
|
3
|
+
import { s as fetchEnvKeys } from "../_chunks/env-HYNFtxu5.js";
|
|
4
4
|
import { runHook } from "@neon/config-runtime";
|
|
5
5
|
//#region src/utils/hooks.ts
|
|
6
6
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neon",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.10",
|
|
4
4
|
"description": "CLI tool for Neon, the cloud backend primitives built around Lakebase Postgres",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"neon",
|
|
@@ -64,9 +64,9 @@
|
|
|
64
64
|
"yaml": "^2.9.0",
|
|
65
65
|
"yargs": "17.7.2",
|
|
66
66
|
"yoctocolors": "^2.1.2",
|
|
67
|
-
"@neon/config": "1.8.
|
|
68
|
-
"@neon/
|
|
69
|
-
"@neon/
|
|
67
|
+
"@neon/config": "1.8.4",
|
|
68
|
+
"@neon/config-runtime": "1.7.6",
|
|
69
|
+
"@neon/sdk": "7.0.1"
|
|
70
70
|
},
|
|
71
71
|
"optionalDependencies": {
|
|
72
72
|
"@napi-rs/keyring": "1.3.0",
|
|
@@ -100,8 +100,8 @@
|
|
|
100
100
|
"typescript": "^5.9.0",
|
|
101
101
|
"vitest": "^3.0.9",
|
|
102
102
|
"@neon-internals/cli-core": "0.0.0",
|
|
103
|
-
"@neon-internals/env-core": "0.0.26",
|
|
104
103
|
"@neon/e2e-harness": "0.0.0",
|
|
104
|
+
"@neon-internals/env-core": "0.0.27",
|
|
105
105
|
"@neon/functions": "0.11.0"
|
|
106
106
|
},
|
|
107
107
|
"publishConfig": {
|