@neondatabase/env 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -4
- package/dist/config/dist/lib/neon-api.d.ts +35 -5
- package/dist/config/dist/lib/neon-api.d.ts.map +1 -1
- package/dist/config/dist/lib/types.d.ts +114 -4
- package/dist/config/dist/lib/types.d.ts.map +1 -1
- package/dist/config/dist/v1.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/lib/env.d.ts +98 -5
- package/dist/lib/env.d.ts.map +1 -1
- package/dist/lib/env.js +78 -6
- package/dist/lib/env.js.map +1 -1
- package/dist/v1.d.ts +2 -2
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ npm install @neondatabase/env
|
|
|
14
14
|
|
|
15
15
|
The library functions are **filesystem- and env-agnostic**: `fetchEnv` requires an explicit `projectId` + `branchId`. (The `neon-env` CLI does the `.neon`/`NEON_*` resolution and passes these in.)
|
|
16
16
|
|
|
17
|
-
> `parseEnv` takes **no branch name**: the secret set is static (top-level `config.auth` / `config.dataApi`), so it reads those toggles directly without evaluating the per-branch closure. Its optional second argument is a **scope** — omit it for external (app/build) env,
|
|
17
|
+
> `parseEnv` takes **no branch name**: the secret set is static (top-level `config.auth` / `config.dataApi`), so it reads those toggles directly without evaluating the per-branch closure. Its optional second argument is a **scope** _or_ a **key filter** — omit it for the full external (app/build) env, pass a **function slug** when running inside that deployed function (adds a typed `function` namespace of its declared env keys), or pass an **array of OS-level env-var keys** to require + return only that subset.
|
|
18
18
|
|
|
19
19
|
```ts
|
|
20
20
|
import config from "../neon";
|
|
@@ -31,14 +31,20 @@ const env2 = parseEnv(config);
|
|
|
31
31
|
// Inside a deployed function, pass its slug for the typed `function` namespace:
|
|
32
32
|
const fnEnv = parseEnv(config, "hello");
|
|
33
33
|
fnEnv.function.resendApiKey; // typed from hello's declared env keys
|
|
34
|
+
|
|
35
|
+
// Key filter — only enforce + return the vars you actually use (e.g. a Next.js app that
|
|
36
|
+
// reads the pooled URL but not the unpooled one). The keys autocomplete from the policy, so
|
|
37
|
+
// you can only select vars the policy enables, and the result is narrowed to match:
|
|
38
|
+
const { postgres } = parseEnv(config, ["DATABASE_URL"]);
|
|
39
|
+
postgres.databaseUrl; // string — `databaseUrlUnpooled` is absent, and never required
|
|
34
40
|
```
|
|
35
41
|
|
|
36
|
-
Both return the same namespaced `NeonEnv` shape: `postgres` is always present; `auth` and `dataApi` are included (and statically typed) when the evaluated branch policy enables them.
|
|
42
|
+
Both return the same namespaced `NeonEnv` shape: `postgres` is always present; `branch` (the branch name, surfaced as `NEON_BRANCH`) is always present on a `fetchEnv` result and present on a `parseEnv` result when `NEON_BRANCH` was injected; `auth` and `dataApi` are included (and statically typed) when the evaluated branch policy enables them.
|
|
37
43
|
|
|
38
44
|
| Function | Description |
|
|
39
45
|
| --- | --- |
|
|
40
46
|
| `fetchEnv(config, { projectId, branchId, ... })` | Async. Calls the Neon API for the given project + branch and returns live connection strings (and Auth/Data API values when enabled). `projectId` and `branchId` are required (`branchId` is a `br-…` id). |
|
|
41
|
-
| `parseEnv(config)` / `parseEnv(config, slug)` | Sync. Reads/validates the Neon env vars already present in `process.env` against the static policy toggles. With a function `slug`, also returns a typed `function` namespace of that function's declared env keys. Throws `PlatformError(EnvNotInjected)` listing missing vars when the env isn't populated. |
|
|
47
|
+
| `parseEnv(config)` / `parseEnv(config, slug)` / `parseEnv(config, keys)` | Sync. Reads/validates the Neon env vars already present in `process.env` against the static policy toggles. With a function `slug`, also returns a typed `function` namespace of that function's declared env keys. With a `keys` array (e.g. `["DATABASE_URL"]`), only those vars are required and returned, as a narrowed namespaced shape — the keys are typesafe against the policy. Throws `PlatformError(EnvNotInjected)` listing missing vars when the env isn't populated. |
|
|
42
48
|
| `toEntries(env)` | Project a resolved `NeonEnv` into `{ KEY: value }` pairs for cross-process transport (named after the web `.entries()` convention; returns a `Record`). |
|
|
43
49
|
|
|
44
50
|
## CLI
|
|
@@ -52,7 +58,7 @@ neon-env run -- npm run dev
|
|
|
52
58
|
neon-env run -- pnpm dev
|
|
53
59
|
```
|
|
54
60
|
|
|
55
|
-
`run` loads `neon.ts`, resolves the branch (via `--branch`, `NEON_BRANCH_ID`, or `.neon[/project.json]`), fetches the connection strings from Neon, and spawns the command with `DATABASE_URL` / `DATABASE_URL_UNPOOLED` (and `NEON_AUTH_BASE_URL` / `NEON_AUTH_JWKS_URL` / `NEON_DATA_API_URL` when the policy enables them) injected on top of the inherited environment. Stdio is inherited so interactive dev servers keep working, and the parent exits with the child's exit code.
|
|
61
|
+
`run` loads `neon.ts`, resolves the branch (via `--branch`, `NEON_BRANCH_ID`, or `.neon[/project.json]`), fetches the connection strings from Neon, and spawns the command with `NEON_BRANCH` / `DATABASE_URL` / `DATABASE_URL_UNPOOLED` (and `NEON_AUTH_BASE_URL` / `NEON_AUTH_JWKS_URL` / `NEON_DATA_API_URL` when the policy enables them) injected on top of the inherited environment. Stdio is inherited so interactive dev servers keep working, and the parent exits with the child's exit code.
|
|
56
62
|
|
|
57
63
|
### `export` — print env to stdout
|
|
58
64
|
|
|
@@ -76,6 +82,7 @@ Flags (both commands): `--config <path>`, `--project-id`, `--branch`, `--api-key
|
|
|
76
82
|
|
|
77
83
|
| Key | From |
|
|
78
84
|
| --- | --- |
|
|
85
|
+
| `NEON_BRANCH` | the resolved branch **name** — mirrors what the Neon Functions runtime injects on every branch, so local dev matches the deployed runtime |
|
|
79
86
|
| `DATABASE_URL` | pooled connection string |
|
|
80
87
|
| `DATABASE_URL_UNPOOLED` | direct connection string |
|
|
81
88
|
| `NEON_AUTH_BASE_URL` | Neon Auth integration (when `auth` is enabled) |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BucketAccessLevel, ComputeSettings, CredentialPrincipalType, CredentialScope, FunctionRuntime } from "./types.js";
|
|
1
|
+
import { BucketAccessLevel, ComputeSettings, CredentialPrincipalType, CredentialScope, DataApiAuthProvider, DataApiSettings, FunctionRuntime } from "./types.js";
|
|
2
2
|
|
|
3
3
|
//#region ../config/dist/lib/neon-api.d.ts
|
|
4
4
|
|
|
@@ -96,11 +96,32 @@ interface NeonAuthSnapshot {
|
|
|
96
96
|
baseUrl?: string;
|
|
97
97
|
}
|
|
98
98
|
/**
|
|
99
|
-
* Public, fetchable bits of a Neon Data API integration on a specific branch
|
|
99
|
+
* Public, fetchable bits of a Neon Data API integration on a specific branch — the subset of
|
|
100
|
+
* the Neon API `DataAPIReponse` we model. `settings` is only populated for SubZero-backed
|
|
101
|
+
* integrations (the API returns `null` otherwise), so it is used for settings-drift diffing
|
|
102
|
+
* when present and ignored when absent.
|
|
100
103
|
*/
|
|
101
104
|
interface NeonDataApiSnapshot {
|
|
102
105
|
/** REST endpoint URL. */
|
|
103
106
|
url: string;
|
|
107
|
+
/** Deployment status (e.g. `"ready"`), when reported. */
|
|
108
|
+
status?: string;
|
|
109
|
+
/** Current runtime settings (SubZero only); `null`/absent when not reported. */
|
|
110
|
+
settings?: DataApiSettings | null;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Input for {@link NeonApi.enableProjectBranchDataApi} — the create-time wiring for a Data
|
|
114
|
+
* API integration (the subset of the Neon API `DataAPICreateRequest` we expose; the
|
|
115
|
+
* `add_default_grants` / `skip_auth_schema` create flags are intentionally not modeled).
|
|
116
|
+
* `authProvider` is the friendly `"neon"` / `"external"` value (mapped to the API's
|
|
117
|
+
* `neon_auth` / `external` by the adapter).
|
|
118
|
+
*/
|
|
119
|
+
interface EnableDataApiInput {
|
|
120
|
+
authProvider?: DataApiAuthProvider;
|
|
121
|
+
jwksUrl?: string;
|
|
122
|
+
providerName?: string;
|
|
123
|
+
jwtAudience?: string;
|
|
124
|
+
settings?: DataApiSettings;
|
|
104
125
|
}
|
|
105
126
|
/**
|
|
106
127
|
* A branchable object-storage bucket (Preview). Backed by the Neon Platform
|
|
@@ -292,9 +313,18 @@ interface NeonApi {
|
|
|
292
313
|
/**
|
|
293
314
|
* Enable the Neon Data API integration on a specific branch + database. Idempotent:
|
|
294
315
|
* if an integration is already enabled, the existing snapshot is returned unchanged.
|
|
295
|
-
* Used by `pushConfig`
|
|
316
|
+
* Used by `pushConfig` to honour branch policy `dataApi: {}` / `dataApi: { … }`. The
|
|
317
|
+
* optional {@link EnableDataApiInput} carries the create-time auth wiring + initial
|
|
318
|
+
* settings; omit it for an all-defaults, Neon-Auth integration.
|
|
319
|
+
*/
|
|
320
|
+
enableProjectBranchDataApi(projectId: string, branchId: string, databaseName: string, input?: EnableDataApiInput): Promise<NeonDataApiSnapshot>;
|
|
321
|
+
/**
|
|
322
|
+
* Update the runtime {@link DataApiSettings} of an already-enabled Data API integration
|
|
323
|
+
* (the Neon API `PATCH .../data-api/{db}`; always refreshes the schema cache). Only
|
|
324
|
+
* `settings` are mutable post-create — the auth provider / JWKS wiring is fixed at
|
|
325
|
+
* enable time. Used by `pushConfig` to reconcile settings drift under `updateExisting`.
|
|
296
326
|
*/
|
|
297
|
-
|
|
327
|
+
updateProjectBranchDataApi(projectId: string, branchId: string, databaseName: string, settings: DataApiSettings): Promise<NeonDataApiSnapshot>;
|
|
298
328
|
/** List branchable object-storage buckets visible on a branch. */
|
|
299
329
|
listBranchBuckets(projectId: string, branchId: string): Promise<NeonBucketSnapshot[]>;
|
|
300
330
|
/** Create a bucket on a branch. Used by `pushConfig` to honour `preview.buckets`. */
|
|
@@ -341,5 +371,5 @@ interface NeonApi {
|
|
|
341
371
|
}
|
|
342
372
|
//#endregion
|
|
343
373
|
//#endregion
|
|
344
|
-
export { CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, DeployFunctionInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, UpdateBranchInput };
|
|
374
|
+
export { CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, DeployFunctionInput, EnableDataApiInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, UpdateBranchInput };
|
|
345
375
|
//# sourceMappingURL=neon-api.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neon-api.d.ts","names":["BucketAccessLevel","ComputeSettings","CredentialPrincipalType","CredentialScope","FunctionRuntime","NeonProjectSnapshot","NeonBranchSnapshot","NeonEndpointSnapshot","CreateProjectInput","CreateBranchInput","UpdateBranchInput","NeonRoleSnapshot","NeonDatabaseSnapshot","NeonAuthSnapshot","NeonDataApiSnapshot","NeonBucketSnapshot","NeonBranchStorageSnapshot","CreateBucketInput","NeonFunctionSnapshot","DeployFunctionInput","Uint8Array","Record","NeonFunctionDeploymentSnapshot","CreateCredentialInput","NeonCredentialSecret","NeonCredentialMeta","GetConnectionUriInput","NeonApi","Promise"],"sources":["../../../../../config/dist/lib/neon-api.d.ts"],"sourcesContent":["import { BucketAccessLevel, ComputeSettings, CredentialPrincipalType, CredentialScope, FunctionRuntime } from \"./types.js\";\n\n//#region src/lib/neon-api.d.ts\n\n/**\n * Snapshot of a Neon project field set we care about. Maps onto a subset of the upstream\n * `@neondatabase/api-client` `Project` type. We do **not** widen this to the full upstream\n * shape — keeping the surface narrow makes the in-memory fake practical to maintain.\n */\ninterface NeonProjectSnapshot {\n id: string;\n name: string;\n regionId: string;\n pgVersion: number;\n orgId?: string;\n defaultEndpointSettings?: ComputeSettings;\n}\ninterface NeonBranchSnapshot {\n id: string;\n name: string;\n parentId?: string;\n isDefault: boolean;\n /** Whether the branch is marked protected on Neon. */\n protected: boolean;\n expiresAt?: string;\n}\ninterface NeonEndpointSnapshot {\n id: string;\n branchId: string;\n type: \"read_only\" | \"read_write\";\n autoscalingLimitMinCu: ComputeSettings[\"autoscalingLimitMinCu\"];\n autoscalingLimitMaxCu: ComputeSettings[\"autoscalingLimitMaxCu\"];\n suspendTimeout: ComputeSettings[\"suspendTimeout\"];\n}\ninterface CreateProjectInput {\n name: string;\n regionId: string;\n pgVersion?: number;\n orgId?: string;\n defaultEndpointSettings?: ComputeSettings;\n /**\n * Optional name for the project's auto-created default branch. When omitted, Neon\n * uses its own default (`main`).\n */\n defaultBranchName?: string;\n}\ninterface CreateBranchInput {\n name: string;\n parentId?: string;\n expiresAt?: string;\n /** When `true`, the branch is created with the `protected` flag set on Neon. */\n protected?: boolean;\n computeSettings?: ComputeSettings;\n}\ninterface UpdateBranchInput {\n name?: string;\n expiresAt?: string | null;\n /** When set, toggles the branch's `protected` flag on Neon. */\n protected?: boolean;\n}\n/**\n * A role on a Neon branch (e.g. `neondb_owner`). Passwords are never returned by\n * {@link NeonApi.listBranchRoles}; use {@link NeonApi.getConnectionUri} to fetch a URI\n * with the role's password baked in.\n */\ninterface NeonRoleSnapshot {\n name: string;\n branchId: string;\n /** Whether the role is system-protected (cannot be deleted). */\n protected: boolean;\n}\n/**\n * A database on a Neon branch (e.g. `neondb`).\n */\ninterface NeonDatabaseSnapshot {\n name: string;\n branchId: string;\n /** The role that owns the database (one role can own multiple databases). */\n ownerName: string;\n}\n/**\n * Bits of a Neon Auth integration. The key fields are optional because the Neon API only\n * includes them on create / rotate responses; `GET /auth` returns the public fields.\n */\ninterface NeonAuthSnapshot {\n /** The Neon Auth project id (`auth_provider_project_id` on the Neon API). */\n projectId: string;\n /** Public client key (`pub_client_key`), only present on create / rotate responses. */\n publishableClientKey?: string;\n /** Secret server key (`secret_server_key`), only present on create / rotate responses. */\n secretServerKey?: string;\n /** JWKS URL for verifying tokens issued by Neon Auth. */\n jwksUrl: string;\n /** Optional base URL of the Neon Auth deployment. */\n baseUrl?: string;\n}\n/**\n * Public, fetchable bits of a Neon Data API integration on a specific branch.\n */\ninterface NeonDataApiSnapshot {\n /** REST endpoint URL. */\n url: string;\n}\n/**\n * A branchable object-storage bucket (Preview). Backed by the Neon Platform\n * branchable-storage service.\n */\ninterface NeonBucketSnapshot {\n name: string;\n accessLevel: BucketAccessLevel;\n}\n/**\n * S3-compatible connection details for a branch's object storage (Preview) — the\n * `BranchStorage` shape from `GET /projects/{id}/branches/{id}/storage`. Non-secret: it\n * carries the endpoint/region/addressing the S3 SDK needs, while the access keys come from\n * a minted {@link NeonCredentialSecret}. `forcePathStyle` is always `true` today (Neon's\n * wildcard TLS cert puts the branch id in the subdomain, so the bucket must travel in the\n * path).\n */\ninterface NeonBranchStorageSnapshot {\n /** S3-compatible endpoint URL, e.g. `https://br-….storage.<suffix>`. */\n s3Endpoint: string;\n /** AWS region string, normalized server-side (e.g. `us-east-2`, `us-east-1`). */\n region: string;\n /** Whether the S3 client must use path-style addressing (always `true` today). */\n forcePathStyle: boolean;\n}\n/**\n * Input for creating a bucket on a branch.\n */\ninterface CreateBucketInput {\n name: string;\n accessLevel?: BucketAccessLevel;\n}\n/**\n * A Neon Function on a branch (Preview). Mirrors the subset of the Functions API we model:\n * the immutable `slug`, the display `name`, and the active deployment id when one exists.\n */\ninterface NeonFunctionSnapshot {\n /** Opaque, stable function identifier. */\n id: string;\n /** Branch-unique slug (the invocation path segment). Immutable. */\n slug: string;\n /** Free-form display name. */\n name: string;\n /** URL at which the function is invoked. */\n invocationUrl: string;\n /** Id (platform version number) of the active deployment, when any code is deployed. */\n activeDeploymentId?: number;\n}\n/**\n * Input for deploying code to a function. `bundle` is the already-built ZIP archive of the\n * function source — building it (esbuild + zip) is an imperative step performed by the\n * caller, not by the {@link NeonApi} adapter.\n */\ninterface DeployFunctionInput {\n bundle: Uint8Array;\n runtime: FunctionRuntime;\n environment: Record<string, string>;\n}\n/**\n * A function deployment (Preview).\n */\ninterface NeonFunctionDeploymentSnapshot {\n /** The deployment id (monotonic per function). */\n id: number;\n status: \"pending\" | \"building\" | \"completed\" | \"failed\";\n}\n/**\n * Input for {@link NeonApi.createCredential}. Mirrors the Neon API `CreateCredentialRequest`\n * (`POST .../credentials`, `x-stability-level: beta`):\n *\n * - `scopes` — 1–16 capabilities the credential may exercise (derived from the policy's\n * enabled Preview features, never hand-authored).\n * - `principalType` — `user` (developer/app) or `function` (a deployed function).\n * - `functionId` — required when `principalType === \"function\"`.\n * - `name` — optional free-form label echoed back on the response.\n */\ninterface CreateCredentialInput {\n scopes: CredentialScope[];\n principalType: CredentialPrincipalType;\n functionId?: string;\n name?: string;\n}\n/**\n * The secret-bearing result of {@link NeonApi.createCredential} — the Neon API\n * `CreateCredentialResponse`. `apiToken` and `s3SecretAccessKey` are returned **exactly\n * once** (they are not stored server-side), so the caller must persist them immediately;\n * they can never be re-fetched (the list endpoint returns metadata only). `tokenIdShort`\n * is the public identifier embedded in `apiToken` (`nt_live_<tokenIdShort>_…`) and doubles\n * as the S3 access-key id.\n */\ninterface NeonCredentialSecret {\n tokenId: string;\n tokenIdShort: string;\n name?: string;\n /** Bearer token (`nt_live_…`); returned once. Used for AI Gateway / Functions invoke. */\n apiToken: string;\n /** 64-char hex S3 secret access key; returned once. Paired with `tokenIdShort` as the access-key id. */\n s3SecretAccessKey: string;\n scopes: CredentialScope[];\n branchId: string;\n createdAt: string;\n /** When the credential expires; absent means it never expires. */\n expiresAt?: string;\n}\n/**\n * Secret-free metadata for an issued credential — the Neon API `CredentialMeta` returned by\n * {@link NeonApi.listCredentials}. Never includes `apiToken` / `s3SecretAccessKey`.\n */\ninterface NeonCredentialMeta {\n tokenId: string;\n tokenIdShort: string;\n name?: string;\n scopes: CredentialScope[];\n principalType: CredentialPrincipalType;\n functionId?: string;\n branchId?: string;\n createdAt: string;\n lastUsedAt?: string;\n revokedAt?: string;\n expiresAt?: string;\n}\n/**\n * Parameters accepted by {@link NeonApi.getConnectionUri}. `branchId` and `endpointId`\n * are optional — when omitted, the API uses the project's default branch and that\n * branch's read-write endpoint, respectively.\n */\ninterface GetConnectionUriInput {\n branchId?: string;\n endpointId?: string;\n databaseName: string;\n roleName: string;\n /** When `true`, returns the pooled (PgBouncer) URI instead of the direct URI. */\n pooled?: boolean;\n}\n/**\n * Narrow façade over the Neon management API. `pullConfig`, `pushConfig`, and `fetchEnv`\n * depend on this interface — *not* on `@neondatabase/api-client` directly — which lets us\n * inject a real in-memory fake during tests without resorting to module mocks.\n */\ninterface NeonApi {\n listProjects(filter: {\n orgId?: string;\n }): Promise<NeonProjectSnapshot[]>;\n getProject(projectId: string): Promise<NeonProjectSnapshot>;\n createProject(input: CreateProjectInput): Promise<NeonProjectSnapshot>;\n updateProject(projectId: string, input: {\n name?: string;\n defaultEndpointSettings?: ComputeSettings;\n }): Promise<NeonProjectSnapshot>;\n listBranches(projectId: string): Promise<NeonBranchSnapshot[]>;\n createBranch(projectId: string, input: CreateBranchInput): Promise<{\n branch: NeonBranchSnapshot;\n endpoints: NeonEndpointSnapshot[];\n }>;\n updateBranch(projectId: string, branchId: string, input: UpdateBranchInput): Promise<NeonBranchSnapshot>;\n listEndpoints(projectId: string): Promise<NeonEndpointSnapshot[]>;\n updateEndpoint(projectId: string, endpointId: string, settings: ComputeSettings): Promise<NeonEndpointSnapshot>;\n /** List roles on a branch. Used by {@link fetchEnv} to auto-pick the role when only one exists. */\n listBranchRoles(projectId: string, branchId: string): Promise<NeonRoleSnapshot[]>;\n /** List databases on a branch. Used by {@link fetchEnv} to auto-pick the database when only one exists. */\n listBranchDatabases(projectId: string, branchId: string): Promise<NeonDatabaseSnapshot[]>;\n /**\n * Fetch a Postgres connection URI for the given role + database on a branch.\n * Returns the same string the Neon Console shows under \"Connection Details\".\n */\n getConnectionUri(projectId: string, input: GetConnectionUriInput): Promise<{\n uri: string;\n }>;\n /**\n * Fetch the Neon Auth integration attached to a specific branch. Returns `null` when\n * no integration is enabled — used by `fetchEnv` to decide whether the `env.auth`\n * namespace can be populated.\n */\n getNeonAuth(projectId: string, branchId: string): Promise<NeonAuthSnapshot | null>;\n /**\n * Enable the Neon Auth integration on a specific branch. Idempotent: if an integration\n * is already enabled, the existing snapshot is returned unchanged. Used by\n * `pushConfig` and `branch` to honour branch policy `auth: {}` / `auth.enabled: true`.\n */\n enableNeonAuth(projectId: string, branchId: string, input?: {\n databaseName?: string;\n }): Promise<NeonAuthSnapshot>;\n /**\n * Fetch the Neon Data API integration attached to a specific branch + database.\n * Returns `null` when no integration is enabled — used by `fetchEnv` to decide\n * whether the `env.dataApi` namespace can be populated.\n */\n getNeonDataApi(projectId: string, branchId: string, databaseName: string): Promise<NeonDataApiSnapshot | null>;\n /**\n * Enable the Neon Data API integration on a specific branch + database. Idempotent:\n * if an integration is already enabled, the existing snapshot is returned unchanged.\n * Used by `pushConfig` and `branch` to honour branch policy `dataApi: {}` / `dataApi.enabled: true`.\n */\n enableProjectBranchDataApi(projectId: string, branchId: string, databaseName: string): Promise<NeonDataApiSnapshot>;\n /** List branchable object-storage buckets visible on a branch. */\n listBranchBuckets(projectId: string, branchId: string): Promise<NeonBucketSnapshot[]>;\n /** Create a bucket on a branch. Used by `pushConfig` to honour `preview.buckets`. */\n createBranchBucket(projectId: string, branchId: string, input: CreateBucketInput): Promise<NeonBucketSnapshot>;\n /** Delete a bucket from a branch. */\n deleteBranchBucket(projectId: string, branchId: string, bucketName: string): Promise<void>;\n /**\n * Fetch the branch's S3-compatible object-storage connection details (endpoint, region,\n * path-style). Returns `null` when storage is not enabled for the branch (the API's 404\n * `BranchStorageNotEnabled`). Used by `fetchEnv` to populate the `AWS_*` storage env\n * alongside the minted credential's access keys.\n */\n getProjectBranchStorage(projectId: string, branchId: string): Promise<NeonBranchStorageSnapshot | null>;\n /** List functions on a branch. */\n listBranchFunctions(projectId: string, branchId: string): Promise<NeonFunctionSnapshot[]>;\n /** Delete a function (by slug) from a branch. */\n deleteBranchFunction(projectId: string, branchId: string, slug: string): Promise<void>;\n /**\n * Deploy a built bundle to a function, creating the function if it does not yet exist —\n * Neon has no separate create endpoint, so the first deployment to a slug creates the\n * function. The newest deployment becomes active. The `bundle` is built (esbuild + zip)\n * by the caller and passed in as bytes.\n */\n deployBranchFunction(projectId: string, branchId: string, slug: string, input: DeployFunctionInput): Promise<NeonFunctionDeploymentSnapshot>;\n /**\n * Mint a new scoped service credential on a branch (`POST .../credentials`). The\n * returned {@link NeonCredentialSecret} carries `apiToken` + `s3SecretAccessKey`\n * **once** — persist them immediately. Used by `fetchEnv` / `env pull` to issue the\n * unified credential for the branch's enabled Preview features (object storage, AI\n * Gateway, Functions).\n */\n createCredential(projectId: string, branchId: string, input: CreateCredentialInput): Promise<NeonCredentialSecret>;\n /**\n * List the secret-free metadata for credentials issued on a branch\n * (`GET .../credentials`). Used to report issued credentials (e.g. `config status`)\n * and to verify a persisted credential still exists / isn't revoked.\n */\n listCredentials(projectId: string, branchId: string): Promise<NeonCredentialMeta[]>;\n /**\n * Revoke (soft-delete) a credential by its `tokenId` (`DELETE .../credentials/{id}`).\n * Idempotent.\n */\n revokeCredential(projectId: string, branchId: string, tokenId: string): Promise<void>;\n}\n//#endregion\nexport { CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, DeployFunctionInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, UpdateBranchInput };\n//# sourceMappingURL=neon-api.d.ts.map"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"neon-api.d.ts","names":["BucketAccessLevel","ComputeSettings","CredentialPrincipalType","CredentialScope","DataApiAuthProvider","DataApiSettings","FunctionRuntime","NeonProjectSnapshot","NeonBranchSnapshot","NeonEndpointSnapshot","CreateProjectInput","CreateBranchInput","UpdateBranchInput","NeonRoleSnapshot","NeonDatabaseSnapshot","NeonAuthSnapshot","NeonDataApiSnapshot","EnableDataApiInput","NeonBucketSnapshot","NeonBranchStorageSnapshot","CreateBucketInput","NeonFunctionSnapshot","DeployFunctionInput","Uint8Array","Record","NeonFunctionDeploymentSnapshot","CreateCredentialInput","NeonCredentialSecret","NeonCredentialMeta","GetConnectionUriInput","NeonApi","Promise"],"sources":["../../../../../config/dist/lib/neon-api.d.ts"],"sourcesContent":["import { BucketAccessLevel, ComputeSettings, CredentialPrincipalType, CredentialScope, DataApiAuthProvider, DataApiSettings, FunctionRuntime } from \"./types.js\";\n\n//#region src/lib/neon-api.d.ts\n\n/**\n * Snapshot of a Neon project field set we care about. Maps onto a subset of the upstream\n * `@neondatabase/api-client` `Project` type. We do **not** widen this to the full upstream\n * shape — keeping the surface narrow makes the in-memory fake practical to maintain.\n */\ninterface NeonProjectSnapshot {\n id: string;\n name: string;\n regionId: string;\n pgVersion: number;\n orgId?: string;\n defaultEndpointSettings?: ComputeSettings;\n}\ninterface NeonBranchSnapshot {\n id: string;\n name: string;\n parentId?: string;\n isDefault: boolean;\n /** Whether the branch is marked protected on Neon. */\n protected: boolean;\n expiresAt?: string;\n}\ninterface NeonEndpointSnapshot {\n id: string;\n branchId: string;\n type: \"read_only\" | \"read_write\";\n autoscalingLimitMinCu: ComputeSettings[\"autoscalingLimitMinCu\"];\n autoscalingLimitMaxCu: ComputeSettings[\"autoscalingLimitMaxCu\"];\n suspendTimeout: ComputeSettings[\"suspendTimeout\"];\n}\ninterface CreateProjectInput {\n name: string;\n regionId: string;\n pgVersion?: number;\n orgId?: string;\n defaultEndpointSettings?: ComputeSettings;\n /**\n * Optional name for the project's auto-created default branch. When omitted, Neon\n * uses its own default (`main`).\n */\n defaultBranchName?: string;\n}\ninterface CreateBranchInput {\n name: string;\n parentId?: string;\n expiresAt?: string;\n /** When `true`, the branch is created with the `protected` flag set on Neon. */\n protected?: boolean;\n computeSettings?: ComputeSettings;\n}\ninterface UpdateBranchInput {\n name?: string;\n expiresAt?: string | null;\n /** When set, toggles the branch's `protected` flag on Neon. */\n protected?: boolean;\n}\n/**\n * A role on a Neon branch (e.g. `neondb_owner`). Passwords are never returned by\n * {@link NeonApi.listBranchRoles}; use {@link NeonApi.getConnectionUri} to fetch a URI\n * with the role's password baked in.\n */\ninterface NeonRoleSnapshot {\n name: string;\n branchId: string;\n /** Whether the role is system-protected (cannot be deleted). */\n protected: boolean;\n}\n/**\n * A database on a Neon branch (e.g. `neondb`).\n */\ninterface NeonDatabaseSnapshot {\n name: string;\n branchId: string;\n /** The role that owns the database (one role can own multiple databases). */\n ownerName: string;\n}\n/**\n * Bits of a Neon Auth integration. The key fields are optional because the Neon API only\n * includes them on create / rotate responses; `GET /auth` returns the public fields.\n */\ninterface NeonAuthSnapshot {\n /** The Neon Auth project id (`auth_provider_project_id` on the Neon API). */\n projectId: string;\n /** Public client key (`pub_client_key`), only present on create / rotate responses. */\n publishableClientKey?: string;\n /** Secret server key (`secret_server_key`), only present on create / rotate responses. */\n secretServerKey?: string;\n /** JWKS URL for verifying tokens issued by Neon Auth. */\n jwksUrl: string;\n /** Optional base URL of the Neon Auth deployment. */\n baseUrl?: string;\n}\n/**\n * Public, fetchable bits of a Neon Data API integration on a specific branch — the subset of\n * the Neon API `DataAPIReponse` we model. `settings` is only populated for SubZero-backed\n * integrations (the API returns `null` otherwise), so it is used for settings-drift diffing\n * when present and ignored when absent.\n */\ninterface NeonDataApiSnapshot {\n /** REST endpoint URL. */\n url: string;\n /** Deployment status (e.g. `\"ready\"`), when reported. */\n status?: string;\n /** Current runtime settings (SubZero only); `null`/absent when not reported. */\n settings?: DataApiSettings | null;\n}\n/**\n * Input for {@link NeonApi.enableProjectBranchDataApi} — the create-time wiring for a Data\n * API integration (the subset of the Neon API `DataAPICreateRequest` we expose; the\n * `add_default_grants` / `skip_auth_schema` create flags are intentionally not modeled).\n * `authProvider` is the friendly `\"neon\"` / `\"external\"` value (mapped to the API's\n * `neon_auth` / `external` by the adapter).\n */\ninterface EnableDataApiInput {\n authProvider?: DataApiAuthProvider;\n jwksUrl?: string;\n providerName?: string;\n jwtAudience?: string;\n settings?: DataApiSettings;\n}\n/**\n * A branchable object-storage bucket (Preview). Backed by the Neon Platform\n * branchable-storage service.\n */\ninterface NeonBucketSnapshot {\n name: string;\n accessLevel: BucketAccessLevel;\n}\n/**\n * S3-compatible connection details for a branch's object storage (Preview) — the\n * `BranchStorage` shape from `GET /projects/{id}/branches/{id}/storage`. Non-secret: it\n * carries the endpoint/region/addressing the S3 SDK needs, while the access keys come from\n * a minted {@link NeonCredentialSecret}. `forcePathStyle` is always `true` today (Neon's\n * wildcard TLS cert puts the branch id in the subdomain, so the bucket must travel in the\n * path).\n */\ninterface NeonBranchStorageSnapshot {\n /** S3-compatible endpoint URL, e.g. `https://br-….storage.<suffix>`. */\n s3Endpoint: string;\n /** AWS region string, normalized server-side (e.g. `us-east-2`, `us-east-1`). */\n region: string;\n /** Whether the S3 client must use path-style addressing (always `true` today). */\n forcePathStyle: boolean;\n}\n/**\n * Input for creating a bucket on a branch.\n */\ninterface CreateBucketInput {\n name: string;\n accessLevel?: BucketAccessLevel;\n}\n/**\n * A Neon Function on a branch (Preview). Mirrors the subset of the Functions API we model:\n * the immutable `slug`, the display `name`, and the active deployment id when one exists.\n */\ninterface NeonFunctionSnapshot {\n /** Opaque, stable function identifier. */\n id: string;\n /** Branch-unique slug (the invocation path segment). Immutable. */\n slug: string;\n /** Free-form display name. */\n name: string;\n /** URL at which the function is invoked. */\n invocationUrl: string;\n /** Id (platform version number) of the active deployment, when any code is deployed. */\n activeDeploymentId?: number;\n}\n/**\n * Input for deploying code to a function. `bundle` is the already-built ZIP archive of the\n * function source — building it (esbuild + zip) is an imperative step performed by the\n * caller, not by the {@link NeonApi} adapter.\n */\ninterface DeployFunctionInput {\n bundle: Uint8Array;\n runtime: FunctionRuntime;\n environment: Record<string, string>;\n}\n/**\n * A function deployment (Preview).\n */\ninterface NeonFunctionDeploymentSnapshot {\n /** The deployment id (monotonic per function). */\n id: number;\n status: \"pending\" | \"building\" | \"completed\" | \"failed\";\n}\n/**\n * Input for {@link NeonApi.createCredential}. Mirrors the Neon API `CreateCredentialRequest`\n * (`POST .../credentials`, `x-stability-level: beta`):\n *\n * - `scopes` — 1–16 capabilities the credential may exercise (derived from the policy's\n * enabled Preview features, never hand-authored).\n * - `principalType` — `user` (developer/app) or `function` (a deployed function).\n * - `functionId` — required when `principalType === \"function\"`.\n * - `name` — optional free-form label echoed back on the response.\n */\ninterface CreateCredentialInput {\n scopes: CredentialScope[];\n principalType: CredentialPrincipalType;\n functionId?: string;\n name?: string;\n}\n/**\n * The secret-bearing result of {@link NeonApi.createCredential} — the Neon API\n * `CreateCredentialResponse`. `apiToken` and `s3SecretAccessKey` are returned **exactly\n * once** (they are not stored server-side), so the caller must persist them immediately;\n * they can never be re-fetched (the list endpoint returns metadata only). `tokenIdShort`\n * is the public identifier embedded in `apiToken` (`nt_live_<tokenIdShort>_…`) and doubles\n * as the S3 access-key id.\n */\ninterface NeonCredentialSecret {\n tokenId: string;\n tokenIdShort: string;\n name?: string;\n /** Bearer token (`nt_live_…`); returned once. Used for AI Gateway / Functions invoke. */\n apiToken: string;\n /** 64-char hex S3 secret access key; returned once. Paired with `tokenIdShort` as the access-key id. */\n s3SecretAccessKey: string;\n scopes: CredentialScope[];\n branchId: string;\n createdAt: string;\n /** When the credential expires; absent means it never expires. */\n expiresAt?: string;\n}\n/**\n * Secret-free metadata for an issued credential — the Neon API `CredentialMeta` returned by\n * {@link NeonApi.listCredentials}. Never includes `apiToken` / `s3SecretAccessKey`.\n */\ninterface NeonCredentialMeta {\n tokenId: string;\n tokenIdShort: string;\n name?: string;\n scopes: CredentialScope[];\n principalType: CredentialPrincipalType;\n functionId?: string;\n branchId?: string;\n createdAt: string;\n lastUsedAt?: string;\n revokedAt?: string;\n expiresAt?: string;\n}\n/**\n * Parameters accepted by {@link NeonApi.getConnectionUri}. `branchId` and `endpointId`\n * are optional — when omitted, the API uses the project's default branch and that\n * branch's read-write endpoint, respectively.\n */\ninterface GetConnectionUriInput {\n branchId?: string;\n endpointId?: string;\n databaseName: string;\n roleName: string;\n /** When `true`, returns the pooled (PgBouncer) URI instead of the direct URI. */\n pooled?: boolean;\n}\n/**\n * Narrow façade over the Neon management API. `pullConfig`, `pushConfig`, and `fetchEnv`\n * depend on this interface — *not* on `@neondatabase/api-client` directly — which lets us\n * inject a real in-memory fake during tests without resorting to module mocks.\n */\ninterface NeonApi {\n listProjects(filter: {\n orgId?: string;\n }): Promise<NeonProjectSnapshot[]>;\n getProject(projectId: string): Promise<NeonProjectSnapshot>;\n createProject(input: CreateProjectInput): Promise<NeonProjectSnapshot>;\n updateProject(projectId: string, input: {\n name?: string;\n defaultEndpointSettings?: ComputeSettings;\n }): Promise<NeonProjectSnapshot>;\n listBranches(projectId: string): Promise<NeonBranchSnapshot[]>;\n createBranch(projectId: string, input: CreateBranchInput): Promise<{\n branch: NeonBranchSnapshot;\n endpoints: NeonEndpointSnapshot[];\n }>;\n updateBranch(projectId: string, branchId: string, input: UpdateBranchInput): Promise<NeonBranchSnapshot>;\n listEndpoints(projectId: string): Promise<NeonEndpointSnapshot[]>;\n updateEndpoint(projectId: string, endpointId: string, settings: ComputeSettings): Promise<NeonEndpointSnapshot>;\n /** List roles on a branch. Used by {@link fetchEnv} to auto-pick the role when only one exists. */\n listBranchRoles(projectId: string, branchId: string): Promise<NeonRoleSnapshot[]>;\n /** List databases on a branch. Used by {@link fetchEnv} to auto-pick the database when only one exists. */\n listBranchDatabases(projectId: string, branchId: string): Promise<NeonDatabaseSnapshot[]>;\n /**\n * Fetch a Postgres connection URI for the given role + database on a branch.\n * Returns the same string the Neon Console shows under \"Connection Details\".\n */\n getConnectionUri(projectId: string, input: GetConnectionUriInput): Promise<{\n uri: string;\n }>;\n /**\n * Fetch the Neon Auth integration attached to a specific branch. Returns `null` when\n * no integration is enabled — used by `fetchEnv` to decide whether the `env.auth`\n * namespace can be populated.\n */\n getNeonAuth(projectId: string, branchId: string): Promise<NeonAuthSnapshot | null>;\n /**\n * Enable the Neon Auth integration on a specific branch. Idempotent: if an integration\n * is already enabled, the existing snapshot is returned unchanged. Used by\n * `pushConfig` and `branch` to honour branch policy `auth: {}` / `auth.enabled: true`.\n */\n enableNeonAuth(projectId: string, branchId: string, input?: {\n databaseName?: string;\n }): Promise<NeonAuthSnapshot>;\n /**\n * Fetch the Neon Data API integration attached to a specific branch + database.\n * Returns `null` when no integration is enabled — used by `fetchEnv` to decide\n * whether the `env.dataApi` namespace can be populated.\n */\n getNeonDataApi(projectId: string, branchId: string, databaseName: string): Promise<NeonDataApiSnapshot | null>;\n /**\n * Enable the Neon Data API integration on a specific branch + database. Idempotent:\n * if an integration is already enabled, the existing snapshot is returned unchanged.\n * Used by `pushConfig` to honour branch policy `dataApi: {}` / `dataApi: { … }`. The\n * optional {@link EnableDataApiInput} carries the create-time auth wiring + initial\n * settings; omit it for an all-defaults, Neon-Auth integration.\n */\n enableProjectBranchDataApi(projectId: string, branchId: string, databaseName: string, input?: EnableDataApiInput): Promise<NeonDataApiSnapshot>;\n /**\n * Update the runtime {@link DataApiSettings} of an already-enabled Data API integration\n * (the Neon API `PATCH .../data-api/{db}`; always refreshes the schema cache). Only\n * `settings` are mutable post-create — the auth provider / JWKS wiring is fixed at\n * enable time. Used by `pushConfig` to reconcile settings drift under `updateExisting`.\n */\n updateProjectBranchDataApi(projectId: string, branchId: string, databaseName: string, settings: DataApiSettings): Promise<NeonDataApiSnapshot>;\n /** List branchable object-storage buckets visible on a branch. */\n listBranchBuckets(projectId: string, branchId: string): Promise<NeonBucketSnapshot[]>;\n /** Create a bucket on a branch. Used by `pushConfig` to honour `preview.buckets`. */\n createBranchBucket(projectId: string, branchId: string, input: CreateBucketInput): Promise<NeonBucketSnapshot>;\n /** Delete a bucket from a branch. */\n deleteBranchBucket(projectId: string, branchId: string, bucketName: string): Promise<void>;\n /**\n * Fetch the branch's S3-compatible object-storage connection details (endpoint, region,\n * path-style). Returns `null` when storage is not enabled for the branch (the API's 404\n * `BranchStorageNotEnabled`). Used by `fetchEnv` to populate the `AWS_*` storage env\n * alongside the minted credential's access keys.\n */\n getProjectBranchStorage(projectId: string, branchId: string): Promise<NeonBranchStorageSnapshot | null>;\n /** List functions on a branch. */\n listBranchFunctions(projectId: string, branchId: string): Promise<NeonFunctionSnapshot[]>;\n /** Delete a function (by slug) from a branch. */\n deleteBranchFunction(projectId: string, branchId: string, slug: string): Promise<void>;\n /**\n * Deploy a built bundle to a function, creating the function if it does not yet exist —\n * Neon has no separate create endpoint, so the first deployment to a slug creates the\n * function. The newest deployment becomes active. The `bundle` is built (esbuild + zip)\n * by the caller and passed in as bytes.\n */\n deployBranchFunction(projectId: string, branchId: string, slug: string, input: DeployFunctionInput): Promise<NeonFunctionDeploymentSnapshot>;\n /**\n * Mint a new scoped service credential on a branch (`POST .../credentials`). The\n * returned {@link NeonCredentialSecret} carries `apiToken` + `s3SecretAccessKey`\n * **once** — persist them immediately. Used by `fetchEnv` / `env pull` to issue the\n * unified credential for the branch's enabled Preview features (object storage, AI\n * Gateway, Functions).\n */\n createCredential(projectId: string, branchId: string, input: CreateCredentialInput): Promise<NeonCredentialSecret>;\n /**\n * List the secret-free metadata for credentials issued on a branch\n * (`GET .../credentials`). Used to report issued credentials (e.g. `config status`)\n * and to verify a persisted credential still exists / isn't revoked.\n */\n listCredentials(projectId: string, branchId: string): Promise<NeonCredentialMeta[]>;\n /**\n * Revoke (soft-delete) a credential by its `tokenId` (`DELETE .../credentials/{id}`).\n * Idempotent.\n */\n revokeCredential(projectId: string, branchId: string, tokenId: string): Promise<void>;\n}\n//#endregion\nexport { CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, DeployFunctionInput, EnableDataApiInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, UpdateBranchInput };\n//# sourceMappingURL=neon-api.d.ts.map"],"mappings":"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"}
|
|
@@ -86,7 +86,7 @@ interface ComputeSettings {
|
|
|
86
86
|
}
|
|
87
87
|
/**
|
|
88
88
|
* Read-only descriptor of the branch a {@link Config} policy is being evaluated for — the
|
|
89
|
-
* `branch` argument passed to your `defineConfig((branch) => …)`
|
|
89
|
+
* `branch` argument passed to your `defineConfig({ branch: (branch) => … })` closure. It describes
|
|
90
90
|
* **which** branch this invocation decides for; it is not a live branch handle and must not
|
|
91
91
|
* be mutated. Switch on its fields and return the desired {@link BranchConfig}.
|
|
92
92
|
*/
|
|
@@ -126,9 +126,114 @@ interface ServiceToggle {
|
|
|
126
126
|
* the type level — that's what makes `NeonEnv<typeof config>` exact.
|
|
127
127
|
*/
|
|
128
128
|
type ServiceToggleInput = boolean | ServiceToggle;
|
|
129
|
+
/**
|
|
130
|
+
* Resolve a **static** service toggle (`true` / `false` / `{ enabled?: boolean }` / object /
|
|
131
|
+
* `undefined`) to a type-level boolean. The tuple wrapping (`[T] extends […]`) disables
|
|
132
|
+
* distribution so a union/`undefined` is judged as a single unit:
|
|
133
|
+
*
|
|
134
|
+
* - `false` / `{ enabled: false }` / `undefined` → `false`
|
|
135
|
+
* - `true` / `{ enabled: true }` / any other object (`{}`, `{ enabled?: boolean }`) → `true`
|
|
136
|
+
* (a present toggle defaults to enabled)
|
|
137
|
+
* - the bare `boolean | … | undefined` (no literal info) → `false`
|
|
138
|
+
*
|
|
139
|
+
* Shared by the {@link Config} static cross-field checks and the `@neondatabase/env`
|
|
140
|
+
* `NeonEnv` namespace derivation, so both read "is this service on?" identically.
|
|
141
|
+
*/
|
|
142
|
+
|
|
129
143
|
interface PostgresConfig {
|
|
130
144
|
computeSettings?: ComputeSettings;
|
|
131
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Authentication providers a Data API integration can verify JWTs against, as written in
|
|
148
|
+
* `neon.ts`. Friendly authoring values (mapped to the Neon API's `neon_auth` / `external`
|
|
149
|
+
* at the API boundary):
|
|
150
|
+
*
|
|
151
|
+
* - `"neon"` — verify tokens minted by **Neon Auth** on the same branch. Neon supplies the
|
|
152
|
+
* JWKS URL / provider wiring for you, so the `jwksUrl` / `providerName` / `jwtAudience`
|
|
153
|
+
* fields are forbidden (a type error) on this variant — and the policy must also enable
|
|
154
|
+
* top-level `auth` (Neon Auth) so the tokens exist.
|
|
155
|
+
* - `"external"` — verify tokens from a third-party IdP (Clerk, Stytch, Auth0, …). You
|
|
156
|
+
* provide `jwksUrl` (and optionally `providerName` / `jwtAudience`).
|
|
157
|
+
*/
|
|
158
|
+
declare const DATA_API_AUTH_PROVIDERS: readonly ["neon", "external"];
|
|
159
|
+
type DataApiAuthProvider = (typeof DATA_API_AUTH_PROVIDERS)[number];
|
|
160
|
+
/**
|
|
161
|
+
* Reusable runtime settings for a Data API integration (the Neon API `DataAPISettings`,
|
|
162
|
+
* camelCased to match the rest of `neon.ts`). Every field is optional; omitted fields keep
|
|
163
|
+
* the Neon defaults shown below. These are the **only** Data API fields that can change on
|
|
164
|
+
* an already-enabled integration — drift here is reconciled as an *update* (requires
|
|
165
|
+
* `updateExisting` / `--update-existing`); the create-only auth wiring above cannot.
|
|
166
|
+
*/
|
|
167
|
+
interface DataApiSettings {
|
|
168
|
+
/** Enable the aggregates feature (`db_aggregates_enabled`). Default `true`. */
|
|
169
|
+
dbAggregatesEnabled?: boolean;
|
|
170
|
+
/** Database role used for anonymous requests (`db_anon_role`). Default `"anonymous"`. */
|
|
171
|
+
dbAnonRole?: string;
|
|
172
|
+
/** Extra schemas appended to the search path (`db_extra_search_path`). */
|
|
173
|
+
dbExtraSearchPath?: string;
|
|
174
|
+
/** Maximum rows returned in a single request (`db_max_rows`). */
|
|
175
|
+
dbMaxRows?: number;
|
|
176
|
+
/** Schemas exposed via the API (`db_schemas`). Default `["public"]`. */
|
|
177
|
+
dbSchemas?: string[];
|
|
178
|
+
/** JWT claim key used for role extraction (`jwt_role_claim_key`). Default `".role"`. */
|
|
179
|
+
jwtRoleClaimKey?: string;
|
|
180
|
+
/** Maximum lifetime of the JWT cache, in seconds (`jwt_cache_max_lifetime`). */
|
|
181
|
+
jwtCacheMaxLifetime?: number;
|
|
182
|
+
/** OpenAPI spec mode (`openapi_mode`). Default `"disabled"`. */
|
|
183
|
+
openapiMode?: "ignore-privileges" | "disabled";
|
|
184
|
+
/** CORS allowed origins (`server_cors_allowed_origins`). */
|
|
185
|
+
serverCorsAllowedOrigins?: string;
|
|
186
|
+
/** Emit server-timing headers (`server_timing_enabled`). */
|
|
187
|
+
serverTimingEnabled?: boolean;
|
|
188
|
+
}
|
|
189
|
+
/** Fields shared by every {@link DataApiConfig} variant. */
|
|
190
|
+
interface DataApiConfigBase {
|
|
191
|
+
/** Defaults to `true` when the `dataApi` namespace is present. Set `false` to opt out. */
|
|
192
|
+
enabled?: boolean;
|
|
193
|
+
/** Reusable runtime settings. Drift here is reconciled as an update. */
|
|
194
|
+
settings?: DataApiSettings;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Data API verified by **Neon Auth** (`authProvider: "neon"`, the default). The external
|
|
198
|
+
* IdP fields are statically forbidden (`?: never`) because Neon supplies them; declaring any
|
|
199
|
+
* of them is a type error directing you to `authProvider: "external"`.
|
|
200
|
+
*/
|
|
201
|
+
interface DataApiNeonAuthConfig extends DataApiConfigBase {
|
|
202
|
+
authProvider?: "neon";
|
|
203
|
+
/** Forbidden with `authProvider: "neon"` — Neon provides the JWKS URL. */
|
|
204
|
+
jwksUrl?: never;
|
|
205
|
+
/** Forbidden with `authProvider: "neon"` — the provider is Neon Auth. */
|
|
206
|
+
providerName?: never;
|
|
207
|
+
/** Forbidden with `authProvider: "neon"` — Neon manages the audience. */
|
|
208
|
+
jwtAudience?: never;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Data API verified by an **external** IdP (`authProvider: "external"`). You provide the
|
|
212
|
+
* JWKS URL (and optionally a provider label / expected audience).
|
|
213
|
+
*/
|
|
214
|
+
interface DataApiExternalAuthConfig extends DataApiConfigBase {
|
|
215
|
+
authProvider: "external";
|
|
216
|
+
/** URL that publishes the IdP's JWKS (JSON Web Key Set). */
|
|
217
|
+
jwksUrl?: string;
|
|
218
|
+
/** Human label for the IdP (e.g. "Clerk", "Stytch", "Auth0"). */
|
|
219
|
+
providerName?: string;
|
|
220
|
+
/**
|
|
221
|
+
* Expected `aud` claim. ⚠️ This only **rejects** tokens carrying a *different* audience;
|
|
222
|
+
* tokens with no `aud` claim are still accepted.
|
|
223
|
+
*/
|
|
224
|
+
jwtAudience?: string;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Object form of the `dataApi` toggle. A discriminated union on {@link DataApiAuthProvider}:
|
|
228
|
+
* the `"neon"` variant forbids the external-IdP fields, the `"external"` variant allows them.
|
|
229
|
+
*/
|
|
230
|
+
type DataApiConfig = DataApiNeonAuthConfig | DataApiExternalAuthConfig;
|
|
231
|
+
/**
|
|
232
|
+
* How the Data API is toggled in a policy: a bare boolean (like the other service toggles)
|
|
233
|
+
* or the richer {@link DataApiConfig} object. `true` / `{}` / `{ enabled: true }` enable it
|
|
234
|
+
* with Neon defaults; `false` / `{ enabled: false }` opt out.
|
|
235
|
+
*/
|
|
236
|
+
type DataApiInput = boolean | DataApiConfig;
|
|
132
237
|
/**
|
|
133
238
|
* Supported function runtimes. Mirrors the Neon Functions deploy API `runtime` enum.
|
|
134
239
|
* Only `nodejs24` exists today; kept as a union so adding runtimes later is a
|
|
@@ -316,10 +421,15 @@ type BranchTuningFn<Preview extends PreviewInput | undefined = PreviewInput | un
|
|
|
316
421
|
* literals; the defaults make the bare `Config` a usable "any policy" type for runtime
|
|
317
422
|
* function signatures.
|
|
318
423
|
*/
|
|
319
|
-
interface Config<Auth extends ServiceToggleInput | undefined = ServiceToggleInput | undefined, DataApi extends
|
|
424
|
+
interface Config<Auth extends ServiceToggleInput | undefined = ServiceToggleInput | undefined, DataApi extends DataApiInput | undefined = DataApiInput | undefined, Preview extends PreviewInput | undefined = PreviewInput | undefined> {
|
|
320
425
|
/** Neon Auth integration toggle (GA). Static — drives `NeonEnv.auth`. */
|
|
321
426
|
auth?: Auth;
|
|
322
|
-
/**
|
|
427
|
+
/**
|
|
428
|
+
* Neon Data API integration (GA). Static — drives `NeonEnv.dataApi`. A boolean/toggle, or
|
|
429
|
+
* a {@link DataApiConfig} object selecting the auth provider (`"neon"` / `"external"`) and
|
|
430
|
+
* runtime {@link DataApiSettings}. With `authProvider: "neon"` the policy must also enable
|
|
431
|
+
* top-level `auth`.
|
|
432
|
+
*/
|
|
323
433
|
dataApi?: DataApi;
|
|
324
434
|
/** Beta (Preview) feature set: AI Gateway, functions, buckets. Static. */
|
|
325
435
|
preview?: Preview;
|
|
@@ -331,5 +441,5 @@ interface Config<Auth extends ServiceToggleInput | undefined = ServiceToggleInpu
|
|
|
331
441
|
* downstream diff/apply never has to re-derive it.
|
|
332
442
|
*/
|
|
333
443
|
//#endregion
|
|
334
|
-
export { BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, CredentialPrincipalType, CredentialScope, DurationString, DurationUnit, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, ServiceToggle, ServiceToggleInput };
|
|
444
|
+
export { BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DurationString, DurationUnit, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, ServiceToggle, ServiceToggleInput };
|
|
335
445
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":["ComputeUnit","DurationUnit","DurationString","SuspendTimeoutSuggestion","TtlSuggestion","DurationField","Suggestions","NonNullable","ComputeSettings","BranchTarget","ServiceToggle","ServiceToggleInput","PostgresConfig","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","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) => …)` callback. 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;\ninterface PostgresConfig {\n computeSettings?: ComputeSettings;\n}\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 ServiceToggleInput | undefined = ServiceToggleInput | undefined, Preview extends PreviewInput | undefined = PreviewInput | undefined> {\n /** Neon Auth integration toggle (GA). Static — drives `NeonEnv.auth`. */\n auth?: Auth;\n /** Neon Data API integration toggle (GA). Static — drives `NeonEnv.dataApi`. */\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}\ninterface ResolvedBranchConfig {\n parent?: string;\n ttlSeconds?: number;\n protected?: boolean;\n postgres?: PostgresConfig;\n authEnabled: boolean;\n dataApiEnabled: boolean;\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, DurationString, DurationUnit, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceToggle, ServiceToggleInput };\n//# sourceMappingURL=types.d.ts.map"],"mappings":";;;AAKgB;AAEC;AAc6B;AAOjB,KAvBxBA,WAAAA,GA8BAI,IAAa,GAAA,GAAA,GAAA,CAAA,GAAA,CAAA,GAAA,CAAA,GAAA,CAAA;AAAA;KA5BbH,YAAAA,GAmCa,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA;;;;;AAAkF;AAAA;;;;;;AAyC5D;AAAA;AAQlB,KAtEjBC,cAAAA,GA0FkB,GAAA,MAAA,GA1FWD,YA0FX,EAAA;AAAA;AAe0B;AAEd;AAOf;AAKO;;KAhHtBE,wBAAAA,GA8JGa,IAAAA,GAAAA,IAAAA,GAAAA,KAAAA,GAAAA,KAAAA,GAAAA,IAAAA,GAAAA,IAAAA,GAAAA,KAAAA,GAAAA,IAAAA,GAAAA,IAAAA;;AAKiB;AAAA;AAcL;AAMQ;AAEN;AAWM,KA7LvBZ,aAAAA,GAqMiB,IAAA,GAAA,IAAA,GAAA,KAAA,GAAA,IAAA,GAAA,IAAA,GAAA,IAAA,GAAA,KAAA,GAAA,KAAA;;;;;;;AAMJ,KApMbC,aAoMa,CAAA,oBApMqBH,cAoMrB,CAAA,GApMuCI,WAoMvC,GAAA,CApMsDJ,cAoMtD,GApMuEK,WAoMvE,CAAA,OAAA,CAAA,CAAA,GAAA,MAAA;AAAA;AAUS;;;;;;AAQN,UA9MXC,eAAAA,CA8MW;EAAA;;;;;uBAqCKgB,CAAAA,EA7OAxB,WA6OAwB;;AAAD;AAAA;;;uBAGwCI,CAAAA,EA1OvC5B,WA0OuC4B;;;AAEtD;AAAA;;;;;;;;AAKsH;AAAA;;;;;;;;gBAgBxHK,CAAAA,EAAAA,KAAAA,GA5OkB5B,aA4OlB4B,CA5OgC9B,wBA4OhC8B,CAAAA;;;;;AAMgB;;;UA1OfxB,YAAAA;;;;;;;;;;;;;;;;;;;;UAoBAC,aAAAA;;;;;;;;;;;;;;;KAeLC,kBAAAA,aAA+BD;UAC1BE,cAAAA;oBACUJ;;;;;;;KAOfK,eAAAA;;;;;UAKKC,iBAAAA;;;;;;;;;;;;;;;;;;;;;;UAsBAC,WAAAA;;;;;;;;;;;;;;;;;;;;;;;;QAwBFC;;;;;QAKAF;;;;;;;;;;;;;;KAcHG,eAAAA;;;;;;KAMAC,uBAAAA;;KAEAC,iBAAAA;;;;;;UAMKC,SAAAA;;;;;WAKCD;;;;;;;;UAQDE,YAAAA;;cAEIV;;cAEAK,eAAeD;;YAEjBC,eAAeI;;;;;;;;UAQjBE,cAAAA;;YAEET;;;;;;;UAOFU;cACIE,QAAQT,OAAOQ,MAAMF;;;;;;;;UAQzBI;;;;;;;;;;;;;;;;;;;;;;;;;QAyBFrB,cAAcD;;;aAGTQ;YACDW,cAAcC;;;KAGrBG,gCAAgCN,4BAA4BO;;IAE7DE,cAAcD;;;;;KAKbE,+BAA+BV,2BAA2BA,qCAAqCZ,iBAAiBiB,aAAaC,gBAAgBC;;;;;;;;;;;;;;UAcxII,oBAAoBrB,iCAAiCA,gDAAgDA,iCAAiCA,gDAAgDU,2BAA2BA;;SAElNY;;YAEGC;;YAEAN;;WAEDG,eAAeH"}
|
|
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 `@neondatabase/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":";;;AAKgB;AAEC;AAc6B;AAOjB,KAvBxBA,WAAAA,GA8BAI,IAAa,GAAA,GAAA,GAAA,CAAA,GAAA,CAAA,GAAA,CAAA,GAAA,CAAA;AAAA;KA5BbH,YAAAA,GAmCa,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA;;;;;AAAkF;AAAA;;;;;;AAyC5D;AAAA;AAQlB,KAtEjBC,cAAAA,GA0FkB,GAAA,MAAA,GA1FWD,YA0FX,EAAA;AAAA;AAiCT;AAEqB;AAciC;AACV;AAQjC;AA2BG,KAxKvBE,wBAAAA,GA+K0B,IAAA,GAASe,IAAAA,GAAAA,KAAAA,GAAAA,KAAiB,GAAA,IAAA,GAAA,IAAA,GAAA,KAAA,GAAA,IAAA,GAAA,IAAA;AAAA;AAaI;;;;AAgBS;AAAA,KArMjEd,aAAAA,GA2MY,IAAA,GAAA,IAAaiB,GAAAA,KAAAA,GAAa,IAAA,GAAA,IAAA,GAAA,IAAA,GAAA,KAAA,GAAA,KAAA;AAAA;AAMvB;AAKO;;;;AAmDF,KAlQpBhB,aAkQoB,CAAA,oBAlQcH,cAkQd,CAAA,GAlQgCI,WAkQhC,GAAA,CAlQ+CJ,cAkQ/C,GAlQgEK,WAkQhE,CAAA,OAAA,CAAA,CAAA,GAAA,MAAA;AAAA;AAcL;AAMQ;AAEN;AAWM;;;UA3RlBC,eAAAA,CAuSmBiB;;;;AAEX;AAAA;EAUS,qBAOJ,CAAA,EApTGzB,WAoTH;EAAA;;;;;EACF,qBAAA,CAAA,EA/SKA,WA+SL;EAAA;;;;;;;AAqCI;AAAA;;;;;;AAKd;AAAA;;;;;gBAKuIsC,CAAAA,EAAAA,KAAAA,GAzUvHjC,aAyUuHiC,CAzUzGnC,wBAyUyGmC,CAAAA;;;AAAjB;AAAA;;;;UAjUvH7B,YAAAA,CA+UqGa;;QAAqES,MAAAA;;OAE3KY,MAAAA;;QASGL,EAAAA,OAAAA;;UAEDG,CAAAA,EAAAA,MAAAA;EAAc;;;;;;;;;;;UAxUf/B,aAAAA;;;;;;;;;;;;;;;KAeLC,kBAAAA,aAA+BD;;;;;;;;;;;;;;;UAmB1BI,cAAAA;oBACUN;;;;;;;;;;;;;;cAcNO;KACTC,mBAAAA,WAA8BD;;;;;;;;UAQzBE,eAAAA;;;;;;;;;;;;;;;;;;;;;;;UAuBAC,iBAAAA;;;;aAIGD;;;;;;;UAOHE,qBAAAA,SAA8BD;;;;;;;;;;;;;UAa9BE,yBAAAA,SAAkCF;;;;;;;;;;;;;;;;KAgBvCG,aAAAA,GAAgBF,wBAAwBC;;;;;;KAMxCE,YAAAA,aAAyBD;;;;;;KAMzBE,eAAAA;;;;;UAKKC,iBAAAA;;;;;;;;;;;;;;;;;;;;;;UAsBAC,WAAAA;;;;;;;;;;;;;;;;;;;;;;;;QAwBFC;;;;;QAKAF;;;;;;;;;;;;;;KAcHG,eAAAA;;;;;;KAMAC,uBAAAA;;KAEAC,iBAAAA;;;;;;UAMKC,SAAAA;;;;;WAKCD;;;;;;;;UAQDE,YAAAA;;cAEIpB;;cAEAe,eAAeD;;YAEjBC,eAAeI;;;;;;;;UAQjBE,cAAAA;;YAEET;;;;;;;UAOFU;cACIE,QAAQT,OAAOQ,MAAMF;;;;;;;;UAQzBI;;;;;;;;;;;;;;;;;;;;;;;;;QAyBF/B,cAAcD;;;aAGTU;YACDmB,cAAcC;;;KAGrBG,gCAAgCN,4BAA4BO;;IAE7DE,cAAcD;;;;;KAKbE,+BAA+BV,2BAA2BA,qCAAqCtB,iBAAiB2B,aAAaC,gBAAgBC;;;;;;;;;;;;;;UAcxII,oBAAoB/B,iCAAiCA,gDAAgDW,2BAA2BA,0CAA0CS,2BAA2BA;;SAEtMY;;;;;;;YAOGC;;YAEAN;;WAEDG,eAAeH"}
|
package/dist/config/dist/v1.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, CredentialPrincipalType, CredentialScope, DurationString, DurationUnit, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, ServiceToggle, ServiceToggleInput } from "./lib/types.js";
|
|
2
|
-
import { CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, DeployFunctionInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, UpdateBranchInput } from "./lib/neon-api.js";
|
|
1
|
+
import { BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DurationString, DurationUnit, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, ServiceToggle, ServiceToggleInput } from "./lib/types.js";
|
|
2
|
+
import { CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, DeployFunctionInput, EnableDataApiInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, UpdateBranchInput } from "./lib/neon-api.js";
|
|
3
3
|
import "zod";
|
|
4
4
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { FetchEnvOptions, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAiGatewayEnv, NeonAuthEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, NeonStorageEnv, fetchEnv, parseEnv, toEntries } from "./lib/env.js";
|
|
2
|
-
export { FetchEnvOptions, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAiGatewayEnv, NeonAuthEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, NeonStorageEnv, fetchEnv, parseEnv, toEntries };
|
|
1
|
+
import { FetchEnvOptions, FilteredNeonEnv, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAiGatewayEnv, NeonAuthEnv, NeonBranchEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, NeonStorageEnv, SelectableEnvKey, fetchEnv, parseEnv, toEntries } from "./lib/env.js";
|
|
2
|
+
export { FetchEnvOptions, FilteredNeonEnv, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAiGatewayEnv, NeonAuthEnv, NeonBranchEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, NeonStorageEnv, SelectableEnvKey, fetchEnv, parseEnv, toEntries };
|
package/dist/lib/env.d.ts
CHANGED
|
@@ -4,6 +4,14 @@ import "../config/dist/v1.js";
|
|
|
4
4
|
|
|
5
5
|
//#region src/lib/env.d.ts
|
|
6
6
|
declare const NEON_ENV_VAR_KEYS: {
|
|
7
|
+
/**
|
|
8
|
+
* Branch identity. `NEON_BRANCH` carries the branch **name** and is injected into the
|
|
9
|
+
* Neon Functions runtime on every branch (including the default) by default. `env pull` /
|
|
10
|
+
* `neon dev` / `neon-env run` emit it too so local dev mirrors the deployed runtime.
|
|
11
|
+
*/
|
|
12
|
+
readonly branch: {
|
|
13
|
+
readonly name: "NEON_BRANCH";
|
|
14
|
+
};
|
|
7
15
|
readonly postgres: {
|
|
8
16
|
readonly databaseUrl: "DATABASE_URL";
|
|
9
17
|
readonly databaseUrlUnpooled: "DATABASE_URL_UNPOOLED";
|
|
@@ -45,6 +53,15 @@ declare const NEON_ENV_VAR_KEYS: {
|
|
|
45
53
|
readonly neonBaseUrl: "NEON_AI_GATEWAY_BASE_URL";
|
|
46
54
|
};
|
|
47
55
|
};
|
|
56
|
+
/**
|
|
57
|
+
* Branch identity for the resolved branch. Always present on a `fetchEnv` result (the branch
|
|
58
|
+
* name is always known); on a `parseEnv` result it's present only when `NEON_BRANCH` was
|
|
59
|
+
* injected into `process.env` (the Functions runtime injects it by default, as do `neon dev` /
|
|
60
|
+
* `neon-env run` / `env pull`). `name` is the branch **name** (e.g. `main`, `preview/foo`).
|
|
61
|
+
*/
|
|
62
|
+
interface NeonBranchEnv {
|
|
63
|
+
name: string;
|
|
64
|
+
}
|
|
48
65
|
/** Per-namespace inner shapes. Exposed so consumers can name the parts independently. */
|
|
49
66
|
interface NeonPostgresEnv {
|
|
50
67
|
/**
|
|
@@ -80,7 +97,8 @@ interface NeonDataApiEnv {
|
|
|
80
97
|
/**
|
|
81
98
|
* S3-compatible object-storage access for the branch (Preview). Present on `NeonEnv` only
|
|
82
99
|
* when the policy declares `preview.buckets`. Combines a minted branch credential's access
|
|
83
|
-
* keys (`accessKeyId` = the credential's
|
|
100
|
+
* keys (`accessKeyId` = the credential's full token id, e.g. `nak_live_…`, which is what the
|
|
101
|
+
* storage gateway authenticates against; `secretAccessKey` = its
|
|
84
102
|
* `s3_secret_access_key`) with the branch's non-secret connection details
|
|
85
103
|
* (`endpoint`/`region`/`forcePathStyle`, from `GET .../storage`). Projects to the AWS SDK's
|
|
86
104
|
* standard config env (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_ENDPOINT_URL_S3`,
|
|
@@ -171,6 +189,11 @@ type AiGatewayOn<C extends Config> = [NonNullable<C["preview"]>] extends [never]
|
|
|
171
189
|
*/
|
|
172
190
|
type NeonEnv<C extends Config = Config> = {
|
|
173
191
|
postgres: NeonPostgresEnv;
|
|
192
|
+
/**
|
|
193
|
+
* Branch identity (`NEON_BRANCH`). Optional because `parseEnv` only surfaces it when the
|
|
194
|
+
* var was injected; `fetchEnv` always populates it.
|
|
195
|
+
*/
|
|
196
|
+
branch?: NeonBranchEnv;
|
|
174
197
|
} & (ServiceOn<NonNullable<C["auth"]>> extends true ? {
|
|
175
198
|
auth: NeonAuthEnv;
|
|
176
199
|
} : NoNamespace) & (ServiceOn<NonNullable<C["dataApi"]>> extends true ? {
|
|
@@ -197,6 +220,65 @@ type FunctionEnvKeysOf<C extends Config, S extends string> = S extends keyof Pre
|
|
|
197
220
|
type NeonFunctionEnv<C extends Config, S extends string> = {
|
|
198
221
|
function: Record<FunctionEnvKeysOf<C, S>, string>;
|
|
199
222
|
};
|
|
223
|
+
/**
|
|
224
|
+
* OS-level env-var keys grouped by the {@link NeonEnv} namespace they populate. Only the
|
|
225
|
+
* **input** vars `parseEnv` validates are listed — the output-only aliases in
|
|
226
|
+
* {@link NEON_ENV_VAR_KEYS} (`NEON_STORAGE_REGION`, `NEON_AI_GATEWAY_TOKEN`, …) and the
|
|
227
|
+
* always-derived `storage.forcePathStyle` are intentionally absent, so they are not
|
|
228
|
+
* selectable in a `parseEnv(config, keys)` filter. Keep in sync with {@link EnvKeyToProp}.
|
|
229
|
+
*/
|
|
230
|
+
interface EnvKeysByNamespace {
|
|
231
|
+
postgres: "DATABASE_URL" | "DATABASE_URL_UNPOOLED";
|
|
232
|
+
auth: "NEON_AUTH_BASE_URL" | "NEON_AUTH_JWKS_URL";
|
|
233
|
+
dataApi: "NEON_DATA_API_URL";
|
|
234
|
+
storage: "AWS_ACCESS_KEY_ID" | "AWS_SECRET_ACCESS_KEY" | "AWS_ENDPOINT_URL_S3" | "AWS_REGION";
|
|
235
|
+
aiGateway: "OPENAI_API_KEY" | "OPENAI_BASE_URL";
|
|
236
|
+
}
|
|
237
|
+
/** The {@link NeonEnv} namespace interface backing each namespace key. */
|
|
238
|
+
interface NamespaceEnv {
|
|
239
|
+
postgres: NeonPostgresEnv;
|
|
240
|
+
auth: NeonAuthEnv;
|
|
241
|
+
dataApi: NeonDataApiEnv;
|
|
242
|
+
storage: NeonStorageEnv;
|
|
243
|
+
aiGateway: NeonAiGatewayEnv;
|
|
244
|
+
}
|
|
245
|
+
/** OS-level env-var key → the camelCase property it sets on its namespace object. */
|
|
246
|
+
interface EnvKeyToProp {
|
|
247
|
+
DATABASE_URL: "databaseUrl";
|
|
248
|
+
DATABASE_URL_UNPOOLED: "databaseUrlUnpooled";
|
|
249
|
+
NEON_AUTH_BASE_URL: "baseUrl";
|
|
250
|
+
NEON_AUTH_JWKS_URL: "jwksUrl";
|
|
251
|
+
NEON_DATA_API_URL: "url";
|
|
252
|
+
AWS_ACCESS_KEY_ID: "accessKeyId";
|
|
253
|
+
AWS_SECRET_ACCESS_KEY: "secretAccessKey";
|
|
254
|
+
AWS_ENDPOINT_URL_S3: "endpoint";
|
|
255
|
+
AWS_REGION: "region";
|
|
256
|
+
OPENAI_API_KEY: "apiKey";
|
|
257
|
+
OPENAI_BASE_URL: "baseUrl";
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* The OS-level env-var keys selectable for a given policy: the union of input vars across
|
|
261
|
+
* exactly the namespaces {@link NeonEnv}<C> carries. Drives the typesafe autocomplete of the
|
|
262
|
+
* `keys` filter — selecting a var from a namespace the policy does not enable is a type error
|
|
263
|
+
* (e.g. `NEON_AUTH_BASE_URL` is only offered once the policy turns on `auth`).
|
|
264
|
+
*/
|
|
265
|
+
type SelectableEnvKey<C extends Config> = EnvKeysByNamespace[keyof NeonEnv<C> & keyof EnvKeysByNamespace];
|
|
266
|
+
/**
|
|
267
|
+
* The result shape of a **filtered** `parseEnv(config, keys)` call: the namespaced
|
|
268
|
+
* {@link NeonEnv} restricted to exactly the selected OS-level keys `K`. Namespaces with no
|
|
269
|
+
* selected key are dropped, and within a kept namespace only the selected properties survive
|
|
270
|
+
* — selecting just `["DATABASE_URL"]` yields `{ postgres: { databaseUrl: string } }`, with no
|
|
271
|
+
* `databaseUrlUnpooled`.
|
|
272
|
+
*
|
|
273
|
+
* The policy gating lives on the `parseEnv` overload (which binds `K` to
|
|
274
|
+
* {@link SelectableEnvKey}); this type only needs the selection, so it takes a bare
|
|
275
|
+
* `K extends string` and filters with `Extract`. The outer mapped type's `as` clause drops
|
|
276
|
+
* any namespace whose intersection with the selection is empty (`[…] extends [never]`,
|
|
277
|
+
* tuple-wrapped to switch off distribution); the inner one re-keys each selected OS var to its
|
|
278
|
+
* camelCase property and looks the value type up on the canonical namespace interface, so it
|
|
279
|
+
* stays correct if a field ever stops being a plain `string`.
|
|
280
|
+
*/
|
|
281
|
+
type FilteredNeonEnv<K extends string> = { [N in keyof EnvKeysByNamespace as [Extract<K, EnvKeysByNamespace[N]>] extends [never] ? never : N]: { [P in Extract<K, EnvKeysByNamespace[N]> as EnvKeyToProp[P & keyof EnvKeyToProp]]: NamespaceEnv[N][EnvKeyToProp[P & keyof EnvKeyToProp] & keyof NamespaceEnv[N]] } };
|
|
200
282
|
interface FetchEnvOptions {
|
|
201
283
|
/**
|
|
202
284
|
* Neon project id. **Required** — the management API addresses branches through their
|
|
@@ -280,12 +362,18 @@ declare function fetchEnv<const C extends Config>(config: C, options: FetchEnvOp
|
|
|
280
362
|
* static (top-level `config.auth` / `config.dataApi`), so it reads those directly without
|
|
281
363
|
* evaluating the per-branch closure.
|
|
282
364
|
*
|
|
283
|
-
* The second argument is a **scope**:
|
|
284
|
-
* - omitted — *external* scope (app bootstrap, build scripts, your dev machine). Returns
|
|
285
|
-
* `{ postgres, auth?, dataApi
|
|
365
|
+
* The second argument is a **scope** or a **key filter**:
|
|
366
|
+
* - omitted — *external* scope (app bootstrap, build scripts, your dev machine). Returns the
|
|
367
|
+
* full `{ postgres, auth?, dataApi?, … }` the policy enables.
|
|
286
368
|
* - a **function slug** (a key of `config.preview.functions`) — *function* scope: you are
|
|
287
369
|
* running inside that function. Returns the same branch secrets **plus** a typed
|
|
288
370
|
* `function` namespace with the function's declared env-var keys.
|
|
371
|
+
* - an **array of OS-level env-var keys** (e.g. `["DATABASE_URL", "NEON_AUTH_BASE_URL"]`) —
|
|
372
|
+
* *filtered* mode: only those vars are required and returned, as a narrowed namespaced
|
|
373
|
+
* shape. The keys autocomplete from the policy ({@link SelectableEnvKey}), so you can only
|
|
374
|
+
* pick vars the policy actually enables. Use this when a process needs just a subset (a
|
|
375
|
+
* Next.js app that reads `DATABASE_URL` but not `DATABASE_URL_UNPOOLED`, say) and you don't
|
|
376
|
+
* want `parseEnv` to throw over vars you never use.
|
|
289
377
|
*
|
|
290
378
|
* Throws `PlatformError(EnvNotInjected)` listing every missing/invalid var when the env
|
|
291
379
|
* isn't fully populated, with a fix hint pointing back at `neon dev` / `neon-env run`.
|
|
@@ -301,9 +389,14 @@ declare function fetchEnv<const C extends Config>(config: C, options: FetchEnvOp
|
|
|
301
389
|
* // Inside the "hello" function:
|
|
302
390
|
* const env = parseEnv(config, "hello");
|
|
303
391
|
* env.function.resendApiKey; // typed from hello's declared env keys
|
|
392
|
+
*
|
|
393
|
+
* // Filtered: only enforce + return the pooled URL.
|
|
394
|
+
* const { postgres } = parseEnv(config, ["DATABASE_URL"]);
|
|
395
|
+
* postgres.databaseUrl; // string — `databaseUrlUnpooled` is absent
|
|
304
396
|
* ```
|
|
305
397
|
*/
|
|
306
398
|
declare function parseEnv<const C extends Config>(config: C): NeonEnv<C>;
|
|
399
|
+
declare function parseEnv<const C extends Config, const K extends SelectableEnvKey<C>>(config: C, keys: readonly K[]): FilteredNeonEnv<K>;
|
|
307
400
|
declare function parseEnv<const C extends Config, const S extends FunctionSlugOf<C>>(config: C, scope: S): NeonEnv<C> & NeonFunctionEnv<C, S>;
|
|
308
401
|
/**
|
|
309
402
|
* Project a fully-resolved {@link NeonEnv} into the OS-level `{ KEY: value }` pairs used
|
|
@@ -318,5 +411,5 @@ declare function parseEnv<const C extends Config, const S extends FunctionSlugOf
|
|
|
318
411
|
*/
|
|
319
412
|
declare function toEntries(env: NeonEnv<Config>): Record<string, string>;
|
|
320
413
|
//#endregion
|
|
321
|
-
export { FetchEnvOptions, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAiGatewayEnv, NeonAuthEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, NeonStorageEnv, fetchEnv, parseEnv, toEntries };
|
|
414
|
+
export { FetchEnvOptions, FilteredNeonEnv, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAiGatewayEnv, NeonAuthEnv, NeonBranchEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, NeonStorageEnv, SelectableEnvKey, fetchEnv, parseEnv, toEntries };
|
|
322
415
|
//# 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":";;;;;cA8Ca;;;;EAAA,CAAA;
|
|
1
|
+
{"version":3,"file":"env.d.ts","names":[],"sources":["../../src/lib/env.ts"],"mappings":"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"}
|
package/dist/lib/env.js
CHANGED
|
@@ -29,6 +29,12 @@ const NEON_MANAGED_AUTH_ROLES = new Set([
|
|
|
29
29
|
"authenticated"
|
|
30
30
|
]);
|
|
31
31
|
const NEON_ENV_VAR_KEYS = {
|
|
32
|
+
/**
|
|
33
|
+
* Branch identity. `NEON_BRANCH` carries the branch **name** and is injected into the
|
|
34
|
+
* Neon Functions runtime on every branch (including the default) by default. `env pull` /
|
|
35
|
+
* `neon dev` / `neon-env run` emit it too so local dev mirrors the deployed runtime.
|
|
36
|
+
*/
|
|
37
|
+
branch: { name: "NEON_BRANCH" },
|
|
32
38
|
postgres: {
|
|
33
39
|
databaseUrl: "DATABASE_URL",
|
|
34
40
|
databaseUrlUnpooled: "DATABASE_URL_UNPOOLED"
|
|
@@ -129,10 +135,13 @@ async function fetchEnv(config, options) {
|
|
|
129
135
|
wantsAuth ? api.getNeonAuth(projectId, branch.id) : Promise.resolve(null),
|
|
130
136
|
wantsDataApi ? api.getNeonDataApi(projectId, branch.id, databaseName) : Promise.resolve(null)
|
|
131
137
|
]);
|
|
132
|
-
const result = {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
138
|
+
const result = {
|
|
139
|
+
postgres: {
|
|
140
|
+
databaseUrl: pooled.uri,
|
|
141
|
+
databaseUrlUnpooled: unpooled.uri
|
|
142
|
+
},
|
|
143
|
+
branch: { name: branch.name }
|
|
144
|
+
};
|
|
136
145
|
if (wantsAuth) {
|
|
137
146
|
if (!authSnapshot) throw new PlatformError(ErrorCode.NotFound, [`fetchEnv: branch policy enables auth but no Neon Auth integration is enabled on branch ${branch.name} (${branch.id}).`, "Enable it via `apply(config, { projectId, branchId })` (or `npx neonctl …`), in the Neon Console — then re-run fetchEnv. Or return auth.enabled=false."].join(" "), { details: {
|
|
138
147
|
projectId,
|
|
@@ -229,7 +238,7 @@ async function resolveCredentialSecrets(args) {
|
|
|
229
238
|
name: `neon-env ${args.branchName}`
|
|
230
239
|
});
|
|
231
240
|
return {
|
|
232
|
-
accessKeyId: minted.
|
|
241
|
+
accessKeyId: minted.tokenId,
|
|
233
242
|
secretAccessKey: minted.s3SecretAccessKey,
|
|
234
243
|
apiToken: minted.apiToken
|
|
235
244
|
};
|
|
@@ -371,8 +380,10 @@ function isServiceEnabledInput(toggle) {
|
|
|
371
380
|
if (typeof toggle === "boolean") return toggle;
|
|
372
381
|
return toggle.enabled !== false;
|
|
373
382
|
}
|
|
374
|
-
function parseEnv(config,
|
|
383
|
+
function parseEnv(config, scopeOrKeys) {
|
|
375
384
|
const source = process.env;
|
|
385
|
+
if (Array.isArray(scopeOrKeys)) return parseFilteredEnv(source, scopeOrKeys);
|
|
386
|
+
const scope = typeof scopeOrKeys === "string" ? scopeOrKeys : void 0;
|
|
376
387
|
const issues = [];
|
|
377
388
|
const result = {};
|
|
378
389
|
const pg = postgresEnvSchema.safeParse({
|
|
@@ -384,6 +395,8 @@ function parseEnv(config, scope) {
|
|
|
384
395
|
databaseUrlUnpooled: pg.data.DATABASE_URL_UNPOOLED
|
|
385
396
|
};
|
|
386
397
|
else for (const issue of pg.error.issues) issues.push(issue.message);
|
|
398
|
+
const branchName = source[NEON_ENV_VAR_KEYS.branch.name];
|
|
399
|
+
if (branchName !== void 0 && branchName !== "") result.branch = { name: branchName };
|
|
387
400
|
if (isServiceEnabledInput(config.auth)) {
|
|
388
401
|
const auth = authEnvSchema.safeParse({
|
|
389
402
|
NEON_AUTH_BASE_URL: source.NEON_AUTH_BASE_URL,
|
|
@@ -450,6 +463,64 @@ function parseEnv(config, scope) {
|
|
|
450
463
|
return result;
|
|
451
464
|
}
|
|
452
465
|
/**
|
|
466
|
+
* Runtime reverse map for filtered `parseEnv`: OS-level env-var key → `[namespace, property]`
|
|
467
|
+
* in the {@link NeonEnv} shape. The compile-time mirror is {@link EnvKeysByNamespace} /
|
|
468
|
+
* {@link EnvKeyToProp}; keep all three in sync. Only input vars appear (no output-only
|
|
469
|
+
* aliases, no derived `forcePathStyle`).
|
|
470
|
+
*/
|
|
471
|
+
const FILTERABLE_ENV_KEYS = {
|
|
472
|
+
DATABASE_URL: ["postgres", "databaseUrl"],
|
|
473
|
+
DATABASE_URL_UNPOOLED: ["postgres", "databaseUrlUnpooled"],
|
|
474
|
+
NEON_AUTH_BASE_URL: ["auth", "baseUrl"],
|
|
475
|
+
NEON_AUTH_JWKS_URL: ["auth", "jwksUrl"],
|
|
476
|
+
NEON_DATA_API_URL: ["dataApi", "url"],
|
|
477
|
+
AWS_ACCESS_KEY_ID: ["storage", "accessKeyId"],
|
|
478
|
+
AWS_SECRET_ACCESS_KEY: ["storage", "secretAccessKey"],
|
|
479
|
+
AWS_ENDPOINT_URL_S3: ["storage", "endpoint"],
|
|
480
|
+
AWS_REGION: ["storage", "region"],
|
|
481
|
+
OPENAI_API_KEY: ["aiGateway", "apiKey"],
|
|
482
|
+
OPENAI_BASE_URL: ["aiGateway", "baseUrl"]
|
|
483
|
+
};
|
|
484
|
+
/**
|
|
485
|
+
* Filtered counterpart to the {@link parseEnv} body: validate and return only the explicitly
|
|
486
|
+
* selected OS-level env-var keys, projected back into the narrowed namespaced shape. Unlike
|
|
487
|
+
* the full reader it never consults the policy — the selection alone decides what's required —
|
|
488
|
+
* so vars the caller didn't ask for (e.g. `DATABASE_URL_UNPOOLED`) can be absent without
|
|
489
|
+
* throwing. Mirrors the same non-empty constraint and {@link PlatformError} aggregation.
|
|
490
|
+
*/
|
|
491
|
+
function parseFilteredEnv(source, keys) {
|
|
492
|
+
const issues = [];
|
|
493
|
+
const result = {};
|
|
494
|
+
for (const key of keys) {
|
|
495
|
+
if (!Object.hasOwn(FILTERABLE_ENV_KEYS, key)) {
|
|
496
|
+
issues.push(`${key} is not a selectable Neon env variable`);
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
const value = source[key];
|
|
500
|
+
if (value === void 0) {
|
|
501
|
+
issues.push(`${key} is missing`);
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
if (value === "") {
|
|
505
|
+
issues.push(`${key} must not be empty`);
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
const [namespace, property] = FILTERABLE_ENV_KEYS[key];
|
|
509
|
+
const bucket = result[namespace] ?? {};
|
|
510
|
+
bucket[property] = value;
|
|
511
|
+
result[namespace] = bucket;
|
|
512
|
+
}
|
|
513
|
+
if (issues.length > 0) throw new PlatformError(ErrorCode.EnvNotInjected, [
|
|
514
|
+
"parseEnv: the required Neon env variables are not present in process.env.",
|
|
515
|
+
...issues.map((i) => ` - ${i}`),
|
|
516
|
+
"Inject them via one of:",
|
|
517
|
+
" - `neon dev` / `neon-env run -- <your dev command>` (wraps the command with the vars injected)",
|
|
518
|
+
" - your hosting platform's Neon integration (Vercel, Fly, Railway, …)",
|
|
519
|
+
"Or switch the call to `await fetchEnv(config, …)` if you're in a context that can do async I/O."
|
|
520
|
+
].join("\n"), { details: { missing: issues } });
|
|
521
|
+
return result;
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
453
524
|
* Project a fully-resolved {@link NeonEnv} into the OS-level `{ KEY: value }` pairs used
|
|
454
525
|
* for cross-process transport. Named after the web-platform `.entries()` convention
|
|
455
526
|
* (`URLSearchParams` / `Headers` / `FormData`); returns a `Record` rather than an
|
|
@@ -465,6 +536,7 @@ function toEntries(env) {
|
|
|
465
536
|
[NEON_ENV_VAR_KEYS.postgres.databaseUrl]: env.postgres.databaseUrl,
|
|
466
537
|
[NEON_ENV_VAR_KEYS.postgres.databaseUrlUnpooled]: env.postgres.databaseUrlUnpooled
|
|
467
538
|
};
|
|
539
|
+
if (env.branch) out[NEON_ENV_VAR_KEYS.branch.name] = env.branch.name;
|
|
468
540
|
const withAuth = env;
|
|
469
541
|
if (withAuth.auth) {
|
|
470
542
|
out[NEON_ENV_VAR_KEYS.auth.baseUrl] = withAuth.auth.baseUrl;
|
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 \"@neondatabase/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 * 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\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 both `AWS_REGION` (SDK-standard) and `NEON_STORAGE_REGION`;\n\t * `forcePathStyle` has no cross-SDK AWS env var, so it keeps its `NEON_` name (the AWS SDKs\n\t * default to path-style for custom endpoints anyway).\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\tregionNeon: \"NEON_STORAGE_REGION\",\n\t\tforcePathStyle: \"NEON_STORAGE_FORCE_PATH_STYLE\",\n\t},\n\t/**\n\t * AI Gateway (Preview). Mapped onto the OpenAI SDK's standard env vars so the OpenAI\n\t * clients work from env alone; `baseUrl` carries the gateway's OpenAI-dialect route prefix\n\t * (`/ai-gateway/openai/v1`). The `NEON_AI_GATEWAY_*` aliases are also emitted: `neonToken`\n\t * mirrors the OpenAI key, and `neonBaseUrl` is the bare branch gateway host\n\t * (`scheme://host`, no path) — the `@ai-sdk/neon` provider appends the\n\t * `/ai-gateway/<dialect>/…` routes itself (https://github.com/vercel/ai/pull/15997).\n\t */\n\taiGateway: {\n\t\tapiKey: \"OPENAI_API_KEY\",\n\t\tbaseUrl: \"OPENAI_BASE_URL\",\n\t\tneonToken: \"NEON_AI_GATEWAY_TOKEN\",\n\t\tneonBaseUrl: \"NEON_AI_GATEWAY_BASE_URL\",\n\t},\n} as const;\n\n/** OpenAI-dialect route prefix on the branch AI Gateway host. */\nconst AI_GATEWAY_OPENAI_PATH = \"/ai-gateway/openai/v1\";\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 short token id, `secretAccessKey` = its\n * `s3_secret_access_key`) with the branch's non-secret connection details\n * (`endpoint`/`region`/`forcePathStyle`, 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.\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 both `AWS_REGION` and `NEON_STORAGE_REGION`. */\n\tregion: string;\n\t/** Whether the S3 client must use path-style addressing (always `true` today). */\n\tforcePathStyle: boolean;\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 gateway's OpenAI-dialect endpoint on the branch-scoped gateway host\n * (`https://<branchId>-api.ai.<region>.…/ai-gateway/openai/v1`). Projects to the OpenAI SDK's\n * standard env (`OPENAI_API_KEY`, `OPENAI_BASE_URL`), plus the `NEON_AI_GATEWAY_*` aliases.\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} & (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> = NonNullable<C[\"preview\"]> extends {\n\tfunctions: infer F;\n}\n\t? F\n\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\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/** Neon branch id (`br-…`). **Required.** Resolve names to ids before calling. */\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, the only database on the branch is auto-picked; throws\n\t * {@link PlatformError} with `PLATFORM_AMBIGUOUS_BRANCH_AUTH` if the branch has more\n\t * than one database.\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 `branchId` explicitly\n * (resolve them in your CLI, e.g. neonctl).\n *\n * ```ts\n * import config from \"../neon\";\n * import { fetchEnv } from \"@neondatabase/env/v1\";\n *\n * const env = await fetchEnv(config, { projectId: \"patient-art-12345\", branchId: \"br-…\" });\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 branch = resolveBranch(options.branchId, 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\troleName,\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};\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\tforcePathStyle: storage.forcePathStyle,\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// Branch-scoped gateway host derived from the branch's connection URI — not the\n\t\t\t\t// control-plane API origin (which doesn't serve the gateway).\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 `OPENAI_API_KEY` / `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\taccessKeyId: minted.tokenIdShort,\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.<region-suffix>` — NOT the\n * control-plane API origin. Derive the `<region>.<cloud>.neon.<tld>` suffix from the branch's\n * own Postgres connection host (e.g. a connection host of `ep-x.us-east-2.aws.neon.build`\n * yields the gateway host `<branchId>-api.ai.us-east-2.aws.neon.build`). Any infra cell prefix\n * (`c-N.`) on the connection host is dropped — the gateway resolves with or without it.\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`) and any infra cell\n\t// prefix (`c-N.`), keeping `<region>.<cloud>.neon.<tld>`.\n\tconst suffix = connectionHost\n\t\t.split(\".\")\n\t\t.slice(1)\n\t\t.join(\".\")\n\t\t.replace(/^c-\\d+\\./, \"\");\n\treturn `${branchId}-api.ai.${suffix}`;\n}\n\n/** The AI Gateway's OpenAI-dialect base URL (`OPENAI_BASE_URL`) on the branch gateway host. */\nfunction aiGatewayBaseUrl(branchId: string, connectionUri: string): string {\n\treturn `https://${aiGatewayHost(branchId, connectionUri)}${AI_GATEWAY_OPENAI_PATH}`;\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\nfunction resolveBranch(\n\tbranchId: string,\n\tbranches: NeonBranchSnapshot[],\n): NeonBranchSnapshot {\n\tconst match = branches.find((b) => b.id === branchId);\n\tif (match) return match;\n\tthrow new PlatformError(\n\t\tErrorCode.BranchNotFound,\n\t\t[\n\t\t\t`fetchEnv: branch id ${JSON.stringify(branchId)} not found on project.`,\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\tbranchId,\n\t\t\t\tavailable: branches.map((b) => 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\troleName: string,\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\tif (databases.length === 1) return databases[0].name;\n\n\t// Prefer a database owned by the role we're connecting as.\n\tconst owned = databases.filter((d) => d.ownerName === roleName);\n\tif (owned.length === 1) return owned[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 ${databases.length} databases; cannot auto-pick.`,\n\t\t\t`Pass \\`databaseName\\` explicitly. 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\tOPENAI_API_KEY: z\n\t\t.string({ message: \"OPENAI_API_KEY is missing\" })\n\t\t.min(1, \"OPENAI_API_KEY must not be empty\"),\n\tOPENAI_BASE_URL: z\n\t\t.string({ message: \"OPENAI_BASE_URL is missing\" })\n\t\t.min(1, \"OPENAI_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/** Parse the `NEON_STORAGE_FORCE_PATH_STYLE` env string into a boolean (defaults to `true`). */\nfunction parseForcePathStyle(value: string | undefined): boolean {\n\tif (value === undefined) return true;\n\treturn value.trim().toLowerCase() !== \"false\";\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**:\n * - omitted — *external* scope (app bootstrap, build scripts, your dev machine). Returns\n * `{ postgres, auth?, dataApi? }`.\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 *\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 \"@neondatabase/env/v1\";\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 */\nexport function parseEnv<const C extends Config>(config: C): NeonEnv<C>;\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(config: Config, scope?: string): unknown {\n\tconst source = process.env;\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\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\tforcePathStyle: parseForcePathStyle(\n\t\t\t\t\tsource.NEON_STORAGE_FORCE_PATH_STYLE,\n\t\t\t\t),\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\tOPENAI_API_KEY: source.OPENAI_API_KEY,\n\t\t\tOPENAI_BASE_URL: source.OPENAI_BASE_URL,\n\t\t});\n\t\tif (aiGateway.success) {\n\t\t\tresult.aiGateway = {\n\t\t\t\tapiKey: aiGateway.data.OPENAI_API_KEY,\n\t\t\t\tbaseUrl: aiGateway.data.OPENAI_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// ───────────────────────── 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\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\t// Region is injected under both the AWS-standard and the Neon-specific name.\n\t\tout[keys.region] = s.region;\n\t\tout[keys.regionNeon] = s.region;\n\t\tout[keys.forcePathStyle] = String(s.forcePathStyle);\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\tout[keys.apiKey] = ai.apiKey;\n\t\tout[keys.baseUrl] = ai.baseUrl;\n\t\t// Neon-branded aliases: the same bearer, plus the bare branch gateway host\n\t\t// (scheme://host, no path) — the @ai-sdk/neon provider appends the\n\t\t// /ai-gateway/<dialect>/… routes itself (https://github.com/vercel/ai/pull/15997).\n\t\tout[keys.neonToken] = ai.apiKey;\n\t\tout[keys.neonBaseUrl] = new URL(ai.baseUrl).origin;\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 \"@neondatabase/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 * 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 both `AWS_REGION` (SDK-standard) and `NEON_STORAGE_REGION`;\n\t * `forcePathStyle` has no cross-SDK AWS env var, so it keeps its `NEON_` name (the AWS SDKs\n\t * default to path-style for custom endpoints anyway).\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\tregionNeon: \"NEON_STORAGE_REGION\",\n\t\tforcePathStyle: \"NEON_STORAGE_FORCE_PATH_STYLE\",\n\t},\n\t/**\n\t * AI Gateway (Preview). Mapped onto the OpenAI SDK's standard env vars so the OpenAI\n\t * clients work from env alone; `baseUrl` carries the gateway's OpenAI-dialect route prefix\n\t * (`/ai-gateway/openai/v1`). The `NEON_AI_GATEWAY_*` aliases are also emitted: `neonToken`\n\t * mirrors the OpenAI key, and `neonBaseUrl` is the bare branch gateway host\n\t * (`scheme://host`, no path) — the `@ai-sdk/neon` provider appends the\n\t * `/ai-gateway/<dialect>/…` routes itself (https://github.com/vercel/ai/pull/15997).\n\t */\n\taiGateway: {\n\t\tapiKey: \"OPENAI_API_KEY\",\n\t\tbaseUrl: \"OPENAI_BASE_URL\",\n\t\tneonToken: \"NEON_AI_GATEWAY_TOKEN\",\n\t\tneonBaseUrl: \"NEON_AI_GATEWAY_BASE_URL\",\n\t},\n} as const;\n\n/** OpenAI-dialect route prefix on the branch AI Gateway host. */\nconst AI_GATEWAY_OPENAI_PATH = \"/ai-gateway/openai/v1\";\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`/`forcePathStyle`, 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.\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 both `AWS_REGION` and `NEON_STORAGE_REGION`. */\n\tregion: string;\n\t/** Whether the S3 client must use path-style addressing (always `true` today). */\n\tforcePathStyle: boolean;\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 gateway's OpenAI-dialect endpoint on the branch-scoped gateway host\n * (`https://<branchId>-api.ai.<region>.…/ai-gateway/openai/v1`). Projects to the OpenAI SDK's\n * standard env (`OPENAI_API_KEY`, `OPENAI_BASE_URL`), plus the `NEON_AI_GATEWAY_*` aliases.\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> = NonNullable<C[\"preview\"]> extends {\n\tfunctions: infer F;\n}\n\t? F\n\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_STORAGE_REGION`, `NEON_AI_GATEWAY_TOKEN`, …) and the\n * always-derived `storage.forcePathStyle` are intentionally absent, so they are not\n * selectable in a `parseEnv(config, keys)` filter. Keep in sync with {@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: \"OPENAI_API_KEY\" | \"OPENAI_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\tOPENAI_API_KEY: \"apiKey\";\n\tOPENAI_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/** Neon branch id (`br-…`). **Required.** Resolve names to ids before calling. */\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, the only database on the branch is auto-picked; throws\n\t * {@link PlatformError} with `PLATFORM_AMBIGUOUS_BRANCH_AUTH` if the branch has more\n\t * than one database.\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 `branchId` explicitly\n * (resolve them in your CLI, e.g. neonctl).\n *\n * ```ts\n * import config from \"../neon\";\n * import { fetchEnv } from \"@neondatabase/env/v1\";\n *\n * const env = await fetchEnv(config, { projectId: \"patient-art-12345\", branchId: \"br-…\" });\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 branch = resolveBranch(options.branchId, 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\troleName,\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\tforcePathStyle: storage.forcePathStyle,\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// Branch-scoped gateway host derived from the branch's connection URI — not the\n\t\t\t\t// control-plane API origin (which doesn't serve the gateway).\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 `OPENAI_API_KEY` / `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.<region-suffix>` — NOT the\n * control-plane API origin. Derive the `<region>.<cloud>.neon.<tld>` suffix from the branch's\n * own Postgres connection host (e.g. a connection host of `ep-x.us-east-2.aws.neon.build`\n * yields the gateway host `<branchId>-api.ai.us-east-2.aws.neon.build`). Any infra cell prefix\n * (`c-N.`) on the connection host is dropped — the gateway resolves with or without it.\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`) and any infra cell\n\t// prefix (`c-N.`), keeping `<region>.<cloud>.neon.<tld>`.\n\tconst suffix = connectionHost\n\t\t.split(\".\")\n\t\t.slice(1)\n\t\t.join(\".\")\n\t\t.replace(/^c-\\d+\\./, \"\");\n\treturn `${branchId}-api.ai.${suffix}`;\n}\n\n/** The AI Gateway's OpenAI-dialect base URL (`OPENAI_BASE_URL`) on the branch gateway host. */\nfunction aiGatewayBaseUrl(branchId: string, connectionUri: string): string {\n\treturn `https://${aiGatewayHost(branchId, connectionUri)}${AI_GATEWAY_OPENAI_PATH}`;\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\nfunction resolveBranch(\n\tbranchId: string,\n\tbranches: NeonBranchSnapshot[],\n): NeonBranchSnapshot {\n\tconst match = branches.find((b) => b.id === branchId);\n\tif (match) return match;\n\tthrow new PlatformError(\n\t\tErrorCode.BranchNotFound,\n\t\t[\n\t\t\t`fetchEnv: branch id ${JSON.stringify(branchId)} not found on project.`,\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\tbranchId,\n\t\t\t\tavailable: branches.map((b) => 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\troleName: string,\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\tif (databases.length === 1) return databases[0].name;\n\n\t// Prefer a database owned by the role we're connecting as.\n\tconst owned = databases.filter((d) => d.ownerName === roleName);\n\tif (owned.length === 1) return owned[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 ${databases.length} databases; cannot auto-pick.`,\n\t\t\t`Pass \\`databaseName\\` explicitly. 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\tOPENAI_API_KEY: z\n\t\t.string({ message: \"OPENAI_API_KEY is missing\" })\n\t\t.min(1, \"OPENAI_API_KEY must not be empty\"),\n\tOPENAI_BASE_URL: z\n\t\t.string({ message: \"OPENAI_BASE_URL is missing\" })\n\t\t.min(1, \"OPENAI_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/** Parse the `NEON_STORAGE_FORCE_PATH_STYLE` env string into a boolean (defaults to `true`). */\nfunction parseForcePathStyle(value: string | undefined): boolean {\n\tif (value === undefined) return true;\n\treturn value.trim().toLowerCase() !== \"false\";\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 \"@neondatabase/env/v1\";\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\tforcePathStyle: parseForcePathStyle(\n\t\t\t\t\tsource.NEON_STORAGE_FORCE_PATH_STYLE,\n\t\t\t\t),\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\tOPENAI_API_KEY: source.OPENAI_API_KEY,\n\t\t\tOPENAI_BASE_URL: source.OPENAI_BASE_URL,\n\t\t});\n\t\tif (aiGateway.success) {\n\t\t\tresult.aiGateway = {\n\t\t\t\tapiKey: aiGateway.data.OPENAI_API_KEY,\n\t\t\t\tbaseUrl: aiGateway.data.OPENAI_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, no derived `forcePathStyle`).\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\tOPENAI_API_KEY: [\"aiGateway\", \"apiKey\"],\n\tOPENAI_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\t// Region is injected under both the AWS-standard and the Neon-specific name.\n\t\tout[keys.region] = s.region;\n\t\tout[keys.regionNeon] = s.region;\n\t\tout[keys.forcePathStyle] = String(s.forcePathStyle);\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\tout[keys.apiKey] = ai.apiKey;\n\t\tout[keys.baseUrl] = ai.baseUrl;\n\t\t// Neon-branded aliases: the same bearer, plus the bare branch gateway host\n\t\t// (scheme://host, no path) — the @ai-sdk/neon provider appends the\n\t\t// /ai-gateway/<dialect>/… routes itself (https://github.com/vercel/ai/pull/15997).\n\t\tout[keys.neonToken] = ai.apiKey;\n\t\tout[keys.neonBaseUrl] = new URL(ai.baseUrl).origin;\n\t}\n\treturn out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA+BA,MAAM,0BAA0B;;;;;;;;AAShC,MAAM,0BAA+C,IAAI,IAAI;CAC5D;CACA;CACA;AACD,CAAC;AAED,MAAa,oBAAoB;;;;;;CAMhC,QAAQ,EACP,MAAM,cACP;CACA,UAAU;EACT,aAAa;EACb,qBAAqB;CACtB;CACA,MAAM;EACL,SAAS;EACT,SAAS;CACV;CACA,SAAS,EACR,KAAK,oBACN;;;;;;;;CAQA,SAAS;EACR,aAAa;EACb,iBAAiB;EACjB,UAAU;EACV,QAAQ;EACR,YAAY;EACZ,gBAAgB;CACjB;;;;;;;;;CASA,WAAW;EACV,QAAQ;EACR,SAAS;EACT,WAAW;EACX,aAAa;CACd;AACD;;AAGA,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;AAsW/B,eAAsB,SACrB,QACA,SACsB;CACtB,MAAM,MAAM,QAAQ,OAAO,qBAAqB,OAAO;CACvD,MAAM,YAAY,QAAQ;CAE1B,MAAM,WAAW,MAAM,IAAI,aAAa,SAAS;CACjD,IAAI,SAAS,WAAW,GACvB,MAAM,IAAI,cACT,UAAU,gBACV,CACC,qBAAqB,UAAU,oBAC/B,wFACD,CAAC,CAAC,KAAK,GAAG,GACV,EAAE,SAAS,EAAE,UAAU,EAAE,CAC1B;CAGD,MAAM,SAAS,cAAc,QAAQ,UAAU,QAAQ;CACvD,MAAM,UAAU,cAAc,QAAQ;EACrC,MAAM,OAAO;EACb,IAAI,OAAO;EACX,QAAQ;EACR,GAAI,OAAO,WAAW,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;EACvD,WAAW,OAAO;EAClB,aAAa,OAAO;EACpB,GAAI,OAAO,YAAY,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;CAC3D,CAAC;CAED,MAAM,CAAC,OAAO,aAAa,MAAM,QAAQ,IAAI,CAC5C,IAAI,gBAAgB,WAAW,OAAO,EAAE,GACxC,IAAI,oBAAoB,WAAW,OAAO,EAAE,CAC7C,CAAC;CAED,MAAM,WAAW,aAAa,OAAO,QAAQ,QAAQ,QAAQ;CAC7D,MAAM,eAAe,iBACpB,WACA,QACA,UACA,QAAQ,YACT;CAMA,MAAM,YAAY,QAAQ;CAC1B,MAAM,eAAe,QAAQ;CAE7B,MAAM,CAAC,QAAQ,UAAU,cAAc,mBAAmB,MAAM,QAAQ,IACvE;EACC,IAAI,iBAAiB,WAAW;GAC/B,UAAU,OAAO;GACjB;GACA;GACA,QAAQ;EACT,CAAC;EACD,IAAI,iBAAiB,WAAW;GAC/B,UAAU,OAAO;GACjB;GACA;GACA,QAAQ;EACT,CAAC;EACD,YACG,IAAI,YAAY,WAAW,OAAO,EAAE,IACpC,QAAQ,QAAQ,IAAI;EACvB,eACG,IAAI,eAAe,WAAW,OAAO,IAAI,YAAY,IACrD,QAAQ,QAAQ,IAAI;CACxB,CACD;CAEA,MAAM,SAAkC;EACvC,UAAU;GACT,aAAa,OAAO;GACpB,qBAAqB,SAAS;EAC/B;EAIA,QAAQ,EAAE,MAAM,OAAO,KAAK;CAC7B;CAEA,IAAI,WAAW;EACd,IAAI,CAAC,cACJ,MAAM,IAAI,cACT,UAAU,UACV,CACC,0FAA0F,OAAO,KAAK,IAAI,OAAO,GAAG,KACpH,wJACD,CAAC,CAAC,KAAK,GAAG,GACV,EACC,SAAS;GAAE;GAAW,UAAU,OAAO;EAAG,EAC3C,CACD;EAED,MAAM,YAAY,QAAQ,OAAO,QAAQ;EAGzC,OAAO,OAAO;GAAE,SAFA,mBAAmB,aAAa,SAAS,SAEnC;GAAG,SADT,mBAAmB,aAAa,SAAS,SAC1B;EAAE;CAClC;CAEA,IAAI,cAAc;EACjB,IAAI,CAAC,iBACJ,MAAM,IAAI,cACT,UAAU,UACV,CACC,4FAA4F,OAAO,KAAK,IAAI,OAAO,GAAG,aAAa,aAAa,IAChJ,wIACD,CAAC,CAAC,KAAK,GAAG,GACV,EACC,SAAS;GACR;GACA,UAAU,OAAO;GACjB;EACD,EACD,CACD;EAED,OAAO,UAAU,EAAE,KAAK,gBAAgB,IAAI;CAC7C;CAOA,MAAM,gBAAgB,QAAQ,SAAS,QAAQ,UAAU,KAAK;CAC9D,MAAM,iBAAiB,QAAQ,SAAS,oBAAoB;CAC5D,IAAI,gBAAgB,gBAAgB;EACnC,MAAM,UAAU,MAAM,yBAAyB;GAC9C;GACA;GACA,UAAU,OAAO;GACjB,YAAY,OAAO;GACnB,QAAQ,wBAAwB,QAAQ,OAAO;GAC/C,KAAK,QAAQ,OAAO,QAAQ;GAC5B,aAAa;GACb,cAAc;EACf,CAAC;EACD,IAAI,cAAc;GACjB,MAAM,UAAU,MAAM,IAAI,wBACzB,WACA,OAAO,EACR;GACA,IAAI,CAAC,SACJ,MAAM,IAAI,cACT,UAAU,UACV,CACC,0GAA0G,OAAO,KAAK,IAAI,OAAO,GAAG,KACpI,oIACD,CAAC,CAAC,KAAK,GAAG,GACV,EAAE,SAAS;IAAE;IAAW,UAAU,OAAO;GAAG,EAAE,CAC/C;GAED,OAAO,UAAU;IAChB,aAAa,QAAQ;IACrB,iBAAiB,QAAQ;IACzB,UAAU,QAAQ;IAClB,QAAQ,QAAQ;IAChB,gBAAgB,QAAQ;GACzB;EACD;EACA,IAAI,gBACH,OAAO,YAAY;GAClB,QAAQ,QAAQ;GAGhB,SAAS,iBAAiB,OAAO,IAAI,SAAS,GAAG;EAClD;CAEF;CAEA,OAAO;AACR;;;;;;;;AASA,SAAS,wBACR,SACoB;CACpB,IAAI,CAAC,SAAS,OAAO,CAAC;CACtB,MAAM,UAAU,QAAQ,QAAQ,SAAS;CACzC,MAAM,YAAY,QAAQ;CAC1B,IAAI,CAAC,WAAW,CAAC,WAAW,OAAO,CAAC;CACpC,OAAO,uBAAuB;EAC7B;EACA;EACA,WAAW,QAAQ,UAAU,SAAS;CACvC,CAAC;AACF;;;;;;;;;;AAWA,eAAe,yBAAyB,MAarC;CACF,MAAM,QAAQ,kBAAkB;CAChC,MAAM,QAAQ,kBAAkB;CAChC,MAAM,cACL,CAAC,KAAK,eACN,QAAQ,KAAK,IAAI,MAAM,gBAAgB,KAAK,IAAI,MAAM,gBAAgB;CACvE,MAAM,eAAe,CAAC,KAAK,gBAAgB,QAAQ,KAAK,IAAI,MAAM,OAAO;CACzE,IAAI,eAAe,cAClB,OAAO;EACN,aAAa,KAAK,IAAI,MAAM,gBAAgB;EAC5C,iBAAiB,KAAK,IAAI,MAAM,oBAAoB;EACpD,UAAU,KAAK,IAAI,MAAM,WAAW;CACrC;CAED,MAAM,SAAS,MAAM,KAAK,IAAI,iBAC7B,KAAK,WACL,KAAK,UACL;EACC,QAAQ,KAAK;EACb,eAAe;EACf,MAAM,YAAY,KAAK;CACxB,CACD;CACA,OAAO;EAIN,aAAa,OAAO;EACpB,iBAAiB,OAAO;EACxB,UAAU,OAAO;CAClB;AACD;;;;;;;;AASA,SAAS,cAAc,UAAkB,eAA+B;CACvE,IAAI,iBAAiB;CACrB,IAAI;EACH,iBAAiB,IAAI,IAAI,aAAa,CAAC,CAAC;CACzC,QAAQ;EACP,iBAAiB;CAClB;CAQA,OAAO,GAAG,SAAS,UALJ,eACb,MAAM,GAAG,CAAC,CACV,MAAM,CAAC,CAAC,CACR,KAAK,GAAG,CAAC,CACT,QAAQ,YAAY,EACY;AACnC;;AAGA,SAAS,iBAAiB,UAAkB,eAA+B;CAC1E,OAAO,WAAW,cAAc,UAAU,aAAa,IAAI;AAC5D;;;;;;;AAQA,SAAS,mBACR,iBACA,QACS;CACT,IAAI,mBAAmB,oBAAoB,IAAI,OAAO;CACtD,OAAO,OAAO,kBAAkB,KAAK,YAAY;AAClD;;;;;;AAOA,SAAS,mBACR,iBACA,QACS;CACT,IAAI,mBAAmB,oBAAoB,IAAI,OAAO;CACtD,OAAO,OAAO,kBAAkB,KAAK,YAAY;AAClD;AAEA,SAAS,qBAAqB,SAAmC;CAChE,OAAO,yBAAyB,YAAY;EAC3C,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;EACnD,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;CACvD,CAAC;AACF;AAEA,SAAS,cACR,UACA,UACqB;CACrB,MAAM,QAAQ,SAAS,MAAM,MAAM,EAAE,OAAO,QAAQ;CACpD,IAAI,OAAO,OAAO;CAClB,MAAM,IAAI,cACT,UAAU,gBACV,CACC,uBAAuB,KAAK,UAAU,QAAQ,EAAE,yBAChD,sBAAsB,SAAS,KAAK,MAAM,GAAG,EAAE,KAAK,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,EAC7E,CAAC,CAAC,KAAK,GAAG,GACV,EACC,SAAS;EACR;EACA,WAAW,SAAS,KAAK,MAAM,EAAE,EAAE;CACpC,EACD,CACD;AACD;AAEA,SAAS,aACR,OACA,QACA,WACS;CACT,IAAI,WAAW;EACd,IAAI,CAAC,MAAM,MAAM,MAAM,EAAE,SAAS,SAAS,GAC1C,MAAM,IAAI,cACT,UAAU,gBACV,CACC,mBAAmB,UAAU,wBAAwB,OAAO,KAAK,IAAI,OAAO,GAAG,KAC/E,mBAAmB,MAAM,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,SAAS,EACpE,CAAC,CAAC,KAAK,GAAG,GACV,EACC,SAAS;GACR,UAAU,OAAO;GACjB,UAAU;GACV,gBAAgB,MAAM,KAAK,MAAM,EAAE,IAAI;EACxC,EACD,CACD;EAED,OAAO;CACR;CACA,IAAI,MAAM,WAAW,GACpB,MAAM,IAAI,cACT,UAAU,gBACV,CACC,oBAAoB,OAAO,KAAK,IAAI,OAAO,GAAG,kBAC9C,gEACD,CAAC,CAAC,KAAK,GAAG,GACV,EAAE,SAAS,EAAE,UAAU,OAAO,GAAG,EAAE,CACpC;CAED,IAAI,MAAM,WAAW,GAAG,OAAO,MAAM,EAAE,CAAC;CAQxC,MAAM,QAAQ,MAAM,MAAM,MAAM,EAAE,SAAS,uBAAuB;CAClE,IAAI,OAAO,OAAO,MAAM;CAExB,MAAM,WAAW,MAAM,QAAQ,MAAM,CAAC,wBAAwB,IAAI,EAAE,IAAI,CAAC;CACzE,IAAI,SAAS,WAAW,GAAG,OAAO,SAAS,EAAE,CAAC;CAE9C,MAAM,IAAI,cACT,UAAU,qBACV,CACC,oBAAoB,OAAO,KAAK,IAAI,OAAO,GAAG,QAAQ,MAAM,OAAO,sBAAsB,wBAAwB,uBACjH,4CAA4C,MAAM,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,EACjF,CAAC,CAAC,KAAK,GAAG,GACV,EACC,SAAS;EACR,UAAU,OAAO;EACjB,gBAAgB,MAAM,KAAK,MAAM,EAAE,IAAI;CACxC,EACD,CACD;AACD;AAEA,SAAS,iBACR,WACA,QACA,UACA,WACS;CACT,IAAI,WAAW;EACd,IAAI,CAAC,UAAU,MAAM,MAAM,EAAE,SAAS,SAAS,GAC9C,MAAM,IAAI,cACT,UAAU,gBACV,CACC,uBAAuB,UAAU,wBAAwB,OAAO,KAAK,IAAI,OAAO,GAAG,KACnF,uBAAuB,UAAU,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,SAAS,EAC5E,CAAC,CAAC,KAAK,GAAG,GACV,EACC,SAAS;GACR,UAAU,OAAO;GACjB,cAAc;GACd,oBAAoB,UAAU,KAAK,MAAM,EAAE,IAAI;EAChD,EACD,CACD;EAED,OAAO;CACR;CACA,IAAI,UAAU,WAAW,GACxB,MAAM,IAAI,cACT,UAAU,gBACV,CACC,oBAAoB,OAAO,KAAK,IAAI,OAAO,GAAG,sBAC9C,oEACD,CAAC,CAAC,KAAK,GAAG,GACV,EAAE,SAAS,EAAE,UAAU,OAAO,GAAG,EAAE,CACpC;CAED,IAAI,UAAU,WAAW,GAAG,OAAO,UAAU,EAAE,CAAC;CAGhD,MAAM,QAAQ,UAAU,QAAQ,MAAM,EAAE,cAAc,QAAQ;CAC9D,IAAI,MAAM,WAAW,GAAG,OAAO,MAAM,EAAE,CAAC;CAExC,MAAM,IAAI,cACT,UAAU,qBACV,CACC,oBAAoB,OAAO,KAAK,IAAI,OAAO,GAAG,QAAQ,UAAU,OAAO,gCACvE,gDAAgD,UAAU,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,EACzF,CAAC,CAAC,KAAK,GAAG,GACV,EACC,SAAS;EACR,UAAU,OAAO;EACjB,oBAAoB,UAAU,KAAK,MAAM,EAAE,IAAI;CAChD,EACD,CACD;AACD;;;;;;;;;AAYA,MAAM,oBAAoB,EAAE,OAAO;CAClC,cAAc,EACZ,OAAO,EAAE,SAAS,0BAA0B,CAAC,CAAC,CAC9C,IAAI,GAAG,gCAAgC;CACzC,uBAAuB,EACrB,OAAO,EAAE,SAAS,mCAAmC,CAAC,CAAC,CACvD,IAAI,GAAG,yCAAyC;AACnD,CAAC;AAED,MAAM,gBAAgB,EAAE,OAAO;CAC9B,oBAAoB,EAClB,OAAO,EAAE,SAAS,gCAAgC,CAAC,CAAC,CACpD,IAAI,GAAG,sCAAsC;CAC/C,oBAAoB,EAClB,OAAO,EAAE,SAAS,gCAAgC,CAAC,CAAC,CACpD,IAAI,GAAG,sCAAsC;AAChD,CAAC;AAED,MAAM,mBAAmB,EAAE,OAAO,EACjC,mBAAmB,EACjB,OAAO,EAAE,SAAS,+BAA+B,CAAC,CAAC,CACnD,IAAI,GAAG,qCAAqC,EAC/C,CAAC;AAED,MAAM,mBAAmB,EAAE,OAAO;CACjC,mBAAmB,EACjB,OAAO,EAAE,SAAS,+BAA+B,CAAC,CAAC,CACnD,IAAI,GAAG,qCAAqC;CAC9C,uBAAuB,EACrB,OAAO,EAAE,SAAS,mCAAmC,CAAC,CAAC,CACvD,IAAI,GAAG,yCAAyC;CAClD,qBAAqB,EACnB,OAAO,EAAE,SAAS,iCAAiC,CAAC,CAAC,CACrD,IAAI,GAAG,uCAAuC;CAChD,YAAY,EACV,OAAO,EAAE,SAAS,wBAAwB,CAAC,CAAC,CAC5C,IAAI,GAAG,8BAA8B;AACxC,CAAC;AAED,MAAM,qBAAqB,EAAE,OAAO;CACnC,gBAAgB,EACd,OAAO,EAAE,SAAS,4BAA4B,CAAC,CAAC,CAChD,IAAI,GAAG,kCAAkC;CAC3C,iBAAiB,EACf,OAAO,EAAE,SAAS,6BAA6B,CAAC,CAAC,CACjD,IAAI,GAAG,mCAAmC;AAC7C,CAAC;;AAGD,SAAS,mBAAmB,QAAyB;CACpD,OAAO,OAAO,KAAK,OAAO,SAAS,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS;AAC5D;;AAGA,SAAS,qBAAqB,QAAyB;CACtD,OAAO,sBAAsB,OAAO,SAAS,SAAS;AACvD;;AAGA,SAAS,oBAAoB,OAAoC;CAChE,IAAI,UAAU,KAAA,GAAW,OAAO;CAChC,OAAO,MAAM,KAAK,CAAC,CAAC,YAAY,MAAM;AACvC;;AAGA,SAAS,sBACR,QACU;CACV,IAAI,WAAW,KAAA,GAAW,OAAO;CACjC,IAAI,OAAO,WAAW,WAAW,OAAO;CACxC,OAAO,OAAO,YAAY;AAC3B;AA2DA,SAAgB,SACf,QACA,aACU;CACV,MAAM,SAAS,QAAQ;CACvB,IAAI,MAAM,QAAQ,WAAW,GAC5B,OAAO,iBAAiB,QAAQ,WAAW;CAI5C,MAAM,QAAQ,OAAO,gBAAgB,WAAW,cAAc,KAAA;CAC9D,MAAM,SAAmB,CAAC;CAC1B,MAAM,SAAkC,CAAC;CAEzC,MAAM,KAAK,kBAAkB,UAAU;EACtC,cAAc,OAAO;EACrB,uBAAuB,OAAO;CAC/B,CAAC;CACD,IAAI,GAAG,SACN,OAAO,WAAW;EACjB,aAAa,GAAG,KAAK;EACrB,qBAAqB,GAAG,KAAK;CAC9B;MAEA,KAAK,MAAM,SAAS,GAAG,MAAM,QAAQ,OAAO,KAAK,MAAM,OAAO;CAO/D,MAAM,aAAa,OAAO,kBAAkB,OAAO;CACnD,IAAI,eAAe,KAAA,KAAa,eAAe,IAC9C,OAAO,SAAS,EAAE,MAAM,WAAW;CAGpC,IAAI,sBAAsB,OAAO,IAAI,GAAG;EACvC,MAAM,OAAO,cAAc,UAAU;GACpC,oBAAoB,OAAO;GAC3B,oBAAoB,OAAO;EAC5B,CAAC;EACD,IAAI,KAAK,SACR,OAAO,OAAO;GACb,SAAS,KAAK,KAAK;GACnB,SAAS,KAAK,KAAK;EACpB;OAEA,KAAK,MAAM,SAAS,KAAK,MAAM,QAAQ,OAAO,KAAK,MAAM,OAAO;CAElE;CAEA,IAAI,sBAAsB,OAAO,OAAO,GAAG;EAC1C,MAAM,UAAU,iBAAiB,UAAU,EAC1C,mBAAmB,OAAO,kBAC3B,CAAC;EACD,IAAI,QAAQ,SACX,OAAO,UAAU,EAChB,KAAK,QAAQ,KAAK,kBACnB;OAEA,KAAK,MAAM,SAAS,QAAQ,MAAM,QACjC,OAAO,KAAK,MAAM,OAAO;CAE5B;CAEA,IAAI,mBAAmB,MAAM,GAAG;EAC/B,MAAM,UAAU,iBAAiB,UAAU;GAC1C,mBAAmB,OAAO;GAC1B,uBAAuB,OAAO;GAC9B,qBAAqB,OAAO;GAC5B,YAAY,OAAO;EACpB,CAAC;EACD,IAAI,QAAQ,SACX,OAAO,UAAU;GAChB,aAAa,QAAQ,KAAK;GAC1B,iBAAiB,QAAQ,KAAK;GAC9B,UAAU,QAAQ,KAAK;GACvB,QAAQ,QAAQ,KAAK;GACrB,gBAAgB,oBACf,OAAO,6BACR;EACD;OAEA,KAAK,MAAM,SAAS,QAAQ,MAAM,QACjC,OAAO,KAAK,MAAM,OAAO;CAE5B;CAEA,IAAI,qBAAqB,MAAM,GAAG;EACjC,MAAM,YAAY,mBAAmB,UAAU;GAC9C,gBAAgB,OAAO;GACvB,iBAAiB,OAAO;EACzB,CAAC;EACD,IAAI,UAAU,SACb,OAAO,YAAY;GAClB,QAAQ,UAAU,KAAK;GACvB,SAAS,UAAU,KAAK;EACzB;OAEA,KAAK,MAAM,SAAS,UAAU,MAAM,QACnC,OAAO,KAAK,MAAM,OAAO;CAE5B;CAEA,IAAI,UAAU,KAAA,GAAW;EACxB,MAAM,KAAK,OAAO,SAAS,YAAY;EACvC,IAAI,CAAC,IACJ,MAAM,IAAI,cACT,UAAU,gBACV,CACC,0BAA0B,MAAM,oDAChC,yEACD,CAAC,CAAC,KAAK,IAAI,GACX,EAAE,SAAS,EAAE,MAAM,EAAE,CACtB;EAED,MAAM,SAAiC,CAAC;EACxC,KAAK,MAAM,OAAO,OAAO,KAAK,GAAG,OAAO,CAAC,CAAC,GAAG;GAC5C,MAAM,QAAQ,OAAO;GAIrB,IAAI,UAAU,KAAA,GACb,OAAO,KAAK,GAAG,IAAI,yBAAyB,MAAM,GAAG;QAErD,OAAO,OAAO;EAEhB;EACA,OAAO,WAAW;CACnB;CAEA,IAAI,OAAO,SAAS,GACnB,MAAM,IAAI,cACT,UAAU,gBACV;EACC;EACA,GAAG,OAAO,KAAK,MAAM,OAAO,GAAG;EAC/B;EACA;EACA;EACA;EACA;CACD,CAAC,CAAC,KAAK,IAAI,GACX,EAAE,SAAS,EAAE,SAAS,OAAO,EAAE,CAChC;CAGD,OAAO;AACR;;;;;;;AAQA,MAAM,sBAAiE;CACtE,cAAc,CAAC,YAAY,aAAa;CACxC,uBAAuB,CAAC,YAAY,qBAAqB;CACzD,oBAAoB,CAAC,QAAQ,SAAS;CACtC,oBAAoB,CAAC,QAAQ,SAAS;CACtC,mBAAmB,CAAC,WAAW,KAAK;CACpC,mBAAmB,CAAC,WAAW,aAAa;CAC5C,uBAAuB,CAAC,WAAW,iBAAiB;CACpD,qBAAqB,CAAC,WAAW,UAAU;CAC3C,YAAY,CAAC,WAAW,QAAQ;CAChC,gBAAgB,CAAC,aAAa,QAAQ;CACtC,iBAAiB,CAAC,aAAa,SAAS;AACzC;;;;;;;;AASA,SAAS,iBACR,QACA,MACyC;CACzC,MAAM,SAAmB,CAAC;CAC1B,MAAM,SAAiD,CAAC;CACxD,KAAK,MAAM,OAAO,MAAM;EAGvB,IAAI,CAAC,OAAO,OAAO,qBAAqB,GAAG,GAAG;GAC7C,OAAO,KAAK,GAAG,IAAI,uCAAuC;GAC1D;EACD;EACA,MAAM,QAAQ,OAAO;EACrB,IAAI,UAAU,KAAA,GAAW;GACxB,OAAO,KAAK,GAAG,IAAI,YAAY;GAC/B;EACD;EACA,IAAI,UAAU,IAAI;GACjB,OAAO,KAAK,GAAG,IAAI,mBAAmB;GACtC;EACD;EACA,MAAM,CAAC,WAAW,YAAY,oBAAoB;EAClD,MAAM,SAAS,OAAO,cAAc,CAAC;EACrC,OAAO,YAAY;EACnB,OAAO,aAAa;CACrB;CACA,IAAI,OAAO,SAAS,GACnB,MAAM,IAAI,cACT,UAAU,gBACV;EACC;EACA,GAAG,OAAO,KAAK,MAAM,OAAO,GAAG;EAC/B;EACA;EACA;EACA;CACD,CAAC,CAAC,KAAK,IAAI,GACX,EAAE,SAAS,EAAE,SAAS,OAAO,EAAE,CAChC;CAED,OAAO;AACR;;;;;;;;;;;;AAeA,SAAgB,UAAU,KAA8C;CACvE,MAAM,MAA8B;GAClC,kBAAkB,SAAS,cAAc,IAAI,SAAS;GACtD,kBAAkB,SAAS,sBAC3B,IAAI,SAAS;CACf;CACA,IAAI,IAAI,QACP,IAAI,kBAAkB,OAAO,QAAQ,IAAI,OAAO;CAEjD,MAAM,WAAW;CACjB,IAAI,SAAS,MAAM;EAClB,IAAI,kBAAkB,KAAK,WAAW,SAAS,KAAK;EACpD,IAAI,kBAAkB,KAAK,WAAW,SAAS,KAAK;CACrD;CACA,MAAM,cAAc;CACpB,IAAI,YAAY,SACf,IAAI,kBAAkB,QAAQ,OAAO,YAAY,QAAQ;CAE1D,MAAM,cAAc;CACpB,IAAI,YAAY,SAAS;EACxB,MAAM,IAAI,YAAY;EACtB,MAAM,OAAO,kBAAkB;EAC/B,IAAI,KAAK,eAAe,EAAE;EAC1B,IAAI,KAAK,mBAAmB,EAAE;EAC9B,IAAI,KAAK,YAAY,EAAE;EAEvB,IAAI,KAAK,UAAU,EAAE;EACrB,IAAI,KAAK,cAAc,EAAE;EACzB,IAAI,KAAK,kBAAkB,OAAO,EAAE,cAAc;CACnD;CACA,MAAM,gBAAgB;CACtB,IAAI,cAAc,WAAW;EAC5B,MAAM,OAAO,kBAAkB;EAC/B,MAAM,KAAK,cAAc;EACzB,IAAI,KAAK,UAAU,GAAG;EACtB,IAAI,KAAK,WAAW,GAAG;EAIvB,IAAI,KAAK,aAAa,GAAG;EACzB,IAAI,KAAK,eAAe,IAAI,IAAI,GAAG,OAAO,CAAC,CAAC;CAC7C;CACA,OAAO;AACR"}
|
package/dist/v1.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { FetchEnvOptions, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAiGatewayEnv, NeonAuthEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, NeonStorageEnv, fetchEnv, parseEnv, toEntries } from "./lib/env.js";
|
|
2
|
-
export { type FetchEnvOptions, type FunctionSlugOf, NEON_ENV_VAR_KEYS, type NeonAiGatewayEnv, type NeonAuthEnv, type NeonDataApiEnv, type NeonEnv, type NeonFunctionEnv, type NeonPostgresEnv, type NeonStorageEnv, fetchEnv, parseEnv, toEntries };
|
|
1
|
+
import { FetchEnvOptions, FilteredNeonEnv, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAiGatewayEnv, NeonAuthEnv, NeonBranchEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, NeonStorageEnv, SelectableEnvKey, fetchEnv, parseEnv, toEntries } from "./lib/env.js";
|
|
2
|
+
export { type FetchEnvOptions, type FilteredNeonEnv, type FunctionSlugOf, NEON_ENV_VAR_KEYS, type NeonAiGatewayEnv, type NeonAuthEnv, type NeonBranchEnv, type NeonDataApiEnv, type NeonEnv, type NeonFunctionEnv, type NeonPostgresEnv, type NeonStorageEnv, type SelectableEnvKey, fetchEnv, parseEnv, toEntries };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neondatabase/env",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
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",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"zod": "^4.4.3",
|
|
57
57
|
"yargs": "^18.0.0",
|
|
58
|
-
"@neondatabase/config": "0.7.
|
|
58
|
+
"@neondatabase/config": "0.7.2"
|
|
59
59
|
},
|
|
60
60
|
"engines": {
|
|
61
61
|
"node": ">=22"
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"build": "tsc --noEmit && tsdown",
|
|
68
68
|
"test": "vitest --passWithNoTests",
|
|
69
69
|
"test:ci": "vitest run --passWithNoTests",
|
|
70
|
+
"test:types": "vitest run --typecheck.enabled --typecheck.only",
|
|
70
71
|
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
71
72
|
"tsc": "tsc"
|
|
72
73
|
}
|