@neondatabase/env 0.11.6 → 0.11.7
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/lib/env.d.ts +21 -3
- package/dist/lib/env.d.ts.map +1 -1
- package/dist/lib/env.js.map +1 -1
- package/package.json +1 -1
package/dist/lib/env.d.ts
CHANGED
|
@@ -202,6 +202,23 @@ type PreviewFunctionsOf<C extends Config> = NonNullable<C["preview"]> extends {
|
|
|
202
202
|
} ? F : Record<never, never>;
|
|
203
203
|
/** The declared function slugs of a config (record keys), as a string union. */
|
|
204
204
|
type FunctionSlugOf<C extends Config> = Extract<keyof PreviewFunctionsOf<C>, string>;
|
|
205
|
+
/**
|
|
206
|
+
* Human-readable hint surfaced as the **expected type** of `parseEnv`'s `scope` argument when
|
|
207
|
+
* the policy declares no functions at all. Without it the argument's expected type is the bare
|
|
208
|
+
* `never` {@link FunctionSlugOf} yields, and TypeScript reports the opaque `Type '"x"' is not
|
|
209
|
+
* assignable to type 'never'`; the literal turns that into a sentence naming the fix (and the
|
|
210
|
+
* editor offers it as the single completion, so the empty completion list is explained rather
|
|
211
|
+
* than just empty). Mirrors `NeonAuthRequiredHint` in `@neon/config`.
|
|
212
|
+
*/
|
|
213
|
+
type NoFunctionScopeHint = "this policy declares no `preview.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";
|
|
214
|
+
/**
|
|
215
|
+
* The expected type of `parseEnv`'s function-slug `scope` argument: the caller's inferred slug
|
|
216
|
+
* `S` normally, and the {@link NoFunctionScopeHint} message when the policy declares no
|
|
217
|
+
* functions. Keeping `S` (rather than `FunctionSlugOf<C>`) in the enabled branch is what makes
|
|
218
|
+
* the returned `function` namespace exact — it stays the one function's env keys instead of
|
|
219
|
+
* widening to every declared function's.
|
|
220
|
+
*/
|
|
221
|
+
type FunctionScopeField<C extends Config, S extends string> = [FunctionSlugOf<C>] extends [never] ? NoFunctionScopeHint : S;
|
|
205
222
|
/** The declared env-var keys of one function `S`, as a string union. */
|
|
206
223
|
type FunctionEnvKeysOf<C extends Config, S extends string> = S extends keyof PreviewFunctionsOf<C> ? NonNullable<PreviewFunctionsOf<C>[S]> extends {
|
|
207
224
|
env: infer E;
|
|
@@ -372,7 +389,8 @@ declare function fetchEnv<const C extends Config>(config: C, options: FetchEnvOp
|
|
|
372
389
|
* full `{ postgres, auth?, dataApi?, … }` the policy enables.
|
|
373
390
|
* - a **function slug** (a key of `config.preview.functions`) — *function* scope: you are
|
|
374
391
|
* running inside that function. Returns the same branch secrets **plus** a typed
|
|
375
|
-
* `function` namespace with the function's declared env-var keys.
|
|
392
|
+
* `function` namespace with the function's declared env-var keys. The slug autocompletes
|
|
393
|
+
* from the policy ({@link FunctionSlugOf}) and an undeclared one is a type error.
|
|
376
394
|
* - an **array of OS-level env-var keys** (e.g. `["DATABASE_URL", "NEON_AUTH_BASE_URL"]`) —
|
|
377
395
|
* *filtered* mode: only those vars are required and returned, as a narrowed namespaced
|
|
378
396
|
* shape. The keys autocomplete from the policy ({@link SelectableEnvKey}), so you can only
|
|
@@ -401,8 +419,8 @@ declare function fetchEnv<const C extends Config>(config: C, options: FetchEnvOp
|
|
|
401
419
|
* ```
|
|
402
420
|
*/
|
|
403
421
|
declare function parseEnv<const C extends Config>(config: C): NeonEnv<C>;
|
|
422
|
+
declare function parseEnv<const C extends Config, const S extends FunctionSlugOf<C>>(config: C, scope: FunctionScopeField<C, S>): NeonEnv<C> & NeonFunctionEnv<C, S>;
|
|
404
423
|
declare function parseEnv<const C extends Config, const K extends SelectableEnvKey<C>>(config: C, keys: readonly K[]): FilteredNeonEnv<K>;
|
|
405
|
-
declare function parseEnv<const C extends Config, const S extends FunctionSlugOf<C>>(config: C, scope: S): NeonEnv<C> & NeonFunctionEnv<C, S>;
|
|
406
424
|
/**
|
|
407
425
|
* Project a fully-resolved {@link NeonEnv} into the OS-level `{ KEY: value }` pairs used
|
|
408
426
|
* for cross-process transport. Named after the web-platform `.entries()` convention
|
|
@@ -416,5 +434,5 @@ declare function parseEnv<const C extends Config, const S extends FunctionSlugOf
|
|
|
416
434
|
*/
|
|
417
435
|
declare function toEntries(env: NeonEnv<Config>): Record<string, string>;
|
|
418
436
|
//#endregion
|
|
419
|
-
export { FetchEnvOptions, FilteredNeonEnv, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAiGatewayEnv, NeonAuthEnv, NeonBranchEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, NeonStorageEnv, SelectableEnvKey, fetchEnv, parseEnv, toEntries };
|
|
437
|
+
export { FetchEnvOptions, FilteredNeonEnv, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAiGatewayEnv, NeonAuthEnv, NeonBranchEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, NeonStorageEnv, NoFunctionScopeHint, SelectableEnvKey, fetchEnv, parseEnv, toEntries };
|
|
420
438
|
//# sourceMappingURL=env.d.ts.map
|
package/dist/lib/env.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","names":[],"sources":["../../src/lib/env.ts"],"mappings":";;;;;cAqDa;;;;AAAb;AAkDA;EAKiB,SAAA,MAAA,EAAA;IAuBA,SAAA,IAAW,EAAA,aAAA;EAOX,CAAA;EAeA,SAAA,QAAc,EAAA;IAiBd,SAAA,WAAgB,EAAA,cAAA;IAU5B,SAAA,mBAAoB,EAAA,uBAAA;EAapB,CAAA;EAAS,SAAA,IAAA,EAAA;IAAO,SAAA,OAAA,EAAA,oBAAA;IAEjB,SAAA,OAAA,EAAA,oBAAA;EAEC,CAAA;EAEC,SAAA,OAAA,EAAA;IAEC,SAAA,GAAA,EAAA,mBAAA;EAEC,CAAA;EAAC;AAAA;AAKiB;AAWX;AAAW;EAAuB,SAAA,OAAA,EAAA;IAAZ,SAAA,WAAA,EAAA,mBAAA;IAEtB,SAAA,eAAA,EAAA,uBAAA;IAAZ,SAAA,QAAA,EAAA,qBAAA;IACqB,SAAA,MAAA,EAAA,YAAA;EAAZ,CAAA;EAAR;AAAO;AAAA;AAYK;AAAW;AAAuB;AAAZ;EAEvB,SAAA,SAAA,EAAA;IAAZ,SAAA,MAAA,EAAA,uBAAA;IACuB,SAAA,OAAA,EAAA,0BAAA;EAAZ,CAAA;AAAV,CAAA;AAAS;AAiBb;AAAmB;AAAW;AAAS;AAC5B;AAKD,UA7JO,aAAA,CA6JP;EACiB,IAAA,EAAA,MAAA;AAAZ;AAAV;AACM,UA1JM,eAAA,CA0JN;EACR;AACqB;AAAZ;AAAV;EACa,WAAA,EAAA,MAAA;EACX;AACS;AAAX;AAAwC;AAAmB;EAC/C,mBAAA,EAAA,MAAA;AAAZ;AACe;AACb;AAAW;AAAE;AAGM;AAAW;AACrB;AAAZ;AAGG;AACA,UAnJa,WAAA,CAmJb;EAAM,OAAA,EAAA,MAAA;EAGE;EAAc,OAAA,EAAA,MAAA;AAAW;AACX;AAAnB,UAhJU,cAAA,CAgJV;EADwC,GAAA,EAAA,MAAA;AAAO;
|
|
1
|
+
{"version":3,"file":"env.d.ts","names":[],"sources":["../../src/lib/env.ts"],"mappings":"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"}
|
package/dist/lib/env.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.js","names":[],"sources":["../../src/lib/env.ts"],"sourcesContent":["import {\n\ttype Config,\n\ttype CredentialScope,\n\tcreateNeonApiFromOptions,\n\tderiveCredentialScopes,\n\tErrorCode,\n\ttype NeonApi,\n\ttype NeonBranchSnapshot,\n\ttype NeonDatabaseSnapshot,\n\ttype NeonRoleSnapshot,\n\tPlatformError,\n\ttype ResolvedPreviewConfig,\n\tresolveConfig,\n\ttype ServiceToggleInput,\n} from \"@neon/config/v1\";\nimport { z } from \"zod\";\n\n/**\n * Mapping between the {@link NeonEnv} property paths and the OS-level env-var keys used\n * for cross-process transport (via `.env` files, `env run -- <cmd>`, or anything else\n * that talks to `process.env`).\n *\n * Each top-level key here is a {@link NeonEnv} namespace; the inner record maps the\n * camelCase property names exposed to TypeScript to the UPPER_SNAKE env-var names used\n * by the OS. Keep this in sync with {@link postgresEnvSchema} / {@link authEnvSchema} /\n * {@link dataApiEnvSchema}.\n */\n/**\n * Neon's default branch owner role, created with every project. This is the role a\n * `DATABASE_URL` should connect as.\n */\nconst NEON_DEFAULT_OWNER_ROLE = \"neondb_owner\";\n\n/**\n * Neon's default database, created with every project. When a branch has several databases\n * and none was requested, this is preferred for the `DATABASE_URL` so the common case (a\n * user added a second database next to `neondb`) auto-picks without asking.\n */\nconst NEON_DEFAULT_DATABASE = \"neondb\";\n\n/**\n * Roles Neon provisions for the Auth / Data API (PostgREST) stack. They exist to back\n * RLS-scoped Data API requests authenticated by JWT — never to hold a `DATABASE_URL` —\n * so they're skipped when auto-picking the connection role. Enabling Neon Auth or the\n * Data API (`neon config apply`) adds these next to the owner role, which is why a plain\n * branch routinely reports more than one role.\n */\nconst NEON_MANAGED_AUTH_ROLES: ReadonlySet<string> = new Set([\n\t\"authenticator\",\n\t\"anonymous\",\n\t\"authenticated\",\n]);\n\nexport const NEON_ENV_VAR_KEYS = {\n\t/**\n\t * Branch identity. `NEON_BRANCH` carries the branch **name** and is injected into the\n\t * Neon Functions runtime on every branch (including the default) by default. `env pull` /\n\t * `neon dev` / `neon-env run` emit it too so local dev mirrors the deployed runtime.\n\t */\n\tbranch: {\n\t\tname: \"NEON_BRANCH\",\n\t},\n\tpostgres: {\n\t\tdatabaseUrl: \"DATABASE_URL\",\n\t\tdatabaseUrlUnpooled: \"DATABASE_URL_UNPOOLED\",\n\t},\n\tauth: {\n\t\tbaseUrl: \"NEON_AUTH_BASE_URL\",\n\t\tjwksUrl: \"NEON_AUTH_JWKS_URL\",\n\t},\n\tdataApi: {\n\t\turl: \"NEON_DATA_API_URL\",\n\t},\n\t/**\n\t * Object storage (Preview). The S3 SDKs read `AWS_*` from their standard config chain, so\n\t * a branch credential + `neon dev` / `env pull` makes object storage work from env alone.\n\t * `region` is injected under the SDK-standard `AWS_REGION`.\n\t */\n\tstorage: {\n\t\taccessKeyId: \"AWS_ACCESS_KEY_ID\",\n\t\tsecretAccessKey: \"AWS_SECRET_ACCESS_KEY\",\n\t\tendpoint: \"AWS_ENDPOINT_URL_S3\",\n\t\tregion: \"AWS_REGION\",\n\t},\n\t/**\n\t * AI Gateway (Preview). Exposed under the Neon-branded env vars the deployed Functions\n\t * runtime injects: `apiKey` is the minted credential's bearer (`NEON_AI_GATEWAY_TOKEN`)\n\t * and `baseUrl` is the bare branch gateway host (`NEON_AI_GATEWAY_BASE_URL`,\n\t * `scheme://host`, no path). Clients like `@neon/ai-sdk-provider` read these and append the\n\t * dialect route (`/v1`, `/openai/v1`, `/anthropic/v1`) themselves (https://github.com/vercel/ai/pull/15997).\n\t */\n\taiGateway: {\n\t\tapiKey: \"NEON_AI_GATEWAY_TOKEN\",\n\t\tbaseUrl: \"NEON_AI_GATEWAY_BASE_URL\",\n\t},\n} as const;\n\n/**\n * Branch identity for the resolved branch. Always present on a `fetchEnv` result (the branch\n * name is always known); on a `parseEnv` result it's present only when `NEON_BRANCH` was\n * injected into `process.env` (the Functions runtime injects it by default, as do `neon dev` /\n * `neon-env run` / `env pull`). `name` is the branch **name** (e.g. `main`, `preview/foo`).\n */\nexport interface NeonBranchEnv {\n\tname: string;\n}\n\n/** Per-namespace inner shapes. Exposed so consumers can name the parts independently. */\nexport interface NeonPostgresEnv {\n\t/**\n\t * Pooled connection string (via Neon's PgBouncer pooler). The right default for\n\t * serverless drivers (`@neondatabase/serverless`, edge runtimes, Postgres.js, …).\n\t */\n\tdatabaseUrl: string;\n\t/**\n\t * Direct (unpooled) connection string. Use this when you need session-level\n\t * features (`LISTEN`/`NOTIFY`, prepared statements across calls, transactions\n\t * spanning round-trips) that PgBouncer's transaction-mode pooling drops.\n\t */\n\tdatabaseUrlUnpooled: string;\n}\n\n/**\n * Bits of a Neon Auth integration for the resolved branch. Only present on `NeonEnv`\n * when the branch policy enables `auth`.\n *\n * Neon Auth exposes the `baseUrl` (which doubles as the publishable client identifier) and\n * the `jwksUrl` used to verify tokens it issues. `fetchEnv` reads both from the live\n * integration; `parseEnv` reads them from `process.env` (`NEON_AUTH_BASE_URL` /\n * `NEON_AUTH_JWKS_URL`).\n */\nexport interface NeonAuthEnv {\n\tbaseUrl: string;\n\t/** JWKS URL for verifying tokens issued by Neon Auth (`NEON_AUTH_JWKS_URL`). */\n\tjwksUrl: string;\n}\n\n/** Bits of a Neon Data API integration. Only present when the branch policy enables it. */\nexport interface NeonDataApiEnv {\n\turl: string;\n}\n\n/**\n * S3-compatible object-storage access for the branch (Preview). Present on `NeonEnv` only\n * when the policy declares `preview.buckets`. Combines a minted branch credential's access\n * keys (`accessKeyId` = the credential's full token id, e.g. `nak_live_…`, which is what the\n * storage gateway authenticates against; `secretAccessKey` = its\n * `s3_secret_access_key`) with the branch's non-secret connection details\n * (`endpoint`/`region`, from `GET .../storage`). Projects to the AWS SDK's\n * standard config env (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_ENDPOINT_URL_S3`,\n * `AWS_REGION`) so the S3 client works from env alone. Neon's storage gateway always\n * requires path-style addressing, so set `forcePathStyle: true` on your S3 client.\n */\nexport interface NeonStorageEnv {\n\taccessKeyId: string;\n\tsecretAccessKey: string;\n\t/** S3-compatible endpoint URL for the branch. */\n\tendpoint: string;\n\t/** AWS region string (e.g. `us-east-2`). Injected as `AWS_REGION`. */\n\tregion: string;\n}\n\n/**\n * AI Gateway access for the branch (Preview). Present on `NeonEnv` only when the policy\n * enables `preview.aiGateway`. `apiKey` is the minted credential's bearer (`api_token`);\n * `baseUrl` is the bare branch-scoped gateway host\n * (`https://<branchId>-api.ai.<region>.…`, no path). Projects to the Neon-branded env\n * (`NEON_AI_GATEWAY_TOKEN`, `NEON_AI_GATEWAY_BASE_URL`); clients like `@neon/ai-sdk-provider`\n * append the dialect route (`/v1`, `/openai/v1`, `/anthropic/v1`) themselves.\n */\nexport interface NeonAiGatewayEnv {\n\tapiKey: string;\n\tbaseUrl: string;\n}\n\n/**\n * Empty record alias used as the \"false\" branch of the conditional namespace adds below.\n * `Record<never, never>` is the no-op for intersection — the cleaner alternative to `{}`,\n * which biome rejects (it means \"any non-null\", not \"empty object\").\n */\ntype NoNamespace = Record<never, never>;\n\n/**\n * Resolve a **static** service toggle (the value of `config.auth` / `config.dataApi`) to a\n * type-level boolean. The whole-thing wrapping (`[T] extends […]`) turns off distribution\n * so a union/`undefined` is checked as one unit:\n *\n * - `false` / `{ enabled: false }` / `undefined` → `false`\n * - `true` / `{ enabled: true }` / any other object (`{}`, `{ enabled?: boolean }`) → `true`\n * (a present toggle defaults to enabled)\n * - the bare `boolean | ServiceToggle | undefined` (the default `Config` param, no literal\n * info) → `false`, so an untyped policy yields just `{ postgres }`.\n */\ntype ServiceOn<T> = [T] extends [false]\n\t? false\n\t: [T] extends [{ enabled: false }]\n\t\t? false\n\t\t: [T] extends [undefined]\n\t\t\t? false\n\t\t\t: [T] extends [true]\n\t\t\t\t? true\n\t\t\t\t: [T] extends [{ enabled: true }]\n\t\t\t\t\t? true\n\t\t\t\t\t: [T] extends [object]\n\t\t\t\t\t\t? true\n\t\t\t\t\t\t: false;\n\n/** True when `T` has at least one known key; `false` for `{}` / `never`. */\ntype HasKeys<T> = [keyof T] extends [never] ? false : true;\n\n/**\n * Whether the policy's **static** `preview` block declares at least one object-storage bucket\n * (`preview.buckets`). Drives whether {@link NeonEnv} carries the `storage` namespace.\n *\n * The leading `[never]` guard is load-bearing: when a policy has no `preview` at all,\n * `NonNullable<C[\"preview\"]>` is `never`, and without the guard the `extends { … }` probe\n * below would vacuously match (everything extends `never`-derived shapes) and `HasKeys<never>`\n * would resolve `true`, wrongly adding the namespace. The guard short-circuits to `false`.\n */\ntype HasBuckets<C extends Config> = [NonNullable<C[\"preview\"]>] extends [never]\n\t? false\n\t: NonNullable<C[\"preview\"]> extends { buckets: infer B }\n\t\t? HasKeys<NonNullable<B>>\n\t\t: false;\n\n/**\n * Whether the policy's **static** `preview` block enables the AI Gateway\n * (`preview.aiGateway`). Drives whether {@link NeonEnv} carries the `aiGateway` namespace.\n *\n * The leading `[never]` guard is load-bearing for the same reason as {@link HasBuckets}: when\n * a policy has no `preview`, `NonNullable<C[\"preview\"]>` is `never`, and a naked `never` in the\n * `extends` below would *distribute* (collapsing the result — and the whole `NeonEnv`\n * intersection — to `never`). The tuple-wrapped guard short-circuits that to `false`.\n */\ntype AiGatewayOn<C extends Config> = [NonNullable<C[\"preview\"]>] extends [never]\n\t? false\n\t: NonNullable<C[\"preview\"]> extends { aiGateway: infer A }\n\t\t? ServiceOn<NonNullable<A>>\n\t\t: false;\n\n/**\n * Static, namespaced shape of `fetchEnv` / `parseEnv`'s return value. Generic over the\n * {@link Config} so the type system knows which optional namespaces are present.\n *\n * Because the secret-bearing toggles now live in the **static** top-level `config.auth` /\n * `config.dataApi` (not inside a per-branch closure), the namespace presence is a direct\n * read of those fields — no union-across-branches, no default-config escape hatch:\n *\n * - `postgres` is always present.\n * - `auth` is added iff `config.auth` is statically enabled.\n * - `dataApi` is added iff `config.dataApi` is statically enabled.\n * - `storage` is added iff `config.preview.buckets` declares at least one bucket.\n * - `aiGateway` is added iff `config.preview.aiGateway` is statically enabled.\n */\nexport type NeonEnv<C extends Config = Config> = {\n\tpostgres: NeonPostgresEnv;\n\t/**\n\t * Branch identity (`NEON_BRANCH`). Optional because `parseEnv` only surfaces it when the\n\t * var was injected; `fetchEnv` always populates it.\n\t */\n\tbranch?: NeonBranchEnv;\n} & (ServiceOn<NonNullable<C[\"auth\"]>> extends true\n\t? { auth: NeonAuthEnv }\n\t: NoNamespace) &\n\t(ServiceOn<NonNullable<C[\"dataApi\"]>> extends true\n\t\t? { dataApi: NeonDataApiEnv }\n\t\t: NoNamespace) &\n\t(HasBuckets<C> extends true ? { storage: NeonStorageEnv } : NoNamespace) &\n\t(AiGatewayOn<C> extends true\n\t\t? { aiGateway: NeonAiGatewayEnv }\n\t\t: NoNamespace);\n\n/** The static `preview.functions` record of a config, or an empty record when absent. */\ntype PreviewFunctionsOf<C extends Config> =\n\tNonNullable<C[\"preview\"]> extends {\n\t\tfunctions: infer F;\n\t}\n\t\t? F\n\t\t: Record<never, never>;\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/** 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 key filtering ─────────────────────────\n\n/**\n * OS-level env-var keys grouped by the {@link NeonEnv} namespace they populate. Only the\n * **input** vars `parseEnv` validates are listed — the output-only aliases in\n * {@link NEON_ENV_VAR_KEYS} (`NEON_AI_GATEWAY_TOKEN`, …) are intentionally absent, so they\n * are not selectable in a `parseEnv(config, keys)` filter. Keep in sync with\n * {@link EnvKeyToProp}.\n */\ninterface EnvKeysByNamespace {\n\tpostgres: \"DATABASE_URL\" | \"DATABASE_URL_UNPOOLED\";\n\tauth: \"NEON_AUTH_BASE_URL\" | \"NEON_AUTH_JWKS_URL\";\n\tdataApi: \"NEON_DATA_API_URL\";\n\tstorage:\n\t\t| \"AWS_ACCESS_KEY_ID\"\n\t\t| \"AWS_SECRET_ACCESS_KEY\"\n\t\t| \"AWS_ENDPOINT_URL_S3\"\n\t\t| \"AWS_REGION\";\n\taiGateway: \"NEON_AI_GATEWAY_TOKEN\" | \"NEON_AI_GATEWAY_BASE_URL\";\n}\n\n/** The {@link NeonEnv} namespace interface backing each namespace key. */\ninterface NamespaceEnv {\n\tpostgres: NeonPostgresEnv;\n\tauth: NeonAuthEnv;\n\tdataApi: NeonDataApiEnv;\n\tstorage: NeonStorageEnv;\n\taiGateway: NeonAiGatewayEnv;\n}\n\n/** OS-level env-var key → the camelCase property it sets on its namespace object. */\ninterface EnvKeyToProp {\n\tDATABASE_URL: \"databaseUrl\";\n\tDATABASE_URL_UNPOOLED: \"databaseUrlUnpooled\";\n\tNEON_AUTH_BASE_URL: \"baseUrl\";\n\tNEON_AUTH_JWKS_URL: \"jwksUrl\";\n\tNEON_DATA_API_URL: \"url\";\n\tAWS_ACCESS_KEY_ID: \"accessKeyId\";\n\tAWS_SECRET_ACCESS_KEY: \"secretAccessKey\";\n\tAWS_ENDPOINT_URL_S3: \"endpoint\";\n\tAWS_REGION: \"region\";\n\tNEON_AI_GATEWAY_TOKEN: \"apiKey\";\n\tNEON_AI_GATEWAY_BASE_URL: \"baseUrl\";\n}\n\n/**\n * The OS-level env-var keys selectable for a given policy: the union of input vars across\n * exactly the namespaces {@link NeonEnv}<C> carries. Drives the typesafe autocomplete of the\n * `keys` filter — selecting a var from a namespace the policy does not enable is a type error\n * (e.g. `NEON_AUTH_BASE_URL` is only offered once the policy turns on `auth`).\n */\nexport type SelectableEnvKey<C extends Config> =\n\tEnvKeysByNamespace[keyof NeonEnv<C> & keyof EnvKeysByNamespace];\n\n/**\n * The result shape of a **filtered** `parseEnv(config, keys)` call: the namespaced\n * {@link NeonEnv} restricted to exactly the selected OS-level keys `K`. Namespaces with no\n * selected key are dropped, and within a kept namespace only the selected properties survive\n * — selecting just `[\"DATABASE_URL\"]` yields `{ postgres: { databaseUrl: string } }`, with no\n * `databaseUrlUnpooled`.\n *\n * The policy gating lives on the `parseEnv` overload (which binds `K` to\n * {@link SelectableEnvKey}); this type only needs the selection, so it takes a bare\n * `K extends string` and filters with `Extract`. The outer mapped type's `as` clause drops\n * any namespace whose intersection with the selection is empty (`[…] extends [never]`,\n * tuple-wrapped to switch off distribution); the inner one re-keys each selected OS var to its\n * camelCase property and looks the value type up on the canonical namespace interface, so it\n * stays correct if a field ever stops being a plain `string`.\n */\nexport type FilteredNeonEnv<K extends string> = {\n\t[N in keyof EnvKeysByNamespace as [\n\t\tExtract<K, EnvKeysByNamespace[N]>,\n\t] extends [never]\n\t\t? never\n\t\t: N]: {\n\t\t[P in Extract<K, EnvKeysByNamespace[N]> as EnvKeyToProp[P &\n\t\t\tkeyof EnvKeyToProp]]: NamespaceEnv[N][EnvKeyToProp[P &\n\t\t\tkeyof EnvKeyToProp] &\n\t\t\tkeyof NamespaceEnv[N]];\n\t};\n};\n\nexport interface FetchEnvOptions {\n\t/**\n\t * Neon project id. **Required** — the management API addresses branches through their\n\t * project. Resolve it in your CLI (e.g. neonctl) and pass it in.\n\t */\n\tprojectId: string;\n\t/**\n\t * Neon branch — its **name** (e.g. `main`) or its id (`br-…`). **Required** (or pass the\n\t * legacy {@link FetchEnvOptions.branchId}). Resolved against the project's branches by\n\t * id first, then by name, so either form works.\n\t */\n\tbranch?: string;\n\t/**\n\t * @deprecated Legacy id-only field. Prefer {@link FetchEnvOptions.branch}, which accepts\n\t * a branch name or id. Still honored for backward compatibility; ignored when `branch`\n\t * is set.\n\t */\n\tbranchId?: string;\n\t/**\n\t * Neon API key. Resolved via the standard chain (option → `NEON_API_KEY` →\n\t * `~/.config/neonctl/credentials.json`) when omitted. Ignored when a custom `api`\n\t * is supplied.\n\t */\n\tapiKey?: string;\n\t/**\n\t * Neon **management** API base URL (not the Auth base URL). Falls back to\n\t * `NEON_API_HOST`, then production. Ignored when a custom `api` is supplied.\n\t */\n\tapiHost?: string;\n\t/**\n\t * Inject a custom NeonApi adapter. Primarily used by tests; production callers can rely\n\t * on the default real adapter built from `apiKey`.\n\t */\n\tapi?: NeonApi;\n\t/**\n\t * Role name to fetch credentials for. When omitted, the connection role is auto-picked:\n\t * the only role on the branch, else Neon's default owner (`neondb_owner`), else the\n\t * single role left after dropping the managed Auth/Data API roles\n\t * (`authenticator`/`anonymous`/`authenticated`). Throws {@link PlatformError} with\n\t * `PLATFORM_AMBIGUOUS_BRANCH_AUTH` only when more than one app role remains.\n\t */\n\troleName?: string;\n\t/**\n\t * Database name. When omitted, it is auto-picked: Neon's default `neondb` if present,\n\t * else the only database on the branch. Throws {@link PlatformError} with\n\t * `PLATFORM_AMBIGUOUS_BRANCH_AUTH` when the branch has several databases and none is\n\t * `neondb` (pass `databaseName` to disambiguate), and `PLATFORM_BRANCH_NOT_FOUND` when\n\t * the branch has no databases or the requested `databaseName` does not exist.\n\t */\n\tdatabaseName?: string;\n\t/**\n\t * Env source used for one-time Auth keys that cannot be refetched after integration\n\t * creation. Defaults to `process.env`; callers may layer values from `.env.local`.\n\t */\n\tenv?: NodeJS.ProcessEnv;\n}\n\n/**\n * Resolve the project + branch this process should target, then fetch live Neon\n * connection strings for that branch over the network. Async — calls the Neon API.\n *\n * Use this from build scripts and the `neon-env run` command, where top-level await is\n * fine. For application code that needs a synchronous bootstrap (most frameworks: Drizzle\n * config, Next.js, Vite, etc.), inject env vars via `neon-env run -- <cmd>` and use\n * {@link parseEnv} instead — same {@link NeonEnv} shape, but a sync call against\n * `process.env`.\n *\n * Filesystem- and env-agnostic: pass `projectId` and the target `branch` (name or id)\n * explicitly (resolve them in your CLI, e.g. neonctl).\n *\n * ```ts\n * import config from \"../neon\";\n * import { fetchEnv } from \"@neon/env\";\n *\n * const env = await fetchEnv(config, { projectId: \"patient-art-12345\", branch: \"main\" });\n * const db = drizzle(neon(env.postgres.databaseUrl), { schema });\n * ```\n *\n * The package does **not** mutate `process.env` or the filesystem itself.\n */\nexport async function fetchEnv<const C extends Config>(\n\tconfig: C,\n\toptions: FetchEnvOptions,\n): Promise<NeonEnv<C>> {\n\tconst api = options.api ?? createApiFromOptions(options);\n\tconst projectId = options.projectId;\n\n\tconst branches = await api.listBranches(projectId);\n\tif (branches.length === 0) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.BranchNotFound,\n\t\t\t[\n\t\t\t\t`fetchEnv: project ${projectId} has no branches.`,\n\t\t\t\t\"Deploy your neon.ts policy (or create a branch) first, or pick a different project id.\",\n\t\t\t].join(\" \"),\n\t\t\t{ details: { projectId } },\n\t\t);\n\t}\n\n\tconst branchRef = options.branch ?? options.branchId;\n\tif (!branchRef) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.BranchNotFound,\n\t\t\t[\n\t\t\t\t\"fetchEnv: no branch provided.\",\n\t\t\t\t\"Pass `branch` with a branch name (e.g. `main`) or id (`br-…`).\",\n\t\t\t].join(\" \"),\n\t\t\t{ details: { projectId } },\n\t\t);\n\t}\n\tconst branch = resolveBranch(branchRef, branches);\n\tconst desired = resolveConfig(config, {\n\t\tname: branch.name,\n\t\tid: branch.id,\n\t\texists: true,\n\t\t...(branch.parentId ? { parentId: branch.parentId } : {}),\n\t\tisDefault: branch.isDefault,\n\t\tisProtected: branch.protected,\n\t\t...(branch.expiresAt ? { expiresAt: branch.expiresAt } : {}),\n\t});\n\n\tconst [roles, databases] = await Promise.all([\n\t\tapi.listBranchRoles(projectId, branch.id),\n\t\tapi.listBranchDatabases(projectId, branch.id),\n\t]);\n\n\tconst roleName = pickRoleName(roles, branch, options.roleName);\n\tconst databaseName = pickDatabaseName(\n\t\tdatabases,\n\t\tbranch,\n\t\toptions.databaseName,\n\t);\n\n\t// Fan out: always fetch both Postgres URIs. Conditionally fetch auth + dataApi based\n\t// on the branch policy. Auth key fields are only returned at integration creation time;\n\t// for Better Auth they may legitimately be empty, so absence in the local env becomes\n\t// empty string values while still emitting the required variable names.\n\tconst wantsAuth = desired.authEnabled;\n\tconst wantsDataApi = desired.dataApiEnabled;\n\n\tconst [pooled, unpooled, authSnapshot, dataApiSnapshot] = await Promise.all(\n\t\t[\n\t\t\tapi.getConnectionUri(projectId, {\n\t\t\t\tbranchId: branch.id,\n\t\t\t\tdatabaseName,\n\t\t\t\troleName,\n\t\t\t\tpooled: true,\n\t\t\t}),\n\t\t\tapi.getConnectionUri(projectId, {\n\t\t\t\tbranchId: branch.id,\n\t\t\t\tdatabaseName,\n\t\t\t\troleName,\n\t\t\t\tpooled: false,\n\t\t\t}),\n\t\t\twantsAuth\n\t\t\t\t? api.getNeonAuth(projectId, branch.id)\n\t\t\t\t: Promise.resolve(null),\n\t\t\twantsDataApi\n\t\t\t\t? api.getNeonDataApi(projectId, branch.id, databaseName)\n\t\t\t\t: Promise.resolve(null),\n\t\t],\n\t);\n\n\tconst result: Record<string, unknown> = {\n\t\tpostgres: {\n\t\t\tdatabaseUrl: pooled.uri,\n\t\t\tdatabaseUrlUnpooled: unpooled.uri,\n\t\t},\n\t\t// Branch identity, mirroring what the Functions runtime injects on every branch.\n\t\t// Surfaced as `NEON_BRANCH` so local dev (`neon dev` / `neon-env run` / `env pull`)\n\t\t// matches the deployed runtime. Uses the branch name.\n\t\tbranch: { name: branch.name } satisfies NeonBranchEnv,\n\t};\n\n\tif (wantsAuth) {\n\t\tif (!authSnapshot) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.NotFound,\n\t\t\t\t[\n\t\t\t\t\t`fetchEnv: branch policy enables auth but no Neon Auth integration is enabled on branch ${branch.name} (${branch.id}).`,\n\t\t\t\t\t\"Enable it via `apply(config, { projectId, branchId })` (or `npx neonctl …`), in the Neon Console — then re-run fetchEnv. Or return auth.enabled=false.\",\n\t\t\t\t].join(\" \"),\n\t\t\t\t{\n\t\t\t\t\tdetails: { projectId, branchId: branch.id },\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\tconst envSource = options.env ?? process.env;\n\t\tconst baseUrl = resolveAuthBaseUrl(authSnapshot.baseUrl, envSource);\n\t\tconst jwksUrl = resolveAuthJwksUrl(authSnapshot.jwksUrl, envSource);\n\t\tresult.auth = { baseUrl, jwksUrl } satisfies NeonAuthEnv;\n\t}\n\n\tif (wantsDataApi) {\n\t\tif (!dataApiSnapshot) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.NotFound,\n\t\t\t\t[\n\t\t\t\t\t`fetchEnv: branch policy enables dataApi but no Data API integration is enabled on branch ${branch.name} (${branch.id}) database ${databaseName}.`,\n\t\t\t\t\t\"Enable it via `apply(config, { projectId, branchId })` or in the Neon Console — then re-run fetchEnv. Or return dataApi.enabled=false.\",\n\t\t\t\t].join(\" \"),\n\t\t\t\t{\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tprojectId,\n\t\t\t\t\t\tbranchId: branch.id,\n\t\t\t\t\t\tdatabaseName,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\tresult.dataApi = { url: dataApiSnapshot.url } satisfies NeonDataApiEnv;\n\t}\n\n\t// Object storage + AI Gateway (Preview). A single branch credential is minted (once) to\n\t// back whichever of these the policy enables; functions never force a credential but ride\n\t// along on its scopes. None of this runs when the policy enables neither, so the\n\t// Postgres / Auth / Data API path never touches the credentials/storage endpoints (and\n\t// keeps working on production, where they may not exist yet).\n\tconst wantsStorage = (desired.preview?.buckets.length ?? 0) > 0;\n\tconst wantsAiGateway = desired.preview?.aiGatewayEnabled ?? false;\n\tif (wantsStorage || wantsAiGateway) {\n\t\tconst secrets = await resolveCredentialSecrets({\n\t\t\tapi,\n\t\t\tprojectId,\n\t\t\tbranchId: branch.id,\n\t\t\tbranchName: branch.name,\n\t\t\tscopes: previewCredentialScopes(desired.preview),\n\t\t\tenv: options.env ?? process.env,\n\t\t\tneedStorage: wantsStorage,\n\t\t\tneedApiToken: wantsAiGateway,\n\t\t});\n\t\tif (wantsStorage) {\n\t\t\tconst storage = await api.getProjectBranchStorage(\n\t\t\t\tprojectId,\n\t\t\t\tbranch.id,\n\t\t\t);\n\t\t\tif (!storage) {\n\t\t\t\tthrow new PlatformError(\n\t\t\t\t\tErrorCode.NotFound,\n\t\t\t\t\t[\n\t\t\t\t\t\t`fetchEnv: branch policy declares object storage (preview.buckets) but storage is not enabled on branch ${branch.name} (${branch.id}).`,\n\t\t\t\t\t\t\"Enable it via `apply(config, { projectId, branchId })` (or in the Neon Console) — then re-run fetchEnv. Or remove preview.buckets.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\t{ details: { projectId, branchId: branch.id } },\n\t\t\t\t);\n\t\t\t}\n\t\t\tresult.storage = {\n\t\t\t\taccessKeyId: secrets.accessKeyId,\n\t\t\t\tsecretAccessKey: secrets.secretAccessKey,\n\t\t\t\tendpoint: storage.s3Endpoint,\n\t\t\t\tregion: storage.region,\n\t\t\t} satisfies NeonStorageEnv;\n\t\t}\n\t\tif (wantsAiGateway) {\n\t\t\tresult.aiGateway = {\n\t\t\t\tapiKey: secrets.apiToken,\n\t\t\t\t// Bare branch-scoped gateway host derived from the branch's connection URI —\n\t\t\t\t// not the control-plane API origin (which doesn't serve the gateway). Clients\n\t\t\t\t// append the dialect route (/v1, /openai/v1, /anthropic/v1) themselves.\n\t\t\t\tbaseUrl: aiGatewayBaseUrl(branch.id, unpooled.uri),\n\t\t\t} satisfies NeonAiGatewayEnv;\n\t\t}\n\t}\n\n\treturn result as NeonEnv<C>;\n}\n\n/**\n * Scopes the branch credential should carry for a resolved branch policy. Only object storage\n * and the AI Gateway *require* a credential; functions never force one (they have no credential\n * of their own), but `functions:invoke` is added to the scope set when a credential is already\n * being minted for storage / the AI Gateway, so the one credential can invoke the branch's\n * functions too. Returns `[]` only when nothing credential-bearing is enabled.\n */\nfunction previewCredentialScopes(\n\tpreview: ResolvedPreviewConfig | undefined,\n): CredentialScope[] {\n\tif (!preview) return [];\n\tconst storage = preview.buckets.length > 0;\n\tconst aiGateway = preview.aiGatewayEnabled;\n\tif (!storage && !aiGateway) return [];\n\treturn deriveCredentialScopes({\n\t\tstorage,\n\t\taiGateway,\n\t\tfunctions: preview.functions.length > 0,\n\t});\n}\n\n/**\n * Resolve the branch credential's secrets, reusing the ones already in the env source when\n * present and minting a fresh `user` credential otherwise. The Neon API returns `api_token` /\n * `s3_secret_access_key` exactly once at mint time, so the persisted copies (e.g. in\n * `.env.local`, surfaced as `NEON_AI_GATEWAY_TOKEN` / `AWS_SECRET_ACCESS_KEY`) are the only way to\n * recover them — exactly how one-time Auth keys are round-tripped. Reuse is presence-based\n * (no extra bookkeeping vars): if every secret the enabled features need is already present,\n * reuse it; otherwise mint one credential covering all currently-needed scopes.\n */\nasync function resolveCredentialSecrets(args: {\n\tapi: NeonApi;\n\tprojectId: string;\n\tbranchId: string;\n\tbranchName: string;\n\tscopes: CredentialScope[];\n\tenv: NodeJS.ProcessEnv;\n\tneedStorage: boolean;\n\tneedApiToken: boolean;\n}): Promise<{\n\taccessKeyId: string;\n\tsecretAccessKey: string;\n\tapiToken: string;\n}> {\n\tconst sKeys = NEON_ENV_VAR_KEYS.storage;\n\tconst aKeys = NEON_ENV_VAR_KEYS.aiGateway;\n\tconst haveStorage =\n\t\t!args.needStorage ||\n\t\tBoolean(args.env[sKeys.accessKeyId] && args.env[sKeys.secretAccessKey]);\n\tconst haveApiToken = !args.needApiToken || Boolean(args.env[aKeys.apiKey]);\n\tif (haveStorage && haveApiToken) {\n\t\treturn {\n\t\t\taccessKeyId: args.env[sKeys.accessKeyId] ?? \"\",\n\t\t\tsecretAccessKey: args.env[sKeys.secretAccessKey] ?? \"\",\n\t\t\tapiToken: args.env[aKeys.apiKey] ?? \"\",\n\t\t};\n\t}\n\tconst minted = await args.api.createCredential(\n\t\targs.projectId,\n\t\targs.branchId,\n\t\t{\n\t\t\tscopes: args.scopes,\n\t\t\tprincipalType: \"user\",\n\t\t\tname: `neon-env ${args.branchName}`,\n\t\t},\n\t);\n\treturn {\n\t\t// The storage gateway authenticates against the full token id (e.g.\n\t\t// `nak_live_…`), not the short token id — using the short id yields\n\t\t// `InvalidAccessKeyId` on every S3 request.\n\t\taccessKeyId: minted.tokenId,\n\t\tsecretAccessKey: minted.s3SecretAccessKey,\n\t\tapiToken: minted.apiToken,\n\t};\n}\n\n/**\n * The AI Gateway is a **branch-scoped host** — `<branchId>-api.ai.<host-suffix>` — NOT the\n * control-plane API origin. Derive the suffix from the branch's own Postgres connection host\n * by dropping only the endpoint label (the first segment) and keeping everything after it,\n * including any infra cell prefix (`c-N.`): a connection host of\n * `ep-x.c-3.us-east-2.aws.neon.tech` yields the gateway host\n * `<branchId>-api.ai.c-3.us-east-2.aws.neon.tech`. The cell prefix is **load-bearing** —\n * the gateway is cell-routed, so dropping `c-N.` resolves to the wrong (or no) host.\n */\nfunction aiGatewayHost(branchId: string, connectionUri: string): string {\n\tlet connectionHost = \"\";\n\ttry {\n\t\tconnectionHost = new URL(connectionUri).hostname;\n\t} catch {\n\t\tconnectionHost = \"\";\n\t}\n\t// Drop the endpoint label (first segment, e.g. `ep-x` / `ep-x-pooler`), keeping the rest\n\t// of the host verbatim — including any infra cell prefix (`c-N.`) the gateway routes on:\n\t// `[c-N.]<region>.<cloud>.neon.<tld>`.\n\tconst suffix = connectionHost.split(\".\").slice(1).join(\".\");\n\treturn `${branchId}-api.ai.${suffix}`;\n}\n\n/** The AI Gateway's bare base URL (`NEON_AI_GATEWAY_BASE_URL`) on the branch gateway host. */\nfunction aiGatewayBaseUrl(branchId: string, connectionUri: string): string {\n\treturn `https://${aiGatewayHost(branchId, connectionUri)}`;\n}\n\n/**\n * Resolve the Neon Auth base URL to surface in `env.auth`. Prefer the value returned by\n * the integration (`getNeonAuth` includes it); fall back to whatever is already in the\n * caller's env source so older integrations created before `base_url` was returned still\n * round-trip through `env run`.\n */\nfunction resolveAuthBaseUrl(\n\tsnapshotBaseUrl: string | undefined,\n\tsource: NodeJS.ProcessEnv,\n): string {\n\tif (snapshotBaseUrl && snapshotBaseUrl !== \"\") return snapshotBaseUrl;\n\treturn source[NEON_ENV_VAR_KEYS.auth.baseUrl] ?? \"\";\n}\n\n/**\n * Resolve the Neon Auth JWKS URL to surface in `env.auth`. Prefer the value returned by the\n * integration (`getNeonAuth` always includes `jwks_url`); fall back to the caller's env\n * source so the value still round-trips through `env run` if a snapshot ever omits it.\n */\nfunction resolveAuthJwksUrl(\n\tsnapshotJwksUrl: string | undefined,\n\tsource: NodeJS.ProcessEnv,\n): string {\n\tif (snapshotJwksUrl && snapshotJwksUrl !== \"\") return snapshotJwksUrl;\n\treturn source[NEON_ENV_VAR_KEYS.auth.jwksUrl] ?? \"\";\n}\n\nfunction createApiFromOptions(options: FetchEnvOptions): NeonApi {\n\treturn createNeonApiFromOptions(\"fetchEnv\", {\n\t\t...(options.apiKey ? { apiKey: options.apiKey } : {}),\n\t\t...(options.apiHost ? { apiHost: options.apiHost } : {}),\n\t});\n}\n\n/**\n * Resolve a branch ref — a name or an id — to a concrete branch. Matches by id first\n * (exact `br-…`), then by name; both are unique within a project, so the lookup is\n * unambiguous. This lets `.neon` files written by `neonctl` (which pin the branch *name*)\n * and explicit `br-…` ids both work.\n */\nfunction resolveBranch(\n\tbranch: string,\n\tbranches: NeonBranchSnapshot[],\n): NeonBranchSnapshot {\n\tconst match =\n\t\tbranches.find((b) => b.id === branch) ??\n\t\tbranches.find((b) => b.name === branch);\n\tif (match) return match;\n\tthrow new PlatformError(\n\t\tErrorCode.BranchNotFound,\n\t\t[\n\t\t\t`fetchEnv: branch ${JSON.stringify(branch)} not found on project (matched by id or name).`,\n\t\t\t`Existing branches: ${branches.map((b) => `${b.name} (${b.id})`).join(\", \")}.`,\n\t\t].join(\" \"),\n\t\t{\n\t\t\tdetails: {\n\t\t\t\tbranch,\n\t\t\t\tavailable: branches.map((b) => `${b.name} (${b.id})`),\n\t\t\t},\n\t\t},\n\t);\n}\n\nfunction pickRoleName(\n\troles: NeonRoleSnapshot[],\n\tbranch: NeonBranchSnapshot,\n\trequested: string | undefined,\n): string {\n\tif (requested) {\n\t\tif (!roles.some((r) => r.name === requested)) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.BranchNotFound,\n\t\t\t\t[\n\t\t\t\t\t`fetchEnv: role \"${requested}\" not found on branch ${branch.name} (${branch.id}).`,\n\t\t\t\t\t`Existing roles: ${roles.map((r) => r.name).join(\", \") || \"(none)\"}.`,\n\t\t\t\t].join(\" \"),\n\t\t\t\t{\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tbranchId: branch.id,\n\t\t\t\t\t\troleName: requested,\n\t\t\t\t\t\tavailableRoles: roles.map((r) => r.name),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\treturn requested;\n\t}\n\tif (roles.length === 0) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.BranchNotFound,\n\t\t\t[\n\t\t\t\t`fetchEnv: branch ${branch.name} (${branch.id}) has no roles.`,\n\t\t\t\t\"Create one via the Neon console or pass `roleName` explicitly.\",\n\t\t\t].join(\" \"),\n\t\t\t{ details: { branchId: branch.id } },\n\t\t);\n\t}\n\tif (roles.length === 1) return roles[0].name;\n\n\t// Multiple roles. Enabling Neon Auth / the Data API provisions the PostgREST roles\n\t// (authenticator/anonymous/authenticated) alongside the project owner, so a normal\n\t// branch ends up with >1 role even though only the owner backs a `DATABASE_URL`.\n\t// Default to Neon's owner role; if the project was created with a custom owner name,\n\t// fall back to the single role left after dropping the managed auth roles. Only a\n\t// genuinely ambiguous set (more than one app role) still asks the caller to choose.\n\tconst owner = roles.find((r) => r.name === NEON_DEFAULT_OWNER_ROLE);\n\tif (owner) return owner.name;\n\n\tconst appRoles = roles.filter((r) => !NEON_MANAGED_AUTH_ROLES.has(r.name));\n\tif (appRoles.length === 1) return appRoles[0].name;\n\n\tthrow new PlatformError(\n\t\tErrorCode.AmbiguousBranchAuth,\n\t\t[\n\t\t\t`fetchEnv: branch ${branch.name} (${branch.id}) has ${roles.length} roles and none is \"${NEON_DEFAULT_OWNER_ROLE}\"; cannot auto-pick.`,\n\t\t\t`Pass \\`roleName\\` explicitly. Available: ${roles.map((r) => r.name).join(\", \")}.`,\n\t\t].join(\" \"),\n\t\t{\n\t\t\tdetails: {\n\t\t\t\tbranchId: branch.id,\n\t\t\t\tavailableRoles: roles.map((r) => r.name),\n\t\t\t},\n\t\t},\n\t);\n}\n\nfunction pickDatabaseName(\n\tdatabases: NeonDatabaseSnapshot[],\n\tbranch: NeonBranchSnapshot,\n\trequested: string | undefined,\n): string {\n\tif (requested) {\n\t\tif (!databases.some((d) => d.name === requested)) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.BranchNotFound,\n\t\t\t\t[\n\t\t\t\t\t`fetchEnv: database \"${requested}\" not found on branch ${branch.name} (${branch.id}).`,\n\t\t\t\t\t`Existing databases: ${databases.map((d) => d.name).join(\", \") || \"(none)\"}.`,\n\t\t\t\t].join(\" \"),\n\t\t\t\t{\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tbranchId: branch.id,\n\t\t\t\t\t\tdatabaseName: requested,\n\t\t\t\t\t\tavailableDatabases: databases.map((d) => d.name),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\treturn requested;\n\t}\n\tif (databases.length === 0) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.BranchNotFound,\n\t\t\t[\n\t\t\t\t`fetchEnv: branch ${branch.name} (${branch.id}) has no databases.`,\n\t\t\t\t\"Create one via the Neon console or pass `databaseName` explicitly.\",\n\t\t\t].join(\" \"),\n\t\t\t{ details: { branchId: branch.id } },\n\t\t);\n\t}\n\n\t// Prefer Neon's default `neondb`. On the common \"added a second database\" branch this\n\t// auto-picks it, so a lone or `neondb`-including branch resolves without asking.\n\tconst neondb = databases.find((d) => d.name === NEON_DEFAULT_DATABASE);\n\tif (neondb) return neondb.name;\n\n\tif (databases.length === 1) return databases[0].name;\n\n\t// Several databases and no `neondb` to fall back on. Auto-picking any of them would be\n\t// perceived as random and is bad DX, so fail loudly and let the caller disambiguate.\n\tthrow new PlatformError(\n\t\tErrorCode.AmbiguousBranchAuth,\n\t\t[\n\t\t\t`fetchEnv: branch ${branch.name} (${branch.id}) has ${databases.length} databases and none is named \"${NEON_DEFAULT_DATABASE}\"; cannot auto-pick.`,\n\t\t\t`Rename one to \"${NEON_DEFAULT_DATABASE}\" or keep a single database on the branch (or, when calling fetchEnv directly, pass \\`databaseName\\`). Available: ${databases.map((d) => d.name).join(\", \")}.`,\n\t\t].join(\" \"),\n\t\t{\n\t\t\tdetails: {\n\t\t\t\tbranchId: branch.id,\n\t\t\t\tavailableDatabases: databases.map((d) => d.name),\n\t\t\t},\n\t\t},\n\t);\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 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 (`preview.buckets`). No network. */\nfunction configWantsStorage(config: Config): boolean {\n\treturn Object.keys(config.preview?.buckets ?? {}).length > 0;\n}\n\n/** Whether a **static** policy enables the AI Gateway (`preview.aiGateway`). No network. */\nfunction configWantsAiGateway(config: Config): boolean {\n\treturn isServiceEnabledInput(config.preview?.aiGateway);\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 (top-level `config.auth` / `config.dataApi`), so it reads those directly without\n * 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.preview.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.\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>;\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\tconst C extends Config,\n\tconst S extends FunctionSlugOf<C>,\n>(config: C, scope: S): NeonEnv<C> & NeonFunctionEnv<C, S>;\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 (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 = config.preview?.functions?.[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 preview.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\"Inject them via one of:\",\n\t\t\t\t\" - `neon dev` / `neon-env run -- <your dev command>` (wraps the command with the vars injected)\",\n\t\t\t\t\" - your hosting platform's Neon integration (Vercel, Fly, Railway, …)\",\n\t\t\t\t\" - for the `function` namespace: deploy the function (`neon deploy` / `config apply`) so its env is uploaded.\",\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\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_AUTH_BASE_URL: [\"auth\", \"baseUrl\"],\n\tNEON_AUTH_JWKS_URL: [\"auth\", \"jwksUrl\"],\n\tNEON_DATA_API_URL: [\"dataApi\", \"url\"],\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, Record<string, string>> {\n\tconst issues: string[] = [];\n\tconst result: Record<string, Record<string, string>> = {};\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\"Inject them via one of:\",\n\t\t\t\t\" - `neon dev` / `neon-env run -- <your dev command>` (wraps the command with the vars injected)\",\n\t\t\t\t\" - your hosting platform's Neon integration (Vercel, Fly, Railway, …)\",\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\n// ───────────────────────── env-var mapping helpers ─────────────────────────\n\n/**\n * Project a fully-resolved {@link NeonEnv} into the OS-level `{ KEY: value }` pairs used\n * for cross-process transport. Named after the web-platform `.entries()` convention\n * (`URLSearchParams` / `Headers` / `FormData`); returns a `Record` rather than an\n * iterator of tuples since that's the shape env injection needs (wrap with\n * `Object.entries(...)` if you want literal `[key, value]` pairs). Used by `neon-env run`\n * to inject the vars into a subprocess's `process.env`.\n *\n * Walks the value at runtime so it works for any `NeonEnv<C>` regardless of which\n * conditional namespaces are present.\n */\nexport function toEntries(env: NeonEnv<Config>): Record<string, string> {\n\tconst out: Record<string, string> = {\n\t\t[NEON_ENV_VAR_KEYS.postgres.databaseUrl]: env.postgres.databaseUrl,\n\t\t[NEON_ENV_VAR_KEYS.postgres.databaseUrlUnpooled]:\n\t\t\tenv.postgres.databaseUrlUnpooled,\n\t};\n\tif (env.branch) {\n\t\tout[NEON_ENV_VAR_KEYS.branch.name] = env.branch.name;\n\t}\n\tconst withAuth = env as { auth?: NeonAuthEnv };\n\tif (withAuth.auth) {\n\t\tout[NEON_ENV_VAR_KEYS.auth.baseUrl] = withAuth.auth.baseUrl;\n\t\tout[NEON_ENV_VAR_KEYS.auth.jwksUrl] = withAuth.auth.jwksUrl;\n\t}\n\tconst withDataApi = env as { dataApi?: NeonDataApiEnv };\n\tif (withDataApi.dataApi) {\n\t\tout[NEON_ENV_VAR_KEYS.dataApi.url] = withDataApi.dataApi.url;\n\t}\n\tconst withStorage = env as { storage?: NeonStorageEnv };\n\tif (withStorage.storage) {\n\t\tconst s = withStorage.storage;\n\t\tconst keys = NEON_ENV_VAR_KEYS.storage;\n\t\tout[keys.accessKeyId] = s.accessKeyId;\n\t\tout[keys.secretAccessKey] = s.secretAccessKey;\n\t\tout[keys.endpoint] = s.endpoint;\n\t\tout[keys.region] = s.region;\n\t}\n\tconst withAiGateway = env as { aiGateway?: NeonAiGatewayEnv };\n\tif (withAiGateway.aiGateway) {\n\t\tconst keys = NEON_ENV_VAR_KEYS.aiGateway;\n\t\tconst ai = withAiGateway.aiGateway;\n\t\t// Neon-branded vars only: the bearer and the bare branch gateway host\n\t\t// (scheme://host, no path) — the @neon/ai-sdk-provider appends the\n\t\t// dialect route (/v1, /openai/v1, /anthropic/v1) itself (https://github.com/vercel/ai/pull/15997).\n\t\tout[keys.apiKey] = ai.apiKey;\n\t\tout[keys.baseUrl] = ai.baseUrl;\n\t}\n\treturn out;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"env.js","names":[],"sources":["../../src/lib/env.ts"],"sourcesContent":["import {\n\ttype Config,\n\ttype CredentialScope,\n\tcreateNeonApiFromOptions,\n\tderiveCredentialScopes,\n\tErrorCode,\n\ttype NeonApi,\n\ttype NeonBranchSnapshot,\n\ttype NeonDatabaseSnapshot,\n\ttype NeonRoleSnapshot,\n\tPlatformError,\n\ttype ResolvedPreviewConfig,\n\tresolveConfig,\n\ttype ServiceToggleInput,\n} from \"@neon/config/v1\";\nimport { z } from \"zod\";\n\n/**\n * Mapping between the {@link NeonEnv} property paths and the OS-level env-var keys used\n * for cross-process transport (via `.env` files, `env run -- <cmd>`, or anything else\n * that talks to `process.env`).\n *\n * Each top-level key here is a {@link NeonEnv} namespace; the inner record maps the\n * camelCase property names exposed to TypeScript to the UPPER_SNAKE env-var names used\n * by the OS. Keep this in sync with {@link postgresEnvSchema} / {@link authEnvSchema} /\n * {@link dataApiEnvSchema}.\n */\n/**\n * Neon's default branch owner role, created with every project. This is the role a\n * `DATABASE_URL` should connect as.\n */\nconst NEON_DEFAULT_OWNER_ROLE = \"neondb_owner\";\n\n/**\n * Neon's default database, created with every project. When a branch has several databases\n * and none was requested, this is preferred for the `DATABASE_URL` so the common case (a\n * user added a second database next to `neondb`) auto-picks without asking.\n */\nconst NEON_DEFAULT_DATABASE = \"neondb\";\n\n/**\n * Roles Neon provisions for the Auth / Data API (PostgREST) stack. They exist to back\n * RLS-scoped Data API requests authenticated by JWT — never to hold a `DATABASE_URL` —\n * so they're skipped when auto-picking the connection role. Enabling Neon Auth or the\n * Data API (`neon config apply`) adds these next to the owner role, which is why a plain\n * branch routinely reports more than one role.\n */\nconst NEON_MANAGED_AUTH_ROLES: ReadonlySet<string> = new Set([\n\t\"authenticator\",\n\t\"anonymous\",\n\t\"authenticated\",\n]);\n\nexport const NEON_ENV_VAR_KEYS = {\n\t/**\n\t * Branch identity. `NEON_BRANCH` carries the branch **name** and is injected into the\n\t * Neon Functions runtime on every branch (including the default) by default. `env pull` /\n\t * `neon dev` / `neon-env run` emit it too so local dev mirrors the deployed runtime.\n\t */\n\tbranch: {\n\t\tname: \"NEON_BRANCH\",\n\t},\n\tpostgres: {\n\t\tdatabaseUrl: \"DATABASE_URL\",\n\t\tdatabaseUrlUnpooled: \"DATABASE_URL_UNPOOLED\",\n\t},\n\tauth: {\n\t\tbaseUrl: \"NEON_AUTH_BASE_URL\",\n\t\tjwksUrl: \"NEON_AUTH_JWKS_URL\",\n\t},\n\tdataApi: {\n\t\turl: \"NEON_DATA_API_URL\",\n\t},\n\t/**\n\t * Object storage (Preview). The S3 SDKs read `AWS_*` from their standard config chain, so\n\t * a branch credential + `neon dev` / `env pull` makes object storage work from env alone.\n\t * `region` is injected under the SDK-standard `AWS_REGION`.\n\t */\n\tstorage: {\n\t\taccessKeyId: \"AWS_ACCESS_KEY_ID\",\n\t\tsecretAccessKey: \"AWS_SECRET_ACCESS_KEY\",\n\t\tendpoint: \"AWS_ENDPOINT_URL_S3\",\n\t\tregion: \"AWS_REGION\",\n\t},\n\t/**\n\t * AI Gateway (Preview). Exposed under the Neon-branded env vars the deployed Functions\n\t * runtime injects: `apiKey` is the minted credential's bearer (`NEON_AI_GATEWAY_TOKEN`)\n\t * and `baseUrl` is the bare branch gateway host (`NEON_AI_GATEWAY_BASE_URL`,\n\t * `scheme://host`, no path). Clients like `@neon/ai-sdk-provider` read these and append the\n\t * dialect route (`/v1`, `/openai/v1`, `/anthropic/v1`) themselves (https://github.com/vercel/ai/pull/15997).\n\t */\n\taiGateway: {\n\t\tapiKey: \"NEON_AI_GATEWAY_TOKEN\",\n\t\tbaseUrl: \"NEON_AI_GATEWAY_BASE_URL\",\n\t},\n} as const;\n\n/**\n * Branch identity for the resolved branch. Always present on a `fetchEnv` result (the branch\n * name is always known); on a `parseEnv` result it's present only when `NEON_BRANCH` was\n * injected into `process.env` (the Functions runtime injects it by default, as do `neon dev` /\n * `neon-env run` / `env pull`). `name` is the branch **name** (e.g. `main`, `preview/foo`).\n */\nexport interface NeonBranchEnv {\n\tname: string;\n}\n\n/** Per-namespace inner shapes. Exposed so consumers can name the parts independently. */\nexport interface NeonPostgresEnv {\n\t/**\n\t * Pooled connection string (via Neon's PgBouncer pooler). The right default for\n\t * serverless drivers (`@neondatabase/serverless`, edge runtimes, Postgres.js, …).\n\t */\n\tdatabaseUrl: string;\n\t/**\n\t * Direct (unpooled) connection string. Use this when you need session-level\n\t * features (`LISTEN`/`NOTIFY`, prepared statements across calls, transactions\n\t * spanning round-trips) that PgBouncer's transaction-mode pooling drops.\n\t */\n\tdatabaseUrlUnpooled: string;\n}\n\n/**\n * Bits of a Neon Auth integration for the resolved branch. Only present on `NeonEnv`\n * when the branch policy enables `auth`.\n *\n * Neon Auth exposes the `baseUrl` (which doubles as the publishable client identifier) and\n * the `jwksUrl` used to verify tokens it issues. `fetchEnv` reads both from the live\n * integration; `parseEnv` reads them from `process.env` (`NEON_AUTH_BASE_URL` /\n * `NEON_AUTH_JWKS_URL`).\n */\nexport interface NeonAuthEnv {\n\tbaseUrl: string;\n\t/** JWKS URL for verifying tokens issued by Neon Auth (`NEON_AUTH_JWKS_URL`). */\n\tjwksUrl: string;\n}\n\n/** Bits of a Neon Data API integration. Only present when the branch policy enables it. */\nexport interface NeonDataApiEnv {\n\turl: string;\n}\n\n/**\n * S3-compatible object-storage access for the branch (Preview). Present on `NeonEnv` only\n * when the policy declares `preview.buckets`. Combines a minted branch credential's access\n * keys (`accessKeyId` = the credential's full token id, e.g. `nak_live_…`, which is what the\n * storage gateway authenticates against; `secretAccessKey` = its\n * `s3_secret_access_key`) with the branch's non-secret connection details\n * (`endpoint`/`region`, from `GET .../storage`). Projects to the AWS SDK's\n * standard config env (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_ENDPOINT_URL_S3`,\n * `AWS_REGION`) so the S3 client works from env alone. Neon's storage gateway always\n * requires path-style addressing, so set `forcePathStyle: true` on your S3 client.\n */\nexport interface NeonStorageEnv {\n\taccessKeyId: string;\n\tsecretAccessKey: string;\n\t/** S3-compatible endpoint URL for the branch. */\n\tendpoint: string;\n\t/** AWS region string (e.g. `us-east-2`). Injected as `AWS_REGION`. */\n\tregion: string;\n}\n\n/**\n * AI Gateway access for the branch (Preview). Present on `NeonEnv` only when the policy\n * enables `preview.aiGateway`. `apiKey` is the minted credential's bearer (`api_token`);\n * `baseUrl` is the bare branch-scoped gateway host\n * (`https://<branchId>-api.ai.<region>.…`, no path). Projects to the Neon-branded env\n * (`NEON_AI_GATEWAY_TOKEN`, `NEON_AI_GATEWAY_BASE_URL`); clients like `@neon/ai-sdk-provider`\n * append the dialect route (`/v1`, `/openai/v1`, `/anthropic/v1`) themselves.\n */\nexport interface NeonAiGatewayEnv {\n\tapiKey: string;\n\tbaseUrl: string;\n}\n\n/**\n * Empty record alias used as the \"false\" branch of the conditional namespace adds below.\n * `Record<never, never>` is the no-op for intersection — the cleaner alternative to `{}`,\n * which biome rejects (it means \"any non-null\", not \"empty object\").\n */\ntype NoNamespace = Record<never, never>;\n\n/**\n * Resolve a **static** service toggle (the value of `config.auth` / `config.dataApi`) to a\n * type-level boolean. The whole-thing wrapping (`[T] extends […]`) turns off distribution\n * so a union/`undefined` is checked as one unit:\n *\n * - `false` / `{ enabled: false }` / `undefined` → `false`\n * - `true` / `{ enabled: true }` / any other object (`{}`, `{ enabled?: boolean }`) → `true`\n * (a present toggle defaults to enabled)\n * - the bare `boolean | ServiceToggle | undefined` (the default `Config` param, no literal\n * info) → `false`, so an untyped policy yields just `{ postgres }`.\n */\ntype ServiceOn<T> = [T] extends [false]\n\t? false\n\t: [T] extends [{ enabled: false }]\n\t\t? false\n\t\t: [T] extends [undefined]\n\t\t\t? false\n\t\t\t: [T] extends [true]\n\t\t\t\t? true\n\t\t\t\t: [T] extends [{ enabled: true }]\n\t\t\t\t\t? true\n\t\t\t\t\t: [T] extends [object]\n\t\t\t\t\t\t? true\n\t\t\t\t\t\t: false;\n\n/** True when `T` has at least one known key; `false` for `{}` / `never`. */\ntype HasKeys<T> = [keyof T] extends [never] ? false : true;\n\n/**\n * Whether the policy's **static** `preview` block declares at least one object-storage bucket\n * (`preview.buckets`). Drives whether {@link NeonEnv} carries the `storage` namespace.\n *\n * The leading `[never]` guard is load-bearing: when a policy has no `preview` at all,\n * `NonNullable<C[\"preview\"]>` is `never`, and without the guard the `extends { … }` probe\n * below would vacuously match (everything extends `never`-derived shapes) and `HasKeys<never>`\n * would resolve `true`, wrongly adding the namespace. The guard short-circuits to `false`.\n */\ntype HasBuckets<C extends Config> = [NonNullable<C[\"preview\"]>] extends [never]\n\t? false\n\t: NonNullable<C[\"preview\"]> extends { buckets: infer B }\n\t\t? HasKeys<NonNullable<B>>\n\t\t: false;\n\n/**\n * Whether the policy's **static** `preview` block enables the AI Gateway\n * (`preview.aiGateway`). Drives whether {@link NeonEnv} carries the `aiGateway` namespace.\n *\n * The leading `[never]` guard is load-bearing for the same reason as {@link HasBuckets}: when\n * a policy has no `preview`, `NonNullable<C[\"preview\"]>` is `never`, and a naked `never` in the\n * `extends` below would *distribute* (collapsing the result — and the whole `NeonEnv`\n * intersection — to `never`). The tuple-wrapped guard short-circuits that to `false`.\n */\ntype AiGatewayOn<C extends Config> = [NonNullable<C[\"preview\"]>] extends [never]\n\t? false\n\t: NonNullable<C[\"preview\"]> extends { aiGateway: infer A }\n\t\t? ServiceOn<NonNullable<A>>\n\t\t: false;\n\n/**\n * Static, namespaced shape of `fetchEnv` / `parseEnv`'s return value. Generic over the\n * {@link Config} so the type system knows which optional namespaces are present.\n *\n * Because the secret-bearing toggles now live in the **static** top-level `config.auth` /\n * `config.dataApi` (not inside a per-branch closure), the namespace presence is a direct\n * read of those fields — no union-across-branches, no default-config escape hatch:\n *\n * - `postgres` is always present.\n * - `auth` is added iff `config.auth` is statically enabled.\n * - `dataApi` is added iff `config.dataApi` is statically enabled.\n * - `storage` is added iff `config.preview.buckets` declares at least one bucket.\n * - `aiGateway` is added iff `config.preview.aiGateway` is statically enabled.\n */\nexport type NeonEnv<C extends Config = Config> = {\n\tpostgres: NeonPostgresEnv;\n\t/**\n\t * Branch identity (`NEON_BRANCH`). Optional because `parseEnv` only surfaces it when the\n\t * var was injected; `fetchEnv` always populates it.\n\t */\n\tbranch?: NeonBranchEnv;\n} & (ServiceOn<NonNullable<C[\"auth\"]>> extends true\n\t? { auth: NeonAuthEnv }\n\t: NoNamespace) &\n\t(ServiceOn<NonNullable<C[\"dataApi\"]>> extends true\n\t\t? { dataApi: NeonDataApiEnv }\n\t\t: NoNamespace) &\n\t(HasBuckets<C> extends true ? { storage: NeonStorageEnv } : NoNamespace) &\n\t(AiGatewayOn<C> extends true\n\t\t? { aiGateway: NeonAiGatewayEnv }\n\t\t: NoNamespace);\n\n/** The static `preview.functions` record of a config, or an empty record when absent. */\ntype PreviewFunctionsOf<C extends Config> =\n\tNonNullable<C[\"preview\"]> extends {\n\t\tfunctions: infer F;\n\t}\n\t\t? F\n\t\t: Record<never, never>;\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 `preview.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 key filtering ─────────────────────────\n\n/**\n * OS-level env-var keys grouped by the {@link NeonEnv} namespace they populate. Only the\n * **input** vars `parseEnv` validates are listed — the output-only aliases in\n * {@link NEON_ENV_VAR_KEYS} (`NEON_AI_GATEWAY_TOKEN`, …) are intentionally absent, so they\n * are not selectable in a `parseEnv(config, keys)` filter. Keep in sync with\n * {@link EnvKeyToProp}.\n */\ninterface EnvKeysByNamespace {\n\tpostgres: \"DATABASE_URL\" | \"DATABASE_URL_UNPOOLED\";\n\tauth: \"NEON_AUTH_BASE_URL\" | \"NEON_AUTH_JWKS_URL\";\n\tdataApi: \"NEON_DATA_API_URL\";\n\tstorage:\n\t\t| \"AWS_ACCESS_KEY_ID\"\n\t\t| \"AWS_SECRET_ACCESS_KEY\"\n\t\t| \"AWS_ENDPOINT_URL_S3\"\n\t\t| \"AWS_REGION\";\n\taiGateway: \"NEON_AI_GATEWAY_TOKEN\" | \"NEON_AI_GATEWAY_BASE_URL\";\n}\n\n/** The {@link NeonEnv} namespace interface backing each namespace key. */\ninterface NamespaceEnv {\n\tpostgres: NeonPostgresEnv;\n\tauth: NeonAuthEnv;\n\tdataApi: NeonDataApiEnv;\n\tstorage: NeonStorageEnv;\n\taiGateway: NeonAiGatewayEnv;\n}\n\n/** OS-level env-var key → the camelCase property it sets on its namespace object. */\ninterface EnvKeyToProp {\n\tDATABASE_URL: \"databaseUrl\";\n\tDATABASE_URL_UNPOOLED: \"databaseUrlUnpooled\";\n\tNEON_AUTH_BASE_URL: \"baseUrl\";\n\tNEON_AUTH_JWKS_URL: \"jwksUrl\";\n\tNEON_DATA_API_URL: \"url\";\n\tAWS_ACCESS_KEY_ID: \"accessKeyId\";\n\tAWS_SECRET_ACCESS_KEY: \"secretAccessKey\";\n\tAWS_ENDPOINT_URL_S3: \"endpoint\";\n\tAWS_REGION: \"region\";\n\tNEON_AI_GATEWAY_TOKEN: \"apiKey\";\n\tNEON_AI_GATEWAY_BASE_URL: \"baseUrl\";\n}\n\n/**\n * The OS-level env-var keys selectable for a given policy: the union of input vars across\n * exactly the namespaces {@link NeonEnv}<C> carries. Drives the typesafe autocomplete of the\n * `keys` filter — selecting a var from a namespace the policy does not enable is a type error\n * (e.g. `NEON_AUTH_BASE_URL` is only offered once the policy turns on `auth`).\n */\nexport type SelectableEnvKey<C extends Config> =\n\tEnvKeysByNamespace[keyof NeonEnv<C> & keyof EnvKeysByNamespace];\n\n/**\n * The result shape of a **filtered** `parseEnv(config, keys)` call: the namespaced\n * {@link NeonEnv} restricted to exactly the selected OS-level keys `K`. Namespaces with no\n * selected key are dropped, and within a kept namespace only the selected properties survive\n * — selecting just `[\"DATABASE_URL\"]` yields `{ postgres: { databaseUrl: string } }`, with no\n * `databaseUrlUnpooled`.\n *\n * The policy gating lives on the `parseEnv` overload (which binds `K` to\n * {@link SelectableEnvKey}); this type only needs the selection, so it takes a bare\n * `K extends string` and filters with `Extract`. The outer mapped type's `as` clause drops\n * any namespace whose intersection with the selection is empty (`[…] extends [never]`,\n * tuple-wrapped to switch off distribution); the inner one re-keys each selected OS var to its\n * camelCase property and looks the value type up on the canonical namespace interface, so it\n * stays correct if a field ever stops being a plain `string`.\n */\nexport type FilteredNeonEnv<K extends string> = {\n\t[N in keyof EnvKeysByNamespace as [\n\t\tExtract<K, EnvKeysByNamespace[N]>,\n\t] extends [never]\n\t\t? never\n\t\t: N]: {\n\t\t[P in Extract<K, EnvKeysByNamespace[N]> as EnvKeyToProp[P &\n\t\t\tkeyof EnvKeyToProp]]: NamespaceEnv[N][EnvKeyToProp[P &\n\t\t\tkeyof EnvKeyToProp] &\n\t\t\tkeyof NamespaceEnv[N]];\n\t};\n};\n\nexport interface FetchEnvOptions {\n\t/**\n\t * Neon project id. **Required** — the management API addresses branches through their\n\t * project. Resolve it in your CLI (e.g. neonctl) and pass it in.\n\t */\n\tprojectId: string;\n\t/**\n\t * Neon branch — its **name** (e.g. `main`) or its id (`br-…`). **Required** (or pass the\n\t * legacy {@link FetchEnvOptions.branchId}). Resolved against the project's branches by\n\t * id first, then by name, so either form works.\n\t */\n\tbranch?: string;\n\t/**\n\t * @deprecated Legacy id-only field. Prefer {@link FetchEnvOptions.branch}, which accepts\n\t * a branch name or id. Still honored for backward compatibility; ignored when `branch`\n\t * is set.\n\t */\n\tbranchId?: string;\n\t/**\n\t * Neon API key. Resolved via the standard chain (option → `NEON_API_KEY` →\n\t * `~/.config/neonctl/credentials.json`) when omitted. Ignored when a custom `api`\n\t * is supplied.\n\t */\n\tapiKey?: string;\n\t/**\n\t * Neon **management** API base URL (not the Auth base URL). Falls back to\n\t * `NEON_API_HOST`, then production. Ignored when a custom `api` is supplied.\n\t */\n\tapiHost?: string;\n\t/**\n\t * Inject a custom NeonApi adapter. Primarily used by tests; production callers can rely\n\t * on the default real adapter built from `apiKey`.\n\t */\n\tapi?: NeonApi;\n\t/**\n\t * Role name to fetch credentials for. When omitted, the connection role is auto-picked:\n\t * the only role on the branch, else Neon's default owner (`neondb_owner`), else the\n\t * single role left after dropping the managed Auth/Data API roles\n\t * (`authenticator`/`anonymous`/`authenticated`). Throws {@link PlatformError} with\n\t * `PLATFORM_AMBIGUOUS_BRANCH_AUTH` only when more than one app role remains.\n\t */\n\troleName?: string;\n\t/**\n\t * Database name. When omitted, it is auto-picked: Neon's default `neondb` if present,\n\t * else the only database on the branch. Throws {@link PlatformError} with\n\t * `PLATFORM_AMBIGUOUS_BRANCH_AUTH` when the branch has several databases and none is\n\t * `neondb` (pass `databaseName` to disambiguate), and `PLATFORM_BRANCH_NOT_FOUND` when\n\t * the branch has no databases or the requested `databaseName` does not exist.\n\t */\n\tdatabaseName?: string;\n\t/**\n\t * Env source used for one-time Auth keys that cannot be refetched after integration\n\t * creation. Defaults to `process.env`; callers may layer values from `.env.local`.\n\t */\n\tenv?: NodeJS.ProcessEnv;\n}\n\n/**\n * Resolve the project + branch this process should target, then fetch live Neon\n * connection strings for that branch over the network. Async — calls the Neon API.\n *\n * Use this from build scripts and the `neon-env run` command, where top-level await is\n * fine. For application code that needs a synchronous bootstrap (most frameworks: Drizzle\n * config, Next.js, Vite, etc.), inject env vars via `neon-env run -- <cmd>` and use\n * {@link parseEnv} instead — same {@link NeonEnv} shape, but a sync call against\n * `process.env`.\n *\n * Filesystem- and env-agnostic: pass `projectId` and the target `branch` (name or id)\n * explicitly (resolve them in your CLI, e.g. neonctl).\n *\n * ```ts\n * import config from \"../neon\";\n * import { fetchEnv } from \"@neon/env\";\n *\n * const env = await fetchEnv(config, { projectId: \"patient-art-12345\", branch: \"main\" });\n * const db = drizzle(neon(env.postgres.databaseUrl), { schema });\n * ```\n *\n * The package does **not** mutate `process.env` or the filesystem itself.\n */\nexport async function fetchEnv<const C extends Config>(\n\tconfig: C,\n\toptions: FetchEnvOptions,\n): Promise<NeonEnv<C>> {\n\tconst api = options.api ?? createApiFromOptions(options);\n\tconst projectId = options.projectId;\n\n\tconst branches = await api.listBranches(projectId);\n\tif (branches.length === 0) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.BranchNotFound,\n\t\t\t[\n\t\t\t\t`fetchEnv: project ${projectId} has no branches.`,\n\t\t\t\t\"Deploy your neon.ts policy (or create a branch) first, or pick a different project id.\",\n\t\t\t].join(\" \"),\n\t\t\t{ details: { projectId } },\n\t\t);\n\t}\n\n\tconst branchRef = options.branch ?? options.branchId;\n\tif (!branchRef) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.BranchNotFound,\n\t\t\t[\n\t\t\t\t\"fetchEnv: no branch provided.\",\n\t\t\t\t\"Pass `branch` with a branch name (e.g. `main`) or id (`br-…`).\",\n\t\t\t].join(\" \"),\n\t\t\t{ details: { projectId } },\n\t\t);\n\t}\n\tconst branch = resolveBranch(branchRef, branches);\n\tconst desired = resolveConfig(config, {\n\t\tname: branch.name,\n\t\tid: branch.id,\n\t\texists: true,\n\t\t...(branch.parentId ? { parentId: branch.parentId } : {}),\n\t\tisDefault: branch.isDefault,\n\t\tisProtected: branch.protected,\n\t\t...(branch.expiresAt ? { expiresAt: branch.expiresAt } : {}),\n\t});\n\n\tconst [roles, databases] = await Promise.all([\n\t\tapi.listBranchRoles(projectId, branch.id),\n\t\tapi.listBranchDatabases(projectId, branch.id),\n\t]);\n\n\tconst roleName = pickRoleName(roles, branch, options.roleName);\n\tconst databaseName = pickDatabaseName(\n\t\tdatabases,\n\t\tbranch,\n\t\toptions.databaseName,\n\t);\n\n\t// Fan out: always fetch both Postgres URIs. Conditionally fetch auth + dataApi based\n\t// on the branch policy. Auth key fields are only returned at integration creation time;\n\t// for Better Auth they may legitimately be empty, so absence in the local env becomes\n\t// empty string values while still emitting the required variable names.\n\tconst wantsAuth = desired.authEnabled;\n\tconst wantsDataApi = desired.dataApiEnabled;\n\n\tconst [pooled, unpooled, authSnapshot, dataApiSnapshot] = await Promise.all(\n\t\t[\n\t\t\tapi.getConnectionUri(projectId, {\n\t\t\t\tbranchId: branch.id,\n\t\t\t\tdatabaseName,\n\t\t\t\troleName,\n\t\t\t\tpooled: true,\n\t\t\t}),\n\t\t\tapi.getConnectionUri(projectId, {\n\t\t\t\tbranchId: branch.id,\n\t\t\t\tdatabaseName,\n\t\t\t\troleName,\n\t\t\t\tpooled: false,\n\t\t\t}),\n\t\t\twantsAuth\n\t\t\t\t? api.getNeonAuth(projectId, branch.id)\n\t\t\t\t: Promise.resolve(null),\n\t\t\twantsDataApi\n\t\t\t\t? api.getNeonDataApi(projectId, branch.id, databaseName)\n\t\t\t\t: Promise.resolve(null),\n\t\t],\n\t);\n\n\tconst result: Record<string, unknown> = {\n\t\tpostgres: {\n\t\t\tdatabaseUrl: pooled.uri,\n\t\t\tdatabaseUrlUnpooled: unpooled.uri,\n\t\t},\n\t\t// Branch identity, mirroring what the Functions runtime injects on every branch.\n\t\t// Surfaced as `NEON_BRANCH` so local dev (`neon dev` / `neon-env run` / `env pull`)\n\t\t// matches the deployed runtime. Uses the branch name.\n\t\tbranch: { name: branch.name } satisfies NeonBranchEnv,\n\t};\n\n\tif (wantsAuth) {\n\t\tif (!authSnapshot) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.NotFound,\n\t\t\t\t[\n\t\t\t\t\t`fetchEnv: branch policy enables auth but no Neon Auth integration is enabled on branch ${branch.name} (${branch.id}).`,\n\t\t\t\t\t\"Enable it via `apply(config, { projectId, branchId })` (or `npx neonctl …`), in the Neon Console — then re-run fetchEnv. Or return auth.enabled=false.\",\n\t\t\t\t].join(\" \"),\n\t\t\t\t{\n\t\t\t\t\tdetails: { projectId, branchId: branch.id },\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\tconst envSource = options.env ?? process.env;\n\t\tconst baseUrl = resolveAuthBaseUrl(authSnapshot.baseUrl, envSource);\n\t\tconst jwksUrl = resolveAuthJwksUrl(authSnapshot.jwksUrl, envSource);\n\t\tresult.auth = { baseUrl, jwksUrl } satisfies NeonAuthEnv;\n\t}\n\n\tif (wantsDataApi) {\n\t\tif (!dataApiSnapshot) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.NotFound,\n\t\t\t\t[\n\t\t\t\t\t`fetchEnv: branch policy enables dataApi but no Data API integration is enabled on branch ${branch.name} (${branch.id}) database ${databaseName}.`,\n\t\t\t\t\t\"Enable it via `apply(config, { projectId, branchId })` or in the Neon Console — then re-run fetchEnv. Or return dataApi.enabled=false.\",\n\t\t\t\t].join(\" \"),\n\t\t\t\t{\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tprojectId,\n\t\t\t\t\t\tbranchId: branch.id,\n\t\t\t\t\t\tdatabaseName,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\tresult.dataApi = { url: dataApiSnapshot.url } satisfies NeonDataApiEnv;\n\t}\n\n\t// Object storage + AI Gateway (Preview). A single branch credential is minted (once) to\n\t// back whichever of these the policy enables; functions never force a credential but ride\n\t// along on its scopes. None of this runs when the policy enables neither, so the\n\t// Postgres / Auth / Data API path never touches the credentials/storage endpoints (and\n\t// keeps working on production, where they may not exist yet).\n\tconst wantsStorage = (desired.preview?.buckets.length ?? 0) > 0;\n\tconst wantsAiGateway = desired.preview?.aiGatewayEnabled ?? false;\n\tif (wantsStorage || wantsAiGateway) {\n\t\tconst secrets = await resolveCredentialSecrets({\n\t\t\tapi,\n\t\t\tprojectId,\n\t\t\tbranchId: branch.id,\n\t\t\tbranchName: branch.name,\n\t\t\tscopes: previewCredentialScopes(desired.preview),\n\t\t\tenv: options.env ?? process.env,\n\t\t\tneedStorage: wantsStorage,\n\t\t\tneedApiToken: wantsAiGateway,\n\t\t});\n\t\tif (wantsStorage) {\n\t\t\tconst storage = await api.getProjectBranchStorage(\n\t\t\t\tprojectId,\n\t\t\t\tbranch.id,\n\t\t\t);\n\t\t\tif (!storage) {\n\t\t\t\tthrow new PlatformError(\n\t\t\t\t\tErrorCode.NotFound,\n\t\t\t\t\t[\n\t\t\t\t\t\t`fetchEnv: branch policy declares object storage (preview.buckets) but storage is not enabled on branch ${branch.name} (${branch.id}).`,\n\t\t\t\t\t\t\"Enable it via `apply(config, { projectId, branchId })` (or in the Neon Console) — then re-run fetchEnv. Or remove preview.buckets.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\t{ details: { projectId, branchId: branch.id } },\n\t\t\t\t);\n\t\t\t}\n\t\t\tresult.storage = {\n\t\t\t\taccessKeyId: secrets.accessKeyId,\n\t\t\t\tsecretAccessKey: secrets.secretAccessKey,\n\t\t\t\tendpoint: storage.s3Endpoint,\n\t\t\t\tregion: storage.region,\n\t\t\t} satisfies NeonStorageEnv;\n\t\t}\n\t\tif (wantsAiGateway) {\n\t\t\tresult.aiGateway = {\n\t\t\t\tapiKey: secrets.apiToken,\n\t\t\t\t// Bare branch-scoped gateway host derived from the branch's connection URI —\n\t\t\t\t// not the control-plane API origin (which doesn't serve the gateway). Clients\n\t\t\t\t// append the dialect route (/v1, /openai/v1, /anthropic/v1) themselves.\n\t\t\t\tbaseUrl: aiGatewayBaseUrl(branch.id, unpooled.uri),\n\t\t\t} satisfies NeonAiGatewayEnv;\n\t\t}\n\t}\n\n\treturn result as NeonEnv<C>;\n}\n\n/**\n * Scopes the branch credential should carry for a resolved branch policy. Only object storage\n * and the AI Gateway *require* a credential; functions never force one (they have no credential\n * of their own), but `functions:invoke` is added to the scope set when a credential is already\n * being minted for storage / the AI Gateway, so the one credential can invoke the branch's\n * functions too. Returns `[]` only when nothing credential-bearing is enabled.\n */\nfunction previewCredentialScopes(\n\tpreview: ResolvedPreviewConfig | undefined,\n): CredentialScope[] {\n\tif (!preview) return [];\n\tconst storage = preview.buckets.length > 0;\n\tconst aiGateway = preview.aiGatewayEnabled;\n\tif (!storage && !aiGateway) return [];\n\treturn deriveCredentialScopes({\n\t\tstorage,\n\t\taiGateway,\n\t\tfunctions: preview.functions.length > 0,\n\t});\n}\n\n/**\n * Resolve the branch credential's secrets, reusing the ones already in the env source when\n * present and minting a fresh `user` credential otherwise. The Neon API returns `api_token` /\n * `s3_secret_access_key` exactly once at mint time, so the persisted copies (e.g. in\n * `.env.local`, surfaced as `NEON_AI_GATEWAY_TOKEN` / `AWS_SECRET_ACCESS_KEY`) are the only way to\n * recover them — exactly how one-time Auth keys are round-tripped. Reuse is presence-based\n * (no extra bookkeeping vars): if every secret the enabled features need is already present,\n * reuse it; otherwise mint one credential covering all currently-needed scopes.\n */\nasync function resolveCredentialSecrets(args: {\n\tapi: NeonApi;\n\tprojectId: string;\n\tbranchId: string;\n\tbranchName: string;\n\tscopes: CredentialScope[];\n\tenv: NodeJS.ProcessEnv;\n\tneedStorage: boolean;\n\tneedApiToken: boolean;\n}): Promise<{\n\taccessKeyId: string;\n\tsecretAccessKey: string;\n\tapiToken: string;\n}> {\n\tconst sKeys = NEON_ENV_VAR_KEYS.storage;\n\tconst aKeys = NEON_ENV_VAR_KEYS.aiGateway;\n\tconst haveStorage =\n\t\t!args.needStorage ||\n\t\tBoolean(args.env[sKeys.accessKeyId] && args.env[sKeys.secretAccessKey]);\n\tconst haveApiToken = !args.needApiToken || Boolean(args.env[aKeys.apiKey]);\n\tif (haveStorage && haveApiToken) {\n\t\treturn {\n\t\t\taccessKeyId: args.env[sKeys.accessKeyId] ?? \"\",\n\t\t\tsecretAccessKey: args.env[sKeys.secretAccessKey] ?? \"\",\n\t\t\tapiToken: args.env[aKeys.apiKey] ?? \"\",\n\t\t};\n\t}\n\tconst minted = await args.api.createCredential(\n\t\targs.projectId,\n\t\targs.branchId,\n\t\t{\n\t\t\tscopes: args.scopes,\n\t\t\tprincipalType: \"user\",\n\t\t\tname: `neon-env ${args.branchName}`,\n\t\t},\n\t);\n\treturn {\n\t\t// The storage gateway authenticates against the full token id (e.g.\n\t\t// `nak_live_…`), not the short token id — using the short id yields\n\t\t// `InvalidAccessKeyId` on every S3 request.\n\t\taccessKeyId: minted.tokenId,\n\t\tsecretAccessKey: minted.s3SecretAccessKey,\n\t\tapiToken: minted.apiToken,\n\t};\n}\n\n/**\n * The AI Gateway is a **branch-scoped host** — `<branchId>-api.ai.<host-suffix>` — NOT the\n * control-plane API origin. Derive the suffix from the branch's own Postgres connection host\n * by dropping only the endpoint label (the first segment) and keeping everything after it,\n * including any infra cell prefix (`c-N.`): a connection host of\n * `ep-x.c-3.us-east-2.aws.neon.tech` yields the gateway host\n * `<branchId>-api.ai.c-3.us-east-2.aws.neon.tech`. The cell prefix is **load-bearing** —\n * the gateway is cell-routed, so dropping `c-N.` resolves to the wrong (or no) host.\n */\nfunction aiGatewayHost(branchId: string, connectionUri: string): string {\n\tlet connectionHost = \"\";\n\ttry {\n\t\tconnectionHost = new URL(connectionUri).hostname;\n\t} catch {\n\t\tconnectionHost = \"\";\n\t}\n\t// Drop the endpoint label (first segment, e.g. `ep-x` / `ep-x-pooler`), keeping the rest\n\t// of the host verbatim — including any infra cell prefix (`c-N.`) the gateway routes on:\n\t// `[c-N.]<region>.<cloud>.neon.<tld>`.\n\tconst suffix = connectionHost.split(\".\").slice(1).join(\".\");\n\treturn `${branchId}-api.ai.${suffix}`;\n}\n\n/** The AI Gateway's bare base URL (`NEON_AI_GATEWAY_BASE_URL`) on the branch gateway host. */\nfunction aiGatewayBaseUrl(branchId: string, connectionUri: string): string {\n\treturn `https://${aiGatewayHost(branchId, connectionUri)}`;\n}\n\n/**\n * Resolve the Neon Auth base URL to surface in `env.auth`. Prefer the value returned by\n * the integration (`getNeonAuth` includes it); fall back to whatever is already in the\n * caller's env source so older integrations created before `base_url` was returned still\n * round-trip through `env run`.\n */\nfunction resolveAuthBaseUrl(\n\tsnapshotBaseUrl: string | undefined,\n\tsource: NodeJS.ProcessEnv,\n): string {\n\tif (snapshotBaseUrl && snapshotBaseUrl !== \"\") return snapshotBaseUrl;\n\treturn source[NEON_ENV_VAR_KEYS.auth.baseUrl] ?? \"\";\n}\n\n/**\n * Resolve the Neon Auth JWKS URL to surface in `env.auth`. Prefer the value returned by the\n * integration (`getNeonAuth` always includes `jwks_url`); fall back to the caller's env\n * source so the value still round-trips through `env run` if a snapshot ever omits it.\n */\nfunction resolveAuthJwksUrl(\n\tsnapshotJwksUrl: string | undefined,\n\tsource: NodeJS.ProcessEnv,\n): string {\n\tif (snapshotJwksUrl && snapshotJwksUrl !== \"\") return snapshotJwksUrl;\n\treturn source[NEON_ENV_VAR_KEYS.auth.jwksUrl] ?? \"\";\n}\n\nfunction createApiFromOptions(options: FetchEnvOptions): NeonApi {\n\treturn createNeonApiFromOptions(\"fetchEnv\", {\n\t\t...(options.apiKey ? { apiKey: options.apiKey } : {}),\n\t\t...(options.apiHost ? { apiHost: options.apiHost } : {}),\n\t});\n}\n\n/**\n * Resolve a branch ref — a name or an id — to a concrete branch. Matches by id first\n * (exact `br-…`), then by name; both are unique within a project, so the lookup is\n * unambiguous. This lets `.neon` files written by `neonctl` (which pin the branch *name*)\n * and explicit `br-…` ids both work.\n */\nfunction resolveBranch(\n\tbranch: string,\n\tbranches: NeonBranchSnapshot[],\n): NeonBranchSnapshot {\n\tconst match =\n\t\tbranches.find((b) => b.id === branch) ??\n\t\tbranches.find((b) => b.name === branch);\n\tif (match) return match;\n\tthrow new PlatformError(\n\t\tErrorCode.BranchNotFound,\n\t\t[\n\t\t\t`fetchEnv: branch ${JSON.stringify(branch)} not found on project (matched by id or name).`,\n\t\t\t`Existing branches: ${branches.map((b) => `${b.name} (${b.id})`).join(\", \")}.`,\n\t\t].join(\" \"),\n\t\t{\n\t\t\tdetails: {\n\t\t\t\tbranch,\n\t\t\t\tavailable: branches.map((b) => `${b.name} (${b.id})`),\n\t\t\t},\n\t\t},\n\t);\n}\n\nfunction pickRoleName(\n\troles: NeonRoleSnapshot[],\n\tbranch: NeonBranchSnapshot,\n\trequested: string | undefined,\n): string {\n\tif (requested) {\n\t\tif (!roles.some((r) => r.name === requested)) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.BranchNotFound,\n\t\t\t\t[\n\t\t\t\t\t`fetchEnv: role \"${requested}\" not found on branch ${branch.name} (${branch.id}).`,\n\t\t\t\t\t`Existing roles: ${roles.map((r) => r.name).join(\", \") || \"(none)\"}.`,\n\t\t\t\t].join(\" \"),\n\t\t\t\t{\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tbranchId: branch.id,\n\t\t\t\t\t\troleName: requested,\n\t\t\t\t\t\tavailableRoles: roles.map((r) => r.name),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\treturn requested;\n\t}\n\tif (roles.length === 0) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.BranchNotFound,\n\t\t\t[\n\t\t\t\t`fetchEnv: branch ${branch.name} (${branch.id}) has no roles.`,\n\t\t\t\t\"Create one via the Neon console or pass `roleName` explicitly.\",\n\t\t\t].join(\" \"),\n\t\t\t{ details: { branchId: branch.id } },\n\t\t);\n\t}\n\tif (roles.length === 1) return roles[0].name;\n\n\t// Multiple roles. Enabling Neon Auth / the Data API provisions the PostgREST roles\n\t// (authenticator/anonymous/authenticated) alongside the project owner, so a normal\n\t// branch ends up with >1 role even though only the owner backs a `DATABASE_URL`.\n\t// Default to Neon's owner role; if the project was created with a custom owner name,\n\t// fall back to the single role left after dropping the managed auth roles. Only a\n\t// genuinely ambiguous set (more than one app role) still asks the caller to choose.\n\tconst owner = roles.find((r) => r.name === NEON_DEFAULT_OWNER_ROLE);\n\tif (owner) return owner.name;\n\n\tconst appRoles = roles.filter((r) => !NEON_MANAGED_AUTH_ROLES.has(r.name));\n\tif (appRoles.length === 1) return appRoles[0].name;\n\n\tthrow new PlatformError(\n\t\tErrorCode.AmbiguousBranchAuth,\n\t\t[\n\t\t\t`fetchEnv: branch ${branch.name} (${branch.id}) has ${roles.length} roles and none is \"${NEON_DEFAULT_OWNER_ROLE}\"; cannot auto-pick.`,\n\t\t\t`Pass \\`roleName\\` explicitly. Available: ${roles.map((r) => r.name).join(\", \")}.`,\n\t\t].join(\" \"),\n\t\t{\n\t\t\tdetails: {\n\t\t\t\tbranchId: branch.id,\n\t\t\t\tavailableRoles: roles.map((r) => r.name),\n\t\t\t},\n\t\t},\n\t);\n}\n\nfunction pickDatabaseName(\n\tdatabases: NeonDatabaseSnapshot[],\n\tbranch: NeonBranchSnapshot,\n\trequested: string | undefined,\n): string {\n\tif (requested) {\n\t\tif (!databases.some((d) => d.name === requested)) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.BranchNotFound,\n\t\t\t\t[\n\t\t\t\t\t`fetchEnv: database \"${requested}\" not found on branch ${branch.name} (${branch.id}).`,\n\t\t\t\t\t`Existing databases: ${databases.map((d) => d.name).join(\", \") || \"(none)\"}.`,\n\t\t\t\t].join(\" \"),\n\t\t\t\t{\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tbranchId: branch.id,\n\t\t\t\t\t\tdatabaseName: requested,\n\t\t\t\t\t\tavailableDatabases: databases.map((d) => d.name),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\treturn requested;\n\t}\n\tif (databases.length === 0) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.BranchNotFound,\n\t\t\t[\n\t\t\t\t`fetchEnv: branch ${branch.name} (${branch.id}) has no databases.`,\n\t\t\t\t\"Create one via the Neon console or pass `databaseName` explicitly.\",\n\t\t\t].join(\" \"),\n\t\t\t{ details: { branchId: branch.id } },\n\t\t);\n\t}\n\n\t// Prefer Neon's default `neondb`. On the common \"added a second database\" branch this\n\t// auto-picks it, so a lone or `neondb`-including branch resolves without asking.\n\tconst neondb = databases.find((d) => d.name === NEON_DEFAULT_DATABASE);\n\tif (neondb) return neondb.name;\n\n\tif (databases.length === 1) return databases[0].name;\n\n\t// Several databases and no `neondb` to fall back on. Auto-picking any of them would be\n\t// perceived as random and is bad DX, so fail loudly and let the caller disambiguate.\n\tthrow new PlatformError(\n\t\tErrorCode.AmbiguousBranchAuth,\n\t\t[\n\t\t\t`fetchEnv: branch ${branch.name} (${branch.id}) has ${databases.length} databases and none is named \"${NEON_DEFAULT_DATABASE}\"; cannot auto-pick.`,\n\t\t\t`Rename one to \"${NEON_DEFAULT_DATABASE}\" or keep a single database on the branch (or, when calling fetchEnv directly, pass \\`databaseName\\`). Available: ${databases.map((d) => d.name).join(\", \")}.`,\n\t\t].join(\" \"),\n\t\t{\n\t\t\tdetails: {\n\t\t\t\tbranchId: branch.id,\n\t\t\t\tavailableDatabases: databases.map((d) => d.name),\n\t\t\t},\n\t\t},\n\t);\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 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 (`preview.buckets`). No network. */\nfunction configWantsStorage(config: Config): boolean {\n\treturn Object.keys(config.preview?.buckets ?? {}).length > 0;\n}\n\n/** Whether a **static** policy enables the AI Gateway (`preview.aiGateway`). No network. */\nfunction configWantsAiGateway(config: Config): boolean {\n\treturn isServiceEnabledInput(config.preview?.aiGateway);\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 (top-level `config.auth` / `config.dataApi`), so it reads those directly without\n * 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.preview.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\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 (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 = config.preview?.functions?.[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 preview.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\"Inject them via one of:\",\n\t\t\t\t\" - `neon dev` / `neon-env run -- <your dev command>` (wraps the command with the vars injected)\",\n\t\t\t\t\" - your hosting platform's Neon integration (Vercel, Fly, Railway, …)\",\n\t\t\t\t\" - for the `function` namespace: deploy the function (`neon deploy` / `config apply`) so its env is uploaded.\",\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\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_AUTH_BASE_URL: [\"auth\", \"baseUrl\"],\n\tNEON_AUTH_JWKS_URL: [\"auth\", \"jwksUrl\"],\n\tNEON_DATA_API_URL: [\"dataApi\", \"url\"],\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, Record<string, string>> {\n\tconst issues: string[] = [];\n\tconst result: Record<string, Record<string, string>> = {};\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\"Inject them via one of:\",\n\t\t\t\t\" - `neon dev` / `neon-env run -- <your dev command>` (wraps the command with the vars injected)\",\n\t\t\t\t\" - your hosting platform's Neon integration (Vercel, Fly, Railway, …)\",\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\n// ───────────────────────── env-var mapping helpers ─────────────────────────\n\n/**\n * Project a fully-resolved {@link NeonEnv} into the OS-level `{ KEY: value }` pairs used\n * for cross-process transport. Named after the web-platform `.entries()` convention\n * (`URLSearchParams` / `Headers` / `FormData`); returns a `Record` rather than an\n * iterator of tuples since that's the shape env injection needs (wrap with\n * `Object.entries(...)` if you want literal `[key, value]` pairs). Used by `neon-env run`\n * to inject the vars into a subprocess's `process.env`.\n *\n * Walks the value at runtime so it works for any `NeonEnv<C>` regardless of which\n * conditional namespaces are present.\n */\nexport function toEntries(env: NeonEnv<Config>): Record<string, string> {\n\tconst out: Record<string, string> = {\n\t\t[NEON_ENV_VAR_KEYS.postgres.databaseUrl]: env.postgres.databaseUrl,\n\t\t[NEON_ENV_VAR_KEYS.postgres.databaseUrlUnpooled]:\n\t\t\tenv.postgres.databaseUrlUnpooled,\n\t};\n\tif (env.branch) {\n\t\tout[NEON_ENV_VAR_KEYS.branch.name] = env.branch.name;\n\t}\n\tconst withAuth = env as { auth?: NeonAuthEnv };\n\tif (withAuth.auth) {\n\t\tout[NEON_ENV_VAR_KEYS.auth.baseUrl] = withAuth.auth.baseUrl;\n\t\tout[NEON_ENV_VAR_KEYS.auth.jwksUrl] = withAuth.auth.jwksUrl;\n\t}\n\tconst withDataApi = env as { dataApi?: NeonDataApiEnv };\n\tif (withDataApi.dataApi) {\n\t\tout[NEON_ENV_VAR_KEYS.dataApi.url] = withDataApi.dataApi.url;\n\t}\n\tconst withStorage = env as { storage?: NeonStorageEnv };\n\tif (withStorage.storage) {\n\t\tconst s = withStorage.storage;\n\t\tconst keys = NEON_ENV_VAR_KEYS.storage;\n\t\tout[keys.accessKeyId] = s.accessKeyId;\n\t\tout[keys.secretAccessKey] = s.secretAccessKey;\n\t\tout[keys.endpoint] = s.endpoint;\n\t\tout[keys.region] = s.region;\n\t}\n\tconst withAiGateway = env as { aiGateway?: NeonAiGatewayEnv };\n\tif (withAiGateway.aiGateway) {\n\t\tconst keys = NEON_ENV_VAR_KEYS.aiGateway;\n\t\tconst ai = withAiGateway.aiGateway;\n\t\t// Neon-branded vars only: the bearer and the bare branch gateway host\n\t\t// (scheme://host, no path) — the @neon/ai-sdk-provider appends the\n\t\t// dialect route (/v1, /openai/v1, /anthropic/v1) itself (https://github.com/vercel/ai/pull/15997).\n\t\tout[keys.apiKey] = ai.apiKey;\n\t\tout[keys.baseUrl] = ai.baseUrl;\n\t}\n\treturn out;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neondatabase/env",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.7",
|
|
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",
|