@neondatabase/env 0.11.8 → 0.12.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/dist/lib/env.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { Config } from "../config/dist/lib/types.js";
2
- import { NeonApi } from "../config/dist/lib/neon-api.js";
1
+ import { Config, CredentialScope, ResolvedPreviewConfig } from "../config/dist/lib/types.js";
2
+ import { NeonApi, NeonBranchSnapshot } from "../config/dist/lib/neon-api.js";
3
+ import { resolveConfig } from "../config/dist/lib/define-config.js";
3
4
  import "../config/dist/v1.js";
4
5
 
5
6
  //#region src/lib/env.d.ts
@@ -239,6 +240,7 @@ type NeonFunctionEnv<C extends Config, S extends string> = {
239
240
  */
240
241
  interface EnvKeysByNamespace {
241
242
  postgres: "DATABASE_URL" | "DATABASE_URL_UNPOOLED";
243
+ branch: "NEON_BRANCH";
242
244
  auth: "NEON_AUTH_BASE_URL" | "NEON_AUTH_JWKS_URL";
243
245
  dataApi: "NEON_DATA_API_URL";
244
246
  storage: "AWS_ACCESS_KEY_ID" | "AWS_SECRET_ACCESS_KEY" | "AWS_ENDPOINT_URL_S3" | "AWS_REGION";
@@ -247,6 +249,7 @@ interface EnvKeysByNamespace {
247
249
  /** The {@link NeonEnv} namespace interface backing each namespace key. */
248
250
  interface NamespaceEnv {
249
251
  postgres: NeonPostgresEnv;
252
+ branch: NeonBranchEnv;
250
253
  auth: NeonAuthEnv;
251
254
  dataApi: NeonDataApiEnv;
252
255
  storage: NeonStorageEnv;
@@ -256,6 +259,7 @@ interface NamespaceEnv {
256
259
  interface EnvKeyToProp {
257
260
  DATABASE_URL: "databaseUrl";
258
261
  DATABASE_URL_UNPOOLED: "databaseUrlUnpooled";
262
+ NEON_BRANCH: "name";
259
263
  NEON_AUTH_BASE_URL: "baseUrl";
260
264
  NEON_AUTH_JWKS_URL: "jwksUrl";
261
265
  NEON_DATA_API_URL: "url";
@@ -339,11 +343,6 @@ interface FetchEnvOptions {
339
343
  * the branch has no databases or the requested `databaseName` does not exist.
340
344
  */
341
345
  databaseName?: string;
342
- /**
343
- * Env source used for one-time Auth keys that cannot be refetched after integration
344
- * creation. Defaults to `process.env`; callers may layer values from `.env.local`.
345
- */
346
- env?: NodeJS.ProcessEnv;
347
346
  }
348
347
  /**
349
348
  * Resolve the project + branch this process should target, then fetch live Neon
@@ -366,9 +365,74 @@ interface FetchEnvOptions {
366
365
  * const db = drizzle(neon(env.postgres.databaseUrl), { schema });
367
366
  * ```
368
367
  *
369
- * The package does **not** mutate `process.env` or the filesystem itself.
368
+ * Pass `keys` to fetch only some of them — see the overload below.
369
+ *
370
+ * The package does **not** read `process.env`, mutate it, or touch the filesystem. Everything
371
+ * it returns comes from the Neon API, so a value the API cannot produce (a one-time secret
372
+ * issued to a previous call) is minted afresh rather than recovered. Callers that hold
373
+ * persisted secrets and want to keep them use {@link fetchEnvReusingSecrets}, which decides
374
+ * what is still valid and narrows this call's `keys` accordingly.
370
375
  */
376
+ declare function fetchEnv<const C extends Config, const K extends SelectableEnvKey<C>>(config: C, options: FetchEnvOptions & {
377
+ /**
378
+ * Fetch only these OS-level env vars, instead of everything the policy enables. The
379
+ * keys autocomplete from the policy ({@link SelectableEnvKey}), and the result is
380
+ * narrowed to match ({@link FilteredNeonEnv}).
381
+ *
382
+ * The point is not just a smaller result: **work is skipped too.** Leave out
383
+ * `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `NEON_AI_GATEWAY_TOKEN` and no branch
384
+ * credential is minted at all, so a caller that already holds valid secrets can refresh
385
+ * everything else without issuing a new one. The non-secret vars of the same features
386
+ * (`AWS_ENDPOINT_URL_S3`, `AWS_REGION`, `NEON_AI_GATEWAY_BASE_URL`) are not
387
+ * credential-backed and stay available on their own.
388
+ *
389
+ * The selection **intersects** with the policy rather than overriding it: naming a var
390
+ * the branch policy does not enable is not an error, it simply yields nothing.
391
+ */
392
+ keys: readonly K[];
393
+ }): Promise<FilteredNeonEnv<K>>;
371
394
  declare function fetchEnv<const C extends Config>(config: C, options: FetchEnvOptions): Promise<NeonEnv<C>>;
395
+ /**
396
+ * The {@link fetchEnv} body, with the key selection as a plain argument and no generic
397
+ * narrowing. Exists for callers that compute the selection at runtime — notably
398
+ * {@link fetchEnvReusingSecrets}, which decides which keys it still needs by checking the
399
+ * branch — since the public overload's `keys` is bound to a literal union those callers cannot
400
+ * produce without asserting.
401
+ *
402
+ * `keys === null` selects everything the policy enables.
403
+ */
404
+ declare function fetchEnvKeys(config: Config, options: FetchEnvOptions, keys: readonly string[] | null): Promise<ResolvedNeonEnv>;
405
+ /**
406
+ * Resolve the target branch and evaluate the policy against it — the first thing any
407
+ * branch-scoped operation needs. Shared by {@link fetchEnv} and {@link fetchEnvReusingSecrets}
408
+ * so the two agree on which branch they're talking about and what it has enabled.
409
+ */
410
+ declare function resolveBranchPolicy(config: Config, options: Pick<FetchEnvOptions, "projectId" | "branch" | "branchId">, api: NeonApi): Promise<{
411
+ branch: NeonBranchSnapshot;
412
+ desired: ReturnType<typeof resolveConfig>;
413
+ }>;
414
+ /**
415
+ * Scopes the branch credential should carry for a resolved branch policy. Only object storage
416
+ * and the AI Gateway *require* a credential; functions never force one (they have no credential
417
+ * of their own), but `functions:invoke` is added to the scope set when a credential is already
418
+ * being minted for storage / the AI Gateway, so the one credential can invoke the branch's
419
+ * functions too. Returns `[]` only when nothing credential-bearing is enabled.
420
+ */
421
+ declare function previewCredentialScopes(preview: ResolvedPreviewConfig | undefined): CredentialScope[];
422
+ /** The `name` this tool stamps on every credential it mints, so it can recognize its own. */
423
+ declare function credentialName(branchName: string): string;
424
+ /** The env-var keys a branch credential's secrets surface under, in emit order. */
425
+ declare function credentialEnvKeys(flags: {
426
+ storage: boolean;
427
+ aiGateway: boolean;
428
+ }): string[];
429
+ /**
430
+ * Every OS-level env var a resolved branch policy produces, in emit order. Lets a caller
431
+ * subtract the ones it already holds and pass the rest as {@link fetchEnv}'s `keys`, without
432
+ * re-deriving which vars a policy implies.
433
+ */
434
+ declare function policyEnvKeys(desired: ReturnType<typeof resolveConfig>): string[];
435
+ declare function createApiFromOptions(options: FetchEnvOptions): NeonApi;
372
436
  /**
373
437
  * Synchronous, network-free counterpart to {@link fetchEnv}. Reads `process.env`, validates
374
438
  * the required Neon env vars with zod, and returns the same {@link NeonEnv} shape — so the
@@ -432,7 +496,14 @@ declare function parseEnv<const C extends Config, const K extends SelectableEnvK
432
496
  * Walks the value at runtime so it works for any `NeonEnv<C>` regardless of which
433
497
  * conditional namespaces are present.
434
498
  */
435
- declare function toEntries(env: NeonEnv<Config>): Record<string, string>;
499
+ declare function toEntries(env: ResolvedNeonEnv): Record<string, string>;
500
+ /**
501
+ * Any resolved env {@link toEntries} can project: a full {@link NeonEnv}, or the narrowed
502
+ * result of a `keys`-filtered {@link fetchEnv} / {@link parseEnv} call. Every namespace and
503
+ * property is optional so a filtered result — which legitimately carries only what was asked
504
+ * for — projects to exactly the vars it holds instead of failing to type-check.
505
+ */
506
+ type ResolvedNeonEnv = { [N in keyof NamespaceEnv]?: Partial<NamespaceEnv[N]> };
436
507
  //#endregion
437
- export { FetchEnvOptions, FilteredNeonEnv, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAiGatewayEnv, NeonAuthEnv, NeonBranchEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, NeonStorageEnv, NoFunctionScopeHint, SelectableEnvKey, fetchEnv, parseEnv, toEntries };
508
+ export { FetchEnvOptions, FilteredNeonEnv, FunctionSlugOf, NEON_ENV_VAR_KEYS, NeonAiGatewayEnv, NeonAuthEnv, NeonBranchEnv, NeonDataApiEnv, NeonEnv, NeonFunctionEnv, NeonPostgresEnv, NeonStorageEnv, NoFunctionScopeHint, ResolvedNeonEnv, SelectableEnvKey, createApiFromOptions, credentialEnvKeys, credentialName, fetchEnv, fetchEnvKeys, parseEnv, policyEnvKeys, previewCredentialScopes, resolveBranchPolicy, toEntries };
438
509
  //# sourceMappingURL=env.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"env.d.ts","names":[],"sources":["../../src/lib/env.ts"],"mappings":"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"}
1
+ {"version":3,"file":"env.d.ts","names":[],"sources":["../../src/lib/env.ts"],"mappings":";;;;;;cAsDa;;;;;AAAb;EAkDiB,SAAA,MAAA,EAAa;IAKb,SAAA,IAAA,EAAe,aAAA;EAuBf,CAAA;EAOA,SAAA,QAAc,EAAA;IAed,SAAA,WAAc,EAAA,cAAA;IAiBd,SAAA,mBAAgB,EAAA,uBAAA;EAU5B,CAAA;EAaA,SAAA,IAAS,EAAA;IAAA,SAAA,OAAA,EAAA,oBAAA;IAAO,SAAA,OAAA,EAAA,oBAAA;EAEjB,CAAA;EAEC,SAAA,OAAA,EAAA;IAEC,SAAA,GAAA,EAAA,mBAAA;EAEC,CAAA;EAEC;AAAC;AAAA;AAKiB;AAWX;EAAW,SAAA,OAAA,EAAA;IAAuB,SAAA,WAAA,EAAA,mBAAA;IAAZ,SAAA,eAAA,EAAA,uBAAA;IAEtB,SAAA,QAAA,EAAA,qBAAA;IAAZ,SAAA,MAAA,EAAA,YAAA;EACqB,CAAA;EAAZ;AAAR;AAAO;AAAA;AAYK;AAAW;AAAuB;EAAZ,SAAA,SAAA,EAAA;IAEvB,SAAA,MAAA,EAAA,uBAAA;IAAZ,SAAA,OAAA,EAAA,0BAAA;EACuB,CAAA;AAAZ,CAAA;AAAV;AAAS;AAiBb;AAAmB;AAAW;AAAS;AAC5B,UAxJM,aAAA,CAwJN;EAKD,IAAA,EAAA,MAAA;AACiB;AAAZ;AAAV,UAzJY,eAAA,CAyJZ;EACM;AACR;AACqB;AAAZ;EAAV,WAAA,EAAA,MAAA;EACa;AACX;AACS;AAAX;AAAwC;EAAmB,mBAAA,EAAA,MAAA;AAC/C;AAAZ;AACe;AACb;AAAW;AAAE;AAGM;AAAW;AACrB;AAAZ;AAGG,UAlJa,WAAA,CAkJb;EACA,OAAA,EAAA,MAAA;EAAM;EAGE,OAAA,EAAA,MAAA;AAAc;AAAW;AACX,UAhJT,cAAA,CAgJS;EAAnB,GAAA,EAAA,MAAA;AADwC;AAAO;AAetD;AACyK;AASlJ;AAAW;AAClB;AAAf;AAEE;AACA;AAAC;AAAA;AAGkB,UAhKL,cAAA,CAgKK;EACX,WAAA,EAAA,MAAA;EAEP,eAAA,EAAA,MAAA;EAAmC;EAAnB,QAAA,EAAA,MAAA;EACc;EAAnB,MAAA,EAAA,MAAA;AAAsB;AAAlC;AACe;AAAd;AAAO;AAQX;AAA2B;AAAW;AACF;AAAG,UA7JtB,gBAAA,CA6JsB;EAArB,MAAA,EAAA,MAAA;EAAP,OAAA,EAAA,MAAA;AAAM;AACf;AAW0B;AAcN;AACX;AACF;AACF,KAhLF,WAAA,GAAc,MAgLZ,CAAA,KAAA,EAAA,KAAA,CAAA;AACG;AACA;AACE;AAAgB;AAAA;AAyB5B;AAA4B;AAAW;AACtC;AAAiC;AAAR;AAAmB,KAhMxC,SAgMwC,CAAA,CAAA,CAAA,GAAA,CAhMxB,CAgMwB,CAAA,SAAA,CAAA,KAAA,CAAA,GAAA,KAAA,GAAA,CA9LzC,CA8LyC,CAAA,SAAA,CAAA;EAAkB,OAAA,EAAA,KAAA;AAiB/D,CAAA,CAAA,GAAY,KAAA,GAAA,CA7MP,CA6MO,CAAA,SAAe,CAAA,SAAA,CAAA,GAAA,KAAA,GAAA,CA3MrB,CA2MqB,CAAA,SAAA,CAAA,IAAA,CAAA,GAAA,IAAA,GAAA,CAzMpB,CAyMoB,CAAA,SAAA,CAAA;EAAA,OAAA,EAAA,IAAA;AACd,CAAA,CAAA,GAAA,IAAA,GAAA,CAxML,CAwMK,CAAA,SAAA,CAAA,MAAA,CAAA,GAAA,IAAA,GAAA,KAAA;AACH;AAAG,KApMR,OAoMQ,CAAA,CAAA,CAAA,GAAA,CAAA,MApMY,CAoMZ,CAAA,SAAA,CAAA,KAAA,CAAA,GAAA,KAAA,GAAA,IAAA;AAAmB;AAA9B;AAGE;AACY;AAAG;AAAmB;AAA9B;AAAqC;AAAa;AACjD,KA9LJ,UA8LI,CAAA,UA9LiB,MA8LjB,CAAA,GAAA,CA9L4B,WA8L5B,CA9LwC,CA8LxC,CAAA,SAAA,CAAA,CAAA,CAAA,SAAA,CAAA,KAAA,CAAA,GAAA,KAAA,GA5LN,WA4LM,CA5LM,CA4LN,CAAA,SAAA,CAAA,CAAA,SAAA;EAAgB,OAAA,EAAA,KAAA,EAAA;AAAa,CAAA,GA3LlC,OA2LkC,CA3L1B,WA2L0B,CA3Ld,CA2Lc,CAAA,CAAA,GAAA,KAAA;AAAG;AAAa;AAC7C;AACA;AAAa;AAAC;AAIvB;AAiFA;AAA8B;AACb,KAvQZ,WAuQY,CAAA,UAvQU,MAuQV,CAAA,GAAA,CAvQqB,WAuQrB,CAvQiC,CAuQjC,CAAA,SAAA,CAAA,CAAA,CAAA,SAAA,CAAA,KAAA,CAAA,GAAA,KAAA,GArQd,WAqQc,CArQF,CAqQE,CAAA,SAAA,CAAA,CAAA,SAAA;EACiB,SAAA,EAAA,KAAA,EAAA;AAAjB,CAAA,GArQb,SAqQa,CArQH,WAqQG,CArQS,CAqQT,CAAA,CAAA,GAAA,KAAA;AAER;AACC;AAgBO;AAEU;AAAhB;AAAR;AAAO;AACV;AAA8B;AAAiB;AACtC;AACC;AACS;AAAR;AAAR,KA7QS,OA6QT,CAAA,UA7Q2B,MA6Q3B,GA7QoC,MA6QpC,CAAA,GAAA;EAAO,QAAA,EA5QC,eA4QD;EAiBY;AAAY;AACzB;AACC;EAEC,MAAA,CAAA,EA5RD,aA4RC;AAAR,CAAA,GAAA,CA3RE,SA2RF,CA3RY,WA2RZ,CA3RwB,CA2RxB,CAAA,MAAA,CAAA,CAAA,CAAA,SAAA,IAAA,GAAA;EAAO,IAAA,EA1RC,WA0RD;AAuMV,CAAA,GAheG,WAgemB,CAAA,GAAA,CA/dpB,SA+duC,CA/d7B,WA+d6B,CA/djB,CA+diB,CAAA,SAAA,CAAA,CAAA,CAAA,SAAA,IAAA,GAAA;EAAA,OAAA,EA9d1B,cA8d0B;AAChC,CAAA,GA9dL,WA8dK,CAAA,GAAA,CA7dP,UA6dO,CA7dI,CA6dJ,CAAA,SAAA,IAAA,GAAA;EACM,OAAA,EA9d2B,cA8d3B;AAAL,CAAA,GA9dmD,WA8dnD,CAAA,GAAA,CA7dR,WA6dQ,CA7dI,CA6dJ,CAAA,SAAA,IAAA,GAAA;EACJ,SAAA,EA7dW,gBA6dX;AAEG,CAAA,GA9dL,WA8dK,CAAA;AACmB;AAAlB,KA5dL,kBA4dK,CAAA,UA5dwB,MA4dxB,CAAA,GA3dT,WA2dS,CA3dG,CA2dH,CAAA,SAAA,CAAA,CAAA,SAAA;EAFP,SAAA,EAAA,KAAA,EAAA;AAAO,CAAA,GAtdN,CAsdM,GArdN,MAqdM,CAAA,KAAA,EAAA,KAAA,CAAA;AAgDV;AAAuC,KAlgB3B,cAkgB2B,CAAA,UAlgBF,MAkgBE,CAAA,GAlgBQ,OAkgBR,CAAA,MAjgBhC,kBAigBgC,CAjgBb,CAigBa,CAAA,EAAA,MAAA,CAAA;AAC7B;AACP;AAAe;AAalB;AAKA;AAoBA;AAA6B;AACD;AAAlB,KA5hBE,mBAAA,GA4hBF,uKAAA;AAAU;AA0FpB;AAAoC;AAAU;AAAkB;AAAO;AA4RvE;AAAwB,KAx4BnB,kBAw4BmB,CAAA,UAx4BU,MAw4BV,EAAA,UAAA,MAAA,CAAA,GAAA,CAv4BvB,cAu4BwC,CAv4BzB,CAu4ByB,CAAA,CAAgB,SAAA,CAAA,KAAA,CAAA,GAr4BtD,mBAq4BsD,GAp4BtD,CAo4BsD;AAAY;AAAR,KAj4BxD,iBAi4BwD,CAAA,UAh4BlD,MAg4BkD,EAAA,UAAA,MAAA,CAAA,GA93BzD,CA83ByD,SAAA,MA93BzC,kBA83ByC,CA93BtB,CA83BsB,CAAA,GA73B1D,WA63B0D,CA73B9C,kBA63B8C,CA73B3B,CA63B2B,CAAA,CA73BxB,CA63BwB,CAAA,CAAA,SAAA;EAAO,GAAA,EAAA,KAAA,EAAA;AASpE,CAAA,GAr4BI,OAq4BY,CAAA,MAr4BE,CAq4BM,EAAA,MAAA,CAAA,GAAA,KAAA,GAAA,KAAA;AAAA;AACP;AACe;AAAf;AAER,KAj4BG,eAi4BH,CAAA,UAj4B6B,MAi4B7B,EAAA,UAAA,MAAA,CAAA,GAAA;EACkB,QAAA,EAj4BhB,MAi4BgB,CAj4BT,iBAi4BS,CAj4BS,CAi4BT,EAj4BY,CAi4BZ,CAAA,EAAA,MAAA,CAAA;AAAG,CAAA;AAAtB;AACG;AAAR;AAA6B;AAAG;AAAnB;AAAe;AAC/B,UAv3BU,kBAAA,CAu3Bc;EAAA,QAAA,EAAA,cAAA,GAAA,uBAAA;EACP,MAAA,EAAA,aAAA;EACiB,IAAA,EAAA,oBAAA,GAAA,oBAAA;EAAjB,OAAA,EAAA,mBAAA;EACP,OAAA,EAAA,mBAAA,GAAA,uBAAA,GAAA,qBAAA,GAAA,YAAA;EAAkB,SAAA,EAAA,uBAAA,GAAA,0BAAA;AAAsB;AAAhB;AAAe,UA52BvC,YAAA,CA42BuC;EAyOjC,QAAA,EAplCL,eAolCc;EAAA,MAAA,EAnlChB,aAmlCgB;EAAM,IAAA,EAllCxB,WAklCwB;EAAkB,OAAA,EAjlCvC,cAilCuC;EAAM,OAAA,EAhlC7C,cAglC6C;EA8B3C,SAAA,EA7mCA,gBA6mCe;AAAA;AACd;AAAwB,UA1mC3B,YAAA,CA0mC2B;EAAa,YAAA,EAAA,aAAA;EAArB,qBAAA,EAAA,qBAAA;EAAO,WAAA,EAAA,MAAA;;;;;;;;;;;;;;;;;KArlCxB,2BAA2B,UACtC,yBAAyB,QAAQ,WAAW;;;;;;;;;;;;;;;;KAiBjC,kDACC,uBACX,QAAQ,GAAG,mBAAmB,+BAG5B,YACI,QAAQ,GAAG,mBAAmB,OAAO,aAAa,UACjD,gBAAgB,aAAa,GAAG,aAAa,UAC7C,sBACA,aAAa;UAIL,eAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiCV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgDe,yBACL,wBACA,iBAAiB,YAEzB,YACC;;;;;;;;;;;;;;;;iBAgBO;IAEd,QAAQ,gBAAgB;iBACL,yBAAyB,gBACtC,YACC,kBACP,QAAQ,QAAQ;;;;;;;;;;iBAiBG,YAAA,SACb,iBACC,kDAEP,QAAQ;;;;;;iBAuMW,mBAAA,SACb,iBACC,KAAK,4DACT,UACH;UACM;WACC,kBAAkB;;;;;;;;;iBA8CZ,uBAAA,UACN,oCACP;;iBAaa,cAAA;;iBAKA,iBAAA;;;;;;;;;iBAoBA,aAAA,UACN,kBAAkB;iBA0FZ,oBAAA,UAA8B,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4RhD,yBAAyB,gBAAgB,IAAI,QAAQ;iBASrD,yBACC,wBACA,eAAe,YAEvB,UACD,mBAAmB,GAAG,KAC3B,QAAQ,KAAK,gBAAgB,GAAG;iBACnB,yBACC,wBACA,iBAAiB,YACxB,kBAAkB,MAAM,gBAAgB;;;;;;;;;;;;iBAyOlC,SAAA,MAAe,kBAAkB;;;;;;;KA8BrC,eAAA,iBACC,gBAAgB,QAAQ,aAAa"}
package/dist/lib/env.js CHANGED
@@ -73,51 +73,31 @@ const NEON_ENV_VAR_KEYS = {
73
73
  baseUrl: "NEON_AI_GATEWAY_BASE_URL"
74
74
  }
75
75
  };
76
+ async function fetchEnv(config, options) {
77
+ return fetchEnvKeys(config, options, options.keys ?? null);
78
+ }
76
79
  /**
77
- * Resolve the project + branch this process should target, then fetch live Neon
78
- * connection strings for that branch over the network. Asynccalls the Neon API.
79
- *
80
- * Use this from build scripts and the `neon-env run` command, where top-level await is
81
- * fine. For application code that needs a synchronous bootstrap (most frameworks: Drizzle
82
- * config, Next.js, Vite, etc.), inject env vars via `neon-env run -- <cmd>` and use
83
- * {@link parseEnv} instead — same {@link NeonEnv} shape, but a sync call against
84
- * `process.env`.
85
- *
86
- * Filesystem- and env-agnostic: pass `projectId` and the target `branch` (name or id)
87
- * explicitly (resolve them in your CLI, e.g. neonctl).
80
+ * The {@link fetchEnv} body, with the key selection as a plain argument and no generic
81
+ * narrowing. Exists for callers that compute the selection at runtime notably
82
+ * {@link fetchEnvReusingSecrets}, which decides which keys it still needs by checking the
83
+ * branch since the public overload's `keys` is bound to a literal union those callers cannot
84
+ * produce without asserting.
88
85
  *
89
- * ```ts
90
- * import config from "../neon";
91
- * import { fetchEnv } from "@neon/env";
92
- *
93
- * const env = await fetchEnv(config, { projectId: "patient-art-12345", branch: "main" });
94
- * const db = drizzle(neon(env.postgres.databaseUrl), { schema });
95
- * ```
96
- *
97
- * The package does **not** mutate `process.env` or the filesystem itself.
86
+ * `keys === null` selects everything the policy enables.
98
87
  */
99
- async function fetchEnv(config, options) {
88
+ async function fetchEnvKeys(config, options, keys) {
100
89
  const api = options.api ?? createApiFromOptions(options);
101
90
  const projectId = options.projectId;
102
- const branches = await api.listBranches(projectId);
103
- if (branches.length === 0) throw new PlatformError(ErrorCode.BranchNotFound, [`fetchEnv: project ${projectId} has no branches.`, "Deploy your neon.ts policy (or create a branch) first, or pick a different project id."].join(" "), { details: { projectId } });
104
- const branchRef = options.branch ?? options.branchId;
105
- if (!branchRef) throw new PlatformError(ErrorCode.BranchNotFound, ["fetchEnv: no branch provided.", "Pass `branch` with a branch name (e.g. `main`) or id (`br-…`)."].join(" "), { details: { projectId } });
106
- const branch = resolveBranch(branchRef, branches);
107
- const desired = resolveConfig(config, {
108
- name: branch.name,
109
- id: branch.id,
110
- exists: true,
111
- ...branch.parentId ? { parentId: branch.parentId } : {},
112
- isDefault: branch.isDefault,
113
- isProtected: branch.protected,
114
- ...branch.expiresAt ? { expiresAt: branch.expiresAt } : {}
115
- });
91
+ const { branch, desired } = await resolveBranchPolicy(config, options, api);
92
+ const selection = keys ? new Set(keys) : null;
93
+ const wants = (key) => selection === null || selection.has(key);
94
+ const result = {};
116
95
  const [roles, databases] = await Promise.all([api.listBranchRoles(projectId, branch.id), api.listBranchDatabases(projectId, branch.id)]);
117
96
  const roleName = pickRoleName(roles, branch, options.roleName);
118
97
  const databaseName = pickDatabaseName(databases, branch, options.databaseName);
119
- const wantsAuth = desired.authEnabled;
120
- const wantsDataApi = desired.dataApiEnabled;
98
+ const K = NEON_ENV_VAR_KEYS;
99
+ const wantsAuth = desired.authEnabled && (wants(K.auth.baseUrl) || wants(K.auth.jwksUrl));
100
+ const wantsDataApi = desired.dataApiEnabled && wants(K.dataApi.url);
121
101
  const [pooled, unpooled, authSnapshot, dataApiSnapshot] = await Promise.all([
122
102
  api.getConnectionUri(projectId, {
123
103
  branchId: branch.id,
@@ -134,23 +114,20 @@ async function fetchEnv(config, options) {
134
114
  wantsAuth ? api.getNeonAuth(projectId, branch.id) : Promise.resolve(null),
135
115
  wantsDataApi ? api.getNeonDataApi(projectId, branch.id, databaseName) : Promise.resolve(null)
136
116
  ]);
137
- const result = {
138
- postgres: {
139
- databaseUrl: pooled.uri,
140
- databaseUrlUnpooled: unpooled.uri
141
- },
142
- branch: { name: branch.name }
143
- };
117
+ const postgres = {};
118
+ if (wants(K.postgres.databaseUrl)) postgres.databaseUrl = pooled.uri;
119
+ if (wants(K.postgres.databaseUrlUnpooled)) postgres.databaseUrlUnpooled = unpooled.uri;
120
+ if (Object.keys(postgres).length > 0) result.postgres = postgres;
121
+ if (wants(K.branch.name)) result.branch = { name: branch.name };
144
122
  if (wantsAuth) {
145
123
  if (!authSnapshot) throw new PlatformError(ErrorCode.NotFound, [`fetchEnv: branch policy enables auth but no Neon Auth integration is enabled on branch ${branch.name} (${branch.id}).`, "Enable it via `apply(config, { projectId, branchId })` (or `npx neonctl …`), in the Neon Console — then re-run fetchEnv. Or return auth.enabled=false."].join(" "), { details: {
146
124
  projectId,
147
125
  branchId: branch.id
148
126
  } });
149
- const envSource = options.env ?? process.env;
150
- result.auth = {
151
- baseUrl: resolveAuthBaseUrl(authSnapshot.baseUrl, envSource),
152
- jwksUrl: resolveAuthJwksUrl(authSnapshot.jwksUrl, envSource)
153
- };
127
+ const auth = {};
128
+ if (wants(K.auth.baseUrl)) auth.baseUrl = authSnapshot.baseUrl ?? "";
129
+ if (wants(K.auth.jwksUrl)) auth.jwksUrl = authSnapshot.jwksUrl ?? "";
130
+ result.auth = auth;
154
131
  }
155
132
  if (wantsDataApi) {
156
133
  if (!dataApiSnapshot) throw new PlatformError(ErrorCode.NotFound, [`fetchEnv: branch policy enables dataApi but no Data API integration is enabled on branch ${branch.name} (${branch.id}) database ${databaseName}.`, "Enable it via `apply(config, { projectId, branchId })` or in the Neon Console — then re-run fetchEnv. Or return dataApi.enabled=false."].join(" "), { details: {
@@ -160,40 +137,70 @@ async function fetchEnv(config, options) {
160
137
  } });
161
138
  result.dataApi = { url: dataApiSnapshot.url };
162
139
  }
163
- const wantsStorage = (desired.preview?.buckets.length ?? 0) > 0;
164
- const wantsAiGateway = desired.preview?.aiGatewayEnabled ?? false;
165
- if (wantsStorage || wantsAiGateway) {
166
- const secrets = await resolveCredentialSecrets({
167
- api,
168
- projectId,
169
- branchId: branch.id,
170
- branchName: branch.name,
171
- scopes: previewCredentialScopes(desired.preview),
172
- env: options.env ?? process.env,
173
- needStorage: wantsStorage,
174
- needApiToken: wantsAiGateway
175
- });
140
+ const storageEnabled = (desired.preview?.buckets.length ?? 0) > 0;
141
+ const gatewayEnabled = desired.preview?.aiGatewayEnabled ?? false;
142
+ const wantsStorage = storageEnabled && (wants(K.storage.accessKeyId) || wants(K.storage.secretAccessKey) || wants(K.storage.endpoint) || wants(K.storage.region));
143
+ const wantsGateway = gatewayEnabled && (wants(K.aiGateway.apiKey) || wants(K.aiGateway.baseUrl));
144
+ const wantsCredential = storageEnabled && (wants(K.storage.accessKeyId) || wants(K.storage.secretAccessKey)) || gatewayEnabled && wants(K.aiGateway.apiKey);
145
+ if (wantsStorage || wantsGateway) {
146
+ let storage = null;
176
147
  if (wantsStorage) {
177
- const storage = await api.getProjectBranchStorage(projectId, branch.id);
148
+ storage = await api.getProjectBranchStorage(projectId, branch.id);
178
149
  if (!storage) throw new PlatformError(ErrorCode.NotFound, [`fetchEnv: branch policy declares object storage (preview.buckets) but storage is not enabled on branch ${branch.name} (${branch.id}).`, "Enable it via `apply(config, { projectId, branchId })` (or in the Neon Console) — then re-run fetchEnv. Or remove preview.buckets."].join(" "), { details: {
179
150
  projectId,
180
151
  branchId: branch.id
181
152
  } });
182
- result.storage = {
183
- accessKeyId: secrets.accessKeyId,
184
- secretAccessKey: secrets.secretAccessKey,
185
- endpoint: storage.s3Endpoint,
186
- region: storage.region
187
- };
188
153
  }
189
- if (wantsAiGateway) result.aiGateway = {
190
- apiKey: secrets.apiToken,
191
- baseUrl: aiGatewayBaseUrl(branch.id, unpooled.uri)
192
- };
154
+ const secrets = wantsCredential ? await mintBranchCredential({
155
+ api,
156
+ projectId,
157
+ branchId: branch.id,
158
+ branchName: branch.name,
159
+ scopes: previewCredentialScopes(desired.preview)
160
+ }) : null;
161
+ if (storage) {
162
+ const storageEnv = {};
163
+ if (secrets && wants(K.storage.accessKeyId)) storageEnv.accessKeyId = secrets.accessKeyId;
164
+ if (secrets && wants(K.storage.secretAccessKey)) storageEnv.secretAccessKey = secrets.secretAccessKey;
165
+ if (wants(K.storage.endpoint)) storageEnv.endpoint = storage.s3Endpoint;
166
+ if (wants(K.storage.region)) storageEnv.region = storage.region;
167
+ result.storage = storageEnv;
168
+ }
169
+ if (wantsGateway) {
170
+ const gateway = {};
171
+ if (secrets && wants(K.aiGateway.apiKey)) gateway.apiKey = secrets.apiToken;
172
+ if (wants(K.aiGateway.baseUrl)) gateway.baseUrl = aiGatewayBaseUrl(branch.id, unpooled.uri);
173
+ result.aiGateway = gateway;
174
+ }
193
175
  }
194
176
  return result;
195
177
  }
196
178
  /**
179
+ * Resolve the target branch and evaluate the policy against it — the first thing any
180
+ * branch-scoped operation needs. Shared by {@link fetchEnv} and {@link fetchEnvReusingSecrets}
181
+ * so the two agree on which branch they're talking about and what it has enabled.
182
+ */
183
+ async function resolveBranchPolicy(config, options, api) {
184
+ const projectId = options.projectId;
185
+ const branches = await api.listBranches(projectId);
186
+ if (branches.length === 0) throw new PlatformError(ErrorCode.BranchNotFound, [`fetchEnv: project ${projectId} has no branches.`, "Deploy your neon.ts policy (or create a branch) first, or pick a different project id."].join(" "), { details: { projectId } });
187
+ const branchRef = options.branch ?? options.branchId;
188
+ if (!branchRef) throw new PlatformError(ErrorCode.BranchNotFound, ["fetchEnv: no branch provided.", "Pass `branch` with a branch name (e.g. `main`) or id (`br-…`)."].join(" "), { details: { projectId } });
189
+ const branch = resolveBranch(branchRef, branches);
190
+ return {
191
+ branch,
192
+ desired: resolveConfig(config, {
193
+ name: branch.name,
194
+ id: branch.id,
195
+ exists: true,
196
+ ...branch.parentId ? { parentId: branch.parentId } : {},
197
+ isDefault: branch.isDefault,
198
+ isProtected: branch.protected,
199
+ ...branch.expiresAt ? { expiresAt: branch.expiresAt } : {}
200
+ })
201
+ };
202
+ }
203
+ /**
197
204
  * Scopes the branch credential should carry for a resolved branch policy. Only object storage
198
205
  * and the AI Gateway *require* a credential; functions never force one (they have no credential
199
206
  * of their own), but `functions:invoke` is added to the scope set when a credential is already
@@ -211,29 +218,50 @@ function previewCredentialScopes(preview) {
211
218
  functions: preview.functions.length > 0
212
219
  });
213
220
  }
221
+ /** The `name` this tool stamps on every credential it mints, so it can recognize its own. */
222
+ function credentialName(branchName) {
223
+ return `neon-env ${branchName}`;
224
+ }
225
+ /** The env-var keys a branch credential's secrets surface under, in emit order. */
226
+ function credentialEnvKeys(flags) {
227
+ return [...flags.storage ? [NEON_ENV_VAR_KEYS.storage.accessKeyId, NEON_ENV_VAR_KEYS.storage.secretAccessKey] : [], ...flags.aiGateway ? [NEON_ENV_VAR_KEYS.aiGateway.apiKey] : []];
228
+ }
214
229
  /**
215
- * Resolve the branch credential's secrets, reusing the ones already in the env source when
216
- * present and minting a fresh `user` credential otherwise. The Neon API returns `api_token` /
217
- * `s3_secret_access_key` exactly once at mint time, so the persisted copies (e.g. in
218
- * `.env.local`, surfaced as `NEON_AI_GATEWAY_TOKEN` / `AWS_SECRET_ACCESS_KEY`) are the only way to
219
- * recover them — exactly how one-time Auth keys are round-tripped. Reuse is presence-based
220
- * (no extra bookkeeping vars): if every secret the enabled features need is already present,
221
- * reuse it; otherwise mint one credential covering all currently-needed scopes.
230
+ * Every OS-level env var a resolved branch policy produces, in emit order. Lets a caller
231
+ * subtract the ones it already holds and pass the rest as {@link fetchEnv}'s `keys`, without
232
+ * re-deriving which vars a policy implies.
222
233
  */
223
- async function resolveCredentialSecrets(args) {
224
- const sKeys = NEON_ENV_VAR_KEYS.storage;
225
- const aKeys = NEON_ENV_VAR_KEYS.aiGateway;
226
- const haveStorage = !args.needStorage || Boolean(args.env[sKeys.accessKeyId] && args.env[sKeys.secretAccessKey]);
227
- const haveApiToken = !args.needApiToken || Boolean(args.env[aKeys.apiKey]);
228
- if (haveStorage && haveApiToken) return {
229
- accessKeyId: args.env[sKeys.accessKeyId] ?? "",
230
- secretAccessKey: args.env[sKeys.secretAccessKey] ?? "",
231
- apiToken: args.env[aKeys.apiKey] ?? ""
232
- };
234
+ function policyEnvKeys(desired) {
235
+ const K = NEON_ENV_VAR_KEYS;
236
+ return [
237
+ K.postgres.databaseUrl,
238
+ K.postgres.databaseUrlUnpooled,
239
+ K.branch.name,
240
+ ...desired.authEnabled ? [K.auth.baseUrl, K.auth.jwksUrl] : [],
241
+ ...desired.dataApiEnabled ? [K.dataApi.url] : [],
242
+ ...(desired.preview?.buckets.length ?? 0) > 0 ? [
243
+ K.storage.accessKeyId,
244
+ K.storage.secretAccessKey,
245
+ K.storage.endpoint,
246
+ K.storage.region
247
+ ] : [],
248
+ ...desired.preview?.aiGatewayEnabled ? [K.aiGateway.apiKey, K.aiGateway.baseUrl] : []
249
+ ];
250
+ }
251
+ /**
252
+ * Mint the branch credential backing object storage / the AI Gateway.
253
+ *
254
+ * `api_token` and `s3_secret_access_key` come back **exactly once** — they are not stored
255
+ * server-side and the list endpoint returns metadata only — so the caller's copy is the only
256
+ * copy. That is why {@link fetchEnv} mints rather than fetches: there is nothing to fetch. A
257
+ * caller that already holds a valid copy should leave the secret keys out of `keys` (see
258
+ * {@link fetchEnvReusingSecrets}) instead of minting one it will discard.
259
+ */
260
+ async function mintBranchCredential(args) {
233
261
  const minted = await args.api.createCredential(args.projectId, args.branchId, {
234
262
  scopes: args.scopes,
235
263
  principalType: "user",
236
- name: `neon-env ${args.branchName}`
264
+ name: credentialName(args.branchName)
237
265
  });
238
266
  return {
239
267
  accessKeyId: minted.tokenId,
@@ -263,25 +291,6 @@ function aiGatewayHost(branchId, connectionUri) {
263
291
  function aiGatewayBaseUrl(branchId, connectionUri) {
264
292
  return `https://${aiGatewayHost(branchId, connectionUri)}`;
265
293
  }
266
- /**
267
- * Resolve the Neon Auth base URL to surface in `env.auth`. Prefer the value returned by
268
- * the integration (`getNeonAuth` includes it); fall back to whatever is already in the
269
- * caller's env source so older integrations created before `base_url` was returned still
270
- * round-trip through `env run`.
271
- */
272
- function resolveAuthBaseUrl(snapshotBaseUrl, source) {
273
- if (snapshotBaseUrl && snapshotBaseUrl !== "") return snapshotBaseUrl;
274
- return source[NEON_ENV_VAR_KEYS.auth.baseUrl] ?? "";
275
- }
276
- /**
277
- * Resolve the Neon Auth JWKS URL to surface in `env.auth`. Prefer the value returned by the
278
- * integration (`getNeonAuth` always includes `jwks_url`); fall back to the caller's env
279
- * source so the value still round-trips through `env run` if a snapshot ever omits it.
280
- */
281
- function resolveAuthJwksUrl(snapshotJwksUrl, source) {
282
- if (snapshotJwksUrl && snapshotJwksUrl !== "") return snapshotJwksUrl;
283
- return source[NEON_ENV_VAR_KEYS.auth.jwksUrl] ?? "";
284
- }
285
294
  function createApiFromOptions(options) {
286
295
  return createNeonApiFromOptions("fetchEnv", {
287
296
  ...options.apiKey ? { apiKey: options.apiKey } : {},
@@ -471,6 +480,7 @@ function parseEnv(config, scopeOrKeys) {
471
480
  const FILTERABLE_ENV_KEYS = {
472
481
  DATABASE_URL: ["postgres", "databaseUrl"],
473
482
  DATABASE_URL_UNPOOLED: ["postgres", "databaseUrlUnpooled"],
483
+ NEON_BRANCH: ["branch", "name"],
474
484
  NEON_AUTH_BASE_URL: ["auth", "baseUrl"],
475
485
  NEON_AUTH_JWKS_URL: ["auth", "jwksUrl"],
476
486
  NEON_DATA_API_URL: ["dataApi", "url"],
@@ -532,37 +542,26 @@ function parseFilteredEnv(source, keys) {
532
542
  * conditional namespaces are present.
533
543
  */
534
544
  function toEntries(env) {
535
- const out = {
536
- [NEON_ENV_VAR_KEYS.postgres.databaseUrl]: env.postgres.databaseUrl,
537
- [NEON_ENV_VAR_KEYS.postgres.databaseUrlUnpooled]: env.postgres.databaseUrlUnpooled
545
+ const out = {};
546
+ const put = (key, value) => {
547
+ if (value !== void 0) out[key] = value;
538
548
  };
539
- if (env.branch) out[NEON_ENV_VAR_KEYS.branch.name] = env.branch.name;
540
- const withAuth = env;
541
- if (withAuth.auth) {
542
- out[NEON_ENV_VAR_KEYS.auth.baseUrl] = withAuth.auth.baseUrl;
543
- out[NEON_ENV_VAR_KEYS.auth.jwksUrl] = withAuth.auth.jwksUrl;
544
- }
545
- const withDataApi = env;
546
- if (withDataApi.dataApi) out[NEON_ENV_VAR_KEYS.dataApi.url] = withDataApi.dataApi.url;
547
- const withStorage = env;
548
- if (withStorage.storage) {
549
- const s = withStorage.storage;
550
- const keys = NEON_ENV_VAR_KEYS.storage;
551
- out[keys.accessKeyId] = s.accessKeyId;
552
- out[keys.secretAccessKey] = s.secretAccessKey;
553
- out[keys.endpoint] = s.endpoint;
554
- out[keys.region] = s.region;
555
- }
556
- const withAiGateway = env;
557
- if (withAiGateway.aiGateway) {
558
- const keys = NEON_ENV_VAR_KEYS.aiGateway;
559
- const ai = withAiGateway.aiGateway;
560
- out[keys.apiKey] = ai.apiKey;
561
- out[keys.baseUrl] = ai.baseUrl;
562
- }
549
+ const K = NEON_ENV_VAR_KEYS;
550
+ put(K.postgres.databaseUrl, env.postgres?.databaseUrl);
551
+ put(K.postgres.databaseUrlUnpooled, env.postgres?.databaseUrlUnpooled);
552
+ put(K.branch.name, env.branch?.name);
553
+ put(K.auth.baseUrl, env.auth?.baseUrl);
554
+ put(K.auth.jwksUrl, env.auth?.jwksUrl);
555
+ put(K.dataApi.url, env.dataApi?.url);
556
+ put(K.storage.accessKeyId, env.storage?.accessKeyId);
557
+ put(K.storage.secretAccessKey, env.storage?.secretAccessKey);
558
+ put(K.storage.endpoint, env.storage?.endpoint);
559
+ put(K.storage.region, env.storage?.region);
560
+ put(K.aiGateway.apiKey, env.aiGateway?.apiKey);
561
+ put(K.aiGateway.baseUrl, env.aiGateway?.baseUrl);
563
562
  return out;
564
563
  }
565
564
  //#endregion
566
- export { NEON_ENV_VAR_KEYS, fetchEnv, parseEnv, toEntries };
565
+ export { NEON_ENV_VAR_KEYS, createApiFromOptions, credentialEnvKeys, credentialName, fetchEnv, fetchEnvKeys, parseEnv, policyEnvKeys, previewCredentialScopes, resolveBranchPolicy, toEntries };
567
566
 
568
567
  //# sourceMappingURL=env.js.map