@neondatabase/env 0.11.6 → 0.11.8
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":["ComputeUnit","DurationUnit","DurationString","SuspendTimeoutSuggestion","TtlSuggestion","DurationField","Suggestions","NonNullable","ComputeSettings","BranchTarget","ServiceToggle","ServiceToggleInput","ServiceEnabled","T","PostgresConfig","DATA_API_AUTH_PROVIDERS","DataApiAuthProvider","DataApiSettings","DataApiConfigBase","DataApiNeonAuthConfig","DataApiExternalAuthConfig","DataApiConfig","DataApiInput","FunctionRuntime","FunctionDevConfig","FunctionDef","Record","CredentialScope","CredentialPrincipalType","BucketAccessLevel","BucketDef","PreviewInput","FunctionTuning","PreviewTuning","Slug","Partial","BranchTuning","FunctionSlugsOf","Preview","F","Extract","BranchTuningFn","Config","Auth","DataApi","ResolvedFunctionConfig","ResolvedBucketConfig","ResolvedPreviewConfig","ResolvedDataApiConfig","ResolvedBranchConfig","AppliedChange","ConflictReport","PushResult"],"sources":["../../../../../config/dist/lib/types.d.ts"],"sourcesContent":["//#region src/lib/types.d.ts\n/**\n * Valid Neon Compute Unit values.\n * Most plans support 0.25, 0.5, 1, 2, 4, 8. Higher values may be available on Business plans.\n */\ntype ComputeUnit = 0.25 | 0.5 | 1 | 2 | 4 | 8;\n/** Time units accepted in a {@link DurationString}: seconds, minutes, hours, days, weeks. */\ntype DurationUnit = \"s\" | \"m\" | \"h\" | \"d\" | \"w\";\n/**\n * A Neon duration string: a positive integer **followed by a unit** — `s` (seconds),\n * `m` (minutes), `h` (hours), `d` (days), or `w` (weeks). Used by\n * {@link ComputeSettings.suspendTimeout} and {@link BranchTuning.ttl}.\n *\n * A **unit is required**: a bare numeric string like `\"7\"` is rejected at the type level. To\n * express a raw number of seconds, pass a `number` (`300`) — not a string (`\"300\"`). This\n * removes the old ambiguity where `\"7\"` silently meant 7 *seconds* instead of, say, `\"7d\"`.\n *\n * @example \"5m\" // 5 minutes\n * @example \"1h\" // 1 hour\n * @example \"7d\" // 7 days\n */\ntype DurationString = `${number}${DurationUnit}`;\n/**\n * Autocomplete suggestions for {@link ComputeSettings.suspendTimeout}. Every value sits inside\n * the Neon API's allowed scale-to-zero band: **60s–604800s** (1 minute – 1 week). This is *not*\n * a closed set — the field also accepts any other {@link DurationString} or a `number` of\n * seconds; out-of-range values type-check but are rejected at apply time.\n */\ntype SuspendTimeoutSuggestion = \"1m\" | \"5m\" | \"15m\" | \"30m\" | \"1h\" | \"6h\" | \"12h\" | \"1d\" | \"7d\";\n/**\n * Autocomplete suggestions for {@link BranchTuning.ttl}. Every value sits within the Neon API's\n * branch-expiration limit (**max 30 days** from creation; the Console's own presets are 1h / 1d\n * / 7d). This is *not* a closed set — the field also accepts any other {@link DurationString} or\n * a `number` of seconds; values over 30 days are rejected at apply time.\n */\ntype TtlSuggestion = \"1h\" | \"6h\" | \"12h\" | \"1d\" | \"3d\" | \"7d\" | \"14d\" | \"30d\";\n/**\n * Compose a field's duration type: its curated autocomplete `Suggestions` plus the open\n * `DurationString` template (so any `<integer><unit>` string still type-checks) and a `number`\n * of seconds. Intersecting the template arm with `NonNullable<unknown>` stops TypeScript from\n * collapsing the literal suggestions into the template, which is what preserves the autocomplete.\n */\ntype DurationField<Suggestions extends DurationString> = Suggestions | (DurationString & NonNullable<unknown>) | number;\n/**\n * Compute settings applied to the read/write endpoint of a branch.\n *\n * Mirrors the subset of {@link https://api-docs.neon.tech/reference/getting-started-with-neon-api Neon endpoint}\n * fields that we expose as IaC primitives. Anything left undefined falls back to the project's\n * `default_endpoint_settings` (which themselves fall back to Neon platform defaults).\n */\ninterface ComputeSettings {\n /**\n * Minimum number of Compute Units. Set to 0.25 for true scale-to-zero.\n * @example 0.25 // scale-to-zero\n * @example 1 // always-on with 1 CU minimum\n */\n autoscalingLimitMinCu?: ComputeUnit;\n /**\n * Maximum number of Compute Units for autoscaling.\n * @example 2\n * @example 8\n */\n autoscalingLimitMaxCu?: ComputeUnit;\n /**\n * How long an idle compute waits before suspending (Neon's scale-to-zero). Accepts a\n * {@link DurationString} (autocompletes common values), a number of seconds, or `false`.\n *\n * - `false` — never suspend (always-on compute)\n * - {@link DurationString} — e.g. `\"5m\"`; autocompletes the in-range values `\"1m\"`, `\"5m\"`,\n * `\"15m\"`, `\"30m\"`, `\"1h\"`, `\"6h\"`, `\"12h\"`, `\"1d\"`, `\"7d\"`, and accepts any other\n * `<integer><unit>` (units: `s`, `m`, `h`, `d`, `w`). A **unit is required** — for raw\n * seconds pass a `number`, not a string.\n * - `number` — custom timeout in **seconds**, must be in `60`–`604800` (1 minute to 1 week)\n * - `undefined` — use the Neon platform default (currently 300s / 5 minutes)\n *\n * Whichever form you use, the resolved timeout must fall in `60`–`604800` seconds (the Neon\n * API limit); the suggestions are all within that band, anything else is checked at apply.\n *\n * @example false // never suspend (always-on)\n * @example \"5m\" // suspend after 5 minutes idle\n * @example \"1h\" // suspend after 1 hour idle\n * @example 300 // 5 minutes, expressed in seconds\n */\n suspendTimeout?: false | DurationField<SuspendTimeoutSuggestion>;\n}\n/**\n * Read-only descriptor of the branch a {@link Config} policy is being evaluated for — the\n * `branch` argument passed to your `defineConfig({ branch: (branch) => … })` closure. It describes\n * **which** branch this invocation decides for; it is not a live branch handle and must not\n * be mutated. Switch on its fields and return the desired {@link BranchConfig}.\n */\ninterface BranchTarget {\n /** Branch name being evaluated. For `branch dev`, this is the generated branch name. */\n name: string;\n /** Neon branch id when the branch already exists. Undefined during pre-create eval. */\n id?: string;\n /** Whether this branch already exists on Neon. */\n exists: boolean;\n /** Parent branch id from Neon when known. */\n parentId?: string;\n /** Whether Neon marks this branch as the project default. */\n isDefault?: boolean;\n /** Whether Neon currently marks this branch protected. */\n isProtected?: boolean;\n /** Current expiration timestamp from Neon, when set. */\n expiresAt?: string;\n}\n/**\n * Object form of a branch-scoped service toggle. `{}` or `{ enabled: true }` enables it;\n * `{ enabled: false }` opts out. Used as the object half of {@link ServiceToggleInput}.\n */\ninterface ServiceToggle {\n /** Defaults to `true` when the service namespace is present. Set `false` to opt out. */\n enabled?: boolean;\n}\n/**\n * How a branch-scoped service (Neon Auth, Data API, AI Gateway) is toggled in a policy.\n *\n * - `true` / `{}` / `{ enabled: true }` — enabled.\n * - `false` / `{ enabled: false }` — disabled.\n * - omitted (`undefined`) — not part of the policy at all.\n *\n * These toggles are **static** (they live in the top-level `defineConfig({ … })` object,\n * not in the per-branch `branch` closure) so the secret set they imply can be derived at\n * the type level — that's what makes `NeonEnv<typeof config>` exact.\n */\ntype ServiceToggleInput = boolean | ServiceToggle;\n/**\n * Resolve a **static** service toggle (`true` / `false` / `{ enabled?: boolean }` / object /\n * `undefined`) to a type-level boolean. The tuple wrapping (`[T] extends […]`) disables\n * distribution so a union/`undefined` is judged as a single 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 | … | undefined` (no literal info) → `false`\n *\n * Shared by the {@link Config} static cross-field checks and the `@neon/env`\n * `NeonEnv` namespace derivation, so both read \"is this service on?\" identically.\n */\ntype ServiceEnabled<T> = [T] extends [false] ? false : [T] extends [{\n enabled: false;\n}] ? false : [T] extends [undefined] ? false : [T] extends [true] ? true : [T] extends [{\n enabled: true;\n}] ? true : [T] extends [object] ? true : false;\ninterface PostgresConfig {\n computeSettings?: ComputeSettings;\n}\n/**\n * Authentication providers a Data API integration can verify JWTs against, as written in\n * `neon.ts`. Friendly authoring values (mapped to the Neon API's `neon_auth` / `external`\n * at the API boundary):\n *\n * - `\"neon\"` — verify tokens minted by **Neon Auth** on the same branch. Neon supplies the\n * JWKS URL / provider wiring for you, so the `jwksUrl` / `providerName` / `jwtAudience`\n * fields are forbidden (a type error) on this variant — and the policy must also enable\n * top-level `auth` (Neon Auth) so the tokens exist.\n * - `\"external\"` — verify tokens from a third-party IdP (Clerk, Stytch, Auth0, …). You\n * provide `jwksUrl` (and optionally `providerName` / `jwtAudience`).\n */\ndeclare const DATA_API_AUTH_PROVIDERS: readonly [\"neon\", \"external\"];\ntype DataApiAuthProvider = (typeof DATA_API_AUTH_PROVIDERS)[number];\n/**\n * Reusable runtime settings for a Data API integration (the Neon API `DataAPISettings`,\n * camelCased to match the rest of `neon.ts`). Every field is optional; omitted fields keep\n * the Neon defaults shown below. These are the **only** Data API fields that can change on\n * an already-enabled integration — drift here is reconciled as an *update* (requires\n * `updateExisting` / `--update-existing`); the create-only auth wiring above cannot.\n */\ninterface DataApiSettings {\n /** Enable the aggregates feature (`db_aggregates_enabled`). Default `true`. */\n dbAggregatesEnabled?: boolean;\n /** Database role used for anonymous requests (`db_anon_role`). Default `\"anonymous\"`. */\n dbAnonRole?: string;\n /** Extra schemas appended to the search path (`db_extra_search_path`). */\n dbExtraSearchPath?: string;\n /** Maximum rows returned in a single request (`db_max_rows`). */\n dbMaxRows?: number;\n /** Schemas exposed via the API (`db_schemas`). Default `[\"public\"]`. */\n dbSchemas?: string[];\n /** JWT claim key used for role extraction (`jwt_role_claim_key`). Default `\".role\"`. */\n jwtRoleClaimKey?: string;\n /** Maximum lifetime of the JWT cache, in seconds (`jwt_cache_max_lifetime`). */\n jwtCacheMaxLifetime?: number;\n /** OpenAPI spec mode (`openapi_mode`). Default `\"disabled\"`. */\n openapiMode?: \"ignore-privileges\" | \"disabled\";\n /** CORS allowed origins (`server_cors_allowed_origins`). */\n serverCorsAllowedOrigins?: string;\n /** Emit server-timing headers (`server_timing_enabled`). */\n serverTimingEnabled?: boolean;\n}\n/** Fields shared by every {@link DataApiConfig} variant. */\ninterface DataApiConfigBase {\n /** Defaults to `true` when the `dataApi` namespace is present. Set `false` to opt out. */\n enabled?: boolean;\n /** Reusable runtime settings. Drift here is reconciled as an update. */\n settings?: DataApiSettings;\n}\n/**\n * Data API verified by **Neon Auth** (`authProvider: \"neon\"`, the default). The external\n * IdP fields are statically forbidden (`?: never`) because Neon supplies them; declaring any\n * of them is a type error directing you to `authProvider: \"external\"`.\n */\ninterface DataApiNeonAuthConfig extends DataApiConfigBase {\n authProvider?: \"neon\";\n /** Forbidden with `authProvider: \"neon\"` — Neon provides the JWKS URL. */\n jwksUrl?: never;\n /** Forbidden with `authProvider: \"neon\"` — the provider is Neon Auth. */\n providerName?: never;\n /** Forbidden with `authProvider: \"neon\"` — Neon manages the audience. */\n jwtAudience?: never;\n}\n/**\n * Data API verified by an **external** IdP (`authProvider: \"external\"`). You provide the\n * JWKS URL (and optionally a provider label / expected audience).\n */\ninterface DataApiExternalAuthConfig extends DataApiConfigBase {\n authProvider: \"external\";\n /** URL that publishes the IdP's JWKS (JSON Web Key Set). */\n jwksUrl?: string;\n /** Human label for the IdP (e.g. \"Clerk\", \"Stytch\", \"Auth0\"). */\n providerName?: string;\n /**\n * Expected `aud` claim. ⚠️ This only **rejects** tokens carrying a *different* audience;\n * tokens with no `aud` claim are still accepted.\n */\n jwtAudience?: string;\n}\n/**\n * Object form of the `dataApi` toggle. A discriminated union on {@link DataApiAuthProvider}:\n * the `\"neon\"` variant forbids the external-IdP fields, the `\"external\"` variant allows them.\n */\ntype DataApiConfig = DataApiNeonAuthConfig | DataApiExternalAuthConfig;\n/**\n * How the Data API is toggled in a policy: a bare boolean (like the other service toggles)\n * or the richer {@link DataApiConfig} object. `true` / `{}` / `{ enabled: true }` enable it\n * with Neon defaults; `false` / `{ enabled: false }` opt out.\n */\ntype DataApiInput = boolean | DataApiConfig;\n/**\n * Supported function runtimes. Mirrors the Neon Functions deploy API `runtime` enum.\n * Only `nodejs24` exists today; kept as a union so adding runtimes later is a\n * non-breaking, type-checked change.\n */\ntype FunctionRuntime = \"nodejs24\";\n/**\n * Local-development settings for a function, used by `neon dev` when it serves every\n * function declared in `neon.ts` (i.e. invoked with no `--source`). Never affects deploy.\n */\ninterface FunctionDevConfig {\n /**\n * Port the local server binds. Bound exactly (and `neon dev` fails loudly if it is taken)\n * when set; a free port is found automatically when omitted.\n */\n port?: number;\n}\n/**\n * Static definition of a Neon Function (Preview feature). Declares that the function\n * **exists** on every branch; its branch-unique slug is the **record key** in\n * {@link PreviewInput.functions} (not a field here), so slugs are statically enumerable,\n * cannot duplicate, and the `branch` closure can only tune slugs that are declared here.\n *\n * A function is invoked like a Cloudflare/Vercel handler — its source module\n * `export default { fetch }` or `export async function handler(req): Response`. The\n * `source` path is bundled (esbuild) and uploaded as a deployment; the newest deployment\n * becomes active.\n *\n * Runtime tuning is **not** here — it varies per branch and lives in the `branch` closure\n * (see {@link FunctionTuning}). Memory is fixed by the platform policy for now and is not\n * user-configurable.\n */\ninterface FunctionDef {\n /** Free-form display name. @example \"Hello World\" */\n name: string;\n /**\n * Path to the function's entry module, **relative to `neon.ts`** (or absolute). The\n * module's default export (`{ fetch }`) or `handler` export is the function entry. This\n * path is resolved against the loaded `neon.ts` location and bundled with esbuild at\n * deploy time.\n *\n * We require a string path rather than an imported handler because a JS function value\n * carries no reference back to its source file, so esbuild has nothing to bundle from.\n * @example \"./functions/hello-world.ts\"\n */\n source: string;\n /**\n * Environment variables injected into the deployed function, keyed by the var name the\n * function reads at runtime. The **keys** are static (preserved at the type level so\n * `parseEnv(config, \"<slug>\").function.<key>` is typed); the **values** are arbitrary\n * strings evaluated when `neon.ts` is loaded (typically `process.env.X`) and uploaded\n * at `config apply`. Every value must be a defined string — a `process.env.X` that is\n * `undefined` (unset) errors at validation time rather than silently shipping\n * `undefined`.\n * @example { resendApiKey: process.env.RESEND_API_KEY ?? \"\" }\n */\n env?: Record<string, string>;\n /**\n * Local-development settings used by `neon dev` when serving every function from\n * `neon.ts`. Ignored at deploy time. See {@link FunctionDevConfig}.\n */\n dev?: FunctionDevConfig;\n}\n/**\n * A single capability a branch-scoped service credential may exercise (Preview). A\n * credential is granted a set of these and may only perform the listed actions. Mirrors\n * the Neon API `CredentialScope` enum (`x-stability-level: beta`):\n *\n * - `storage:read` / `storage:write` — object-storage (bucket) access via the S3 key.\n * - `ai_gateway:invoke` — call the AI Gateway with the bearer `api_token`.\n * - `functions:invoke` — invoke Neon Functions with the bearer `api_token`.\n *\n * The set a policy needs is derived from its enabled Preview features (see\n * {@link deriveCredentialScopes}); it is never authored by hand.\n */\ntype CredentialScope = \"storage:read\" | \"storage:write\" | \"ai_gateway:invoke\" | \"functions:invoke\";\n/**\n * Who a credential acts as. `user` is the developer/app principal minted for local dev and\n * app bootstrap (`fetchEnv` / `env pull`); `function` is a deployed-function principal\n * (carries a `function_id`). The env tooling only mints `user` credentials today.\n */\ntype CredentialPrincipalType = \"user\" | \"function\";\n/** Anonymous-access level for a branchable object-storage bucket. */\ntype BucketAccessLevel = \"private\" | \"public_read\";\n/**\n * Static definition of a branchable object-storage bucket (Preview feature). The bucket's\n * name is the **record key** in {@link PreviewInput.buckets}, so names are statically\n * enumerable and cannot duplicate.\n */\ninterface BucketDef {\n /**\n * Anonymous access level. `private` (default) requires authenticated reads/writes;\n * `public_read` allows anonymous GetObject/HeadObject.\n */\n access?: BucketAccessLevel;\n}\n/**\n * Static, branch-scoped **Preview** features. Grouped under `preview` to signal they are\n * backed by Neon `x-stability-level: beta` endpoints and may change before GA. Everything\n * here is existential (it determines what exists on the branch); per-branch tuning lives in\n * the `branch` closure.\n */\ninterface PreviewInput {\n /** Enable/disable the AI Gateway on the branch (toggle, like auth / dataApi). */\n aiGateway?: ServiceToggleInput;\n /** Functions to deploy, keyed by branch-unique slug (`^[a-z0-9]{1,20}$`). */\n functions?: Record<string, FunctionDef>;\n /** Object-storage buckets to create, keyed by bucket name. */\n buckets?: Record<string, BucketDef>;\n}\n/**\n * Per-branch deploy tuning for a single function. Returned (per slug) by the `branch`\n * closure. Deliberately **cannot** change the function's existence, source, name, env\n * **keys**, or memory — only runtime selection is currently configurable — so the static\n * secret/function set stays sound.\n */\ninterface FunctionTuning {\n /** Runtime to execute the function with. Defaults to `\"nodejs24\"`. */\n runtime?: FunctionRuntime;\n}\n/**\n * Per-branch tuning of Preview features. Only existing function slugs (those declared in\n * the static {@link PreviewInput.functions}) may be tuned — `Slug` is constrained to the\n * declared keys by {@link BranchTuningFn}.\n */\ninterface PreviewTuning<Slug extends string = string> {\n functions?: Partial<Record<Slug, FunctionTuning>>;\n}\n/**\n * The per-branch tuning object returned by the `branch` closure. It can adjust branch\n * lifecycle (`parent`, `ttl`, `protected`), Postgres compute settings, and per-function\n * deploy tuning — but **cannot** add/remove services or functions. That guarantee is what\n * keeps the static secret set (and therefore `NeonEnv`) exact.\n */\ninterface BranchTuning<Slug extends string = string> {\n /** Parent branch name used when creating a new branch. Not a Postgres setting. */\n parent?: string;\n /**\n * Branch time-to-live: how long after creation the branch should auto-expire. Applied\n * when creating a new branch and reconciled on existing branches (when `updateExisting`\n * is set). Accepts a {@link DurationString} (autocompletes common values) or a number of\n * seconds. Omit to keep the branch indefinitely.\n *\n * - {@link DurationString} — e.g. `\"7d\"`; autocompletes `\"1h\"`, `\"6h\"`, `\"12h\"`, `\"1d\"`,\n * `\"3d\"`, `\"7d\"`, `\"14d\"`, `\"30d\"`, and accepts any other `<integer><unit>` (units: `s`,\n * `m`, `h`, `d`, `w` — e.g. `\"12h\"`, `\"2w\"`). A **unit is required** — `\"7\"` is rejected;\n * for raw seconds pass a `number`.\n * - `number` — custom TTL in **seconds** (e.g. `3600`)\n * - `undefined` — no expiry; the branch persists until explicitly deleted\n *\n * The Neon API caps branch expiration at **30 days** from creation, so the resolved TTL must\n * be `> 0` and `<= 30d`; the suggestions stay within that limit and anything longer is\n * rejected at apply.\n *\n * @example \"1d\" // ephemeral preview branch: expires a day after creation\n * @example \"7d\" // one-week TTL\n * @example \"30d\" // the maximum the API allows\n * @example 3600 // 1 hour, expressed in seconds\n */\n ttl?: DurationField<TtlSuggestion>;\n /** Whether the selected branch should be protected. Undefined means \"leave as-is\". */\n protected?: boolean;\n postgres?: PostgresConfig;\n preview?: PreviewTuning<Slug>;\n}\n/** Extract the declared function slugs from a {@link PreviewInput} for closure typing. */\ntype FunctionSlugsOf<Preview extends PreviewInput | undefined> = Preview extends {\n functions: infer F;\n} ? Extract<keyof F, string> : string;\n/**\n * Signature of the `branch` closure. Generic over the static {@link PreviewInput} so the\n * `preview.functions` keys it may tune are constrained to the slugs actually declared.\n */\ntype BranchTuningFn<Preview extends PreviewInput | undefined = PreviewInput | undefined> = (branch: BranchTarget) => BranchTuning<FunctionSlugsOf<Preview>>;\n/**\n * A validated Neon branch policy — the value `defineConfig({ … })` returns and `neon.ts`\n * default-exports.\n *\n * Split into a **static** existential set (top-level `auth` / `dataApi` GA toggles plus the\n * beta `preview` block) and a **dynamic** per-branch `branch` closure for tuning. The\n * static half is what makes the secret set — and therefore `NeonEnv<typeof config>` and\n * `parseEnv` — exact; the closure can tune but never change what exists.\n *\n * Generic over the three static fields so the type system can read the exact toggle/slug\n * literals; the defaults make the bare `Config` a usable \"any policy\" type for runtime\n * function signatures.\n */\ninterface Config<Auth extends ServiceToggleInput | undefined = ServiceToggleInput | undefined, DataApi extends DataApiInput | undefined = DataApiInput | undefined, Preview extends PreviewInput | undefined = PreviewInput | undefined> {\n /** Neon Auth integration toggle (GA). Static — drives `NeonEnv.auth`. */\n auth?: Auth;\n /**\n * Neon Data API integration (GA). Static — drives `NeonEnv.dataApi`. A boolean/toggle, or\n * a {@link DataApiConfig} object selecting the auth provider (`\"neon\"` / `\"external\"`) and\n * runtime {@link DataApiSettings}. With `authProvider: \"neon\"` the policy must also enable\n * top-level `auth`.\n */\n dataApi?: DataApi;\n /** Beta (Preview) feature set: AI Gateway, functions, buckets. Static. */\n preview?: Preview;\n /** Per-branch tuning closure. Cannot change the static existential set. */\n branch?: BranchTuningFn<Preview>;\n}\n/**\n * A function with all deploy defaults applied. `resolveConfig` fills in `runtime` so\n * downstream diff/apply never has to re-derive it.\n */\ninterface ResolvedFunctionConfig {\n slug: string;\n name: string;\n source: string;\n env: Record<string, string>;\n runtime: FunctionRuntime;\n /**\n * Local-development settings, passed through untouched from {@link FunctionDef.dev}\n * (no defaults applied). Only consumed by `neon dev`; deploy ignores it.\n */\n dev?: FunctionDevConfig;\n}\n/** A bucket with its access level defaulted to `private`. */\ninterface ResolvedBucketConfig {\n name: string;\n access: BucketAccessLevel;\n}\n/**\n * Normalized {@link PreviewInput}. Only present on {@link ResolvedBranchConfig} when the\n * policy returned a `preview` block. `aiGatewayEnabled` follows the same\n * \"present-and-not-`false`\" semantics as `authEnabled` / `dataApiEnabled`.\n */\ninterface ResolvedPreviewConfig {\n functions: ResolvedFunctionConfig[];\n buckets: ResolvedBucketConfig[];\n aiGatewayEnabled: boolean;\n}\n/**\n * Normalized Data API integration. Present on {@link ResolvedBranchConfig} only when the\n * policy enables `dataApi`. `authProvider` always resolves (defaults to `\"neon\"`); the\n * external-IdP wiring is present only for `\"external\"`; `settings` carries the camelCase\n * runtime settings (reconciled as an update when they drift).\n */\ninterface ResolvedDataApiConfig {\n authProvider: DataApiAuthProvider;\n jwksUrl?: string;\n providerName?: string;\n jwtAudience?: string;\n settings?: DataApiSettings;\n}\ninterface ResolvedBranchConfig {\n parent?: string;\n ttlSeconds?: number;\n protected?: boolean;\n postgres?: PostgresConfig;\n authEnabled: boolean;\n dataApiEnabled: boolean;\n /**\n * Resolved Data API integration. Present iff {@link dataApiEnabled} is `true`. Carries the\n * create-time auth wiring and the updatable {@link DataApiSettings}.\n */\n dataApi?: ResolvedDataApiConfig;\n preview?: ResolvedPreviewConfig;\n}\n/**\n * One concrete change `pushConfig` made (or, in dry-run, would make) on the remote.\n */\ninterface AppliedChange {\n /**\n * `service` covers branch-scoped integrations driven by the branch policy (e.g.\n * Neon Auth, Data API).\n */\n kind: \"branch\" | \"service\";\n action: \"create\" | \"update\" | \"noop\";\n identifier: string;\n details?: Record<string, unknown>;\n}\n/**\n * A diff entry that conflicts with the desired config. `pushConfig` throws\n * {@link PushConflictError} on the first call when conflicts exist; pass\n * `updateExisting: true` to apply mutable drift (settings, `protected`, TTL, project\n * rename). Immutable fields (region, Postgres major version) are always conflicts —\n * recreate the project to change them.\n */\ninterface ConflictReport {\n kind: \"branch\";\n identifier: string;\n field: string;\n current: unknown;\n desired: unknown;\n reason: string;\n}\n/**\n * Result of a `pushConfig` invocation.\n */\ninterface PushResult {\n projectId: string;\n orgId?: string;\n branchId: string;\n branchName: string;\n /**\n * `true` when `pushConfig` was called with `{ dryRun: true }`. `applied` then records\n * what **would** be applied on a real push; no API mutations were performed.\n */\n dryRun: boolean;\n applied: AppliedChange[];\n conflicts: ConflictReport[];\n}\n//#endregion\nexport { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConflictReport, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DurationString, DurationUnit, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput };\n//# sourceMappingURL=types.d.ts.map"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":["ComputeUnit","DurationUnit","DurationString","SuspendTimeoutSuggestion","TtlSuggestion","DurationField","Suggestions","NonNullable","ComputeSettings","BranchTarget","ServiceToggle","ServiceToggleInput","ServiceEnabled","T","PostgresConfig","DATA_API_AUTH_PROVIDERS","DataApiAuthProvider","DataApiSettings","DataApiConfigBase","DataApiNeonAuthConfig","DataApiExternalAuthConfig","DataApiConfig","DataApiInput","FunctionRuntime","FunctionDevConfig","FunctionDef","Record","CredentialScope","CredentialPrincipalType","BucketAccessLevel","BucketDef","PreviewInput","FunctionTuning","PreviewTuning","Slug","Partial","BranchTuning","FunctionSlugsOf","Preview","F","Extract","BranchTuningFn","Config","Auth","DataApi","ResolvedFunctionConfig","ResolvedBucketConfig","ResolvedPreviewConfig","ResolvedDataApiConfig","ResolvedBranchConfig","AppliedChange","ConflictReport","PushResult"],"sources":["../../../../../config/dist/lib/types.d.ts"],"sourcesContent":["//#region src/lib/types.d.ts\n/**\n * Valid Neon Compute Unit values.\n * Most plans support 0.25, 0.5, 1, 2, 4, 8. Higher values may be available on Business plans.\n */\ntype ComputeUnit = 0.25 | 0.5 | 1 | 2 | 4 | 8;\n/** Time units accepted in a {@link DurationString}: seconds, minutes, hours, days, weeks. */\ntype DurationUnit = \"s\" | \"m\" | \"h\" | \"d\" | \"w\";\n/**\n * A Neon duration string: a positive integer **followed by a unit** — `s` (seconds),\n * `m` (minutes), `h` (hours), `d` (days), or `w` (weeks). Used by\n * {@link ComputeSettings.suspendTimeout} and {@link BranchTuning.ttl}.\n *\n * A **unit is required**: a bare numeric string like `\"7\"` is rejected at the type level. To\n * express a raw number of seconds, pass a `number` (`300`) — not a string (`\"300\"`). This\n * removes the old ambiguity where `\"7\"` silently meant 7 *seconds* instead of, say, `\"7d\"`.\n *\n * @example \"5m\" // 5 minutes\n * @example \"1h\" // 1 hour\n * @example \"7d\" // 7 days\n */\ntype DurationString = `${number}${DurationUnit}`;\n/**\n * Autocomplete suggestions for {@link ComputeSettings.suspendTimeout}. Every value sits inside\n * the Neon API's allowed scale-to-zero band: **60s–604800s** (1 minute – 1 week). This is *not*\n * a closed set — the field also accepts any other {@link DurationString} or a `number` of\n * seconds; out-of-range values type-check but are rejected at apply time.\n */\ntype SuspendTimeoutSuggestion = \"1m\" | \"5m\" | \"15m\" | \"30m\" | \"1h\" | \"6h\" | \"12h\" | \"1d\" | \"7d\";\n/**\n * Autocomplete suggestions for {@link BranchTuning.ttl}. Every value sits within the Neon API's\n * branch-expiration limit (**max 30 days** from creation; the Console's own presets are 1h / 1d\n * / 7d). This is *not* a closed set — the field also accepts any other {@link DurationString} or\n * a `number` of seconds; values over 30 days are rejected at apply time.\n */\ntype TtlSuggestion = \"1h\" | \"6h\" | \"12h\" | \"1d\" | \"3d\" | \"7d\" | \"14d\" | \"30d\";\n/**\n * Compose a field's duration type: its curated autocomplete `Suggestions` plus the open\n * `DurationString` template (so any `<integer><unit>` string still type-checks) and a `number`\n * of seconds. Intersecting the template arm with `NonNullable<unknown>` stops TypeScript from\n * collapsing the literal suggestions into the template, which is what preserves the autocomplete.\n */\ntype DurationField<Suggestions extends DurationString> = Suggestions | (DurationString & NonNullable<unknown>) | number;\n/**\n * Compute settings applied to the read/write endpoint of a branch.\n *\n * Mirrors the subset of {@link https://api-docs.neon.tech/reference/getting-started-with-neon-api Neon endpoint}\n * fields that we expose as IaC primitives. Anything left undefined falls back to the project's\n * `default_endpoint_settings` (which themselves fall back to Neon platform defaults).\n */\ninterface ComputeSettings {\n /**\n * Minimum number of Compute Units. Set to 0.25 for true scale-to-zero.\n * @example 0.25 // scale-to-zero\n * @example 1 // always-on with 1 CU minimum\n */\n autoscalingLimitMinCu?: ComputeUnit;\n /**\n * Maximum number of Compute Units for autoscaling.\n * @example 2\n * @example 8\n */\n autoscalingLimitMaxCu?: ComputeUnit;\n /**\n * How long an idle compute waits before suspending (Neon's scale-to-zero). Accepts a\n * {@link DurationString} (autocompletes common values), a number of seconds, or `false`.\n *\n * - `false` — never suspend (always-on compute)\n * - {@link DurationString} — e.g. `\"5m\"`; autocompletes the in-range values `\"1m\"`, `\"5m\"`,\n * `\"15m\"`, `\"30m\"`, `\"1h\"`, `\"6h\"`, `\"12h\"`, `\"1d\"`, `\"7d\"`, and accepts any other\n * `<integer><unit>` (units: `s`, `m`, `h`, `d`, `w`). A **unit is required** — for raw\n * seconds pass a `number`, not a string.\n * - `number` — custom timeout in **seconds**, must be in `60`–`604800` (1 minute to 1 week)\n * - `undefined` — use the Neon platform default (currently 300s / 5 minutes)\n *\n * Whichever form you use, the resolved timeout must fall in `60`–`604800` seconds (the Neon\n * API limit); the suggestions are all within that band, anything else is checked at apply.\n *\n * @example false // never suspend (always-on)\n * @example \"5m\" // suspend after 5 minutes idle\n * @example \"1h\" // suspend after 1 hour idle\n * @example 300 // 5 minutes, expressed in seconds\n */\n suspendTimeout?: false | DurationField<SuspendTimeoutSuggestion>;\n}\n/**\n * Read-only descriptor of the branch a {@link Config} policy is being evaluated for — the\n * `branch` argument passed to your `defineConfig({ branch: (branch) => … })` closure. It describes\n * **which** branch this invocation decides for; it is not a live branch handle and must not\n * be mutated. Switch on its fields and return the desired {@link BranchConfig}.\n */\ninterface BranchTarget {\n /** Branch name being evaluated. For `branch dev`, this is the generated branch name. */\n name: string;\n /** Neon branch id when the branch already exists. Undefined during pre-create eval. */\n id?: string;\n /** Whether this branch already exists on Neon. */\n exists: boolean;\n /** Parent branch id from Neon when known. */\n parentId?: string;\n /** Whether Neon marks this branch as the project default. */\n isDefault?: boolean;\n /** Whether Neon currently marks this branch protected. */\n isProtected?: boolean;\n /** Current expiration timestamp from Neon, when set. */\n expiresAt?: string;\n}\n/**\n * Object form of a branch-scoped service toggle. `{}` or `{ enabled: true }` enables it;\n * `{ enabled: false }` opts out. Used as the object half of {@link ServiceToggleInput}.\n */\ninterface ServiceToggle {\n /** Defaults to `true` when the service namespace is present. Set `false` to opt out. */\n enabled?: boolean;\n}\n/**\n * How a branch-scoped service (Neon Auth, Data API, AI Gateway) is toggled in a policy.\n *\n * - `true` / `{}` / `{ enabled: true }` — enabled.\n * - `false` / `{ enabled: false }` — disabled.\n * - omitted (`undefined`) — not part of the policy at all.\n *\n * These toggles are **static** (they live in the top-level `defineConfig({ … })` object,\n * not in the per-branch `branch` closure) so the secret set they imply can be derived at\n * the type level — that's what makes `NeonEnv<typeof config>` exact.\n */\ntype ServiceToggleInput = boolean | ServiceToggle;\n/**\n * Resolve a **static** service toggle (`true` / `false` / `{ enabled?: boolean }` / object /\n * `undefined`) to a type-level boolean. The tuple wrapping (`[T] extends […]`) disables\n * distribution so a union/`undefined` is judged as a single 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 | … | undefined` (no literal info) → `false`\n *\n * Shared by the {@link Config} static cross-field checks and the `@neon/env`\n * `NeonEnv` namespace derivation, so both read \"is this service on?\" identically.\n */\ntype ServiceEnabled<T> = [T] extends [false] ? false : [T] extends [{\n enabled: false;\n}] ? false : [T] extends [undefined] ? false : [T] extends [true] ? true : [T] extends [{\n enabled: true;\n}] ? true : [T] extends [object] ? true : false;\ninterface PostgresConfig {\n computeSettings?: ComputeSettings;\n}\n/**\n * Authentication providers a Data API integration can verify JWTs against, as written in\n * `neon.ts`. Friendly authoring values (mapped to the Neon API's `neon_auth` / `external`\n * at the API boundary):\n *\n * - `\"neon\"` — verify tokens minted by **Neon Auth** on the same branch. Neon supplies the\n * JWKS URL / provider wiring for you, so the `jwksUrl` / `providerName` / `jwtAudience`\n * fields are forbidden (a type error) on this variant — and the policy must also enable\n * top-level `auth` (Neon Auth) so the tokens exist.\n * - `\"external\"` — verify tokens from a third-party IdP (Clerk, Stytch, Auth0, …). You\n * provide `jwksUrl` (and optionally `providerName` / `jwtAudience`).\n */\ndeclare const DATA_API_AUTH_PROVIDERS: readonly [\"neon\", \"external\"];\ntype DataApiAuthProvider = (typeof DATA_API_AUTH_PROVIDERS)[number];\n/**\n * Reusable runtime settings for a Data API integration (the Neon API `DataAPISettings`,\n * camelCased to match the rest of `neon.ts`). Every field is optional; omitted fields keep\n * the Neon defaults shown below. These are the **only** Data API fields that can change on\n * an already-enabled integration — drift here is reconciled as an *update* (requires\n * `updateExisting` / `--update-existing`); the create-only auth wiring above cannot.\n */\ninterface DataApiSettings {\n /** Enable the aggregates feature (`db_aggregates_enabled`). Default `true`. */\n dbAggregatesEnabled?: boolean;\n /** Database role used for anonymous requests (`db_anon_role`). Default `\"anonymous\"`. */\n dbAnonRole?: string;\n /** Extra schemas appended to the search path (`db_extra_search_path`). */\n dbExtraSearchPath?: string;\n /** Maximum rows returned in a single request (`db_max_rows`). */\n dbMaxRows?: number;\n /** Schemas exposed via the API (`db_schemas`). Default `[\"public\"]`. */\n dbSchemas?: string[];\n /** JWT claim key used for role extraction (`jwt_role_claim_key`). Default `\".role\"`. */\n jwtRoleClaimKey?: string;\n /** Maximum lifetime of the JWT cache, in seconds (`jwt_cache_max_lifetime`). */\n jwtCacheMaxLifetime?: number;\n /** OpenAPI spec mode (`openapi_mode`). Default `\"disabled\"`. */\n openapiMode?: \"ignore-privileges\" | \"disabled\";\n /** CORS allowed origins (`server_cors_allowed_origins`). */\n serverCorsAllowedOrigins?: string;\n /** Emit server-timing headers (`server_timing_enabled`). */\n serverTimingEnabled?: boolean;\n}\n/** Fields shared by every {@link DataApiConfig} variant. */\ninterface DataApiConfigBase {\n /** Defaults to `true` when the `dataApi` namespace is present. Set `false` to opt out. */\n enabled?: boolean;\n /** Reusable runtime settings. Drift here is reconciled as an update. */\n settings?: DataApiSettings;\n}\n/**\n * Data API verified by **Neon Auth** (`authProvider: \"neon\"`, the default). The external\n * IdP fields are statically forbidden (`?: never`) because Neon supplies them; declaring any\n * of them is a type error directing you to `authProvider: \"external\"`.\n */\ninterface DataApiNeonAuthConfig extends DataApiConfigBase {\n authProvider?: \"neon\";\n /** Forbidden with `authProvider: \"neon\"` — Neon provides the JWKS URL. */\n jwksUrl?: never;\n /** Forbidden with `authProvider: \"neon\"` — the provider is Neon Auth. */\n providerName?: never;\n /** Forbidden with `authProvider: \"neon\"` — Neon manages the audience. */\n jwtAudience?: never;\n}\n/**\n * Data API verified by an **external** IdP (`authProvider: \"external\"`). You provide the\n * JWKS URL (and optionally a provider label / expected audience).\n */\ninterface DataApiExternalAuthConfig extends DataApiConfigBase {\n authProvider: \"external\";\n /** URL that publishes the IdP's JWKS (JSON Web Key Set). */\n jwksUrl?: string;\n /** Human label for the IdP (e.g. \"Clerk\", \"Stytch\", \"Auth0\"). */\n providerName?: string;\n /**\n * Expected `aud` claim. ⚠️ This only **rejects** tokens carrying a *different* audience;\n * tokens with no `aud` claim are still accepted.\n */\n jwtAudience?: string;\n}\n/**\n * Object form of the `dataApi` toggle. A discriminated union on {@link DataApiAuthProvider}:\n * the `\"neon\"` variant forbids the external-IdP fields, the `\"external\"` variant allows them.\n */\ntype DataApiConfig = DataApiNeonAuthConfig | DataApiExternalAuthConfig;\n/**\n * How the Data API is toggled in a policy: a bare boolean (like the other service toggles)\n * or the richer {@link DataApiConfig} object. `true` / `{}` / `{ enabled: true }` enable it\n * with Neon defaults; `false` / `{ enabled: false }` opt out.\n */\ntype DataApiInput = boolean | DataApiConfig;\n/**\n * Supported function runtimes. Mirrors the Neon Functions deploy API `runtime` enum.\n * Only `nodejs24` exists today; kept as a union so adding runtimes later is a\n * non-breaking, type-checked change.\n */\ntype FunctionRuntime = \"nodejs24\";\n/**\n * Local-development settings for a function, used by `neon dev` when it serves every\n * function declared in `neon.ts` (i.e. invoked with no `--source`). Never affects deploy.\n */\ninterface FunctionDevConfig {\n /**\n * Port the local server binds. Bound exactly (and `neon dev` fails loudly if it is taken)\n * when set; a free port is found automatically when omitted.\n */\n port?: number;\n}\n/**\n * Static definition of a Neon Function (Preview feature). Declares that the function\n * **exists** on every branch; its branch-unique slug is the **record key** in\n * {@link PreviewInput.functions} (not a field here), so slugs are statically enumerable,\n * cannot duplicate, and the `branch` closure can only tune slugs that are declared here.\n *\n * A function is invoked like a Cloudflare/Vercel handler — its source module\n * `export default { fetch }` or `export async function handler(req): Response`. The\n * `source` path is bundled (esbuild) and uploaded as a deployment; the newest deployment\n * becomes active.\n *\n * Runtime tuning is **not** here — it varies per branch and lives in the `branch` closure\n * (see {@link FunctionTuning}). Memory is fixed by the platform policy for now and is not\n * user-configurable.\n */\ninterface FunctionDef {\n /** Free-form display name. @example \"Hello World\" */\n name: string;\n /**\n * Path to the function's entry module, **relative to `neon.ts`** (or absolute). The\n * module's default export (`{ fetch }`) or `handler` export is the function entry. This\n * path is resolved against the loaded `neon.ts` location and bundled with esbuild at\n * deploy time.\n *\n * We require a string path rather than an imported handler because a JS function value\n * carries no reference back to its source file, so esbuild has nothing to bundle from.\n * @example \"./functions/hello-world.ts\"\n */\n source: string;\n /**\n * Environment variables injected into the deployed function, keyed by the var name the\n * function reads at runtime. The **keys** are static (preserved at the type level so\n * `parseEnv(config, \"<slug>\").function.<key>` is typed); the **values** are arbitrary\n * strings evaluated when `neon.ts` is loaded (typically `process.env.X`) and uploaded\n * at `config apply`. Every value must be a defined string — a `process.env.X` that is\n * `undefined` (unset) errors at validation time rather than silently shipping\n * `undefined`.\n * @example { resendApiKey: process.env.RESEND_API_KEY ?? \"\" }\n */\n env?: Record<string, string>;\n /**\n * Local-development settings used by `neon dev` when serving every function from\n * `neon.ts`. Ignored at deploy time. See {@link FunctionDevConfig}.\n */\n dev?: FunctionDevConfig;\n}\n/**\n * A single capability a branch-scoped service credential may exercise (Preview). A\n * credential is granted a set of these and may only perform the listed actions. Mirrors\n * the Neon API `CredentialScope` enum (`x-stability-level: beta`):\n *\n * - `storage:read` / `storage:write` — object-storage (bucket) access via the S3 key.\n * - `ai_gateway:invoke` — call the AI Gateway with the bearer `api_token`.\n * - `functions:invoke` — invoke Neon Functions with the bearer `api_token`.\n *\n * The set a policy needs is derived from its enabled Preview features (see\n * {@link deriveCredentialScopes}); it is never authored by hand.\n */\ntype CredentialScope = \"storage:read\" | \"storage:write\" | \"ai_gateway:invoke\" | \"functions:invoke\";\n/**\n * Who a credential acts as. `user` is the developer/app principal minted for local dev and\n * app bootstrap (`fetchEnv` / `env pull`); `function` is a deployed-function principal\n * (carries a `function_id`). The env tooling only mints `user` credentials today.\n */\ntype CredentialPrincipalType = \"user\" | \"function\";\n/** Anonymous-access level for a branchable object-storage bucket. */\ntype BucketAccessLevel = \"private\" | \"public_read\";\n/**\n * Static definition of a branchable object-storage bucket (Preview feature). The bucket's\n * name is the **record key** in {@link PreviewInput.buckets}, so names are statically\n * enumerable and cannot duplicate.\n */\ninterface BucketDef {\n /**\n * Anonymous access level. `private` (default) requires authenticated reads/writes;\n * `public_read` allows anonymous GetObject/HeadObject.\n */\n access?: BucketAccessLevel;\n}\n/**\n * Static, branch-scoped **Preview** features. Grouped under `preview` to signal they are\n * backed by Neon `x-stability-level: beta` endpoints and may change before GA. Everything\n * here is existential (it determines what exists on the branch); per-branch tuning lives in\n * the `branch` closure.\n */\ninterface PreviewInput {\n /** Enable/disable the AI Gateway on the branch (toggle, like auth / dataApi). */\n aiGateway?: ServiceToggleInput;\n /** Functions to deploy, keyed by branch-unique slug (`^[a-z0-9]{1,20}$`). */\n functions?: Record<string, FunctionDef>;\n /** Object-storage buckets to create, keyed by bucket name. */\n buckets?: Record<string, BucketDef>;\n}\n/**\n * Per-branch deploy tuning for a single function. Returned (per slug) by the `branch`\n * closure. Deliberately **cannot** change the function's existence, source, name, env\n * **keys**, or memory — only runtime selection is currently configurable — so the static\n * secret/function set stays sound.\n */\ninterface FunctionTuning {\n /** Runtime to execute the function with. Defaults to `\"nodejs24\"`. */\n runtime?: FunctionRuntime;\n}\n/**\n * Per-branch tuning of Preview features. Only existing function slugs (those declared in\n * the static {@link PreviewInput.functions}) may be tuned — `Slug` is constrained to the\n * declared keys by {@link BranchTuningFn}.\n */\ninterface PreviewTuning<Slug extends string = string> {\n functions?: Partial<Record<Slug, FunctionTuning>>;\n}\n/**\n * The per-branch tuning object returned by the `branch` closure. It can adjust branch\n * lifecycle (`parent`, `ttl`, `protected`), Postgres compute settings, and per-function\n * deploy tuning — but **cannot** add/remove services or functions. That guarantee is what\n * keeps the static secret set (and therefore `NeonEnv`) exact.\n */\ninterface BranchTuning<Slug extends string = string> {\n /** Parent branch name used when creating a new branch. Not a Postgres setting. */\n parent?: string;\n /**\n * Branch time-to-live: how long after creation the branch should auto-expire. Applied\n * when creating a new branch and reconciled on existing branches (when `updateExisting`\n * is set). Accepts a {@link DurationString} (autocompletes common values) or a number of\n * seconds. Omit to keep the branch indefinitely.\n *\n * - {@link DurationString} — e.g. `\"7d\"`; autocompletes `\"1h\"`, `\"6h\"`, `\"12h\"`, `\"1d\"`,\n * `\"3d\"`, `\"7d\"`, `\"14d\"`, `\"30d\"`, and accepts any other `<integer><unit>` (units: `s`,\n * `m`, `h`, `d`, `w` — e.g. `\"12h\"`, `\"2w\"`). A **unit is required** — `\"7\"` is rejected;\n * for raw seconds pass a `number`.\n * - `number` — custom TTL in **seconds** (e.g. `3600`)\n * - `undefined` — no expiry; the branch persists until explicitly deleted\n *\n * The Neon API caps branch expiration at **30 days** from creation, so the resolved TTL must\n * be `> 0` and `<= 30d`; the suggestions stay within that limit and anything longer is\n * rejected at apply.\n *\n * @example \"1d\" // ephemeral preview branch: expires a day after creation\n * @example \"7d\" // one-week TTL\n * @example \"30d\" // the maximum the API allows\n * @example 3600 // 1 hour, expressed in seconds\n */\n ttl?: DurationField<TtlSuggestion>;\n /** Whether the selected branch should be protected. Undefined means \"leave as-is\". */\n protected?: boolean;\n postgres?: PostgresConfig;\n preview?: PreviewTuning<Slug>;\n}\n/** Extract the declared function slugs from a {@link PreviewInput} for closure typing. */\ntype FunctionSlugsOf<Preview extends PreviewInput | undefined> = Preview extends {\n functions: infer F;\n} ? Extract<keyof F, string> : string;\n/**\n * Signature of the `branch` closure. Generic over the static {@link PreviewInput} so the\n * `preview.functions` keys it may tune are constrained to the slugs actually declared.\n */\ntype BranchTuningFn<Preview extends PreviewInput | undefined = PreviewInput | undefined> = (branch: BranchTarget) => BranchTuning<FunctionSlugsOf<Preview>>;\n/**\n * A validated Neon branch policy — the value `defineConfig({ … })` returns and `neon.ts`\n * default-exports.\n *\n * Split into a **static** existential set (top-level `auth` / `dataApi` GA toggles plus the\n * beta `preview` block) and a **dynamic** per-branch `branch` closure for tuning. The\n * static half is what makes the secret set — and therefore `NeonEnv<typeof config>` and\n * `parseEnv` — exact; the closure can tune but never change what exists.\n *\n * Generic over the three static fields so the type system can read the exact toggle/slug\n * literals; the defaults make the bare `Config` a usable \"any policy\" type for runtime\n * function signatures.\n */\ninterface Config<Auth extends ServiceToggleInput | undefined = ServiceToggleInput | undefined, DataApi extends DataApiInput | undefined = DataApiInput | undefined, Preview extends PreviewInput | undefined = PreviewInput | undefined> {\n /** Neon Auth integration toggle (GA). Static — drives `NeonEnv.auth`. */\n auth?: Auth;\n /**\n * Neon Data API integration (GA). Static — drives `NeonEnv.dataApi`. A boolean/toggle, or\n * a {@link DataApiConfig} object selecting the auth provider (`\"neon\"` / `\"external\"`) and\n * runtime {@link DataApiSettings}. With `authProvider: \"neon\"` the policy must also enable\n * top-level `auth`.\n */\n dataApi?: DataApi;\n /** Beta (Preview) feature set: AI Gateway, functions, buckets. Static. */\n preview?: Preview;\n /** Per-branch tuning closure. Cannot change the static existential set. */\n branch?: BranchTuningFn<Preview>;\n}\n/**\n * A function with all deploy defaults applied. `resolveConfig` fills in `runtime` so\n * downstream diff/apply never has to re-derive it.\n */\ninterface ResolvedFunctionConfig {\n slug: string;\n name: string;\n source: string;\n env: Record<string, string>;\n runtime: FunctionRuntime;\n /**\n * Local-development settings, passed through untouched from {@link FunctionDef.dev}\n * (no defaults applied). Only consumed by `neon dev`; deploy ignores it.\n */\n dev?: FunctionDevConfig;\n}\n/** A bucket with its access level defaulted to `private`. */\ninterface ResolvedBucketConfig {\n name: string;\n access: BucketAccessLevel;\n}\n/**\n * Normalized {@link PreviewInput}. Only present on {@link ResolvedBranchConfig} when the\n * policy returned a `preview` block. `aiGatewayEnabled` follows the same\n * \"present-and-not-`false`\" semantics as `authEnabled` / `dataApiEnabled`.\n */\ninterface ResolvedPreviewConfig {\n functions: ResolvedFunctionConfig[];\n buckets: ResolvedBucketConfig[];\n aiGatewayEnabled: boolean;\n}\n/**\n * Normalized Data API integration. Present on {@link ResolvedBranchConfig} only when the\n * policy enables `dataApi`. `authProvider` always resolves (defaults to `\"neon\"`); the\n * external-IdP wiring is present only for `\"external\"`; `settings` carries the camelCase\n * runtime settings (reconciled as an update when they drift).\n */\ninterface ResolvedDataApiConfig {\n authProvider: DataApiAuthProvider;\n jwksUrl?: string;\n providerName?: string;\n jwtAudience?: string;\n settings?: DataApiSettings;\n}\ninterface ResolvedBranchConfig {\n parent?: string;\n ttlSeconds?: number;\n protected?: boolean;\n postgres?: PostgresConfig;\n authEnabled: boolean;\n dataApiEnabled: boolean;\n /**\n * Resolved Data API integration. Present iff {@link dataApiEnabled} is `true`. Carries the\n * create-time auth wiring and the updatable {@link DataApiSettings}.\n */\n dataApi?: ResolvedDataApiConfig;\n preview?: ResolvedPreviewConfig;\n}\n/**\n * One concrete change `pushConfig` made (or, in dry-run, would make) on the remote.\n */\ninterface AppliedChange {\n /**\n * `service` covers branch-scoped integrations driven by the branch policy (e.g.\n * Neon Auth, Data API).\n */\n kind: \"branch\" | \"service\";\n action: \"create\" | \"update\" | \"noop\";\n identifier: string;\n details?: Record<string, unknown>;\n}\n/**\n * A diff entry that conflicts with the desired config. `pushConfig` throws\n * {@link PushConflictError} on the first call when conflicts exist; pass\n * `updateExisting: true` to apply mutable drift (settings, `protected`, TTL, project\n * rename). Immutable fields (region, Postgres major version) are always conflicts —\n * recreate the project to change them.\n */\ninterface ConflictReport {\n kind: \"branch\";\n identifier: string;\n field: string;\n current: unknown;\n desired: unknown;\n reason: string;\n}\n/**\n * Result of a `pushConfig` invocation.\n */\ninterface PushResult {\n projectId: string;\n orgId?: string;\n branchId: string;\n branchName: string;\n /**\n * `true` when `pushConfig` was called with `{ dryRun: true }`. `applied` then records\n * what **would** be applied on a real push; no API mutations were performed.\n */\n dryRun: boolean;\n applied: AppliedChange[];\n conflicts: ConflictReport[];\n}\n//#endregion\nexport { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConflictReport, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DurationString, DurationUnit, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput };\n//# sourceMappingURL=types.d.ts.map"],"mappings":"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"}
|
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.8",
|
|
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",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"zod": "^4.4.3",
|
|
52
52
|
"yargs": "^18.0.0",
|
|
53
|
-
"@neon/config": "0.
|
|
53
|
+
"@neon/config": "0.10.0"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
|
56
56
|
"node": ">=20.19.0"
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
62
|
"build": "tsc --noEmit && tsdown",
|
|
63
|
-
"test": "vitest --passWithNoTests",
|
|
63
|
+
"test": "pnpm --filter @neon/env... build && vitest --passWithNoTests",
|
|
64
64
|
"test:ci": "vitest run --passWithNoTests",
|
|
65
65
|
"test:types": "vitest run --typecheck.enabled --typecheck.only",
|
|
66
66
|
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|