@neondatabase/config 1.8.7 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -3
- package/dist/lib/authored-services.d.ts +2 -1
- package/dist/lib/authored-services.d.ts.map +1 -1
- package/dist/lib/authored-services.js +4 -2
- package/dist/lib/authored-services.js.map +1 -1
- package/dist/lib/define-config.d.ts +6 -3
- package/dist/lib/define-config.d.ts.map +1 -1
- package/dist/lib/define-config.js +21 -2
- package/dist/lib/define-config.js.map +1 -1
- package/dist/lib/diff.d.ts +20 -1
- package/dist/lib/diff.d.ts.map +1 -1
- package/dist/lib/diff.js +67 -0
- package/dist/lib/diff.js.map +1 -1
- package/dist/lib/neon-api-real.d.ts.map +1 -1
- package/dist/lib/neon-api-real.js +66 -1
- package/dist/lib/neon-api-real.js.map +1 -1
- package/dist/lib/neon-api.d.ts +27 -1
- package/dist/lib/neon-api.d.ts.map +1 -1
- package/dist/lib/schema.d.ts +22 -8
- package/dist/lib/schema.d.ts.map +1 -1
- package/dist/lib/schema.js +19 -2
- package/dist/lib/schema.js.map +1 -1
- package/dist/lib/types.d.ts +26 -12
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js.map +1 -1
- package/dist/v1.d.ts +21 -9
- package/dist/v1.d.ts.map +1 -1
- package/dist/v1.js +3 -1
- package/dist/v1.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, CheckoutAfterContext, CheckoutBeforeContext, CheckoutBeforeResult, CheckoutEvent, CheckoutHooks, ComputeSettings, ComputeUnit, Config, ConflictReport, CreateAfterContext, CreateBeforeContext, CreateHooks, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DeployAfterContext, DeployBeforeContext, DeployEvent, DeployHooks, DurationString, DurationUnit, ExperimentalInput, ExternalPackageDef, ExternalPackageEntry, FunctionBundle, FunctionBundler, FunctionBundlerInput, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionScheduleTriggerDef, FunctionStorageObjectCreatedTriggerDef, FunctionTriggerDef, FunctionTuning, GitContext, Hook, HookBranch, HookEnv, Hooks, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedExternalPackage, ResolvedFunctionConfig, ResolvedFunctionScheduleTrigger, ResolvedFunctionStorageObjectCreatedTrigger, ResolvedFunctionTrigger, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput, ShellHook } from "./lib/types.js";
|
|
1
|
+
import { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, CheckoutAfterContext, CheckoutBeforeContext, CheckoutBeforeResult, CheckoutEvent, CheckoutHooks, ComputeSettings, ComputeUnit, Config, ConflictReport, CreateAfterContext, CreateBeforeContext, CreateHooks, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DeployAfterContext, DeployBeforeContext, DeployEvent, DeployHooks, DurationString, DurationUnit, ExperimentalInput, ExternalPackageDef, ExternalPackageEntry, FunctionBundle, FunctionBundler, FunctionBundlerInput, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionScheduleTriggerDef, FunctionStorageObjectCreatedTriggerDef, FunctionTriggerDef, FunctionTuning, GitContext, Hook, HookBranch, HookEnv, Hooks, PostgresConfig, PreviewInput, PreviewTuning, PushResult, RealtimeConfig, RealtimeInput, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedExternalPackage, ResolvedFunctionConfig, ResolvedFunctionScheduleTrigger, ResolvedFunctionStorageObjectCreatedTrigger, ResolvedFunctionTrigger, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput, ShellHook } from "./lib/types.js";
|
|
2
2
|
import { ConfigLoadError, ConfigValidationError, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, isPartialBranchCreateError, isPlatformError } from "./lib/errors.js";
|
|
3
|
-
import { CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, CreateTriggerInput, DeployFunctionInput, EnableDataApiInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialReveal, NeonCredentialSecret, NeonCustomDomainSnapshot, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, NeonScheduleTriggerSnapshot, NeonStorageObjectCreatedTriggerSnapshot, NeonTriggerSnapshot, UpdateBranchInput, UpdateTriggerInput } from "./lib/neon-api.js";
|
|
3
|
+
import { ConfigureRealtimeInput, CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, CreateTriggerInput, DeployFunctionInput, EnableDataApiInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialReveal, NeonCredentialSecret, NeonCustomDomainSnapshot, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRealtimeSecret, NeonRealtimeSnapshot, NeonRoleSnapshot, NeonScheduleTriggerSnapshot, NeonStorageObjectCreatedTriggerSnapshot, NeonTriggerSnapshot, UpdateBranchInput, UpdateTriggerInput } from "./lib/neon-api.js";
|
|
4
4
|
import { createNeonApiFromOptions } from "./lib/auth.js";
|
|
5
5
|
import { authoredAiGateway, authoredBuckets, authoredFunctions, deprecatedPreviewAuthoring, previewGaWarningForConfig, previewGaWarningMessage } from "./lib/authored-services.js";
|
|
6
6
|
import { CredentialFeatureFlags, credentialScopesSatisfied, deriveCredentialScopes } from "./lib/credentials.js";
|
|
@@ -11,4 +11,4 @@ import { FUNCTION_ARCHIVE_ENTRIES, FUNCTION_SOURCE_ENTRIES, FunctionArchiveEntry
|
|
|
11
11
|
import { LoadConfigOptions, loadConfigFromFile } from "./lib/loader.js";
|
|
12
12
|
import { createRealNeonApi } from "./lib/neon-api-real.js";
|
|
13
13
|
import { errors, schemas } from "./v1.js";
|
|
14
|
-
export { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, CheckoutAfterContext, CheckoutBeforeContext, CheckoutBeforeResult, CheckoutEvent, CheckoutHooks, ComputeSettings, ComputeUnit, Config, ConfigLoadError, ConfigValidationError, ConflictReport, CreateAfterContext, CreateBeforeContext, CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateHooks, CreateProjectInput, CreateTriggerInput, CredentialFeatureFlags, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DeployAfterContext, DeployBeforeContext, DeployEvent, DeployFunctionInput, DeployHooks, DiffOptions, DiffResult, DurationString, DurationUnit, EnableDataApiInput, ErrorCode, ExperimentalInput, ExternalPackageDef, ExternalPackageEntry, FUNCTION_ARCHIVE_ENTRIES, FUNCTION_SOURCE_ENTRIES, FunctionArchiveEntry, FunctionBundle, FunctionBundler, FunctionBundlerInput, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionScheduleTriggerDef, FunctionSourceEntry, FunctionStorageObjectCreatedTriggerDef, FunctionTriggerDef, FunctionTuning, GetConnectionUriInput, GitContext, Hook, HookBranch, HookEnv, Hooks, LoadConfigOptions, MissingContextError, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialReveal, NeonCredentialSecret, NeonCustomDomainSnapshot, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, NeonScheduleTriggerSnapshot, NeonStorageObjectCreatedTriggerSnapshot, NeonTriggerSnapshot, PartialBranchCreateError, PlanStep, PlatformError, PostgresConfig, PreviewInput, PreviewTuning, PushAbortedError, PushConflictError, PushResult, RemotePreviewState, RemoteServiceState, RemoteState, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedExternalPackage, ResolvedFunctionConfig, ResolvedFunctionScheduleTrigger, ResolvedFunctionStorageObjectCreatedTrigger, ResolvedFunctionTrigger, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput, ShellHook, UpdateBranchInput, UpdateTriggerInput, authoredAiGateway, authoredBuckets, authoredFunctions, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deprecatedPreviewAuthoring, deriveCredentialScopes, diffConfig, errors, externalPackageRoot, isFunctionArchiveEntry, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, packagesToStage, pickFunctionSourceEntry, previewGaWarningForConfig, previewGaWarningMessage, resolveConfig, schemas };
|
|
14
|
+
export { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, CheckoutAfterContext, CheckoutBeforeContext, CheckoutBeforeResult, CheckoutEvent, CheckoutHooks, ComputeSettings, ComputeUnit, Config, ConfigLoadError, ConfigValidationError, ConfigureRealtimeInput, ConflictReport, CreateAfterContext, CreateBeforeContext, CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateHooks, CreateProjectInput, CreateTriggerInput, CredentialFeatureFlags, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DeployAfterContext, DeployBeforeContext, DeployEvent, DeployFunctionInput, DeployHooks, DiffOptions, DiffResult, DurationString, DurationUnit, EnableDataApiInput, ErrorCode, ExperimentalInput, ExternalPackageDef, ExternalPackageEntry, FUNCTION_ARCHIVE_ENTRIES, FUNCTION_SOURCE_ENTRIES, FunctionArchiveEntry, FunctionBundle, FunctionBundler, FunctionBundlerInput, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionScheduleTriggerDef, FunctionSourceEntry, FunctionStorageObjectCreatedTriggerDef, FunctionTriggerDef, FunctionTuning, GetConnectionUriInput, GitContext, Hook, HookBranch, HookEnv, Hooks, LoadConfigOptions, MissingContextError, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialReveal, NeonCredentialSecret, NeonCustomDomainSnapshot, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRealtimeSecret, NeonRealtimeSnapshot, NeonRoleSnapshot, NeonScheduleTriggerSnapshot, NeonStorageObjectCreatedTriggerSnapshot, NeonTriggerSnapshot, PartialBranchCreateError, PlanStep, PlatformError, PostgresConfig, PreviewInput, PreviewTuning, PushAbortedError, PushConflictError, PushResult, RealtimeConfig, RealtimeInput, RemotePreviewState, RemoteServiceState, RemoteState, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedExternalPackage, ResolvedFunctionConfig, ResolvedFunctionScheduleTrigger, ResolvedFunctionStorageObjectCreatedTrigger, ResolvedFunctionTrigger, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput, ShellHook, UpdateBranchInput, UpdateTriggerInput, authoredAiGateway, authoredBuckets, authoredFunctions, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deprecatedPreviewAuthoring, deriveCredentialScopes, diffConfig, errors, externalPackageRoot, isFunctionArchiveEntry, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, packagesToStage, pickFunctionSourceEntry, previewGaWarningForConfig, previewGaWarningMessage, resolveConfig, schemas };
|
|
@@ -12,7 +12,8 @@ declare function authoredAiGateway(config: Pick<Config, "aiGateway" | "preview">
|
|
|
12
12
|
*
|
|
13
13
|
* Collision between the two homes is rejected at validation time, so each field
|
|
14
14
|
* has at most one source. An empty `preview: {}` still produces an empty object
|
|
15
|
-
* so resolve keeps today's `resolved.preview` of empty arrays.
|
|
15
|
+
* so resolve keeps today's `resolved.preview` of empty arrays. A preview block that
|
|
16
|
+
* contains only Realtime stays out of this legacy service normalization.
|
|
16
17
|
*/
|
|
17
18
|
declare function mergeAuthoredPreview(config: Config): PreviewInput | undefined;
|
|
18
19
|
/** Per-function branch tuning from top-level `functions` or deprecated `preview.functions`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authored-services.d.ts","names":["BranchTarget","BranchTuning","BucketDef","Config","FunctionDef","PreviewInput","ServiceToggleInput","AuthoredServiceKey","authoredFunctions","Pick","Record","authoredBuckets","authoredAiGateway","mergeAuthoredPreview","authoredFunctionTuning","NonNullable","deprecatedPreviewAuthoring","previewGaWarningMessage","previewGaWarningForConfig","BranchTarget","BranchTuning","BucketDef","Config","FunctionDef","PreviewInput","ServiceToggleInput","AuthoredServiceKey","authoredFunctions","config","Pick","Record","authoredBuckets","authoredAiGateway","mergeAuthoredPreview","authoredFunctionTuning","tuning","NonNullable","deprecatedPreviewAuthoring","previewGaWarningMessage","keys","previewGaWarningForConfig","target"],"sources":["../../src/lib/authored-services.ts"],"mappings":";;;;KAYYO,kBAAAA;AAAAA,iBAcIC,iBAAAA,CAdcoB,MAAA,EAerBnB,IAfqB,CAehBN,MAfgB,EAAA,WAAA,GAAA,SAAA,CAAA,CAAA,EAgB3BO,MAhB2B,CAAA,MAAA,EAgBZN,WAhBY,CAAA,GAAA,SAAA;AAcdI,iBAMAG,eAAAA,CANiBiB,MAAA,EAOxBnB,IAPwB,CAOnBN,MAPmB,EAAA,SAAA,GAAA,SAAA,CAAA,CAAA,EAQ9BO,MAR8B,CAAA,MAAA,EAQfR,SARe,CAAA,GAAA,SAAA;AAAA,iBAYjBU,iBAAAA,CAZiBgB,MAAA,EAaxBnB,IAbwB,CAanBN,MAbmB,EAAA,WAAA,GAAA,SAAA,CAAA,CAAA,EAc9BG,kBAd8B,GAAA,SAAA;AACnBH;AAALM;AACSL;AAAfM;AAAM;AAIT;AAA+B;AACjBP;AAALM,
|
|
1
|
+
{"version":3,"file":"authored-services.d.ts","names":["BranchTarget","BranchTuning","BucketDef","Config","FunctionDef","PreviewInput","ServiceToggleInput","AuthoredServiceKey","authoredFunctions","Pick","Record","authoredBuckets","authoredAiGateway","mergeAuthoredPreview","authoredFunctionTuning","NonNullable","deprecatedPreviewAuthoring","previewGaWarningMessage","previewGaWarningForConfig","BranchTarget","BranchTuning","BucketDef","Config","FunctionDef","PreviewInput","ServiceToggleInput","AuthoredServiceKey","authoredFunctions","config","Pick","Record","authoredBuckets","authoredAiGateway","mergeAuthoredPreview","authoredFunctionTuning","tuning","NonNullable","deprecatedPreviewAuthoring","previewGaWarningMessage","keys","previewGaWarningForConfig","target"],"sources":["../../src/lib/authored-services.ts"],"mappings":";;;;KAYYO,kBAAAA;AAAAA,iBAcIC,iBAAAA,CAdcoB,MAAA,EAerBnB,IAfqB,CAehBN,MAfgB,EAAA,WAAA,GAAA,SAAA,CAAA,CAAA,EAgB3BO,MAhB2B,CAAA,MAAA,EAgBZN,WAhBY,CAAA,GAAA,SAAA;AAcdI,iBAMAG,eAAAA,CANiBiB,MAAA,EAOxBnB,IAPwB,CAOnBN,MAPmB,EAAA,SAAA,GAAA,SAAA,CAAA,CAAA,EAQ9BO,MAR8B,CAAA,MAAA,EAQfR,SARe,CAAA,GAAA,SAAA;AAAA,iBAYjBU,iBAAAA,CAZiBgB,MAAA,EAaxBnB,IAbwB,CAanBN,MAbmB,EAAA,WAAA,GAAA,SAAA,CAAA,CAAA,EAc9BG,kBAd8B,GAAA,SAAA;AACnBH;AAALM;AACSL;AAAfM;AAAM;AAIT;AAA+B;AACjBP;AAALM;AACSP,iBAmBFW,oBAAAA,CAnBEX,MAAAA,EAmB2BC,MAnB3BD,CAAAA,EAmBoCG,YAnBpCH,GAAAA,SAAAA;AAAfQ;AAAM,iBA0COI,sBAAAA,CA1CPqB,MAAA,EA2CAlC,YA3CA,CAAA,EA4CNc,WA5CM,CA4CMd,YA5CN,CAAA,WAAA,CAAA,CAAA;AAIT;AAAiC;AACnBE;AAALM;AACNH,iBA8CaU,0BAAAA,CA9CbV,MAAAA,EA+CMG,IA/CNH,CA+CWH,MA/CXG,EAAAA,SAAAA,CAAAA,EAAAA,MAAAA,CAAAA,EAgDOG,IAhDPH,CAgDYL,YAhDZK,EAAAA,SAAAA,GAAAA,WAAAA,CAAAA,CAAAA,EAAAA,MAAAA,EAAAA;AAAkB;AAaLO,iBAgDAI,uBAAAA,CAhDoBsB,IAAA,EAAA,SAAA,MAAA,EAAA,CAAA,EAAA,MAAA;AAAA;AAASpC;AAASE;AAAY;AAuBlE;AAAsC;AAC7BJ,iBAgDOiB,yBAAAA,CAhDPjB,MAAAA,EAiDAE,MAjDAF,EAAAA,MAAAA,CAAAA,EAkDCD,YAlDDC,CAAAA,EAAAA,MAAAA,GAAAA,IAAAA"}
|
|
@@ -25,13 +25,15 @@ function authoredAiGateway(config) {
|
|
|
25
25
|
*
|
|
26
26
|
* Collision between the two homes is rejected at validation time, so each field
|
|
27
27
|
* has at most one source. An empty `preview: {}` still produces an empty object
|
|
28
|
-
* so resolve keeps today's `resolved.preview` of empty arrays.
|
|
28
|
+
* so resolve keeps today's `resolved.preview` of empty arrays. A preview block that
|
|
29
|
+
* contains only Realtime stays out of this legacy service normalization.
|
|
29
30
|
*/
|
|
30
31
|
function mergeAuthoredPreview(config) {
|
|
31
32
|
const functions = authoredFunctions(config);
|
|
32
33
|
const buckets = authoredBuckets(config);
|
|
33
34
|
const aiGateway = authoredAiGateway(config);
|
|
34
|
-
|
|
35
|
+
const hasEmptyPreview = config.preview !== void 0 && Object.keys(config.preview).length === 0;
|
|
36
|
+
if (functions === void 0 && buckets === void 0 && aiGateway === void 0 && !hasEmptyPreview) return;
|
|
35
37
|
const merged = {};
|
|
36
38
|
if (aiGateway !== void 0) merged.aiGateway = aiGateway;
|
|
37
39
|
if (functions !== void 0) merged.functions = functions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authored-services.js","names":[],"sources":["../../src/lib/authored-services.ts"],"sourcesContent":["import { branchTuningSchema } from \"./schema.js\";\nimport type {\n\tBranchTarget,\n\tBranchTuning,\n\tBucketDef,\n\tConfig,\n\tFunctionDef,\n\tPreviewInput,\n\tServiceToggleInput,\n} from \"./types.js\";\n\n/** The home a static service can be authored in. */\nexport type AuthoredServiceKey = \"aiGateway\" | \"functions\" | \"buckets\";\n\nconst PREVIEW_PATH: Record<AuthoredServiceKey, string> = {\n\taiGateway: \"preview.aiGateway\",\n\tfunctions: \"preview.functions\",\n\tbuckets: \"preview.buckets\",\n};\n\nconst GA_PATH: Record<AuthoredServiceKey, string> = {\n\taiGateway: \"aiGateway\",\n\tfunctions: \"functions\",\n\tbuckets: \"buckets\",\n};\n\nexport function authoredFunctions(\n\tconfig: Pick<Config, \"functions\" | \"preview\">,\n): Record<string, FunctionDef> | undefined {\n\treturn config.functions ?? config.preview?.functions;\n}\n\nexport function authoredBuckets(\n\tconfig: Pick<Config, \"buckets\" | \"preview\">,\n): Record<string, BucketDef> | undefined {\n\treturn config.buckets ?? config.preview?.buckets;\n}\n\nexport function authoredAiGateway(\n\tconfig: Pick<Config, \"aiGateway\" | \"preview\">,\n): ServiceToggleInput | undefined {\n\treturn config.aiGateway ?? config.preview?.aiGateway;\n}\n\n/**\n * Fold top-level GA keys and deprecated `preview` keys into the shape\n * {@link import(\"./define-config.js\").resolveConfig} already consumes.\n *\n * Collision between the two homes is rejected at validation time, so each field\n * has at most one source. An empty `preview: {}` still produces an empty object\n * so resolve keeps today's `resolved.preview` of empty arrays.\n */\nexport function mergeAuthoredPreview(config: Config): PreviewInput | undefined {\n\tconst functions = authoredFunctions(config);\n\tconst buckets = authoredBuckets(config);\n\tconst aiGateway = authoredAiGateway(config);\n\tif (\n\t\tfunctions === undefined &&\n\t\tbuckets === undefined &&\n\t\taiGateway === undefined &&\n\t\
|
|
1
|
+
{"version":3,"file":"authored-services.js","names":[],"sources":["../../src/lib/authored-services.ts"],"sourcesContent":["import { branchTuningSchema } from \"./schema.js\";\nimport type {\n\tBranchTarget,\n\tBranchTuning,\n\tBucketDef,\n\tConfig,\n\tFunctionDef,\n\tPreviewInput,\n\tServiceToggleInput,\n} from \"./types.js\";\n\n/** The home a static service can be authored in. */\nexport type AuthoredServiceKey = \"aiGateway\" | \"functions\" | \"buckets\";\n\nconst PREVIEW_PATH: Record<AuthoredServiceKey, string> = {\n\taiGateway: \"preview.aiGateway\",\n\tfunctions: \"preview.functions\",\n\tbuckets: \"preview.buckets\",\n};\n\nconst GA_PATH: Record<AuthoredServiceKey, string> = {\n\taiGateway: \"aiGateway\",\n\tfunctions: \"functions\",\n\tbuckets: \"buckets\",\n};\n\nexport function authoredFunctions(\n\tconfig: Pick<Config, \"functions\" | \"preview\">,\n): Record<string, FunctionDef> | undefined {\n\treturn config.functions ?? config.preview?.functions;\n}\n\nexport function authoredBuckets(\n\tconfig: Pick<Config, \"buckets\" | \"preview\">,\n): Record<string, BucketDef> | undefined {\n\treturn config.buckets ?? config.preview?.buckets;\n}\n\nexport function authoredAiGateway(\n\tconfig: Pick<Config, \"aiGateway\" | \"preview\">,\n): ServiceToggleInput | undefined {\n\treturn config.aiGateway ?? config.preview?.aiGateway;\n}\n\n/**\n * Fold top-level GA keys and deprecated `preview` keys into the shape\n * {@link import(\"./define-config.js\").resolveConfig} already consumes.\n *\n * Collision between the two homes is rejected at validation time, so each field\n * has at most one source. An empty `preview: {}` still produces an empty object\n * so resolve keeps today's `resolved.preview` of empty arrays. A preview block that\n * contains only Realtime stays out of this legacy service normalization.\n */\nexport function mergeAuthoredPreview(config: Config): PreviewInput | undefined {\n\tconst functions = authoredFunctions(config);\n\tconst buckets = authoredBuckets(config);\n\tconst aiGateway = authoredAiGateway(config);\n\tconst hasEmptyPreview =\n\t\tconfig.preview !== undefined &&\n\t\tObject.keys(config.preview).length === 0;\n\tif (\n\t\tfunctions === undefined &&\n\t\tbuckets === undefined &&\n\t\taiGateway === undefined &&\n\t\t!hasEmptyPreview\n\t) {\n\t\treturn undefined;\n\t}\n\tconst merged: PreviewInput = {};\n\tif (aiGateway !== undefined) merged.aiGateway = aiGateway;\n\tif (functions !== undefined) merged.functions = functions;\n\tif (buckets !== undefined) merged.buckets = buckets;\n\treturn merged;\n}\n\n/** Per-function branch tuning from top-level `functions` or deprecated `preview.functions`. */\nexport function authoredFunctionTuning(\n\ttuning: BranchTuning,\n): NonNullable<BranchTuning[\"functions\"]> {\n\treturn tuning.functions ?? tuning.preview?.functions ?? {};\n}\n\n/**\n * Deprecated authoring paths still present on the policy. Used by the CLI deploy/apply\n * warning. Empty `preview: {}` contributes nothing.\n */\nexport function deprecatedPreviewAuthoring(\n\tconfig: Pick<Config, \"preview\">,\n\ttuning?: Pick<BranchTuning, \"preview\" | \"functions\">,\n): string[] {\n\tconst keys: string[] = [];\n\tfor (const key of [\"aiGateway\", \"functions\", \"buckets\"] as const) {\n\t\tif (config.preview?.[key] !== undefined) keys.push(PREVIEW_PATH[key]);\n\t}\n\tif (tuning?.preview?.functions !== undefined) {\n\t\tkeys.push(\"branch.preview.functions\");\n\t}\n\treturn keys;\n}\n\n/** One-line deploy warning naming each deprecated path and its GA replacement. */\nexport function previewGaWarningMessage(keys: readonly string[]): string {\n\tconst lifts = keys.map((key) => {\n\t\tswitch (key) {\n\t\t\tcase \"preview.aiGateway\":\n\t\t\t\treturn `${PREVIEW_PATH.aiGateway} → ${GA_PATH.aiGateway}`;\n\t\t\tcase \"preview.functions\":\n\t\t\t\treturn `${PREVIEW_PATH.functions} → ${GA_PATH.functions}`;\n\t\t\tcase \"preview.buckets\":\n\t\t\t\treturn `${PREVIEW_PATH.buckets} → ${GA_PATH.buckets}`;\n\t\t\tcase \"branch.preview.functions\":\n\t\t\t\treturn \"branch.preview.functions → branch.functions\";\n\t\t\tdefault:\n\t\t\t\treturn key;\n\t\t}\n\t});\n\treturn `These neon.ts keys are now GA and can be lifted out of preview: ${lifts.join(\", \")}.`;\n}\n\n/**\n * Deprecation warning for a policy that still authors GA services under `preview`.\n * Pass the same {@link BranchTarget} `resolveConfig` / apply will use so\n * `branch.preview.functions` tuning on that branch is included. Without a\n * target, only static `preview.*` keys are reported.\n */\nexport function previewGaWarningForConfig(\n\tconfig: Config,\n\ttarget?: BranchTarget,\n): string | null {\n\tconst keys = new Set(deprecatedPreviewAuthoring(config));\n\tif (typeof config.branch === \"function\" && target !== undefined) {\n\t\ttry {\n\t\t\tconst parsed = branchTuningSchema.safeParse(\n\t\t\t\tconfig.branch(target) ?? {},\n\t\t\t);\n\t\t\tif (parsed.success) {\n\t\t\t\tfor (const key of deprecatedPreviewAuthoring(\n\t\t\t\t\tconfig,\n\t\t\t\t\tparsed.data,\n\t\t\t\t)) {\n\t\t\t\t\tkeys.add(key);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// A throwing closure is a resolveConfig error, not a warning path.\n\t\t}\n\t}\n\tif (keys.size === 0) return null;\n\treturn previewGaWarningMessage([...keys]);\n}\n"],"mappings":";;AAcA,MAAM,eAAmD;CACxD,WAAW;CACX,WAAW;CACX,SAAS;AACV;AAEA,MAAM,UAA8C;CACnD,WAAW;CACX,WAAW;CACX,SAAS;AACV;AAEA,SAAgB,kBACf,QAC0C;CAC1C,OAAO,OAAO,aAAa,OAAO,SAAS;AAC5C;AAEA,SAAgB,gBACf,QACwC;CACxC,OAAO,OAAO,WAAW,OAAO,SAAS;AAC1C;AAEA,SAAgB,kBACf,QACiC;CACjC,OAAO,OAAO,aAAa,OAAO,SAAS;AAC5C;;;;;;;;;;AAWA,SAAgB,qBAAqB,QAA0C;CAC9E,MAAM,YAAY,kBAAkB,MAAM;CAC1C,MAAM,UAAU,gBAAgB,MAAM;CACtC,MAAM,YAAY,kBAAkB,MAAM;CAC1C,MAAM,kBACL,OAAO,YAAY,KAAA,KACnB,OAAO,KAAK,OAAO,OAAO,CAAC,CAAC,WAAW;CACxC,IACC,cAAc,KAAA,KACd,YAAY,KAAA,KACZ,cAAc,KAAA,KACd,CAAC,iBAED;CAED,MAAM,SAAuB,CAAC;CAC9B,IAAI,cAAc,KAAA,GAAW,OAAO,YAAY;CAChD,IAAI,cAAc,KAAA,GAAW,OAAO,YAAY;CAChD,IAAI,YAAY,KAAA,GAAW,OAAO,UAAU;CAC5C,OAAO;AACR;;AAGA,SAAgB,uBACf,QACyC;CACzC,OAAO,OAAO,aAAa,OAAO,SAAS,aAAa,CAAC;AAC1D;;;;;AAMA,SAAgB,2BACf,QACA,QACW;CACX,MAAM,OAAiB,CAAC;CACxB,KAAK,MAAM,OAAO;EAAC;EAAa;EAAa;CAAS,GACrD,IAAI,OAAO,UAAU,SAAS,KAAA,GAAW,KAAK,KAAK,aAAa,IAAI;CAErE,IAAI,QAAQ,SAAS,cAAc,KAAA,GAClC,KAAK,KAAK,0BAA0B;CAErC,OAAO;AACR;;AAGA,SAAgB,wBAAwB,MAAiC;CAexE,OAAO,mEAdO,KAAK,KAAK,QAAQ;EAC/B,QAAQ,KAAR;GACC,KAAK,qBACJ,OAAO,GAAG,aAAa,UAAU,KAAK,QAAQ;GAC/C,KAAK,qBACJ,OAAO,GAAG,aAAa,UAAU,KAAK,QAAQ;GAC/C,KAAK,mBACJ,OAAO,GAAG,aAAa,QAAQ,KAAK,QAAQ;GAC7C,KAAK,4BACJ,OAAO;GACR,SACC,OAAO;EACT;CACD,CAC8E,CAAC,CAAC,KAAK,IAAI,EAAE;AAC5F;;;;;;;AAQA,SAAgB,0BACf,QACA,QACgB;CAChB,MAAM,OAAO,IAAI,IAAI,2BAA2B,MAAM,CAAC;CACvD,IAAI,OAAO,OAAO,WAAW,cAAc,WAAW,KAAA,GACrD,IAAI;EACH,MAAM,SAAS,mBAAmB,UACjC,OAAO,OAAO,MAAM,KAAK,CAAC,CAC3B;EACA,IAAI,OAAO,SACV,KAAK,MAAM,OAAO,2BACjB,QACA,OAAO,IACR,GACC,KAAK,IAAI,GAAG;CAGf,QAAQ,CAER;CAED,IAAI,KAAK,SAAS,GAAG,OAAO;CAC5B,OAAO,wBAAwB,CAAC,GAAG,IAAI,CAAC;AACzC"}
|
|
@@ -75,6 +75,9 @@ type BucketsAutocomplete<Buckets> = Buckets extends Record<string, unknown> ? {
|
|
|
75
75
|
* import { defineConfig } from "@neon/config/v1";
|
|
76
76
|
*
|
|
77
77
|
* export default defineConfig({
|
|
78
|
+
* preview: {
|
|
79
|
+
* realtime: { allowedOrigins: ["https://app.example.com"] },
|
|
80
|
+
* },
|
|
78
81
|
* auth: true,
|
|
79
82
|
* functions: {
|
|
80
83
|
* hello: { name: "Hello", source: "./functions/hello.ts", dev: { port: 8787 } },
|
|
@@ -83,8 +86,9 @@ type BucketsAutocomplete<Buckets> = Buckets extends Record<string, unknown> ? {
|
|
|
83
86
|
* });
|
|
84
87
|
* ```
|
|
85
88
|
*
|
|
86
|
-
* The policy is split into a **static** existential set (top-level `auth` /
|
|
87
|
-
* `aiGateway` / `functions` / `buckets` / `triggers`, plus the deprecated
|
|
89
|
+
* The policy is split into a **static** existential set (`preview.realtime`, top-level `auth` /
|
|
90
|
+
* `dataApi` / `aiGateway` / `functions` / `buckets` / `triggers`, plus the deprecated
|
|
91
|
+
* aliases under `preview`) and a
|
|
88
92
|
* **dynamic** per-branch `branch` closure. The static half determines which secrets exist —
|
|
89
93
|
* so `NeonEnv<typeof config>` and `parseEnv` are exact — while the closure can only *tune*
|
|
90
94
|
* a branch (lifecycle, compute, per-function deploy settings), never change what exists.
|
|
@@ -105,7 +109,6 @@ declare function defineConfig<const Auth extends ServiceToggleInput | undefined
|
|
|
105
109
|
functions?: Functions & Record<string, FunctionDef> & FunctionsAutocomplete<Functions>;
|
|
106
110
|
buckets?: Buckets & Record<string, BucketDef> & BucketsAutocomplete<Buckets>;
|
|
107
111
|
triggers?: Record<string, FunctionTriggerDef>;
|
|
108
|
-
/** @deprecated Use top-level `aiGateway`, `functions`, and `buckets`. */
|
|
109
112
|
preview?: Preview & PreviewInput & PreviewAutocomplete<Preview>;
|
|
110
113
|
branch?: BranchTuningFn<Preview, Functions>;
|
|
111
114
|
experimental?: ExperimentalInput;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-config.d.ts","names":["BranchTarget","BranchTuningFn","BucketDef","Config","DataApiInput","ExperimentalInput","FunctionDef","FunctionTriggerDef","PreviewInput","ResolvedBranchConfig","ServiceEnabled","ServiceToggleInput","DataApiUsesNeonAuth","DataApi","NeonAuthRequiredHint","DataApiField","Auth","PreviewAutocomplete","Preview","F","B","FunctionsAutocomplete","Functions","Record","BucketsAutocomplete","Buckets","defineConfig","AiGateway","resolveConfig","normalizeRegion","BranchTarget","BranchTuningFn","BucketDef","Config","DataApiInput","ExperimentalInput","FunctionDef","FunctionTriggerDef","PreviewInput","ResolvedBranchConfig","ServiceEnabled","ServiceToggleInput","DataApiUsesNeonAuth","DataApi","authProvider","NeonAuthRequiredHint","DataApiField","Auth","PreviewAutocomplete","Preview","functions","F","buckets","B","FunctionsAutocomplete","Functions","Record","BucketsAutocomplete","Buckets","defineConfig","input","auth","dataApi","aiGateway","AiGateway","triggers","preview","branch","experimental","resolveConfig","config","normalizeRegion","region"],"sources":["../../src/lib/define-config.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"define-config.d.ts","names":["BranchTarget","BranchTuningFn","BucketDef","Config","DataApiInput","ExperimentalInput","FunctionDef","FunctionTriggerDef","PreviewInput","ResolvedBranchConfig","ServiceEnabled","ServiceToggleInput","DataApiUsesNeonAuth","DataApi","NeonAuthRequiredHint","DataApiField","Auth","PreviewAutocomplete","Preview","F","B","FunctionsAutocomplete","Functions","Record","BucketsAutocomplete","Buckets","defineConfig","AiGateway","resolveConfig","normalizeRegion","BranchTarget","BranchTuningFn","BucketDef","Config","DataApiInput","ExperimentalInput","FunctionDef","FunctionTriggerDef","PreviewInput","ResolvedBranchConfig","ServiceEnabled","ServiceToggleInput","DataApiUsesNeonAuth","DataApi","authProvider","NeonAuthRequiredHint","DataApiField","Auth","PreviewAutocomplete","Preview","functions","F","buckets","B","FunctionsAutocomplete","Functions","Record","BucketsAutocomplete","Buckets","defineConfig","input","auth","dataApi","aiGateway","AiGateway","triggers","preview","branch","experimental","resolveConfig","config","normalizeRegion","region"],"sources":["../../src/lib/define-config.ts"],"mappings":";;;;;;AAmCoB;AAcI;AACRa;AAAfH,KADIE,mBACJF,CAAAA,OAAAA,CAAAA,GAAAA,cAAAA,CAAeG,OAAfH,CAAAA,SAAAA,IAAAA,GAAAA,CACIG,OADJH,CAAAA,SAAAA,CAAAA;EACIG,YAAAA,EAAAA,UAAAA;AAAO,CAAA,CAAA,GAAA,KAAA,GAAA,IAAA,GAAA,KAAA;AAiBZ;AAqBA;AAAwB;AACHA;AAApBD;AACkBI;AAAfN;AACCG;AAAUT;AACVU;AACDD,KA1BQC,oBAAAA,GA0BRD,+QAAAA;AAAUT;AAAY;AAAC;AAoBH;AAAac;AACJC;AAAIb;AAEnCY;AAC8BE;AAAIlB;AAAS;AAAA;AAGnB;AACzBoB;AAAkBC;AACED;AAAYhB,KAlCrBS,YAkCqBT,CAAAA,IAAAA,EAAAA,OAAAA,CAAAA,GAjChCM,mBAiCgCN,CAjCZO,OAiCYP,CAAAA,SAAAA,IAAAA,GAhC7BI,cAgC6BJ,CAhCdU,IAgCcV,CAAAA,SAAAA,IAAAA,GA/B5BO,OA+B4BP,GA/BlBF,YA+BkBE,GA9B5BQ,oBA8B4BR,GA7B7BO,OA6B6BP,GA7BnBF,YA6BmBE;AAAW;AAAA;AAGpB;AACvBmB;AAAgBF;AACIE;AAAUvB;AAAS;AAsCxC;AAA4B;AACRS;AACGP;AACAI;AACiBF;AAAfiB;AACarB;AAAfqB;AACEZ;AAQjBK,KAlEHC,mBAkEGD,CAAAA,OAAAA,CAAAA,GAAAA,CAlE6BE,OAkE7BF,SAAAA;EAAOL,SAAAA,EAAAA,KAAAA,EAAAA;AAISK,CAAAA,GAAAA;EAAMH,SAAAA,EAAAA,WAAnBE,MArEsBI,CAqEtBJ,GArE0BT,WAqE1BS,EACEY;AAAYhB,CAAAA,GAAAA,OAAAA,CAAAA,GAAAA,CApEvBO,OAoEuBP,SAAAA;EACZW,OAAAA,EAAAA,KAAAA,EAAAA;AACIhB,CAAAA,GAAAA;EAAfiB,OAAAA,EAAAA,WACsBD,MAtEQF,CAsERE,GAtEYpB,SAsEZoB,EAAtBD;AACSI,CAAAA,GAAAA,OAAAA,CAAAA;AACMvB,KArEZmB,qBAqEYnB,CAAAA,SAAAA,CAAAA,GApEhBoB,SAoEgBpB,SApEEqB,MAoEFrB,CAAAA,MAAAA,EAAAA,OAAAA,CAAAA,GAAAA,WAAfqB,MAnEmBD,SAmEnBC,GAnE+BjB,WAmE/BiB,EACoBE,GAAAA,OAAAA;AAApBD,KAjEGA,mBAiEHA,CAAAA,OAAAA,CAAAA,GAhEDC,OAgECD,SAhEeD,MAgEfC,CAAAA,MAAAA,EAAAA,OAAAA,CAAAA,GAAAA,WACyBjB,MAhENkB,OAgEMlB,GAhEIL,SAgEJK,EAAfgB,GAAAA,OAAAA;AAIDL;AAAUV;AAAmCU;AAApBD;AACXC;AAASI;AAAxBrB;AAIMI;AACLW;AAAMH;AAASK;AAASI;AAAWG;AAASE;AAAnDxB;AAAM;AAmCV;AAA6B;AACpBA;AACAH;AACNS;AAAoB;AAmRvB;;;;;;;;;;;;;iBA7VgBiB,gCACIf,kEACGP,4DACAI,8DACEe,eAAejB,4DACjBiB,eAAerB,4DACbS;SAQjBK,OAAOL;YAIJI,aAAaC,MAAMH;cACjBc,YAAYhB;cACZW,YACXC,eAAejB,eACfe,sBAAsBC;YACbG,UACTF,eAAerB,aACfsB,oBAAoBC;aACVF,eAAehB;YAIhBW,UAAUV,eAAeS,oBAAoBC;WAC9CjB,eAAeiB,SAASI;iBAIlBjB;IACZF,OAAOa,MAAMH,SAASK,SAASI,WAAWG,SAASE;;;;;;;;iBAmCvCC,aAAAA,SACPzB,gBACAH,eACNS;;;;;;iBAmRaoB,eAAAA"}
|
|
@@ -17,6 +17,9 @@ const REGION_PREFIX = /^(aws|azure|gcp)-/;
|
|
|
17
17
|
* import { defineConfig } from "@neon/config/v1";
|
|
18
18
|
*
|
|
19
19
|
* export default defineConfig({
|
|
20
|
+
* preview: {
|
|
21
|
+
* realtime: { allowedOrigins: ["https://app.example.com"] },
|
|
22
|
+
* },
|
|
20
23
|
* auth: true,
|
|
21
24
|
* functions: {
|
|
22
25
|
* hello: { name: "Hello", source: "./functions/hello.ts", dev: { port: 8787 } },
|
|
@@ -25,8 +28,9 @@ const REGION_PREFIX = /^(aws|azure|gcp)-/;
|
|
|
25
28
|
* });
|
|
26
29
|
* ```
|
|
27
30
|
*
|
|
28
|
-
* The policy is split into a **static** existential set (top-level `auth` /
|
|
29
|
-
* `aiGateway` / `functions` / `buckets` / `triggers`, plus the deprecated
|
|
31
|
+
* The policy is split into a **static** existential set (`preview.realtime`, top-level `auth` /
|
|
32
|
+
* `dataApi` / `aiGateway` / `functions` / `buckets` / `triggers`, plus the deprecated
|
|
33
|
+
* aliases under `preview`) and a
|
|
30
34
|
* **dynamic** per-branch `branch` closure. The static half determines which secrets exist —
|
|
31
35
|
* so `NeonEnv<typeof config>` and `parseEnv` are exact — while the closure can only *tune*
|
|
32
36
|
* a branch (lifecycle, compute, per-function deploy settings), never change what exists.
|
|
@@ -56,11 +60,15 @@ function defineConfig(input) {
|
|
|
56
60
|
*/
|
|
57
61
|
function resolveConfig(config, branch) {
|
|
58
62
|
const tuning = evaluateBranchTuning(config.branch, branch);
|
|
63
|
+
const realtimeInput = config.preview?.realtime;
|
|
59
64
|
const resolved = {
|
|
65
|
+
realtimePolicy: realtimeInput === void 0 ? "omitted" : isRealtimeEnabled(realtimeInput) ? "enabled" : "disabled",
|
|
60
66
|
authEnabled: isServiceEnabled(config.auth),
|
|
61
67
|
dataApiEnabled: isDataApiEnabled(config.dataApi),
|
|
62
68
|
dataApiPolicy: config.dataApi === void 0 ? "omitted" : isDataApiEnabled(config.dataApi) ? "enabled" : "disabled"
|
|
63
69
|
};
|
|
70
|
+
const realtime = resolveRealtime(realtimeInput);
|
|
71
|
+
if (realtime) resolved.realtime = realtime;
|
|
64
72
|
const dataApi = resolveDataApi(config.dataApi);
|
|
65
73
|
if (dataApi) resolved.dataApi = dataApi;
|
|
66
74
|
if (tuning.parent !== void 0) resolved.parent = tuning.parent;
|
|
@@ -97,6 +105,17 @@ function isServiceEnabled(toggle) {
|
|
|
97
105
|
if (typeof toggle === "boolean") return toggle;
|
|
98
106
|
return toggle.enabled !== false;
|
|
99
107
|
}
|
|
108
|
+
/** Whether a {@link RealtimeInput} is enabled (present object or `true`). */
|
|
109
|
+
function isRealtimeEnabled(input) {
|
|
110
|
+
if (input === void 0) return false;
|
|
111
|
+
if (typeof input === "boolean") return input;
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
/** Copy the options from an object-form {@link RealtimeInput}. */
|
|
115
|
+
function resolveRealtime(input) {
|
|
116
|
+
if (typeof input !== "object") return void 0;
|
|
117
|
+
return { ...input.allowedOrigins !== void 0 ? { allowedOrigins: [...input.allowedOrigins] } : {} };
|
|
118
|
+
}
|
|
100
119
|
/** Whether a {@link DataApiInput} is enabled (present object/`true` unless `enabled: false`). */
|
|
101
120
|
function isDataApiEnabled(input) {
|
|
102
121
|
if (input === void 0) return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-config.js","names":[],"sources":["../../src/lib/define-config.ts"],"sourcesContent":["import {\n\tauthoredFunctionTuning,\n\tmergeAuthoredPreview,\n} from \"./authored-services.js\";\nimport { normalizeCustomDomain } from \"./custom-domain.js\";\nimport { 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\tExperimentalInput,\n\tFunctionDef,\n\tFunctionTriggerDef,\n\tFunctionTuning,\n\tPreviewInput,\n\tResolvedBranchConfig,\n\tResolvedDataApiConfig,\n\tResolvedFunctionConfig,\n\tResolvedFunctionTrigger,\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 DEFAULT_FUNCTION_BUNDLER = \"esbuild\" 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\ntype FunctionsAutocomplete<Functions> =\n\tFunctions extends Record<string, unknown>\n\t\t? { [Slug in keyof Functions]: FunctionDef }\n\t\t: unknown;\n\ntype BucketsAutocomplete<Buckets> =\n\tBuckets extends Record<string, unknown>\n\t\t? { [Name in keyof Buckets]: 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 * functions: {\n * hello: { name: \"Hello\", source: \"./functions/hello.ts\", dev: { port: 8787 } },\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 * `aiGateway` / `functions` / `buckets` / `triggers`, plus the deprecated `preview` aliases) and a\n * **dynamic** per-branch `branch` closure. The static half determines which secrets exist —\n * so `NeonEnv<typeof config>` and `parseEnv` are exact — while the closure can only *tune*\n * a branch (lifecycle, compute, per-function 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\tconst Functions extends Record<string, FunctionDef> | undefined = undefined,\n\tconst Buckets extends Record<string, BucketDef> | undefined = undefined,\n\tconst AiGateway extends ServiceToggleInput | 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\taiGateway?: AiGateway & ServiceToggleInput;\n\tfunctions?: Functions &\n\t\tRecord<string, FunctionDef> &\n\t\tFunctionsAutocomplete<Functions>;\n\tbuckets?: Buckets &\n\t\tRecord<string, BucketDef> &\n\t\tBucketsAutocomplete<Buckets>;\n\ttriggers?: Record<string, FunctionTriggerDef>;\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\t/** @deprecated Use top-level `aiGateway`, `functions`, and `buckets`. */\n\tpreview?: Preview & PreviewInput & PreviewAutocomplete<Preview>;\n\tbranch?: BranchTuningFn<Preview, Functions>;\n\t// Experimental (unstable) features — currently just lifecycle hooks. Static — carried\n\t// through onto the returned Config and read by the runtime at `checkout` / `deploy` time.\n\t// Never evaluated here.\n\texperimental?: ExperimentalInput;\n}): Config<Auth, DataApi, Preview, Functions, Buckets, AiGateway> {\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, functions: { … }, branch: (branch) => ({ … }) })`.\",\n\t\t\t\"The static services 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<\n\t\tAuth,\n\t\tDataApi,\n\t\tPreview,\n\t\tFunctions,\n\t\tBuckets,\n\t\tAiGateway\n\t>;\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 + 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\tdataApiPolicy:\n\t\t\tconfig.dataApi === undefined\n\t\t\t\t? \"omitted\"\n\t\t\t\t: isDataApiEnabled(config.dataApi)\n\t\t\t\t\t? \"enabled\"\n\t\t\t\t\t: \"disabled\",\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(\n\t\tmergeAuthoredPreview(config),\n\t\ttuning,\n\t\tbranch,\n\t);\n\tif (preview) resolved.preview = preview;\n\tconst triggers = resolveTriggers(config.triggers);\n\tif (triggers.length > 0) resolved.triggers = triggers;\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\tbranch: BranchTarget,\n): ResolvedPreviewConfig | undefined {\n\tif (!preview) return undefined;\n\tconst fnTuning = authoredFunctionTuning(tuning);\n\tconst functions: ResolvedFunctionConfig[] = Object.entries(\n\t\tpreview.functions ?? {},\n\t).map(([slug, def]) =>\n\t\tresolveFunctionConfig(slug, def, fnTuning[slug] ?? {}, branch),\n\t);\n\tassertUniqueResolvedCustomDomains(functions);\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\tbranch: BranchTarget,\n): ResolvedFunctionConfig {\n\tconst customDomains = resolveFunctionCustomDomains(def, tuning, branch);\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\tbundler: def.bundler ?? DEFAULT_FUNCTION_BUNDLER,\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\t...(customDomains !== undefined ? { customDomains } : {}),\n\t};\n}\n\nfunction resolveTriggers(\n\ttriggers: Record<string, FunctionTriggerDef> | undefined,\n): ResolvedFunctionTrigger[] {\n\tif (!triggers) return [];\n\treturn Object.entries(triggers).map(([name, trigger]) => {\n\t\tif (trigger.type === \"schedule\") {\n\t\t\treturn {\n\t\t\t\ttype: \"schedule\" as const,\n\t\t\t\tname,\n\t\t\t\tfunctionSlug: trigger.function,\n\t\t\t\tcron: trigger.cron,\n\t\t\t\tfunctionPath: trigger.functionPath ?? \"/\",\n\t\t\t\tenabled: trigger.enabled ?? true,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\ttype: \"storage_object_created\" as const,\n\t\t\tname,\n\t\t\tfunctionSlug: trigger.function,\n\t\t\tbucketName: trigger.bucket,\n\t\t\t...(trigger.prefix !== undefined ? { prefix: trigger.prefix } : {}),\n\t\t\tfunctionPath: trigger.functionPath ?? \"/\",\n\t\t\tenabled: trigger.enabled ?? true,\n\t\t};\n\t});\n}\n\nfunction resolveFunctionCustomDomains(\n\tdef: FunctionDef,\n\ttuning: FunctionTuning,\n\tbranch: BranchTarget,\n): string[] | undefined {\n\tif (tuning.customDomains !== undefined) {\n\t\treturn tuning.customDomains.map(normalizeCustomDomain);\n\t}\n\t// Hostnames are globally unique, so a child checkout 409s if it inherits this list.\n\tif (def.customDomains !== undefined && branch.isDefault === true) {\n\t\treturn def.customDomains.map(normalizeCustomDomain);\n\t}\n\treturn undefined;\n}\n\nfunction assertUniqueResolvedCustomDomains(\n\tfunctions: ResolvedFunctionConfig[],\n): void {\n\tconst byDomain = new Map<string, string>();\n\tfor (const fn of functions) {\n\t\tfor (const domain of fn.customDomains ?? []) {\n\t\t\tconst prior = byDomain.get(domain);\n\t\t\tif (prior !== undefined) {\n\t\t\t\tthrow new ConfigValidationError([\n\t\t\t\t\t`custom domain \"${domain}\" is used by both function \"${prior}\" and \"${fn.slug}\"`,\n\t\t\t\t]);\n\t\t\t}\n\t\t\tbyDomain.set(domain, fn.slug);\n\t\t}\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 {\n\tauthoredFunctionTuning,\n\tmergeAuthoredPreview,\n} from \"./authored-services.js\";\nimport { normalizeCustomDomain } from \"./custom-domain.js\";\nimport { 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\tExperimentalInput,\n\tFunctionDef,\n\tFunctionTriggerDef,\n\tFunctionTuning,\n\tPreviewInput,\n\tRealtimeConfig,\n\tRealtimeInput,\n\tResolvedBranchConfig,\n\tResolvedDataApiConfig,\n\tResolvedFunctionConfig,\n\tResolvedFunctionTrigger,\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 DEFAULT_FUNCTION_BUNDLER = \"esbuild\" 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\ntype FunctionsAutocomplete<Functions> =\n\tFunctions extends Record<string, unknown>\n\t\t? { [Slug in keyof Functions]: FunctionDef }\n\t\t: unknown;\n\ntype BucketsAutocomplete<Buckets> =\n\tBuckets extends Record<string, unknown>\n\t\t? { [Name in keyof Buckets]: 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 * preview: {\n * realtime: { allowedOrigins: [\"https://app.example.com\"] },\n * },\n * auth: true,\n * functions: {\n * hello: { name: \"Hello\", source: \"./functions/hello.ts\", dev: { port: 8787 } },\n * },\n * branch: (branch) => ({ protected: branch.name === \"main\" }),\n * });\n * ```\n *\n * The policy is split into a **static** existential set (`preview.realtime`, top-level `auth` /\n * `dataApi` / `aiGateway` / `functions` / `buckets` / `triggers`, plus the deprecated\n * aliases under `preview`) and a\n * **dynamic** per-branch `branch` closure. The static half determines which secrets exist —\n * so `NeonEnv<typeof config>` and `parseEnv` are exact — while the closure can only *tune*\n * a branch (lifecycle, compute, per-function 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\tconst Functions extends Record<string, FunctionDef> | undefined = undefined,\n\tconst Buckets extends Record<string, BucketDef> | undefined = undefined,\n\tconst AiGateway extends ServiceToggleInput | 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\taiGateway?: AiGateway & ServiceToggleInput;\n\tfunctions?: Functions &\n\t\tRecord<string, FunctionDef> &\n\t\tFunctionsAutocomplete<Functions>;\n\tbuckets?: Buckets &\n\t\tRecord<string, BucketDef> &\n\t\tBucketsAutocomplete<Buckets>;\n\ttriggers?: Record<string, FunctionTriggerDef>;\n\t// `& PreviewInput` restores top-level member hints (realtime/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, Functions>;\n\t// Experimental (unstable) features — currently just lifecycle hooks. Static — carried\n\t// through onto the returned Config and read by the runtime at `checkout` / `deploy` time.\n\t// Never evaluated here.\n\texperimental?: ExperimentalInput;\n}): Config<Auth, DataApi, Preview, Functions, Buckets, AiGateway> {\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, functions: { … }, branch: (branch) => ({ … }) })`.\",\n\t\t\t\"The static services 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<\n\t\tAuth,\n\t\tDataApi,\n\t\tPreview,\n\t\tFunctions,\n\t\tBuckets,\n\t\tAiGateway\n\t>;\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 + 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\tconst realtimeInput = config.preview?.realtime;\n\n\tconst resolved: ResolvedBranchConfig = {\n\t\trealtimePolicy:\n\t\t\trealtimeInput === undefined\n\t\t\t\t? \"omitted\"\n\t\t\t\t: isRealtimeEnabled(realtimeInput)\n\t\t\t\t\t? \"enabled\"\n\t\t\t\t\t: \"disabled\",\n\t\tauthEnabled: isServiceEnabled(config.auth),\n\t\tdataApiEnabled: isDataApiEnabled(config.dataApi),\n\t\tdataApiPolicy:\n\t\t\tconfig.dataApi === undefined\n\t\t\t\t? \"omitted\"\n\t\t\t\t: isDataApiEnabled(config.dataApi)\n\t\t\t\t\t? \"enabled\"\n\t\t\t\t\t: \"disabled\",\n\t};\n\tconst realtime = resolveRealtime(realtimeInput);\n\tif (realtime) resolved.realtime = realtime;\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(\n\t\tmergeAuthoredPreview(config),\n\t\ttuning,\n\t\tbranch,\n\t);\n\tif (preview) resolved.preview = preview;\n\tconst triggers = resolveTriggers(config.triggers);\n\tif (triggers.length > 0) resolved.triggers = triggers;\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 RealtimeInput} is enabled (present object or `true`). */\nfunction isRealtimeEnabled(input: RealtimeInput | undefined): boolean {\n\tif (input === undefined) return false;\n\tif (typeof input === \"boolean\") return input;\n\treturn true;\n}\n\n/** Copy the options from an object-form {@link RealtimeInput}. */\nfunction resolveRealtime(\n\tinput: RealtimeInput | undefined,\n): RealtimeConfig | undefined {\n\tif (typeof input !== \"object\") return undefined;\n\treturn {\n\t\t...(input.allowedOrigins !== undefined\n\t\t\t? { allowedOrigins: [...input.allowedOrigins] }\n\t\t\t: {}),\n\t};\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\tbranch: BranchTarget,\n): ResolvedPreviewConfig | undefined {\n\tif (!preview) return undefined;\n\tconst fnTuning = authoredFunctionTuning(tuning);\n\tconst functions: ResolvedFunctionConfig[] = Object.entries(\n\t\tpreview.functions ?? {},\n\t).map(([slug, def]) =>\n\t\tresolveFunctionConfig(slug, def, fnTuning[slug] ?? {}, branch),\n\t);\n\tassertUniqueResolvedCustomDomains(functions);\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\tbranch: BranchTarget,\n): ResolvedFunctionConfig {\n\tconst customDomains = resolveFunctionCustomDomains(def, tuning, branch);\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\tbundler: def.bundler ?? DEFAULT_FUNCTION_BUNDLER,\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\t...(customDomains !== undefined ? { customDomains } : {}),\n\t};\n}\n\nfunction resolveTriggers(\n\ttriggers: Record<string, FunctionTriggerDef> | undefined,\n): ResolvedFunctionTrigger[] {\n\tif (!triggers) return [];\n\treturn Object.entries(triggers).map(([name, trigger]) => {\n\t\tif (trigger.type === \"schedule\") {\n\t\t\treturn {\n\t\t\t\ttype: \"schedule\" as const,\n\t\t\t\tname,\n\t\t\t\tfunctionSlug: trigger.function,\n\t\t\t\tcron: trigger.cron,\n\t\t\t\tfunctionPath: trigger.functionPath ?? \"/\",\n\t\t\t\tenabled: trigger.enabled ?? true,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\ttype: \"storage_object_created\" as const,\n\t\t\tname,\n\t\t\tfunctionSlug: trigger.function,\n\t\t\tbucketName: trigger.bucket,\n\t\t\t...(trigger.prefix !== undefined ? { prefix: trigger.prefix } : {}),\n\t\t\tfunctionPath: trigger.functionPath ?? \"/\",\n\t\t\tenabled: trigger.enabled ?? true,\n\t\t};\n\t});\n}\n\nfunction resolveFunctionCustomDomains(\n\tdef: FunctionDef,\n\ttuning: FunctionTuning,\n\tbranch: BranchTarget,\n): string[] | undefined {\n\tif (tuning.customDomains !== undefined) {\n\t\treturn tuning.customDomains.map(normalizeCustomDomain);\n\t}\n\t// Hostnames are globally unique, so a child checkout 409s if it inherits this list.\n\tif (def.customDomains !== undefined && branch.isDefault === true) {\n\t\treturn def.customDomains.map(normalizeCustomDomain);\n\t}\n\treturn undefined;\n}\n\nfunction assertUniqueResolvedCustomDomains(\n\tfunctions: ResolvedFunctionConfig[],\n): void {\n\tconst byDomain = new Map<string, string>();\n\tfor (const fn of functions) {\n\t\tfor (const domain of fn.customDomains ?? []) {\n\t\t\tconst prior = byDomain.get(domain);\n\t\t\tif (prior !== undefined) {\n\t\t\t\tthrow new ConfigValidationError([\n\t\t\t\t\t`custom domain \"${domain}\" is used by both function \"${prior}\" and \"${fn.slug}\"`,\n\t\t\t\t]);\n\t\t\t}\n\t\t\tbyDomain.set(domain, fn.slug);\n\t\t}\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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"}
|
package/dist/lib/diff.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BucketAccessLevel, ComputeSettings, ConflictReport, DataApiSettings, ResolvedBranchConfig, ResolvedFunctionConfig, ResolvedFunctionTrigger } from "./types.js";
|
|
2
|
-
import { EnableDataApiInput, NeonBranchSnapshot, NeonBucketSnapshot, NeonCustomDomainSnapshot, NeonEndpointSnapshot, NeonFunctionSnapshot, NeonTriggerSnapshot } from "./neon-api.js";
|
|
2
|
+
import { ConfigureRealtimeInput, EnableDataApiInput, NeonBranchSnapshot, NeonBucketSnapshot, NeonCustomDomainSnapshot, NeonEndpointSnapshot, NeonFunctionSnapshot, NeonRealtimeSnapshot, NeonTriggerSnapshot } from "./neon-api.js";
|
|
3
3
|
|
|
4
4
|
//#region src/lib/diff.d.ts
|
|
5
5
|
|
|
@@ -8,6 +8,23 @@ import { EnableDataApiInput, NeonBranchSnapshot, NeonBucketSnapshot, NeonCustomD
|
|
|
8
8
|
* produces a list of these for `pushConfig` to execute (or report).
|
|
9
9
|
*/
|
|
10
10
|
type PlanStep = {
|
|
11
|
+
kind: "enable-realtime";
|
|
12
|
+
projectId: string;
|
|
13
|
+
branchId: string;
|
|
14
|
+
branchName: string;
|
|
15
|
+
input?: ConfigureRealtimeInput;
|
|
16
|
+
} | {
|
|
17
|
+
kind: "update-realtime";
|
|
18
|
+
projectId: string;
|
|
19
|
+
branchId: string;
|
|
20
|
+
branchName: string;
|
|
21
|
+
input: Required<ConfigureRealtimeInput>;
|
|
22
|
+
} | {
|
|
23
|
+
kind: "disable-realtime";
|
|
24
|
+
projectId: string;
|
|
25
|
+
branchId: string;
|
|
26
|
+
branchName: string;
|
|
27
|
+
} | {
|
|
11
28
|
kind: "update-branch-ttl";
|
|
12
29
|
projectId: string;
|
|
13
30
|
branchId: string;
|
|
@@ -131,6 +148,8 @@ interface RemoteState {
|
|
|
131
148
|
projectId: string;
|
|
132
149
|
branch: NeonBranchSnapshot;
|
|
133
150
|
endpoint?: NeonEndpointSnapshot;
|
|
151
|
+
/** Present when the policy manages Realtime. */
|
|
152
|
+
realtime?: NeonRealtimeSnapshot;
|
|
134
153
|
services: RemoteServiceState;
|
|
135
154
|
preview?: RemotePreviewState;
|
|
136
155
|
}
|
package/dist/lib/diff.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff.d.ts","names":["EnableDataApiInput","NeonBranchSnapshot","NeonBucketSnapshot","NeonCustomDomainSnapshot","NeonEndpointSnapshot","NeonFunctionSnapshot","NeonTriggerSnapshot","BucketAccessLevel","ComputeSettings","ConflictReport","DataApiSettings","ResolvedBranchConfig","ResolvedFunctionConfig","ResolvedFunctionTrigger","PlanStep","RemoteServiceState","RemotePreviewState","RemoteState","DiffOptions","DiffResult","diffConfig","BucketAccessLevel","ComputeSettings","ConflictReport","DataApiSettings","ResolvedBranchConfig","ResolvedFunctionConfig","ResolvedFunctionTrigger","EnableDataApiInput","NeonBranchSnapshot","NeonBucketSnapshot","NeonCustomDomainSnapshot","NeonEndpointSnapshot","NeonFunctionSnapshot","NeonTriggerSnapshot","PlanStep","kind","projectId","branchId","branchName","expiresAt","protected","endpointId","settings","databaseName","
|
|
1
|
+
{"version":3,"file":"diff.d.ts","names":["ConfigureRealtimeInput","EnableDataApiInput","NeonBranchSnapshot","NeonBucketSnapshot","NeonCustomDomainSnapshot","NeonEndpointSnapshot","NeonFunctionSnapshot","NeonRealtimeSnapshot","NeonTriggerSnapshot","BucketAccessLevel","ComputeSettings","ConflictReport","DataApiSettings","ResolvedBranchConfig","ResolvedFunctionConfig","ResolvedFunctionTrigger","PlanStep","Required","RemoteServiceState","RemotePreviewState","RemoteState","DiffOptions","DiffResult","diffConfig","BucketAccessLevel","ComputeSettings","ConflictReport","DataApiSettings","ResolvedBranchConfig","ResolvedFunctionConfig","ResolvedFunctionTrigger","ConfigureRealtimeInput","EnableDataApiInput","NeonBranchSnapshot","NeonBucketSnapshot","NeonCustomDomainSnapshot","NeonEndpointSnapshot","NeonFunctionSnapshot","NeonRealtimeSnapshot","NeonTriggerSnapshot","PlanStep","kind","projectId","branchId","branchName","input","Required","expiresAt","protected","endpointId","settings","databaseName","bucketName","accessLevel","fn","functionExists","functionSlug","trigger","triggerId","domain","previousSlug","RemoteServiceState","authEnabled","dataApiEnabled","dataApiSettings","RemotePreviewState","buckets","functions","triggers","customDomains","RemoteState","branch","endpoint","realtime","services","preview","DiffOptions","updateExisting","DiffResult","plan","conflicts","diffConfig","config","remote","options"],"sources":["../../src/lib/diff.ts"],"mappings":";;;;;;;AA0BA;AAAoB;AAMTA,KANCgB,QAAAA,GAMDhB;EAOQA,IAAAA,EAAAA,iBAAAA;EAATiB,SAAAA,EAAAA,MAAAA;EA2BGP,QAAAA,EAAAA,MAAAA;EAgBFT,UAAAA,EAAAA,MAAAA;EAQEW,KAAAA,CAAAA,EA1DFZ,sBA0DEY;AAeGH,CAAAA,GAAAA;EAcTK,IAAAA,EAAAA,iBAAAA;EAUKC,SAAAA,EAAAA,MAAAA;EASAA,QAAAA,EAAAA,MAAAA;EAAuB6B,UAAA,EAAA,MAAA;EAoBlB1B,KAAAA,EAvHPD,QAuHOC,CAvHElB,sBAgIAY,CAAAA;AAOnB,CAAA,GAAiBO;EAAkBsB,IAAA,EAAA,kBAAA;EACzBtC,SAAAA,EAAAA,MAAAA;EACEG,QAAAA,EAAAA,MAAAA;EACDE,UAAAA,EAAAA,MAAAA;AAEMJ,CAAAA,GAAAA;EAAwBqC,IAAA,EAAA,mBAAA;EAGxBrB,SAAAA,EAAAA,MAAW;EAAAuB,QAAA,EAAA,MAAA;EAEnBzC,UAAAA,EAAAA,MAAAA;EACGG,SAAAA,EAAAA,MAAAA,GAAAA,IAAAA;AAEAE,CAAAA,GAAAA;EACDW,IAAAA,EAAAA,yBAAAA;EACAC,SAAAA,EAAAA,MAAAA;EAAkBwB,QAAA,EAAA,MAAA;EAGZtB,UAAAA,EAAAA,MAAW;EAQXC,SAAAA,EAAAA,OAAU;AAAA,CAAA,GAAA;EACpBN,IAAAA,EAAAA,iBAAAA;EACKL,SAAAA,EAAAA,MAAAA;EAAciC,UAAA,EAAA,MAAA;EAMVrB,UAAAA,EAAAA,MAAU;EAAA2B,QAAA,EA9IbxC,eA8Ia;AACjBG,CAAAA,GAAAA;EACAO,IAAAA,EAAAA,aAAAA;EACCC,SAAAA,EAAAA,MAAAA;EACPC,QAAAA,EAAAA,MAAAA;EAAUsB,UAAA,EAAA,MAAA;;;;;;;;;UAlIF3C;;;;;;;YAQEW;;;;;;;;;;;;;eAeGH;;;;;;;;;;;;;MAcTK;;;;;;;;;WAUKC;;;;;;;;WASAA;;;;;;;;;;;;;;;;;UAoBKG,kBAAAA;;;;;;;;;oBASEN;;;;;;UAOFO,kBAAAA;WACPhB;aACEG;YACDE;;kBAEMJ;;UAGAgB,WAAAA;;UAERlB;aACGG;;aAEAE;YACDW;YACAC;;UAGME,WAAAA;;;;;;;UAQAC,UAAAA;QACVN;aACKL;;;;;iBAMIY,UAAAA,SACPV,8BACAO,sBACCC,cACPC"}
|
package/dist/lib/diff.js
CHANGED
|
@@ -12,6 +12,13 @@ function diffConfig(config, remote, options) {
|
|
|
12
12
|
plan,
|
|
13
13
|
conflicts
|
|
14
14
|
});
|
|
15
|
+
diffRealtime({
|
|
16
|
+
config,
|
|
17
|
+
remote,
|
|
18
|
+
options,
|
|
19
|
+
plan,
|
|
20
|
+
conflicts
|
|
21
|
+
});
|
|
15
22
|
diffServices({
|
|
16
23
|
config,
|
|
17
24
|
remote,
|
|
@@ -31,6 +38,66 @@ function diffConfig(config, remote, options) {
|
|
|
31
38
|
conflicts
|
|
32
39
|
};
|
|
33
40
|
}
|
|
41
|
+
function diffRealtime(args) {
|
|
42
|
+
const { config, remote, options, plan, conflicts } = args;
|
|
43
|
+
const policy = config.realtimePolicy ?? "omitted";
|
|
44
|
+
if (policy === "omitted") return;
|
|
45
|
+
const state = remote.realtime ?? {
|
|
46
|
+
enabled: false,
|
|
47
|
+
pending: false
|
|
48
|
+
};
|
|
49
|
+
if (policy === "disabled") {
|
|
50
|
+
if (!state.enabled) return;
|
|
51
|
+
if (options.updateExisting) plan.push({
|
|
52
|
+
kind: "disable-realtime",
|
|
53
|
+
projectId: remote.projectId,
|
|
54
|
+
branchId: remote.branch.id,
|
|
55
|
+
branchName: remote.branch.name
|
|
56
|
+
});
|
|
57
|
+
else conflicts.push({
|
|
58
|
+
kind: "branch",
|
|
59
|
+
identifier: remote.branch.name,
|
|
60
|
+
field: "preview.realtime",
|
|
61
|
+
current: true,
|
|
62
|
+
desired: false,
|
|
63
|
+
reason: "Existing Realtime would be disabled. Pass `updateExisting: true` (SDK) or `--update-existing` (CLI) to apply."
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const allowedOrigins = config.realtime?.allowedOrigins;
|
|
68
|
+
if (!state.enabled) {
|
|
69
|
+
plan.push({
|
|
70
|
+
kind: "enable-realtime",
|
|
71
|
+
projectId: remote.projectId,
|
|
72
|
+
branchId: remote.branch.id,
|
|
73
|
+
branchName: remote.branch.name,
|
|
74
|
+
...allowedOrigins !== void 0 ? { input: { allowedOrigins: [...allowedOrigins] } } : {}
|
|
75
|
+
});
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (allowedOrigins === void 0 || originsEqual(allowedOrigins, state.allowedOrigins)) return;
|
|
79
|
+
if (options.updateExisting) plan.push({
|
|
80
|
+
kind: "update-realtime",
|
|
81
|
+
projectId: remote.projectId,
|
|
82
|
+
branchId: remote.branch.id,
|
|
83
|
+
branchName: remote.branch.name,
|
|
84
|
+
input: { allowedOrigins: [...allowedOrigins] }
|
|
85
|
+
});
|
|
86
|
+
else conflicts.push({
|
|
87
|
+
kind: "branch",
|
|
88
|
+
identifier: remote.branch.name,
|
|
89
|
+
field: "preview.realtime.allowedOrigins",
|
|
90
|
+
current: state.allowedOrigins,
|
|
91
|
+
desired: allowedOrigins,
|
|
92
|
+
reason: "Existing Realtime has different allowed origins. Pass `updateExisting: true` (SDK) or `--update-existing` (CLI) to apply."
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function originsEqual(desired, current) {
|
|
96
|
+
if (current === void 0 || desired.length !== current.length) return false;
|
|
97
|
+
const left = [...desired].sort();
|
|
98
|
+
const right = [...current].sort();
|
|
99
|
+
return left.every((origin, index) => origin === right[index]);
|
|
100
|
+
}
|
|
34
101
|
/**
|
|
35
102
|
* Data API teardown requires explicit `dataApi: false` so omission remains non-destructive.
|
|
36
103
|
*
|