@neondatabase/config 0.14.1 → 1.0.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 +41 -13
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/lib/define-config.d.ts.map +1 -1
- package/dist/lib/define-config.js +2 -1
- package/dist/lib/define-config.js.map +1 -1
- package/dist/lib/external-packages.d.ts +32 -0
- package/dist/lib/external-packages.d.ts.map +1 -0
- package/dist/lib/external-packages.js +47 -0
- package/dist/lib/external-packages.js.map +1 -0
- package/dist/lib/schema.d.ts +17 -3
- package/dist/lib/schema.d.ts.map +1 -1
- package/dist/lib/schema.js +91 -9
- package/dist/lib/schema.js.map +1 -1
- package/dist/lib/types.d.ts +105 -33
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js.map +1 -1
- package/dist/v1.d.ts +15 -5
- package/dist/v1.d.ts.map +1 -1
- package/dist/v1.js +2 -1
- package/dist/v1.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -43,36 +43,64 @@ A policy is split into a **static** existential set and a **dynamic** `branch` c
|
|
|
43
43
|
|
|
44
44
|
Service toggles accept `true` / `{}` / `{ enabled: true }` (enabled) and `false` / `{ enabled: false }` (disabled). Function slugs (record keys) must match `^[a-z0-9]{1,20}$`.
|
|
45
45
|
|
|
46
|
-
###
|
|
46
|
+
### Shipping a dependency's files (`externalPackages`)
|
|
47
47
|
|
|
48
|
-
A function's `source` is bundled with esbuild at deploy time, and
|
|
48
|
+
A function's `source` is bundled with esbuild at deploy time, and a package backed by a native `.node` binary cannot be bundled by anything: the binary is a compiled object the platform loads from a real path. `sharp` is the common case, and it does not even fail the build — it loads its binary through `createRequire`, which esbuild does not follow, so it bundles cleanly and then fails at invoke with `Could not load the "sharp" module`.
|
|
49
49
|
|
|
50
|
-
`externalPackages` is the
|
|
50
|
+
`externalPackages` is the deploy-time counterpart of Next.js's `serverExternalPackages`. Every entry is passed to esbuild's `external`, so the import survives into the bundle instead of being followed, and the package's own files are shipped into the archive beside the bundle so that import resolves:
|
|
51
51
|
|
|
52
52
|
```ts
|
|
53
53
|
export default defineConfig({
|
|
54
54
|
preview: {
|
|
55
55
|
functions: {
|
|
56
|
-
|
|
57
|
-
name: "
|
|
58
|
-
source: "./functions/
|
|
59
|
-
externalPackages: ["
|
|
56
|
+
resize: {
|
|
57
|
+
name: "Resize",
|
|
58
|
+
source: "./functions/resize.ts",
|
|
59
|
+
externalPackages: ["sharp"],
|
|
60
60
|
},
|
|
61
61
|
},
|
|
62
62
|
},
|
|
63
63
|
});
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
Each declared package is installed for the Functions runtime target — **linux-arm64, glibc** — into a throwaway directory, traced for the files it actually reaches, and copied into the archive under `node_modules/` with its directory layout intact. The layout matters: a `.node` addon finds its sibling shared libraries relative to its own directory, so a flattened tree fails to load.
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
Your own `node_modules` is never read for those files or modified. Its binaries are built for your machine rather than the deploy target, and a cross-platform install does not survive your next plain `npm install`, so the target's packages are resolved fresh on each deploy.
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
- **Backed by a native `.node` binary** — cannot be bundled by any bundler; the binary is a compiled object the platform loads from a real path. Such a package cannot work on Functions until the archive can carry files alongside the bundle. Listing it here does not help, it only moves the error from deploy to invoke.
|
|
70
|
+
Requirements, all checked at deploy time rather than left to fail at invoke:
|
|
72
71
|
|
|
73
|
-
|
|
72
|
+
- the package is installed in your project — the deploy stages the version you have, and refuses rather than guessing one
|
|
73
|
+
- the package publishes a linux-arm64 glibc build (`sharp` and most `@napi-rs/*` packages do; anything compiled from source at install time does not)
|
|
74
|
+
- `npm` is on `PATH`
|
|
75
|
+
- the archive stays within the deploy size limits — native binaries are large, so a couple of them is the practical ceiling
|
|
74
76
|
|
|
75
|
-
|
|
77
|
+
#### When the deploy warns about a package you did not declare
|
|
78
|
+
|
|
79
|
+
A deploy (and `neon dev`) reports a package it bundled that carries native code and is not in
|
|
80
|
+
`externalPackages`, because such a package deploys cleanly and then fails at invoke — `sharp`
|
|
81
|
+
produces no build error at all.
|
|
82
|
+
|
|
83
|
+
**The report is advisory and never fails a deploy.** It can only see that the package contains
|
|
84
|
+
compiled code, not whether your function reaches it. A package with a native accelerator behind
|
|
85
|
+
a working JavaScript fallback — `ws` with `bufferutil` installed is the common one — is reported
|
|
86
|
+
and is already correct; no change is needed.
|
|
87
|
+
|
|
88
|
+
Do not use `includeFiles: false` to silence it. That externalizes the package and ships nothing
|
|
89
|
+
for it, so an import that *is* reached then fails on every invoke.
|
|
90
|
+
|
|
91
|
+
#### Excluding a package's files
|
|
92
|
+
|
|
93
|
+
`includeFiles: false` externalizes an import without shipping anything for it. That is the escape hatch for a package that cannot be staged — no build for the runtime target, or too large — and that the function never actually reaches:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
externalPackages: ["sharp", { name: "canvas", includeFiles: false }],
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**An excluded package is not resolvable at runtime.** Nothing is shipped for it, so it throws `Cannot find module` if the function reaches it. It unblocks an import that is never evaluated; it does not make a dependency usable.
|
|
100
|
+
|
|
101
|
+
Entries are package names, optionally with a subpath (`pkg`, `@scope/pkg`, `pkg/sub`). A relative or absolute path is rejected at validation time. Files are staged per package, so a subpath narrows what esbuild leaves unresolved without narrowing what ships.
|
|
102
|
+
|
|
103
|
+
Under `neon dev` the list only keeps the package out of the bundle. Nothing is installed or copied, and it resolves from your own `node_modules` against your host architecture — which is what you want locally.
|
|
76
104
|
|
|
77
105
|
### Data API
|
|
78
106
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConflictReport, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DurationString, DurationUnit, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput } from "./lib/types.js";
|
|
1
|
+
import { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConflictReport, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DurationString, DurationUnit, ExternalPackageDef, ExternalPackageEntry, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedExternalPackage, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput } from "./lib/types.js";
|
|
2
2
|
import { ConfigLoadError, ConfigValidationError, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, isPartialBranchCreateError, isPlatformError } from "./lib/errors.js";
|
|
3
3
|
import { CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, DeployFunctionInput, EnableDataApiInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, UpdateBranchInput } from "./lib/neon-api.js";
|
|
4
4
|
import { createNeonApiFromOptions } from "./lib/auth.js";
|
|
5
5
|
import { CredentialFeatureFlags, credentialScopesSatisfied, deriveCredentialScopes } from "./lib/credentials.js";
|
|
6
6
|
import { defineConfig, resolveConfig } from "./lib/define-config.js";
|
|
7
7
|
import { DiffOptions, DiffResult, PlanStep, RemotePreviewState, RemoteServiceState, RemoteState, diffConfig } from "./lib/diff.js";
|
|
8
|
+
import { externalPackageRoot, packagesToStage } from "./lib/external-packages.js";
|
|
8
9
|
import { LoadConfigOptions, loadConfigFromFile } from "./lib/loader.js";
|
|
9
10
|
import { createRealNeonApi } from "./lib/neon-api-real.js";
|
|
10
11
|
import { errors, schemas } from "./v1.js";
|
|
11
|
-
export { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConfigLoadError, ConfigValidationError, ConflictReport, CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, CredentialFeatureFlags, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DeployFunctionInput, DiffOptions, DiffResult, DurationString, DurationUnit, EnableDataApiInput, ErrorCode, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, GetConnectionUriInput, LoadConfigOptions, MissingContextError, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, PartialBranchCreateError, PlanStep, PlatformError, PostgresConfig, PreviewInput, PreviewTuning, PushAbortedError, PushConflictError, PushResult, RemotePreviewState, RemoteServiceState, RemoteState, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput, UpdateBranchInput, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, resolveConfig, schemas };
|
|
12
|
+
export { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConfigLoadError, ConfigValidationError, ConflictReport, CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, CredentialFeatureFlags, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DeployFunctionInput, DiffOptions, DiffResult, DurationString, DurationUnit, EnableDataApiInput, ErrorCode, ExternalPackageDef, ExternalPackageEntry, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, GetConnectionUriInput, LoadConfigOptions, MissingContextError, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, PartialBranchCreateError, PlanStep, PlatformError, PostgresConfig, PreviewInput, PreviewTuning, PushAbortedError, PushConflictError, PushResult, RemotePreviewState, RemoteServiceState, RemoteState, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedExternalPackage, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput, UpdateBranchInput, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, externalPackageRoot, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, packagesToStage, resolveConfig, schemas };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ConfigLoadError, ConfigValidationError, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, isPartialBranchCreateError, isPlatformError } from "./lib/errors.js";
|
|
2
|
+
import { externalPackageRoot, packagesToStage } from "./lib/external-packages.js";
|
|
2
3
|
import { createRealNeonApi } from "./lib/neon-api-real.js";
|
|
3
4
|
import { createNeonApiFromOptions } from "./lib/auth.js";
|
|
4
5
|
import { credentialScopesSatisfied, deriveCredentialScopes } from "./lib/credentials.js";
|
|
@@ -7,4 +8,4 @@ import { diffConfig } from "./lib/diff.js";
|
|
|
7
8
|
import { loadConfigFromFile } from "./lib/loader.js";
|
|
8
9
|
import { DATA_API_AUTH_PROVIDERS } from "./lib/types.js";
|
|
9
10
|
import { errors, schemas } from "./v1.js";
|
|
10
|
-
export { ConfigLoadError, ConfigValidationError, DATA_API_AUTH_PROVIDERS, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, resolveConfig, schemas };
|
|
11
|
+
export { ConfigLoadError, ConfigValidationError, DATA_API_AUTH_PROVIDERS, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, externalPackageRoot, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, packagesToStage, resolveConfig, schemas };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-config.d.ts","names":[],"sources":["../../src/lib/define-config.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"define-config.d.ts","names":[],"sources":["../../src/lib/define-config.ts"],"mappings":";;;;;;AAyBoB;AAYI;AACR;AAAf,KADI,mBACJ,CAAA,OAAA,CAAA,GAAA,cAAA,CAAe,OAAf,CAAA,SAAA,IAAA,GAAA,CACI,OADJ,CAAA,SAAA,CAAA;EACI,YAAA,EAAA,UAAA;AAAO,CAAA,CAAA,GAAA,KAAA,GAAA,IAAA,GAAA,KAAA;AAiBZ;AAqBA;AAAwB;AACH;AAApB;AACkB;AAAf;AACC;AAAU;AACV;AACD,KA1BQ,oBAAA,GA0BR,+QAAA;AAAU;AAAY;AAAC;AAoBH;AAAa;AACJ;AAAI;AAEnC;AAC8B;AAAI;AAAS;AAoC7C;AAA4B;AACR;AACG;AACA;AAQf,KA5EI,YA4EJ,CAAA,IAAA,EAAA,OAAA,CAAA,GA3EP,mBA2EO,CA3Ea,OA2Eb,CAAA,SAAA,IAAA,GA1EJ,cA0EI,CA1EW,IA0EX,CAAA,SAAA,IAAA,GAzEH,OAyEG,GAzEO,YAyEP,GAxEH,oBAwEG,GAvEJ,OAuEI,GAvEM,YAuEN;AAAO;AAIS;AAAM;AAAnB;AAIA;AAAU;AAAmC;AAApB;AACX;AAAf;AACC;AAAM;AAAS;AAAtB;AAAM;AA4BV;AAA6B;AACpB;AACA,KA3FJ,mBA2FI,CAAA,OAAA,CAAA,GAAA,CA3F4B,OA2F5B,SAAA;EACN,SAAA,EAAA,KAAA,EAAA;AAAoB,CAAA,GAAA;EA0KP,SAAA,EAAA,iBArQiB,IAAI;gBAEnC;;;4BAC8B,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoCpB,gCACI,kEACG,4DACA;SAQf,OAAO;YAIJ,aAAa,MAAM;YAInB,UAAU,eAAe,oBAAoB;WAC9C,eAAe;IACrB,OAAO,MAAM,SAAS;;;;;;;;iBA4BV,aAAA,SACP,gBACA,eACN;;;;;;iBA0Ka,eAAA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ConfigValidationError } from "./errors.js";
|
|
2
2
|
import { parseBranchTtl } from "./duration.js";
|
|
3
|
+
import { normalizeExternalPackage } from "./external-packages.js";
|
|
3
4
|
import { branchTuningSchema, configInputSchema, formatZodIssues } from "./schema.js";
|
|
4
5
|
//#region src/lib/define-config.ts
|
|
5
6
|
/** Default deploy parameters applied to functions that omit them in `neon.ts`. */
|
|
@@ -150,7 +151,7 @@ function resolveFunctionConfig(slug, def, tuning) {
|
|
|
150
151
|
source: def.source,
|
|
151
152
|
env: { ...def.env ?? {} },
|
|
152
153
|
runtime: tuning.runtime ?? DEFAULT_FUNCTION_RUNTIME,
|
|
153
|
-
...def.externalPackages ? { externalPackages:
|
|
154
|
+
...def.externalPackages ? { externalPackages: def.externalPackages.map(normalizeExternalPackage) } : {},
|
|
154
155
|
...def.dev ? { dev: def.dev } : {}
|
|
155
156
|
};
|
|
156
157
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-config.js","names":[],"sources":["../../src/lib/define-config.ts"],"sourcesContent":["import { parseBranchTtl } from \"./duration.js\";\nimport { ConfigValidationError } from \"./errors.js\";\nimport {\n\tbranchTuningSchema,\n\tconfigInputSchema,\n\tformatZodIssues,\n} from \"./schema.js\";\nimport type {\n\tBranchTarget,\n\tBranchTuning,\n\tBranchTuningFn,\n\tBucketDef,\n\tConfig,\n\tDataApiInput,\n\tDataApiSettings,\n\tFunctionDef,\n\tFunctionTuning,\n\tPreviewInput,\n\tResolvedBranchConfig,\n\tResolvedDataApiConfig,\n\tResolvedFunctionConfig,\n\tResolvedPreviewConfig,\n\tServiceEnabled,\n\tServiceToggleInput,\n} from \"./types.js\";\n\n/** Default deploy parameters applied to functions that omit them in `neon.ts`. */\nconst DEFAULT_FUNCTION_RUNTIME = \"nodejs24\" as const;\n\nconst REGION_PREFIX = /^(aws|azure|gcp)-/;\n\n/**\n * Whether a `dataApi` toggle is **enabled and verified by Neon Auth** at the type level: it is\n * on (see {@link ServiceEnabled}) and not the explicit `authProvider: \"external\"` variant\n * (so the default / `\"neon\"` provider). This is the case that requires top-level Neon Auth.\n */\ntype DataApiUsesNeonAuth<DataApi> =\n\tServiceEnabled<DataApi> extends true\n\t\t? [DataApi] extends [{ authProvider: \"external\" }]\n\t\t\t? false\n\t\t\t: true\n\t\t: false;\n\n/**\n * Human-readable hint surfaced as the **expected type** of `dataApi` when a Neon-Auth Data\n * API is declared without Neon Auth enabled (see {@link DataApiField}). TypeScript prints the\n * offending value against this string literal — `Type 'true' is not assignable to type\n * '…requires `auth: true`…'` — which points straight at the fix, instead of the opaque\n * `Type 'true' is not assignable to type 'never'` an intersection guard produces.\n *\n * It documents **both** fixes: enabling Neon Auth (`auth: true`), and running the Data API\n * *without* Neon Auth by verifying a third-party IdP (`authProvider: 'external'` + `jwksUrl`).\n */\n// Exported (type-only) for the type tests in `define-config.test-d.ts`; intentionally not\n// re-exported from `v1.ts` / `index.ts`, so it stays an internal implementation detail.\nexport type NeonAuthRequiredHint =\n\t\"`dataApi` with Neon Auth (the default `authProvider: 'neon'`) requires Neon Auth, so add `auth: true`. To enable the Data API WITHOUT Neon Auth, verify a third-party IdP instead: `dataApi: { authProvider: 'external', jwksUrl: 'https://your-idp/.well-known/jwks.json' }`\";\n\n/**\n * Static cross-field guard for {@link defineConfig}, expressed as the **type of the `dataApi`\n * field** rather than an intersected requirement on `auth`.\n *\n * - A Neon-Auth Data API (`authProvider: \"neon\"`, the default) with top-level `auth` enabled,\n * or any external Data API: the field keeps its normal `DataApi & DataApiInput` type (the\n * `& DataApiInput` preserves member autocomplete; the `const DataApi` still types the\n * returned {@link Config}).\n * - A Neon-Auth Data API **without** `auth` enabled: the field's expected type collapses to\n * the {@link NeonAuthRequiredHint} message, so the author sees the rule (and the two fixes)\n * right on the `dataApi` value.\n *\n * The runtime `superRefine` in {@link configInputSchema} enforces the same invariant for\n * non-typed (plain-JS) callers, so the behavior is identical — only the type-level message\n * changes.\n */\n// Exported (type-only) for the type tests in `define-config.test-d.ts`; intentionally not\n// re-exported from `v1.ts` / `index.ts`, so it stays an internal implementation detail.\nexport type DataApiField<Auth, DataApi> =\n\tDataApiUsesNeonAuth<DataApi> extends true\n\t\t? ServiceEnabled<Auth> extends true\n\t\t\t? DataApi & DataApiInput\n\t\t\t: NeonAuthRequiredHint\n\t\t: DataApi & DataApiInput;\n\n/**\n * Autocomplete bridge for the nested `preview.functions` / `preview.buckets` slug objects.\n *\n * {@link PreviewInput} types those records with a string index signature\n * (`Record<string, FunctionDef>` / `Record<string, BucketDef>`). When `defineConfig` infers\n * `const Preview`, every authored slug becomes a **named** property on the inferred literal\n * (e.g. `{ hello: { name; source } }`), and a named property **shadows** the index signature\n * when the editor computes the contextual type of that slug's value — so the rest of\n * {@link FunctionDef} / {@link BucketDef} (`env`, `dev`, `access`, …) never surfaces as\n * completions inside `hello: { … }` / `uploads: { … }`.\n *\n * Re-declaring each inferred slug's value as `FunctionDef` / `BucketDef` (a *named* member, via\n * a mapped type over the already-inferred keys) puts those members back onto the contextual\n * type without going through an index signature, which restores autocomplete. Intersected with\n * `Preview & PreviewInput` it neither widens what is accepted (the values were already\n * `FunctionDef` / `BucketDef`) nor perturbs the inferred `const Preview` — so slug inference for\n * `BranchTuningFn<Preview>` and the returned {@link Config} is unchanged.\n */\ntype PreviewAutocomplete<Preview> = (Preview extends { functions: infer F }\n\t? { functions: { [Slug in keyof F]: FunctionDef } }\n\t: unknown) &\n\t(Preview extends { buckets: infer B }\n\t\t? { buckets: { [Name in keyof B]: BucketDef } }\n\t\t: unknown);\n\n/**\n * Validate and freeze a Neon branch policy.\n *\n * Used at the top of `neon.ts`:\n * ```ts\n * import { defineConfig } from \"@neon/config/v1\";\n *\n * export default defineConfig({\n * auth: true,\n * preview: {\n * functions: {\n * hello: { name: \"Hello\", source: \"./functions/hello.ts\", dev: { port: 8787 } },\n * },\n * },\n * branch: (branch) => ({ protected: branch.name === \"main\" }),\n * });\n * ```\n *\n * The policy is split into a **static** existential set (top-level `auth` / `dataApi`\n * toggles and the beta `preview` block) and a **dynamic** per-branch `branch` closure. The\n * static half determines which secrets exist — so `NeonEnv<typeof config>` and `parseEnv`\n * are exact — while the closure can only *tune* a branch (lifecycle, compute, per-function\n * deploy settings), never change what exists.\n *\n * The `branch` callback receives a read-only {@link BranchTarget} descriptor of the branch\n * being decided for (not a live handle); switch on its facts (`branch.name`,\n * `branch.isDefault`, `branch.exists`, …) and **return** the desired tuning. It runs in two\n * modes: against an existing branch (fields populated from Neon) and during pre-create\n * evaluation (`exists: false`, `id` undefined).\n *\n * Pure: no I/O, no side effects. The static parts are validated here; the closure's output\n * is validated every time it is evaluated so errors point at the concrete branch target.\n */\nexport function defineConfig<\n\tconst Auth extends ServiceToggleInput | undefined = undefined,\n\tconst DataApi extends DataApiInput | undefined = undefined,\n\tconst Preview extends PreviewInput | undefined = undefined,\n>(input: {\n\t// Each field is intersected with its concrete interface (not just typed as the bare\n\t// generic). The generic alone — e.g. `preview?: Preview` — gives editors no members to\n\t// complete against in the object-literal position (they see `{} | undefined`), so you\n\t// lose hints for `aiGateway` / `functions` / `buckets`. `& PreviewInput` restores the\n\t// full shape for autocomplete while still inferring the `const` literal that types the\n\t// `branch` closure's slugs (BranchTuningFn<Preview>) and the returned Config.\n\tauth?: Auth & ServiceToggleInput;\n\t// The `dataApi` field carries the Neon-Auth cross-field guard at the type level (see\n\t// `DataApiField`): a Neon-Auth Data API without `auth` enabled surfaces a readable hint\n\t// as the field's expected type instead of collapsing the value to `never`.\n\tdataApi?: DataApiField<Auth, DataApi>;\n\t// `& PreviewInput` restores top-level member hints (aiGateway/functions/buckets);\n\t// `& PreviewAutocomplete<Preview>` restores hints *inside* each function/bucket slug\n\t// object (see `PreviewAutocomplete`), which the bare index signature otherwise hides.\n\tpreview?: Preview & PreviewInput & PreviewAutocomplete<Preview>;\n\tbranch?: BranchTuningFn<Preview>;\n}): Config<Auth, DataApi, Preview> {\n\tif (typeof input === \"function\") {\n\t\tthrow new ConfigValidationError([\n\t\t\t\"defineConfig now expects an object, not a function: `export default defineConfig({ auth: true, preview: { … }, branch: (branch) => ({ … }) })`.\",\n\t\t\t\"The static services/preview set moved to the top level; per-branch logic moved into the `branch` closure.\",\n\t\t]);\n\t}\n\tif (input === null || typeof input !== \"object\") {\n\t\tthrow new ConfigValidationError([\n\t\t\t\"defineConfig expects a configuration object: `export default defineConfig({ … })`.\",\n\t\t]);\n\t}\n\n\tconst parsed = configInputSchema.safeParse(input);\n\tif (!parsed.success) {\n\t\tthrow new ConfigValidationError(formatZodIssues(parsed.error));\n\t}\n\n\treturn Object.freeze({ ...input }) as Config<Auth, DataApi, Preview>;\n}\n\n/**\n * Evaluate a branch policy for a specific branch target and return a normalized config.\n *\n * Merges the static existential set (services + preview functions/buckets) with the\n * per-branch tuning returned by the `branch` closure into the same {@link\n * ResolvedBranchConfig} the rest of the runtime (diff / push / fetchEnv) consumes.\n */\nexport function resolveConfig(\n\tconfig: Config,\n\tbranch: BranchTarget,\n): ResolvedBranchConfig {\n\tconst tuning = evaluateBranchTuning(config.branch, branch);\n\n\tconst resolved: ResolvedBranchConfig = {\n\t\tauthEnabled: isServiceEnabled(config.auth),\n\t\tdataApiEnabled: isDataApiEnabled(config.dataApi),\n\t};\n\tconst dataApi = resolveDataApi(config.dataApi);\n\tif (dataApi) resolved.dataApi = dataApi;\n\tif (tuning.parent !== undefined) resolved.parent = tuning.parent;\n\tif (tuning.ttl !== undefined) {\n\t\t// `branchTuningSchema` already validated `ttl` with the same `parseBranchTtl`, so\n\t\t// this only converts the validated value to seconds — it cannot fail here.\n\t\tconst parsedTtl = parseBranchTtl(tuning.ttl);\n\t\tif (!(\"error\" in parsedTtl)) resolved.ttlSeconds = parsedTtl.seconds;\n\t}\n\tif (tuning.protected !== undefined) resolved.protected = tuning.protected;\n\tif (tuning.postgres?.computeSettings) {\n\t\tresolved.postgres = {\n\t\t\tcomputeSettings: { ...tuning.postgres.computeSettings },\n\t\t};\n\t}\n\n\tconst preview = resolvePreviewConfig(config.preview, tuning);\n\tif (preview) resolved.preview = preview;\n\n\treturn resolved;\n}\n\n/**\n * Run the `branch` closure (when present) for the target and validate its output. The\n * closure is optional — a fully static policy resolves with empty tuning.\n */\nfunction evaluateBranchTuning(\n\tbranchFn: BranchTuningFn | undefined,\n\ttarget: BranchTarget,\n): BranchTuning {\n\tif (!branchFn) return {};\n\tlet raw: unknown;\n\ttry {\n\t\traw = branchFn(Object.freeze({ ...target }));\n\t} catch (cause) {\n\t\tthrow new ConfigValidationError([\n\t\t\t`Branch policy threw while evaluating branch \"${target.name}\".`,\n\t\t\t(cause as Error)?.message ?? String(cause),\n\t\t]);\n\t}\n\tconst parsed = branchTuningSchema.safeParse(raw ?? {});\n\tif (!parsed.success) {\n\t\tthrow new ConfigValidationError(formatZodIssues(parsed.error));\n\t}\n\treturn parsed.data as BranchTuning;\n}\n\nfunction isServiceEnabled(toggle: ServiceToggleInput | undefined): boolean {\n\tif (toggle === undefined) return false;\n\tif (typeof toggle === \"boolean\") return toggle;\n\treturn toggle.enabled !== false;\n}\n\n/** Whether a {@link DataApiInput} is enabled (present object/`true` unless `enabled: false`). */\nfunction isDataApiEnabled(input: DataApiInput | undefined): boolean {\n\tif (input === undefined) return false;\n\tif (typeof input === \"boolean\") return input;\n\treturn input.enabled !== false;\n}\n\n/**\n * Normalize a {@link DataApiInput} into a {@link ResolvedDataApiConfig}, or `undefined` when\n * the Data API is not enabled. `authProvider` defaults to `\"neon\"`; the external-IdP wiring\n * is carried through only for the `\"external\"` provider; `settings` is copied with its\n * `undefined` entries dropped so diffing only considers fields the policy actually set.\n */\nfunction resolveDataApi(\n\tinput: DataApiInput | undefined,\n): ResolvedDataApiConfig | undefined {\n\tif (!isDataApiEnabled(input)) return undefined;\n\tif (typeof input !== \"object\") {\n\t\t// Bare `true`: enabled with Neon Auth and all-default settings.\n\t\treturn { authProvider: \"neon\" };\n\t}\n\tconst authProvider = input.authProvider ?? \"neon\";\n\tconst resolved: ResolvedDataApiConfig = { authProvider };\n\tif (authProvider === \"external\") {\n\t\tif (input.jwksUrl !== undefined) resolved.jwksUrl = input.jwksUrl;\n\t\tif (input.providerName !== undefined)\n\t\t\tresolved.providerName = input.providerName;\n\t\tif (input.jwtAudience !== undefined)\n\t\t\tresolved.jwtAudience = input.jwtAudience;\n\t}\n\tconst settings = normalizeDataApiSettings(input.settings);\n\tif (settings) resolved.settings = settings;\n\treturn resolved;\n}\n\n/** Copy a {@link DataApiSettings}, dropping `undefined` entries; `undefined` when empty. */\nfunction normalizeDataApiSettings(\n\tsettings: DataApiSettings | undefined,\n): DataApiSettings | undefined {\n\tif (!settings) return undefined;\n\tconst out: DataApiSettings = {};\n\tfor (const [key, value] of Object.entries(settings)) {\n\t\tif (value !== undefined) {\n\t\t\t(out as Record<string, unknown>)[key] = value;\n\t\t}\n\t}\n\treturn Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * Normalize the static {@link PreviewInput} (merged with per-branch function tuning) into a\n * {@link ResolvedPreviewConfig}. Returns `undefined` when the policy declares no `preview`\n * block so the field can be omitted entirely. Function slugs / bucket names come from the\n * record keys.\n */\nfunction resolvePreviewConfig(\n\tpreview: PreviewInput | undefined,\n\ttuning: BranchTuning,\n): ResolvedPreviewConfig | undefined {\n\tif (!preview) return undefined;\n\tconst fnTuning = tuning.preview?.functions ?? {};\n\tconst functions: ResolvedFunctionConfig[] = Object.entries(\n\t\tpreview.functions ?? {},\n\t).map(([slug, def]) =>\n\t\tresolveFunctionConfig(slug, def, fnTuning[slug] ?? {}),\n\t);\n\tconst buckets = Object.entries(preview.buckets ?? {}).map(\n\t\t([name, def]) => ({\n\t\t\tname,\n\t\t\taccess: def.access ?? \"private\",\n\t\t}),\n\t);\n\treturn {\n\t\tfunctions,\n\t\tbuckets,\n\t\taiGatewayEnabled: isServiceEnabled(preview.aiGateway),\n\t};\n}\n\nfunction resolveFunctionConfig(\n\tslug: string,\n\tdef: FunctionDef,\n\ttuning: FunctionTuning,\n): ResolvedFunctionConfig {\n\treturn {\n\t\tslug,\n\t\tname: def.name,\n\t\tsource: def.source,\n\t\tenv: { ...(def.env ?? {}) },\n\t\truntime: tuning.runtime ?? DEFAULT_FUNCTION_RUNTIME,\n\t\t// Copied only when declared, so a policy without it resolves unchanged. Both\n\t\t// bundlers read it; `neon dev` mirrors it so a local run bundles like a deploy.\n\t\t...(def.externalPackages\n\t\t\t? { externalPackages: [...def.externalPackages] }\n\t\t\t: {}),\n\t\t// Passed through untouched (no defaults); only `neon dev` reads it.\n\t\t...(def.dev ? { dev: def.dev } : {}),\n\t};\n}\n\n/**\n * Normalize a region identifier to Neon's `<cloud>-<region>` format. When the user writes\n * `us-east-1` we assume `aws-us-east-1`. Pure helper used by both the validator and the\n * NeonApi adapter.\n */\nexport function normalizeRegion(region: string): string {\n\tif (REGION_PREFIX.test(region)) return region;\n\treturn `aws-${region}`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"define-config.js","names":[],"sources":["../../src/lib/define-config.ts"],"sourcesContent":["import { parseBranchTtl } from \"./duration.js\";\nimport { ConfigValidationError } from \"./errors.js\";\nimport { normalizeExternalPackage } from \"./external-packages.js\";\nimport {\n\tbranchTuningSchema,\n\tconfigInputSchema,\n\tformatZodIssues,\n} from \"./schema.js\";\nimport type {\n\tBranchTarget,\n\tBranchTuning,\n\tBranchTuningFn,\n\tBucketDef,\n\tConfig,\n\tDataApiInput,\n\tDataApiSettings,\n\tFunctionDef,\n\tFunctionTuning,\n\tPreviewInput,\n\tResolvedBranchConfig,\n\tResolvedDataApiConfig,\n\tResolvedFunctionConfig,\n\tResolvedPreviewConfig,\n\tServiceEnabled,\n\tServiceToggleInput,\n} from \"./types.js\";\n\n/** Default deploy parameters applied to functions that omit them in `neon.ts`. */\nconst DEFAULT_FUNCTION_RUNTIME = \"nodejs24\" as const;\n\nconst REGION_PREFIX = /^(aws|azure|gcp)-/;\n\n/**\n * Whether a `dataApi` toggle is **enabled and verified by Neon Auth** at the type level: it is\n * on (see {@link ServiceEnabled}) and not the explicit `authProvider: \"external\"` variant\n * (so the default / `\"neon\"` provider). This is the case that requires top-level Neon Auth.\n */\ntype DataApiUsesNeonAuth<DataApi> =\n\tServiceEnabled<DataApi> extends true\n\t\t? [DataApi] extends [{ authProvider: \"external\" }]\n\t\t\t? false\n\t\t\t: true\n\t\t: false;\n\n/**\n * Human-readable hint surfaced as the **expected type** of `dataApi` when a Neon-Auth Data\n * API is declared without Neon Auth enabled (see {@link DataApiField}). TypeScript prints the\n * offending value against this string literal — `Type 'true' is not assignable to type\n * '…requires `auth: true`…'` — which points straight at the fix, instead of the opaque\n * `Type 'true' is not assignable to type 'never'` an intersection guard produces.\n *\n * It documents **both** fixes: enabling Neon Auth (`auth: true`), and running the Data API\n * *without* Neon Auth by verifying a third-party IdP (`authProvider: 'external'` + `jwksUrl`).\n */\n// Exported (type-only) for the type tests in `define-config.test-d.ts`; intentionally not\n// re-exported from `v1.ts` / `index.ts`, so it stays an internal implementation detail.\nexport type NeonAuthRequiredHint =\n\t\"`dataApi` with Neon Auth (the default `authProvider: 'neon'`) requires Neon Auth, so add `auth: true`. To enable the Data API WITHOUT Neon Auth, verify a third-party IdP instead: `dataApi: { authProvider: 'external', jwksUrl: 'https://your-idp/.well-known/jwks.json' }`\";\n\n/**\n * Static cross-field guard for {@link defineConfig}, expressed as the **type of the `dataApi`\n * field** rather than an intersected requirement on `auth`.\n *\n * - A Neon-Auth Data API (`authProvider: \"neon\"`, the default) with top-level `auth` enabled,\n * or any external Data API: the field keeps its normal `DataApi & DataApiInput` type (the\n * `& DataApiInput` preserves member autocomplete; the `const DataApi` still types the\n * returned {@link Config}).\n * - A Neon-Auth Data API **without** `auth` enabled: the field's expected type collapses to\n * the {@link NeonAuthRequiredHint} message, so the author sees the rule (and the two fixes)\n * right on the `dataApi` value.\n *\n * The runtime `superRefine` in {@link configInputSchema} enforces the same invariant for\n * non-typed (plain-JS) callers, so the behavior is identical — only the type-level message\n * changes.\n */\n// Exported (type-only) for the type tests in `define-config.test-d.ts`; intentionally not\n// re-exported from `v1.ts` / `index.ts`, so it stays an internal implementation detail.\nexport type DataApiField<Auth, DataApi> =\n\tDataApiUsesNeonAuth<DataApi> extends true\n\t\t? ServiceEnabled<Auth> extends true\n\t\t\t? DataApi & DataApiInput\n\t\t\t: NeonAuthRequiredHint\n\t\t: DataApi & DataApiInput;\n\n/**\n * Autocomplete bridge for the nested `preview.functions` / `preview.buckets` slug objects.\n *\n * {@link PreviewInput} types those records with a string index signature\n * (`Record<string, FunctionDef>` / `Record<string, BucketDef>`). When `defineConfig` infers\n * `const Preview`, every authored slug becomes a **named** property on the inferred literal\n * (e.g. `{ hello: { name; source } }`), and a named property **shadows** the index signature\n * when the editor computes the contextual type of that slug's value — so the rest of\n * {@link FunctionDef} / {@link BucketDef} (`env`, `dev`, `access`, …) never surfaces as\n * completions inside `hello: { … }` / `uploads: { … }`.\n *\n * Re-declaring each inferred slug's value as `FunctionDef` / `BucketDef` (a *named* member, via\n * a mapped type over the already-inferred keys) puts those members back onto the contextual\n * type without going through an index signature, which restores autocomplete. Intersected with\n * `Preview & PreviewInput` it neither widens what is accepted (the values were already\n * `FunctionDef` / `BucketDef`) nor perturbs the inferred `const Preview` — so slug inference for\n * `BranchTuningFn<Preview>` and the returned {@link Config} is unchanged.\n */\ntype PreviewAutocomplete<Preview> = (Preview extends { functions: infer F }\n\t? { functions: { [Slug in keyof F]: FunctionDef } }\n\t: unknown) &\n\t(Preview extends { buckets: infer B }\n\t\t? { buckets: { [Name in keyof B]: BucketDef } }\n\t\t: unknown);\n\n/**\n * Validate and freeze a Neon branch policy.\n *\n * Used at the top of `neon.ts`:\n * ```ts\n * import { defineConfig } from \"@neon/config/v1\";\n *\n * export default defineConfig({\n * auth: true,\n * preview: {\n * functions: {\n * hello: { name: \"Hello\", source: \"./functions/hello.ts\", dev: { port: 8787 } },\n * },\n * },\n * branch: (branch) => ({ protected: branch.name === \"main\" }),\n * });\n * ```\n *\n * The policy is split into a **static** existential set (top-level `auth` / `dataApi`\n * toggles and the beta `preview` block) and a **dynamic** per-branch `branch` closure. The\n * static half determines which secrets exist — so `NeonEnv<typeof config>` and `parseEnv`\n * are exact — while the closure can only *tune* a branch (lifecycle, compute, per-function\n * deploy settings), never change what exists.\n *\n * The `branch` callback receives a read-only {@link BranchTarget} descriptor of the branch\n * being decided for (not a live handle); switch on its facts (`branch.name`,\n * `branch.isDefault`, `branch.exists`, …) and **return** the desired tuning. It runs in two\n * modes: against an existing branch (fields populated from Neon) and during pre-create\n * evaluation (`exists: false`, `id` undefined).\n *\n * Pure: no I/O, no side effects. The static parts are validated here; the closure's output\n * is validated every time it is evaluated so errors point at the concrete branch target.\n */\nexport function defineConfig<\n\tconst Auth extends ServiceToggleInput | undefined = undefined,\n\tconst DataApi extends DataApiInput | undefined = undefined,\n\tconst Preview extends PreviewInput | undefined = undefined,\n>(input: {\n\t// Each field is intersected with its concrete interface (not just typed as the bare\n\t// generic). The generic alone — e.g. `preview?: Preview` — gives editors no members to\n\t// complete against in the object-literal position (they see `{} | undefined`), so you\n\t// lose hints for `aiGateway` / `functions` / `buckets`. `& PreviewInput` restores the\n\t// full shape for autocomplete while still inferring the `const` literal that types the\n\t// `branch` closure's slugs (BranchTuningFn<Preview>) and the returned Config.\n\tauth?: Auth & ServiceToggleInput;\n\t// The `dataApi` field carries the Neon-Auth cross-field guard at the type level (see\n\t// `DataApiField`): a Neon-Auth Data API without `auth` enabled surfaces a readable hint\n\t// as the field's expected type instead of collapsing the value to `never`.\n\tdataApi?: DataApiField<Auth, DataApi>;\n\t// `& PreviewInput` restores top-level member hints (aiGateway/functions/buckets);\n\t// `& PreviewAutocomplete<Preview>` restores hints *inside* each function/bucket slug\n\t// object (see `PreviewAutocomplete`), which the bare index signature otherwise hides.\n\tpreview?: Preview & PreviewInput & PreviewAutocomplete<Preview>;\n\tbranch?: BranchTuningFn<Preview>;\n}): Config<Auth, DataApi, Preview> {\n\tif (typeof input === \"function\") {\n\t\tthrow new ConfigValidationError([\n\t\t\t\"defineConfig now expects an object, not a function: `export default defineConfig({ auth: true, preview: { … }, branch: (branch) => ({ … }) })`.\",\n\t\t\t\"The static services/preview set moved to the top level; per-branch logic moved into the `branch` closure.\",\n\t\t]);\n\t}\n\tif (input === null || typeof input !== \"object\") {\n\t\tthrow new ConfigValidationError([\n\t\t\t\"defineConfig expects a configuration object: `export default defineConfig({ … })`.\",\n\t\t]);\n\t}\n\n\tconst parsed = configInputSchema.safeParse(input);\n\tif (!parsed.success) {\n\t\tthrow new ConfigValidationError(formatZodIssues(parsed.error));\n\t}\n\n\treturn Object.freeze({ ...input }) as Config<Auth, DataApi, Preview>;\n}\n\n/**\n * Evaluate a branch policy for a specific branch target and return a normalized config.\n *\n * Merges the static existential set (services + preview functions/buckets) with the\n * per-branch tuning returned by the `branch` closure into the same {@link\n * ResolvedBranchConfig} the rest of the runtime (diff / push / fetchEnv) consumes.\n */\nexport function resolveConfig(\n\tconfig: Config,\n\tbranch: BranchTarget,\n): ResolvedBranchConfig {\n\tconst tuning = evaluateBranchTuning(config.branch, branch);\n\n\tconst resolved: ResolvedBranchConfig = {\n\t\tauthEnabled: isServiceEnabled(config.auth),\n\t\tdataApiEnabled: isDataApiEnabled(config.dataApi),\n\t};\n\tconst dataApi = resolveDataApi(config.dataApi);\n\tif (dataApi) resolved.dataApi = dataApi;\n\tif (tuning.parent !== undefined) resolved.parent = tuning.parent;\n\tif (tuning.ttl !== undefined) {\n\t\t// `branchTuningSchema` already validated `ttl` with the same `parseBranchTtl`, so\n\t\t// this only converts the validated value to seconds — it cannot fail here.\n\t\tconst parsedTtl = parseBranchTtl(tuning.ttl);\n\t\tif (!(\"error\" in parsedTtl)) resolved.ttlSeconds = parsedTtl.seconds;\n\t}\n\tif (tuning.protected !== undefined) resolved.protected = tuning.protected;\n\tif (tuning.postgres?.computeSettings) {\n\t\tresolved.postgres = {\n\t\t\tcomputeSettings: { ...tuning.postgres.computeSettings },\n\t\t};\n\t}\n\n\tconst preview = resolvePreviewConfig(config.preview, tuning);\n\tif (preview) resolved.preview = preview;\n\n\treturn resolved;\n}\n\n/**\n * Run the `branch` closure (when present) for the target and validate its output. The\n * closure is optional — a fully static policy resolves with empty tuning.\n */\nfunction evaluateBranchTuning(\n\tbranchFn: BranchTuningFn | undefined,\n\ttarget: BranchTarget,\n): BranchTuning {\n\tif (!branchFn) return {};\n\tlet raw: unknown;\n\ttry {\n\t\traw = branchFn(Object.freeze({ ...target }));\n\t} catch (cause) {\n\t\tthrow new ConfigValidationError([\n\t\t\t`Branch policy threw while evaluating branch \"${target.name}\".`,\n\t\t\t(cause as Error)?.message ?? String(cause),\n\t\t]);\n\t}\n\tconst parsed = branchTuningSchema.safeParse(raw ?? {});\n\tif (!parsed.success) {\n\t\tthrow new ConfigValidationError(formatZodIssues(parsed.error));\n\t}\n\treturn parsed.data as BranchTuning;\n}\n\nfunction isServiceEnabled(toggle: ServiceToggleInput | undefined): boolean {\n\tif (toggle === undefined) return false;\n\tif (typeof toggle === \"boolean\") return toggle;\n\treturn toggle.enabled !== false;\n}\n\n/** Whether a {@link DataApiInput} is enabled (present object/`true` unless `enabled: false`). */\nfunction isDataApiEnabled(input: DataApiInput | undefined): boolean {\n\tif (input === undefined) return false;\n\tif (typeof input === \"boolean\") return input;\n\treturn input.enabled !== false;\n}\n\n/**\n * Normalize a {@link DataApiInput} into a {@link ResolvedDataApiConfig}, or `undefined` when\n * the Data API is not enabled. `authProvider` defaults to `\"neon\"`; the external-IdP wiring\n * is carried through only for the `\"external\"` provider; `settings` is copied with its\n * `undefined` entries dropped so diffing only considers fields the policy actually set.\n */\nfunction resolveDataApi(\n\tinput: DataApiInput | undefined,\n): ResolvedDataApiConfig | undefined {\n\tif (!isDataApiEnabled(input)) return undefined;\n\tif (typeof input !== \"object\") {\n\t\t// Bare `true`: enabled with Neon Auth and all-default settings.\n\t\treturn { authProvider: \"neon\" };\n\t}\n\tconst authProvider = input.authProvider ?? \"neon\";\n\tconst resolved: ResolvedDataApiConfig = { authProvider };\n\tif (authProvider === \"external\") {\n\t\tif (input.jwksUrl !== undefined) resolved.jwksUrl = input.jwksUrl;\n\t\tif (input.providerName !== undefined)\n\t\t\tresolved.providerName = input.providerName;\n\t\tif (input.jwtAudience !== undefined)\n\t\t\tresolved.jwtAudience = input.jwtAudience;\n\t}\n\tconst settings = normalizeDataApiSettings(input.settings);\n\tif (settings) resolved.settings = settings;\n\treturn resolved;\n}\n\n/** Copy a {@link DataApiSettings}, dropping `undefined` entries; `undefined` when empty. */\nfunction normalizeDataApiSettings(\n\tsettings: DataApiSettings | undefined,\n): DataApiSettings | undefined {\n\tif (!settings) return undefined;\n\tconst out: DataApiSettings = {};\n\tfor (const [key, value] of Object.entries(settings)) {\n\t\tif (value !== undefined) {\n\t\t\t(out as Record<string, unknown>)[key] = value;\n\t\t}\n\t}\n\treturn Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * Normalize the static {@link PreviewInput} (merged with per-branch function tuning) into a\n * {@link ResolvedPreviewConfig}. Returns `undefined` when the policy declares no `preview`\n * block so the field can be omitted entirely. Function slugs / bucket names come from the\n * record keys.\n */\nfunction resolvePreviewConfig(\n\tpreview: PreviewInput | undefined,\n\ttuning: BranchTuning,\n): ResolvedPreviewConfig | undefined {\n\tif (!preview) return undefined;\n\tconst fnTuning = tuning.preview?.functions ?? {};\n\tconst functions: ResolvedFunctionConfig[] = Object.entries(\n\t\tpreview.functions ?? {},\n\t).map(([slug, def]) =>\n\t\tresolveFunctionConfig(slug, def, fnTuning[slug] ?? {}),\n\t);\n\tconst buckets = Object.entries(preview.buckets ?? {}).map(\n\t\t([name, def]) => ({\n\t\t\tname,\n\t\t\taccess: def.access ?? \"private\",\n\t\t}),\n\t);\n\treturn {\n\t\tfunctions,\n\t\tbuckets,\n\t\taiGatewayEnabled: isServiceEnabled(preview.aiGateway),\n\t};\n}\n\nfunction resolveFunctionConfig(\n\tslug: string,\n\tdef: FunctionDef,\n\ttuning: FunctionTuning,\n): ResolvedFunctionConfig {\n\treturn {\n\t\tslug,\n\t\tname: def.name,\n\t\tsource: def.source,\n\t\tenv: { ...(def.env ?? {}) },\n\t\truntime: tuning.runtime ?? DEFAULT_FUNCTION_RUNTIME,\n\t\t// Normalized only when declared, so a policy without it resolves unchanged and takes\n\t\t// the pre-existing bundling path. Both bundlers read it; `neon dev` mirrors it so a\n\t\t// local run leaves the same packages unbundled as a deploy.\n\t\t...(def.externalPackages\n\t\t\t? {\n\t\t\t\t\texternalPackages: def.externalPackages.map(\n\t\t\t\t\t\tnormalizeExternalPackage,\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t: {}),\n\t\t// Passed through untouched (no defaults); only `neon dev` reads it.\n\t\t...(def.dev ? { dev: def.dev } : {}),\n\t};\n}\n\n/**\n * Normalize a region identifier to Neon's `<cloud>-<region>` format. When the user writes\n * `us-east-1` we assume `aws-us-east-1`. Pure helper used by both the validator and the\n * NeonApi adapter.\n */\nexport function normalizeRegion(region: string): string {\n\tif (REGION_PREFIX.test(region)) return region;\n\treturn `aws-${region}`;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ExternalPackageEntry, ResolvedExternalPackage } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/external-packages.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The package a specifier belongs to, dropping any subpath: `sharp` from `sharp/lib/x`,
|
|
7
|
+
* `@scope/pkg` from `@scope/pkg/sub`.
|
|
8
|
+
*
|
|
9
|
+
* Files are installed and traced one package at a time, so this is the unit the deploy
|
|
10
|
+
* stages. A subpath narrows what esbuild leaves unresolved; it does not narrow what ships.
|
|
11
|
+
*/
|
|
12
|
+
declare const externalPackageRoot: (specifier: string) => string;
|
|
13
|
+
/**
|
|
14
|
+
* Normalize one authored entry into the shape every consumer reads.
|
|
15
|
+
*
|
|
16
|
+
* `includeFiles` defaults to **true**: the bare-string form is the one users reach for, and
|
|
17
|
+
* it should produce a function that works. Turning it off is the deliberate gesture.
|
|
18
|
+
*/
|
|
19
|
+
declare const normalizeExternalPackage: (entry: ExternalPackageEntry) => ResolvedExternalPackage;
|
|
20
|
+
/**
|
|
21
|
+
* The specifiers whose files a function ships, in declaration order and deduplicated.
|
|
22
|
+
*
|
|
23
|
+
* These are the specifiers **as authored**, subpath included, because that is what the trace
|
|
24
|
+
* has to import. A package may export only a subpath — `exports: { "./native": … }` with no
|
|
25
|
+
* `.` — in which case importing the root throws `ERR_PACKAGE_PATH_NOT_EXPORTED` and the
|
|
26
|
+
* trace finds nothing. Use {@link externalPackageRoot} on these to get what to *install*,
|
|
27
|
+
* which is always the whole package.
|
|
28
|
+
*/
|
|
29
|
+
declare const packagesToStage: (entries: readonly ResolvedExternalPackage[]) => string[];
|
|
30
|
+
//#endregion
|
|
31
|
+
export { externalPackageRoot, normalizeExternalPackage, packagesToStage };
|
|
32
|
+
//# sourceMappingURL=external-packages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-packages.d.ts","names":[],"sources":["../../src/lib/external-packages.ts"],"mappings":";;;;;;AASA;AAYA;AAKoE;AAJ5D;AACL;AAGiE,cAjBvD,mBAiBuD,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,GAAA,MAAA;AAWpE;;;;;;cAhBa,kCACL,yBACL;;;;;;;;;;cAcU,oCACM"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//#region src/lib/external-packages.ts
|
|
2
|
+
/**
|
|
3
|
+
* The package a specifier belongs to, dropping any subpath: `sharp` from `sharp/lib/x`,
|
|
4
|
+
* `@scope/pkg` from `@scope/pkg/sub`.
|
|
5
|
+
*
|
|
6
|
+
* Files are installed and traced one package at a time, so this is the unit the deploy
|
|
7
|
+
* stages. A subpath narrows what esbuild leaves unresolved; it does not narrow what ships.
|
|
8
|
+
*/
|
|
9
|
+
const externalPackageRoot = (specifier) => {
|
|
10
|
+
const segments = specifier.split("/");
|
|
11
|
+
const keep = specifier.startsWith("@") ? 2 : 1;
|
|
12
|
+
return segments.slice(0, keep).join("/");
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Normalize one authored entry into the shape every consumer reads.
|
|
16
|
+
*
|
|
17
|
+
* `includeFiles` defaults to **true**: the bare-string form is the one users reach for, and
|
|
18
|
+
* it should produce a function that works. Turning it off is the deliberate gesture.
|
|
19
|
+
*/
|
|
20
|
+
const normalizeExternalPackage = (entry) => typeof entry === "string" ? {
|
|
21
|
+
name: entry,
|
|
22
|
+
includeFiles: true
|
|
23
|
+
} : {
|
|
24
|
+
name: entry.name,
|
|
25
|
+
includeFiles: entry.includeFiles !== false
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* The specifiers whose files a function ships, in declaration order and deduplicated.
|
|
29
|
+
*
|
|
30
|
+
* These are the specifiers **as authored**, subpath included, because that is what the trace
|
|
31
|
+
* has to import. A package may export only a subpath — `exports: { "./native": … }` with no
|
|
32
|
+
* `.` — in which case importing the root throws `ERR_PACKAGE_PATH_NOT_EXPORTED` and the
|
|
33
|
+
* trace finds nothing. Use {@link externalPackageRoot} on these to get what to *install*,
|
|
34
|
+
* which is always the whole package.
|
|
35
|
+
*/
|
|
36
|
+
const packagesToStage = (entries) => {
|
|
37
|
+
const specifiers = [];
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
if (!entry.includeFiles) continue;
|
|
40
|
+
if (!specifiers.includes(entry.name)) specifiers.push(entry.name);
|
|
41
|
+
}
|
|
42
|
+
return specifiers;
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { externalPackageRoot, normalizeExternalPackage, packagesToStage };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=external-packages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-packages.js","names":[],"sources":["../../src/lib/external-packages.ts"],"sourcesContent":["import type { ExternalPackageEntry, ResolvedExternalPackage } from \"./types.js\";\n\n/**\n * The package a specifier belongs to, dropping any subpath: `sharp` from `sharp/lib/x`,\n * `@scope/pkg` from `@scope/pkg/sub`.\n *\n * Files are installed and traced one package at a time, so this is the unit the deploy\n * stages. A subpath narrows what esbuild leaves unresolved; it does not narrow what ships.\n */\nexport const externalPackageRoot = (specifier: string): string => {\n\tconst segments = specifier.split(\"/\");\n\tconst keep = specifier.startsWith(\"@\") ? 2 : 1;\n\treturn segments.slice(0, keep).join(\"/\");\n};\n\n/**\n * Normalize one authored entry into the shape every consumer reads.\n *\n * `includeFiles` defaults to **true**: the bare-string form is the one users reach for, and\n * it should produce a function that works. Turning it off is the deliberate gesture.\n */\nexport const normalizeExternalPackage = (\n\tentry: ExternalPackageEntry,\n): ResolvedExternalPackage =>\n\ttypeof entry === \"string\"\n\t\t? { name: entry, includeFiles: true }\n\t\t: { name: entry.name, includeFiles: entry.includeFiles !== false };\n\n/**\n * The specifiers whose files a function ships, in declaration order and deduplicated.\n *\n * These are the specifiers **as authored**, subpath included, because that is what the trace\n * has to import. A package may export only a subpath — `exports: { \"./native\": … }` with no\n * `.` — in which case importing the root throws `ERR_PACKAGE_PATH_NOT_EXPORTED` and the\n * trace finds nothing. Use {@link externalPackageRoot} on these to get what to *install*,\n * which is always the whole package.\n */\nexport const packagesToStage = (\n\tentries: readonly ResolvedExternalPackage[],\n): string[] => {\n\tconst specifiers: string[] = [];\n\tfor (const entry of entries) {\n\t\tif (!entry.includeFiles) continue;\n\t\tif (!specifiers.includes(entry.name)) specifiers.push(entry.name);\n\t}\n\treturn specifiers;\n};\n"],"mappings":";;;;;;;;AASA,MAAa,uBAAuB,cAA8B;CACjE,MAAM,WAAW,UAAU,MAAM,GAAG;CACpC,MAAM,OAAO,UAAU,WAAW,GAAG,IAAI,IAAI;CAC7C,OAAO,SAAS,MAAM,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG;AACxC;;;;;;;AAQA,MAAa,4BACZ,UAEA,OAAO,UAAU,WACd;CAAE,MAAM;CAAO,cAAc;AAAK,IAClC;CAAE,MAAM,MAAM;CAAM,cAAc,MAAM,iBAAiB;AAAM;;;;;;;;;;AAWnE,MAAa,mBACZ,YACc;CACd,MAAM,aAAuB,CAAC;CAC9B,KAAK,MAAM,SAAS,SAAS;EAC5B,IAAI,CAAC,MAAM,cAAc;EACzB,IAAI,CAAC,WAAW,SAAS,MAAM,IAAI,GAAG,WAAW,KAAK,MAAM,IAAI;CACjE;CACA,OAAO;AACR"}
|
package/dist/lib/schema.d.ts
CHANGED
|
@@ -99,12 +99,20 @@ declare const postgresConfigSchema: z.ZodObject<{
|
|
|
99
99
|
* Static definition of a function (existence). The slug is the record key (validated by
|
|
100
100
|
* {@link functionSlugSchema}), so it is not a field here. Deploy tuning (`runtime`) lives
|
|
101
101
|
* in the `branch` closure, not here.
|
|
102
|
+
*
|
|
103
|
+
* `externalPackages` entries are checked for contradictions: the same package named twice,
|
|
104
|
+
* or named once bare and once through a subpath with a different `includeFiles`. Both state
|
|
105
|
+
* two intents for one package, and files are staged per package rather than per subpath, so
|
|
106
|
+
* neither can be honoured as written.
|
|
102
107
|
*/
|
|
103
108
|
declare const functionDefSchema: z.ZodObject<{
|
|
104
109
|
name: z.ZodString;
|
|
105
110
|
source: z.ZodString;
|
|
106
111
|
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
107
|
-
externalPackages: z.ZodOptional<z.ZodArray<z.ZodString
|
|
112
|
+
externalPackages: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
113
|
+
name: z.ZodString;
|
|
114
|
+
includeFiles: z.ZodOptional<z.ZodBoolean>;
|
|
115
|
+
}, z.core.$strict>]>>>;
|
|
108
116
|
dev: z.ZodOptional<z.ZodObject<{
|
|
109
117
|
port: z.ZodOptional<z.ZodNumber>;
|
|
110
118
|
}, z.core.$strict>>;
|
|
@@ -122,7 +130,10 @@ declare const previewInputSchema: z.ZodObject<{
|
|
|
122
130
|
name: z.ZodString;
|
|
123
131
|
source: z.ZodString;
|
|
124
132
|
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
125
|
-
externalPackages: z.ZodOptional<z.ZodArray<z.ZodString
|
|
133
|
+
externalPackages: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
134
|
+
name: z.ZodString;
|
|
135
|
+
includeFiles: z.ZodOptional<z.ZodBoolean>;
|
|
136
|
+
}, z.core.$strict>]>>>;
|
|
126
137
|
dev: z.ZodOptional<z.ZodObject<{
|
|
127
138
|
port: z.ZodOptional<z.ZodNumber>;
|
|
128
139
|
}, z.core.$strict>>;
|
|
@@ -192,7 +203,10 @@ declare const configInputSchema: z.ZodObject<{
|
|
|
192
203
|
name: z.ZodString;
|
|
193
204
|
source: z.ZodString;
|
|
194
205
|
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
195
|
-
externalPackages: z.ZodOptional<z.ZodArray<z.ZodString
|
|
206
|
+
externalPackages: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
207
|
+
name: z.ZodString;
|
|
208
|
+
includeFiles: z.ZodOptional<z.ZodBoolean>;
|
|
209
|
+
}, z.core.$strict>]>>>;
|
|
196
210
|
dev: z.ZodOptional<z.ZodObject<{
|
|
197
211
|
port: z.ZodOptional<z.ZodNumber>;
|
|
198
212
|
}, z.core.$strict>>;
|
package/dist/lib/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","names":[],"sources":["../../src/lib/schema.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","names":[],"sources":["../../src/lib/schema.ts"],"mappings":"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"}
|
package/dist/lib/schema.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { parseBranchTtl, parseSuspendTimeout } from "./duration.js";
|
|
2
|
+
import { externalPackageRoot } from "./external-packages.js";
|
|
2
3
|
import { isWildcardPattern, validatePattern } from "./patterns.js";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
//#region src/lib/schema.ts
|
|
@@ -144,24 +145,62 @@ const devPortSchema = z.number().int().min(1).max(65535);
|
|
|
144
145
|
*/
|
|
145
146
|
const functionDevConfigSchema = z.strictObject({ port: devPortSchema.optional() });
|
|
146
147
|
/**
|
|
147
|
-
*
|
|
148
|
-
* package — a bare name, a scope, or a subpath — and rejects a relative or
|
|
149
|
-
* which names a local module rather than a dependency and is never the right
|
|
150
|
-
* externalize (the bundle would ship an import of a file that isn't deployed).
|
|
148
|
+
* The name of a package the bundler must leave alone. Accepts what esbuild's `external`
|
|
149
|
+
* accepts for a package — a bare name, a scope, or a subpath — and rejects a relative or
|
|
150
|
+
* absolute path, which names a local module rather than a dependency and is never the right
|
|
151
|
+
* thing to externalize (the bundle would ship an import of a file that isn't deployed).
|
|
151
152
|
*/
|
|
152
|
-
const
|
|
153
|
+
const externalPackageNameSchema = z.string().min(1).refine((value) => !value.startsWith(".") && !value.startsWith("/"), { error: "must be a package name such as \"microsandbox\" or \"@scope/pkg\", not a relative or absolute path" });
|
|
154
|
+
/**
|
|
155
|
+
* An entry whose files are staged has to name one installable package, because the deploy
|
|
156
|
+
* hands its root to `npm install`. esbuild's `external` additionally accepts a `*` wildcard
|
|
157
|
+
* and a bare scope, which name a set rather than a package — legal only when nothing is
|
|
158
|
+
* being installed for them.
|
|
159
|
+
*/
|
|
160
|
+
const stageablePackageName = (value) => {
|
|
161
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(value)) return false;
|
|
162
|
+
if (value.split("/").some((segment) => segment === "" || segment === "..")) return false;
|
|
163
|
+
return isNpmPackageName(externalPackageRoot(value));
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* npm's own rules for a package name, which is what the deploy hands to `npm install`.
|
|
167
|
+
* Deliberately strict: whatever slips through here becomes a subprocess argument.
|
|
168
|
+
*/
|
|
169
|
+
const NPM_NAME_SEGMENT = /^[a-z0-9~][a-z0-9._~-]*$/;
|
|
170
|
+
const isNpmPackageName = (root) => {
|
|
171
|
+
if (root.length === 0 || root.length > 214) return false;
|
|
172
|
+
if (!root.startsWith("@")) return NPM_NAME_SEGMENT.test(root);
|
|
173
|
+
const [scope, name, ...rest] = root.slice(1).split("/");
|
|
174
|
+
if (rest.length > 0 || name === void 0) return false;
|
|
175
|
+
return NPM_NAME_SEGMENT.test(scope) && NPM_NAME_SEGMENT.test(name);
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* One entry of `externalPackages`. A bare string is the common case and ships the package's
|
|
179
|
+
* files; the object form exists only to turn that off. See {@link FunctionDef.externalPackages}.
|
|
180
|
+
*/
|
|
181
|
+
const externalPackageEntrySchema = z.union([externalPackageNameSchema, z.strictObject({
|
|
182
|
+
name: externalPackageNameSchema,
|
|
183
|
+
includeFiles: z.boolean().optional()
|
|
184
|
+
})]);
|
|
153
185
|
/**
|
|
154
186
|
* Per-function list of packages esbuild leaves unresolved at deploy time. See
|
|
155
|
-
* {@link FunctionDef.externalPackages}
|
|
156
|
-
* archive has no `node_modules`, so an externalized package must never be reached at
|
|
157
|
-
* runtime.
|
|
187
|
+
* {@link FunctionDef.externalPackages}.
|
|
158
188
|
*/
|
|
159
|
-
const functionExternalPackagesSchema = z.array(
|
|
189
|
+
const functionExternalPackagesSchema = z.array(externalPackageEntrySchema);
|
|
160
190
|
const runtimeSchema = z.literal("nodejs24");
|
|
191
|
+
/** The declared name of an entry, whichever form it was written in. */
|
|
192
|
+
const entryName = (entry) => typeof entry === "string" ? entry : entry.name;
|
|
193
|
+
/** Whether an entry ships its files. Absent means yes — see `FunctionDef.externalPackages`. */
|
|
194
|
+
const entryIncludesFiles = (entry) => typeof entry === "string" ? true : entry.includeFiles !== false;
|
|
161
195
|
/**
|
|
162
196
|
* Static definition of a function (existence). The slug is the record key (validated by
|
|
163
197
|
* {@link functionSlugSchema}), so it is not a field here. Deploy tuning (`runtime`) lives
|
|
164
198
|
* in the `branch` closure, not here.
|
|
199
|
+
*
|
|
200
|
+
* `externalPackages` entries are checked for contradictions: the same package named twice,
|
|
201
|
+
* or named once bare and once through a subpath with a different `includeFiles`. Both state
|
|
202
|
+
* two intents for one package, and files are staged per package rather than per subpath, so
|
|
203
|
+
* neither can be honoured as written.
|
|
165
204
|
*/
|
|
166
205
|
const functionDefSchema = z.strictObject({
|
|
167
206
|
name: z.string().min(1).max(255),
|
|
@@ -169,6 +208,49 @@ const functionDefSchema = z.strictObject({
|
|
|
169
208
|
env: functionEnvSchema.optional(),
|
|
170
209
|
externalPackages: functionExternalPackagesSchema.optional(),
|
|
171
210
|
dev: functionDevConfigSchema.optional()
|
|
211
|
+
}).check((ctx) => {
|
|
212
|
+
const entries = ctx.value.externalPackages ?? [];
|
|
213
|
+
const seenNames = /* @__PURE__ */ new Map();
|
|
214
|
+
const rootIntent = /* @__PURE__ */ new Map();
|
|
215
|
+
entries.forEach((entry, index) => {
|
|
216
|
+
const name = entryName(entry);
|
|
217
|
+
const includeFiles = entryIncludesFiles(entry);
|
|
218
|
+
if (includeFiles && !stageablePackageName(name)) {
|
|
219
|
+
ctx.issues.push({
|
|
220
|
+
code: "custom",
|
|
221
|
+
input: entry,
|
|
222
|
+
path: ["externalPackages", index],
|
|
223
|
+
message: `"${name}" does not name a single installable package, so its files cannot be staged. Name one package, or set includeFiles: false to leave the import unresolved without shipping anything for it`
|
|
224
|
+
});
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const firstIndex = seenNames.get(name);
|
|
228
|
+
if (firstIndex !== void 0) {
|
|
229
|
+
ctx.issues.push({
|
|
230
|
+
code: "custom",
|
|
231
|
+
input: entry,
|
|
232
|
+
path: ["externalPackages", index],
|
|
233
|
+
message: `"${name}" is listed more than once (first at index ${firstIndex})`
|
|
234
|
+
});
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
seenNames.set(name, index);
|
|
238
|
+
const root = externalPackageRoot(name);
|
|
239
|
+
const prior = rootIntent.get(root);
|
|
240
|
+
if (prior !== void 0 && prior.includeFiles !== includeFiles) {
|
|
241
|
+
ctx.issues.push({
|
|
242
|
+
code: "custom",
|
|
243
|
+
input: entry,
|
|
244
|
+
path: ["externalPackages", index],
|
|
245
|
+
message: `"${name}" and "${prior.at}" are both part of the "${root}" package but disagree about includeFiles; files ship per package, so the whole package either ships or does not`
|
|
246
|
+
});
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
rootIntent.set(root, {
|
|
250
|
+
includeFiles,
|
|
251
|
+
at: name
|
|
252
|
+
});
|
|
253
|
+
});
|
|
172
254
|
});
|
|
173
255
|
/** Static definition of a bucket (existence). Name is the record key. */
|
|
174
256
|
const bucketDefSchema = z.strictObject({ access: z.union([z.literal("private"), z.literal("public_read")]).optional() });
|
package/dist/lib/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","names":[],"sources":["../../src/lib/schema.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { parseBranchTtl, parseSuspendTimeout } from \"./duration.js\";\nimport { isWildcardPattern, validatePattern } from \"./patterns.js\";\n\n/**\n * Zod schema for {@link import(\"./types.js\").ComputeSettings}.\n *\n * - CU values must be one of: 0.25, 0.5, 1, 2, 4, 8\n * - `suspendTimeout` can be:\n * - `false` (never suspend)\n * - duration string like \"5m\", \"1h\" (must be 60s-604800s when parsed)\n * - number in seconds (60-604800, or -1/0 for special values)\n * - `undefined` (use platform default)\n *\n * Cross-field invariants (min <= max) are enforced via `superRefine`.\n */\nexport const computeSettingsSchema = z\n\t.strictObject({\n\t\tautoscalingLimitMinCu: z\n\t\t\t.union([\n\t\t\t\tz.literal(0.25),\n\t\t\t\tz.literal(0.5),\n\t\t\t\tz.literal(1),\n\t\t\t\tz.literal(2),\n\t\t\t\tz.literal(4),\n\t\t\t\tz.literal(8),\n\t\t\t])\n\t\t\t.optional(),\n\t\tautoscalingLimitMaxCu: z\n\t\t\t.union([\n\t\t\t\tz.literal(0.25),\n\t\t\t\tz.literal(0.5),\n\t\t\t\tz.literal(1),\n\t\t\t\tz.literal(2),\n\t\t\t\tz.literal(4),\n\t\t\t\tz.literal(8),\n\t\t\t])\n\t\t\t.optional(),\n\t\tsuspendTimeout: z\n\t\t\t.union([z.literal(false), z.string(), z.number()])\n\t\t\t.optional()\n\t\t\t.superRefine((value, ctx) => {\n\t\t\t\tif (value === undefined) return; // undefined is valid (use platform default)\n\t\t\t\tconst result = parseSuspendTimeout(value);\n\t\t\t\tif (\"error\" in result) {\n\t\t\t\t\tctx.addIssue({\n\t\t\t\t\t\tcode: \"custom\",\n\t\t\t\t\t\tmessage: result.error,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}),\n\t})\n\t.superRefine((settings, ctx) => {\n\t\tconst { autoscalingLimitMinCu: min, autoscalingLimitMaxCu: max } =\n\t\t\tsettings;\n\t\tif (min !== undefined && max !== undefined && min > max) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: \"custom\",\n\t\t\t\tpath: [\"autoscalingLimitMinCu\"],\n\t\t\t\tmessage: `autoscalingLimitMinCu (${min}) must be <= autoscalingLimitMaxCu (${max})`,\n\t\t\t});\n\t\t}\n\t});\n\n/** Object form of a service toggle (`{ enabled?: boolean }`). */\nexport const serviceToggleSchema = z.strictObject({\n\tenabled: z.boolean().optional(),\n});\n\n/** A service toggle as written in a policy: `boolean` or `{ enabled?: boolean }`. */\nexport const serviceToggleInputSchema = z.union([\n\tz.boolean(),\n\tserviceToggleSchema,\n]);\n\n/**\n * Reusable Data API runtime settings (camelCase mirror of the Neon API `DataAPISettings`).\n * `strictObject` so a typo / snake_case key fails loudly instead of being silently dropped.\n */\nexport const dataApiSettingsSchema = z.strictObject({\n\tdbAggregatesEnabled: z.boolean().optional(),\n\tdbAnonRole: z.string().optional(),\n\tdbExtraSearchPath: z.string().optional(),\n\tdbMaxRows: z.number().int().optional(),\n\tdbSchemas: z.array(z.string()).optional(),\n\tjwtRoleClaimKey: z.string().optional(),\n\tjwtCacheMaxLifetime: z.number().int().optional(),\n\topenapiMode: z\n\t\t.union([z.literal(\"ignore-privileges\"), z.literal(\"disabled\")])\n\t\t.optional(),\n\tserverCorsAllowedOrigins: z.string().optional(),\n\tserverTimingEnabled: z.boolean().optional(),\n});\n\n/** Names of the external-IdP-only fields, forbidden when `authProvider` is `\"neon\"`. */\nconst DATA_API_EXTERNAL_ONLY_KEYS = [\n\t\"jwksUrl\",\n\t\"providerName\",\n\t\"jwtAudience\",\n] as const;\n\n/**\n * Object form of the `dataApi` toggle. A single `strictObject` plus a `superRefine` (rather\n * than a discriminated union) so the `\"neon\"` default works without the discriminator being\n * present, and so the \"external-only field with authProvider neon\" error points at the exact\n * offending key — mirroring the `?: never` type-level guard at runtime.\n */\nexport const dataApiConfigSchema = z\n\t.strictObject({\n\t\tenabled: z.boolean().optional(),\n\t\tauthProvider: z\n\t\t\t.union([z.literal(\"neon\"), z.literal(\"external\")])\n\t\t\t.optional(),\n\t\tjwksUrl: z.string().optional(),\n\t\tproviderName: z.string().optional(),\n\t\tjwtAudience: z.string().optional(),\n\t\tsettings: dataApiSettingsSchema.optional(),\n\t})\n\t.superRefine((cfg, ctx) => {\n\t\tconst provider = cfg.authProvider ?? \"neon\";\n\t\tif (provider !== \"neon\") return;\n\t\tfor (const key of DATA_API_EXTERNAL_ONLY_KEYS) {\n\t\t\tif (cfg[key] !== undefined) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: \"custom\",\n\t\t\t\t\tpath: [key],\n\t\t\t\t\tmessage: `${key} is only allowed with authProvider: \"external\" — Neon supplies it for authProvider: \"neon\".`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n/** A `dataApi` toggle as written in a policy: `boolean` or {@link dataApiConfigSchema}. */\nexport const dataApiInputSchema = z.union([z.boolean(), dataApiConfigSchema]);\n\nexport const postgresConfigSchema = z.strictObject({\n\tcomputeSettings: computeSettingsSchema.optional(),\n});\n\n/**\n * Branch-unique function slug. Mirrors the Neon Functions API path-segment rule\n * (`platform/internal/platform/functions/name.go`): 1–20 lowercase letters and digits.\n * Used as the **key schema** of the `preview.functions` record, so a bad slug fails\n * validation with a path pointing at the offending key and duplicate slugs are impossible\n * by construction (object keys are unique).\n */\nconst functionSlugSchema = z\n\t.string()\n\t.regex(\n\t\t/^[a-z0-9]{1,20}$/,\n\t\t\"function slug must be 1-20 lowercase letters and digits (no hyphens or other characters)\",\n\t);\n\n/** Bucket name: 1–255 chars. Used as the key schema of the `preview.buckets` record. */\nconst bucketNameSchema = z.string().min(1).max(255);\n\n/**\n * A single function environment-variable value. Must be a defined string: a `process.env.X`\n * that is unset evaluates to `undefined`, and the bare `z.string()` message for that case\n * (`Invalid input: expected string, received undefined`) gives no hint that an env var is the\n * culprit. The custom `error` replaces *only* the `undefined` case with a message that names\n * the offending function + env key (read from the issue path) and how to fix it; any other\n * wrong type keeps zod's default (`expected string, received number`, …).\n */\nconst functionEnvValueSchema = z.string({\n\terror: (issue) => {\n\t\tif (issue.input !== undefined) return undefined;\n\t\tconst path = issue.path ?? [];\n\t\tconst key = path.length > 0 ? String(path[path.length - 1]) : undefined;\n\t\tconst functionsIndex = path.indexOf(\"functions\");\n\t\tconst slug =\n\t\t\tfunctionsIndex >= 0 && functionsIndex + 1 < path.length\n\t\t\t\t? String(path[functionsIndex + 1])\n\t\t\t\t: undefined;\n\t\tconst subject =\n\t\t\tslug !== undefined && key !== undefined\n\t\t\t\t? `Environment variable \"${key}\" for function \"${slug}\"`\n\t\t\t\t: key !== undefined\n\t\t\t\t\t? `Environment variable \"${key}\"`\n\t\t\t\t\t: \"An environment variable\";\n\t\treturn `${subject} is undefined — its value (typically a \\`process.env.*\\`) is unset. Set it (e.g. add it to your .env) or provide a fallback like \\`process.env.X ?? \"\"\\`.`;\n\t},\n});\n\n/**\n * Per-function environment map. Every value must be a defined string (see\n * {@link functionEnvValueSchema}): a `process.env.X` that is unset surfaces as `undefined` and\n * is rejected here (rather than silently shipping `undefined` into the deployment).\n */\nconst functionEnvSchema = z.record(z.string(), functionEnvValueSchema);\n\n/**\n * TCP port for a function's local dev server. Excludes 0 (which means \"any port\" to the OS\n * — `neon dev` expresses \"pick one for me\" by omitting `port`, not by passing 0).\n */\nconst devPortSchema = z.number().int().min(1).max(65535);\n\n/**\n * Local-dev settings for a function (`neon dev` only; never affects deploy). `port` is bound\n * exactly when set (and `neon dev` fails if it is taken), or a free port is found when omitted.\n */\nconst functionDevConfigSchema = z.strictObject({\n\tport: devPortSchema.optional(),\n});\n\n/**\n * A package the bundler must leave alone. Accepts what esbuild's `external` accepts for a\n * package — a bare name, a scope, or a subpath — and rejects a relative or absolute path,\n * which names a local module rather than a dependency and is never the right thing to\n * externalize (the bundle would ship an import of a file that isn't deployed).\n */\nconst externalPackageSchema = z\n\t.string()\n\t.min(1)\n\t.refine((value) => !value.startsWith(\".\") && !value.startsWith(\"/\"), {\n\t\terror: 'must be a package name such as \"microsandbox\" or \"@scope/pkg\", not a relative or absolute path',\n\t});\n\n/**\n * Per-function list of packages esbuild leaves unresolved at deploy time. See\n * {@link FunctionDef.externalPackages} for when this is the right tool — the deployed\n * archive has no `node_modules`, so an externalized package must never be reached at\n * runtime.\n */\nconst functionExternalPackagesSchema = z.array(externalPackageSchema);\n\nconst runtimeSchema = z.literal(\"nodejs24\");\n\n/**\n * Static definition of a function (existence). The slug is the record key (validated by\n * {@link functionSlugSchema}), so it is not a field here. Deploy tuning (`runtime`) lives\n * in the `branch` closure, not here.\n */\nexport const functionDefSchema = z.strictObject({\n\tname: z.string().min(1).max(255),\n\tsource: z.string().min(1),\n\tenv: functionEnvSchema.optional(),\n\texternalPackages: functionExternalPackagesSchema.optional(),\n\tdev: functionDevConfigSchema.optional(),\n});\n\n/** Static definition of a bucket (existence). Name is the record key. */\nexport const bucketDefSchema = z.strictObject({\n\taccess: z\n\t\t.union([z.literal(\"private\"), z.literal(\"public_read\")])\n\t\t.optional(),\n});\n\n/** Static, beta Preview feature set: AI Gateway toggle + functions/buckets records. */\nexport const previewInputSchema = z.strictObject({\n\taiGateway: serviceToggleInputSchema.optional(),\n\tfunctions: z.record(functionSlugSchema, functionDefSchema).optional(),\n\tbuckets: z.record(bucketNameSchema, bucketDefSchema).optional(),\n});\n\n/** Per-function deploy tuning returned by the `branch` closure. */\nexport const functionTuningSchema = z.strictObject({\n\truntime: runtimeSchema.optional(),\n});\n\n/** Per-branch Preview tuning. Keys must be slugs declared in the static `preview`. */\nconst previewTuningSchema = z.strictObject({\n\tfunctions: z.record(functionSlugSchema, functionTuningSchema).optional(),\n});\n\n/**\n * The object returned by the `branch` closure. Validated on every `resolveConfig` call so\n * tuning errors point at the concrete branch target that triggered them.\n */\nexport const branchTuningSchema = z\n\t.strictObject({\n\t\tparent: z.string().optional(),\n\t\tprotected: z.boolean().optional(),\n\t\tttl: z\n\t\t\t.union([z.string(), z.number()])\n\t\t\t.optional()\n\t\t\t.superRefine((value, ctx) => {\n\t\t\t\tif (value === undefined) return;\n\t\t\t\tconst result = parseBranchTtl(value);\n\t\t\t\tif (\"error\" in result) {\n\t\t\t\t\tctx.addIssue({ code: \"custom\", message: result.error });\n\t\t\t\t}\n\t\t\t}),\n\t\tpostgres: postgresConfigSchema.optional(),\n\t\tpreview: previewTuningSchema.optional(),\n\t})\n\t.superRefine((cfg, ctx) => {\n\t\tvalidateParentReference({\n\t\t\tctx,\n\t\t\tpath: [\"parent\"],\n\t\t\tparent: cfg.parent,\n\t\t});\n\t});\n\n/**\n * The top-level object accepted by `defineConfig`. The `branch` closure is validated\n * structurally as a function here; its returned tuning is validated per-evaluation by\n * {@link branchTuningSchema} inside `resolveConfig`.\n */\nexport const configInputSchema = z\n\t.strictObject({\n\t\tauth: serviceToggleInputSchema.optional(),\n\t\tdataApi: dataApiInputSchema.optional(),\n\t\tpreview: previewInputSchema.optional(),\n\t\tbranch: z\n\t\t\t.custom<(...args: unknown[]) => unknown>(\n\t\t\t\t(value) => typeof value === \"function\",\n\t\t\t\t{\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t\"branch must be a function: `branch: (branch) => ({ … })`\",\n\t\t\t\t},\n\t\t\t)\n\t\t\t.optional(),\n\t})\n\t.superRefine((cfg, ctx) => {\n\t\t// A Data API verified by Neon Auth (`authProvider: \"neon\"`, the default) needs Neon\n\t\t// Auth enabled on the same branch so the tokens it verifies actually exist. Enforce\n\t\t// the same invariant the `defineConfig` type-level check expresses, at runtime.\n\t\tif (!isToggleEnabledValue(cfg.dataApi)) return;\n\t\tif (dataApiAuthProviderValue(cfg.dataApi) !== \"neon\") return;\n\t\tif (!isToggleEnabledValue(cfg.auth)) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: \"custom\",\n\t\t\t\tpath: [\"auth\"],\n\t\t\t\tmessage:\n\t\t\t\t\t'dataApi with authProvider \"neon\" requires Neon Auth — set `auth: true` (or `auth: { enabled: true }`), or use `dataApi.authProvider: \"external\"` with your own `jwksUrl`.',\n\t\t\t});\n\t\t}\n\t});\n\n/**\n * Whether a parsed `auth` / `dataApi` toggle value is enabled: a present object (or `true`)\n * is on unless `enabled` is explicitly `false`. Mirrors `isServiceEnabled` in\n * `define-config.ts`, operating on the already-validated runtime value.\n */\nfunction isToggleEnabledValue(value: unknown): boolean {\n\tif (value === undefined || value === null) return false;\n\tif (typeof value === \"boolean\") return value;\n\tif (typeof value === \"object\") {\n\t\treturn (value as { enabled?: unknown }).enabled !== false;\n\t}\n\treturn false;\n}\n\n/** Read the (defaulted) `authProvider` from a parsed `dataApi` value. */\nfunction dataApiAuthProviderValue(value: unknown): \"neon\" | \"external\" {\n\tif (value !== null && typeof value === \"object\") {\n\t\tconst provider = (value as { authProvider?: unknown }).authProvider;\n\t\tif (provider === \"external\") return \"external\";\n\t}\n\treturn \"neon\";\n}\n\nfunction validateParentReference(args: {\n\tctx: z.RefinementCtx;\n\tpath: (string | number)[];\n\tparent: string | undefined;\n}): void {\n\tconst { ctx, path, parent } = args;\n\tif (parent === undefined) return;\n\n\tconst patternCheck = validatePattern(parent);\n\tif (\"error\" in patternCheck) {\n\t\tctx.addIssue({ code: \"custom\", path, message: patternCheck.error });\n\t} else if (isWildcardPattern(parent)) {\n\t\tctx.addIssue({\n\t\t\tcode: \"custom\",\n\t\t\tpath,\n\t\t\tmessage: `parent must be a concrete branch name (no wildcards), got \"${parent}\"`,\n\t\t});\n\t}\n}\n\n/**\n * Convert the structured {@link z.ZodError} produced by `configSchema.safeParse` into the\n * `string[]` shape used by {@link import(\"./errors.js\").ConfigValidationError}.\n *\n * Issue paths are rendered as dot-separated property accesses (`postgres.computeSettings`)\n * and unknown-key issues from `strictObject` are normalised so the message contains the\n * substring \"unknown key\" — keeping pre-zod assertions in test suites and downstream tools\n * stable.\n */\nexport function formatZodIssues(error: z.ZodError): string[] {\n\treturn error.issues.map((issue) => {\n\t\tconst path = renderPath(issue.path);\n\t\tconst message = normaliseIssueMessage(issue);\n\t\treturn path ? `${path}: ${message}` : message;\n\t});\n}\n\nfunction renderPath(path: ReadonlyArray<PropertyKey>): string {\n\tlet out = \"\";\n\tfor (const segment of path) {\n\t\tif (typeof segment === \"number\") out += `[${segment}]`;\n\t\telse if (out === \"\") out += String(segment);\n\t\telse out += `.${String(segment)}`;\n\t}\n\treturn out;\n}\n\nfunction normaliseIssueMessage(issue: z.core.$ZodIssue): string {\n\tif (issue.code === \"unrecognized_keys\") {\n\t\tconst keys = issue.keys ?? [];\n\t\tconst formatted = keys.map((k) => JSON.stringify(k)).join(\", \");\n\t\treturn `unknown key${keys.length === 1 ? \"\" : \"s\"}: ${formatted}`;\n\t}\n\tif (issue.code === \"invalid_key\") {\n\t\t// A record *key* that fails its key schema (e.g. a bad function slug) surfaces in\n\t\t// zod as a single `invalid_key` issue whose own `message` is the generic, useless\n\t\t// \"Invalid key in record\". The actual reason — the function-slug regex rule, say —\n\t\t// lives in the nested key-schema `issues`. Hoist those so the user sees *why* the\n\t\t// key was rejected (the offending key itself is already in the issue `path`).\n\t\tconst reasons = issue.issues\n\t\t\t.map((nested) => nested.message)\n\t\t\t.filter((message) => message.length > 0);\n\t\tif (reasons.length > 0) return reasons.join(\"; \");\n\t}\n\treturn issue.message;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,MAAa,wBAAwB,EACnC,aAAa;CACb,uBAAuB,EACrB,MAAM;EACN,EAAE,QAAQ,GAAI;EACd,EAAE,QAAQ,EAAG;EACb,EAAE,QAAQ,CAAC;EACX,EAAE,QAAQ,CAAC;EACX,EAAE,QAAQ,CAAC;EACX,EAAE,QAAQ,CAAC;CACZ,CAAC,CAAC,CACD,SAAS;CACX,uBAAuB,EACrB,MAAM;EACN,EAAE,QAAQ,GAAI;EACd,EAAE,QAAQ,EAAG;EACb,EAAE,QAAQ,CAAC;EACX,EAAE,QAAQ,CAAC;EACX,EAAE,QAAQ,CAAC;EACX,EAAE,QAAQ,CAAC;CACZ,CAAC,CAAC,CACD,SAAS;CACX,gBAAgB,EACd,MAAM;EAAC,EAAE,QAAQ,KAAK;EAAG,EAAE,OAAO;EAAG,EAAE,OAAO;CAAC,CAAC,CAAC,CACjD,SAAS,CAAC,CACV,aAAa,OAAO,QAAQ;EAC5B,IAAI,UAAU,KAAA,GAAW;EACzB,MAAM,SAAS,oBAAoB,KAAK;EACxC,IAAI,WAAW,QACd,IAAI,SAAS;GACZ,MAAM;GACN,SAAS,OAAO;EACjB,CAAC;CAEH,CAAC;AACH,CAAC,CAAC,CACD,aAAa,UAAU,QAAQ;CAC/B,MAAM,EAAE,uBAAuB,KAAK,uBAAuB,QAC1D;CACD,IAAI,QAAQ,KAAA,KAAa,QAAQ,KAAA,KAAa,MAAM,KACnD,IAAI,SAAS;EACZ,MAAM;EACN,MAAM,CAAC,uBAAuB;EAC9B,SAAS,0BAA0B,IAAI,sCAAsC,IAAI;CAClF,CAAC;AAEH,CAAC;;AAGF,MAAa,sBAAsB,EAAE,aAAa,EACjD,SAAS,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC/B,CAAC;;AAGD,MAAa,2BAA2B,EAAE,MAAM,CAC/C,EAAE,QAAQ,GACV,mBACD,CAAC;;;;;AAMD,MAAa,wBAAwB,EAAE,aAAa;CACnD,qBAAqB,EAAE,QAAQ,CAAC,CAAC,SAAS;CAC1C,YAAY,EAAE,OAAO,CAAC,CAAC,SAAS;CAChC,mBAAmB,EAAE,OAAO,CAAC,CAAC,SAAS;CACvC,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS;CACrC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS;CACxC,iBAAiB,EAAE,OAAO,CAAC,CAAC,SAAS;CACrC,qBAAqB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS;CAC/C,aAAa,EACX,MAAM,CAAC,EAAE,QAAQ,mBAAmB,GAAG,EAAE,QAAQ,UAAU,CAAC,CAAC,CAAC,CAC9D,SAAS;CACX,0BAA0B,EAAE,OAAO,CAAC,CAAC,SAAS;CAC9C,qBAAqB,EAAE,QAAQ,CAAC,CAAC,SAAS;AAC3C,CAAC;;AAGD,MAAM,8BAA8B;CACnC;CACA;CACA;AACD;;;;;;;AAQA,MAAa,sBAAsB,EACjC,aAAa;CACb,SAAS,EAAE,QAAQ,CAAC,CAAC,SAAS;CAC9B,cAAc,EACZ,MAAM,CAAC,EAAE,QAAQ,MAAM,GAAG,EAAE,QAAQ,UAAU,CAAC,CAAC,CAAC,CACjD,SAAS;CACX,SAAS,EAAE,OAAO,CAAC,CAAC,SAAS;CAC7B,cAAc,EAAE,OAAO,CAAC,CAAC,SAAS;CAClC,aAAa,EAAE,OAAO,CAAC,CAAC,SAAS;CACjC,UAAU,sBAAsB,SAAS;AAC1C,CAAC,CAAC,CACD,aAAa,KAAK,QAAQ;CAE1B,KADiB,IAAI,gBAAgB,YACpB,QAAQ;CACzB,KAAK,MAAM,OAAO,6BACjB,IAAI,IAAI,SAAS,KAAA,GAChB,IAAI,SAAS;EACZ,MAAM;EACN,MAAM,CAAC,GAAG;EACV,SAAS,GAAG,IAAI;CACjB,CAAC;AAGJ,CAAC;;AAGF,MAAa,qBAAqB,EAAE,MAAM,CAAC,EAAE,QAAQ,GAAG,mBAAmB,CAAC;AAE5E,MAAa,uBAAuB,EAAE,aAAa,EAClD,iBAAiB,sBAAsB,SAAS,EACjD,CAAC;;;;;;;;AASD,MAAM,qBAAqB,EACzB,OAAO,CAAC,CACR,MACA,oBACA,0FACD;;AAGD,MAAM,mBAAmB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG;;;;;;;;;AAUlD,MAAM,yBAAyB,EAAE,OAAO,EACvC,QAAQ,UAAU;CACjB,IAAI,MAAM,UAAU,KAAA,GAAW,OAAO,KAAA;CACtC,MAAM,OAAO,MAAM,QAAQ,CAAC;CAC5B,MAAM,MAAM,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,IAAI,KAAA;CAC9D,MAAM,iBAAiB,KAAK,QAAQ,WAAW;CAC/C,MAAM,OACL,kBAAkB,KAAK,iBAAiB,IAAI,KAAK,SAC9C,OAAO,KAAK,iBAAiB,EAAE,IAC/B,KAAA;CAOJ,OAAO,GALN,SAAS,KAAA,KAAa,QAAQ,KAAA,IAC3B,yBAAyB,IAAI,kBAAkB,KAAK,KACpD,QAAQ,KAAA,IACP,yBAAyB,IAAI,KAC7B,0BACa;AACnB,EACD,CAAC;;;;;;AAOD,MAAM,oBAAoB,EAAE,OAAO,EAAE,OAAO,GAAG,sBAAsB;;;;;AAMrE,MAAM,gBAAgB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK;;;;;AAMvD,MAAM,0BAA0B,EAAE,aAAa,EAC9C,MAAM,cAAc,SAAS,EAC9B,CAAC;;;;;;;AAQD,MAAM,wBAAwB,EAC5B,OAAO,CAAC,CACR,IAAI,CAAC,CAAC,CACN,QAAQ,UAAU,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,WAAW,GAAG,GAAG,EACpE,OAAO,qGACR,CAAC;;;;;;;AAQF,MAAM,iCAAiC,EAAE,MAAM,qBAAqB;AAEpE,MAAM,gBAAgB,EAAE,QAAQ,UAAU;;;;;;AAO1C,MAAa,oBAAoB,EAAE,aAAa;CAC/C,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG;CAC/B,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACxB,KAAK,kBAAkB,SAAS;CAChC,kBAAkB,+BAA+B,SAAS;CAC1D,KAAK,wBAAwB,SAAS;AACvC,CAAC;;AAGD,MAAa,kBAAkB,EAAE,aAAa,EAC7C,QAAQ,EACN,MAAM,CAAC,EAAE,QAAQ,SAAS,GAAG,EAAE,QAAQ,aAAa,CAAC,CAAC,CAAC,CACvD,SAAS,EACZ,CAAC;;AAGD,MAAa,qBAAqB,EAAE,aAAa;CAChD,WAAW,yBAAyB,SAAS;CAC7C,WAAW,EAAE,OAAO,oBAAoB,iBAAiB,CAAC,CAAC,SAAS;CACpE,SAAS,EAAE,OAAO,kBAAkB,eAAe,CAAC,CAAC,SAAS;AAC/D,CAAC;;AAGD,MAAa,uBAAuB,EAAE,aAAa,EAClD,SAAS,cAAc,SAAS,EACjC,CAAC;;AAGD,MAAM,sBAAsB,EAAE,aAAa,EAC1C,WAAW,EAAE,OAAO,oBAAoB,oBAAoB,CAAC,CAAC,SAAS,EACxE,CAAC;;;;;AAMD,MAAa,qBAAqB,EAChC,aAAa;CACb,QAAQ,EAAE,OAAO,CAAC,CAAC,SAAS;CAC5B,WAAW,EAAE,QAAQ,CAAC,CAAC,SAAS;CAChC,KAAK,EACH,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAC/B,SAAS,CAAC,CACV,aAAa,OAAO,QAAQ;EAC5B,IAAI,UAAU,KAAA,GAAW;EACzB,MAAM,SAAS,eAAe,KAAK;EACnC,IAAI,WAAW,QACd,IAAI,SAAS;GAAE,MAAM;GAAU,SAAS,OAAO;EAAM,CAAC;CAExD,CAAC;CACF,UAAU,qBAAqB,SAAS;CACxC,SAAS,oBAAoB,SAAS;AACvC,CAAC,CAAC,CACD,aAAa,KAAK,QAAQ;CAC1B,wBAAwB;EACvB;EACA,MAAM,CAAC,QAAQ;EACf,QAAQ,IAAI;CACb,CAAC;AACF,CAAC;;;;;;AAOF,MAAa,oBAAoB,EAC/B,aAAa;CACb,MAAM,yBAAyB,SAAS;CACxC,SAAS,mBAAmB,SAAS;CACrC,SAAS,mBAAmB,SAAS;CACrC,QAAQ,EACN,QACC,UAAU,OAAO,UAAU,YAC5B,EACC,SACC,2DACF,CACD,CAAC,CACA,SAAS;AACZ,CAAC,CAAC,CACD,aAAa,KAAK,QAAQ;CAI1B,IAAI,CAAC,qBAAqB,IAAI,OAAO,GAAG;CACxC,IAAI,yBAAyB,IAAI,OAAO,MAAM,QAAQ;CACtD,IAAI,CAAC,qBAAqB,IAAI,IAAI,GACjC,IAAI,SAAS;EACZ,MAAM;EACN,MAAM,CAAC,MAAM;EACb,SACC;CACF,CAAC;AAEH,CAAC;;;;;;AAOF,SAAS,qBAAqB,OAAyB;CACtD,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM,OAAO;CAClD,IAAI,OAAO,UAAU,WAAW,OAAO;CACvC,IAAI,OAAO,UAAU,UACpB,OAAQ,MAAgC,YAAY;CAErD,OAAO;AACR;;AAGA,SAAS,yBAAyB,OAAqC;CACtE,IAAI,UAAU,QAAQ,OAAO,UAAU,UACpB;MAAA,MAAqC,iBACtC,YAAY,OAAO;CAAA;CAErC,OAAO;AACR;AAEA,SAAS,wBAAwB,MAIxB;CACR,MAAM,EAAE,KAAK,MAAM,WAAW;CAC9B,IAAI,WAAW,KAAA,GAAW;CAE1B,MAAM,eAAe,gBAAgB,MAAM;CAC3C,IAAI,WAAW,cACd,IAAI,SAAS;EAAE,MAAM;EAAU;EAAM,SAAS,aAAa;CAAM,CAAC;MAC5D,IAAI,kBAAkB,MAAM,GAClC,IAAI,SAAS;EACZ,MAAM;EACN;EACA,SAAS,8DAA8D,OAAO;CAC/E,CAAC;AAEH;;;;;;;;;;AAWA,SAAgB,gBAAgB,OAA6B;CAC5D,OAAO,MAAM,OAAO,KAAK,UAAU;EAClC,MAAM,OAAO,WAAW,MAAM,IAAI;EAClC,MAAM,UAAU,sBAAsB,KAAK;EAC3C,OAAO,OAAO,GAAG,KAAK,IAAI,YAAY;CACvC,CAAC;AACF;AAEA,SAAS,WAAW,MAA0C;CAC7D,IAAI,MAAM;CACV,KAAK,MAAM,WAAW,MACrB,IAAI,OAAO,YAAY,UAAU,OAAO,IAAI,QAAQ;MAC/C,IAAI,QAAQ,IAAI,OAAO,OAAO,OAAO;MACrC,OAAO,IAAI,OAAO,OAAO;CAE/B,OAAO;AACR;AAEA,SAAS,sBAAsB,OAAiC;CAC/D,IAAI,MAAM,SAAS,qBAAqB;EACvC,MAAM,OAAO,MAAM,QAAQ,CAAC;EAC5B,MAAM,YAAY,KAAK,KAAK,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI;EAC9D,OAAO,cAAc,KAAK,WAAW,IAAI,KAAK,IAAI,IAAI;CACvD;CACA,IAAI,MAAM,SAAS,eAAe;EAMjC,MAAM,UAAU,MAAM,OACpB,KAAK,WAAW,OAAO,OAAO,CAAC,CAC/B,QAAQ,YAAY,QAAQ,SAAS,CAAC;EACxC,IAAI,QAAQ,SAAS,GAAG,OAAO,QAAQ,KAAK,IAAI;CACjD;CACA,OAAO,MAAM;AACd"}
|
|
1
|
+
{"version":3,"file":"schema.js","names":[],"sources":["../../src/lib/schema.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { parseBranchTtl, parseSuspendTimeout } from \"./duration.js\";\nimport { externalPackageRoot } from \"./external-packages.js\";\nimport { isWildcardPattern, validatePattern } from \"./patterns.js\";\n\n/**\n * Zod schema for {@link import(\"./types.js\").ComputeSettings}.\n *\n * - CU values must be one of: 0.25, 0.5, 1, 2, 4, 8\n * - `suspendTimeout` can be:\n * - `false` (never suspend)\n * - duration string like \"5m\", \"1h\" (must be 60s-604800s when parsed)\n * - number in seconds (60-604800, or -1/0 for special values)\n * - `undefined` (use platform default)\n *\n * Cross-field invariants (min <= max) are enforced via `superRefine`.\n */\nexport const computeSettingsSchema = z\n\t.strictObject({\n\t\tautoscalingLimitMinCu: z\n\t\t\t.union([\n\t\t\t\tz.literal(0.25),\n\t\t\t\tz.literal(0.5),\n\t\t\t\tz.literal(1),\n\t\t\t\tz.literal(2),\n\t\t\t\tz.literal(4),\n\t\t\t\tz.literal(8),\n\t\t\t])\n\t\t\t.optional(),\n\t\tautoscalingLimitMaxCu: z\n\t\t\t.union([\n\t\t\t\tz.literal(0.25),\n\t\t\t\tz.literal(0.5),\n\t\t\t\tz.literal(1),\n\t\t\t\tz.literal(2),\n\t\t\t\tz.literal(4),\n\t\t\t\tz.literal(8),\n\t\t\t])\n\t\t\t.optional(),\n\t\tsuspendTimeout: z\n\t\t\t.union([z.literal(false), z.string(), z.number()])\n\t\t\t.optional()\n\t\t\t.superRefine((value, ctx) => {\n\t\t\t\tif (value === undefined) return; // undefined is valid (use platform default)\n\t\t\t\tconst result = parseSuspendTimeout(value);\n\t\t\t\tif (\"error\" in result) {\n\t\t\t\t\tctx.addIssue({\n\t\t\t\t\t\tcode: \"custom\",\n\t\t\t\t\t\tmessage: result.error,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}),\n\t})\n\t.superRefine((settings, ctx) => {\n\t\tconst { autoscalingLimitMinCu: min, autoscalingLimitMaxCu: max } =\n\t\t\tsettings;\n\t\tif (min !== undefined && max !== undefined && min > max) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: \"custom\",\n\t\t\t\tpath: [\"autoscalingLimitMinCu\"],\n\t\t\t\tmessage: `autoscalingLimitMinCu (${min}) must be <= autoscalingLimitMaxCu (${max})`,\n\t\t\t});\n\t\t}\n\t});\n\n/** Object form of a service toggle (`{ enabled?: boolean }`). */\nexport const serviceToggleSchema = z.strictObject({\n\tenabled: z.boolean().optional(),\n});\n\n/** A service toggle as written in a policy: `boolean` or `{ enabled?: boolean }`. */\nexport const serviceToggleInputSchema = z.union([\n\tz.boolean(),\n\tserviceToggleSchema,\n]);\n\n/**\n * Reusable Data API runtime settings (camelCase mirror of the Neon API `DataAPISettings`).\n * `strictObject` so a typo / snake_case key fails loudly instead of being silently dropped.\n */\nexport const dataApiSettingsSchema = z.strictObject({\n\tdbAggregatesEnabled: z.boolean().optional(),\n\tdbAnonRole: z.string().optional(),\n\tdbExtraSearchPath: z.string().optional(),\n\tdbMaxRows: z.number().int().optional(),\n\tdbSchemas: z.array(z.string()).optional(),\n\tjwtRoleClaimKey: z.string().optional(),\n\tjwtCacheMaxLifetime: z.number().int().optional(),\n\topenapiMode: z\n\t\t.union([z.literal(\"ignore-privileges\"), z.literal(\"disabled\")])\n\t\t.optional(),\n\tserverCorsAllowedOrigins: z.string().optional(),\n\tserverTimingEnabled: z.boolean().optional(),\n});\n\n/** Names of the external-IdP-only fields, forbidden when `authProvider` is `\"neon\"`. */\nconst DATA_API_EXTERNAL_ONLY_KEYS = [\n\t\"jwksUrl\",\n\t\"providerName\",\n\t\"jwtAudience\",\n] as const;\n\n/**\n * Object form of the `dataApi` toggle. A single `strictObject` plus a `superRefine` (rather\n * than a discriminated union) so the `\"neon\"` default works without the discriminator being\n * present, and so the \"external-only field with authProvider neon\" error points at the exact\n * offending key — mirroring the `?: never` type-level guard at runtime.\n */\nexport const dataApiConfigSchema = z\n\t.strictObject({\n\t\tenabled: z.boolean().optional(),\n\t\tauthProvider: z\n\t\t\t.union([z.literal(\"neon\"), z.literal(\"external\")])\n\t\t\t.optional(),\n\t\tjwksUrl: z.string().optional(),\n\t\tproviderName: z.string().optional(),\n\t\tjwtAudience: z.string().optional(),\n\t\tsettings: dataApiSettingsSchema.optional(),\n\t})\n\t.superRefine((cfg, ctx) => {\n\t\tconst provider = cfg.authProvider ?? \"neon\";\n\t\tif (provider !== \"neon\") return;\n\t\tfor (const key of DATA_API_EXTERNAL_ONLY_KEYS) {\n\t\t\tif (cfg[key] !== undefined) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: \"custom\",\n\t\t\t\t\tpath: [key],\n\t\t\t\t\tmessage: `${key} is only allowed with authProvider: \"external\" — Neon supplies it for authProvider: \"neon\".`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n/** A `dataApi` toggle as written in a policy: `boolean` or {@link dataApiConfigSchema}. */\nexport const dataApiInputSchema = z.union([z.boolean(), dataApiConfigSchema]);\n\nexport const postgresConfigSchema = z.strictObject({\n\tcomputeSettings: computeSettingsSchema.optional(),\n});\n\n/**\n * Branch-unique function slug. Mirrors the Neon Functions API path-segment rule\n * (`platform/internal/platform/functions/name.go`): 1–20 lowercase letters and digits.\n * Used as the **key schema** of the `preview.functions` record, so a bad slug fails\n * validation with a path pointing at the offending key and duplicate slugs are impossible\n * by construction (object keys are unique).\n */\nconst functionSlugSchema = z\n\t.string()\n\t.regex(\n\t\t/^[a-z0-9]{1,20}$/,\n\t\t\"function slug must be 1-20 lowercase letters and digits (no hyphens or other characters)\",\n\t);\n\n/** Bucket name: 1–255 chars. Used as the key schema of the `preview.buckets` record. */\nconst bucketNameSchema = z.string().min(1).max(255);\n\n/**\n * A single function environment-variable value. Must be a defined string: a `process.env.X`\n * that is unset evaluates to `undefined`, and the bare `z.string()` message for that case\n * (`Invalid input: expected string, received undefined`) gives no hint that an env var is the\n * culprit. The custom `error` replaces *only* the `undefined` case with a message that names\n * the offending function + env key (read from the issue path) and how to fix it; any other\n * wrong type keeps zod's default (`expected string, received number`, …).\n */\nconst functionEnvValueSchema = z.string({\n\terror: (issue) => {\n\t\tif (issue.input !== undefined) return undefined;\n\t\tconst path = issue.path ?? [];\n\t\tconst key = path.length > 0 ? String(path[path.length - 1]) : undefined;\n\t\tconst functionsIndex = path.indexOf(\"functions\");\n\t\tconst slug =\n\t\t\tfunctionsIndex >= 0 && functionsIndex + 1 < path.length\n\t\t\t\t? String(path[functionsIndex + 1])\n\t\t\t\t: undefined;\n\t\tconst subject =\n\t\t\tslug !== undefined && key !== undefined\n\t\t\t\t? `Environment variable \"${key}\" for function \"${slug}\"`\n\t\t\t\t: key !== undefined\n\t\t\t\t\t? `Environment variable \"${key}\"`\n\t\t\t\t\t: \"An environment variable\";\n\t\treturn `${subject} is undefined — its value (typically a \\`process.env.*\\`) is unset. Set it (e.g. add it to your .env) or provide a fallback like \\`process.env.X ?? \"\"\\`.`;\n\t},\n});\n\n/**\n * Per-function environment map. Every value must be a defined string (see\n * {@link functionEnvValueSchema}): a `process.env.X` that is unset surfaces as `undefined` and\n * is rejected here (rather than silently shipping `undefined` into the deployment).\n */\nconst functionEnvSchema = z.record(z.string(), functionEnvValueSchema);\n\n/**\n * TCP port for a function's local dev server. Excludes 0 (which means \"any port\" to the OS\n * — `neon dev` expresses \"pick one for me\" by omitting `port`, not by passing 0).\n */\nconst devPortSchema = z.number().int().min(1).max(65535);\n\n/**\n * Local-dev settings for a function (`neon dev` only; never affects deploy). `port` is bound\n * exactly when set (and `neon dev` fails if it is taken), or a free port is found when omitted.\n */\nconst functionDevConfigSchema = z.strictObject({\n\tport: devPortSchema.optional(),\n});\n\n/**\n * The name of a package the bundler must leave alone. Accepts what esbuild's `external`\n * accepts for a package — a bare name, a scope, or a subpath — and rejects a relative or\n * absolute path, which names a local module rather than a dependency and is never the right\n * thing to externalize (the bundle would ship an import of a file that isn't deployed).\n */\nconst externalPackageNameSchema = z\n\t.string()\n\t.min(1)\n\t.refine((value) => !value.startsWith(\".\") && !value.startsWith(\"/\"), {\n\t\terror: 'must be a package name such as \"microsandbox\" or \"@scope/pkg\", not a relative or absolute path',\n\t});\n\n/**\n * An entry whose files are staged has to name one installable package, because the deploy\n * hands its root to `npm install`. esbuild's `external` additionally accepts a `*` wildcard\n * and a bare scope, which name a set rather than a package — legal only when nothing is\n * being installed for them.\n */\nconst stageablePackageName = (value: string): boolean => {\n\t// A protocol (`node:fs`, `npm:pkg`) is a specifier, not something to install.\n\tif (/^[a-z][a-z0-9+.-]*:/i.test(value)) return false;\n\t// An empty segment (`foo//bar`) or a traversal is not a subpath the deploy can act on.\n\tconst segments = value.split(\"/\");\n\tif (segments.some((segment) => segment === \"\" || segment === \"..\")) {\n\t\treturn false;\n\t}\n\treturn isNpmPackageName(externalPackageRoot(value));\n};\n\n/**\n * npm's own rules for a package name, which is what the deploy hands to `npm install`.\n * Deliberately strict: whatever slips through here becomes a subprocess argument.\n */\nconst NPM_NAME_SEGMENT = /^[a-z0-9~][a-z0-9._~-]*$/;\n\nconst isNpmPackageName = (root: string): boolean => {\n\tif (root.length === 0 || root.length > 214) return false;\n\tif (!root.startsWith(\"@\")) return NPM_NAME_SEGMENT.test(root);\n\tconst [scope, name, ...rest] = root.slice(1).split(\"/\");\n\t// A bare scope names every package in it, not one package.\n\tif (rest.length > 0 || name === undefined) return false;\n\treturn NPM_NAME_SEGMENT.test(scope) && NPM_NAME_SEGMENT.test(name);\n};\n\n/**\n * One entry of `externalPackages`. A bare string is the common case and ships the package's\n * files; the object form exists only to turn that off. See {@link FunctionDef.externalPackages}.\n */\nconst externalPackageEntrySchema = z.union([\n\texternalPackageNameSchema,\n\tz.strictObject({\n\t\tname: externalPackageNameSchema,\n\t\tincludeFiles: z.boolean().optional(),\n\t}),\n]);\n\n/**\n * Per-function list of packages esbuild leaves unresolved at deploy time. See\n * {@link FunctionDef.externalPackages}.\n */\nconst functionExternalPackagesSchema = z.array(externalPackageEntrySchema);\n\nconst runtimeSchema = z.literal(\"nodejs24\");\n\n/** The declared name of an entry, whichever form it was written in. */\nconst entryName = (\n\tentry: z.infer<typeof externalPackageEntrySchema>,\n): string => (typeof entry === \"string\" ? entry : entry.name);\n\n/** Whether an entry ships its files. Absent means yes — see `FunctionDef.externalPackages`. */\nconst entryIncludesFiles = (\n\tentry: z.infer<typeof externalPackageEntrySchema>,\n): boolean => (typeof entry === \"string\" ? true : entry.includeFiles !== false);\n\n/**\n * Static definition of a function (existence). The slug is the record key (validated by\n * {@link functionSlugSchema}), so it is not a field here. Deploy tuning (`runtime`) lives\n * in the `branch` closure, not here.\n *\n * `externalPackages` entries are checked for contradictions: the same package named twice,\n * or named once bare and once through a subpath with a different `includeFiles`. Both state\n * two intents for one package, and files are staged per package rather than per subpath, so\n * neither can be honoured as written.\n */\nexport const functionDefSchema = z\n\t.strictObject({\n\t\tname: z.string().min(1).max(255),\n\t\tsource: z.string().min(1),\n\t\tenv: functionEnvSchema.optional(),\n\t\texternalPackages: functionExternalPackagesSchema.optional(),\n\t\tdev: functionDevConfigSchema.optional(),\n\t})\n\t.check((ctx) => {\n\t\tconst entries = ctx.value.externalPackages ?? [];\n\t\tconst seenNames = new Map<string, number>();\n\t\tconst rootIntent = new Map<\n\t\t\tstring,\n\t\t\t{ includeFiles: boolean; at: string }\n\t\t>();\n\n\t\tentries.forEach((entry, index) => {\n\t\t\tconst name = entryName(entry);\n\t\t\tconst includeFiles = entryIncludesFiles(entry);\n\n\t\t\tif (includeFiles && !stageablePackageName(name)) {\n\t\t\t\tctx.issues.push({\n\t\t\t\t\tcode: \"custom\",\n\t\t\t\t\tinput: entry,\n\t\t\t\t\tpath: [\"externalPackages\", index],\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`\"${name}\" does not name a single installable package, so its files cannot ` +\n\t\t\t\t\t\t`be staged. Name one package, or set includeFiles: false to leave the ` +\n\t\t\t\t\t\t`import unresolved without shipping anything for it`,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst firstIndex = seenNames.get(name);\n\t\t\tif (firstIndex !== undefined) {\n\t\t\t\tctx.issues.push({\n\t\t\t\t\tcode: \"custom\",\n\t\t\t\t\tinput: entry,\n\t\t\t\t\tpath: [\"externalPackages\", index],\n\t\t\t\t\tmessage: `\"${name}\" is listed more than once (first at index ${firstIndex})`,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tseenNames.set(name, index);\n\n\t\t\t// Files are installed and traced per package, so two specifiers that resolve to the\n\t\t\t// same package cannot disagree about whether that package's files ship.\n\t\t\tconst root = externalPackageRoot(name);\n\t\t\tconst prior = rootIntent.get(root);\n\t\t\tif (prior !== undefined && prior.includeFiles !== includeFiles) {\n\t\t\t\tctx.issues.push({\n\t\t\t\t\tcode: \"custom\",\n\t\t\t\t\tinput: entry,\n\t\t\t\t\tpath: [\"externalPackages\", index],\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`\"${name}\" and \"${prior.at}\" are both part of the \"${root}\" package but disagree ` +\n\t\t\t\t\t\t`about includeFiles; files ship per package, so the whole package either ships or does not`,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\trootIntent.set(root, { includeFiles, at: name });\n\t\t});\n\t});\n\n/** Static definition of a bucket (existence). Name is the record key. */\nexport const bucketDefSchema = z.strictObject({\n\taccess: z\n\t\t.union([z.literal(\"private\"), z.literal(\"public_read\")])\n\t\t.optional(),\n});\n\n/** Static, beta Preview feature set: AI Gateway toggle + functions/buckets records. */\nexport const previewInputSchema = z.strictObject({\n\taiGateway: serviceToggleInputSchema.optional(),\n\tfunctions: z.record(functionSlugSchema, functionDefSchema).optional(),\n\tbuckets: z.record(bucketNameSchema, bucketDefSchema).optional(),\n});\n\n/** Per-function deploy tuning returned by the `branch` closure. */\nexport const functionTuningSchema = z.strictObject({\n\truntime: runtimeSchema.optional(),\n});\n\n/** Per-branch Preview tuning. Keys must be slugs declared in the static `preview`. */\nconst previewTuningSchema = z.strictObject({\n\tfunctions: z.record(functionSlugSchema, functionTuningSchema).optional(),\n});\n\n/**\n * The object returned by the `branch` closure. Validated on every `resolveConfig` call so\n * tuning errors point at the concrete branch target that triggered them.\n */\nexport const branchTuningSchema = z\n\t.strictObject({\n\t\tparent: z.string().optional(),\n\t\tprotected: z.boolean().optional(),\n\t\tttl: z\n\t\t\t.union([z.string(), z.number()])\n\t\t\t.optional()\n\t\t\t.superRefine((value, ctx) => {\n\t\t\t\tif (value === undefined) return;\n\t\t\t\tconst result = parseBranchTtl(value);\n\t\t\t\tif (\"error\" in result) {\n\t\t\t\t\tctx.addIssue({ code: \"custom\", message: result.error });\n\t\t\t\t}\n\t\t\t}),\n\t\tpostgres: postgresConfigSchema.optional(),\n\t\tpreview: previewTuningSchema.optional(),\n\t})\n\t.superRefine((cfg, ctx) => {\n\t\tvalidateParentReference({\n\t\t\tctx,\n\t\t\tpath: [\"parent\"],\n\t\t\tparent: cfg.parent,\n\t\t});\n\t});\n\n/**\n * The top-level object accepted by `defineConfig`. The `branch` closure is validated\n * structurally as a function here; its returned tuning is validated per-evaluation by\n * {@link branchTuningSchema} inside `resolveConfig`.\n */\nexport const configInputSchema = z\n\t.strictObject({\n\t\tauth: serviceToggleInputSchema.optional(),\n\t\tdataApi: dataApiInputSchema.optional(),\n\t\tpreview: previewInputSchema.optional(),\n\t\tbranch: z\n\t\t\t.custom<(...args: unknown[]) => unknown>(\n\t\t\t\t(value) => typeof value === \"function\",\n\t\t\t\t{\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t\"branch must be a function: `branch: (branch) => ({ … })`\",\n\t\t\t\t},\n\t\t\t)\n\t\t\t.optional(),\n\t})\n\t.superRefine((cfg, ctx) => {\n\t\t// A Data API verified by Neon Auth (`authProvider: \"neon\"`, the default) needs Neon\n\t\t// Auth enabled on the same branch so the tokens it verifies actually exist. Enforce\n\t\t// the same invariant the `defineConfig` type-level check expresses, at runtime.\n\t\tif (!isToggleEnabledValue(cfg.dataApi)) return;\n\t\tif (dataApiAuthProviderValue(cfg.dataApi) !== \"neon\") return;\n\t\tif (!isToggleEnabledValue(cfg.auth)) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: \"custom\",\n\t\t\t\tpath: [\"auth\"],\n\t\t\t\tmessage:\n\t\t\t\t\t'dataApi with authProvider \"neon\" requires Neon Auth — set `auth: true` (or `auth: { enabled: true }`), or use `dataApi.authProvider: \"external\"` with your own `jwksUrl`.',\n\t\t\t});\n\t\t}\n\t});\n\n/**\n * Whether a parsed `auth` / `dataApi` toggle value is enabled: a present object (or `true`)\n * is on unless `enabled` is explicitly `false`. Mirrors `isServiceEnabled` in\n * `define-config.ts`, operating on the already-validated runtime value.\n */\nfunction isToggleEnabledValue(value: unknown): boolean {\n\tif (value === undefined || value === null) return false;\n\tif (typeof value === \"boolean\") return value;\n\tif (typeof value === \"object\") {\n\t\treturn (value as { enabled?: unknown }).enabled !== false;\n\t}\n\treturn false;\n}\n\n/** Read the (defaulted) `authProvider` from a parsed `dataApi` value. */\nfunction dataApiAuthProviderValue(value: unknown): \"neon\" | \"external\" {\n\tif (value !== null && typeof value === \"object\") {\n\t\tconst provider = (value as { authProvider?: unknown }).authProvider;\n\t\tif (provider === \"external\") return \"external\";\n\t}\n\treturn \"neon\";\n}\n\nfunction validateParentReference(args: {\n\tctx: z.RefinementCtx;\n\tpath: (string | number)[];\n\tparent: string | undefined;\n}): void {\n\tconst { ctx, path, parent } = args;\n\tif (parent === undefined) return;\n\n\tconst patternCheck = validatePattern(parent);\n\tif (\"error\" in patternCheck) {\n\t\tctx.addIssue({ code: \"custom\", path, message: patternCheck.error });\n\t} else if (isWildcardPattern(parent)) {\n\t\tctx.addIssue({\n\t\t\tcode: \"custom\",\n\t\t\tpath,\n\t\t\tmessage: `parent must be a concrete branch name (no wildcards), got \"${parent}\"`,\n\t\t});\n\t}\n}\n\n/**\n * Convert the structured {@link z.ZodError} produced by `configSchema.safeParse` into the\n * `string[]` shape used by {@link import(\"./errors.js\").ConfigValidationError}.\n *\n * Issue paths are rendered as dot-separated property accesses (`postgres.computeSettings`)\n * and unknown-key issues from `strictObject` are normalised so the message contains the\n * substring \"unknown key\" — keeping pre-zod assertions in test suites and downstream tools\n * stable.\n */\nexport function formatZodIssues(error: z.ZodError): string[] {\n\treturn error.issues.map((issue) => {\n\t\tconst path = renderPath(issue.path);\n\t\tconst message = normaliseIssueMessage(issue);\n\t\treturn path ? `${path}: ${message}` : message;\n\t});\n}\n\nfunction renderPath(path: ReadonlyArray<PropertyKey>): string {\n\tlet out = \"\";\n\tfor (const segment of path) {\n\t\tif (typeof segment === \"number\") out += `[${segment}]`;\n\t\telse if (out === \"\") out += String(segment);\n\t\telse out += `.${String(segment)}`;\n\t}\n\treturn out;\n}\n\nfunction normaliseIssueMessage(issue: z.core.$ZodIssue): string {\n\tif (issue.code === \"unrecognized_keys\") {\n\t\tconst keys = issue.keys ?? [];\n\t\tconst formatted = keys.map((k) => JSON.stringify(k)).join(\", \");\n\t\treturn `unknown key${keys.length === 1 ? \"\" : \"s\"}: ${formatted}`;\n\t}\n\tif (issue.code === \"invalid_key\") {\n\t\t// A record *key* that fails its key schema (e.g. a bad function slug) surfaces in\n\t\t// zod as a single `invalid_key` issue whose own `message` is the generic, useless\n\t\t// \"Invalid key in record\". The actual reason — the function-slug regex rule, say —\n\t\t// lives in the nested key-schema `issues`. Hoist those so the user sees *why* the\n\t\t// key was rejected (the offending key itself is already in the issue `path`).\n\t\tconst reasons = issue.issues\n\t\t\t.map((nested) => nested.message)\n\t\t\t.filter((message) => message.length > 0);\n\t\tif (reasons.length > 0) return reasons.join(\"; \");\n\t}\n\treturn issue.message;\n}\n"],"mappings":"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"}
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -254,6 +254,37 @@ interface FunctionDevConfig {
|
|
|
254
254
|
*/
|
|
255
255
|
port?: number;
|
|
256
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* The object form of an {@link FunctionDef.externalPackages} entry, for the one case the
|
|
259
|
+
* bare string cannot express: externalizing a package without shipping its files.
|
|
260
|
+
*/
|
|
261
|
+
interface ExternalPackageDef {
|
|
262
|
+
/** Package name, optionally with a subpath: `sharp`, `@scope/pkg`, `pkg/sub`. */
|
|
263
|
+
name: string;
|
|
264
|
+
/**
|
|
265
|
+
* Whether the package's real files ship into the deployed archive next to the bundle.
|
|
266
|
+
*
|
|
267
|
+
* Defaults to `true`, which is the state where the import resolves and the function
|
|
268
|
+
* works. Set it to `false` only for a package the function never reaches: nothing is
|
|
269
|
+
* shipped for it, so reaching it throws `Cannot find module` at invoke.
|
|
270
|
+
*/
|
|
271
|
+
includeFiles?: boolean;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* One entry of {@link FunctionDef.externalPackages}. A bare string is the common form and
|
|
275
|
+
* ships the package's files; {@link ExternalPackageDef} exists to turn that off.
|
|
276
|
+
*/
|
|
277
|
+
type ExternalPackageEntry = string | ExternalPackageDef;
|
|
278
|
+
/**
|
|
279
|
+
* An {@link ExternalPackageEntry} with its default applied, as every consumer downstream of
|
|
280
|
+
* `resolveConfig` reads it.
|
|
281
|
+
*/
|
|
282
|
+
interface ResolvedExternalPackage {
|
|
283
|
+
/** Package name as declared, subpath included. */
|
|
284
|
+
name: string;
|
|
285
|
+
/** Whether this package's files are staged into the archive. */
|
|
286
|
+
includeFiles: boolean;
|
|
287
|
+
}
|
|
257
288
|
/**
|
|
258
289
|
* Static definition of a Neon Function (Preview feature). Declares that the function
|
|
259
290
|
* **exists** on every branch; its branch-unique slug is the **record key** in
|
|
@@ -295,41 +326,67 @@ interface FunctionDef {
|
|
|
295
326
|
*/
|
|
296
327
|
env?: Record<string, string>;
|
|
297
328
|
/**
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
329
|
+
* Ship a dependency's real files into the deployed archive instead of bundling it —
|
|
330
|
+
* `sharp` and other packages backed by a native binary.
|
|
331
|
+
*
|
|
332
|
+
* The deploy-time equivalent of Next.js's `serverExternalPackages`. Every entry is passed
|
|
333
|
+
* to esbuild's `external`, so the import survives into the bundle instead of being
|
|
334
|
+
* followed, and the package's own files are shipped beside the bundle so that import
|
|
335
|
+
* resolves.
|
|
301
336
|
*
|
|
302
337
|
* Reach for this when bundling a package is impossible rather than merely undesirable.
|
|
303
|
-
* The
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
338
|
+
* The case that comes up is a package backed by a native `.node` binary: the binary is a
|
|
339
|
+
* compiled object the platform loads from a real path, so no bundler can inline it.
|
|
340
|
+
* `sharp` is the common one, and it does not even fail at build time — it loads its
|
|
341
|
+
* binary through `createRequire`, which esbuild does not follow, so it bundles cleanly
|
|
342
|
+
* and then fails at invoke with "Could not load the sharp module".
|
|
343
|
+
*
|
|
344
|
+
* ```ts
|
|
345
|
+
* externalPackages: ["sharp"]
|
|
346
|
+
* ```
|
|
347
|
+
*
|
|
348
|
+
* Each declared package is installed for the Functions runtime target — **linux-arm64,
|
|
349
|
+
* glibc** — into a throwaway directory, traced for the files it actually reaches, and
|
|
350
|
+
* copied into the archive under `node_modules/` with its directory layout preserved. That
|
|
351
|
+
* layout is load-bearing rather than cosmetic: a `.node` addon locates its sibling shared
|
|
352
|
+
* libraries relative to its own directory, so a flattened tree fails to load.
|
|
353
|
+
*
|
|
354
|
+
* Your own `node_modules` is never read for these files or modified. Its binaries are
|
|
355
|
+
* built for your machine rather than the deploy target, and a cross-platform install does
|
|
356
|
+
* not survive your next plain `npm install`, so the target's packages are resolved fresh
|
|
357
|
+
* on each deploy.
|
|
358
|
+
*
|
|
359
|
+
* Requirements, all reported at deploy time rather than at invoke: the package must
|
|
360
|
+
* publish a linux-arm64 glibc build (`sharp` and most `@napi-rs/*` packages do; anything
|
|
361
|
+
* compiled from source at install time does not), `npm` must be on `PATH`, and the
|
|
362
|
+
* archive must stay inside the deploy size limits — native binaries are large.
|
|
363
|
+
*
|
|
364
|
+
* ### Excluding a package's files
|
|
308
365
|
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
* unblocks an import that is never evaluated; it does not make a dependency usable.
|
|
366
|
+
* `includeFiles: false` externalizes the import without shipping anything, which is the
|
|
367
|
+
* escape hatch for a package that cannot be staged — no build for the target, or too
|
|
368
|
+
* large — and that the function never actually reaches:
|
|
313
369
|
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
* native `.node` binary cannot be bundled by anything — the binary is a compiled
|
|
318
|
-
* object the platform loads from a real path — so such a package cannot work on
|
|
319
|
-
* Functions until the deployed archive can carry files alongside the bundle. Do not
|
|
320
|
-
* reach for `externalPackages` to try: it moves the error from deploy to invoke.
|
|
370
|
+
* ```ts
|
|
371
|
+
* externalPackages: ["sharp", { name: "canvas", includeFiles: false }]
|
|
372
|
+
* ```
|
|
321
373
|
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
374
|
+
* **An excluded package is not resolvable at runtime.** Nothing is shipped for it, so it
|
|
375
|
+
* throws `Cannot find module` if the function reaches it. It unblocks an import that is
|
|
376
|
+
* never evaluated; it does not make a dependency usable.
|
|
325
377
|
*
|
|
326
|
-
* Entries are package names, optionally with a subpath (`pkg`, `@scope/pkg`,
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
*
|
|
330
|
-
*
|
|
378
|
+
* Entries are package names, optionally with a subpath (`pkg`, `@scope/pkg`, `pkg/sub`),
|
|
379
|
+
* matching esbuild. A relative or absolute path is rejected at validation time: those are
|
|
380
|
+
* local modules, and a local module that cannot be bundled is a different problem. Files
|
|
381
|
+
* are staged per package, so a subpath narrows what esbuild leaves unresolved without
|
|
382
|
+
* narrowing what ships.
|
|
383
|
+
*
|
|
384
|
+
* Under `neon dev` the list only keeps the package out of the bundle — nothing is
|
|
385
|
+
* installed or copied, and it resolves from your own `node_modules` against your host
|
|
386
|
+
* architecture, which is what you want locally.
|
|
387
|
+
* @example ["sharp", { name: "canvas", includeFiles: false }]
|
|
331
388
|
*/
|
|
332
|
-
externalPackages?:
|
|
389
|
+
externalPackages?: ExternalPackageEntry[];
|
|
333
390
|
/**
|
|
334
391
|
* Local-development settings used by `neon dev` when serving every function from
|
|
335
392
|
* `neon.ts`. Ignored at deploy time. See {@link FunctionDevConfig}.
|
|
@@ -485,11 +542,13 @@ interface ResolvedFunctionConfig {
|
|
|
485
542
|
source: string;
|
|
486
543
|
env: Record<string, string>;
|
|
487
544
|
/**
|
|
488
|
-
* Packages the bundler leaves unresolved,
|
|
489
|
-
* {@link FunctionDef.externalPackages}
|
|
490
|
-
*
|
|
545
|
+
* Packages the bundler leaves unresolved, normalized from
|
|
546
|
+
* {@link FunctionDef.externalPackages} with `includeFiles` defaulted.
|
|
547
|
+
*
|
|
548
|
+
* Absent rather than empty when undeclared, so a policy that never mentions it takes the
|
|
549
|
+
* pre-existing bundling path and produces the archive it always did.
|
|
491
550
|
*/
|
|
492
|
-
externalPackages?:
|
|
551
|
+
externalPackages?: ResolvedExternalPackage[];
|
|
493
552
|
runtime: FunctionRuntime;
|
|
494
553
|
/**
|
|
495
554
|
* Local-development settings, passed through untouched from {@link FunctionDef.dev}
|
|
@@ -582,7 +641,20 @@ interface PushResult {
|
|
|
582
641
|
dryRun: boolean;
|
|
583
642
|
applied: AppliedChange[];
|
|
584
643
|
conflicts: ConflictReport[];
|
|
644
|
+
/**
|
|
645
|
+
* Advisory findings from the push — a function that bundles a native dependency it never
|
|
646
|
+
* declared, or a staged package whose version could not be pinned.
|
|
647
|
+
*
|
|
648
|
+
* Returned rather than logged, because a library has no business choosing an output
|
|
649
|
+
* channel, and returned rather than left to an opt-in callback, because these are the
|
|
650
|
+
* only warning that a deployed function will fail at invoke and an unregistered callback
|
|
651
|
+
* is easy to never notice. Empty when there is nothing to report.
|
|
652
|
+
*
|
|
653
|
+
* Only populated by the built-in bundler: a caller that injects its own `bundleFunction`
|
|
654
|
+
* owns its own reporting.
|
|
655
|
+
*/
|
|
656
|
+
warnings: string[];
|
|
585
657
|
}
|
|
586
658
|
//#endregion
|
|
587
|
-
export { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConflictReport, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DurationString, DurationUnit, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput };
|
|
659
|
+
export { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConflictReport, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DurationString, DurationUnit, ExternalPackageDef, ExternalPackageEntry, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedExternalPackage, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput };
|
|
588
660
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/lib/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/lib/types.ts"],"mappings":";;AAIA;AAGA;AAeA;AAQK,KA1BO,WAAA,GA0BP,IAAA,GAAwB,GAAA,GAAA,CAAA,GAAA,CAAA,GAAA,CAAA,GAAA,CAAA;AAAA;AAyBxB,KAhDO,YAAA,GAgDM,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA;AAAA;AAAqB;AACpC;AACC;AAAiB;AAAW;AAUhC;AAAgC;AAMP;AAMA;AAqBe;AAAd;AAAa;AAStB,KAvFL,cAAA,GAuFiB,GAAA,MAAA,GAvFY,YAuFZ,EAAA;AAqB7B;AAgBA;AAeA;AAA0B;AAAO;AAE7B;AAEC,KAvIA,wBAAA,GAuIA,IAAA,GAAA,IAAA,GAAA,KAAA,GAAA,KAAA,GAAA,IAAA,GAAA,IAAA,GAAA,KAAA,GAAA,IAAA,GAAA,IAAA;AAEC;AAEC;AAEC;AAAC;AAIT;AAgBA;AACA,KAjJK,aAAA,GAiJO,IAAA,GAAmB,IAAA,GAAA,KAAW,GAAA,IAAA,GAAA,IAAA,GAAA,IAAuB,GAAA,KAAA,GAAA,KAAA;AASjE;AAqBC;AAeD;AAcA;AAiBA;AAAyB;AAAG,KArNvB,aAqNuB,CAAA,oBArNW,cAqNX,CAAA,GApNzB,WAoNyB,GAAA,CAnNxB,cAmNwB,GAnNP,WAmNO,CAAA,OAAA,CAAA,CAAA,GAAA,MAAA;AAAwB;AAAyB;AAO7E;AAOA;AAMA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/lib/types.ts"],"mappings":";;AAIA;AAGA;AAeA;AAQK,KA1BO,WAAA,GA0BP,IAAA,GAAwB,GAAA,GAAA,CAAA,GAAA,CAAA,GAAA,CAAA,GAAA,CAAA;AAAA;AAyBxB,KAhDO,YAAA,GAgDM,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA;AAAA;AAAqB;AACpC;AACC;AAAiB;AAAW;AAUhC;AAAgC;AAMP;AAMA;AAqBe;AAAd;AAAa;AAStB,KAvFL,cAAA,GAuFiB,GAAA,MAAA,GAvFY,YAuFZ,EAAA;AAqB7B;AAgBA;AAeA;AAA0B;AAAO;AAE7B;AAEC,KAvIA,wBAAA,GAuIA,IAAA,GAAA,IAAA,GAAA,KAAA,GAAA,KAAA,GAAA,IAAA,GAAA,IAAA,GAAA,KAAA,GAAA,IAAA,GAAA,IAAA;AAEC;AAEC;AAEC;AAAC;AAIT;AAgBA;AACA,KAjJK,aAAA,GAiJO,IAAA,GAAmB,IAAA,GAAA,KAAW,GAAA,IAAA,GAAA,IAAA,GAAA,IAAuB,GAAA,KAAA,GAAA,KAAA;AASjE;AAqBC;AAeD;AAcA;AAiBA;AAAyB;AAAG,KArNvB,aAqNuB,CAAA,oBArNW,cAqNX,CAAA,GApNzB,WAoNyB,GAAA,CAnNxB,cAmNwB,GAnNP,WAmNO,CAAA,OAAA,CAAA,CAAA,GAAA,MAAA;AAAwB;AAAyB;AAO7E;AAOA;AAMA;AAYA;AAiBA;AAMiB,UAhQA,eAAA,CAgQuB;EAsBvB;AAAW;AAwBrB;AA8Da;AAKb;EAAiB,qBAAA,CAAA,EA3WC,WA2WD;EAeZ;AAWZ;AAGA;AAOA;AAcA;EAA6B,qBAAA,CAAA,EAvZJ,WAuZI;EAEhB;AAEe;AAAf;AAEa;AAAf;AAAM;AASjB;AAUA;AAA8B;AACF;AAAM;AAAb;AAAR;AAAO;AASpB;AAA6B;AAyBR;AAAd;AAGK;AACa;EAAd,cAAA,CAAA,EAAA,KAAA,GAlce,aAkcf,CAlc6B,wBAkc7B,CAAA;AAAa;AACvB;AAGmB;AAAiB;AACpC;AAGiB;AAAd;AAAO,UAjcM,YAAA,CAicN;EAOC;EAAc,IAAA,EAAA,MAAA;EACT;EAA2B,EAAA,CAAA,EAAA,MAAA;EAC/B;EAA8C,MAAA,EAAA,OAAA;EAAhB;EAAb,QAAA,CAAA,EAAA,MAAA;EAAY;EAezB,SAAM,CAAA,EAAA,OAAA;EAAA;EACT,WAAA,CAAA,EAAA,OAAA;EACV;EAEa,SAAA,CAAA,EAAA,MAAA;AAA2B;AAC3B;AAA2B;AAGpC;AAOG;AAEA,UArdM,aAAA,CAqdN;EAEc;EAAf,OAAA,CAAA,EAAA,OAAA;AAAc;AAOxB;AAAuC;AAIjC;AAQc;AACV;AAKH;AAAiB;AAIxB;AAUA;AAAsC;AAC1B;AACF,KAhfE,kBAAA,GAgfF,OAAA,GAhfiC,aAgfjC;AAAoB;AAU9B;AAAsC;AACvB;AAIH;AAAe;AAG3B;AAAqC;AAIzB;AAOD;AACA;AAAqB;AAMhC;AAkBiB,KAvhBL,cAuhBmB,CAAA,CAAA,CAAA,GAAA,CAvhBE,CAuhBF,CAAA,SAAA,CAAA,KAAA,CAAA,GAAA,KAAA,GAAA,CArhB3B,CAqhB2B,CAAA,SAAA,CAAA;EAYd,OAAA,EAAA,KAAU;AAAA,CAAA,CAAA,GAAA,KAAA,GAAA,CA/hBtB,CA+hBsB,CAAA,SAAA,CAAA,SAAA,CAAA,GAAA,KAAA,GAAA,CA7hBrB,CA6hBqB,CAAA,SAAA,CAAA,IAAA,CAAA,GAAA,IAAA,GAAA,CA3hBpB,CA2hBoB,CAAA,SAAA,CAAA;EAUjB,OAAA,EAAA,IAAA;AACE,CAAA,CAAA,GAAA,IAAA,GAAA,CApiBJ,CAoiBI,CAAA,SAAA,CAAA,MAAA,CAAA,GAAA,IAAA,GAAA,KAAA;AAAc,UAhiBT,cAAA,CAgiBS;oBA/hBP;;;;;;;;;;;;;;cAeN;KACD,mBAAA,WAA8B;;;;;;;;UASzB,eAAA;;;;;;;;;;;;;;;;;;;;;;;UAwBP,iBAAA;;;;aAIE;;;;;;;UAQK,qBAAA,SAA8B;;;;;;;;;;;;;UAc9B,yBAAA,SAAkC;;;;;;;;;;;;;;;;KAiBvC,aAAA,GAAgB,wBAAwB;;;;;;KAOxC,YAAA,aAAyB;;;;;;KAOzB,eAAA;;;;;UAMK,iBAAA;;;;;;;;;;;UAYA,kBAAA;;;;;;;;;;;;;;;;KAiBL,oBAAA,YAAgC;;;;;UAM3B,uBAAA;;;;;;;;;;;;;;;;;;;;;UAsBA,WAAA;;;;;;;;;;;;;;;;;;;;;;;;QAwBV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA8Da;;;;;QAKb;;;;;;;;;;;;;;KAeK,eAAA;;;;;;KAWA,uBAAA;;KAGA,iBAAA;;;;;;UAOK,SAAA;;;;;WAKP;;;;;;;;UASO,YAAA;;cAEJ;;cAEA,eAAe;;YAEjB,eAAe;;;;;;;;UAST,cAAA;;YAEN;;;;;;;UAQM;cACJ,QAAQ,OAAO,MAAM;;;;;;;;UASjB;;;;;;;;;;;;;;;;;;;;;;;;;QAyBV,cAAc;;;aAGT;YACD,cAAc;;;KAIpB,gCAAgC,4BACpC;;IAGG,cAAc;;;;;KAON,+BACK,2BAA2B,qCAC/B,iBAAiB,aAAa,gBAAgB;;;;;;;;;;;;;;UAe1C,oBACH,iCACV,gDAEa,2BAA2B,0CAC3B,2BAA2B;;SAGpC;;;;;;;YAOG;;YAEA;;WAED,eAAe;;;;;;UAOR,sBAAA;;;;OAIX;;;;;;;;qBAQc;WACV;;;;;QAKH;;;UAIU,oBAAA;;UAER;;;;;;;UAQQ,qBAAA;aACL;WACF;;;;;;;;;UAUO,qBAAA;gBACF;;;;aAIH;;UAGK,oBAAA;;;;aAIL;;;;;;;YAOD;YACA;;;;;UAMM,aAAA;;;;;;;;YAQN;;;;;;;;;UAUM,cAAA;;;;;;;;;;;UAYA,UAAA;;;;;;;;;;WAUP;aACE"}
|
package/dist/lib/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../src/lib/types.ts"],"sourcesContent":["/**\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 */\nexport type ComputeUnit = 0.25 | 0.5 | 1 | 2 | 4 | 8;\n\n/** Time units accepted in a {@link DurationString}: seconds, minutes, hours, days, weeks. */\nexport type DurationUnit = \"s\" | \"m\" | \"h\" | \"d\" | \"w\";\n\n/**\n * A Neon duration string: a positive integer **followed by a unit** — `s` (seconds),\n * `m` (minutes), `h` (hours), `d` (days), or `w` (weeks). Used by\n * {@link ComputeSettings.suspendTimeout} and {@link BranchTuning.ttl}.\n *\n * A **unit is required**: a bare numeric string like `\"7\"` is rejected at the type level. To\n * express a raw number of seconds, pass a `number` (`300`) — not a string (`\"300\"`). This\n * removes the old ambiguity where `\"7\"` silently meant 7 *seconds* instead of, say, `\"7d\"`.\n *\n * @example \"5m\" // 5 minutes\n * @example \"1h\" // 1 hour\n * @example \"7d\" // 7 days\n */\nexport type DurationString = `${number}${DurationUnit}`;\n\n/**\n * Autocomplete suggestions for {@link ComputeSettings.suspendTimeout}. Every value sits inside\n * the Neon API's allowed scale-to-zero band: **60s–604800s** (1 minute – 1 week). This is *not*\n * a closed set — the field also accepts any other {@link DurationString} or a `number` of\n * seconds; out-of-range values type-check but are rejected at apply time.\n */\ntype SuspendTimeoutSuggestion =\n\t| \"1m\"\n\t| \"5m\"\n\t| \"15m\"\n\t| \"30m\"\n\t| \"1h\"\n\t| \"6h\"\n\t| \"12h\"\n\t| \"1d\"\n\t| \"7d\";\n\n/**\n * Autocomplete suggestions for {@link BranchTuning.ttl}. Every value sits within the Neon API's\n * branch-expiration limit (**max 30 days** from creation; the Console's own presets are 1h / 1d\n * / 7d). This is *not* a closed set — the field also accepts any other {@link DurationString} or\n * a `number` of seconds; values over 30 days are rejected at apply time.\n */\ntype TtlSuggestion = \"1h\" | \"6h\" | \"12h\" | \"1d\" | \"3d\" | \"7d\" | \"14d\" | \"30d\";\n\n/**\n * Compose a field's duration type: its curated autocomplete `Suggestions` plus the open\n * `DurationString` template (so any `<integer><unit>` string still type-checks) and a `number`\n * of seconds. Intersecting the template arm with `NonNullable<unknown>` stops TypeScript from\n * collapsing the literal suggestions into the template, which is what preserves the autocomplete.\n */\ntype DurationField<Suggestions extends DurationString> =\n\t| Suggestions\n\t| (DurationString & NonNullable<unknown>)\n\t| number;\n\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 defaults).\n */\nexport interface ComputeSettings {\n\t/**\n\t * Minimum number of Compute Units. Set to 0.25 for true scale-to-zero.\n\t * @example 0.25 // scale-to-zero\n\t * @example 1 // always-on with 1 CU minimum\n\t */\n\tautoscalingLimitMinCu?: ComputeUnit;\n\t/**\n\t * Maximum number of Compute Units for autoscaling.\n\t * @example 2\n\t * @example 8\n\t */\n\tautoscalingLimitMaxCu?: ComputeUnit;\n\t/**\n\t * How long an idle compute waits before suspending (Neon's scale-to-zero). Accepts a\n\t * {@link DurationString} (autocompletes common values), a number of seconds, or `false`.\n\t *\n\t * - `false` — never suspend (always-on compute)\n\t * - {@link DurationString} — e.g. `\"5m\"`; autocompletes the in-range values `\"1m\"`, `\"5m\"`,\n\t * `\"15m\"`, `\"30m\"`, `\"1h\"`, `\"6h\"`, `\"12h\"`, `\"1d\"`, `\"7d\"`, and accepts any other\n\t * `<integer><unit>` (units: `s`, `m`, `h`, `d`, `w`). A **unit is required** — for raw\n\t * seconds pass a `number`, not a string.\n\t * - `number` — custom timeout in **seconds**, must be in `60`–`604800` (1 minute to 1 week)\n\t * - `undefined` — use the Neon default (currently 300s / 5 minutes)\n\t *\n\t * Whichever form you use, the resolved timeout must fall in `60`–`604800` seconds (the Neon\n\t * API limit); the suggestions are all within that band, anything else is checked at apply.\n\t *\n\t * @example false // never suspend (always-on)\n\t * @example \"5m\" // suspend after 5 minutes idle\n\t * @example \"1h\" // suspend after 1 hour idle\n\t * @example 300 // 5 minutes, expressed in seconds\n\t */\n\tsuspendTimeout?: false | DurationField<SuspendTimeoutSuggestion>;\n}\n\n/**\n * Read-only descriptor of the branch a {@link Config} policy is being evaluated for — the\n * `branch` argument passed to your `defineConfig({ branch: (branch) => … })` closure. It describes\n * **which** branch this invocation decides for; it is not a live branch handle and must not\n * be mutated. Switch on its fields and return the desired {@link BranchConfig}.\n */\nexport interface BranchTarget {\n\t/** Branch name being evaluated. For `branch dev`, this is the generated branch name. */\n\tname: string;\n\t/** Neon branch id when the branch already exists. Undefined during pre-create eval. */\n\tid?: string;\n\t/** Whether this branch already exists on Neon. */\n\texists: boolean;\n\t/** Parent branch id from Neon when known. */\n\tparentId?: string;\n\t/** Whether Neon marks this branch as the project default. */\n\tisDefault?: boolean;\n\t/** Whether Neon currently marks this branch protected. */\n\tisProtected?: boolean;\n\t/** Current expiration timestamp from Neon, when set. */\n\texpiresAt?: string;\n}\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 */\nexport interface ServiceToggle {\n\t/** Defaults to `true` when the service namespace is present. Set `false` to opt out. */\n\tenabled?: boolean;\n}\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 */\nexport type ServiceToggleInput = boolean | ServiceToggle;\n\n/**\n * Resolve a **static** service toggle (`true` / `false` / `{ enabled?: boolean }` / object /\n * `undefined`) to a type-level boolean. The tuple wrapping (`[T] extends […]`) disables\n * distribution so a union/`undefined` is judged as a single unit:\n *\n * - `false` / `{ enabled: false }` / `undefined` → `false`\n * - `true` / `{ enabled: true }` / any other object (`{}`, `{ enabled?: boolean }`) → `true`\n * (a present toggle defaults to enabled)\n * - the bare `boolean | … | undefined` (no literal info) → `false`\n *\n * Shared by the {@link Config} static cross-field checks and the `@neon/env`\n * `NeonEnv` namespace derivation, so both read \"is this service on?\" identically.\n */\nexport type ServiceEnabled<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\nexport interface PostgresConfig {\n\tcomputeSettings?: ComputeSettings;\n}\n\n/**\n * Authentication providers a Data API integration can verify JWTs against, as written in\n * `neon.ts`. Friendly authoring values (mapped to the Neon API's `neon_auth` / `external`\n * at the API boundary):\n *\n * - `\"neon\"` — verify tokens minted by **Neon Auth** on the same branch. Neon supplies the\n * JWKS URL / provider wiring for you, so the `jwksUrl` / `providerName` / `jwtAudience`\n * fields are forbidden (a type error) on this variant — and the policy must also enable\n * top-level `auth` (Neon Auth) so the tokens exist.\n * - `\"external\"` — verify tokens from a third-party IdP (Clerk, Stytch, Auth0, …). You\n * provide `jwksUrl` (and optionally `providerName` / `jwtAudience`).\n */\nexport const DATA_API_AUTH_PROVIDERS = [\"neon\", \"external\"] as const;\nexport type DataApiAuthProvider = (typeof DATA_API_AUTH_PROVIDERS)[number];\n\n/**\n * Reusable runtime settings for a Data API integration (the Neon API `DataAPISettings`,\n * camelCased to match the rest of `neon.ts`). Every field is optional; omitted fields keep\n * the Neon defaults shown below. These are the **only** Data API fields that can change on\n * an already-enabled integration — drift here is reconciled as an *update* (requires\n * `updateExisting` / `--update-existing`); the create-only auth wiring above cannot.\n */\nexport interface DataApiSettings {\n\t/** Enable the aggregates feature (`db_aggregates_enabled`). Default `true`. */\n\tdbAggregatesEnabled?: boolean;\n\t/** Database role used for anonymous requests (`db_anon_role`). Default `\"anonymous\"`. */\n\tdbAnonRole?: string;\n\t/** Extra schemas appended to the search path (`db_extra_search_path`). */\n\tdbExtraSearchPath?: string;\n\t/** Maximum rows returned in a single request (`db_max_rows`). */\n\tdbMaxRows?: number;\n\t/** Schemas exposed via the API (`db_schemas`). Default `[\"public\"]`. */\n\tdbSchemas?: string[];\n\t/** JWT claim key used for role extraction (`jwt_role_claim_key`). Default `\".role\"`. */\n\tjwtRoleClaimKey?: string;\n\t/** Maximum lifetime of the JWT cache, in seconds (`jwt_cache_max_lifetime`). */\n\tjwtCacheMaxLifetime?: number;\n\t/** OpenAPI spec mode (`openapi_mode`). Default `\"disabled\"`. */\n\topenapiMode?: \"ignore-privileges\" | \"disabled\";\n\t/** CORS allowed origins (`server_cors_allowed_origins`). */\n\tserverCorsAllowedOrigins?: string;\n\t/** Emit server-timing headers (`server_timing_enabled`). */\n\tserverTimingEnabled?: boolean;\n}\n\n/** Fields shared by every {@link DataApiConfig} variant. */\ninterface DataApiConfigBase {\n\t/** Defaults to `true` when the `dataApi` namespace is present. Set `false` to opt out. */\n\tenabled?: boolean;\n\t/** Reusable runtime settings. Drift here is reconciled as an update. */\n\tsettings?: DataApiSettings;\n}\n\n/**\n * Data API verified by **Neon Auth** (`authProvider: \"neon\"`, the default). The external\n * IdP fields are statically forbidden (`?: never`) because Neon supplies them; declaring any\n * of them is a type error directing you to `authProvider: \"external\"`.\n */\nexport interface DataApiNeonAuthConfig extends DataApiConfigBase {\n\tauthProvider?: \"neon\";\n\t/** Forbidden with `authProvider: \"neon\"` — Neon provides the JWKS URL. */\n\tjwksUrl?: never;\n\t/** Forbidden with `authProvider: \"neon\"` — the provider is Neon Auth. */\n\tproviderName?: never;\n\t/** Forbidden with `authProvider: \"neon\"` — Neon manages the audience. */\n\tjwtAudience?: never;\n}\n\n/**\n * Data API verified by an **external** IdP (`authProvider: \"external\"`). You provide the\n * JWKS URL (and optionally a provider label / expected audience).\n */\nexport interface DataApiExternalAuthConfig extends DataApiConfigBase {\n\tauthProvider: \"external\";\n\t/** URL that publishes the IdP's JWKS (JSON Web Key Set). */\n\tjwksUrl?: string;\n\t/** Human label for the IdP (e.g. \"Clerk\", \"Stytch\", \"Auth0\"). */\n\tproviderName?: string;\n\t/**\n\t * Expected `aud` claim. ⚠️ This only **rejects** tokens carrying a *different* audience;\n\t * tokens with no `aud` claim are still accepted.\n\t */\n\tjwtAudience?: string;\n}\n\n/**\n * Object form of the `dataApi` toggle. A discriminated union on {@link DataApiAuthProvider}:\n * the `\"neon\"` variant forbids the external-IdP fields, the `\"external\"` variant allows them.\n */\nexport type DataApiConfig = DataApiNeonAuthConfig | DataApiExternalAuthConfig;\n\n/**\n * How the Data API is toggled in a policy: a bare boolean (like the other service toggles)\n * or the richer {@link DataApiConfig} object. `true` / `{}` / `{ enabled: true }` enable it\n * with Neon defaults; `false` / `{ enabled: false }` opt out.\n */\nexport type DataApiInput = boolean | DataApiConfig;\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 */\nexport type FunctionRuntime = \"nodejs24\";\n\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 */\nexport interface FunctionDevConfig {\n\t/**\n\t * Port the local server binds. Bound exactly (and `neon dev` fails loudly if it is taken)\n\t * when set; a free port is found automatically when omitted.\n\t */\n\tport?: number;\n}\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 */\nexport interface FunctionDef {\n\t/** Free-form display name. @example \"Hello World\" */\n\tname: string;\n\t/**\n\t * Path to the function's entry module, **relative to `neon.ts`** (or absolute). The\n\t * module's default export (`{ fetch }`) or `handler` export is the function entry. This\n\t * path is resolved against the loaded `neon.ts` location and bundled with esbuild at\n\t * deploy time.\n\t *\n\t * We require a string path rather than an imported handler because a JS function value\n\t * carries no reference back to its source file, so esbuild has nothing to bundle from.\n\t * @example \"./functions/hello-world.ts\"\n\t */\n\tsource: string;\n\t/**\n\t * Environment variables injected into the deployed function, keyed by the var name the\n\t * function reads at runtime. The **keys** are static (preserved at the type level so\n\t * `parseEnv(config, \"<slug>\").function.<key>` is typed); the **values** are arbitrary\n\t * strings evaluated when `neon.ts` is loaded (typically `process.env.X`) and uploaded\n\t * at `config apply`. Every value must be a defined string — a `process.env.X` that is\n\t * `undefined` (unset) errors at validation time rather than silently shipping\n\t * `undefined`.\n\t * @example { resendApiKey: process.env.RESEND_API_KEY ?? \"\" }\n\t */\n\tenv?: Record<string, string>;\n\t/**\n\t * Packages the bundler must leave alone, by name — the deploy-time equivalent of\n\t * Next.js's `serverExternalPackages`. Every entry is passed to esbuild's `external`,\n\t * so the import survives into the bundle instead of being followed.\n\t *\n\t * Reach for this when bundling a package is impossible rather than merely undesirable.\n\t * The cases that come up: a native `.node` addon or a `node-gyp` dependency esbuild has\n\t * no loader for, and an optional peer dependency a library references on a code path\n\t * this function never takes. Both fail the deploy at bundle time with a resolve or\n\t * loader error naming the package, and neither is fixable from the function's own\n\t * source.\n\t *\n\t * **An external package is not resolvable at runtime.** The deployed archive is a\n\t * single `index.mjs` with no `node_modules` beside it, so anything listed here throws\n\t * `Cannot find module` if the function actually reaches it. This option therefore only\n\t * unblocks an import that is never evaluated; it does not make a dependency usable.\n\t *\n\t * A dependency the handler actually calls has to be bundled, and whether that is\n\t * possible depends on what it is. A pure-JavaScript package can be bundled, and a\n\t * failure to do so is usually something specific and fixable. A package backed by a\n\t * native `.node` binary cannot be bundled by anything — the binary is a compiled\n\t * object the platform loads from a real path — so such a package cannot work on\n\t * Functions until the deployed archive can carry files alongside the bundle. Do not\n\t * reach for `externalPackages` to try: it moves the error from deploy to invoke.\n\t *\n\t * Note that a native package may bundle without ever needing this option. `sharp`, for\n\t * instance, loads its binary through `createRequire`, which esbuild does not follow, so\n\t * it bundles cleanly and then fails at invoke with \"Could not load the sharp module\".\n\t *\n\t * Entries are package names, optionally with a subpath (`pkg`, `@scope/pkg`,\n\t * `pkg/sub`), matching esbuild. A relative or absolute path is rejected at validation\n\t * time: those are local modules, and a local module that cannot be bundled is a\n\t * different problem.\n\t * @example [\"microsandbox\", \"@mongodb-js/zstd\"]\n\t */\n\texternalPackages?: string[];\n\t/**\n\t * Local-development settings used by `neon dev` when serving every function from\n\t * `neon.ts`. Ignored at deploy time. See {@link FunctionDevConfig}.\n\t */\n\tdev?: FunctionDevConfig;\n}\n\n/**\n * A single capability a branch-scoped service credential may exercise (Preview). A\n * credential is granted a set of these and may only perform the listed actions. Mirrors\n * the Neon API `CredentialScope` enum (`x-stability-level: beta`):\n *\n * - `storage:read` / `storage:write` — object-storage (bucket) access via the S3 key.\n * - `ai_gateway:invoke` — call the AI Gateway with the bearer `api_token`.\n * - `functions:invoke` — invoke Neon Functions with the bearer `api_token`.\n *\n * The set a policy needs is derived from its enabled Preview features (see\n * {@link deriveCredentialScopes}); it is never authored by hand.\n */\nexport type CredentialScope =\n\t| \"storage:read\"\n\t| \"storage:write\"\n\t| \"ai_gateway:invoke\"\n\t| \"functions:invoke\";\n\n/**\n * Who a credential acts as. `user` is the developer/app principal minted for local dev and\n * app bootstrap (`fetchEnv` / `env pull`); `function` is a deployed-function principal\n * (carries a `function_id`). The env tooling only mints `user` credentials today.\n */\nexport type CredentialPrincipalType = \"user\" | \"function\";\n\n/** Anonymous-access level for a branchable object-storage bucket. */\nexport type BucketAccessLevel = \"private\" | \"public_read\";\n\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 */\nexport interface BucketDef {\n\t/**\n\t * Anonymous access level. `private` (default) requires authenticated reads/writes;\n\t * `public_read` allows anonymous GetObject/HeadObject.\n\t */\n\taccess?: BucketAccessLevel;\n}\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 */\nexport interface PreviewInput {\n\t/** Enable/disable the AI Gateway on the branch (toggle, like auth / dataApi). */\n\taiGateway?: ServiceToggleInput;\n\t/** Functions to deploy, keyed by branch-unique slug (`^[a-z0-9]{1,20}$`). */\n\tfunctions?: Record<string, FunctionDef>;\n\t/** Object-storage buckets to create, keyed by bucket name. */\n\tbuckets?: Record<string, BucketDef>;\n}\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 */\nexport interface FunctionTuning {\n\t/** Runtime to execute the function with. Defaults to `\"nodejs24\"`. */\n\truntime?: FunctionRuntime;\n}\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 */\nexport interface PreviewTuning<Slug extends string = string> {\n\tfunctions?: Partial<Record<Slug, FunctionTuning>>;\n}\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 */\nexport interface BranchTuning<Slug extends string = string> {\n\t/** Parent branch name used when creating a new branch. Not a Postgres setting. */\n\tparent?: string;\n\t/**\n\t * Branch time-to-live: how long after creation the branch should auto-expire. Applied\n\t * when creating a new branch and reconciled on existing branches (when `updateExisting`\n\t * is set). Accepts a {@link DurationString} (autocompletes common values) or a number of\n\t * seconds. Omit to keep the branch indefinitely.\n\t *\n\t * - {@link DurationString} — e.g. `\"7d\"`; autocompletes `\"1h\"`, `\"6h\"`, `\"12h\"`, `\"1d\"`,\n\t * `\"3d\"`, `\"7d\"`, `\"14d\"`, `\"30d\"`, and accepts any other `<integer><unit>` (units: `s`,\n\t * `m`, `h`, `d`, `w` — e.g. `\"12h\"`, `\"2w\"`). A **unit is required** — `\"7\"` is rejected;\n\t * for raw seconds pass a `number`.\n\t * - `number` — custom TTL in **seconds** (e.g. `3600`)\n\t * - `undefined` — no expiry; the branch persists until explicitly deleted\n\t *\n\t * The Neon API caps branch expiration at **30 days** from creation, so the resolved TTL must\n\t * be `> 0` and `<= 30d`; the suggestions stay within that limit and anything longer is\n\t * rejected at apply.\n\t *\n\t * @example \"1d\" // ephemeral preview branch: expires a day after creation\n\t * @example \"7d\" // one-week TTL\n\t * @example \"30d\" // the maximum the API allows\n\t * @example 3600 // 1 hour, expressed in seconds\n\t */\n\tttl?: DurationField<TtlSuggestion>;\n\t/** Whether the selected branch should be protected. Undefined means \"leave as-is\". */\n\tprotected?: boolean;\n\tpostgres?: PostgresConfig;\n\tpreview?: PreviewTuning<Slug>;\n}\n\n/** Extract the declared function slugs from a {@link PreviewInput} for closure typing. */\ntype FunctionSlugsOf<Preview extends PreviewInput | undefined> =\n\tPreview extends {\n\t\tfunctions: infer F;\n\t}\n\t\t? Extract<keyof F, string>\n\t\t: string;\n\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 */\nexport type BranchTuningFn<\n\tPreview extends PreviewInput | undefined = PreviewInput | undefined,\n> = (branch: BranchTarget) => BranchTuning<FunctionSlugsOf<Preview>>;\n\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 */\nexport interface Config<\n\tAuth extends ServiceToggleInput | undefined =\n\t\t| ServiceToggleInput\n\t\t| undefined,\n\tDataApi extends DataApiInput | undefined = DataApiInput | undefined,\n\tPreview extends PreviewInput | undefined = PreviewInput | undefined,\n> {\n\t/** Neon Auth integration toggle (GA). Static — drives `NeonEnv.auth`. */\n\tauth?: Auth;\n\t/**\n\t * Neon Data API integration (GA). Static — drives `NeonEnv.dataApi`. A boolean/toggle, or\n\t * a {@link DataApiConfig} object selecting the auth provider (`\"neon\"` / `\"external\"`) and\n\t * runtime {@link DataApiSettings}. With `authProvider: \"neon\"` the policy must also enable\n\t * top-level `auth`.\n\t */\n\tdataApi?: DataApi;\n\t/** Beta (Preview) feature set: AI Gateway, functions, buckets. Static. */\n\tpreview?: Preview;\n\t/** Per-branch tuning closure. Cannot change the static existential set. */\n\tbranch?: BranchTuningFn<Preview>;\n}\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 */\nexport interface ResolvedFunctionConfig {\n\tslug: string;\n\tname: string;\n\tsource: string;\n\tenv: Record<string, string>;\n\t/**\n\t * Packages the bundler leaves unresolved, passed through from\n\t * {@link FunctionDef.externalPackages}. Absent rather than empty when undeclared, so a\n\t * policy that never mentions it resolves to the same shape it always did.\n\t */\n\texternalPackages?: string[];\n\truntime: FunctionRuntime;\n\t/**\n\t * Local-development settings, passed through untouched from {@link FunctionDef.dev}\n\t * (no defaults applied). Only consumed by `neon dev`; deploy ignores it.\n\t */\n\tdev?: FunctionDevConfig;\n}\n\n/** A bucket with its access level defaulted to `private`. */\nexport interface ResolvedBucketConfig {\n\tname: string;\n\taccess: BucketAccessLevel;\n}\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 */\nexport interface ResolvedPreviewConfig {\n\tfunctions: ResolvedFunctionConfig[];\n\tbuckets: ResolvedBucketConfig[];\n\taiGatewayEnabled: boolean;\n}\n\n/**\n * Normalized Data API integration. Present on {@link ResolvedBranchConfig} only when the\n * policy enables `dataApi`. `authProvider` always resolves (defaults to `\"neon\"`); the\n * external-IdP wiring is present only for `\"external\"`; `settings` carries the camelCase\n * runtime settings (reconciled as an update when they drift).\n */\nexport interface ResolvedDataApiConfig {\n\tauthProvider: DataApiAuthProvider;\n\tjwksUrl?: string;\n\tproviderName?: string;\n\tjwtAudience?: string;\n\tsettings?: DataApiSettings;\n}\n\nexport interface ResolvedBranchConfig {\n\tparent?: string;\n\tttlSeconds?: number;\n\tprotected?: boolean;\n\tpostgres?: PostgresConfig;\n\tauthEnabled: boolean;\n\tdataApiEnabled: boolean;\n\t/**\n\t * Resolved Data API integration. Present iff {@link dataApiEnabled} is `true`. Carries the\n\t * create-time auth wiring and the updatable {@link DataApiSettings}.\n\t */\n\tdataApi?: ResolvedDataApiConfig;\n\tpreview?: ResolvedPreviewConfig;\n}\n\n/**\n * One concrete change `pushConfig` made (or, in dry-run, would make) on the remote.\n */\nexport interface AppliedChange {\n\t/**\n\t * `service` covers branch-scoped integrations driven by the branch policy (e.g.\n\t * Neon Auth, Data API).\n\t */\n\tkind: \"branch\" | \"service\";\n\taction: \"create\" | \"update\" | \"noop\";\n\tidentifier: string;\n\tdetails?: Record<string, unknown>;\n}\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 */\nexport interface ConflictReport {\n\tkind: \"branch\";\n\tidentifier: string;\n\tfield: string;\n\tcurrent: unknown;\n\tdesired: unknown;\n\treason: string;\n}\n\n/**\n * Result of a `pushConfig` invocation.\n */\nexport interface PushResult {\n\tprojectId: string;\n\torgId?: string;\n\tbranchId: string;\n\tbranchName: string;\n\t/**\n\t * `true` when `pushConfig` was called with `{ dryRun: true }`. `applied` then records\n\t * what **would** be applied on a real push; no API mutations were performed.\n\t */\n\tdryRun: boolean;\n\tapplied: AppliedChange[];\n\tconflicts: ConflictReport[];\n}\n"],"mappings":";;;;;;;;;;;;;AA+LA,MAAa,0BAA0B,CAAC,QAAQ,UAAU"}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../src/lib/types.ts"],"sourcesContent":["/**\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 */\nexport type ComputeUnit = 0.25 | 0.5 | 1 | 2 | 4 | 8;\n\n/** Time units accepted in a {@link DurationString}: seconds, minutes, hours, days, weeks. */\nexport type DurationUnit = \"s\" | \"m\" | \"h\" | \"d\" | \"w\";\n\n/**\n * A Neon duration string: a positive integer **followed by a unit** — `s` (seconds),\n * `m` (minutes), `h` (hours), `d` (days), or `w` (weeks). Used by\n * {@link ComputeSettings.suspendTimeout} and {@link BranchTuning.ttl}.\n *\n * A **unit is required**: a bare numeric string like `\"7\"` is rejected at the type level. To\n * express a raw number of seconds, pass a `number` (`300`) — not a string (`\"300\"`). This\n * removes the old ambiguity where `\"7\"` silently meant 7 *seconds* instead of, say, `\"7d\"`.\n *\n * @example \"5m\" // 5 minutes\n * @example \"1h\" // 1 hour\n * @example \"7d\" // 7 days\n */\nexport type DurationString = `${number}${DurationUnit}`;\n\n/**\n * Autocomplete suggestions for {@link ComputeSettings.suspendTimeout}. Every value sits inside\n * the Neon API's allowed scale-to-zero band: **60s–604800s** (1 minute – 1 week). This is *not*\n * a closed set — the field also accepts any other {@link DurationString} or a `number` of\n * seconds; out-of-range values type-check but are rejected at apply time.\n */\ntype SuspendTimeoutSuggestion =\n\t| \"1m\"\n\t| \"5m\"\n\t| \"15m\"\n\t| \"30m\"\n\t| \"1h\"\n\t| \"6h\"\n\t| \"12h\"\n\t| \"1d\"\n\t| \"7d\";\n\n/**\n * Autocomplete suggestions for {@link BranchTuning.ttl}. Every value sits within the Neon API's\n * branch-expiration limit (**max 30 days** from creation; the Console's own presets are 1h / 1d\n * / 7d). This is *not* a closed set — the field also accepts any other {@link DurationString} or\n * a `number` of seconds; values over 30 days are rejected at apply time.\n */\ntype TtlSuggestion = \"1h\" | \"6h\" | \"12h\" | \"1d\" | \"3d\" | \"7d\" | \"14d\" | \"30d\";\n\n/**\n * Compose a field's duration type: its curated autocomplete `Suggestions` plus the open\n * `DurationString` template (so any `<integer><unit>` string still type-checks) and a `number`\n * of seconds. Intersecting the template arm with `NonNullable<unknown>` stops TypeScript from\n * collapsing the literal suggestions into the template, which is what preserves the autocomplete.\n */\ntype DurationField<Suggestions extends DurationString> =\n\t| Suggestions\n\t| (DurationString & NonNullable<unknown>)\n\t| number;\n\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 defaults).\n */\nexport interface ComputeSettings {\n\t/**\n\t * Minimum number of Compute Units. Set to 0.25 for true scale-to-zero.\n\t * @example 0.25 // scale-to-zero\n\t * @example 1 // always-on with 1 CU minimum\n\t */\n\tautoscalingLimitMinCu?: ComputeUnit;\n\t/**\n\t * Maximum number of Compute Units for autoscaling.\n\t * @example 2\n\t * @example 8\n\t */\n\tautoscalingLimitMaxCu?: ComputeUnit;\n\t/**\n\t * How long an idle compute waits before suspending (Neon's scale-to-zero). Accepts a\n\t * {@link DurationString} (autocompletes common values), a number of seconds, or `false`.\n\t *\n\t * - `false` — never suspend (always-on compute)\n\t * - {@link DurationString} — e.g. `\"5m\"`; autocompletes the in-range values `\"1m\"`, `\"5m\"`,\n\t * `\"15m\"`, `\"30m\"`, `\"1h\"`, `\"6h\"`, `\"12h\"`, `\"1d\"`, `\"7d\"`, and accepts any other\n\t * `<integer><unit>` (units: `s`, `m`, `h`, `d`, `w`). A **unit is required** — for raw\n\t * seconds pass a `number`, not a string.\n\t * - `number` — custom timeout in **seconds**, must be in `60`–`604800` (1 minute to 1 week)\n\t * - `undefined` — use the Neon default (currently 300s / 5 minutes)\n\t *\n\t * Whichever form you use, the resolved timeout must fall in `60`–`604800` seconds (the Neon\n\t * API limit); the suggestions are all within that band, anything else is checked at apply.\n\t *\n\t * @example false // never suspend (always-on)\n\t * @example \"5m\" // suspend after 5 minutes idle\n\t * @example \"1h\" // suspend after 1 hour idle\n\t * @example 300 // 5 minutes, expressed in seconds\n\t */\n\tsuspendTimeout?: false | DurationField<SuspendTimeoutSuggestion>;\n}\n\n/**\n * Read-only descriptor of the branch a {@link Config} policy is being evaluated for — the\n * `branch` argument passed to your `defineConfig({ branch: (branch) => … })` closure. It describes\n * **which** branch this invocation decides for; it is not a live branch handle and must not\n * be mutated. Switch on its fields and return the desired {@link BranchConfig}.\n */\nexport interface BranchTarget {\n\t/** Branch name being evaluated. For `branch dev`, this is the generated branch name. */\n\tname: string;\n\t/** Neon branch id when the branch already exists. Undefined during pre-create eval. */\n\tid?: string;\n\t/** Whether this branch already exists on Neon. */\n\texists: boolean;\n\t/** Parent branch id from Neon when known. */\n\tparentId?: string;\n\t/** Whether Neon marks this branch as the project default. */\n\tisDefault?: boolean;\n\t/** Whether Neon currently marks this branch protected. */\n\tisProtected?: boolean;\n\t/** Current expiration timestamp from Neon, when set. */\n\texpiresAt?: string;\n}\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 */\nexport interface ServiceToggle {\n\t/** Defaults to `true` when the service namespace is present. Set `false` to opt out. */\n\tenabled?: boolean;\n}\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 */\nexport type ServiceToggleInput = boolean | ServiceToggle;\n\n/**\n * Resolve a **static** service toggle (`true` / `false` / `{ enabled?: boolean }` / object /\n * `undefined`) to a type-level boolean. The tuple wrapping (`[T] extends […]`) disables\n * distribution so a union/`undefined` is judged as a single unit:\n *\n * - `false` / `{ enabled: false }` / `undefined` → `false`\n * - `true` / `{ enabled: true }` / any other object (`{}`, `{ enabled?: boolean }`) → `true`\n * (a present toggle defaults to enabled)\n * - the bare `boolean | … | undefined` (no literal info) → `false`\n *\n * Shared by the {@link Config} static cross-field checks and the `@neon/env`\n * `NeonEnv` namespace derivation, so both read \"is this service on?\" identically.\n */\nexport type ServiceEnabled<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\nexport interface PostgresConfig {\n\tcomputeSettings?: ComputeSettings;\n}\n\n/**\n * Authentication providers a Data API integration can verify JWTs against, as written in\n * `neon.ts`. Friendly authoring values (mapped to the Neon API's `neon_auth` / `external`\n * at the API boundary):\n *\n * - `\"neon\"` — verify tokens minted by **Neon Auth** on the same branch. Neon supplies the\n * JWKS URL / provider wiring for you, so the `jwksUrl` / `providerName` / `jwtAudience`\n * fields are forbidden (a type error) on this variant — and the policy must also enable\n * top-level `auth` (Neon Auth) so the tokens exist.\n * - `\"external\"` — verify tokens from a third-party IdP (Clerk, Stytch, Auth0, …). You\n * provide `jwksUrl` (and optionally `providerName` / `jwtAudience`).\n */\nexport const DATA_API_AUTH_PROVIDERS = [\"neon\", \"external\"] as const;\nexport type DataApiAuthProvider = (typeof DATA_API_AUTH_PROVIDERS)[number];\n\n/**\n * Reusable runtime settings for a Data API integration (the Neon API `DataAPISettings`,\n * camelCased to match the rest of `neon.ts`). Every field is optional; omitted fields keep\n * the Neon defaults shown below. These are the **only** Data API fields that can change on\n * an already-enabled integration — drift here is reconciled as an *update* (requires\n * `updateExisting` / `--update-existing`); the create-only auth wiring above cannot.\n */\nexport interface DataApiSettings {\n\t/** Enable the aggregates feature (`db_aggregates_enabled`). Default `true`. */\n\tdbAggregatesEnabled?: boolean;\n\t/** Database role used for anonymous requests (`db_anon_role`). Default `\"anonymous\"`. */\n\tdbAnonRole?: string;\n\t/** Extra schemas appended to the search path (`db_extra_search_path`). */\n\tdbExtraSearchPath?: string;\n\t/** Maximum rows returned in a single request (`db_max_rows`). */\n\tdbMaxRows?: number;\n\t/** Schemas exposed via the API (`db_schemas`). Default `[\"public\"]`. */\n\tdbSchemas?: string[];\n\t/** JWT claim key used for role extraction (`jwt_role_claim_key`). Default `\".role\"`. */\n\tjwtRoleClaimKey?: string;\n\t/** Maximum lifetime of the JWT cache, in seconds (`jwt_cache_max_lifetime`). */\n\tjwtCacheMaxLifetime?: number;\n\t/** OpenAPI spec mode (`openapi_mode`). Default `\"disabled\"`. */\n\topenapiMode?: \"ignore-privileges\" | \"disabled\";\n\t/** CORS allowed origins (`server_cors_allowed_origins`). */\n\tserverCorsAllowedOrigins?: string;\n\t/** Emit server-timing headers (`server_timing_enabled`). */\n\tserverTimingEnabled?: boolean;\n}\n\n/** Fields shared by every {@link DataApiConfig} variant. */\ninterface DataApiConfigBase {\n\t/** Defaults to `true` when the `dataApi` namespace is present. Set `false` to opt out. */\n\tenabled?: boolean;\n\t/** Reusable runtime settings. Drift here is reconciled as an update. */\n\tsettings?: DataApiSettings;\n}\n\n/**\n * Data API verified by **Neon Auth** (`authProvider: \"neon\"`, the default). The external\n * IdP fields are statically forbidden (`?: never`) because Neon supplies them; declaring any\n * of them is a type error directing you to `authProvider: \"external\"`.\n */\nexport interface DataApiNeonAuthConfig extends DataApiConfigBase {\n\tauthProvider?: \"neon\";\n\t/** Forbidden with `authProvider: \"neon\"` — Neon provides the JWKS URL. */\n\tjwksUrl?: never;\n\t/** Forbidden with `authProvider: \"neon\"` — the provider is Neon Auth. */\n\tproviderName?: never;\n\t/** Forbidden with `authProvider: \"neon\"` — Neon manages the audience. */\n\tjwtAudience?: never;\n}\n\n/**\n * Data API verified by an **external** IdP (`authProvider: \"external\"`). You provide the\n * JWKS URL (and optionally a provider label / expected audience).\n */\nexport interface DataApiExternalAuthConfig extends DataApiConfigBase {\n\tauthProvider: \"external\";\n\t/** URL that publishes the IdP's JWKS (JSON Web Key Set). */\n\tjwksUrl?: string;\n\t/** Human label for the IdP (e.g. \"Clerk\", \"Stytch\", \"Auth0\"). */\n\tproviderName?: string;\n\t/**\n\t * Expected `aud` claim. ⚠️ This only **rejects** tokens carrying a *different* audience;\n\t * tokens with no `aud` claim are still accepted.\n\t */\n\tjwtAudience?: string;\n}\n\n/**\n * Object form of the `dataApi` toggle. A discriminated union on {@link DataApiAuthProvider}:\n * the `\"neon\"` variant forbids the external-IdP fields, the `\"external\"` variant allows them.\n */\nexport type DataApiConfig = DataApiNeonAuthConfig | DataApiExternalAuthConfig;\n\n/**\n * How the Data API is toggled in a policy: a bare boolean (like the other service toggles)\n * or the richer {@link DataApiConfig} object. `true` / `{}` / `{ enabled: true }` enable it\n * with Neon defaults; `false` / `{ enabled: false }` opt out.\n */\nexport type DataApiInput = boolean | DataApiConfig;\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 */\nexport type FunctionRuntime = \"nodejs24\";\n\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 */\nexport interface FunctionDevConfig {\n\t/**\n\t * Port the local server binds. Bound exactly (and `neon dev` fails loudly if it is taken)\n\t * when set; a free port is found automatically when omitted.\n\t */\n\tport?: number;\n}\n\n/**\n * The object form of an {@link FunctionDef.externalPackages} entry, for the one case the\n * bare string cannot express: externalizing a package without shipping its files.\n */\nexport interface ExternalPackageDef {\n\t/** Package name, optionally with a subpath: `sharp`, `@scope/pkg`, `pkg/sub`. */\n\tname: string;\n\t/**\n\t * Whether the package's real files ship into the deployed archive next to the bundle.\n\t *\n\t * Defaults to `true`, which is the state where the import resolves and the function\n\t * works. Set it to `false` only for a package the function never reaches: nothing is\n\t * shipped for it, so reaching it throws `Cannot find module` at invoke.\n\t */\n\tincludeFiles?: boolean;\n}\n\n/**\n * One entry of {@link FunctionDef.externalPackages}. A bare string is the common form and\n * ships the package's files; {@link ExternalPackageDef} exists to turn that off.\n */\nexport type ExternalPackageEntry = string | ExternalPackageDef;\n\n/**\n * An {@link ExternalPackageEntry} with its default applied, as every consumer downstream of\n * `resolveConfig` reads it.\n */\nexport interface ResolvedExternalPackage {\n\t/** Package name as declared, subpath included. */\n\tname: string;\n\t/** Whether this package's files are staged into the archive. */\n\tincludeFiles: boolean;\n}\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 */\nexport interface FunctionDef {\n\t/** Free-form display name. @example \"Hello World\" */\n\tname: string;\n\t/**\n\t * Path to the function's entry module, **relative to `neon.ts`** (or absolute). The\n\t * module's default export (`{ fetch }`) or `handler` export is the function entry. This\n\t * path is resolved against the loaded `neon.ts` location and bundled with esbuild at\n\t * deploy time.\n\t *\n\t * We require a string path rather than an imported handler because a JS function value\n\t * carries no reference back to its source file, so esbuild has nothing to bundle from.\n\t * @example \"./functions/hello-world.ts\"\n\t */\n\tsource: string;\n\t/**\n\t * Environment variables injected into the deployed function, keyed by the var name the\n\t * function reads at runtime. The **keys** are static (preserved at the type level so\n\t * `parseEnv(config, \"<slug>\").function.<key>` is typed); the **values** are arbitrary\n\t * strings evaluated when `neon.ts` is loaded (typically `process.env.X`) and uploaded\n\t * at `config apply`. Every value must be a defined string — a `process.env.X` that is\n\t * `undefined` (unset) errors at validation time rather than silently shipping\n\t * `undefined`.\n\t * @example { resendApiKey: process.env.RESEND_API_KEY ?? \"\" }\n\t */\n\tenv?: Record<string, string>;\n\t/**\n\t * Ship a dependency's real files into the deployed archive instead of bundling it —\n\t * `sharp` and other packages backed by a native binary.\n\t *\n\t * The deploy-time equivalent of Next.js's `serverExternalPackages`. Every entry is passed\n\t * to esbuild's `external`, so the import survives into the bundle instead of being\n\t * followed, and the package's own files are shipped beside the bundle so that import\n\t * resolves.\n\t *\n\t * Reach for this when bundling a package is impossible rather than merely undesirable.\n\t * The case that comes up is a package backed by a native `.node` binary: the binary is a\n\t * compiled object the platform loads from a real path, so no bundler can inline it.\n\t * `sharp` is the common one, and it does not even fail at build time — it loads its\n\t * binary through `createRequire`, which esbuild does not follow, so it bundles cleanly\n\t * and then fails at invoke with \"Could not load the sharp module\".\n\t *\n\t * ```ts\n\t * externalPackages: [\"sharp\"]\n\t * ```\n\t *\n\t * Each declared package is installed for the Functions runtime target — **linux-arm64,\n\t * glibc** — into a throwaway directory, traced for the files it actually reaches, and\n\t * copied into the archive under `node_modules/` with its directory layout preserved. That\n\t * layout is load-bearing rather than cosmetic: a `.node` addon locates its sibling shared\n\t * libraries relative to its own directory, so a flattened tree fails to load.\n\t *\n\t * Your own `node_modules` is never read for these files or modified. Its binaries are\n\t * built for your machine rather than the deploy target, and a cross-platform install does\n\t * not survive your next plain `npm install`, so the target's packages are resolved fresh\n\t * on each deploy.\n\t *\n\t * Requirements, all reported at deploy time rather than at invoke: the package must\n\t * publish a linux-arm64 glibc build (`sharp` and most `@napi-rs/*` packages do; anything\n\t * compiled from source at install time does not), `npm` must be on `PATH`, and the\n\t * archive must stay inside the deploy size limits — native binaries are large.\n\t *\n\t * ### Excluding a package's files\n\t *\n\t * `includeFiles: false` externalizes the import without shipping anything, which is the\n\t * escape hatch for a package that cannot be staged — no build for the target, or too\n\t * large — and that the function never actually reaches:\n\t *\n\t * ```ts\n\t * externalPackages: [\"sharp\", { name: \"canvas\", includeFiles: false }]\n\t * ```\n\t *\n\t * **An excluded package is not resolvable at runtime.** Nothing is shipped for it, so it\n\t * throws `Cannot find module` if the function reaches it. It unblocks an import that is\n\t * never evaluated; it does not make a dependency usable.\n\t *\n\t * Entries are package names, optionally with a subpath (`pkg`, `@scope/pkg`, `pkg/sub`),\n\t * matching esbuild. A relative or absolute path is rejected at validation time: those are\n\t * local modules, and a local module that cannot be bundled is a different problem. Files\n\t * are staged per package, so a subpath narrows what esbuild leaves unresolved without\n\t * narrowing what ships.\n\t *\n\t * Under `neon dev` the list only keeps the package out of the bundle — nothing is\n\t * installed or copied, and it resolves from your own `node_modules` against your host\n\t * architecture, which is what you want locally.\n\t * @example [\"sharp\", { name: \"canvas\", includeFiles: false }]\n\t */\n\texternalPackages?: ExternalPackageEntry[];\n\t/**\n\t * Local-development settings used by `neon dev` when serving every function from\n\t * `neon.ts`. Ignored at deploy time. See {@link FunctionDevConfig}.\n\t */\n\tdev?: FunctionDevConfig;\n}\n\n/**\n * A single capability a branch-scoped service credential may exercise (Preview). A\n * credential is granted a set of these and may only perform the listed actions. Mirrors\n * the Neon API `CredentialScope` enum (`x-stability-level: beta`):\n *\n * - `storage:read` / `storage:write` — object-storage (bucket) access via the S3 key.\n * - `ai_gateway:invoke` — call the AI Gateway with the bearer `api_token`.\n * - `functions:invoke` — invoke Neon Functions with the bearer `api_token`.\n *\n * The set a policy needs is derived from its enabled Preview features (see\n * {@link deriveCredentialScopes}); it is never authored by hand.\n */\nexport type CredentialScope =\n\t| \"storage:read\"\n\t| \"storage:write\"\n\t| \"ai_gateway:invoke\"\n\t| \"functions:invoke\";\n\n/**\n * Who a credential acts as. `user` is the developer/app principal minted for local dev and\n * app bootstrap (`fetchEnv` / `env pull`); `function` is a deployed-function principal\n * (carries a `function_id`). The env tooling only mints `user` credentials today.\n */\nexport type CredentialPrincipalType = \"user\" | \"function\";\n\n/** Anonymous-access level for a branchable object-storage bucket. */\nexport type BucketAccessLevel = \"private\" | \"public_read\";\n\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 */\nexport interface BucketDef {\n\t/**\n\t * Anonymous access level. `private` (default) requires authenticated reads/writes;\n\t * `public_read` allows anonymous GetObject/HeadObject.\n\t */\n\taccess?: BucketAccessLevel;\n}\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 */\nexport interface PreviewInput {\n\t/** Enable/disable the AI Gateway on the branch (toggle, like auth / dataApi). */\n\taiGateway?: ServiceToggleInput;\n\t/** Functions to deploy, keyed by branch-unique slug (`^[a-z0-9]{1,20}$`). */\n\tfunctions?: Record<string, FunctionDef>;\n\t/** Object-storage buckets to create, keyed by bucket name. */\n\tbuckets?: Record<string, BucketDef>;\n}\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 */\nexport interface FunctionTuning {\n\t/** Runtime to execute the function with. Defaults to `\"nodejs24\"`. */\n\truntime?: FunctionRuntime;\n}\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 */\nexport interface PreviewTuning<Slug extends string = string> {\n\tfunctions?: Partial<Record<Slug, FunctionTuning>>;\n}\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 */\nexport interface BranchTuning<Slug extends string = string> {\n\t/** Parent branch name used when creating a new branch. Not a Postgres setting. */\n\tparent?: string;\n\t/**\n\t * Branch time-to-live: how long after creation the branch should auto-expire. Applied\n\t * when creating a new branch and reconciled on existing branches (when `updateExisting`\n\t * is set). Accepts a {@link DurationString} (autocompletes common values) or a number of\n\t * seconds. Omit to keep the branch indefinitely.\n\t *\n\t * - {@link DurationString} — e.g. `\"7d\"`; autocompletes `\"1h\"`, `\"6h\"`, `\"12h\"`, `\"1d\"`,\n\t * `\"3d\"`, `\"7d\"`, `\"14d\"`, `\"30d\"`, and accepts any other `<integer><unit>` (units: `s`,\n\t * `m`, `h`, `d`, `w` — e.g. `\"12h\"`, `\"2w\"`). A **unit is required** — `\"7\"` is rejected;\n\t * for raw seconds pass a `number`.\n\t * - `number` — custom TTL in **seconds** (e.g. `3600`)\n\t * - `undefined` — no expiry; the branch persists until explicitly deleted\n\t *\n\t * The Neon API caps branch expiration at **30 days** from creation, so the resolved TTL must\n\t * be `> 0` and `<= 30d`; the suggestions stay within that limit and anything longer is\n\t * rejected at apply.\n\t *\n\t * @example \"1d\" // ephemeral preview branch: expires a day after creation\n\t * @example \"7d\" // one-week TTL\n\t * @example \"30d\" // the maximum the API allows\n\t * @example 3600 // 1 hour, expressed in seconds\n\t */\n\tttl?: DurationField<TtlSuggestion>;\n\t/** Whether the selected branch should be protected. Undefined means \"leave as-is\". */\n\tprotected?: boolean;\n\tpostgres?: PostgresConfig;\n\tpreview?: PreviewTuning<Slug>;\n}\n\n/** Extract the declared function slugs from a {@link PreviewInput} for closure typing. */\ntype FunctionSlugsOf<Preview extends PreviewInput | undefined> =\n\tPreview extends {\n\t\tfunctions: infer F;\n\t}\n\t\t? Extract<keyof F, string>\n\t\t: string;\n\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 */\nexport type BranchTuningFn<\n\tPreview extends PreviewInput | undefined = PreviewInput | undefined,\n> = (branch: BranchTarget) => BranchTuning<FunctionSlugsOf<Preview>>;\n\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 */\nexport interface Config<\n\tAuth extends ServiceToggleInput | undefined =\n\t\t| ServiceToggleInput\n\t\t| undefined,\n\tDataApi extends DataApiInput | undefined = DataApiInput | undefined,\n\tPreview extends PreviewInput | undefined = PreviewInput | undefined,\n> {\n\t/** Neon Auth integration toggle (GA). Static — drives `NeonEnv.auth`. */\n\tauth?: Auth;\n\t/**\n\t * Neon Data API integration (GA). Static — drives `NeonEnv.dataApi`. A boolean/toggle, or\n\t * a {@link DataApiConfig} object selecting the auth provider (`\"neon\"` / `\"external\"`) and\n\t * runtime {@link DataApiSettings}. With `authProvider: \"neon\"` the policy must also enable\n\t * top-level `auth`.\n\t */\n\tdataApi?: DataApi;\n\t/** Beta (Preview) feature set: AI Gateway, functions, buckets. Static. */\n\tpreview?: Preview;\n\t/** Per-branch tuning closure. Cannot change the static existential set. */\n\tbranch?: BranchTuningFn<Preview>;\n}\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 */\nexport interface ResolvedFunctionConfig {\n\tslug: string;\n\tname: string;\n\tsource: string;\n\tenv: Record<string, string>;\n\t/**\n\t * Packages the bundler leaves unresolved, normalized from\n\t * {@link FunctionDef.externalPackages} with `includeFiles` defaulted.\n\t *\n\t * Absent rather than empty when undeclared, so a policy that never mentions it takes the\n\t * pre-existing bundling path and produces the archive it always did.\n\t */\n\texternalPackages?: ResolvedExternalPackage[];\n\truntime: FunctionRuntime;\n\t/**\n\t * Local-development settings, passed through untouched from {@link FunctionDef.dev}\n\t * (no defaults applied). Only consumed by `neon dev`; deploy ignores it.\n\t */\n\tdev?: FunctionDevConfig;\n}\n\n/** A bucket with its access level defaulted to `private`. */\nexport interface ResolvedBucketConfig {\n\tname: string;\n\taccess: BucketAccessLevel;\n}\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 */\nexport interface ResolvedPreviewConfig {\n\tfunctions: ResolvedFunctionConfig[];\n\tbuckets: ResolvedBucketConfig[];\n\taiGatewayEnabled: boolean;\n}\n\n/**\n * Normalized Data API integration. Present on {@link ResolvedBranchConfig} only when the\n * policy enables `dataApi`. `authProvider` always resolves (defaults to `\"neon\"`); the\n * external-IdP wiring is present only for `\"external\"`; `settings` carries the camelCase\n * runtime settings (reconciled as an update when they drift).\n */\nexport interface ResolvedDataApiConfig {\n\tauthProvider: DataApiAuthProvider;\n\tjwksUrl?: string;\n\tproviderName?: string;\n\tjwtAudience?: string;\n\tsettings?: DataApiSettings;\n}\n\nexport interface ResolvedBranchConfig {\n\tparent?: string;\n\tttlSeconds?: number;\n\tprotected?: boolean;\n\tpostgres?: PostgresConfig;\n\tauthEnabled: boolean;\n\tdataApiEnabled: boolean;\n\t/**\n\t * Resolved Data API integration. Present iff {@link dataApiEnabled} is `true`. Carries the\n\t * create-time auth wiring and the updatable {@link DataApiSettings}.\n\t */\n\tdataApi?: ResolvedDataApiConfig;\n\tpreview?: ResolvedPreviewConfig;\n}\n\n/**\n * One concrete change `pushConfig` made (or, in dry-run, would make) on the remote.\n */\nexport interface AppliedChange {\n\t/**\n\t * `service` covers branch-scoped integrations driven by the branch policy (e.g.\n\t * Neon Auth, Data API).\n\t */\n\tkind: \"branch\" | \"service\";\n\taction: \"create\" | \"update\" | \"noop\";\n\tidentifier: string;\n\tdetails?: Record<string, unknown>;\n}\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 */\nexport interface ConflictReport {\n\tkind: \"branch\";\n\tidentifier: string;\n\tfield: string;\n\tcurrent: unknown;\n\tdesired: unknown;\n\treason: string;\n}\n\n/**\n * Result of a `pushConfig` invocation.\n */\nexport interface PushResult {\n\tprojectId: string;\n\torgId?: string;\n\tbranchId: string;\n\tbranchName: string;\n\t/**\n\t * `true` when `pushConfig` was called with `{ dryRun: true }`. `applied` then records\n\t * what **would** be applied on a real push; no API mutations were performed.\n\t */\n\tdryRun: boolean;\n\tapplied: AppliedChange[];\n\tconflicts: ConflictReport[];\n\t/**\n\t * Advisory findings from the push — a function that bundles a native dependency it never\n\t * declared, or a staged package whose version could not be pinned.\n\t *\n\t * Returned rather than logged, because a library has no business choosing an output\n\t * channel, and returned rather than left to an opt-in callback, because these are the\n\t * only warning that a deployed function will fail at invoke and an unregistered callback\n\t * is easy to never notice. Empty when there is nothing to report.\n\t *\n\t * Only populated by the built-in bundler: a caller that injects its own `bundleFunction`\n\t * owns its own reporting.\n\t */\n\twarnings: string[];\n}\n"],"mappings":";;;;;;;;;;;;;AA+LA,MAAa,0BAA0B,CAAC,QAAQ,UAAU"}
|
package/dist/v1.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConflictReport, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DurationString, DurationUnit, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput } from "./lib/types.js";
|
|
1
|
+
import { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConflictReport, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DurationString, DurationUnit, ExternalPackageDef, ExternalPackageEntry, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedExternalPackage, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput } from "./lib/types.js";
|
|
2
2
|
import { ConfigLoadError, ConfigValidationError, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, isPartialBranchCreateError, isPlatformError } from "./lib/errors.js";
|
|
3
3
|
import { CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, DeployFunctionInput, EnableDataApiInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, UpdateBranchInput } from "./lib/neon-api.js";
|
|
4
4
|
import { createNeonApiFromOptions } from "./lib/auth.js";
|
|
5
5
|
import { CredentialFeatureFlags, credentialScopesSatisfied, deriveCredentialScopes } from "./lib/credentials.js";
|
|
6
6
|
import { defineConfig, resolveConfig } from "./lib/define-config.js";
|
|
7
7
|
import { DiffOptions, DiffResult, PlanStep, RemotePreviewState, RemoteServiceState, RemoteState, diffConfig } from "./lib/diff.js";
|
|
8
|
+
import { externalPackageRoot, packagesToStage } from "./lib/external-packages.js";
|
|
8
9
|
import { LoadConfigOptions, loadConfigFromFile } from "./lib/loader.js";
|
|
9
10
|
import { createRealNeonApi } from "./lib/neon-api-real.js";
|
|
10
11
|
import * as zod0 from "zod";
|
|
@@ -83,7 +84,10 @@ declare const schemas: {
|
|
|
83
84
|
name: zod0.ZodString;
|
|
84
85
|
source: zod0.ZodString;
|
|
85
86
|
env: zod0.ZodOptional<zod0.ZodRecord<zod0.ZodString, zod0.ZodString>>;
|
|
86
|
-
externalPackages: zod0.ZodOptional<zod0.ZodArray<zod0.ZodString
|
|
87
|
+
externalPackages: zod0.ZodOptional<zod0.ZodArray<zod0.ZodUnion<readonly [zod0.ZodString, zod0.ZodObject<{
|
|
88
|
+
name: zod0.ZodString;
|
|
89
|
+
includeFiles: zod0.ZodOptional<zod0.ZodBoolean>;
|
|
90
|
+
}, zod_v4_core0.$strict>]>>>;
|
|
87
91
|
dev: zod0.ZodOptional<zod0.ZodObject<{
|
|
88
92
|
port: zod0.ZodOptional<zod0.ZodNumber>;
|
|
89
93
|
}, zod_v4_core0.$strict>>;
|
|
@@ -173,7 +177,10 @@ declare const schemas: {
|
|
|
173
177
|
name: zod0.ZodString;
|
|
174
178
|
source: zod0.ZodString;
|
|
175
179
|
env: zod0.ZodOptional<zod0.ZodRecord<zod0.ZodString, zod0.ZodString>>;
|
|
176
|
-
externalPackages: zod0.ZodOptional<zod0.ZodArray<zod0.ZodString
|
|
180
|
+
externalPackages: zod0.ZodOptional<zod0.ZodArray<zod0.ZodUnion<readonly [zod0.ZodString, zod0.ZodObject<{
|
|
181
|
+
name: zod0.ZodString;
|
|
182
|
+
includeFiles: zod0.ZodOptional<zod0.ZodBoolean>;
|
|
183
|
+
}, zod_v4_core0.$strict>]>>>;
|
|
177
184
|
dev: zod0.ZodOptional<zod0.ZodObject<{
|
|
178
185
|
port: zod0.ZodOptional<zod0.ZodNumber>;
|
|
179
186
|
}, zod_v4_core0.$strict>>;
|
|
@@ -196,7 +203,10 @@ declare const schemas: {
|
|
|
196
203
|
name: zod0.ZodString;
|
|
197
204
|
source: zod0.ZodString;
|
|
198
205
|
env: zod0.ZodOptional<zod0.ZodRecord<zod0.ZodString, zod0.ZodString>>;
|
|
199
|
-
externalPackages: zod0.ZodOptional<zod0.ZodArray<zod0.ZodString
|
|
206
|
+
externalPackages: zod0.ZodOptional<zod0.ZodArray<zod0.ZodUnion<readonly [zod0.ZodString, zod0.ZodObject<{
|
|
207
|
+
name: zod0.ZodString;
|
|
208
|
+
includeFiles: zod0.ZodOptional<zod0.ZodBoolean>;
|
|
209
|
+
}, zod_v4_core0.$strict>]>>>;
|
|
200
210
|
dev: zod0.ZodOptional<zod0.ZodObject<{
|
|
201
211
|
port: zod0.ZodOptional<zod0.ZodNumber>;
|
|
202
212
|
}, zod_v4_core0.$strict>>;
|
|
@@ -213,5 +223,5 @@ declare const schemas: {
|
|
|
213
223
|
}, zod_v4_core0.$strict>]>;
|
|
214
224
|
};
|
|
215
225
|
//#endregion
|
|
216
|
-
export { type AppliedChange, type BranchTarget, type BranchTuning, type BranchTuningFn, type BucketAccessLevel, type BucketDef, type ComputeSettings, type ComputeUnit, type Config, ConfigLoadError, ConfigValidationError, type ConflictReport, type CreateBranchInput, type CreateBucketInput, type CreateCredentialInput, type CreateProjectInput, type CredentialFeatureFlags, type CredentialPrincipalType, type CredentialScope, DATA_API_AUTH_PROVIDERS, type DataApiAuthProvider, type DataApiConfig, type DataApiExternalAuthConfig, type DataApiInput, type DataApiNeonAuthConfig, type DataApiSettings, type DeployFunctionInput, type DiffOptions, type DiffResult, type DurationString, type DurationUnit, type EnableDataApiInput, ErrorCode, type FunctionDef, type FunctionDevConfig, type FunctionRuntime, type FunctionTuning, type GetConnectionUriInput, type LoadConfigOptions, MissingContextError, type NeonApi, type NeonAuthSnapshot, type NeonBranchSnapshot, type NeonBranchStorageSnapshot, type NeonBucketSnapshot, type NeonCredentialMeta, type NeonCredentialSecret, type NeonDataApiSnapshot, type NeonDatabaseSnapshot, type NeonEndpointSnapshot, type NeonFunctionDeploymentSnapshot, type NeonFunctionSnapshot, type NeonProjectSnapshot, type NeonRoleSnapshot, PartialBranchCreateError, type PlanStep, PlatformError, type PostgresConfig, type PreviewInput, type PreviewTuning, PushAbortedError, PushConflictError, type PushResult, type RemotePreviewState, type RemoteServiceState, type RemoteState, type ResolvedBranchConfig, type ResolvedBucketConfig, type ResolvedDataApiConfig, type ResolvedFunctionConfig, type ResolvedPreviewConfig, type ServiceEnabled, type ServiceToggle, type ServiceToggleInput, type UpdateBranchInput, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, resolveConfig, schemas };
|
|
226
|
+
export { type AppliedChange, type BranchTarget, type BranchTuning, type BranchTuningFn, type BucketAccessLevel, type BucketDef, type ComputeSettings, type ComputeUnit, type Config, ConfigLoadError, ConfigValidationError, type ConflictReport, type CreateBranchInput, type CreateBucketInput, type CreateCredentialInput, type CreateProjectInput, type CredentialFeatureFlags, type CredentialPrincipalType, type CredentialScope, DATA_API_AUTH_PROVIDERS, type DataApiAuthProvider, type DataApiConfig, type DataApiExternalAuthConfig, type DataApiInput, type DataApiNeonAuthConfig, type DataApiSettings, type DeployFunctionInput, type DiffOptions, type DiffResult, type DurationString, type DurationUnit, type EnableDataApiInput, ErrorCode, type ExternalPackageDef, type ExternalPackageEntry, type FunctionDef, type FunctionDevConfig, type FunctionRuntime, type FunctionTuning, type GetConnectionUriInput, type LoadConfigOptions, MissingContextError, type NeonApi, type NeonAuthSnapshot, type NeonBranchSnapshot, type NeonBranchStorageSnapshot, type NeonBucketSnapshot, type NeonCredentialMeta, type NeonCredentialSecret, type NeonDataApiSnapshot, type NeonDatabaseSnapshot, type NeonEndpointSnapshot, type NeonFunctionDeploymentSnapshot, type NeonFunctionSnapshot, type NeonProjectSnapshot, type NeonRoleSnapshot, PartialBranchCreateError, type PlanStep, PlatformError, type PostgresConfig, type PreviewInput, type PreviewTuning, PushAbortedError, PushConflictError, type PushResult, type RemotePreviewState, type RemoteServiceState, type RemoteState, type ResolvedBranchConfig, type ResolvedBucketConfig, type ResolvedDataApiConfig, type ResolvedExternalPackage, type ResolvedFunctionConfig, type ResolvedPreviewConfig, type ServiceEnabled, type ServiceToggle, type ServiceToggleInput, type UpdateBranchInput, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, externalPackageRoot, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, packagesToStage, resolveConfig, schemas };
|
|
217
227
|
//# sourceMappingURL=v1.d.ts.map
|
package/dist/v1.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"v1.d.ts","names":[],"sources":["../src/v1.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"v1.d.ts","names":[],"sources":["../src/v1.ts"],"mappings":";;;;;;;;;;;;;;;;;;;cAuEa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAcA;;mDAcH,IAAA,CAAA,UAAA"}
|
package/dist/v1.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ConfigLoadError, ConfigValidationError, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, isPartialBranchCreateError, isPlatformError } from "./lib/errors.js";
|
|
2
|
+
import { externalPackageRoot, packagesToStage } from "./lib/external-packages.js";
|
|
2
3
|
import { branchTuningSchema, bucketDefSchema, computeSettingsSchema, configInputSchema, dataApiConfigSchema, dataApiInputSchema, dataApiSettingsSchema, functionDefSchema, functionTuningSchema, postgresConfigSchema, previewInputSchema, serviceToggleInputSchema, serviceToggleSchema } from "./lib/schema.js";
|
|
3
4
|
import { createRealNeonApi } from "./lib/neon-api-real.js";
|
|
4
5
|
import { createNeonApiFromOptions } from "./lib/auth.js";
|
|
@@ -79,6 +80,6 @@ const schemas = {
|
|
|
79
80
|
serviceInput: serviceToggleInputSchema
|
|
80
81
|
};
|
|
81
82
|
//#endregion
|
|
82
|
-
export { ConfigLoadError, ConfigValidationError, DATA_API_AUTH_PROVIDERS, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, resolveConfig, schemas };
|
|
83
|
+
export { ConfigLoadError, ConfigValidationError, DATA_API_AUTH_PROVIDERS, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, externalPackageRoot, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, packagesToStage, resolveConfig, schemas };
|
|
83
84
|
|
|
84
85
|
//# sourceMappingURL=v1.js.map
|
package/dist/v1.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"v1.js","names":[],"sources":["../src/v1.ts"],"sourcesContent":["/**\n * `@neon/config/v1` — the v1 public API for Config-as-Code on Neon.\n *\n * Usage in `neon.ts`:\n * ```ts\n * import { defineConfig } from \"@neon/config/v1\";\n *\n * export default defineConfig({\n * // Static: what *exists* on every branch (drives the typed env).\n * auth: true,\n * // Dynamic: per-branch tuning only — cannot add/remove services.\n * branch: (branch) => ({\n * protected: branch.name === \"main\",\n * ...(branch.name === \"main\" ? {} : { parent: \"main\", ttl: \"7d\" }),\n * }),\n * });\n * ```\n *\n * This is the **authoring** surface — `defineConfig`, types, schemas, the pure diff engine,\n * and the Neon API adapter. It is intentionally free of heavy/native dependencies so that\n * importing it from `neon.ts` stays cheap and bundler-safe.\n *\n * The imperative operations (`inspect` / `plan` / `apply`, `pushConfig` / `pullConfig`) and\n * function bundling/deploy live in **`@neon/config-runtime`**, which depends on this\n * package and pulls in `esbuild`. Import that from your CLI / CI, not from `neon.ts`:\n * ```ts\n * import config from \"../neon\";\n * import { inspect, plan, apply } from \"@neon/config-runtime/v1\";\n * ```\n *\n * Surface guidelines:\n * - Top-level: `defineConfig` / `resolveConfig`, the pure `diffConfig` engine, the\n * `createRealNeonApi` adapter + `NeonApi` types, the config loader, the `PlatformError`\n * base class + `ErrorCode` enum, and the config types used in `neon.ts`.\n * - `errors` namespace: specific `PlatformError` subclasses (`ConfigLoadError`,\n * `PushConflictError`, …).\n * - `schemas` namespace: the zod schemas underlying `defineConfig`.\n */\n\nimport {\n\tConfigLoadError,\n\tConfigValidationError,\n\tErrorCode,\n\tisPartialBranchCreateError,\n\tisPlatformError,\n\tMissingContextError,\n\tPartialBranchCreateError,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n} from \"./lib/errors.js\";\nimport {\n\tbranchTuningSchema,\n\tbucketDefSchema,\n\tcomputeSettingsSchema,\n\tconfigInputSchema,\n\tdataApiConfigSchema,\n\tdataApiInputSchema,\n\tdataApiSettingsSchema,\n\tfunctionDefSchema,\n\tfunctionTuningSchema,\n\tpostgresConfigSchema,\n\tpreviewInputSchema,\n\tserviceToggleInputSchema,\n\tserviceToggleSchema,\n} from \"./lib/schema.js\";\n\n/**\n * Specific `PlatformError` subclasses, grouped for `instanceof` / structured access.\n * Also available as top-level exports.\n */\nexport const errors = {\n\tConfigLoadError,\n\tConfigValidationError,\n\tErrorCode,\n\tisPartialBranchCreateError,\n\tisPlatformError,\n\tMissingContextError,\n\tPartialBranchCreateError,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n} as const;\n\n/** The zod schemas underlying `defineConfig`, grouped under product-friendly names. */\nexport const schemas = {\n\tconfig: configInputSchema,\n\tbranchTuning: branchTuningSchema,\n\tbucket: bucketDefSchema,\n\tcomputeSettings: computeSettingsSchema,\n\tdataApi: dataApiConfigSchema,\n\tdataApiInput: dataApiInputSchema,\n\tdataApiSettings: dataApiSettingsSchema,\n\tfunction: functionDefSchema,\n\tfunctionTuning: functionTuningSchema,\n\tpostgres: postgresConfigSchema,\n\tpreview: previewInputSchema,\n\tservice: serviceToggleSchema,\n\tserviceInput: serviceToggleInputSchema,\n} as const;\n\n// ─── Lower-level adapters ──────────────────────────────────────────────────────\nexport { createNeonApiFromOptions } from \"./lib/auth.js\";\n// ─── Credentials (pure scope derivation; Preview) ─────────────────────────────\nexport type { CredentialFeatureFlags } from \"./lib/credentials.js\";\nexport {\n\tcredentialScopesSatisfied,\n\tderiveCredentialScopes,\n} from \"./lib/credentials.js\";\nexport { defineConfig, resolveConfig } from \"./lib/define-config.js\";\n// ─── Diff engine (pure; consumed by @neon/config-runtime) ─────────────\nexport type {\n\tDiffOptions,\n\tDiffResult,\n\tPlanStep,\n\tRemotePreviewState,\n\tRemoteServiceState,\n\tRemoteState,\n} from \"./lib/diff.js\";\nexport { diffConfig } from \"./lib/diff.js\";\n// ─── Errors ────────────────────────────────────────────────────────────────────\nexport {\n\tConfigLoadError,\n\tConfigValidationError,\n\tErrorCode,\n\tisPartialBranchCreateError,\n\tisPlatformError,\n\tMissingContextError,\n\tPartialBranchCreateError,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n} from \"./lib/errors.js\";\nexport type { LoadConfigOptions } from \"./lib/loader.js\";\nexport { loadConfigFromFile } from \"./lib/loader.js\";\n// ─── NeonApi types (needed by callers implementing their own adapters) ────────\nexport type {\n\tCreateBranchInput,\n\tCreateBucketInput,\n\tCreateCredentialInput,\n\tCreateProjectInput,\n\tDeployFunctionInput,\n\tEnableDataApiInput,\n\tGetConnectionUriInput,\n\tNeonApi,\n\tNeonAuthSnapshot,\n\tNeonBranchSnapshot,\n\tNeonBranchStorageSnapshot,\n\tNeonBucketSnapshot,\n\tNeonCredentialMeta,\n\tNeonCredentialSecret,\n\tNeonDataApiSnapshot,\n\tNeonDatabaseSnapshot,\n\tNeonEndpointSnapshot,\n\tNeonFunctionDeploymentSnapshot,\n\tNeonFunctionSnapshot,\n\tNeonProjectSnapshot,\n\tNeonRoleSnapshot,\n\tUpdateBranchInput,\n} from \"./lib/neon-api.js\";\nexport { createRealNeonApi } from \"./lib/neon-api-real.js\";\nexport type {\n\tAppliedChange,\n\tBranchTarget,\n\tBranchTuning,\n\tBranchTuningFn,\n\tBucketAccessLevel,\n\tBucketDef,\n\tComputeSettings,\n\tComputeUnit,\n\tConfig,\n\tConflictReport,\n\tCredentialPrincipalType,\n\tCredentialScope,\n\tDataApiAuthProvider,\n\tDataApiConfig,\n\tDataApiExternalAuthConfig,\n\tDataApiInput,\n\tDataApiNeonAuthConfig,\n\tDataApiSettings,\n\tDurationString,\n\tDurationUnit,\n\tFunctionDef,\n\tFunctionDevConfig,\n\tFunctionRuntime,\n\tFunctionTuning,\n\tPostgresConfig,\n\tPreviewInput,\n\tPreviewTuning,\n\tPushResult,\n\tResolvedBranchConfig,\n\tResolvedBucketConfig,\n\tResolvedDataApiConfig,\n\tResolvedFunctionConfig,\n\tResolvedPreviewConfig,\n\tServiceEnabled,\n\tServiceToggle,\n\tServiceToggleInput,\n} from \"./lib/types.js\";\n// ─── Config types (used in neon.ts and in operation return values) ────────────\nexport { DATA_API_AUTH_PROVIDERS } from \"./lib/types.js\";\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"v1.js","names":[],"sources":["../src/v1.ts"],"sourcesContent":["/**\n * `@neon/config/v1` — the v1 public API for Config-as-Code on Neon.\n *\n * Usage in `neon.ts`:\n * ```ts\n * import { defineConfig } from \"@neon/config/v1\";\n *\n * export default defineConfig({\n * // Static: what *exists* on every branch (drives the typed env).\n * auth: true,\n * // Dynamic: per-branch tuning only — cannot add/remove services.\n * branch: (branch) => ({\n * protected: branch.name === \"main\",\n * ...(branch.name === \"main\" ? {} : { parent: \"main\", ttl: \"7d\" }),\n * }),\n * });\n * ```\n *\n * This is the **authoring** surface — `defineConfig`, types, schemas, the pure diff engine,\n * and the Neon API adapter. It is intentionally free of heavy/native dependencies so that\n * importing it from `neon.ts` stays cheap and bundler-safe.\n *\n * The imperative operations (`inspect` / `plan` / `apply`, `pushConfig` / `pullConfig`) and\n * function bundling/deploy live in **`@neon/config-runtime`**, which depends on this\n * package and pulls in `esbuild`. Import that from your CLI / CI, not from `neon.ts`:\n * ```ts\n * import config from \"../neon\";\n * import { inspect, plan, apply } from \"@neon/config-runtime/v1\";\n * ```\n *\n * Surface guidelines:\n * - Top-level: `defineConfig` / `resolveConfig`, the pure `diffConfig` engine, the\n * `createRealNeonApi` adapter + `NeonApi` types, the config loader, the `PlatformError`\n * base class + `ErrorCode` enum, and the config types used in `neon.ts`.\n * - `errors` namespace: specific `PlatformError` subclasses (`ConfigLoadError`,\n * `PushConflictError`, …).\n * - `schemas` namespace: the zod schemas underlying `defineConfig`.\n */\n\nimport {\n\tConfigLoadError,\n\tConfigValidationError,\n\tErrorCode,\n\tisPartialBranchCreateError,\n\tisPlatformError,\n\tMissingContextError,\n\tPartialBranchCreateError,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n} from \"./lib/errors.js\";\nimport {\n\tbranchTuningSchema,\n\tbucketDefSchema,\n\tcomputeSettingsSchema,\n\tconfigInputSchema,\n\tdataApiConfigSchema,\n\tdataApiInputSchema,\n\tdataApiSettingsSchema,\n\tfunctionDefSchema,\n\tfunctionTuningSchema,\n\tpostgresConfigSchema,\n\tpreviewInputSchema,\n\tserviceToggleInputSchema,\n\tserviceToggleSchema,\n} from \"./lib/schema.js\";\n\n/**\n * Specific `PlatformError` subclasses, grouped for `instanceof` / structured access.\n * Also available as top-level exports.\n */\nexport const errors = {\n\tConfigLoadError,\n\tConfigValidationError,\n\tErrorCode,\n\tisPartialBranchCreateError,\n\tisPlatformError,\n\tMissingContextError,\n\tPartialBranchCreateError,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n} as const;\n\n/** The zod schemas underlying `defineConfig`, grouped under product-friendly names. */\nexport const schemas = {\n\tconfig: configInputSchema,\n\tbranchTuning: branchTuningSchema,\n\tbucket: bucketDefSchema,\n\tcomputeSettings: computeSettingsSchema,\n\tdataApi: dataApiConfigSchema,\n\tdataApiInput: dataApiInputSchema,\n\tdataApiSettings: dataApiSettingsSchema,\n\tfunction: functionDefSchema,\n\tfunctionTuning: functionTuningSchema,\n\tpostgres: postgresConfigSchema,\n\tpreview: previewInputSchema,\n\tservice: serviceToggleSchema,\n\tserviceInput: serviceToggleInputSchema,\n} as const;\n\n// ─── Lower-level adapters ──────────────────────────────────────────────────────\nexport { createNeonApiFromOptions } from \"./lib/auth.js\";\n// ─── Credentials (pure scope derivation; Preview) ─────────────────────────────\nexport type { CredentialFeatureFlags } from \"./lib/credentials.js\";\nexport {\n\tcredentialScopesSatisfied,\n\tderiveCredentialScopes,\n} from \"./lib/credentials.js\";\nexport { defineConfig, resolveConfig } from \"./lib/define-config.js\";\n// ─── Diff engine (pure; consumed by @neon/config-runtime) ─────────────\nexport type {\n\tDiffOptions,\n\tDiffResult,\n\tPlanStep,\n\tRemotePreviewState,\n\tRemoteServiceState,\n\tRemoteState,\n} from \"./lib/diff.js\";\nexport { diffConfig } from \"./lib/diff.js\";\n// ─── Errors ────────────────────────────────────────────────────────────────────\nexport {\n\tConfigLoadError,\n\tConfigValidationError,\n\tErrorCode,\n\tisPartialBranchCreateError,\n\tisPlatformError,\n\tMissingContextError,\n\tPartialBranchCreateError,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n} from \"./lib/errors.js\";\n// ─── External packages (pure; also for a custom FunctionBundler) ──────────────\nexport {\n\texternalPackageRoot,\n\tpackagesToStage,\n} from \"./lib/external-packages.js\";\nexport type { LoadConfigOptions } from \"./lib/loader.js\";\nexport { loadConfigFromFile } from \"./lib/loader.js\";\n// ─── NeonApi types (needed by callers implementing their own adapters) ────────\nexport type {\n\tCreateBranchInput,\n\tCreateBucketInput,\n\tCreateCredentialInput,\n\tCreateProjectInput,\n\tDeployFunctionInput,\n\tEnableDataApiInput,\n\tGetConnectionUriInput,\n\tNeonApi,\n\tNeonAuthSnapshot,\n\tNeonBranchSnapshot,\n\tNeonBranchStorageSnapshot,\n\tNeonBucketSnapshot,\n\tNeonCredentialMeta,\n\tNeonCredentialSecret,\n\tNeonDataApiSnapshot,\n\tNeonDatabaseSnapshot,\n\tNeonEndpointSnapshot,\n\tNeonFunctionDeploymentSnapshot,\n\tNeonFunctionSnapshot,\n\tNeonProjectSnapshot,\n\tNeonRoleSnapshot,\n\tUpdateBranchInput,\n} from \"./lib/neon-api.js\";\nexport { createRealNeonApi } from \"./lib/neon-api-real.js\";\nexport type {\n\tAppliedChange,\n\tBranchTarget,\n\tBranchTuning,\n\tBranchTuningFn,\n\tBucketAccessLevel,\n\tBucketDef,\n\tComputeSettings,\n\tComputeUnit,\n\tConfig,\n\tConflictReport,\n\tCredentialPrincipalType,\n\tCredentialScope,\n\tDataApiAuthProvider,\n\tDataApiConfig,\n\tDataApiExternalAuthConfig,\n\tDataApiInput,\n\tDataApiNeonAuthConfig,\n\tDataApiSettings,\n\tDurationString,\n\tDurationUnit,\n\tExternalPackageDef,\n\tExternalPackageEntry,\n\tFunctionDef,\n\tFunctionDevConfig,\n\tFunctionRuntime,\n\tFunctionTuning,\n\tPostgresConfig,\n\tPreviewInput,\n\tPreviewTuning,\n\tPushResult,\n\tResolvedBranchConfig,\n\tResolvedBucketConfig,\n\tResolvedDataApiConfig,\n\tResolvedExternalPackage,\n\tResolvedFunctionConfig,\n\tResolvedPreviewConfig,\n\tServiceEnabled,\n\tServiceToggle,\n\tServiceToggleInput,\n} from \"./lib/types.js\";\n// ─── Config types (used in neon.ts and in operation return values) ────────────\nexport { DATA_API_AUTH_PROVIDERS } from \"./lib/types.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuEA,MAAa,SAAS;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;;AAGA,MAAa,UAAU;CACtB,QAAQ;CACR,cAAc;CACd,QAAQ;CACR,iBAAiB;CACjB,SAAS;CACT,cAAc;CACd,iBAAiB;CACjB,UAAU;CACV,gBAAgB;CAChB,UAAU;CACV,SAAS;CACT,SAAS;CACT,cAAc;AACf"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neondatabase/config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Config-as-Code for Neon. Define a `neon.ts` policy and inspect/diff/deploy it against the Neon API as plain TypeScript functions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"neon",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"jiti": "^2.7.0",
|
|
53
53
|
"zod": "^4.4.3",
|
|
54
|
-
"@neon/sdk": "
|
|
54
|
+
"@neon/sdk": "2.0.0"
|
|
55
55
|
},
|
|
56
56
|
"engines": {
|
|
57
57
|
"node": ">=20.19.0"
|