@neon/env 1.6.14 → 2.0.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 +30 -12
- package/dist/cli.js +5 -9
- package/dist/cli.js.map +1 -1
- package/dist/env.js +49 -110
- package/dist/env.js.map +1 -1
- package/dist/index.d.ts +50 -54
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +72 -55
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,6 +1,66 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as fetchEnv, n as NEON_ENV_VAR_KEYS, p as toEntries, t as NEON_DEV_FUNCTION_PORTS } from "./env.js";
|
|
2
2
|
import { ErrorCode, PlatformError, authoredAiGateway, authoredBuckets, authoredFunctions } from "@neon/config/v1";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
// src/lib/function-base-url.ts
|
|
5
|
+
/**
|
|
6
|
+
* `functionBaseUrl` — the URL another Neon Function on the same branch answers at, built from
|
|
7
|
+
* the variables the Functions runtime injects into every function, so a deployed function needs
|
|
8
|
+
* no extra env. `neon env pull` writes the same variables locally and `neon dev` adds the
|
|
9
|
+
* localhost port of each function it serves.
|
|
10
|
+
*/
|
|
11
|
+
const SLUG = /^[a-z0-9]{1,20}$/;
|
|
12
|
+
const DNS_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
13
|
+
/**
|
|
14
|
+
* The base URL of function `slug` on the current branch, without a trailing slash:
|
|
15
|
+
* `https://<NEON_BRANCH_ID>-<slug><NEON_FUNCTION_HOST_SUFFIX>`, or `http://localhost:<port>`
|
|
16
|
+
* when `neon dev` serves that function.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { functionBaseUrl } from "@neon/env";
|
|
21
|
+
*
|
|
22
|
+
* const res = await fetch(`${functionBaseUrl("hello")}/greet`);
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @throws {TypeError} when `slug` is not a valid function slug (`[a-z0-9]{1,20}`).
|
|
26
|
+
* @throws {PlatformError} `PLATFORM_ENV_NOT_INJECTED` when the variables are missing or do
|
|
27
|
+
* not form a valid hostname.
|
|
28
|
+
*/
|
|
29
|
+
function functionBaseUrl(slug, env = process.env) {
|
|
30
|
+
if (!SLUG.test(slug)) throw new TypeError(`functionBaseUrl: ${JSON.stringify(slug)} is not a function slug (1-20 lowercase letters and digits).`);
|
|
31
|
+
const port = devFunctionPort(slug, env[NEON_DEV_FUNCTION_PORTS]);
|
|
32
|
+
if (port !== void 0) return `http://localhost:${port}`;
|
|
33
|
+
const K = NEON_ENV_VAR_KEYS.branch;
|
|
34
|
+
const branchId = env[K.id];
|
|
35
|
+
const suffix = env[K.functionHostSuffix];
|
|
36
|
+
const missing = [...branchId ? [] : [K.id], ...suffix ? [] : [K.functionHostSuffix]];
|
|
37
|
+
if (!branchId || !suffix) throw new PlatformError(ErrorCode.EnvNotInjected, [`functionBaseUrl: ${missing.join(" and ")} ${missing.length > 1 ? "are" : "is"} not set.`, "Deployed Neon Functions have them. Locally, run `neon env pull` or `neon dev`."].join("\n"), { details: { missing } });
|
|
38
|
+
const label = `${branchId}-${slug}`;
|
|
39
|
+
const hostname = `${label}${suffix}`;
|
|
40
|
+
const suffixLabels = suffix.startsWith(".") ? suffix.slice(1).split(".") : [];
|
|
41
|
+
if (!DNS_LABEL.test(label) || suffixLabels.length === 0 || !suffixLabels.every((part) => DNS_LABEL.test(part)) || hostname.length > 253) throw new PlatformError(ErrorCode.EnvNotInjected, `functionBaseUrl: ${K.id}=${JSON.stringify(branchId)} and ${K.functionHostSuffix}=${JSON.stringify(suffix)} do not form a function hostname. Re-run \`neon env pull\`.`, { details: {
|
|
42
|
+
branchId,
|
|
43
|
+
functionHostSuffix: suffix
|
|
44
|
+
} });
|
|
45
|
+
return `https://${hostname}`;
|
|
46
|
+
}
|
|
47
|
+
function devFunctionPort(slug, raw) {
|
|
48
|
+
if (raw === void 0) return void 0;
|
|
49
|
+
let ports;
|
|
50
|
+
try {
|
|
51
|
+
ports = JSON.parse(raw);
|
|
52
|
+
} catch {
|
|
53
|
+
throw invalidDevPorts(raw);
|
|
54
|
+
}
|
|
55
|
+
if (typeof ports !== "object" || ports === null || Array.isArray(ports)) throw invalidDevPorts(raw);
|
|
56
|
+
if (!Object.hasOwn(ports, slug)) return void 0;
|
|
57
|
+
const port = Reflect.get(ports, slug);
|
|
58
|
+
if (typeof port !== "number" || !Number.isInteger(port) || port < 1 || port > 65535) throw invalidDevPorts(raw);
|
|
59
|
+
return port;
|
|
60
|
+
}
|
|
61
|
+
function invalidDevPorts(raw) {
|
|
62
|
+
return new PlatformError(ErrorCode.EnvNotInjected, `functionBaseUrl: ${NEON_DEV_FUNCTION_PORTS}=${JSON.stringify(raw)} is not a JSON object of function ports. \`neon dev\` sets it; restart \`neon dev\`.`, { details: { [NEON_DEV_FUNCTION_PORTS]: raw } });
|
|
63
|
+
}
|
|
4
64
|
// src/lib/parse-env.ts
|
|
5
65
|
/**
|
|
6
66
|
* `parseEnv` — the synchronous, network-free counterpart to `fetchEnv`: read the Neon env vars
|
|
@@ -72,7 +132,14 @@ function parseEnv(config, scopeOrKeys) {
|
|
|
72
132
|
};
|
|
73
133
|
else for (const issue of pg.error.issues) issues.push(issue.message);
|
|
74
134
|
const branchName = source[NEON_ENV_VAR_KEYS.branch.name];
|
|
75
|
-
if (branchName !== void 0 && branchName !== "")
|
|
135
|
+
if (branchName !== void 0 && branchName !== "") {
|
|
136
|
+
const branch = { name: branchName };
|
|
137
|
+
const branchId = source[NEON_ENV_VAR_KEYS.branch.id];
|
|
138
|
+
if (branchId) branch.id = branchId;
|
|
139
|
+
const hostSuffix = source[NEON_ENV_VAR_KEYS.branch.functionHostSuffix];
|
|
140
|
+
if (hostSuffix) branch.functionHostSuffix = hostSuffix;
|
|
141
|
+
result.branch = branch;
|
|
142
|
+
}
|
|
76
143
|
if (isServiceEnabledInput(config.auth)) {
|
|
77
144
|
const auth = authEnvSchema.safeParse({
|
|
78
145
|
NEON_AUTH_BASE_URL: source.NEON_AUTH_BASE_URL,
|
|
@@ -126,18 +193,6 @@ function parseEnv(config, scopeOrKeys) {
|
|
|
126
193
|
};
|
|
127
194
|
else for (const issue of aiGateway.error.issues) issues.push(issue.message);
|
|
128
195
|
}
|
|
129
|
-
const declaredFunctionSlugs = Object.keys(authoredFunctions(config) ?? {}).sort();
|
|
130
|
-
if (declaredFunctionSlugs.length > 0) {
|
|
131
|
-
const functions = {};
|
|
132
|
-
for (const slug of declaredFunctionSlugs) {
|
|
133
|
-
const key = functionBaseUrlKey(slug);
|
|
134
|
-
if (source[key] === void 0) continue;
|
|
135
|
-
const parsed = readFunctionBaseUrl(key, source[key]);
|
|
136
|
-
if (parsed.ok) functions[slug] = { baseUrl: parsed.value };
|
|
137
|
-
else issues.push(parsed.issue);
|
|
138
|
-
}
|
|
139
|
-
if (Object.keys(functions).length === declaredFunctionSlugs.length) result.functions = functions;
|
|
140
|
-
}
|
|
141
196
|
if (scope !== void 0) {
|
|
142
197
|
const fn = authoredFunctions(config)?.[scope];
|
|
143
198
|
if (!fn) throw new PlatformError(ErrorCode.EnvNotInjected, [`parseEnv: no function "${scope}" is declared in this policy's functions.`, "Pass a declared function slug (or omit the scope to read external env)."].join("\n"), { details: { scope } });
|
|
@@ -157,40 +212,13 @@ function parseEnv(config, scopeOrKeys) {
|
|
|
157
212
|
].join("\n"), { details: { missing: issues } });
|
|
158
213
|
return result;
|
|
159
214
|
}
|
|
160
|
-
function isFunctionBaseUrlIssue(issue) {
|
|
161
|
-
return /^NEON_FUNCTION_[A-Z0-9]+_BASE_URL (is missing|must not be empty|must be a URL)$/.test(issue);
|
|
162
|
-
}
|
|
163
|
-
function readFunctionBaseUrl(key, value) {
|
|
164
|
-
if (value === void 0) return {
|
|
165
|
-
ok: false,
|
|
166
|
-
issue: `${key} is missing`
|
|
167
|
-
};
|
|
168
|
-
if (value === "") return {
|
|
169
|
-
ok: false,
|
|
170
|
-
issue: `${key} must not be empty`
|
|
171
|
-
};
|
|
172
|
-
try {
|
|
173
|
-
new URL(value);
|
|
174
|
-
} catch {
|
|
175
|
-
return {
|
|
176
|
-
ok: false,
|
|
177
|
-
issue: `${key} must be a URL`
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
return {
|
|
181
|
-
ok: true,
|
|
182
|
-
value
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
215
|
function parseEnvInjectHint(issues) {
|
|
186
|
-
if (issues.length > 0 && issues.every(isFunctionBaseUrlIssue)) return ["Inject them via `neon env pull` or `neon-env run` (production URL), or `neon dev` (`http://localhost:<port>`)."];
|
|
187
216
|
const lines = [
|
|
188
217
|
"Inject them via one of:",
|
|
189
218
|
" - `neon dev` / `neon-env run -- <your dev command>` (wraps the command with the vars injected)",
|
|
190
219
|
" - your hosting platform's Neon integration (Vercel, Fly, Railway, …)"
|
|
191
220
|
];
|
|
192
221
|
if (issues.some((issue) => issue.includes("(function \""))) lines.push(" - for the `function` namespace: deploy the function (`neon deploy` / `config apply`) so its env is uploaded.");
|
|
193
|
-
if (issues.some(isFunctionBaseUrlIssue)) lines.push(" - for NEON_FUNCTION_*_BASE_URL: `neon env pull` or `neon dev`.");
|
|
194
222
|
return lines;
|
|
195
223
|
}
|
|
196
224
|
/**
|
|
@@ -203,6 +231,8 @@ const FILTERABLE_ENV_KEYS = {
|
|
|
203
231
|
DATABASE_URL: ["postgres", "databaseUrl"],
|
|
204
232
|
DATABASE_URL_UNPOOLED: ["postgres", "databaseUrlUnpooled"],
|
|
205
233
|
NEON_BRANCH: ["branch", "name"],
|
|
234
|
+
NEON_BRANCH_ID: ["branch", "id"],
|
|
235
|
+
NEON_FUNCTION_HOST_SUFFIX: ["branch", "functionHostSuffix"],
|
|
206
236
|
NEON_AUTH_BASE_URL: ["auth", "baseUrl"],
|
|
207
237
|
NEON_AUTH_JWKS_URL: ["auth", "jwksUrl"],
|
|
208
238
|
NEON_DATA_API_URL: ["dataApi", "url"],
|
|
@@ -225,19 +255,7 @@ const FILTERABLE_ENV_KEYS = {
|
|
|
225
255
|
function parseFilteredEnv(source, keys) {
|
|
226
256
|
const issues = [];
|
|
227
257
|
const result = {};
|
|
228
|
-
const functionUrls = {};
|
|
229
258
|
for (const key of keys) {
|
|
230
|
-
if (isFunctionBaseUrlKey(key)) {
|
|
231
|
-
const slug = parseFunctionBaseUrlKey(key);
|
|
232
|
-
if (slug === null) continue;
|
|
233
|
-
const parsed = readFunctionBaseUrl(key, source[key]);
|
|
234
|
-
if (!parsed.ok) {
|
|
235
|
-
issues.push(parsed.issue);
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
238
|
-
functionUrls[slug] = { baseUrl: parsed.value };
|
|
239
|
-
continue;
|
|
240
|
-
}
|
|
241
259
|
if (!Object.hasOwn(FILTERABLE_ENV_KEYS, key)) {
|
|
242
260
|
issues.push(`${key} is not a selectable Neon env variable`);
|
|
243
261
|
continue;
|
|
@@ -256,7 +274,6 @@ function parseFilteredEnv(source, keys) {
|
|
|
256
274
|
bucket[property] = value;
|
|
257
275
|
result[namespace] = bucket;
|
|
258
276
|
}
|
|
259
|
-
if (Object.keys(functionUrls).length > 0) result.functions = functionUrls;
|
|
260
277
|
if (issues.length > 0) throw new PlatformError(ErrorCode.EnvNotInjected, [
|
|
261
278
|
"parseEnv: the required Neon env variables are not present in process.env.",
|
|
262
279
|
...issues.map((i) => ` - ${i}`),
|
|
@@ -265,6 +282,6 @@ function parseFilteredEnv(source, keys) {
|
|
|
265
282
|
].join("\n"), { details: { missing: issues } });
|
|
266
283
|
return result;
|
|
267
284
|
}
|
|
268
|
-
export { NEON_ENV_VAR_KEYS, fetchEnv,
|
|
285
|
+
export { NEON_ENV_VAR_KEYS, fetchEnv, functionBaseUrl, parseEnv, toEntries };
|
|
269
286
|
|
|
270
287
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/lib/parse-env.ts"],"sourcesContent":["/**\n * `parseEnv` — the synchronous, network-free counterpart to `fetchEnv`: read the Neon env vars\n * already injected into `process.env`, validate them against the policy, and return them in the\n * same namespaced shape.\n *\n * Lives in this package rather than in `@neon-internals/env-core` because nothing else needs\n * it. The `neon` CLI resolves env from the API and injects it; it never reads it back. Keeping\n * it here also keeps `zod` out of that package, and so out of every consumer that bundles it.\n */\n\nimport {\n\tauthoredAiGateway,\n\tauthoredBuckets,\n\tauthoredFunctions,\n\ttype Config,\n\tErrorCode,\n\tPlatformError,\n\ttype ServiceToggleInput,\n} from \"@neon/config/v1\";\nimport {\n\ttype FilteredNeonEnv,\n\tfunctionBaseUrlKey,\n\tisFunctionBaseUrlKey,\n\tNEON_ENV_VAR_KEYS,\n\ttype NeonAiGatewayEnv,\n\ttype NeonAuthEnv,\n\ttype NeonBranchEnv,\n\ttype NeonDataApiEnv,\n\ttype NeonEnv,\n\ttype NeonFunctionUrlEnv,\n\ttype NeonPostgresEnv,\n\ttype NeonRealtimeEnv,\n\ttype NeonStorageEnv,\n\tparseFunctionBaseUrlKey,\n\ttype SelectableEnvKey,\n} from \"@neon-internals/env-core/env\";\nimport { z } from \"zod\";\n\n/** The static `functions` record of a config (GA or deprecated `preview.functions`). */\ntype GaFunctionsOf<C extends Config> = [NonNullable<C[\"functions\"]>] extends [\n\tnever,\n]\n\t? Record<never, never>\n\t: string extends keyof NonNullable<C[\"functions\"]>\n\t\t? Record<never, never>\n\t\t: NonNullable<C[\"functions\"]>;\n\ntype PreviewFunctionsHome<C extends Config> = [\n\tNonNullable<C[\"preview\"]>,\n] extends [never]\n\t? Record<never, never>\n\t: NonNullable<C[\"preview\"]> extends { functions: infer F }\n\t\t? F\n\t\t: Record<never, never>;\n\ntype PreviewFunctionsOf<C extends Config> = [keyof GaFunctionsOf<C>] extends [\n\tnever,\n]\n\t? PreviewFunctionsHome<C>\n\t: [keyof PreviewFunctionsHome<C>] extends [never]\n\t\t? GaFunctionsOf<C>\n\t\t: GaFunctionsOf<C> & PreviewFunctionsHome<C>;\n\n/** The declared function slugs of a config (record keys), as a string union. */\nexport type FunctionSlugOf<C extends Config> = Extract<\n\tkeyof PreviewFunctionsOf<C>,\n\tstring\n>;\n\n/**\n * Human-readable hint surfaced as the **expected type** of `parseEnv`'s `scope` argument when\n * the policy declares no functions at all. Without it the argument's expected type is the bare\n * `never` {@link FunctionSlugOf} yields, and TypeScript reports the opaque `Type '\"x\"' is not\n * assignable to type 'never'`; the literal turns that into a sentence naming the fix (and the\n * editor offers it as the single completion, so the empty completion list is explained rather\n * than just empty). Mirrors `NeonAuthRequiredHint` in `@neon/config`.\n */\n// Exported (type-only) for the type tests in `env.test-d.ts`; intentionally not re-exported\n// from `index.ts`, so it stays an internal implementation detail.\nexport type NoFunctionScopeHint =\n\t\"this policy declares no `functions`, so there is no function scope to read. Declare the function in `neon.ts` first, or omit the scope to read the branch env\";\n\n/**\n * The expected type of `parseEnv`'s function-slug `scope` argument: the caller's inferred slug\n * `S` normally, and the {@link NoFunctionScopeHint} message when the policy declares no\n * functions. Keeping `S` (rather than `FunctionSlugOf<C>`) in the enabled branch is what makes\n * the returned `function` namespace exact — it stays the one function's env keys instead of\n * widening to every declared function's.\n */\ntype FunctionScopeField<C extends Config, S extends string> = [\n\tFunctionSlugOf<C>,\n] extends [never]\n\t? NoFunctionScopeHint\n\t: S;\n\n/** The declared env-var keys of one function `S`, as a string union. */\ntype FunctionEnvKeysOf<\n\tC extends Config,\n\tS extends string,\n> = S extends keyof PreviewFunctionsOf<C>\n\t? NonNullable<PreviewFunctionsOf<C>[S]> extends { env: infer E }\n\t\t? Extract<keyof E, string>\n\t\t: never\n\t: never;\n\n/**\n * The extra `function` namespace added to `parseEnv`'s result when called with a function\n * slug scope: the declared env-var keys for that function, each resolved to a `string`.\n */\n/**\n * What `parseEnv` returns without a key filter: {@link NeonEnv} with `functions` optional,\n * because the deployed Functions runtime does not inject `NEON_FUNCTION_<SLUG>_BASE_URL`.\n * Select the key (`parseEnv(config, [\"NEON_FUNCTION_HELLO_BASE_URL\"])`) to require it.\n */\nexport type ParsedNeonEnv<C extends Config> =\n\tNeonEnv<C> extends { functions: infer F }\n\t\t? Omit<NeonEnv<C>, \"functions\"> & { functions?: F }\n\t\t: NeonEnv<C>;\n\nexport type NeonFunctionEnv<C extends Config, S extends string> = {\n\tfunction: Record<FunctionEnvKeysOf<C, S>, string>;\n};\n\n// ───────────────────────── parseEnv ─────────────────────────\n\n/**\n * Per-namespace zod schemas. Each defines exactly the OS-level keys parsed from\n * `process.env` for its namespace. Keep in sync with {@link NEON_ENV_VAR_KEYS}.\n *\n * `z.string().url()` would be tighter than `min(1)` but Postgres URIs that include\n * URL-illegal characters in the password (rare but legal in Neon's connection-string\n * format) fail the WHATWG `URL` parse, so we settle for \"non-empty string\".\n */\nconst postgresEnvSchema = z.object({\n\tDATABASE_URL: z\n\t\t.string({ message: \"DATABASE_URL is missing\" })\n\t\t.min(1, \"DATABASE_URL must not be empty\"),\n\tDATABASE_URL_UNPOOLED: z\n\t\t.string({ message: \"DATABASE_URL_UNPOOLED is missing\" })\n\t\t.min(1, \"DATABASE_URL_UNPOOLED must not be empty\"),\n});\n\nconst authEnvSchema = z.object({\n\tNEON_AUTH_BASE_URL: z\n\t\t.string({ message: \"NEON_AUTH_BASE_URL is missing\" })\n\t\t.min(1, \"NEON_AUTH_BASE_URL must not be empty\"),\n\tNEON_AUTH_JWKS_URL: z\n\t\t.string({ message: \"NEON_AUTH_JWKS_URL is missing\" })\n\t\t.min(1, \"NEON_AUTH_JWKS_URL must not be empty\"),\n});\n\nconst dataApiEnvSchema = z.object({\n\tNEON_DATA_API_URL: z\n\t\t.string({ message: \"NEON_DATA_API_URL is missing\" })\n\t\t.min(1, \"NEON_DATA_API_URL must not be empty\"),\n});\n\nconst realtimeEnvSchema = z.object({\n\tNEON_REALTIME_URL: z\n\t\t.string({ message: \"NEON_REALTIME_URL is missing\" })\n\t\t.min(1, \"NEON_REALTIME_URL must not be empty\"),\n\tNEON_REALTIME_SECRET: z\n\t\t.string({ message: \"NEON_REALTIME_SECRET is missing\" })\n\t\t.min(1, \"NEON_REALTIME_SECRET must not be empty\"),\n});\n\nconst storageEnvSchema = z.object({\n\tAWS_ACCESS_KEY_ID: z\n\t\t.string({ message: \"AWS_ACCESS_KEY_ID is missing\" })\n\t\t.min(1, \"AWS_ACCESS_KEY_ID must not be empty\"),\n\tAWS_SECRET_ACCESS_KEY: z\n\t\t.string({ message: \"AWS_SECRET_ACCESS_KEY is missing\" })\n\t\t.min(1, \"AWS_SECRET_ACCESS_KEY must not be empty\"),\n\tAWS_ENDPOINT_URL_S3: z\n\t\t.string({ message: \"AWS_ENDPOINT_URL_S3 is missing\" })\n\t\t.min(1, \"AWS_ENDPOINT_URL_S3 must not be empty\"),\n\tAWS_REGION: z\n\t\t.string({ message: \"AWS_REGION is missing\" })\n\t\t.min(1, \"AWS_REGION must not be empty\"),\n});\n\nconst aiGatewayEnvSchema = z.object({\n\tNEON_AI_GATEWAY_TOKEN: z\n\t\t.string({ message: \"NEON_AI_GATEWAY_TOKEN is missing\" })\n\t\t.min(1, \"NEON_AI_GATEWAY_TOKEN must not be empty\"),\n\tNEON_AI_GATEWAY_BASE_URL: z\n\t\t.string({ message: \"NEON_AI_GATEWAY_BASE_URL is missing\" })\n\t\t.min(1, \"NEON_AI_GATEWAY_BASE_URL must not be empty\"),\n});\n\n/** Whether a **static** policy declares object storage (`buckets`). No network. */\nfunction configWantsStorage(config: Config): boolean {\n\treturn Object.keys(authoredBuckets(config) ?? {}).length > 0;\n}\n\n/** Whether a **static** policy enables the AI Gateway (`aiGateway`). No network. */\nfunction configWantsAiGateway(config: Config): boolean {\n\treturn isServiceEnabledInput(authoredAiGateway(config));\n}\n\n/** Static-toggle helper mirroring `config`'s `isServiceEnabled` for the env reader. */\nfunction isServiceEnabledInput(\n\ttoggle: ServiceToggleInput | undefined,\n): boolean {\n\tif (toggle === undefined) return false;\n\tif (typeof toggle === \"boolean\") return toggle;\n\treturn toggle.enabled !== false;\n}\n\n/**\n * Synchronous, network-free counterpart to {@link fetchEnv}. Reads `process.env`, validates\n * the required Neon env vars with zod, and returns the same {@link NeonEnv} shape — so the\n * rest of your app touches `env.postgres.databaseUrl` instead of stringly-typed\n * `process.env.DATABASE_URL` lookups.\n *\n * Designed for the **\"env-vars-already-injected\"** path:\n * - You wrapped your dev command with `neon-env run -- <cmd>` or `neon dev`.\n * - Your platform (Vercel, Fly, Railway, …) injected the vars via its own integration.\n * - You are **inside a deployed Neon Function**, whose env was uploaded at `config apply`.\n *\n * Unlike the old API, `parseEnv` does **not** take a branch name: the secret set is now\n * static (`config.auth` / `config.dataApi` / `config.preview.realtime`), so it reads those\n * directly without evaluating the per-branch closure.\n *\n * The second argument is a **scope** or a **key filter**:\n * - omitted — *external* scope (app bootstrap, build scripts, your dev machine). Returns the\n * full `{ postgres, auth?, dataApi?, … }` the policy enables.\n * - a **function slug** (a key of `config.functions`) — *function* scope: you are\n * running inside that function. Returns the same branch secrets **plus** a typed\n * `function` namespace with the function's declared env-var keys. The slug autocompletes\n * from the policy ({@link FunctionSlugOf}) and an undeclared one is a type error.\n * - an **array of OS-level env-var keys** (e.g. `[\"DATABASE_URL\", \"NEON_AUTH_BASE_URL\"]`) —\n * *filtered* mode: only those vars are required and returned, as a narrowed namespaced\n * shape. The keys autocomplete from the policy ({@link SelectableEnvKey}), so you can only\n * pick vars the policy actually enables. Use this when a process needs just a subset (a\n * Next.js app that reads `DATABASE_URL` but not `DATABASE_URL_UNPOOLED`, say) and you don't\n * want `parseEnv` to throw over vars you never use.\n *\n * Throws `PlatformError(EnvNotInjected)` listing every missing/invalid var when the env\n * isn't fully populated, with a fix hint pointing back at `neon dev` / `neon-env run`.\n *\n * ```ts\n * import config from \"../neon\";\n * import { parseEnv } from \"@neon/env\";\n *\n * // External (app / build):\n * const env = parseEnv(config);\n * const db = drizzle(neon(env.postgres.databaseUrl), { schema });\n *\n * // Inside the \"hello\" function:\n * const env = parseEnv(config, \"hello\");\n * env.function.resendApiKey; // typed from hello's declared env keys\n *\n * // Filtered: only enforce + return the pooled URL.\n * const { postgres } = parseEnv(config, [\"DATABASE_URL\"]);\n * postgres.databaseUrl; // string — `databaseUrlUnpooled` is absent\n * ```\n */\nexport function parseEnv<const C extends Config>(config: C): ParsedNeonEnv<C>;\n// Overload order is load-bearing for **editor autocomplete**, not for type checking: when the\n// argument is a half-typed string literal the call resolves against no signature, and the\n// editor takes its string-literal completions from the first candidate overload. With the\n// `keys` overload listed first, the expected type of `parseEnv(config, \"…\")` is read as\n// `readonly K[]` — an array has no literal completions, so typing a function slug offered\n// nothing. Keep the slug overload ahead of the array one: `env.completions.test.ts` asserts the\n// completions through the language service, and `env.test-d.ts` locks the order itself (the\n// last overload is observable as `Parameters<typeof parseEnv>`), so `tsc` fails on a reorder.\nexport function parseEnv<\n\tconst C extends Config,\n\tconst S extends FunctionSlugOf<C>,\n>(\n\tconfig: C,\n\tscope: FunctionScopeField<C, S>,\n): ParsedNeonEnv<C> & NeonFunctionEnv<C, S>;\nexport function parseEnv<\n\tconst C extends Config,\n\tconst K extends SelectableEnvKey<C>,\n>(config: C, keys: readonly K[]): FilteredNeonEnv<K>;\nexport function parseEnv(\n\tconfig: Config,\n\tscopeOrKeys?: string | readonly string[],\n): unknown {\n\tconst source = process.env;\n\tif (Array.isArray(scopeOrKeys)) {\n\t\treturn parseFilteredEnv(source, scopeOrKeys);\n\t}\n\t// `Array.isArray` doesn't narrow a `readonly string[]` out of the union, so re-derive the\n\t// function-slug scope from the remaining `string` shape explicitly.\n\tconst scope = typeof scopeOrKeys === \"string\" ? scopeOrKeys : undefined;\n\tconst issues: string[] = [];\n\tconst result: Record<string, unknown> = {};\n\n\tconst pg = postgresEnvSchema.safeParse({\n\t\tDATABASE_URL: source.DATABASE_URL,\n\t\tDATABASE_URL_UNPOOLED: source.DATABASE_URL_UNPOOLED,\n\t});\n\tif (pg.success) {\n\t\tresult.postgres = {\n\t\t\tdatabaseUrl: pg.data.DATABASE_URL,\n\t\t\tdatabaseUrlUnpooled: pg.data.DATABASE_URL_UNPOOLED,\n\t\t} satisfies NeonPostgresEnv;\n\t} else {\n\t\tfor (const issue of pg.error.issues) issues.push(issue.message);\n\t}\n\n\t// Branch identity is optional: the Functions runtime injects `NEON_BRANCH` on every\n\t// branch by default and `neon dev` / `neon-env run` / `env pull` emit it too, but older\n\t// runtimes and platform integrations may not, so a missing value is not an error — we\n\t// just omit the namespace rather than failing the whole parse.\n\tconst branchName = source[NEON_ENV_VAR_KEYS.branch.name];\n\tif (branchName !== undefined && branchName !== \"\") {\n\t\tresult.branch = { name: branchName } satisfies NeonBranchEnv;\n\t}\n\n\tif (isServiceEnabledInput(config.auth)) {\n\t\tconst auth = authEnvSchema.safeParse({\n\t\t\tNEON_AUTH_BASE_URL: source.NEON_AUTH_BASE_URL,\n\t\t\tNEON_AUTH_JWKS_URL: source.NEON_AUTH_JWKS_URL,\n\t\t});\n\t\tif (auth.success) {\n\t\t\tresult.auth = {\n\t\t\t\tbaseUrl: auth.data.NEON_AUTH_BASE_URL,\n\t\t\t\tjwksUrl: auth.data.NEON_AUTH_JWKS_URL,\n\t\t\t} satisfies NeonAuthEnv;\n\t\t} else {\n\t\t\tfor (const issue of auth.error.issues) issues.push(issue.message);\n\t\t}\n\t}\n\n\tif (isServiceEnabledInput(config.dataApi)) {\n\t\tconst dataApi = dataApiEnvSchema.safeParse({\n\t\t\tNEON_DATA_API_URL: source.NEON_DATA_API_URL,\n\t\t});\n\t\tif (dataApi.success) {\n\t\t\tresult.dataApi = {\n\t\t\t\turl: dataApi.data.NEON_DATA_API_URL,\n\t\t\t} satisfies NeonDataApiEnv;\n\t\t} else {\n\t\t\tfor (const issue of dataApi.error.issues)\n\t\t\t\tissues.push(issue.message);\n\t\t}\n\t}\n\n\tif (\n\t\tconfig.preview?.realtime !== undefined &&\n\t\tconfig.preview.realtime !== false\n\t) {\n\t\tconst realtime = realtimeEnvSchema.safeParse({\n\t\t\tNEON_REALTIME_URL: source.NEON_REALTIME_URL,\n\t\t\tNEON_REALTIME_SECRET: source.NEON_REALTIME_SECRET,\n\t\t});\n\t\tif (realtime.success) {\n\t\t\tresult.realtime = {\n\t\t\t\turl: realtime.data.NEON_REALTIME_URL,\n\t\t\t\tsecret: realtime.data.NEON_REALTIME_SECRET,\n\t\t\t} satisfies NeonRealtimeEnv;\n\t\t} else {\n\t\t\tfor (const issue of realtime.error.issues)\n\t\t\t\tissues.push(issue.message);\n\t\t}\n\t}\n\n\tif (configWantsStorage(config)) {\n\t\tconst storage = storageEnvSchema.safeParse({\n\t\t\tAWS_ACCESS_KEY_ID: source.AWS_ACCESS_KEY_ID,\n\t\t\tAWS_SECRET_ACCESS_KEY: source.AWS_SECRET_ACCESS_KEY,\n\t\t\tAWS_ENDPOINT_URL_S3: source.AWS_ENDPOINT_URL_S3,\n\t\t\tAWS_REGION: source.AWS_REGION,\n\t\t});\n\t\tif (storage.success) {\n\t\t\tresult.storage = {\n\t\t\t\taccessKeyId: storage.data.AWS_ACCESS_KEY_ID,\n\t\t\t\tsecretAccessKey: storage.data.AWS_SECRET_ACCESS_KEY,\n\t\t\t\tendpoint: storage.data.AWS_ENDPOINT_URL_S3,\n\t\t\t\tregion: storage.data.AWS_REGION,\n\t\t\t} satisfies NeonStorageEnv;\n\t\t} else {\n\t\t\tfor (const issue of storage.error.issues)\n\t\t\t\tissues.push(issue.message);\n\t\t}\n\t}\n\n\tif (configWantsAiGateway(config)) {\n\t\tconst aiGateway = aiGatewayEnvSchema.safeParse({\n\t\t\tNEON_AI_GATEWAY_TOKEN: source.NEON_AI_GATEWAY_TOKEN,\n\t\t\tNEON_AI_GATEWAY_BASE_URL: source.NEON_AI_GATEWAY_BASE_URL,\n\t\t});\n\t\tif (aiGateway.success) {\n\t\t\tresult.aiGateway = {\n\t\t\t\tapiKey: aiGateway.data.NEON_AI_GATEWAY_TOKEN,\n\t\t\t\tbaseUrl: aiGateway.data.NEON_AI_GATEWAY_BASE_URL,\n\t\t\t} satisfies NeonAiGatewayEnv;\n\t\t} else {\n\t\t\tfor (const issue of aiGateway.error.issues)\n\t\t\t\tissues.push(issue.message);\n\t\t}\n\t}\n\n\tconst declaredFunctionSlugs = Object.keys(\n\t\tauthoredFunctions(config) ?? {},\n\t).sort();\n\tif (declaredFunctionSlugs.length > 0) {\n\t\tconst functions: Record<string, NeonFunctionUrlEnv> = {};\n\t\tfor (const slug of declaredFunctionSlugs) {\n\t\t\tconst key = functionBaseUrlKey(slug);\n\t\t\t// The Functions runtime does not inject NEON_FUNCTION_<SLUG>_BASE_URL, so an\n\t\t\t// unset one leaves `functions` out instead of failing every deployed function.\n\t\t\tif (source[key] === undefined) continue;\n\t\t\tconst parsed = readFunctionBaseUrl(key, source[key]);\n\t\t\tif (parsed.ok) {\n\t\t\t\tfunctions[slug] = { baseUrl: parsed.value };\n\t\t\t} else {\n\t\t\t\tissues.push(parsed.issue);\n\t\t\t}\n\t\t}\n\t\tif (Object.keys(functions).length === declaredFunctionSlugs.length) {\n\t\t\tresult.functions = functions;\n\t\t}\n\t}\n\n\tif (scope !== undefined) {\n\t\tconst fn = authoredFunctions(config)?.[scope];\n\t\tif (!fn) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.EnvNotInjected,\n\t\t\t\t[\n\t\t\t\t\t`parseEnv: no function \"${scope}\" is declared in this policy's functions.`,\n\t\t\t\t\t\"Pass a declared function slug (or omit the scope to read external env).\",\n\t\t\t\t].join(\"\\n\"),\n\t\t\t\t{ details: { scope } },\n\t\t\t);\n\t\t}\n\t\tconst envOut: Record<string, string> = {};\n\t\tfor (const key of Object.keys(fn.env ?? {})) {\n\t\t\tconst value = source[key];\n\t\t\t// Only a truly *unset* var is \"not injected\". Function env values carry no\n\t\t\t// non-empty constraint (unlike DATABASE_URL / NEON_AUTH_BASE_URL), so a\n\t\t\t// deliberately empty value is a present, valid value and is passed through.\n\t\t\tif (value === undefined) {\n\t\t\t\tissues.push(`${key} is missing (function \"${scope}\")`);\n\t\t\t} else {\n\t\t\t\tenvOut[key] = value;\n\t\t\t}\n\t\t}\n\t\tresult.function = envOut;\n\t}\n\n\tif (issues.length > 0) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.EnvNotInjected,\n\t\t\t[\n\t\t\t\t\"parseEnv: the required Neon env variables are not present in process.env.\",\n\t\t\t\t...issues.map((i) => ` - ${i}`),\n\t\t\t\t...parseEnvInjectHint(issues),\n\t\t\t\t\"Or switch the call to `await fetchEnv(config, …)` if you're in a context that can do async I/O.\",\n\t\t\t].join(\"\\n\"),\n\t\t\t{ details: { missing: issues } },\n\t\t);\n\t}\n\n\treturn result;\n}\n\nfunction isFunctionBaseUrlIssue(issue: string): boolean {\n\treturn /^NEON_FUNCTION_[A-Z0-9]+_BASE_URL (is missing|must not be empty|must be a URL)$/.test(\n\t\tissue,\n\t);\n}\n\nfunction readFunctionBaseUrl(\n\tkey: string,\n\tvalue: string | undefined,\n): { ok: true; value: string } | { ok: false; issue: string } {\n\tif (value === undefined) {\n\t\treturn { ok: false, issue: `${key} is missing` };\n\t}\n\tif (value === \"\") {\n\t\treturn { ok: false, issue: `${key} must not be empty` };\n\t}\n\ttry {\n\t\tnew URL(value);\n\t} catch {\n\t\treturn { ok: false, issue: `${key} must be a URL` };\n\t}\n\treturn { ok: true, value };\n}\n\nfunction parseEnvInjectHint(issues: readonly string[]): string[] {\n\tif (issues.length > 0 && issues.every(isFunctionBaseUrlIssue)) {\n\t\treturn [\n\t\t\t\"Inject them via `neon env pull` or `neon-env run` (production URL), or `neon dev` (`http://localhost:<port>`).\",\n\t\t];\n\t}\n\tconst lines = [\n\t\t\"Inject them via one of:\",\n\t\t\" - `neon dev` / `neon-env run -- <your dev command>` (wraps the command with the vars injected)\",\n\t\t\" - your hosting platform's Neon integration (Vercel, Fly, Railway, …)\",\n\t];\n\tif (issues.some((issue) => issue.includes('(function \"'))) {\n\t\tlines.push(\n\t\t\t\" - for the `function` namespace: deploy the function (`neon deploy` / `config apply`) so its env is uploaded.\",\n\t\t);\n\t}\n\tif (issues.some(isFunctionBaseUrlIssue)) {\n\t\tlines.push(\n\t\t\t\" - for NEON_FUNCTION_*_BASE_URL: `neon env pull` or `neon dev`.\",\n\t\t);\n\t}\n\treturn lines;\n}\n\n/**\n * Runtime reverse map for filtered `parseEnv`: OS-level env-var key → `[namespace, property]`\n * in the {@link NeonEnv} shape. The compile-time mirror is {@link EnvKeysByNamespace} /\n * {@link EnvKeyToProp}; keep all three in sync. Only input vars appear (no output-only\n * aliases).\n */\nconst FILTERABLE_ENV_KEYS: Record<string, readonly [string, string]> = {\n\tDATABASE_URL: [\"postgres\", \"databaseUrl\"],\n\tDATABASE_URL_UNPOOLED: [\"postgres\", \"databaseUrlUnpooled\"],\n\tNEON_BRANCH: [\"branch\", \"name\"],\n\tNEON_AUTH_BASE_URL: [\"auth\", \"baseUrl\"],\n\tNEON_AUTH_JWKS_URL: [\"auth\", \"jwksUrl\"],\n\tNEON_DATA_API_URL: [\"dataApi\", \"url\"],\n\tNEON_REALTIME_URL: [\"realtime\", \"url\"],\n\tNEON_REALTIME_SECRET: [\"realtime\", \"secret\"],\n\tAWS_ACCESS_KEY_ID: [\"storage\", \"accessKeyId\"],\n\tAWS_SECRET_ACCESS_KEY: [\"storage\", \"secretAccessKey\"],\n\tAWS_ENDPOINT_URL_S3: [\"storage\", \"endpoint\"],\n\tAWS_REGION: [\"storage\", \"region\"],\n\tNEON_AI_GATEWAY_TOKEN: [\"aiGateway\", \"apiKey\"],\n\tNEON_AI_GATEWAY_BASE_URL: [\"aiGateway\", \"baseUrl\"],\n};\n\n/**\n * Filtered counterpart to the {@link parseEnv} body: validate and return only the explicitly\n * selected OS-level env-var keys, projected back into the narrowed namespaced shape. Unlike\n * the full reader it never consults the policy — the selection alone decides what's required —\n * so vars the caller didn't ask for (e.g. `DATABASE_URL_UNPOOLED`) can be absent without\n * throwing. Mirrors the same non-empty constraint and {@link PlatformError} aggregation.\n */\nfunction parseFilteredEnv(\n\tsource: NodeJS.ProcessEnv,\n\tkeys: readonly string[],\n): Record<string, unknown> {\n\tconst issues: string[] = [];\n\tconst result: Record<string, Record<string, unknown>> = {};\n\tconst functionUrls: Record<string, NeonFunctionUrlEnv> = {};\n\tfor (const key of keys) {\n\t\tif (isFunctionBaseUrlKey(key)) {\n\t\t\tconst slug = parseFunctionBaseUrlKey(key);\n\t\t\tif (slug === null) continue;\n\t\t\tconst parsed = readFunctionBaseUrl(key, source[key]);\n\t\t\tif (!parsed.ok) {\n\t\t\t\tissues.push(parsed.issue);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfunctionUrls[slug] = { baseUrl: parsed.value };\n\t\t\tcontinue;\n\t\t}\n\t\t// Unknown keys are blocked at the type level; a runtime caller bypassing the types\n\t\t// gets a clear error rather than a silently-dropped selection.\n\t\tif (!Object.hasOwn(FILTERABLE_ENV_KEYS, key)) {\n\t\t\tissues.push(`${key} is not a selectable Neon env variable`);\n\t\t\tcontinue;\n\t\t}\n\t\tconst value = source[key];\n\t\tif (value === undefined) {\n\t\t\tissues.push(`${key} is missing`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (value === \"\") {\n\t\t\tissues.push(`${key} must not be empty`);\n\t\t\tcontinue;\n\t\t}\n\t\tconst [namespace, property] = FILTERABLE_ENV_KEYS[key];\n\t\tconst bucket = result[namespace] ?? {};\n\t\tbucket[property] = value;\n\t\tresult[namespace] = bucket;\n\t}\n\tif (Object.keys(functionUrls).length > 0) {\n\t\tresult.functions = functionUrls;\n\t}\n\tif (issues.length > 0) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.EnvNotInjected,\n\t\t\t[\n\t\t\t\t\"parseEnv: the required Neon env variables are not present in process.env.\",\n\t\t\t\t...issues.map((i) => ` - ${i}`),\n\t\t\t\t...parseEnvInjectHint(issues),\n\t\t\t\t\"Or switch the call to `await fetchEnv(config, …)` if you're in a context that can do async I/O.\",\n\t\t\t].join(\"\\n\"),\n\t\t\t{ details: { missing: issues } },\n\t\t);\n\t}\n\treturn result;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/lib/function-base-url.ts","../src/lib/parse-env.ts"],"sourcesContent":["/**\n * `functionBaseUrl` — the URL another Neon Function on the same branch answers at, built from\n * the variables the Functions runtime injects into every function, so a deployed function needs\n * no extra env. `neon env pull` writes the same variables locally and `neon dev` adds the\n * localhost port of each function it serves.\n */\n\nimport { ErrorCode, PlatformError } from \"@neon/config/v1\";\nimport {\n\tNEON_DEV_FUNCTION_PORTS,\n\tNEON_ENV_VAR_KEYS,\n} from \"@neon-internals/env-core/env\";\n\n/** The variables {@link functionBaseUrl} reads. `process.env` satisfies it. */\nexport type FunctionBaseUrlEnv = Readonly<Record<string, string | undefined>>;\n\nconst SLUG = /^[a-z0-9]{1,20}$/;\nconst DNS_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;\n\n/**\n * The base URL of function `slug` on the current branch, without a trailing slash:\n * `https://<NEON_BRANCH_ID>-<slug><NEON_FUNCTION_HOST_SUFFIX>`, or `http://localhost:<port>`\n * when `neon dev` serves that function.\n *\n * @example\n * ```ts\n * import { functionBaseUrl } from \"@neon/env\";\n *\n * const res = await fetch(`${functionBaseUrl(\"hello\")}/greet`);\n * ```\n *\n * @throws {TypeError} when `slug` is not a valid function slug (`[a-z0-9]{1,20}`).\n * @throws {PlatformError} `PLATFORM_ENV_NOT_INJECTED` when the variables are missing or do\n * not form a valid hostname.\n */\nexport function functionBaseUrl(\n\tslug: string,\n\tenv: FunctionBaseUrlEnv = process.env,\n): string {\n\tif (!SLUG.test(slug)) {\n\t\tthrow new TypeError(\n\t\t\t`functionBaseUrl: ${JSON.stringify(slug)} is not a function slug (1-20 lowercase letters and digits).`,\n\t\t);\n\t}\n\n\tconst port = devFunctionPort(slug, env[NEON_DEV_FUNCTION_PORTS]);\n\tif (port !== undefined) return `http://localhost:${port}`;\n\n\tconst K = NEON_ENV_VAR_KEYS.branch;\n\tconst branchId = env[K.id];\n\tconst suffix = env[K.functionHostSuffix];\n\tconst missing = [\n\t\t...(branchId ? [] : [K.id]),\n\t\t...(suffix ? [] : [K.functionHostSuffix]),\n\t];\n\tif (!branchId || !suffix) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.EnvNotInjected,\n\t\t\t[\n\t\t\t\t`functionBaseUrl: ${missing.join(\" and \")} ${missing.length > 1 ? \"are\" : \"is\"} not set.`,\n\t\t\t\t\"Deployed Neon Functions have them. Locally, run `neon env pull` or `neon dev`.\",\n\t\t\t].join(\"\\n\"),\n\t\t\t{ details: { missing } },\n\t\t);\n\t}\n\n\t// Validated whole, so a malformed value cannot move the request to another authority\n\t// (`@`, `/`, `:` in either part) or produce a hostname DNS rejects.\n\tconst label = `${branchId}-${slug}`;\n\tconst hostname = `${label}${suffix}`;\n\tconst suffixLabels = suffix.startsWith(\".\")\n\t\t? suffix.slice(1).split(\".\")\n\t\t: [];\n\tif (\n\t\t!DNS_LABEL.test(label) ||\n\t\tsuffixLabels.length === 0 ||\n\t\t!suffixLabels.every((part) => DNS_LABEL.test(part)) ||\n\t\thostname.length > 253\n\t) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.EnvNotInjected,\n\t\t\t`functionBaseUrl: ${K.id}=${JSON.stringify(branchId)} and ${K.functionHostSuffix}=${JSON.stringify(suffix)} do not form a function hostname. Re-run \\`neon env pull\\`.`,\n\t\t\t{ details: { branchId, functionHostSuffix: suffix } },\n\t\t);\n\t}\n\treturn `https://${hostname}`;\n}\n\nfunction devFunctionPort(\n\tslug: string,\n\traw: string | undefined,\n): number | undefined {\n\tif (raw === undefined) return undefined;\n\tlet ports: unknown;\n\ttry {\n\t\tports = JSON.parse(raw);\n\t} catch {\n\t\tthrow invalidDevPorts(raw);\n\t}\n\tif (typeof ports !== \"object\" || ports === null || Array.isArray(ports)) {\n\t\tthrow invalidDevPorts(raw);\n\t}\n\tif (!Object.hasOwn(ports, slug)) return undefined;\n\tconst port: unknown = Reflect.get(ports, slug);\n\tif (\n\t\ttypeof port !== \"number\" ||\n\t\t!Number.isInteger(port) ||\n\t\tport < 1 ||\n\t\tport > 65535\n\t) {\n\t\tthrow invalidDevPorts(raw);\n\t}\n\treturn port;\n}\n\nfunction invalidDevPorts(raw: string): PlatformError {\n\treturn new PlatformError(\n\t\tErrorCode.EnvNotInjected,\n\t\t`functionBaseUrl: ${NEON_DEV_FUNCTION_PORTS}=${JSON.stringify(raw)} is not a JSON object of function ports. \\`neon dev\\` sets it; restart \\`neon dev\\`.`,\n\t\t{ details: { [NEON_DEV_FUNCTION_PORTS]: raw } },\n\t);\n}\n","/**\n * `parseEnv` — the synchronous, network-free counterpart to `fetchEnv`: read the Neon env vars\n * already injected into `process.env`, validate them against the policy, and return them in the\n * same namespaced shape.\n *\n * Lives in this package rather than in `@neon-internals/env-core` because nothing else needs\n * it. The `neon` CLI resolves env from the API and injects it; it never reads it back. Keeping\n * it here also keeps `zod` out of that package, and so out of every consumer that bundles it.\n */\n\nimport {\n\tauthoredAiGateway,\n\tauthoredBuckets,\n\tauthoredFunctions,\n\ttype Config,\n\tErrorCode,\n\tPlatformError,\n\ttype ServiceToggleInput,\n} from \"@neon/config/v1\";\nimport {\n\ttype FilteredNeonEnv,\n\tNEON_ENV_VAR_KEYS,\n\ttype NeonAiGatewayEnv,\n\ttype NeonAuthEnv,\n\ttype NeonBranchEnv,\n\ttype NeonDataApiEnv,\n\ttype NeonEnv,\n\ttype NeonPostgresEnv,\n\ttype NeonRealtimeEnv,\n\ttype NeonStorageEnv,\n\ttype SelectableEnvKey,\n} from \"@neon-internals/env-core/env\";\nimport { z } from \"zod\";\n\n/** The static `functions` record of a config (GA or deprecated `preview.functions`). */\ntype GaFunctionsOf<C extends Config> = [NonNullable<C[\"functions\"]>] extends [\n\tnever,\n]\n\t? Record<never, never>\n\t: string extends keyof NonNullable<C[\"functions\"]>\n\t\t? Record<never, never>\n\t\t: NonNullable<C[\"functions\"]>;\n\ntype PreviewFunctionsHome<C extends Config> = [\n\tNonNullable<C[\"preview\"]>,\n] extends [never]\n\t? Record<never, never>\n\t: NonNullable<C[\"preview\"]> extends { functions: infer F }\n\t\t? F\n\t\t: Record<never, never>;\n\ntype PreviewFunctionsOf<C extends Config> = [keyof GaFunctionsOf<C>] extends [\n\tnever,\n]\n\t? PreviewFunctionsHome<C>\n\t: [keyof PreviewFunctionsHome<C>] extends [never]\n\t\t? GaFunctionsOf<C>\n\t\t: GaFunctionsOf<C> & PreviewFunctionsHome<C>;\n\n/** The declared function slugs of a config (record keys), as a string union. */\nexport type FunctionSlugOf<C extends Config> = Extract<\n\tkeyof PreviewFunctionsOf<C>,\n\tstring\n>;\n\n/**\n * Human-readable hint surfaced as the **expected type** of `parseEnv`'s `scope` argument when\n * the policy declares no functions at all. Without it the argument's expected type is the bare\n * `never` {@link FunctionSlugOf} yields, and TypeScript reports the opaque `Type '\"x\"' is not\n * assignable to type 'never'`; the literal turns that into a sentence naming the fix (and the\n * editor offers it as the single completion, so the empty completion list is explained rather\n * than just empty). Mirrors `NeonAuthRequiredHint` in `@neon/config`.\n */\n// Exported (type-only) for the type tests in `env.test-d.ts`; intentionally not re-exported\n// from `index.ts`, so it stays an internal implementation detail.\nexport type NoFunctionScopeHint =\n\t\"this policy declares no `functions`, so there is no function scope to read. Declare the function in `neon.ts` first, or omit the scope to read the branch env\";\n\n/**\n * The expected type of `parseEnv`'s function-slug `scope` argument: the caller's inferred slug\n * `S` normally, and the {@link NoFunctionScopeHint} message when the policy declares no\n * functions. Keeping `S` (rather than `FunctionSlugOf<C>`) in the enabled branch is what makes\n * the returned `function` namespace exact — it stays the one function's env keys instead of\n * widening to every declared function's.\n */\ntype FunctionScopeField<C extends Config, S extends string> = [\n\tFunctionSlugOf<C>,\n] extends [never]\n\t? NoFunctionScopeHint\n\t: S;\n\n/** The declared env-var keys of one function `S`, as a string union. */\ntype FunctionEnvKeysOf<\n\tC extends Config,\n\tS extends string,\n> = S extends keyof PreviewFunctionsOf<C>\n\t? NonNullable<PreviewFunctionsOf<C>[S]> extends { env: infer E }\n\t\t? Extract<keyof E, string>\n\t\t: never\n\t: never;\n\n/**\n * The extra `function` namespace added to `parseEnv`'s result when called with a function\n * slug scope: the declared env-var keys for that function, each resolved to a `string`.\n */\nexport type NeonFunctionEnv<C extends Config, S extends string> = {\n\tfunction: Record<FunctionEnvKeysOf<C, S>, string>;\n};\n\n// ───────────────────────── parseEnv ─────────────────────────\n\n/**\n * Per-namespace zod schemas. Each defines exactly the OS-level keys parsed from\n * `process.env` for its namespace. Keep in sync with {@link NEON_ENV_VAR_KEYS}.\n *\n * `z.string().url()` would be tighter than `min(1)` but Postgres URIs that include\n * URL-illegal characters in the password (rare but legal in Neon's connection-string\n * format) fail the WHATWG `URL` parse, so we settle for \"non-empty string\".\n */\nconst postgresEnvSchema = z.object({\n\tDATABASE_URL: z\n\t\t.string({ message: \"DATABASE_URL is missing\" })\n\t\t.min(1, \"DATABASE_URL must not be empty\"),\n\tDATABASE_URL_UNPOOLED: z\n\t\t.string({ message: \"DATABASE_URL_UNPOOLED is missing\" })\n\t\t.min(1, \"DATABASE_URL_UNPOOLED must not be empty\"),\n});\n\nconst authEnvSchema = z.object({\n\tNEON_AUTH_BASE_URL: z\n\t\t.string({ message: \"NEON_AUTH_BASE_URL is missing\" })\n\t\t.min(1, \"NEON_AUTH_BASE_URL must not be empty\"),\n\tNEON_AUTH_JWKS_URL: z\n\t\t.string({ message: \"NEON_AUTH_JWKS_URL is missing\" })\n\t\t.min(1, \"NEON_AUTH_JWKS_URL must not be empty\"),\n});\n\nconst dataApiEnvSchema = z.object({\n\tNEON_DATA_API_URL: z\n\t\t.string({ message: \"NEON_DATA_API_URL is missing\" })\n\t\t.min(1, \"NEON_DATA_API_URL must not be empty\"),\n});\n\nconst realtimeEnvSchema = z.object({\n\tNEON_REALTIME_URL: z\n\t\t.string({ message: \"NEON_REALTIME_URL is missing\" })\n\t\t.min(1, \"NEON_REALTIME_URL must not be empty\"),\n\tNEON_REALTIME_SECRET: z\n\t\t.string({ message: \"NEON_REALTIME_SECRET is missing\" })\n\t\t.min(1, \"NEON_REALTIME_SECRET must not be empty\"),\n});\n\nconst storageEnvSchema = z.object({\n\tAWS_ACCESS_KEY_ID: z\n\t\t.string({ message: \"AWS_ACCESS_KEY_ID is missing\" })\n\t\t.min(1, \"AWS_ACCESS_KEY_ID must not be empty\"),\n\tAWS_SECRET_ACCESS_KEY: z\n\t\t.string({ message: \"AWS_SECRET_ACCESS_KEY is missing\" })\n\t\t.min(1, \"AWS_SECRET_ACCESS_KEY must not be empty\"),\n\tAWS_ENDPOINT_URL_S3: z\n\t\t.string({ message: \"AWS_ENDPOINT_URL_S3 is missing\" })\n\t\t.min(1, \"AWS_ENDPOINT_URL_S3 must not be empty\"),\n\tAWS_REGION: z\n\t\t.string({ message: \"AWS_REGION is missing\" })\n\t\t.min(1, \"AWS_REGION must not be empty\"),\n});\n\nconst aiGatewayEnvSchema = z.object({\n\tNEON_AI_GATEWAY_TOKEN: z\n\t\t.string({ message: \"NEON_AI_GATEWAY_TOKEN is missing\" })\n\t\t.min(1, \"NEON_AI_GATEWAY_TOKEN must not be empty\"),\n\tNEON_AI_GATEWAY_BASE_URL: z\n\t\t.string({ message: \"NEON_AI_GATEWAY_BASE_URL is missing\" })\n\t\t.min(1, \"NEON_AI_GATEWAY_BASE_URL must not be empty\"),\n});\n\n/** Whether a **static** policy declares object storage (`buckets`). No network. */\nfunction configWantsStorage(config: Config): boolean {\n\treturn Object.keys(authoredBuckets(config) ?? {}).length > 0;\n}\n\n/** Whether a **static** policy enables the AI Gateway (`aiGateway`). No network. */\nfunction configWantsAiGateway(config: Config): boolean {\n\treturn isServiceEnabledInput(authoredAiGateway(config));\n}\n\n/** Static-toggle helper mirroring `config`'s `isServiceEnabled` for the env reader. */\nfunction isServiceEnabledInput(\n\ttoggle: ServiceToggleInput | undefined,\n): boolean {\n\tif (toggle === undefined) return false;\n\tif (typeof toggle === \"boolean\") return toggle;\n\treturn toggle.enabled !== false;\n}\n\n/**\n * Synchronous, network-free counterpart to {@link fetchEnv}. Reads `process.env`, validates\n * the required Neon env vars with zod, and returns the same {@link NeonEnv} shape — so the\n * rest of your app touches `env.postgres.databaseUrl` instead of stringly-typed\n * `process.env.DATABASE_URL` lookups.\n *\n * Designed for the **\"env-vars-already-injected\"** path:\n * - You wrapped your dev command with `neon-env run -- <cmd>` or `neon dev`.\n * - Your platform (Vercel, Fly, Railway, …) injected the vars via its own integration.\n * - You are **inside a deployed Neon Function**, whose env was uploaded at `config apply`.\n *\n * Unlike the old API, `parseEnv` does **not** take a branch name: the secret set is now\n * static (`config.auth` / `config.dataApi` / `config.preview.realtime`), so it reads those\n * directly without evaluating the per-branch closure.\n *\n * The second argument is a **scope** or a **key filter**:\n * - omitted — *external* scope (app bootstrap, build scripts, your dev machine). Returns the\n * full `{ postgres, auth?, dataApi?, … }` the policy enables.\n * - a **function slug** (a key of `config.functions`) — *function* scope: you are\n * running inside that function. Returns the same branch secrets **plus** a typed\n * `function` namespace with the function's declared env-var keys. The slug autocompletes\n * from the policy ({@link FunctionSlugOf}) and an undeclared one is a type error.\n * - an **array of OS-level env-var keys** (e.g. `[\"DATABASE_URL\", \"NEON_AUTH_BASE_URL\"]`) —\n * *filtered* mode: only those vars are required and returned, as a narrowed namespaced\n * shape. The keys autocomplete from the policy ({@link SelectableEnvKey}), so you can only\n * pick vars the policy actually enables. Use this when a process needs just a subset (a\n * Next.js app that reads `DATABASE_URL` but not `DATABASE_URL_UNPOOLED`, say) and you don't\n * want `parseEnv` to throw over vars you never use.\n *\n * Throws `PlatformError(EnvNotInjected)` listing every missing/invalid var when the env\n * isn't fully populated, with a fix hint pointing back at `neon dev` / `neon-env run`.\n *\n * ```ts\n * import config from \"../neon\";\n * import { parseEnv } from \"@neon/env\";\n *\n * // External (app / build):\n * const env = parseEnv(config);\n * const db = drizzle(neon(env.postgres.databaseUrl), { schema });\n *\n * // Inside the \"hello\" function:\n * const env = parseEnv(config, \"hello\");\n * env.function.resendApiKey; // typed from hello's declared env keys\n *\n * // Filtered: only enforce + return the pooled URL.\n * const { postgres } = parseEnv(config, [\"DATABASE_URL\"]);\n * postgres.databaseUrl; // string — `databaseUrlUnpooled` is absent\n * ```\n */\nexport function parseEnv<const C extends Config>(config: C): NeonEnv<C>;\n// Overload order is load-bearing for **editor autocomplete**, not for type checking: when the\n// argument is a half-typed string literal the call resolves against no signature, and the\n// editor takes its string-literal completions from the first candidate overload. With the\n// `keys` overload listed first, the expected type of `parseEnv(config, \"…\")` is read as\n// `readonly K[]` — an array has no literal completions, so typing a function slug offered\n// nothing. Keep the slug overload ahead of the array one: `env.completions.test.ts` asserts the\n// completions through the language service, and `env.test-d.ts` locks the order itself (the\n// last overload is observable as `Parameters<typeof parseEnv>`), so `tsc` fails on a reorder.\nexport function parseEnv<\n\tconst C extends Config,\n\tconst S extends FunctionSlugOf<C>,\n>(\n\tconfig: C,\n\tscope: FunctionScopeField<C, S>,\n): NeonEnv<C> & NeonFunctionEnv<C, S>;\nexport function parseEnv<\n\tconst C extends Config,\n\tconst K extends SelectableEnvKey<C>,\n>(config: C, keys: readonly K[]): FilteredNeonEnv<K>;\nexport function parseEnv(\n\tconfig: Config,\n\tscopeOrKeys?: string | readonly string[],\n): unknown {\n\tconst source = process.env;\n\tif (Array.isArray(scopeOrKeys)) {\n\t\treturn parseFilteredEnv(source, scopeOrKeys);\n\t}\n\t// `Array.isArray` doesn't narrow a `readonly string[]` out of the union, so re-derive the\n\t// function-slug scope from the remaining `string` shape explicitly.\n\tconst scope = typeof scopeOrKeys === \"string\" ? scopeOrKeys : undefined;\n\tconst issues: string[] = [];\n\tconst result: Record<string, unknown> = {};\n\n\tconst pg = postgresEnvSchema.safeParse({\n\t\tDATABASE_URL: source.DATABASE_URL,\n\t\tDATABASE_URL_UNPOOLED: source.DATABASE_URL_UNPOOLED,\n\t});\n\tif (pg.success) {\n\t\tresult.postgres = {\n\t\t\tdatabaseUrl: pg.data.DATABASE_URL,\n\t\t\tdatabaseUrlUnpooled: pg.data.DATABASE_URL_UNPOOLED,\n\t\t} satisfies NeonPostgresEnv;\n\t} else {\n\t\tfor (const issue of pg.error.issues) issues.push(issue.message);\n\t}\n\n\t// Branch identity is optional: the Functions runtime injects `NEON_BRANCH` on every\n\t// branch by default and `neon dev` / `neon-env run` / `env pull` emit it too, but older\n\t// runtimes and platform integrations may not, so a missing value is not an error — we\n\t// just omit the namespace rather than failing the whole parse.\n\tconst branchName = source[NEON_ENV_VAR_KEYS.branch.name];\n\tif (branchName !== undefined && branchName !== \"\") {\n\t\tconst branch: NeonBranchEnv = { name: branchName };\n\t\tconst branchId = source[NEON_ENV_VAR_KEYS.branch.id];\n\t\tif (branchId) branch.id = branchId;\n\t\tconst hostSuffix = source[NEON_ENV_VAR_KEYS.branch.functionHostSuffix];\n\t\tif (hostSuffix) branch.functionHostSuffix = hostSuffix;\n\t\tresult.branch = branch;\n\t}\n\n\tif (isServiceEnabledInput(config.auth)) {\n\t\tconst auth = authEnvSchema.safeParse({\n\t\t\tNEON_AUTH_BASE_URL: source.NEON_AUTH_BASE_URL,\n\t\t\tNEON_AUTH_JWKS_URL: source.NEON_AUTH_JWKS_URL,\n\t\t});\n\t\tif (auth.success) {\n\t\t\tresult.auth = {\n\t\t\t\tbaseUrl: auth.data.NEON_AUTH_BASE_URL,\n\t\t\t\tjwksUrl: auth.data.NEON_AUTH_JWKS_URL,\n\t\t\t} satisfies NeonAuthEnv;\n\t\t} else {\n\t\t\tfor (const issue of auth.error.issues) issues.push(issue.message);\n\t\t}\n\t}\n\n\tif (isServiceEnabledInput(config.dataApi)) {\n\t\tconst dataApi = dataApiEnvSchema.safeParse({\n\t\t\tNEON_DATA_API_URL: source.NEON_DATA_API_URL,\n\t\t});\n\t\tif (dataApi.success) {\n\t\t\tresult.dataApi = {\n\t\t\t\turl: dataApi.data.NEON_DATA_API_URL,\n\t\t\t} satisfies NeonDataApiEnv;\n\t\t} else {\n\t\t\tfor (const issue of dataApi.error.issues)\n\t\t\t\tissues.push(issue.message);\n\t\t}\n\t}\n\n\tif (\n\t\tconfig.preview?.realtime !== undefined &&\n\t\tconfig.preview.realtime !== false\n\t) {\n\t\tconst realtime = realtimeEnvSchema.safeParse({\n\t\t\tNEON_REALTIME_URL: source.NEON_REALTIME_URL,\n\t\t\tNEON_REALTIME_SECRET: source.NEON_REALTIME_SECRET,\n\t\t});\n\t\tif (realtime.success) {\n\t\t\tresult.realtime = {\n\t\t\t\turl: realtime.data.NEON_REALTIME_URL,\n\t\t\t\tsecret: realtime.data.NEON_REALTIME_SECRET,\n\t\t\t} satisfies NeonRealtimeEnv;\n\t\t} else {\n\t\t\tfor (const issue of realtime.error.issues)\n\t\t\t\tissues.push(issue.message);\n\t\t}\n\t}\n\n\tif (configWantsStorage(config)) {\n\t\tconst storage = storageEnvSchema.safeParse({\n\t\t\tAWS_ACCESS_KEY_ID: source.AWS_ACCESS_KEY_ID,\n\t\t\tAWS_SECRET_ACCESS_KEY: source.AWS_SECRET_ACCESS_KEY,\n\t\t\tAWS_ENDPOINT_URL_S3: source.AWS_ENDPOINT_URL_S3,\n\t\t\tAWS_REGION: source.AWS_REGION,\n\t\t});\n\t\tif (storage.success) {\n\t\t\tresult.storage = {\n\t\t\t\taccessKeyId: storage.data.AWS_ACCESS_KEY_ID,\n\t\t\t\tsecretAccessKey: storage.data.AWS_SECRET_ACCESS_KEY,\n\t\t\t\tendpoint: storage.data.AWS_ENDPOINT_URL_S3,\n\t\t\t\tregion: storage.data.AWS_REGION,\n\t\t\t} satisfies NeonStorageEnv;\n\t\t} else {\n\t\t\tfor (const issue of storage.error.issues)\n\t\t\t\tissues.push(issue.message);\n\t\t}\n\t}\n\n\tif (configWantsAiGateway(config)) {\n\t\tconst aiGateway = aiGatewayEnvSchema.safeParse({\n\t\t\tNEON_AI_GATEWAY_TOKEN: source.NEON_AI_GATEWAY_TOKEN,\n\t\t\tNEON_AI_GATEWAY_BASE_URL: source.NEON_AI_GATEWAY_BASE_URL,\n\t\t});\n\t\tif (aiGateway.success) {\n\t\t\tresult.aiGateway = {\n\t\t\t\tapiKey: aiGateway.data.NEON_AI_GATEWAY_TOKEN,\n\t\t\t\tbaseUrl: aiGateway.data.NEON_AI_GATEWAY_BASE_URL,\n\t\t\t} satisfies NeonAiGatewayEnv;\n\t\t} else {\n\t\t\tfor (const issue of aiGateway.error.issues)\n\t\t\t\tissues.push(issue.message);\n\t\t}\n\t}\n\n\tif (scope !== undefined) {\n\t\tconst fn = authoredFunctions(config)?.[scope];\n\t\tif (!fn) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.EnvNotInjected,\n\t\t\t\t[\n\t\t\t\t\t`parseEnv: no function \"${scope}\" is declared in this policy's functions.`,\n\t\t\t\t\t\"Pass a declared function slug (or omit the scope to read external env).\",\n\t\t\t\t].join(\"\\n\"),\n\t\t\t\t{ details: { scope } },\n\t\t\t);\n\t\t}\n\t\tconst envOut: Record<string, string> = {};\n\t\tfor (const key of Object.keys(fn.env ?? {})) {\n\t\t\tconst value = source[key];\n\t\t\t// Only a truly *unset* var is \"not injected\". Function env values carry no\n\t\t\t// non-empty constraint (unlike DATABASE_URL / NEON_AUTH_BASE_URL), so a\n\t\t\t// deliberately empty value is a present, valid value and is passed through.\n\t\t\tif (value === undefined) {\n\t\t\t\tissues.push(`${key} is missing (function \"${scope}\")`);\n\t\t\t} else {\n\t\t\t\tenvOut[key] = value;\n\t\t\t}\n\t\t}\n\t\tresult.function = envOut;\n\t}\n\n\tif (issues.length > 0) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.EnvNotInjected,\n\t\t\t[\n\t\t\t\t\"parseEnv: the required Neon env variables are not present in process.env.\",\n\t\t\t\t...issues.map((i) => ` - ${i}`),\n\t\t\t\t...parseEnvInjectHint(issues),\n\t\t\t\t\"Or switch the call to `await fetchEnv(config, …)` if you're in a context that can do async I/O.\",\n\t\t\t].join(\"\\n\"),\n\t\t\t{ details: { missing: issues } },\n\t\t);\n\t}\n\n\treturn result;\n}\n\nfunction parseEnvInjectHint(issues: readonly string[]): string[] {\n\tconst lines = [\n\t\t\"Inject them via one of:\",\n\t\t\" - `neon dev` / `neon-env run -- <your dev command>` (wraps the command with the vars injected)\",\n\t\t\" - your hosting platform's Neon integration (Vercel, Fly, Railway, …)\",\n\t];\n\tif (issues.some((issue) => issue.includes('(function \"'))) {\n\t\tlines.push(\n\t\t\t\" - for the `function` namespace: deploy the function (`neon deploy` / `config apply`) so its env is uploaded.\",\n\t\t);\n\t}\n\treturn lines;\n}\n\n/**\n * Runtime reverse map for filtered `parseEnv`: OS-level env-var key → `[namespace, property]`\n * in the {@link NeonEnv} shape. The compile-time mirror is {@link EnvKeysByNamespace} /\n * {@link EnvKeyToProp}; keep all three in sync. Only input vars appear (no output-only\n * aliases).\n */\nconst FILTERABLE_ENV_KEYS: Record<string, readonly [string, string]> = {\n\tDATABASE_URL: [\"postgres\", \"databaseUrl\"],\n\tDATABASE_URL_UNPOOLED: [\"postgres\", \"databaseUrlUnpooled\"],\n\tNEON_BRANCH: [\"branch\", \"name\"],\n\tNEON_BRANCH_ID: [\"branch\", \"id\"],\n\tNEON_FUNCTION_HOST_SUFFIX: [\"branch\", \"functionHostSuffix\"],\n\tNEON_AUTH_BASE_URL: [\"auth\", \"baseUrl\"],\n\tNEON_AUTH_JWKS_URL: [\"auth\", \"jwksUrl\"],\n\tNEON_DATA_API_URL: [\"dataApi\", \"url\"],\n\tNEON_REALTIME_URL: [\"realtime\", \"url\"],\n\tNEON_REALTIME_SECRET: [\"realtime\", \"secret\"],\n\tAWS_ACCESS_KEY_ID: [\"storage\", \"accessKeyId\"],\n\tAWS_SECRET_ACCESS_KEY: [\"storage\", \"secretAccessKey\"],\n\tAWS_ENDPOINT_URL_S3: [\"storage\", \"endpoint\"],\n\tAWS_REGION: [\"storage\", \"region\"],\n\tNEON_AI_GATEWAY_TOKEN: [\"aiGateway\", \"apiKey\"],\n\tNEON_AI_GATEWAY_BASE_URL: [\"aiGateway\", \"baseUrl\"],\n};\n\n/**\n * Filtered counterpart to the {@link parseEnv} body: validate and return only the explicitly\n * selected OS-level env-var keys, projected back into the narrowed namespaced shape. Unlike\n * the full reader it never consults the policy — the selection alone decides what's required —\n * so vars the caller didn't ask for (e.g. `DATABASE_URL_UNPOOLED`) can be absent without\n * throwing. Mirrors the same non-empty constraint and {@link PlatformError} aggregation.\n */\nfunction parseFilteredEnv(\n\tsource: NodeJS.ProcessEnv,\n\tkeys: readonly string[],\n): Record<string, unknown> {\n\tconst issues: string[] = [];\n\tconst result: Record<string, Record<string, unknown>> = {};\n\tfor (const key of keys) {\n\t\t// Unknown keys are blocked at the type level; a runtime caller bypassing the types\n\t\t// gets a clear error rather than a silently-dropped selection.\n\t\tif (!Object.hasOwn(FILTERABLE_ENV_KEYS, key)) {\n\t\t\tissues.push(`${key} is not a selectable Neon env variable`);\n\t\t\tcontinue;\n\t\t}\n\t\tconst value = source[key];\n\t\tif (value === undefined) {\n\t\t\tissues.push(`${key} is missing`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (value === \"\") {\n\t\t\tissues.push(`${key} must not be empty`);\n\t\t\tcontinue;\n\t\t}\n\t\tconst [namespace, property] = FILTERABLE_ENV_KEYS[key];\n\t\tconst bucket = result[namespace] ?? {};\n\t\tbucket[property] = value;\n\t\tresult[namespace] = bucket;\n\t}\n\tif (issues.length > 0) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.EnvNotInjected,\n\t\t\t[\n\t\t\t\t\"parseEnv: the required Neon env variables are not present in process.env.\",\n\t\t\t\t...issues.map((i) => ` - ${i}`),\n\t\t\t\t...parseEnvInjectHint(issues),\n\t\t\t\t\"Or switch the call to `await fetchEnv(config, …)` if you're in a context that can do async I/O.\",\n\t\t\t].join(\"\\n\"),\n\t\t\t{ details: { missing: issues } },\n\t\t);\n\t}\n\treturn result;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neon/env",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Resolve and inject Neon connection strings for the branch selected by your neon.ts policy. fetchEnv / parseEnv plus a `neon-env` CLI with `run` and `export`.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"neon",
|
|
@@ -45,15 +45,15 @@
|
|
|
45
45
|
"tsdown": "^0.14.1",
|
|
46
46
|
"typescript": "^5.9.0",
|
|
47
47
|
"vitest": "^3.0.9",
|
|
48
|
-
"@neon-internals/env-core": "0.0.44",
|
|
49
|
-
"@neon/sdk": "7.9.0",
|
|
50
48
|
"@neon-internals/cli-core": "0.0.0",
|
|
51
|
-
"@neon/
|
|
49
|
+
"@neon-internals/env-core": "0.0.46",
|
|
50
|
+
"@neon/e2e-harness": "0.0.0",
|
|
51
|
+
"@neon/sdk": "7.10.0"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"zod": "^4.5.4",
|
|
55
55
|
"yargs": "^18.0.0",
|
|
56
|
-
"@neon/config": "1.
|
|
56
|
+
"@neon/config": "1.12.0"
|
|
57
57
|
},
|
|
58
58
|
"optionalDependencies": {
|
|
59
59
|
"@napi-rs/keyring": "1.3.0"
|