@neondatabase/env 0.1.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/dist/config/dist/lib/neon-api.d.ts +1 -2
- package/dist/config/dist/lib/neon-api.d.ts.map +1 -1
- package/dist/config/dist/lib/types.d.ts +111 -60
- package/dist/config/dist/lib/types.d.ts.map +1 -1
- package/dist/config/dist/v1.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/lib/cli/resolve-context.d.ts +0 -2
- package/dist/lib/cli/resolve-context.d.ts.map +1 -1
- package/dist/lib/cli/resolve-context.js +1 -4
- package/dist/lib/cli/resolve-context.js.map +1 -1
- package/dist/lib/env.d.ts +67 -29
- package/dist/lib/env.d.ts.map +1 -1
- package/dist/lib/env.js +23 -39
- package/dist/lib/env.js.map +1 -1
- package/dist/v1.d.ts +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -12,9 +12,9 @@ npm install @neondatabase/env
|
|
|
12
12
|
|
|
13
13
|
## Functions
|
|
14
14
|
|
|
15
|
-
The library functions are **filesystem- and env-agnostic**: `fetchEnv` requires an explicit `projectId` + `branchId
|
|
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
|
|
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, or pass a **function slug** when running inside that deployed function to also get a typed `function` namespace of its declared env keys.
|
|
18
18
|
|
|
19
19
|
```ts
|
|
20
20
|
import config from "../neon";
|
|
@@ -26,7 +26,11 @@ const db = drizzle(neon(env.postgres.databaseUrl), { schema });
|
|
|
26
26
|
|
|
27
27
|
// Sync — reads already-injected process.env and validates it (no network).
|
|
28
28
|
// Use in app bootstrap where async isn't available.
|
|
29
|
-
const env2 = parseEnv(config
|
|
29
|
+
const env2 = parseEnv(config);
|
|
30
|
+
|
|
31
|
+
// Inside a deployed function, pass its slug for the typed `function` namespace:
|
|
32
|
+
const fnEnv = parseEnv(config, "hello");
|
|
33
|
+
fnEnv.function.resendApiKey; // typed from hello's declared env keys
|
|
30
34
|
```
|
|
31
35
|
|
|
32
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.
|
|
@@ -34,7 +38,7 @@ Both return the same namespaced `NeonEnv` shape: `postgres` is always present; `
|
|
|
34
38
|
| Function | Description |
|
|
35
39
|
| --- | --- |
|
|
36
40
|
| `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). |
|
|
37
|
-
| `parseEnv(config,
|
|
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. |
|
|
38
42
|
| `toEntries(env)` | Project a resolved `NeonEnv` into `{ KEY: value }` pairs for cross-process transport (named after the web `.entries()` convention; returns a `Record`). |
|
|
39
43
|
|
|
40
44
|
## CLI
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BucketAccessLevel, ComputeSettings,
|
|
1
|
+
import { BucketAccessLevel, ComputeSettings, FunctionRuntime } from "./types.js";
|
|
2
2
|
|
|
3
3
|
//#region ../config/dist/lib/neon-api.d.ts
|
|
4
4
|
|
|
@@ -141,7 +141,6 @@ interface NeonFunctionSnapshot {
|
|
|
141
141
|
interface DeployFunctionInput {
|
|
142
142
|
bundle: Uint8Array;
|
|
143
143
|
runtime: FunctionRuntime;
|
|
144
|
-
memoryMib: FunctionMemoryMib;
|
|
145
144
|
environment: Record<string, string>;
|
|
146
145
|
}
|
|
147
146
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neon-api.d.ts","names":["BucketAccessLevel","ComputeSettings","FunctionMemoryMib","FunctionRuntime","NeonProjectSnapshot","NeonBranchSnapshot","NeonEndpointSnapshot","CreateProjectInput","CreateBranchInput","UpdateBranchInput","NeonRoleSnapshot","NeonDatabaseSnapshot","NeonAuthSnapshot","NeonDataApiSnapshot","NeonBucketSnapshot","CreateBucketInput","NeonFunctionSnapshot","DeployFunctionInput","Uint8Array","Record","NeonFunctionDeploymentSnapshot","GetConnectionUriInput","NeonApi","Promise"],"sources":["../../../../../config/dist/lib/neon-api.d.ts"],"sourcesContent":["import { BucketAccessLevel, ComputeSettings, FunctionMemoryMib, 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 * 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 memoryMib: FunctionMemoryMib;\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 * 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 /** List functions on a branch. */\n listBranchFunctions(projectId: string, branchId: string): Promise<NeonFunctionSnapshot[]>;\n /**\n * Create a function on a branch. The function has no deployment until code is deployed\n * to it with {@link deployBranchFunction}.\n */\n createBranchFunction(projectId: string, branchId: string, input: {\n slug: string;\n name: string;\n }): 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. The newest deployment becomes active. The\n * `bundle` is built (esbuild + zip) by the caller and passed in as bytes.\n */\n deployBranchFunction(projectId: string, branchId: string, slug: string, input: DeployFunctionInput): Promise<NeonFunctionDeploymentSnapshot>;\n /**\n * Whether the AI Gateway is enabled on a branch. Toggle-style, like Neon Auth / Data\n * API: used by both `fetchEnv` (to decide visibility) and `pushConfig` (to diff intent).\n */\n getAiGatewayEnabled(projectId: string, branchId: string): Promise<boolean>;\n /** Enable the AI Gateway on a branch. Idempotent. */\n enableAiGateway(projectId: string, branchId: string): Promise<void>;\n /** Disable the AI Gateway on a branch. Idempotent. */\n disableAiGateway(projectId: string, branchId: string): Promise<void>;\n}\n//#endregion\nexport { CreateBranchInput, CreateBucketInput, CreateProjectInput, DeployFunctionInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBucketSnapshot, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, UpdateBranchInput };\n//# sourceMappingURL=neon-api.d.ts.map"],"mappings":";;;;;AAe2C;AAEf;;;;UARlBI,mBAAAA,CAuBQH;EAAe,EAAA,EAAA,MAAA;EAAA,IAEvBM,EAAAA,MAAAA;EAKiC,QAOjCC,EAAAA,MAAAA;EAMyB,SAEzBC,EAAAA,MAAAA;EAAiB,KAWjBC,CAAAA,EAAAA,MAAAA;EAAgB,uBAShBC,CAAAA,EA3DkBV,eA2DE;AAAA;AAUJ,UAnEhBI,kBAAAA,CAkFmB;EAAA,EAQnBS,EAAAA,MAAAA;EAEsB,IAKtBC,EAAAA,MAAAA;EAEuB,QAMvBC,CAAAA,EAAAA,MAAAA;EAAoB,SAiBpBC,EAAAA,OAAAA;EAAmB;WACnBC,EAAAA,OAAAA;WACCf,CAAAA,EAAAA,MAAAA;;UAnHDG,oBAAAA,CAqHKa;EAAM,EAAA,EAAA,MAAA;EAAA,QAKXC,EAAAA,MAAAA;EAA8B,IAU9BC,EAAAA,WAAAA,GAAAA,YAAqB;EAAA,qBAad,EA7IQpB,eA6IR,CAAA,uBAAA,CAAA;EAAA,qBAAA,EA5IQA,eA4IR,CAAA,uBAAA,CAAA;gBAGHG,EA9IIH,eA8IJG,CAAAA,gBAAAA,CAAAA;;UA5IJG,kBAAAA,CA6I+BH;QAARmB,MAAAA;UACVhB,EAAAA,MAAAA;WAA6BH,CAAAA,EAAAA,MAAAA;OAARmB,CAAAA,EAAAA,MAAAA;yBAGdtB,CAAAA,EA5IFA,eA4IEA;;;;;mBAGWO,CAAAA,EAAAA,MAAAA;;UAxI/BA,iBAAAA,CA0IKF;QAF8CiB,MAAAA;UAIFd,CAAAA,EAAAA,MAAAA;WAA4BJ,CAAAA,EAAAA,MAAAA;;WAC3CC,CAAAA,EAAAA,OAAAA;iBAARiB,CAAAA,EAvIhBtB,eAuIgBsB;;UArI1Bd,iBAAAA,CAsIkFH;OAARiB,EAAAA,MAAAA;WAEpBb,CAAAA,EAAAA,MAAAA,GAAAA,IAAAA;;WAEIC,CAAAA,EAAAA,OAAAA;;;;;;;UA/H1DD,gBAAAA,CAoJJa;QAM+EV,MAAAA;UAARU,EAAAA,MAAAA;;WAMYA,EAAAA,OAAAA;;;;;UAvJ/EZ,oBAAAA,CA2J2EY;QAENA,MAAAA;UAEXP,EAAAA,MAAAA;;WAQtDA,EAAAA,MAAAA;;;;;;UA7JJJ,gBAAAA,CAyKkDW;;WAIHA,EAAAA,MAAAA;EAAO;;;;;;;;;;;;UA9JtDV,mBAAAA;;;;;;;;UAQAC,kBAAAA;;eAEKd;;;;;UAKLe,iBAAAA;;gBAEMf;;;;;;UAMNgB,oBAAAA;;;;;;;;;;;;;;;;;UAiBAC,mBAAAA;UACAC;WACCf;aACED;eACEiB;;;;;UAKLC,8BAAAA;;;;;;;;;;UAUAC,qBAAAA;;;;;;;;;;;;;UAaAC,OAAAA;;;MAGJC,QAAQnB;iCACmBmB,QAAQnB;uBAClBG,qBAAqBgB,QAAQnB;;;8BAGtBH;MACxBsB,QAAQnB;mCACqBmB,QAAQlB;yCACFG,oBAAoBe;YACjDlB;eACGC;;2DAE4CG,oBAAoBc,QAAQlB;oCACnDkB,QAAQjB;kEACsBL,kBAAkBsB,QAAQjB;;wDAEpCiB,QAAQb;;4DAEJa,QAAQZ;;;;;6CAKvBU,wBAAwBE;;;;;;;;oDAQjBA,QAAQX;;;;;;;;MAQtDW,QAAQX;;;;;;6EAM+DW,QAAQV;;;;;;yFAMIU,QAAQV;;0DAEvCU,QAAQT;;iEAEDC,oBAAoBQ,QAAQT;;+EAEdS;;4DAEnBA,QAAQP;;;;;;;;MAQ9DO,QAAQP;;2EAE6DO;;;;;iFAKMN,sBAAsBM,QAAQH;;;;;4DAKnDG;;wDAEJA;;yDAECA"}
|
|
1
|
+
{"version":3,"file":"neon-api.d.ts","names":["BucketAccessLevel","ComputeSettings","FunctionRuntime","NeonProjectSnapshot","NeonBranchSnapshot","NeonEndpointSnapshot","CreateProjectInput","CreateBranchInput","UpdateBranchInput","NeonRoleSnapshot","NeonDatabaseSnapshot","NeonAuthSnapshot","NeonDataApiSnapshot","NeonBucketSnapshot","CreateBucketInput","NeonFunctionSnapshot","DeployFunctionInput","Uint8Array","Record","NeonFunctionDeploymentSnapshot","GetConnectionUriInput","NeonApi","Promise"],"sources":["../../../../../config/dist/lib/neon-api.d.ts"],"sourcesContent":["import { BucketAccessLevel, ComputeSettings, 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 * 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 * 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 /** List functions on a branch. */\n listBranchFunctions(projectId: string, branchId: string): Promise<NeonFunctionSnapshot[]>;\n /**\n * Create a function on a branch. The function has no deployment until code is deployed\n * to it with {@link deployBranchFunction}.\n */\n createBranchFunction(projectId: string, branchId: string, input: {\n slug: string;\n name: string;\n }): 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. The newest deployment becomes active. The\n * `bundle` is built (esbuild + zip) by the caller and passed in as bytes.\n */\n deployBranchFunction(projectId: string, branchId: string, slug: string, input: DeployFunctionInput): Promise<NeonFunctionDeploymentSnapshot>;\n /**\n * Whether the AI Gateway is enabled on a branch. Toggle-style, like Neon Auth / Data\n * API: used by both `fetchEnv` (to decide visibility) and `pushConfig` (to diff intent).\n */\n getAiGatewayEnabled(projectId: string, branchId: string): Promise<boolean>;\n /** Enable the AI Gateway on a branch. Idempotent. */\n enableAiGateway(projectId: string, branchId: string): Promise<void>;\n /** Disable the AI Gateway on a branch. Idempotent. */\n disableAiGateway(projectId: string, branchId: string): Promise<void>;\n}\n//#endregion\nexport { CreateBranchInput, CreateBucketInput, CreateProjectInput, DeployFunctionInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBucketSnapshot, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, UpdateBranchInput };\n//# sourceMappingURL=neon-api.d.ts.map"],"mappings":";;;;;AAe2C;AAEf;;;;UARlBG,mBAAAA,CAuBQF;EAAe,EAAA,EAAA,MAAA;EAAA,IAEvBK,EAAAA,MAAAA;EAKiC,QAOjCC,EAAAA,MAAAA;EAMyB,SAEzBC,EAAAA,MAAAA;EAAiB,KAWjBC,CAAAA,EAAAA,MAAAA;EAAgB,uBAShBC,CAAAA,EA3DkBT,eA2DE;AAAA;AAUJ,UAnEhBG,kBAAAA,CAkFmB;EAAA,EAQnBS,EAAAA,MAAAA;EAEsB,IAKtBC,EAAAA,MAAAA;EAEuB,QAMvBC,CAAAA,EAAAA,MAAAA;EAAoB,SAiBpBC,EAAAA,OAAAA;EAAmB;WACnBC,EAAAA,OAAAA;WACCf,CAAAA,EAAAA,MAAAA;;AACU,UApHXG,oBAAAA,CAoHW;EAAA,EAKXc,EAAAA,MAAAA;EAA8B,QAU9BC,EAAAA,MAAAA;EAAqB,IAarBC,EAAAA,WAAO,GAAA,YAAA;EAAA,qBAAA,EA5IQpB,eA4IR,CAAA,uBAAA,CAAA;uBAGHE,EA9IWF,eA8IXE,CAAAA,uBAAAA,CAAAA;gBAARmB,EA7IYrB,eA6IZqB,CAAAA,gBAAAA,CAAAA;;UA3IIhB,kBAAAA,CA4IuBgB;QACVhB,MAAAA;UAA6BH,EAAAA,MAAAA;WAARmB,CAAAA,EAAAA,MAAAA;OAGdrB,CAAAA,EAAAA,MAAAA;yBAChBE,CAAAA,EA5IcF,eA4IdE;;;;;mBAGFC,CAAAA,EAAAA,MAAAA;;UAxIFG,iBAAAA,CAuImDe;QAIFd,MAAAA;UAA4BJ,CAAAA,EAAAA,MAAAA;WAARkB,CAAAA,EAAAA,MAAAA;;WAC3CA,CAAAA,EAAAA,OAAAA;iBAC8BrB,CAAAA,EAvI9CA,eAuI8CA;;UArIxDO,iBAAAA,CAqI0Ec;OAEpBb,EAAAA,MAAAA;WAARa,CAAAA,EAAAA,MAAAA,GAAAA,IAAAA;;WAEIA,CAAAA,EAAAA,OAAAA;;;;;;;UA9HlDb,gBAAAA,CAyJ2EG;QAARU,MAAAA;UAMoBV,EAAAA,MAAAA;;WAE/BC,EAAAA,OAAAA;;;;;UAxJxDH,oBAAAA,CA4JqEY;QAEXP,MAAAA;UAARO,EAAAA,MAAAA;;WAQtDA,EAAAA,MAAAA;;;;;;UA5JIX,gBAAAA,CA0K8CW;;EAEQ,SAAA,EAAA,MAAA;;;;;;;;;;;;;UA7JtDV,mBAAAA;;;;;;;;UAQAC,kBAAAA;;eAEKb;;;;;UAKLc,iBAAAA;;gBAEMd;;;;;;UAMNe,oBAAAA;;;;;;;;;;;;;;;;;UAiBAC,mBAAAA;UACAC;WACCf;eACIgB;;;;;UAKLC,8BAAAA;;;;;;;;;;UAUAC,qBAAAA;;;;;;;;;;;;;UAaAC,OAAAA;;;MAGJC,QAAQnB;iCACmBmB,QAAQnB;uBAClBG,qBAAqBgB,QAAQnB;;;8BAGtBF;MACxBqB,QAAQnB;mCACqBmB,QAAQlB;yCACFG,oBAAoBe;YACjDlB;eACGC;;2DAE4CG,oBAAoBc,QAAQlB;oCACnDkB,QAAQjB;kEACsBJ,kBAAkBqB,QAAQjB;;wDAEpCiB,QAAQb;;4DAEJa,QAAQZ;;;;;6CAKvBU,wBAAwBE;;;;;;;;oDAQjBA,QAAQX;;;;;;;;MAQtDW,QAAQX;;;;;;6EAM+DW,QAAQV;;;;;;yFAMIU,QAAQV;;0DAEvCU,QAAQT;;iEAEDC,oBAAoBQ,QAAQT;;+EAEdS;;4DAEnBA,QAAQP;;;;;;;;MAQ9DO,QAAQP;;2EAE6DO;;;;;iFAKMN,sBAAsBM,QAAQH;;;;;4DAKnDG;;wDAEJA;;yDAECA"}
|
|
@@ -62,10 +62,26 @@ interface BranchTarget {
|
|
|
62
62
|
/** Current expiration timestamp from Neon, when set. */
|
|
63
63
|
expiresAt?: string;
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Object form of a branch-scoped service toggle. `{}` or `{ enabled: true }` enables it;
|
|
67
|
+
* `{ enabled: false }` opts out. Used as the object half of {@link ServiceToggleInput}.
|
|
68
|
+
*/
|
|
65
69
|
interface ServiceToggle {
|
|
66
70
|
/** Defaults to `true` when the service namespace is present. Set `false` to opt out. */
|
|
67
71
|
enabled?: boolean;
|
|
68
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* How a branch-scoped service (Neon Auth, Data API, AI Gateway) is toggled in a policy.
|
|
75
|
+
*
|
|
76
|
+
* - `true` / `{}` / `{ enabled: true }` — enabled.
|
|
77
|
+
* - `false` / `{ enabled: false }` — disabled.
|
|
78
|
+
* - omitted (`undefined`) — not part of the policy at all.
|
|
79
|
+
*
|
|
80
|
+
* These toggles are **static** (they live in the top-level `defineConfig({ … })` object,
|
|
81
|
+
* not in the per-branch `branch` closure) so the secret set they imply can be derived at
|
|
82
|
+
* the type level — that's what makes `NeonEnv<typeof config>` exact.
|
|
83
|
+
*/
|
|
84
|
+
type ServiceToggleInput = boolean | ServiceToggle;
|
|
69
85
|
interface PostgresConfig {
|
|
70
86
|
computeSettings?: ComputeSettings;
|
|
71
87
|
}
|
|
@@ -75,11 +91,6 @@ interface PostgresConfig {
|
|
|
75
91
|
* non-breaking, type-checked change.
|
|
76
92
|
*/
|
|
77
93
|
type FunctionRuntime = "nodejs24";
|
|
78
|
-
/**
|
|
79
|
-
* Memory sizes (MiB) accepted by the Neon Functions deploy API. Mirrors the
|
|
80
|
-
* `memory_mib` enum in the spec.
|
|
81
|
-
*/
|
|
82
|
-
type FunctionMemoryMib = 256 | 512 | 1024 | 2048 | 4096 | 8192;
|
|
83
94
|
/**
|
|
84
95
|
* Local-development settings for a function, used by `neon dev` when it serves every
|
|
85
96
|
* function declared in `neon.ts` (i.e. invoked with no `--source`). Never affects deploy.
|
|
@@ -105,20 +116,21 @@ interface FunctionDevConfig {
|
|
|
105
116
|
portless?: boolean;
|
|
106
117
|
}
|
|
107
118
|
/**
|
|
108
|
-
*
|
|
119
|
+
* Static definition of a Neon Function (Preview feature). Declares that the function
|
|
120
|
+
* **exists** on every branch; its branch-unique slug is the **record key** in
|
|
121
|
+
* {@link PreviewInput.functions} (not a field here), so slugs are statically enumerable,
|
|
122
|
+
* cannot duplicate, and the `branch` closure can only tune slugs that are declared here.
|
|
109
123
|
*
|
|
110
124
|
* A function is invoked like a Cloudflare/Vercel handler — its source module
|
|
111
125
|
* `export default { fetch }` or `export async function handler(req): Response`. The
|
|
112
|
-
* `source` path is bundled (esbuild) and uploaded as a deployment; the newest
|
|
113
|
-
*
|
|
126
|
+
* `source` path is bundled (esbuild) and uploaded as a deployment; the newest deployment
|
|
127
|
+
* becomes active.
|
|
128
|
+
*
|
|
129
|
+
* Runtime tuning is **not** here — it varies per branch and lives in the `branch` closure
|
|
130
|
+
* (see {@link FunctionTuning}). Memory is fixed by the platform policy for now and is not
|
|
131
|
+
* user-configurable.
|
|
114
132
|
*/
|
|
115
|
-
interface
|
|
116
|
-
/**
|
|
117
|
-
* Branch-unique slug used as the path segment in the function's invocation URL.
|
|
118
|
-
* Immutable once created. 1–20 lowercase letters and digits: `^[a-z0-9]{1,20}$`.
|
|
119
|
-
* @example "hellofn"
|
|
120
|
-
*/
|
|
121
|
-
slug: string;
|
|
133
|
+
interface FunctionDef {
|
|
122
134
|
/** Free-form display name. @example "Hello World" */
|
|
123
135
|
name: string;
|
|
124
136
|
/**
|
|
@@ -133,16 +145,16 @@ interface FunctionConfig {
|
|
|
133
145
|
*/
|
|
134
146
|
source: string;
|
|
135
147
|
/**
|
|
136
|
-
* Environment variables injected into the deployed function
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
148
|
+
* Environment variables injected into the deployed function, keyed by the var name the
|
|
149
|
+
* function reads at runtime. The **keys** are static (preserved at the type level so
|
|
150
|
+
* `parseEnv(config, "<slug>").function.<key>` is typed); the **values** are arbitrary
|
|
151
|
+
* strings evaluated when `neon.ts` is loaded (typically `process.env.X`) and uploaded
|
|
152
|
+
* at `config apply`. Every value must be a defined string — a `process.env.X` that is
|
|
153
|
+
* `undefined` (unset) errors at validation time rather than silently shipping
|
|
154
|
+
* `undefined`.
|
|
155
|
+
* @example { resendApiKey: process.env.RESEND_API_KEY ?? "" }
|
|
140
156
|
*/
|
|
141
157
|
env?: Record<string, string>;
|
|
142
|
-
/** Runtime to execute the function with. Defaults to `"nodejs24"`. */
|
|
143
|
-
runtime?: FunctionRuntime;
|
|
144
|
-
/** Memory allotted to each invocation, in MiB. Defaults to `512`. */
|
|
145
|
-
memoryMib?: FunctionMemoryMib;
|
|
146
158
|
/**
|
|
147
159
|
* Local-development settings used by `neon dev` when serving every function from
|
|
148
160
|
* `neon.ts`. Ignored at deploy time. See {@link FunctionDevConfig}.
|
|
@@ -152,11 +164,11 @@ interface FunctionConfig {
|
|
|
152
164
|
/** Anonymous-access level for a branchable object-storage bucket. */
|
|
153
165
|
type BucketAccessLevel = "private" | "public_read";
|
|
154
166
|
/**
|
|
155
|
-
*
|
|
167
|
+
* Static definition of a branchable object-storage bucket (Preview feature). The bucket's
|
|
168
|
+
* name is the **record key** in {@link PreviewInput.buckets}, so names are statically
|
|
169
|
+
* enumerable and cannot duplicate.
|
|
156
170
|
*/
|
|
157
|
-
interface
|
|
158
|
-
/** Bucket name, unique within a branch. 1–255 chars. */
|
|
159
|
-
name: string;
|
|
171
|
+
interface BucketDef {
|
|
160
172
|
/**
|
|
161
173
|
* Anonymous access level. `private` (default) requires authenticated reads/writes;
|
|
162
174
|
* `public_read` allows anonymous GetObject/HeadObject.
|
|
@@ -164,18 +176,44 @@ interface BucketConfig {
|
|
|
164
176
|
access?: BucketAccessLevel;
|
|
165
177
|
}
|
|
166
178
|
/**
|
|
167
|
-
*
|
|
168
|
-
* Neon `x-stability-level: beta` endpoints and may change before GA.
|
|
179
|
+
* Static, branch-scoped **Preview** features. Grouped under `preview` to signal they are
|
|
180
|
+
* backed by Neon `x-stability-level: beta` endpoints and may change before GA. Everything
|
|
181
|
+
* here is existential (it determines what exists on the branch); per-branch tuning lives in
|
|
182
|
+
* the `branch` closure.
|
|
169
183
|
*/
|
|
170
|
-
interface
|
|
171
|
-
/** Functions to deploy on the branch. */
|
|
172
|
-
functions?: FunctionConfig[];
|
|
173
|
-
/** Object-storage buckets to create on the branch. */
|
|
174
|
-
buckets?: BucketConfig[];
|
|
184
|
+
interface PreviewInput {
|
|
175
185
|
/** Enable/disable the AI Gateway on the branch (toggle, like auth / dataApi). */
|
|
176
|
-
aiGateway?:
|
|
186
|
+
aiGateway?: ServiceToggleInput;
|
|
187
|
+
/** Functions to deploy, keyed by branch-unique slug (`^[a-z0-9]{1,20}$`). */
|
|
188
|
+
functions?: Record<string, FunctionDef>;
|
|
189
|
+
/** Object-storage buckets to create, keyed by bucket name. */
|
|
190
|
+
buckets?: Record<string, BucketDef>;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Per-branch deploy tuning for a single function. Returned (per slug) by the `branch`
|
|
194
|
+
* closure. Deliberately **cannot** change the function's existence, source, name, env
|
|
195
|
+
* **keys**, or memory — only runtime selection is currently configurable — so the static
|
|
196
|
+
* secret/function set stays sound.
|
|
197
|
+
*/
|
|
198
|
+
interface FunctionTuning {
|
|
199
|
+
/** Runtime to execute the function with. Defaults to `"nodejs24"`. */
|
|
200
|
+
runtime?: FunctionRuntime;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Per-branch tuning of Preview features. Only existing function slugs (those declared in
|
|
204
|
+
* the static {@link PreviewInput.functions}) may be tuned — `Slug` is constrained to the
|
|
205
|
+
* declared keys by {@link BranchTuningFn}.
|
|
206
|
+
*/
|
|
207
|
+
interface PreviewTuning<Slug extends string = string> {
|
|
208
|
+
functions?: Partial<Record<Slug, FunctionTuning>>;
|
|
177
209
|
}
|
|
178
|
-
|
|
210
|
+
/**
|
|
211
|
+
* The per-branch tuning object returned by the `branch` closure. It can adjust branch
|
|
212
|
+
* lifecycle (`parent`, `ttl`, `protected`), Postgres compute settings, and per-function
|
|
213
|
+
* deploy tuning — but **cannot** add/remove services or functions. That guarantee is what
|
|
214
|
+
* keeps the static secret set (and therefore `NeonEnv`) exact.
|
|
215
|
+
*/
|
|
216
|
+
interface BranchTuning<Slug extends string = string> {
|
|
179
217
|
/** Parent branch name used when creating a new branch. Not a Postgres setting. */
|
|
180
218
|
parent?: string;
|
|
181
219
|
/** Time-to-live applied when creating a new branch, or reconciled on existing branches. */
|
|
@@ -183,31 +221,44 @@ interface BranchConfigBase {
|
|
|
183
221
|
/** Whether the selected branch should be protected. Undefined means "leave as-is". */
|
|
184
222
|
protected?: boolean;
|
|
185
223
|
postgres?: PostgresConfig;
|
|
186
|
-
|
|
187
|
-
* Branch-scoped Preview features (functions, object-storage buckets, AI Gateway).
|
|
188
|
-
* Backed by Neon `x-stability-level: beta` endpoints — see {@link PreviewConfig}.
|
|
189
|
-
*/
|
|
190
|
-
preview?: PreviewConfig;
|
|
224
|
+
preview?: PreviewTuning<Slug>;
|
|
191
225
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
*
|
|
209
|
-
*
|
|
226
|
+
/** Extract the declared function slugs from a {@link PreviewInput} for closure typing. */
|
|
227
|
+
type FunctionSlugsOf<Preview extends PreviewInput | undefined> = Preview extends {
|
|
228
|
+
functions: infer F;
|
|
229
|
+
} ? Extract<keyof F, string> : string;
|
|
230
|
+
/**
|
|
231
|
+
* Signature of the `branch` closure. Generic over the static {@link PreviewInput} so the
|
|
232
|
+
* `preview.functions` keys it may tune are constrained to the slugs actually declared.
|
|
233
|
+
*/
|
|
234
|
+
type BranchTuningFn<Preview extends PreviewInput | undefined = PreviewInput | undefined> = (branch: BranchTarget) => BranchTuning<FunctionSlugsOf<Preview>>;
|
|
235
|
+
/**
|
|
236
|
+
* A validated Neon branch policy — the value `defineConfig({ … })` returns and `neon.ts`
|
|
237
|
+
* default-exports.
|
|
238
|
+
*
|
|
239
|
+
* Split into a **static** existential set (top-level `auth` / `dataApi` GA toggles plus the
|
|
240
|
+
* beta `preview` block) and a **dynamic** per-branch `branch` closure for tuning. The
|
|
241
|
+
* static half is what makes the secret set — and therefore `NeonEnv<typeof config>` and
|
|
242
|
+
* `parseEnv` — exact; the closure can tune but never change what exists.
|
|
243
|
+
*
|
|
244
|
+
* Generic over the three static fields so the type system can read the exact toggle/slug
|
|
245
|
+
* literals; the defaults make the bare `Config` a usable "any policy" type for runtime
|
|
246
|
+
* function signatures.
|
|
247
|
+
*/
|
|
248
|
+
interface Config<Auth extends ServiceToggleInput | undefined = ServiceToggleInput | undefined, DataApi extends ServiceToggleInput | undefined = ServiceToggleInput | undefined, Preview extends PreviewInput | undefined = PreviewInput | undefined> {
|
|
249
|
+
/** Neon Auth integration toggle (GA). Static — drives `NeonEnv.auth`. */
|
|
250
|
+
auth?: Auth;
|
|
251
|
+
/** Neon Data API integration toggle (GA). Static — drives `NeonEnv.dataApi`. */
|
|
252
|
+
dataApi?: DataApi;
|
|
253
|
+
/** Beta (Preview) feature set: AI Gateway, functions, buckets. Static. */
|
|
254
|
+
preview?: Preview;
|
|
255
|
+
/** Per-branch tuning closure. Cannot change the static existential set. */
|
|
256
|
+
branch?: BranchTuningFn<Preview>;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* A function with all deploy defaults applied. `resolveConfig` fills in `runtime` so
|
|
260
|
+
* downstream diff/apply never has to re-derive it.
|
|
210
261
|
*/
|
|
211
262
|
//#endregion
|
|
212
|
-
export {
|
|
263
|
+
export { BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, Config, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, ServiceToggle, ServiceToggleInput };
|
|
213
264
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":["ComputeUnit","ComputeSettings","BranchTarget","ServiceToggle","PostgresConfig","FunctionRuntime","FunctionMemoryMib","FunctionDevConfig","FunctionConfig","Record","BucketAccessLevel","BucketConfig","PreviewConfig","BranchConfigBase","BranchServiceConfig","BranchConfig","Config","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/**\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 to wait before suspending an idle compute.\n *\n * - `false` — never suspend (always-on compute)\n * - `\"5m\"` — duration string (supports \"30s\", \"5m\", \"1h\", \"7d\", etc)\n * - `300` — custom timeout in seconds (60-604800)\n * - `undefined` — use Neon platform default (currently 300s / 5 minutes)\n *\n * @example false // never suspend\n * @example \"5m\" // 5 minutes\n * @example \"1h\" // 1 hour\n * @example 300 // 5 minutes in seconds\n */\n suspendTimeout?: false | \"5m\" | \"1h\" | string | number;\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}\ninterface ServiceToggle {\n /** Defaults to `true` when the service namespace is present. Set `false` to opt out. */\n enabled?: boolean;\n}\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 * Memory sizes (MiB) accepted by the Neon Functions deploy API. Mirrors the\n * `memory_mib` enum in the spec.\n */\ntype FunctionMemoryMib = 256 | 512 | 1024 | 2048 | 4096 | 8192;\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 *\n * `port` and `portless` are independent:\n *\n * - `portless: true` — wrap this function's local server with `portless <slug> …` so it gets\n * a stable `slug.localhost` URL. Portless assigns the port itself (it injects `PORT`), so\n * `port` is ignored in this mode.\n * - otherwise — serve directly. `port`, when set, is bound exactly (and `neon dev` fails\n * loudly if it is taken); when omitted a free port is found automatically.\n */\ninterface FunctionDevConfig {\n /**\n * Port the local server binds. Bound exactly (fails if taken) when set; a free port is\n * found when omitted. Ignored when `portless` is true (portless assigns the port).\n */\n port?: number;\n /**\n * Expose this function via `portless` (a stable `slug.localhost` URL). Requires the\n * `portless` binary on PATH. Portless assigns the port, so `port` is ignored here.\n */\n portless?: boolean;\n}\n/**\n * A single Neon Function deployed to a branch (Preview feature).\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\n * deployment becomes active.\n */\ninterface FunctionConfig {\n /**\n * Branch-unique slug used as the path segment in the function's invocation URL.\n * Immutable once created. 1–20 lowercase letters and digits: `^[a-z0-9]{1,20}$`.\n * @example \"hellofn\"\n */\n slug: string;\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. Every value must be a\n * defined string — a `process.env.X` that is `undefined` (unset) errors at validation\n * time rather than silently shipping `undefined`.\n * @example { RESEND_API_KEY: process.env.RESEND_API_KEY }\n */\n env?: Record<string, string>;\n /** Runtime to execute the function with. Defaults to `\"nodejs24\"`. */\n runtime?: FunctionRuntime;\n /** Memory allotted to each invocation, in MiB. Defaults to `512`. */\n memoryMib?: FunctionMemoryMib;\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/** Anonymous-access level for a branchable object-storage bucket. */\ntype BucketAccessLevel = \"private\" | \"public_read\";\n/**\n * A branchable object-storage bucket on a branch (Preview feature).\n */\ninterface BucketConfig {\n /** Bucket name, unique within a branch. 1–255 chars. */\n name: string;\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 * Branch-scoped Preview features. Grouped under `preview` to signal they are backed by\n * Neon `x-stability-level: beta` endpoints and may change before GA.\n */\ninterface PreviewConfig {\n /** Functions to deploy on the branch. */\n functions?: FunctionConfig[];\n /** Object-storage buckets to create on the branch. */\n buckets?: BucketConfig[];\n /** Enable/disable the AI Gateway on the branch (toggle, like auth / dataApi). */\n aiGateway?: ServiceToggle;\n}\ninterface BranchConfigBase {\n /** Parent branch name used when creating a new branch. Not a Postgres setting. */\n parent?: string;\n /** Time-to-live applied when creating a new branch, or reconciled on existing branches. */\n ttl?: string | number;\n /** Whether the selected branch should be protected. Undefined means \"leave as-is\". */\n protected?: boolean;\n postgres?: PostgresConfig;\n /**\n * Branch-scoped Preview features (functions, object-storage buckets, AI Gateway).\n * Backed by Neon `x-stability-level: beta` endpoints — see {@link PreviewConfig}.\n */\n preview?: PreviewConfig;\n}\ntype BranchServiceConfig = {\n auth?: never;\n dataApi?: never;\n} | {\n auth: ServiceToggle;\n dataApi?: never;\n} | {\n auth?: never;\n dataApi: ServiceToggle;\n} | {\n auth: ServiceToggle;\n dataApi: ServiceToggle;\n};\ntype BranchConfig = BranchConfigBase & BranchServiceConfig;\ntype Config = (branch: BranchTarget) => BranchConfig;\n/**\n * A function with all deploy defaults applied. `resolveConfig` fills in `runtime` and\n * `memoryMib` so downstream diff/apply never has to re-derive them.\n */\ninterface ResolvedFunctionConfig {\n slug: string;\n name: string;\n source: string;\n env: Record<string, string>;\n runtime: FunctionRuntime;\n memoryMib: FunctionMemoryMib;\n /**\n * Local-development settings, passed through untouched from {@link FunctionConfig.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 PreviewConfig}. 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, BranchConfig, BranchTarget, BucketAccessLevel, BucketConfig, ComputeSettings, ComputeUnit, Config, ConflictReport, FunctionConfig, FunctionDevConfig, FunctionMemoryMib, FunctionRuntime, PostgresConfig, PreviewConfig, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceToggle };\n//# sourceMappingURL=types.d.ts.map"],"mappings":";;;AAKgB;;;KAAXA,WAAAA,GAoBqBA,IAAAA,GAAAA,GAAAA,GAAAA,CAAAA,GAAAA,CAAAA,GAAAA,CAAAA,GAAAA,CAAAA;AAAW;AAAA;AAsBf;AAgBC;AAKY;AAOf;AAKE;AAaK,UAhFjBC,eAAAA,CAoGc;EAAA;;;;;EAmCC,qBAAA,CAAA,EAjICD,WAiID;EAAA;AAGH;AAWM;;;uBAUhBW,CAAAA,EAnJcX,WAmJdW;;AAEe;AAAA;;;;AAcF;AAAA;;;;;;EAaD,cAAA,CAAA,EAAA,KAAA,GAAA,IAAA,GAAA,IAAA,GAAA,MAAA,GAAA,MAAA;AAAA;;;;AAEkC;AAAA;;UA5JhDT,YAAAA,CA6JaA;;EAA6B,IAAA,EAAA,MAAA;;;;;;;;;;;;;;UA7I1CC,aAAAA;;;;UAIAC,cAAAA;oBACUH;;;;;;;KAOfI,eAAAA;;;;;KAKAC,iBAAAA;;;;;;;;;;;;;UAaKC,iBAAAA;;;;;;;;;;;;;;;;;;;;UAoBAC,cAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;QA0BFC;;YAEIJ;;cAEEC;;;;;QAKNC;;;KAGHG,iBAAAA;;;;UAIKC,YAAAA;;;;;;;WAOCD;;;;;;UAMDE,aAAAA;;cAEIJ;;YAEFG;;cAEER;;UAEJU,gBAAAA;;;;;;;aAOGT;;;;;YAKDQ;;KAEPE,mBAAAA;;;;QAIGX;;;;WAIGA;;QAEHA;WACGA;;KAENY,YAAAA,GAAeF,mBAAmBC;KAClCE,MAAAA,YAAkBd,iBAAiBa"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":["ComputeUnit","ComputeSettings","BranchTarget","ServiceToggle","ServiceToggleInput","PostgresConfig","FunctionRuntime","FunctionDevConfig","FunctionDef","Record","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/**\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 to wait before suspending an idle compute.\n *\n * - `false` — never suspend (always-on compute)\n * - `\"5m\"` — duration string (supports \"30s\", \"5m\", \"1h\", \"7d\", etc)\n * - `300` — custom timeout in seconds (60-604800)\n * - `undefined` — use Neon platform default (currently 300s / 5 minutes)\n *\n * @example false // never suspend\n * @example \"5m\" // 5 minutes\n * @example \"1h\" // 1 hour\n * @example 300 // 5 minutes in seconds\n */\n suspendTimeout?: false | \"5m\" | \"1h\" | string | number;\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 *\n * `port` and `portless` are independent:\n *\n * - `portless: true` — wrap this function's local server with `portless <slug> …` so it gets\n * a stable `slug.localhost` URL. Portless assigns the port itself (it injects `PORT`), so\n * `port` is ignored in this mode.\n * - otherwise — serve directly. `port`, when set, is bound exactly (and `neon dev` fails\n * loudly if it is taken); when omitted a free port is found automatically.\n */\ninterface FunctionDevConfig {\n /**\n * Port the local server binds. Bound exactly (fails if taken) when set; a free port is\n * found when omitted. Ignored when `portless` is true (portless assigns the port).\n */\n port?: number;\n /**\n * Expose this function via `portless` (a stable `slug.localhost` URL). Requires the\n * `portless` binary on PATH. Portless assigns the port, so `port` is ignored here.\n */\n portless?: boolean;\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/** 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 /** Time-to-live applied when creating a new branch, or reconciled on existing branches. */\n ttl?: string | number;\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, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceToggle, ServiceToggleInput };\n//# sourceMappingURL=types.d.ts.map"],"mappings":";;;AAKgB;;;KAAXA,WAAAA,GAoBqBA,IAAAA,GAAAA,GAAAA,GAAAA,CAAAA,GAAAA,CAAAA,GAAAA,CAAAA,GAAAA,CAAAA;AAAW;AAAA;AAsBf;AAoBC;AAe0B;AAEd;AAOf;AAaO,UA3FjBC,eAAAA,CAsHW;EAAA;;;AA6BI;AAAA;EAGH,qBAMH,CAAA,EAtJOD,WA2JfU;EAAiB;;;;;uBAcDC,CAAAA,EAnKDX,WAmKCW;;AAAT;AAAA;AAUS;;;;;;AAQN;AAAA;;;gBAgBKI,CAAAA,EAAAA,KAAAA,GAAAA,IAAAA,GAAAA,IAAAA,GAAAA,MAAAA,GAAAA,MAAAA;;AAAD;AAAA;;;;;UA/Kfb,YAAAA,CAoLNmB;EAAO;EAAA,IAKNC,EAAAA,MAAAA;EAAc;OAAiBV,MAAAA;;QAAgEV,EAAAA,OAAAA;;UAA8BgB,CAAAA,EAAAA,MAAAA;;EAAD,SAAA,CAAA,EAAA,OAAA;EAAA;EAcjH,WAAA,CAAA,EAAA,OAAA;;WAA+Cd,CAAAA,EAAAA,MAAAA;;;;;;UAnLrDD,aAAAA,CAuLEsB;;SAIcN,CAAAA,EAAAA,OAAAA;;AAAD;;;;;;;;;;;KA5KpBf,kBAAAA,aAA+BD;UAC1BE,cAAAA;oBACUJ;;;;;;;KAOfK,eAAAA;;;;;;;;;;;;;UAaKC,iBAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;UA2BAC,WAAAA;;;;;;;;;;;;;;;;;;;;;;;;QAwBFC;;;;;QAKAF;;;KAGHG,iBAAAA;;;;;;UAMKC,SAAAA;;;;;WAKCD;;;;;;;;UAQDE,YAAAA;;cAEIR;;cAEAK,eAAeD;;YAEjBC,eAAeE;;;;;;;;UAQjBE,cAAAA;;YAEEP;;;;;;;UAOFQ;cACIE,QAAQP,OAAOM,MAAMF;;;;;;;;UAQzBI;;;;;;;aAOGZ;YACDS,cAAcC;;;KAGrBG,gCAAgCN,4BAA4BO;;IAE7DE,cAAcD;;;;;KAKbE,+BAA+BV,2BAA2BA,qCAAqCV,iBAAiBe,aAAaC,gBAAgBC;;;;;;;;;;;;;;UAcxII,oBAAoBnB,iCAAiCA,gDAAgDA,iCAAiCA,gDAAgDQ,2BAA2BA;;SAElNY;;YAEGC;;YAEAN;;WAEDG,eAAeH"}
|
package/dist/config/dist/v1.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, Config, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, ServiceToggle, ServiceToggleInput } from "./lib/types.js";
|
|
2
2
|
import { CreateBranchInput, CreateBucketInput, CreateProjectInput, DeployFunctionInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBucketSnapshot, 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, NEON_ENV_VAR_KEYS, NeonAuthEnv, NeonDataApiEnv, NeonEnv, NeonPostgresEnv, fetchEnv, parseEnv, toEntries } from "./lib/env.js";
|
|
2
|
-
export { FetchEnvOptions, NEON_ENV_VAR_KEYS, NeonAuthEnv, NeonDataApiEnv, NeonEnv, NeonPostgresEnv, fetchEnv, parseEnv, toEntries };
|
|
1
|
+
import { FetchEnvOptions, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAuthEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, fetchEnv, parseEnv, toEntries } from "./lib/env.js";
|
|
2
|
+
export { FetchEnvOptions, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAuthEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, fetchEnv, parseEnv, toEntries };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-context.d.ts","names":[],"sources":["../../../src/lib/cli/resolve-context.ts"],"mappings":";;AASA;
|
|
1
|
+
{"version":3,"file":"resolve-context.d.ts","names":[],"sources":["../../../src/lib/cli/resolve-context.ts"],"mappings":";;AASA;AAKA;AAcA;;AACU,UApBO,eAAA,CAoBP;WACc,EAAA,MAAA;EAAe,QAAA,EAAA,MAAA;;UAhBtB,qBAAA;;;;QAIV,MAAA,CAAO;;;;;;;;;iBAUE,cAAA,UACN;;WACc"}
|
|
@@ -14,7 +14,6 @@ function resolveContext(options) {
|
|
|
14
14
|
const file = findNeonFile(options.cwd);
|
|
15
15
|
const projectId = nonEmpty(options.projectId) ?? nonEmpty(env.NEON_PROJECT_ID) ?? file?.projectId;
|
|
16
16
|
const branchId = nonEmpty(options.branch) ?? nonEmpty(env.NEON_BRANCH_ID) ?? file?.branchId;
|
|
17
|
-
const branchName = nonEmpty(env.NEON_BRANCH_NAME) ?? file?.branchName;
|
|
18
17
|
const missing = [];
|
|
19
18
|
if (!projectId) missing.push("project id — pass `--project-id`, set `NEON_PROJECT_ID`, or add `projectId` to `.neon/project.json` (run `npx neonctl link`).");
|
|
20
19
|
if (!branchId) missing.push("branch — pass `--branch`, set `NEON_BRANCH_ID`, or add `branchId` to `.neon/project.json` (run `npx neonctl checkout <branch>`).");
|
|
@@ -26,8 +25,7 @@ function resolveContext(options) {
|
|
|
26
25
|
ok: true,
|
|
27
26
|
context: {
|
|
28
27
|
projectId,
|
|
29
|
-
branchId
|
|
30
|
-
...branchName ? { branchName } : {}
|
|
28
|
+
branchId
|
|
31
29
|
}
|
|
32
30
|
};
|
|
33
31
|
}
|
|
@@ -69,7 +67,6 @@ function readNeonFileAt(path) {
|
|
|
69
67
|
const out = {};
|
|
70
68
|
if (typeof obj.projectId === "string" && obj.projectId !== "") out.projectId = obj.projectId;
|
|
71
69
|
if (typeof obj.branchId === "string" && obj.branchId !== "") out.branchId = obj.branchId;
|
|
72
|
-
if (typeof obj.branchName === "string" && obj.branchName !== "") out.branchName = obj.branchName;
|
|
73
70
|
return out;
|
|
74
71
|
}
|
|
75
72
|
function isFile(path) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-context.js","names":[],"sources":["../../../src/lib/cli/resolve-context.ts"],"sourcesContent":["import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, resolve } from \"node:path\";\n\n/**\n * Resolved project + branch context for the `neon-env` CLI. The CLI owns this resolution\n * (flags → `NEON_*` env → `.neon[/project.json]` file) so the `@neondatabase/env` library\n * functions can stay filesystem- and env-agnostic.\n */\nexport interface ResolvedContext {\n\tprojectId: string;\n\tbranchId: string;\n
|
|
1
|
+
{"version":3,"file":"resolve-context.js","names":[],"sources":["../../../src/lib/cli/resolve-context.ts"],"sourcesContent":["import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, resolve } from \"node:path\";\n\n/**\n * Resolved project + branch context for the `neon-env` CLI. The CLI owns this resolution\n * (flags → `NEON_*` env → `.neon[/project.json]` file) so the `@neondatabase/env` library\n * functions can stay filesystem- and env-agnostic.\n */\nexport interface ResolvedContext {\n\tprojectId: string;\n\tbranchId: string;\n}\n\nexport interface ResolveContextOptions {\n\tprojectId?: string;\n\tbranch?: string;\n\tcwd: string;\n\tenv?: NodeJS.ProcessEnv;\n}\n\n/**\n * Resolve `projectId` and `branch` for a CLI invocation. Precedence (each wins over the\n * next): explicit flag → `NEON_*` env var → `.neon[/project.json]` walked up from `cwd`.\n *\n * Returns the resolved values plus a list of human-readable reasons for any field that\n * could not be resolved (so the caller can render one combined error).\n */\nexport function resolveContext(\n\toptions: ResolveContextOptions,\n): { ok: true; context: ResolvedContext } | { ok: false; missing: string[] } {\n\tconst env = options.env ?? process.env;\n\tconst file = findNeonFile(options.cwd);\n\n\tconst projectId =\n\t\tnonEmpty(options.projectId) ??\n\t\tnonEmpty(env.NEON_PROJECT_ID) ??\n\t\tfile?.projectId;\n\n\tconst branchId =\n\t\tnonEmpty(options.branch) ??\n\t\tnonEmpty(env.NEON_BRANCH_ID) ??\n\t\tfile?.branchId;\n\n\tconst missing: string[] = [];\n\tif (!projectId) {\n\t\tmissing.push(\n\t\t\t\"project id — pass `--project-id`, set `NEON_PROJECT_ID`, or add `projectId` to `.neon/project.json` (run `npx neonctl link`).\",\n\t\t);\n\t}\n\tif (!branchId) {\n\t\tmissing.push(\n\t\t\t\"branch — pass `--branch`, set `NEON_BRANCH_ID`, or add `branchId` to `.neon/project.json` (run `npx neonctl checkout <branch>`).\",\n\t\t);\n\t}\n\tif (!projectId || !branchId) return { ok: false, missing };\n\n\treturn {\n\t\tok: true,\n\t\tcontext: { projectId, branchId },\n\t};\n}\n\ninterface NeonFile {\n\tprojectId?: string;\n\tbranchId?: string;\n}\n\n/**\n * Walk up from `cwd` looking for `.neon/project.json` (preferred) or `.neon` (neonctl\n * convention). Stops at the first `.git` directory or the home directory. Read-only.\n */\nfunction findNeonFile(cwd: string): NeonFile | null {\n\tlet current = resolve(cwd);\n\tconst stop = resolve(homedir());\n\tlet lastSeen: string | null = null;\n\n\twhile (true) {\n\t\tconst parsed =\n\t\t\treadNeonFileAt(resolve(current, \".neon\", \"project.json\")) ??\n\t\t\treadNeonFileAt(resolve(current, \".neon\"));\n\t\tif (parsed) return parsed;\n\n\t\tif (current === stop) return null;\n\t\tif (existsSync(resolve(current, \".git\"))) return null;\n\n\t\tconst parent = dirname(current);\n\t\tif (parent === current || parent === lastSeen) return null;\n\t\tlastSeen = current;\n\t\tcurrent = parent;\n\t}\n}\n\nfunction readNeonFileAt(path: string): NeonFile | null {\n\tif (!isFile(path)) return null;\n\tlet raw: string;\n\ttry {\n\t\traw = readFileSync(path, \"utf-8\");\n\t} catch {\n\t\treturn null;\n\t}\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\treturn null;\n\t}\n\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed))\n\t\treturn null;\n\tconst obj = parsed as Record<string, unknown>;\n\tconst out: NeonFile = {};\n\tif (typeof obj.projectId === \"string\" && obj.projectId !== \"\")\n\t\tout.projectId = obj.projectId;\n\tif (typeof obj.branchId === \"string\" && obj.branchId !== \"\")\n\t\tout.branchId = obj.branchId;\n\treturn out;\n}\n\nfunction isFile(path: string): boolean {\n\ttry {\n\t\treturn statSync(path).isFile();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction nonEmpty(value: string | undefined): string | undefined {\n\tif (typeof value !== \"string\") return undefined;\n\tconst trimmed = value.trim();\n\treturn trimmed === \"\" ? undefined : trimmed;\n}\n"],"mappings":";;;;;;;;;;;AA4BA,SAAgB,eACf,SAC4E;CAC5E,MAAM,MAAM,QAAQ,OAAO,QAAQ;CACnC,MAAM,OAAO,aAAa,QAAQ,GAAG;CAErC,MAAM,YACL,SAAS,QAAQ,SAAS,KAC1B,SAAS,IAAI,eAAe,KAC5B,MAAM;CAEP,MAAM,WACL,SAAS,QAAQ,MAAM,KACvB,SAAS,IAAI,cAAc,KAC3B,MAAM;CAEP,MAAM,UAAoB,CAAC;CAC3B,IAAI,CAAC,WACJ,QAAQ,KACP,+HACD;CAED,IAAI,CAAC,UACJ,QAAQ,KACP,kIACD;CAED,IAAI,CAAC,aAAa,CAAC,UAAU,OAAO;EAAE,IAAI;EAAO;CAAQ;CAEzD,OAAO;EACN,IAAI;EACJ,SAAS;GAAE;GAAW;EAAS;CAChC;AACD;;;;;AAWA,SAAS,aAAa,KAA8B;CACnD,IAAI,UAAU,QAAQ,GAAG;CACzB,MAAM,OAAO,QAAQ,QAAQ,CAAC;CAC9B,IAAI,WAA0B;CAE9B,OAAO,MAAM;EACZ,MAAM,SACL,eAAe,QAAQ,SAAS,SAAS,cAAc,CAAC,KACxD,eAAe,QAAQ,SAAS,OAAO,CAAC;EACzC,IAAI,QAAQ,OAAO;EAEnB,IAAI,YAAY,MAAM,OAAO;EAC7B,IAAI,WAAW,QAAQ,SAAS,MAAM,CAAC,GAAG,OAAO;EAEjD,MAAM,SAAS,QAAQ,OAAO;EAC9B,IAAI,WAAW,WAAW,WAAW,UAAU,OAAO;EACtD,WAAW;EACX,UAAU;CACX;AACD;AAEA,SAAS,eAAe,MAA+B;CACtD,IAAI,CAAC,OAAO,IAAI,GAAG,OAAO;CAC1B,IAAI;CACJ,IAAI;EACH,MAAM,aAAa,MAAM,OAAO;CACjC,QAAQ;EACP,OAAO;CACR;CACA,IAAI;CACJ,IAAI;EACH,SAAS,KAAK,MAAM,GAAG;CACxB,QAAQ;EACP,OAAO;CACR;CACA,IAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GACxE,OAAO;CACR,MAAM,MAAM;CACZ,MAAM,MAAgB,CAAC;CACvB,IAAI,OAAO,IAAI,cAAc,YAAY,IAAI,cAAc,IAC1D,IAAI,YAAY,IAAI;CACrB,IAAI,OAAO,IAAI,aAAa,YAAY,IAAI,aAAa,IACxD,IAAI,WAAW,IAAI;CACpB,OAAO;AACR;AAEA,SAAS,OAAO,MAAuB;CACtC,IAAI;EACH,OAAO,SAAS,IAAI,EAAE,OAAO;CAC9B,QAAQ;EACP,OAAO;CACR;AACD;AAEA,SAAS,SAAS,OAA+C;CAChE,IAAI,OAAO,UAAU,UAAU,OAAO,KAAA;CACtC,MAAM,UAAU,MAAM,KAAK;CAC3B,OAAO,YAAY,KAAK,KAAA,IAAY;AACrC"}
|
package/dist/lib/env.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Config } from "../config/dist/lib/types.js";
|
|
2
2
|
import { NeonApi } from "../config/dist/lib/neon-api.js";
|
|
3
3
|
import "../config/dist/v1.js";
|
|
4
4
|
|
|
@@ -62,29 +62,58 @@ interface NeonDataApiEnv {
|
|
|
62
62
|
* which biome rejects (it means "any non-null", not "empty object").
|
|
63
63
|
*/
|
|
64
64
|
type NoNamespace = Record<never, never>;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
type
|
|
65
|
+
/**
|
|
66
|
+
* Resolve a **static** service toggle (the value of `config.auth` / `config.dataApi`) to a
|
|
67
|
+
* type-level boolean. The whole-thing wrapping (`[T] extends […]`) turns off distribution
|
|
68
|
+
* so a union/`undefined` is checked as one unit:
|
|
69
|
+
*
|
|
70
|
+
* - `false` / `{ enabled: false }` / `undefined` → `false`
|
|
71
|
+
* - `true` / `{ enabled: true }` / any other object (`{}`, `{ enabled?: boolean }`) → `true`
|
|
72
|
+
* (a present toggle defaults to enabled)
|
|
73
|
+
* - the bare `boolean | ServiceToggle | undefined` (the default `Config` param, no literal
|
|
74
|
+
* info) → `false`, so an untyped policy yields just `{ postgres }`.
|
|
75
|
+
*/
|
|
76
|
+
type ServiceOn<T> = [T] extends [false] ? false : [T] extends [{
|
|
68
77
|
enabled: false;
|
|
69
|
-
}
|
|
70
|
-
|
|
78
|
+
}] ? false : [T] extends [undefined] ? false : [T] extends [true] ? true : [T] extends [{
|
|
79
|
+
enabled: true;
|
|
80
|
+
}] ? true : [T] extends [object] ? true : false;
|
|
71
81
|
/**
|
|
72
82
|
* Static, namespaced shape of `fetchEnv` / `parseEnv`'s return value. Generic over the
|
|
73
83
|
* {@link Config} so the type system knows which optional namespaces are present.
|
|
74
84
|
*
|
|
85
|
+
* Because the secret-bearing toggles now live in the **static** top-level `config.auth` /
|
|
86
|
+
* `config.dataApi` (not inside a per-branch closure), the namespace presence is a direct
|
|
87
|
+
* read of those fields — no union-across-branches, no default-config escape hatch:
|
|
88
|
+
*
|
|
75
89
|
* - `postgres` is always present.
|
|
76
|
-
* - `auth` is added iff
|
|
77
|
-
*
|
|
78
|
-
* - `dataApi` is added iff the config return type has a `dataApi` namespace that is not
|
|
79
|
-
* explicitly disabled.
|
|
90
|
+
* - `auth` is added iff `config.auth` is statically enabled.
|
|
91
|
+
* - `dataApi` is added iff `config.dataApi` is statically enabled.
|
|
80
92
|
*/
|
|
81
93
|
type NeonEnv<C extends Config = Config> = {
|
|
82
94
|
postgres: NeonPostgresEnv;
|
|
83
|
-
} & (
|
|
95
|
+
} & (ServiceOn<NonNullable<C["auth"]>> extends true ? {
|
|
84
96
|
auth: NeonAuthEnv;
|
|
85
|
-
} : NoNamespace) & (
|
|
97
|
+
} : NoNamespace) & (ServiceOn<NonNullable<C["dataApi"]>> extends true ? {
|
|
86
98
|
dataApi: NeonDataApiEnv;
|
|
87
99
|
} : NoNamespace);
|
|
100
|
+
/** The static `preview.functions` record of a config, or an empty record when absent. */
|
|
101
|
+
type PreviewFunctionsOf<C extends Config> = NonNullable<C["preview"]> extends {
|
|
102
|
+
functions: infer F;
|
|
103
|
+
} ? F : Record<never, never>;
|
|
104
|
+
/** The declared function slugs of a config (record keys), as a string union. */
|
|
105
|
+
type FunctionSlugOf<C extends Config> = Extract<keyof PreviewFunctionsOf<C>, string>;
|
|
106
|
+
/** The declared env-var keys of one function `S`, as a string union. */
|
|
107
|
+
type FunctionEnvKeysOf<C extends Config, S extends string> = S extends keyof PreviewFunctionsOf<C> ? NonNullable<PreviewFunctionsOf<C>[S]> extends {
|
|
108
|
+
env: infer E;
|
|
109
|
+
} ? Extract<keyof E, string> : never : never;
|
|
110
|
+
/**
|
|
111
|
+
* The extra `function` namespace added to `parseEnv`'s result when called with a function
|
|
112
|
+
* slug scope: the declared env-var keys for that function, each resolved to a `string`.
|
|
113
|
+
*/
|
|
114
|
+
type NeonFunctionEnv<C extends Config, S extends string> = {
|
|
115
|
+
function: Record<FunctionEnvKeysOf<C, S>, string>;
|
|
116
|
+
};
|
|
88
117
|
interface FetchEnvOptions {
|
|
89
118
|
/**
|
|
90
119
|
* Neon project id. **Required** — the management API addresses branches through their
|
|
@@ -147,36 +176,45 @@ interface FetchEnvOptions {
|
|
|
147
176
|
*/
|
|
148
177
|
declare function fetchEnv<const C extends Config>(config: C, options: FetchEnvOptions): Promise<NeonEnv<C>>;
|
|
149
178
|
/**
|
|
150
|
-
* Synchronous, network-free counterpart to {@link fetchEnv}. Reads `process.env
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
179
|
+
* Synchronous, network-free counterpart to {@link fetchEnv}. Reads `process.env`, validates
|
|
180
|
+
* the required Neon env vars with zod, and returns the same {@link NeonEnv} shape — so the
|
|
181
|
+
* rest of your app touches `env.postgres.databaseUrl` instead of stringly-typed
|
|
182
|
+
* `process.env.DATABASE_URL` lookups.
|
|
154
183
|
*
|
|
155
184
|
* Designed for the **"env-vars-already-injected"** path:
|
|
156
|
-
* - You wrapped your dev command with `neon-env run -- <cmd
|
|
185
|
+
* - You wrapped your dev command with `neon-env run -- <cmd>` or `neon dev`.
|
|
157
186
|
* - Your platform (Vercel, Fly, Railway, …) injected the vars via its own integration.
|
|
187
|
+
* - You are **inside a deployed Neon Function**, whose env was uploaded at `config apply`.
|
|
158
188
|
*
|
|
159
|
-
*
|
|
160
|
-
* `
|
|
161
|
-
* evaluating
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
189
|
+
* Unlike the old API, `parseEnv` does **not** take a branch name: the secret set is now
|
|
190
|
+
* static (top-level `config.auth` / `config.dataApi`), so it reads those directly without
|
|
191
|
+
* evaluating the per-branch closure.
|
|
192
|
+
*
|
|
193
|
+
* The second argument is a **scope**:
|
|
194
|
+
* - omitted — *external* scope (app bootstrap, build scripts, your dev machine). Returns
|
|
195
|
+
* `{ postgres, auth?, dataApi? }`.
|
|
196
|
+
* - a **function slug** (a key of `config.preview.functions`) — *function* scope: you are
|
|
197
|
+
* running inside that function. Returns the same branch secrets **plus** a typed
|
|
198
|
+
* `function` namespace with the function's declared env-var keys.
|
|
166
199
|
*
|
|
167
200
|
* Throws `PlatformError(EnvNotInjected)` listing every missing/invalid var when the env
|
|
168
|
-
* isn't fully populated, with a fix hint pointing back at `neon-env run`.
|
|
201
|
+
* isn't fully populated, with a fix hint pointing back at `neon dev` / `neon-env run`.
|
|
169
202
|
*
|
|
170
203
|
* ```ts
|
|
171
204
|
* import config from "../neon";
|
|
172
205
|
* import { parseEnv } from "@neondatabase/env/v1";
|
|
173
206
|
*
|
|
174
|
-
*
|
|
207
|
+
* // External (app / build):
|
|
208
|
+
* const env = parseEnv(config);
|
|
175
209
|
* const db = drizzle(neon(env.postgres.databaseUrl), { schema });
|
|
176
|
-
*
|
|
210
|
+
*
|
|
211
|
+
* // Inside the "hello" function:
|
|
212
|
+
* const env = parseEnv(config, "hello");
|
|
213
|
+
* env.function.resendApiKey; // typed from hello's declared env keys
|
|
177
214
|
* ```
|
|
178
215
|
*/
|
|
179
|
-
declare function parseEnv<const C extends Config>(config: C
|
|
216
|
+
declare function parseEnv<const C extends Config>(config: C): NeonEnv<C>;
|
|
217
|
+
declare function parseEnv<const C extends Config, const S extends FunctionSlugOf<C>>(config: C, scope: S): NeonEnv<C> & NeonFunctionEnv<C, S>;
|
|
180
218
|
/**
|
|
181
219
|
* Project a fully-resolved {@link NeonEnv} into the OS-level `{ KEY: value }` pairs used
|
|
182
220
|
* for cross-process transport. Named after the web-platform `.entries()` convention
|
|
@@ -190,5 +228,5 @@ declare function parseEnv<const C extends Config>(config: C, branchName: string)
|
|
|
190
228
|
*/
|
|
191
229
|
declare function toEntries(env: NeonEnv<Config>): Record<string, string>;
|
|
192
230
|
//#endregion
|
|
193
|
-
export { FetchEnvOptions, NEON_ENV_VAR_KEYS, NeonAuthEnv, NeonDataApiEnv, NeonEnv, NeonPostgresEnv, fetchEnv, parseEnv, toEntries };
|
|
231
|
+
export { FetchEnvOptions, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAuthEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, fetchEnv, parseEnv, toEntries };
|
|
194
232
|
//# 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":";;;;;;;;;;AAwBA;AAcA;AAuBA;AAKA;AAEC;AAOwB;
|
|
1
|
+
{"version":3,"file":"env.d.ts","names":[],"sources":["../../src/lib/env.ts"],"mappings":";;;;;;;;;;AAwBA;AAcA;AAuBA;AAKA;AAEC;AAOwB;AAaX,cAhED,iBAgEC,EAAA;WAAO,QAAA,EAAA;IAEjB,SAAA,WAAA,EAAA,cAAA;IAEC,SAAA,mBAAA,EAAA,uBAAA;;WAIE,IAAA,EAAA;IAEC,SAAA,OAAA,EAAA,oBAAA;EAAC,CAAA;EAgBG,SAAA,OAAO,EAAA;IAAA,SAAA,GAAA,EAAA,mBAAA;;;;AAEQ,UA9EV,eAAA,CA8EU;;;;;aAGH,EAAA,MAAA;;;;;AAET;EAGV,mBAAA,EAAkB,MAAA;;;;;;;AAId;AAGT;;;AAC0B,UAvET,WAAA,CAuES;SAAnB,EAAA,MAAA;;AAD+C;AAMjD,UAvEY,cAAA,CAuEK;EAAA,GAAA,EAAA,MAAA;;;;;;;KA9DjB,WAAA,GAAc,MAkEkB,CAAA,KAAA,EAAA,KAAA,CAAA;;;;AAC1B;AAQX;;;;;;;AACiB,KA/DZ,SA+DY,CAAA,CAAA,CAAA,GAAA,CA/DI,CA+DJ,CAAA,SAAA,CAAA,KAAA,CAAA,GAAA,KAAA,GAAA,CA7Db,CA6Da,CAAA,SAAA,CAAA;EAGA,OAAA,EAAA,KAAA;CAAe,CAAA,GAAA,KAAA,GAAA,CA9D3B,CA8D2B,CAAA,SAAA,CAAA,SAAA,CAAA,GAAA,KAAA,GAAA,CA5D1B,CA4D0B,CAAA,SAAA,CAAA,IAAA,CAAA,GAAA,IAAA,GAAA,CA1DzB,CA0DyB,CAAA,SAAA,CAAA;SAkBzB,EAAA,IAAA;SAiBA,GAAA,CA3FC,CA2FM,CAAA,SAAA,CAAA,MAAA,CAAA,GAAA,IAAA,GAAA,KAAA;AAAU;AA0BxB;;;;;;;;AAGU;AA0VV;;AAAyC,KAlc7B,OAkc6B,CAAA,UAlcX,MAkcW,GAlcF,MAkcE,CAAA,GAAA;UAAgB,EAjc9C,eAic8C;KAhcpD,SAgcgE,CAhctD,WAgcsD,CAhc1C,CAgc0C,CAAA,MAAA,CAAA,CAAA,CAAA,SAAA,IAAA,GAAA;MAAR,EA/blD,WA+bkD;AAAO,CAAA,GA9bjE,WA8biE,CAAA,GAAA,CA7blE,SA6bkE,CA7bxD,WA6bwD,CA7b5C,CA6b4C,CAAA,SAAA,CAAA,CAAA,CAAA,SAAA,IAAA,GAAA;EACpD,OAAA,EA7bD,cA6bS;CAAA,GA5bpB,WA4boB,CAAA;;KAzbnB,kBA2b2B,CAAA,UA3bE,MA2bF,CAAA,GA3bY,WA2bZ,CA3bwB,CA2bxB,CAAA,SAAA,CAAA,CAAA,SAAA;WAAf,EAAA,KAAA,EAAA;IAxbd,IACA,MAwbO,CAAA,KAAA,EAAA,KAAA,CAAA;;AAAsB,KArbpB,cAqboB,CAAA,UArbK,MAqbL,CAAA,GArbe,OAqbf,CAAA,MApbzB,kBAobyB,CApbN,CAobM,CAAA,EAAA,MAAA,CAAA;;KA/a3B,iBA+agD,CAAA,UA9a1C,MA8a0C,EAAA,UAAA,MAAA,CAAA,GA5ajD,CA4aiD,SAAA,MA5ajC,kBA4aiC,CA5ad,CA4ac,CAAA,GA3alD,WA2akD,CA3atC,kBA2asC,CA3anB,CA2amB,CAAA,CA3ahB,CA2agB,CAAA,CAAA,SAAA;KAAG,EAAA,KAAA,EAAA;IA1apD,OA0aiC,CAAA,MA1anB,CA0amB,EAAA,MAAA,CAAA,GAAA,KAAA,GAAA,KAAA;AAAe;AAyGpD;;;AAA+B,KA3gBnB,eA2gBmB,CAAA,UA3gBO,MA2gBP,EAAA,UAAA,MAAA,CAAA,GAAA;UAAkB,EA1gBtC,MA0gBsC,CA1gB/B,iBA0gB+B,CA1gBb,CA0gBa,EA1gBV,CA0gBU,CAAA,EAAA,MAAA,CAAA;AAAM,CAAA;UAvgBtC,eAAA;;;;;;;;;;;;;;;;;;QAkBV;;;;;;;;;;;;;;;;;QAiBA,MAAA,CAAO;;;;;;;;;;;;;;;;;;;;;;;;;iBA0BQ,yBAAyB,gBACtC,YACC,kBACP,QAAQ,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0VH,yBAAyB,gBAAgB,IAAI,QAAQ;iBACrD,yBACC,wBACA,eAAe,YACtB,UAAU,IAAI,QAAQ,KAAK,gBAAgB,GAAG;;;;;;;;;;;;iBAyGxC,SAAA,MAAe,QAAQ,UAAU"}
|
package/dist/lib/env.js
CHANGED
|
@@ -168,44 +168,16 @@ const postgresEnvSchema = z.object({
|
|
|
168
168
|
});
|
|
169
169
|
const authEnvSchema = z.object({ NEON_AUTH_BASE_URL: z.string({ message: "NEON_AUTH_BASE_URL is missing" }).min(1, "NEON_AUTH_BASE_URL must not be empty") });
|
|
170
170
|
const dataApiEnvSchema = z.object({ NEON_DATA_API_URL: z.string({ message: "NEON_DATA_API_URL is missing" }).min(1, "NEON_DATA_API_URL must not be empty") });
|
|
171
|
-
/**
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
* - You wrapped your dev command with `neon-env run -- <cmd>`.
|
|
179
|
-
* - Your platform (Vercel, Fly, Railway, …) injected the vars via its own integration.
|
|
180
|
-
*
|
|
181
|
-
* Takes a branch **name** (not an id like the API-backed `fetchEnv` / config operations):
|
|
182
|
-
* `parseEnv` makes no Neon API call, so the only thing it needs the branch for is
|
|
183
|
-
* evaluating your `neon.ts` policy, which switches on `branch.name`. With no network round
|
|
184
|
-
* trip there's no way to turn a `br-…` id into a name, so the name is passed directly.
|
|
185
|
-
* Pass it explicitly so the result is deterministic and not coupled to any `NEON_*` env
|
|
186
|
-
* var. (The `neon-env` CLI injects `NEON_BRANCH_NAME`; pass that through, or default to
|
|
187
|
-
* your main branch name.) Prefer `fetchEnv` when runtime code needs the exact live branch.
|
|
188
|
-
*
|
|
189
|
-
* Throws `PlatformError(EnvNotInjected)` listing every missing/invalid var when the env
|
|
190
|
-
* isn't fully populated, with a fix hint pointing back at `neon-env run`.
|
|
191
|
-
*
|
|
192
|
-
* ```ts
|
|
193
|
-
* import config from "../neon";
|
|
194
|
-
* import { parseEnv } from "@neondatabase/env/v1";
|
|
195
|
-
*
|
|
196
|
-
* const env = parseEnv(config, process.env.NEON_BRANCH_NAME ?? "main");
|
|
197
|
-
* const db = drizzle(neon(env.postgres.databaseUrl), { schema });
|
|
198
|
-
* // env.auth is statically typed when the config return type has auth: {} or auth.enabled: true.
|
|
199
|
-
* ```
|
|
200
|
-
*/
|
|
201
|
-
function parseEnv(config, branchName) {
|
|
171
|
+
/** Static-toggle helper mirroring `config`'s `isServiceEnabled` for the env reader. */
|
|
172
|
+
function isServiceEnabledInput(toggle) {
|
|
173
|
+
if (toggle === void 0) return false;
|
|
174
|
+
if (typeof toggle === "boolean") return toggle;
|
|
175
|
+
return toggle.enabled !== false;
|
|
176
|
+
}
|
|
177
|
+
function parseEnv(config, scope) {
|
|
202
178
|
const source = process.env;
|
|
203
179
|
const issues = [];
|
|
204
180
|
const result = {};
|
|
205
|
-
const desired = resolveConfig(config, {
|
|
206
|
-
name: branchName,
|
|
207
|
-
exists: true
|
|
208
|
-
});
|
|
209
181
|
const pg = postgresEnvSchema.safeParse({
|
|
210
182
|
DATABASE_URL: source.DATABASE_URL,
|
|
211
183
|
DATABASE_URL_UNPOOLED: source.DATABASE_URL_UNPOOLED
|
|
@@ -215,23 +187,35 @@ function parseEnv(config, branchName) {
|
|
|
215
187
|
databaseUrlUnpooled: pg.data.DATABASE_URL_UNPOOLED
|
|
216
188
|
};
|
|
217
189
|
else for (const issue of pg.error.issues) issues.push(issue.message);
|
|
218
|
-
if (
|
|
190
|
+
if (isServiceEnabledInput(config.auth)) {
|
|
219
191
|
const auth = authEnvSchema.safeParse({ NEON_AUTH_BASE_URL: source.NEON_AUTH_BASE_URL });
|
|
220
192
|
if (auth.success) result.auth = { baseUrl: auth.data.NEON_AUTH_BASE_URL };
|
|
221
193
|
else for (const issue of auth.error.issues) issues.push(issue.message);
|
|
222
194
|
}
|
|
223
|
-
if (
|
|
195
|
+
if (isServiceEnabledInput(config.dataApi)) {
|
|
224
196
|
const dataApi = dataApiEnvSchema.safeParse({ NEON_DATA_API_URL: source.NEON_DATA_API_URL });
|
|
225
197
|
if (dataApi.success) result.dataApi = { url: dataApi.data.NEON_DATA_API_URL };
|
|
226
198
|
else for (const issue of dataApi.error.issues) issues.push(issue.message);
|
|
227
199
|
}
|
|
200
|
+
if (scope !== void 0) {
|
|
201
|
+
const fn = config.preview?.functions?.[scope];
|
|
202
|
+
if (!fn) throw new PlatformError(ErrorCode.EnvNotInjected, [`parseEnv: no function "${scope}" is declared in this policy's preview.functions.`, "Pass a declared function slug (or omit the scope to read external env)."].join("\n"), { details: { scope } });
|
|
203
|
+
const envOut = {};
|
|
204
|
+
for (const key of Object.keys(fn.env ?? {})) {
|
|
205
|
+
const value = source[key];
|
|
206
|
+
if (value === void 0) issues.push(`${key} is missing (function "${scope}")`);
|
|
207
|
+
else envOut[key] = value;
|
|
208
|
+
}
|
|
209
|
+
result.function = envOut;
|
|
210
|
+
}
|
|
228
211
|
if (issues.length > 0) throw new PlatformError(ErrorCode.EnvNotInjected, [
|
|
229
212
|
"parseEnv: the required Neon env variables are not present in process.env.",
|
|
230
213
|
...issues.map((i) => ` - ${i}`),
|
|
231
214
|
"Inject them via one of:",
|
|
232
|
-
" - `neon-env run -- <your dev command>` (wraps the command with the vars injected)",
|
|
215
|
+
" - `neon dev` / `neon-env run -- <your dev command>` (wraps the command with the vars injected)",
|
|
233
216
|
" - your hosting platform's Neon integration (Vercel, Fly, Railway, …)",
|
|
234
|
-
"
|
|
217
|
+
" - for the `function` namespace: deploy the function (`neon deploy` / `config apply`) so its env is uploaded.",
|
|
218
|
+
"Or switch the call to `await fetchEnv(config, …)` if you're in a context that can do async I/O."
|
|
235
219
|
].join("\n"), { details: { missing: issues } });
|
|
236
220
|
return result;
|
|
237
221
|
}
|
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 BranchConfig,\n\ttype Config,\n\tcreateNeonApiFromOptions,\n\tErrorCode,\n\ttype NeonApi,\n\ttype NeonBranchSnapshot,\n\ttype NeonDatabaseSnapshot,\n\ttype NeonRoleSnapshot,\n\tPlatformError,\n\tresolveConfig,\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 */\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},\n\tdataApi: {\n\t\turl: \"NEON_DATA_API_URL\",\n\t},\n} as const;\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 a single `baseUrl` that doubles as the publishable client identifier\n * — the rest of the surface (project id, JWKS URL, …) is derived from it at runtime by\n * the Neon Auth SDK. `fetchEnv` reads it from the live integration; `parseEnv` reads it\n * from `process.env` (`NEON_AUTH_BASE_URL`).\n */\nexport interface NeonAuthEnv {\n\tbaseUrl: 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 * 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\ntype BranchConfigOf<C extends Config> = ReturnType<C> extends BranchConfig\n\t? ReturnType<C>\n\t: BranchConfig;\n\ntype ServiceToggleOf<Cfg, Key extends \"auth\" | \"dataApi\"> = Cfg extends unknown\n\t? Key extends keyof Cfg\n\t\t? Cfg[Key]\n\t\t: never\n\t: never;\n\ntype HasEnabledService<Cfg, Key extends \"auth\" | \"dataApi\"> = [\n\tExclude<ServiceToggleOf<Cfg, Key>, undefined | { enabled: false }>,\n] extends [never]\n\t? false\n\t: true;\n\ntype IsDefaultConfig<C extends Config> = Config extends C ? true : 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 * - `postgres` is always present.\n * - `auth` is added iff the config return type has an `auth` namespace that is not\n * explicitly disabled.\n * - `dataApi` is added iff the config return type has a `dataApi` namespace that is not\n * explicitly disabled.\n */\nexport type NeonEnv<C extends Config = Config> = {\n\tpostgres: NeonPostgresEnv;\n} & (IsDefaultConfig<C> extends true\n\t? NoNamespace\n\t: HasEnabledService<BranchConfigOf<C>, \"auth\"> extends true\n\t\t? { auth: NeonAuthEnv }\n\t\t: NoNamespace) &\n\t(IsDefaultConfig<C> extends true\n\t\t? NoNamespace\n\t\t: HasEnabledService<BranchConfigOf<C>, \"dataApi\"> extends true\n\t\t\t? { dataApi: NeonDataApiEnv }\n\t\t\t: NoNamespace);\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 * 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 only role on the branch is\n\t * auto-picked; throws {@link PlatformError} with `PLATFORM_AMBIGUOUS_BRANCH_AUTH` if\n\t * the branch has more than one role.\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 baseUrl = resolveAuthBaseUrl(\n\t\t\tauthSnapshot.baseUrl,\n\t\t\toptions.env ?? process.env,\n\t\t);\n\t\tresult.auth = { baseUrl } 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\treturn result as NeonEnv<C>;\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\nfunction createApiFromOptions(options: FetchEnvOptions): NeonApi {\n\treturn createNeonApiFromOptions(\n\t\t\"fetchEnv\",\n\t\toptions.apiKey ? { apiKey: options.apiKey } : {},\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\tthrow new PlatformError(\n\t\tErrorCode.AmbiguousBranchAuth,\n\t\t[\n\t\t\t`fetchEnv: branch ${branch.name} (${branch.id}) has ${roles.length} roles; 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});\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\n/**\n * Synchronous, network-free counterpart to {@link fetchEnv}. Reads `process.env` (or\n * `options.env`), validates the required Neon env vars with zod, and returns the same\n * {@link NeonEnv} shape — so the rest of your app touches `env.postgres.databaseUrl`\n * instead of stringly-typed `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>`.\n * - Your platform (Vercel, Fly, Railway, …) injected the vars via its own integration.\n *\n * Takes a branch **name** (not an id like the API-backed `fetchEnv` / config operations):\n * `parseEnv` makes no Neon API call, so the only thing it needs the branch for is\n * evaluating your `neon.ts` policy, which switches on `branch.name`. With no network round\n * trip there's no way to turn a `br-…` id into a name, so the name is passed directly.\n * Pass it explicitly so the result is deterministic and not coupled to any `NEON_*` env\n * var. (The `neon-env` CLI injects `NEON_BRANCH_NAME`; pass that through, or default to\n * your main branch name.) Prefer `fetchEnv` when runtime code needs the exact live branch.\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-env run`.\n *\n * ```ts\n * import config from \"../neon\";\n * import { parseEnv } from \"@neondatabase/env/v1\";\n *\n * const env = parseEnv(config, process.env.NEON_BRANCH_NAME ?? \"main\");\n * const db = drizzle(neon(env.postgres.databaseUrl), { schema });\n * // env.auth is statically typed when the config return type has auth: {} or auth.enabled: true.\n * ```\n */\nexport function parseEnv<const C extends Config>(\n\tconfig: C,\n\tbranchName: string,\n): NeonEnv<C> {\n\tconst source = process.env;\n\tconst issues: string[] = [];\n\tconst result: Record<string, unknown> = {};\n\tconst desired = resolveConfig(config, {\n\t\tname: branchName,\n\t\texists: true,\n\t});\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 (desired.authEnabled) {\n\t\tconst auth = authEnvSchema.safeParse({\n\t\t\tNEON_AUTH_BASE_URL: source.NEON_AUTH_BASE_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} 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 (desired.dataApiEnabled) {\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 (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-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\n\treturn result as NeonEnv<C>;\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}\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\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\tcreateNeonApiFromOptions,\n\tErrorCode,\n\ttype NeonApi,\n\ttype NeonBranchSnapshot,\n\ttype NeonDatabaseSnapshot,\n\ttype NeonRoleSnapshot,\n\tPlatformError,\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 */\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},\n\tdataApi: {\n\t\turl: \"NEON_DATA_API_URL\",\n\t},\n} as const;\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 a single `baseUrl` that doubles as the publishable client identifier\n * — the rest of the surface (project id, JWKS URL, …) is derived from it at runtime by\n * the Neon Auth SDK. `fetchEnv` reads it from the live integration; `parseEnv` reads it\n * from `process.env` (`NEON_AUTH_BASE_URL`).\n */\nexport interface NeonAuthEnv {\n\tbaseUrl: 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 * 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/**\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 */\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\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 * 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 only role on the branch is\n\t * auto-picked; throws {@link PlatformError} with `PLATFORM_AMBIGUOUS_BRANCH_AUTH` if\n\t * the branch has more than one role.\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 baseUrl = resolveAuthBaseUrl(\n\t\t\tauthSnapshot.baseUrl,\n\t\t\toptions.env ?? process.env,\n\t\t);\n\t\tresult.auth = { baseUrl } 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\treturn result as NeonEnv<C>;\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\nfunction createApiFromOptions(options: FetchEnvOptions): NeonApi {\n\treturn createNeonApiFromOptions(\n\t\t\"fetchEnv\",\n\t\toptions.apiKey ? { apiKey: options.apiKey } : {},\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\tthrow new PlatformError(\n\t\tErrorCode.AmbiguousBranchAuth,\n\t\t[\n\t\t\t`fetchEnv: branch ${branch.name} (${branch.id}) has ${roles.length} roles; 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});\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\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});\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} 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 (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}\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\treturn out;\n}\n"],"mappings":"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"}
|
package/dist/v1.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { FetchEnvOptions, NEON_ENV_VAR_KEYS, NeonAuthEnv, NeonDataApiEnv, NeonEnv, NeonPostgresEnv, fetchEnv, parseEnv, toEntries } from "./lib/env.js";
|
|
2
|
-
export { type FetchEnvOptions, NEON_ENV_VAR_KEYS, type NeonAuthEnv, type NeonDataApiEnv, type NeonEnv, type NeonPostgresEnv, fetchEnv, parseEnv, toEntries };
|
|
1
|
+
import { FetchEnvOptions, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAuthEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, fetchEnv, parseEnv, toEntries } from "./lib/env.js";
|
|
2
|
+
export { type FetchEnvOptions, type FunctionSlugOf, NEON_ENV_VAR_KEYS, type NeonAuthEnv, type NeonDataApiEnv, type NeonEnv, type NeonFunctionEnv, type NeonPostgresEnv, fetchEnv, parseEnv, toEntries };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neondatabase/env",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Resolve and inject Neon connection strings for the branch selected by your neon.ts policy. fetchEnv / parseEnv plus a single `env run -- <cmd>` CLI.",
|
|
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.
|
|
58
|
+
"@neondatabase/config": "0.4.0"
|
|
59
59
|
},
|
|
60
60
|
"engines": {
|
|
61
61
|
"node": ">=22"
|