@neon/config-runtime 1.8.0 → 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.
@@ -1,5 +1,5 @@
1
1
  import { FunctionBundler } from "./function-bundle.js";
2
- import { PulledBranchConfig } from "./pull-config.js";
2
+ import { PullConfigOptions, PulledBranchConfig } from "./pull-config.js";
3
3
  import { PushConfigOptions } from "./push-config.js";
4
4
  import { Config, NeonApi, PushResult } from "@neon/config";
5
5
 
@@ -52,7 +52,7 @@ interface ApplyOptions extends ConfigOperationOptions {
52
52
  *
53
53
  * `projectId` and `branchId` are **required** (both in `options`).
54
54
  */
55
- declare function inspect(options: ConfigOperationOptions): Promise<PulledBranchConfig>;
55
+ declare function inspect(options: ConfigOperationOptions & Pick<PullConfigOptions, "realtime">): Promise<PulledBranchConfig>;
56
56
  /**
57
57
  * Compute what {@link apply} would do for the given branch without mutating anything
58
58
  * (dry-run plan). Returns the full {@link PushResult} with the planned changes in
@@ -1 +1 @@
1
- {"version":3,"file":"operations.d.ts","names":["Config","NeonApi","PushResult","FunctionBundler","PulledBranchConfig","PushConfigOptions","ConfigOperationOptions","ApplyOptions","inspect","Promise","plan","apply","CreateBranchOptions","CreateBranchResult","createBranch","FunctionBundler","PulledBranchConfig","PushConfigOptions","Config","NeonApi","PushResult","ConfigOperationOptions","projectId","branchId","apiKey","apiHost","api","ApplyOptions","updateExisting","allowProtectedBranch","confirm","beforeMutations","bundleFunction","inspect","options","Promise","plan","config","apply","CreateBranchOptions","branchName","CreateBranchResult","result","createBranch"],"sources":["../../src/lib/operations.ts"],"mappings":";;;;;;;;;AAsBA;AAsBA;AAA8B;AASnBK,UA/BMC,sBAAAA,CA+BND;EAEQA;AAEDF;AAboBG;AAAsB;EAsBtCE,SAAAA,EAAO,MAAA;EAAA;AACnBF;AACCF;AAARK;EAAOc,QAAA,EAAA,MAAA;EAkBYb;EAAIc,MAAA,CAAA,EAAA,MAAA;EACjBxB;EACCM,OAAAA,CAAAA,EAAAA,MAAAA;EACCJ;EAARO,GAAAA,CAAAA,EAnDIJ,iBAmDJI,CAAAA,KAAAA,CAAAA;AAAO;AAwBV;AAA2B;AAClBT;AACCO,UAvEOA,YAAAA,SAAqBD,sBAuE5BC,CAAAA;EACCL;AAARO;AAAO;AAuBV;EAAoCmB,cAAA,CAAA,EAAA,OAAA;EAQ7B3B;EAEWE,oBAAAA,CAAAA,EAAAA,OAAAA;EAAe;EAOhBU,OAAAA,CAAAA,EAvGNR,iBAuGwB,CAAA,SAI1BH,CAAAA;EA+BaY;EAAYiB,eAAA,CAAA,EAxIf1B,iBAwIe,CAAA,iBAAA,CAAA;EACzBL;EACCY,cAAAA,CAAAA,EAxIQT,eAwIRS;AACCC;AAARJ;AAAO;;;;;iBAhIYD,OAAAA,UACZF,yBACPG,QAAQL;;;;;;;;;iBAkBWM,IAAAA,SACbV,iBACCM,yBACPG,QAAQP;;;;;;;;;;;;iBAwBWS,KAAAA,SACbX,iBACCO,eACPE,QAAQP;;;;;UAuBMU,mBAAAA;;;;;;;;QAQVX;;mBAEWE;;;;;;UAODU,kBAAAA;;;;UAIRX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+BaY,YAAAA,SACbd,iBACCY,sBACPH,QAAQI"}
1
+ {"version":3,"file":"operations.d.ts","names":["Config","NeonApi","PushResult","FunctionBundler","PullConfigOptions","PulledBranchConfig","PushConfigOptions","ConfigOperationOptions","ApplyOptions","inspect","Pick","Promise","plan","apply","CreateBranchOptions","CreateBranchResult","createBranch","FunctionBundler","PullConfigOptions","PulledBranchConfig","PushConfigOptions","Config","NeonApi","PushResult","ConfigOperationOptions","projectId","branchId","apiKey","apiHost","api","ApplyOptions","updateExisting","allowProtectedBranch","confirm","beforeMutations","bundleFunction","inspect","options","Pick","Promise","plan","config","apply","CreateBranchOptions","branchName","CreateBranchResult","result","createBranch"],"sources":["../../src/lib/operations.ts"],"mappings":";;;;;;;;;AA0BA;AAsBA;AAA8B;AASnBM,UA/BMC,sBAAAA,CA+BND;EAEQA;AAEDH;AAboBI;AAAsB;EAsBtCE,SAAAA,EAAO,MAAA;EAAA;AACnBF;AAA8BH;AAALM;EACxBL,QAAAA,EAAAA,MAAAA;EAARM;EAAOgB,MAAA,CAAA,EAAA,MAAA;EAmBYf;EAAIgB,OAAA,CAAA,EAAA,MAAA;EACjB5B;EACCO,GAAAA,CAAAA,EAnDHD,iBAmDGC,CAAAA,KAAAA,CAAAA;AACCL;AAARS;AAAO;AAwBV;AAA2B,UAtEVH,YAAAA,SAAqBD,sBAsEX,CAAA;EAClBP;AACCQ;AACCN;AAARS;EAAOoB,cAAA,CAAA,EAAA,OAAA;EAuBOjB;EAAmBkB,oBAAA,CAAA,EAAA,OAAA;EAQ7B/B;EAEWE,OAAAA,CAAAA,EAjGPG,iBAiGOH,CAAAA,SAAAA,CAAAA;EAAe;EAOhBY,eAAAA,CAAAA,EAtGET,iBA0GVJ,CAAAA,iBAAU,CAAA;EA+BGc;EAAYmB,cAAA,CAAA,EAvIhBhC,eAuIgB;AACzBH;AACCc;AACCC;AAARJ;AAAO;;;iBAjIYF,OAAAA,UACZF,yBAAyBG,KAAKN,iCACrCO,QAAQN;;;;;;;;;iBAmBWO,IAAAA,SACbZ,iBACCO,yBACPI,QAAQT;;;;;;;;;;;;iBAwBWW,KAAAA,SACbb,iBACCQ,eACPG,QAAQT;;;;;UAuBMY,mBAAAA;;;;;;;;QAQVb;;mBAEWE;;;;;;UAODY,kBAAAA;;;;UAIRb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+Bac,YAAAA,SACbhB,iBACCc,sBACPH,QAAQI"}
@@ -14,7 +14,8 @@ async function inspect(options) {
14
14
  branchId: options.branchId,
15
15
  ...options.api ? { api: options.api } : {},
16
16
  ...options.apiKey ? { apiKey: options.apiKey } : {},
17
- ...options.apiHost ? { apiHost: options.apiHost } : {}
17
+ ...options.apiHost ? { apiHost: options.apiHost } : {},
18
+ ...options.realtime ? { realtime: true } : {}
18
19
  });
19
20
  }
20
21
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"operations.js","names":[],"sources":["../../src/lib/operations.ts"],"sourcesContent":["import {\n\ttype AppliedChange,\n\ttype ComputeSettings,\n\ttype Config,\n\tcreateNeonApiFromOptions,\n\tErrorCode,\n\ttype NeonApi,\n\ttype NeonBranchSnapshot,\n\tPartialBranchCreateError,\n\tPlatformError,\n\ttype PushResult,\n\tresolveConfig,\n} from \"@neon/config\";\nimport type { FunctionBundler } from \"./function-bundle.js\";\nimport { type PulledBranchConfig, pullConfig } from \"./pull-config.js\";\nimport { type PushConfigOptions, pushConfig } from \"./push-config.js\";\n\n/**\n * Where to run the operation and how to authenticate. Filesystem- and env-agnostic: the\n * `projectId` and `branchId` are always passed explicitly by the caller (e.g. neonctl\n * resolves them from `.neon` / `NEON_*` and forwards them here).\n */\nexport interface ConfigOperationOptions {\n\t/**\n\t * Neon project id. **Required** — the management API addresses branches through their\n\t * project, so operations cannot run without it.\n\t */\n\tprojectId: string;\n\t/**\n\t * Neon branch id (`br-…`). **Required.** Must already exist on the project; resolve\n\t * branch names to ids before calling.\n\t */\n\tbranchId: string;\n\t/** Neon API key. Falls back to `NEON_API_KEY` / neonctl credentials. */\n\tapiKey?: string;\n\t/** Neon API base URL. Falls back to `NEON_API_HOST`, then production. */\n\tapiHost?: string;\n\t/** Inject a custom NeonApi adapter (primarily for tests). */\n\tapi?: PushConfigOptions[\"api\"];\n}\n\n/**\n * Options accepted by {@link apply} on top of {@link ConfigOperationOptions}.\n */\nexport interface ApplyOptions extends ConfigOperationOptions {\n\t/**\n\t * Auto-confirm overriding existing remote settings (TTL, `protected`, compute\n\t * settings) on the selected branch. Without it, drift is reported as a conflict.\n\t */\n\tupdateExisting?: boolean;\n\t/** Auto-confirm applying to a branch marked `protected` on Neon. */\n\tallowProtectedBranch?: boolean;\n\t/** Asked before a protected-branch push or an override. See {@link PushConfigOptions.confirm}. */\n\tconfirm?: PushConfigOptions[\"confirm\"];\n\t/** Runs after confirmation, before any change. See {@link PushConfigOptions.beforeMutations}. */\n\tbeforeMutations?: PushConfigOptions[\"beforeMutations\"];\n\t/** Inject to deploy without this package loading esbuild. */\n\tbundleFunction?: FunctionBundler;\n}\n\n/**\n * Read a branch's live Neon state as a plain object (project + branch metadata and the\n * reverse-engineered `BranchConfig`). Network read only — never mutates.\n *\n * `projectId` and `branchId` are **required** (both in `options`).\n */\nexport async function inspect(\n\toptions: ConfigOperationOptions,\n): Promise<PulledBranchConfig> {\n\treturn pullConfig({\n\t\tprojectId: options.projectId,\n\t\tbranchId: options.branchId,\n\t\t...(options.api ? { api: options.api } : {}),\n\t\t...(options.apiKey ? { apiKey: options.apiKey } : {}),\n\t\t...(options.apiHost ? { apiHost: options.apiHost } : {}),\n\t});\n}\n\n/**\n * Compute what {@link apply} would do for the given branch without mutating anything\n * (dry-run plan). Returns the full {@link PushResult} with the planned changes in\n * `applied` and any blocking drift in `conflicts` — the Neon equivalent of\n * `terraform plan`.\n *\n * `projectId` and `branchId` are **required** (both in `options`).\n */\nexport async function plan(\n\tconfig: Config,\n\toptions: ConfigOperationOptions,\n): Promise<PushResult> {\n\treturn pushConfig(config, {\n\t\tprojectId: options.projectId,\n\t\tbranchId: options.branchId,\n\t\tdryRun: true,\n\t\t// Surface the full would-apply list as plan steps without mutating anything.\n\t\tupdateExisting: true,\n\t\t...(options.api ? { api: options.api } : {}),\n\t\t...(options.apiKey ? { apiKey: options.apiKey } : {}),\n\t\t...(options.apiHost ? { apiHost: options.apiHost } : {}),\n\t});\n}\n\n/**\n * Apply a `neon.ts` policy to the given Neon branch and return the {@link PushResult}\n * describing what changed — the Neon equivalent of `terraform apply`.\n *\n * `projectId` and `branchId` are **required** (both in `options`). Pass `updateExisting`\n * to auto-confirm overriding existing remote settings and `allowProtectedBranch` to\n * auto-confirm applying to a protected branch; otherwise drift is reported as a\n * `PushConflictError`.\n *\n * Never creates projects or branches — both must already exist.\n */\nexport async function apply(\n\tconfig: Config,\n\toptions: ApplyOptions,\n): Promise<PushResult> {\n\treturn pushConfig(config, {\n\t\tprojectId: options.projectId,\n\t\tbranchId: options.branchId,\n\t\t...(options.api ? { api: options.api } : {}),\n\t\t...(options.apiKey ? { apiKey: options.apiKey } : {}),\n\t\t...(options.apiHost ? { apiHost: options.apiHost } : {}),\n\t\t...(options.updateExisting ? { updateExisting: true } : {}),\n\t\t...(options.allowProtectedBranch ? { allowProtectedBranch: true } : {}),\n\t\t...(options.confirm ? { confirm: options.confirm } : {}),\n\t\t...(options.beforeMutations\n\t\t\t? { beforeMutations: options.beforeMutations }\n\t\t\t: {}),\n\t\t...(options.bundleFunction\n\t\t\t? { bundleFunction: options.bundleFunction }\n\t\t\t: {}),\n\t});\n}\n\n/**\n * Options accepted by {@link createBranch}. Unlike {@link ConfigOperationOptions} this takes a\n * branch **name** (the branch does not exist yet) rather than an id.\n */\nexport interface CreateBranchOptions {\n\t/** Neon project id to create the branch in. **Required.** */\n\tprojectId: string;\n\t/** Name of the branch to create. **Required.** Must not already exist on the project. */\n\tbranchName: string;\n\t/** Neon API key. Falls back to `NEON_API_KEY` / neonctl credentials. Ignored when `api` is set. */\n\tapiKey?: string;\n\t/** Inject a custom NeonApi adapter (primarily for tests). */\n\tapi?: NeonApi;\n\t/** Inject to deploy without this package loading esbuild. */\n\tbundleFunction?: FunctionBundler;\n}\n\n/**\n * Result of {@link createBranch}: the created branch's id/name plus the {@link PushResult}\n * describing the policy that was applied to it.\n */\nexport interface CreateBranchResult {\n\tbranchId: string;\n\tbranchName: string;\n\t/** What applying the policy to the freshly created branch changed. */\n\tresult: PushResult;\n}\n\n/**\n * Create a Neon branch **from a `neon.ts` policy** and bring it up with its declared\n * settings/infra in one step — the operation `neonctl checkout <new-name>` needs.\n *\n * The flow is the one a creation actually wants:\n * 1. Evaluate the policy for the new branch with `exists: false` (so creation-time tuning —\n * `parent`, `ttl`, compute settings, `protected` — resolves instead of the\n * \"existing branch, leave as-is\" path most policies guard with `if (branch.exists)`).\n * 2. Create the branch **with** that tuning: `parent`, `expires_at`, `protected`, and the\n * compute settings all ride along on the single create call, which Neon validates as a\n * whole. A setting it rejects therefore fails the creation outright, leaving nothing\n * behind, rather than producing a branch that doesn't match the policy.\n * 3. {@link pushConfig} the rest onto it with `branchExists: false` — the services (Neon\n * Auth, Data API, buckets, functions), which have no create-time equivalent because they\n * are provisioned against an existing branch id.\n *\n * This is why `apply` alone couldn't do it: `apply` operates on an *existing* branch\n * (`exists: true`), so a policy keyed on `!branch.exists` never returns the creation tuning.\n *\n * `result.applied` covers both steps — the settings the create call carried are reported\n * exactly like the ones a push applies (see {@link settingsAppliedAtCreate}), so folding them\n * into the creation doesn't make them vanish from the summary.\n *\n * Throws {@link PlatformError} (`Conflict`) if a branch with `branchName` already exists, or\n * (`BranchNotFound`) if the policy names a `parent` that isn't on the project — both before\n * anything is created, as is a setting Neon rejects in step 2. Only step 3 can fail with a\n * branch already created; that throws {@link PartialBranchCreateError} carrying its id/name.\n */\nexport async function createBranch(\n\tconfig: Config,\n\toptions: CreateBranchOptions,\n): Promise<CreateBranchResult> {\n\tconst api =\n\t\toptions.api ??\n\t\tcreateNeonApiFromOptions(\n\t\t\t\"createBranch\",\n\t\t\toptions.apiKey ? { apiKey: options.apiKey } : {},\n\t\t);\n\tconst { projectId, branchName } = options;\n\n\tconst branches = await api.listBranches(projectId);\n\tif (branches.some((b) => b.name === branchName)) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.Conflict,\n\t\t\t`createBranch: a branch named \"${branchName}\" already exists on project ${projectId}. Pick a different name or check it out instead of creating it.`,\n\t\t\t{ details: { projectId, branchName } },\n\t\t);\n\t}\n\n\t// Evaluate the policy as a creation so `parent` (only settable at create time) resolves.\n\tconst resolved = resolveConfig(config, {\n\t\tname: branchName,\n\t\texists: false,\n\t});\n\tconst parentId = resolveParentBranchId(\n\t\tresolved.parent,\n\t\tbranches,\n\t\tbranchName,\n\t);\n\n\t// Everything the policy can express *in the create call itself* goes into it. Neon\n\t// validates the whole request, so a value it rejects (a plan-gated suspend timeout, an\n\t// out-of-range autoscaling limit) fails with **no branch created** instead of leaving one\n\t// behind that silently diverges from the policy. Only the services below genuinely need an\n\t// existing branch id, which is what keeps them a second step.\n\tconst expiresAt =\n\t\tresolved.ttlSeconds !== undefined\n\t\t\t? new Date(Date.now() + resolved.ttlSeconds * 1000).toISOString()\n\t\t\t: undefined;\n\tconst computeSettings = resolved.postgres?.computeSettings;\n\n\tconst { branch } = await api.createBranch(projectId, {\n\t\tname: branchName,\n\t\t...(parentId ? { parentId } : {}),\n\t\t...(expiresAt ? { expiresAt } : {}),\n\t\t...(resolved.protected !== undefined\n\t\t\t? { protected: resolved.protected }\n\t\t\t: {}),\n\t\t...(computeSettings ? { computeSettings } : {}),\n\t});\n\n\tconst appliedAtCreate = settingsAppliedAtCreate({\n\t\tbranchName: branch.name,\n\t\t...(resolved.parent !== undefined\n\t\t\t? { parentName: resolved.parent }\n\t\t\t: {}),\n\t\t...(expiresAt !== undefined ? { expiresAt } : {}),\n\t\t...(resolved.protected !== undefined\n\t\t\t? { isProtected: resolved.protected }\n\t\t\t: {}),\n\t\t...(computeSettings ? { computeSettings } : {}),\n\t});\n\n\t// Reconcile what the create call could not express as a new branch (`branchExists: false`):\n\t// the services/functions the policy declares. The settings above are already in place, so\n\t// push sees them satisfied and applies nothing for them.\n\t// `updateExisting`/`allowProtectedBranch` are safe here — there is no pre-existing state a\n\t// user would be surprised to see overridden.\n\t//\n\t// The branch is already created at this point, so a failure here (a service that can't be\n\t// provisioned, a function that fails to deploy, a transient API error) cannot be undone by\n\t// throwing: the branch would linger without its declared services, invisible to the caller.\n\t// Re-throw as PartialBranchCreateError so the id/name survive and the caller can keep the\n\t// branch usable while reporting that it diverges from the policy.\n\tlet result: PushResult;\n\ttry {\n\t\tresult = await pushConfig(config, {\n\t\t\tprojectId,\n\t\t\tbranchId: branch.id,\n\t\t\tapi,\n\t\t\tbranchExists: false,\n\t\t\tupdateExisting: true,\n\t\t\tallowProtectedBranch: true,\n\t\t\t...(options.bundleFunction\n\t\t\t\t? { bundleFunction: options.bundleFunction }\n\t\t\t\t: {}),\n\t\t});\n\t} catch (cause) {\n\t\tthrow new PartialBranchCreateError(branch.id, branch.name, cause);\n\t}\n\n\treturn {\n\t\tbranchId: branch.id,\n\t\tbranchName: branch.name,\n\t\tresult: {\n\t\t\t...result,\n\t\t\tapplied: mergeCreateSettings(appliedAtCreate, result.applied),\n\t\t},\n\t};\n}\n\n/**\n * Describe the policy settings the create call itself carried as {@link AppliedChange}s, keyed\n * by field.\n *\n * Applying a setting *at creation* rather than in a follow-up call must not make it disappear\n * from the report, so these are shaped exactly like the changes `pushConfig` returns for the\n * same fields — same `kind`/`identifier`/`details`, so every renderer already knows how to\n * print them and no caller needs to special-case a creation.\n */\nconst settingsAppliedAtCreate = (args: {\n\tbranchName: string;\n\t/** The parent the *policy* named, omitted when the branch fell back to the project default. */\n\tparentName?: string;\n\texpiresAt?: string;\n\tisProtected?: boolean;\n\tcomputeSettings?: ComputeSettings;\n}): Map<string, AppliedChange> => {\n\tconst changes = new Map<string, AppliedChange>();\n\tconst add = (field: string, details: Record<string, unknown>): void => {\n\t\tchanges.set(field, {\n\t\t\tkind: \"branch\",\n\t\t\taction: \"create\",\n\t\t\tidentifier: args.branchName,\n\t\t\tdetails: { field, ...details },\n\t\t});\n\t};\n\tif (args.parentName !== undefined) {\n\t\tadd(\"parent\", { parent: args.parentName });\n\t}\n\tif (args.expiresAt !== undefined) add(\"ttl\", { expiresAt: args.expiresAt });\n\tif (args.isProtected !== undefined) {\n\t\tadd(\"protected\", { protected: args.isProtected });\n\t}\n\tif (args.computeSettings) {\n\t\tadd(\"computeSettings\", { settings: args.computeSettings });\n\t}\n\treturn changes;\n};\n\n/**\n * Fold the create-time settings into what the push applied, reporting each field once.\n *\n * A field the create call already satisfied is a noop for the push, so the two normally don't\n * overlap. They do when the create didn't take (an API that ignores a create-time field, or\n * drift in the moments between the two calls) and the push applied it for real — the push\n * change is the one that describes what actually happened, so it wins.\n */\nconst mergeCreateSettings = (\n\tatCreate: Map<string, AppliedChange>,\n\tpushed: AppliedChange[],\n): AppliedChange[] => {\n\tconst pushedFields = new Set(\n\t\tpushed\n\t\t\t.filter((c) => c.kind === \"branch\" && c.action !== \"noop\")\n\t\t\t.map((c) => c.details?.field)\n\t\t\t.filter((field): field is string => typeof field === \"string\"),\n\t);\n\tconst fromCreate = [...atCreate]\n\t\t.filter(([field]) => !pushedFields.has(field))\n\t\t.map(([, change]) => change);\n\treturn [...fromCreate, ...pushed];\n};\n\n/**\n * Resolve the parent branch id for a new branch. A policy-declared `parent` (a branch name) is\n * looked up by name; an unknown name is a hard error. With no `parent`, fall back to the\n * project's default branch, or `undefined` (let the API pick the project default) when none is\n * marked default.\n */\nfunction resolveParentBranchId(\n\tparentName: string | undefined,\n\tbranches: NeonBranchSnapshot[],\n\tbranchName: string,\n): string | undefined {\n\tif (parentName !== undefined) {\n\t\tconst match = branches.find((b) => b.name === parentName);\n\t\tif (!match) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.BranchNotFound,\n\t\t\t\t`createBranch: the policy for \"${branchName}\" sets parent \"${parentName}\", but no branch with that name exists. Existing branches: ${\n\t\t\t\t\tbranches.map((b) => b.name).join(\", \") || \"(none)\"\n\t\t\t\t}.`,\n\t\t\t\t{\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tbranchName,\n\t\t\t\t\t\tparent: parentName,\n\t\t\t\t\t\tavailable: branches.map((b) => b.name),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\treturn match.id;\n\t}\n\treturn branches.find((b) => b.isDefault)?.id;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"operations.js","names":[],"sources":["../../src/lib/operations.ts"],"sourcesContent":["import {\n\ttype AppliedChange,\n\ttype ComputeSettings,\n\ttype Config,\n\tcreateNeonApiFromOptions,\n\tErrorCode,\n\ttype NeonApi,\n\ttype NeonBranchSnapshot,\n\tPartialBranchCreateError,\n\tPlatformError,\n\ttype PushResult,\n\tresolveConfig,\n} from \"@neon/config\";\nimport type { FunctionBundler } from \"./function-bundle.js\";\nimport {\n\ttype PullConfigOptions,\n\ttype PulledBranchConfig,\n\tpullConfig,\n} from \"./pull-config.js\";\nimport { type PushConfigOptions, pushConfig } from \"./push-config.js\";\n\n/**\n * Where to run the operation and how to authenticate. Filesystem- and env-agnostic: the\n * `projectId` and `branchId` are always passed explicitly by the caller (e.g. neonctl\n * resolves them from `.neon` / `NEON_*` and forwards them here).\n */\nexport interface ConfigOperationOptions {\n\t/**\n\t * Neon project id. **Required** — the management API addresses branches through their\n\t * project, so operations cannot run without it.\n\t */\n\tprojectId: string;\n\t/**\n\t * Neon branch id (`br-…`). **Required.** Must already exist on the project; resolve\n\t * branch names to ids before calling.\n\t */\n\tbranchId: string;\n\t/** Neon API key. Falls back to `NEON_API_KEY` / neonctl credentials. */\n\tapiKey?: string;\n\t/** Neon API base URL. Falls back to `NEON_API_HOST`, then production. */\n\tapiHost?: string;\n\t/** Inject a custom NeonApi adapter (primarily for tests). */\n\tapi?: PushConfigOptions[\"api\"];\n}\n\n/**\n * Options accepted by {@link apply} on top of {@link ConfigOperationOptions}.\n */\nexport interface ApplyOptions extends ConfigOperationOptions {\n\t/**\n\t * Auto-confirm overriding existing remote settings (TTL, `protected`, compute\n\t * settings) on the selected branch. Without it, drift is reported as a conflict.\n\t */\n\tupdateExisting?: boolean;\n\t/** Auto-confirm applying to a branch marked `protected` on Neon. */\n\tallowProtectedBranch?: boolean;\n\t/** Asked before a protected-branch push or an override. See {@link PushConfigOptions.confirm}. */\n\tconfirm?: PushConfigOptions[\"confirm\"];\n\t/** Runs after confirmation, before any change. See {@link PushConfigOptions.beforeMutations}. */\n\tbeforeMutations?: PushConfigOptions[\"beforeMutations\"];\n\t/** Inject to deploy without this package loading esbuild. */\n\tbundleFunction?: FunctionBundler;\n}\n\n/**\n * Read a branch's live Neon state as a plain object (project + branch metadata and the\n * reverse-engineered `BranchConfig`). Network read only — never mutates.\n *\n * `projectId` and `branchId` are **required** (both in `options`).\n */\nexport async function inspect(\n\toptions: ConfigOperationOptions & Pick<PullConfigOptions, \"realtime\">,\n): Promise<PulledBranchConfig> {\n\treturn pullConfig({\n\t\tprojectId: options.projectId,\n\t\tbranchId: options.branchId,\n\t\t...(options.api ? { api: options.api } : {}),\n\t\t...(options.apiKey ? { apiKey: options.apiKey } : {}),\n\t\t...(options.apiHost ? { apiHost: options.apiHost } : {}),\n\t\t...(options.realtime ? { realtime: true } : {}),\n\t});\n}\n\n/**\n * Compute what {@link apply} would do for the given branch without mutating anything\n * (dry-run plan). Returns the full {@link PushResult} with the planned changes in\n * `applied` and any blocking drift in `conflicts` — the Neon equivalent of\n * `terraform plan`.\n *\n * `projectId` and `branchId` are **required** (both in `options`).\n */\nexport async function plan(\n\tconfig: Config,\n\toptions: ConfigOperationOptions,\n): Promise<PushResult> {\n\treturn pushConfig(config, {\n\t\tprojectId: options.projectId,\n\t\tbranchId: options.branchId,\n\t\tdryRun: true,\n\t\t// Surface the full would-apply list as plan steps without mutating anything.\n\t\tupdateExisting: true,\n\t\t...(options.api ? { api: options.api } : {}),\n\t\t...(options.apiKey ? { apiKey: options.apiKey } : {}),\n\t\t...(options.apiHost ? { apiHost: options.apiHost } : {}),\n\t});\n}\n\n/**\n * Apply a `neon.ts` policy to the given Neon branch and return the {@link PushResult}\n * describing what changed — the Neon equivalent of `terraform apply`.\n *\n * `projectId` and `branchId` are **required** (both in `options`). Pass `updateExisting`\n * to auto-confirm overriding existing remote settings and `allowProtectedBranch` to\n * auto-confirm applying to a protected branch; otherwise drift is reported as a\n * `PushConflictError`.\n *\n * Never creates projects or branches — both must already exist.\n */\nexport async function apply(\n\tconfig: Config,\n\toptions: ApplyOptions,\n): Promise<PushResult> {\n\treturn pushConfig(config, {\n\t\tprojectId: options.projectId,\n\t\tbranchId: options.branchId,\n\t\t...(options.api ? { api: options.api } : {}),\n\t\t...(options.apiKey ? { apiKey: options.apiKey } : {}),\n\t\t...(options.apiHost ? { apiHost: options.apiHost } : {}),\n\t\t...(options.updateExisting ? { updateExisting: true } : {}),\n\t\t...(options.allowProtectedBranch ? { allowProtectedBranch: true } : {}),\n\t\t...(options.confirm ? { confirm: options.confirm } : {}),\n\t\t...(options.beforeMutations\n\t\t\t? { beforeMutations: options.beforeMutations }\n\t\t\t: {}),\n\t\t...(options.bundleFunction\n\t\t\t? { bundleFunction: options.bundleFunction }\n\t\t\t: {}),\n\t});\n}\n\n/**\n * Options accepted by {@link createBranch}. Unlike {@link ConfigOperationOptions} this takes a\n * branch **name** (the branch does not exist yet) rather than an id.\n */\nexport interface CreateBranchOptions {\n\t/** Neon project id to create the branch in. **Required.** */\n\tprojectId: string;\n\t/** Name of the branch to create. **Required.** Must not already exist on the project. */\n\tbranchName: string;\n\t/** Neon API key. Falls back to `NEON_API_KEY` / neonctl credentials. Ignored when `api` is set. */\n\tapiKey?: string;\n\t/** Inject a custom NeonApi adapter (primarily for tests). */\n\tapi?: NeonApi;\n\t/** Inject to deploy without this package loading esbuild. */\n\tbundleFunction?: FunctionBundler;\n}\n\n/**\n * Result of {@link createBranch}: the created branch's id/name plus the {@link PushResult}\n * describing the policy that was applied to it.\n */\nexport interface CreateBranchResult {\n\tbranchId: string;\n\tbranchName: string;\n\t/** What applying the policy to the freshly created branch changed. */\n\tresult: PushResult;\n}\n\n/**\n * Create a Neon branch **from a `neon.ts` policy** and bring it up with its declared\n * settings/infra in one step — the operation `neonctl checkout <new-name>` needs.\n *\n * The flow is the one a creation actually wants:\n * 1. Evaluate the policy for the new branch with `exists: false` (so creation-time tuning —\n * `parent`, `ttl`, compute settings, `protected` — resolves instead of the\n * \"existing branch, leave as-is\" path most policies guard with `if (branch.exists)`).\n * 2. Create the branch **with** that tuning: `parent`, `expires_at`, `protected`, and the\n * compute settings all ride along on the single create call, which Neon validates as a\n * whole. A setting it rejects therefore fails the creation outright, leaving nothing\n * behind, rather than producing a branch that doesn't match the policy.\n * 3. {@link pushConfig} the rest onto it with `branchExists: false` — the services (Neon\n * Auth, Data API, buckets, functions), which have no create-time equivalent because they\n * are provisioned against an existing branch id.\n *\n * This is why `apply` alone couldn't do it: `apply` operates on an *existing* branch\n * (`exists: true`), so a policy keyed on `!branch.exists` never returns the creation tuning.\n *\n * `result.applied` covers both steps — the settings the create call carried are reported\n * exactly like the ones a push applies (see {@link settingsAppliedAtCreate}), so folding them\n * into the creation doesn't make them vanish from the summary.\n *\n * Throws {@link PlatformError} (`Conflict`) if a branch with `branchName` already exists, or\n * (`BranchNotFound`) if the policy names a `parent` that isn't on the project — both before\n * anything is created, as is a setting Neon rejects in step 2. Only step 3 can fail with a\n * branch already created; that throws {@link PartialBranchCreateError} carrying its id/name.\n */\nexport async function createBranch(\n\tconfig: Config,\n\toptions: CreateBranchOptions,\n): Promise<CreateBranchResult> {\n\tconst api =\n\t\toptions.api ??\n\t\tcreateNeonApiFromOptions(\n\t\t\t\"createBranch\",\n\t\t\toptions.apiKey ? { apiKey: options.apiKey } : {},\n\t\t);\n\tconst { projectId, branchName } = options;\n\n\tconst branches = await api.listBranches(projectId);\n\tif (branches.some((b) => b.name === branchName)) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.Conflict,\n\t\t\t`createBranch: a branch named \"${branchName}\" already exists on project ${projectId}. Pick a different name or check it out instead of creating it.`,\n\t\t\t{ details: { projectId, branchName } },\n\t\t);\n\t}\n\n\t// Evaluate the policy as a creation so `parent` (only settable at create time) resolves.\n\tconst resolved = resolveConfig(config, {\n\t\tname: branchName,\n\t\texists: false,\n\t});\n\tconst parentId = resolveParentBranchId(\n\t\tresolved.parent,\n\t\tbranches,\n\t\tbranchName,\n\t);\n\n\t// Everything the policy can express *in the create call itself* goes into it. Neon\n\t// validates the whole request, so a value it rejects (a plan-gated suspend timeout, an\n\t// out-of-range autoscaling limit) fails with **no branch created** instead of leaving one\n\t// behind that silently diverges from the policy. Only the services below genuinely need an\n\t// existing branch id, which is what keeps them a second step.\n\tconst expiresAt =\n\t\tresolved.ttlSeconds !== undefined\n\t\t\t? new Date(Date.now() + resolved.ttlSeconds * 1000).toISOString()\n\t\t\t: undefined;\n\tconst computeSettings = resolved.postgres?.computeSettings;\n\n\tconst { branch } = await api.createBranch(projectId, {\n\t\tname: branchName,\n\t\t...(parentId ? { parentId } : {}),\n\t\t...(expiresAt ? { expiresAt } : {}),\n\t\t...(resolved.protected !== undefined\n\t\t\t? { protected: resolved.protected }\n\t\t\t: {}),\n\t\t...(computeSettings ? { computeSettings } : {}),\n\t});\n\n\tconst appliedAtCreate = settingsAppliedAtCreate({\n\t\tbranchName: branch.name,\n\t\t...(resolved.parent !== undefined\n\t\t\t? { parentName: resolved.parent }\n\t\t\t: {}),\n\t\t...(expiresAt !== undefined ? { expiresAt } : {}),\n\t\t...(resolved.protected !== undefined\n\t\t\t? { isProtected: resolved.protected }\n\t\t\t: {}),\n\t\t...(computeSettings ? { computeSettings } : {}),\n\t});\n\n\t// Reconcile what the create call could not express as a new branch (`branchExists: false`):\n\t// the services/functions the policy declares. The settings above are already in place, so\n\t// push sees them satisfied and applies nothing for them.\n\t// `updateExisting`/`allowProtectedBranch` are safe here — there is no pre-existing state a\n\t// user would be surprised to see overridden.\n\t//\n\t// The branch is already created at this point, so a failure here (a service that can't be\n\t// provisioned, a function that fails to deploy, a transient API error) cannot be undone by\n\t// throwing: the branch would linger without its declared services, invisible to the caller.\n\t// Re-throw as PartialBranchCreateError so the id/name survive and the caller can keep the\n\t// branch usable while reporting that it diverges from the policy.\n\tlet result: PushResult;\n\ttry {\n\t\tresult = await pushConfig(config, {\n\t\t\tprojectId,\n\t\t\tbranchId: branch.id,\n\t\t\tapi,\n\t\t\tbranchExists: false,\n\t\t\tupdateExisting: true,\n\t\t\tallowProtectedBranch: true,\n\t\t\t...(options.bundleFunction\n\t\t\t\t? { bundleFunction: options.bundleFunction }\n\t\t\t\t: {}),\n\t\t});\n\t} catch (cause) {\n\t\tthrow new PartialBranchCreateError(branch.id, branch.name, cause);\n\t}\n\n\treturn {\n\t\tbranchId: branch.id,\n\t\tbranchName: branch.name,\n\t\tresult: {\n\t\t\t...result,\n\t\t\tapplied: mergeCreateSettings(appliedAtCreate, result.applied),\n\t\t},\n\t};\n}\n\n/**\n * Describe the policy settings the create call itself carried as {@link AppliedChange}s, keyed\n * by field.\n *\n * Applying a setting *at creation* rather than in a follow-up call must not make it disappear\n * from the report, so these are shaped exactly like the changes `pushConfig` returns for the\n * same fields — same `kind`/`identifier`/`details`, so every renderer already knows how to\n * print them and no caller needs to special-case a creation.\n */\nconst settingsAppliedAtCreate = (args: {\n\tbranchName: string;\n\t/** The parent the *policy* named, omitted when the branch fell back to the project default. */\n\tparentName?: string;\n\texpiresAt?: string;\n\tisProtected?: boolean;\n\tcomputeSettings?: ComputeSettings;\n}): Map<string, AppliedChange> => {\n\tconst changes = new Map<string, AppliedChange>();\n\tconst add = (field: string, details: Record<string, unknown>): void => {\n\t\tchanges.set(field, {\n\t\t\tkind: \"branch\",\n\t\t\taction: \"create\",\n\t\t\tidentifier: args.branchName,\n\t\t\tdetails: { field, ...details },\n\t\t});\n\t};\n\tif (args.parentName !== undefined) {\n\t\tadd(\"parent\", { parent: args.parentName });\n\t}\n\tif (args.expiresAt !== undefined) add(\"ttl\", { expiresAt: args.expiresAt });\n\tif (args.isProtected !== undefined) {\n\t\tadd(\"protected\", { protected: args.isProtected });\n\t}\n\tif (args.computeSettings) {\n\t\tadd(\"computeSettings\", { settings: args.computeSettings });\n\t}\n\treturn changes;\n};\n\n/**\n * Fold the create-time settings into what the push applied, reporting each field once.\n *\n * A field the create call already satisfied is a noop for the push, so the two normally don't\n * overlap. They do when the create didn't take (an API that ignores a create-time field, or\n * drift in the moments between the two calls) and the push applied it for real — the push\n * change is the one that describes what actually happened, so it wins.\n */\nconst mergeCreateSettings = (\n\tatCreate: Map<string, AppliedChange>,\n\tpushed: AppliedChange[],\n): AppliedChange[] => {\n\tconst pushedFields = new Set(\n\t\tpushed\n\t\t\t.filter((c) => c.kind === \"branch\" && c.action !== \"noop\")\n\t\t\t.map((c) => c.details?.field)\n\t\t\t.filter((field): field is string => typeof field === \"string\"),\n\t);\n\tconst fromCreate = [...atCreate]\n\t\t.filter(([field]) => !pushedFields.has(field))\n\t\t.map(([, change]) => change);\n\treturn [...fromCreate, ...pushed];\n};\n\n/**\n * Resolve the parent branch id for a new branch. A policy-declared `parent` (a branch name) is\n * looked up by name; an unknown name is a hard error. With no `parent`, fall back to the\n * project's default branch, or `undefined` (let the API pick the project default) when none is\n * marked default.\n */\nfunction resolveParentBranchId(\n\tparentName: string | undefined,\n\tbranches: NeonBranchSnapshot[],\n\tbranchName: string,\n): string | undefined {\n\tif (parentName !== undefined) {\n\t\tconst match = branches.find((b) => b.name === parentName);\n\t\tif (!match) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.BranchNotFound,\n\t\t\t\t`createBranch: the policy for \"${branchName}\" sets parent \"${parentName}\", but no branch with that name exists. Existing branches: ${\n\t\t\t\t\tbranches.map((b) => b.name).join(\", \") || \"(none)\"\n\t\t\t\t}.`,\n\t\t\t\t{\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tbranchName,\n\t\t\t\t\t\tparent: parentName,\n\t\t\t\t\t\tavailable: branches.map((b) => b.name),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\treturn match.id;\n\t}\n\treturn branches.find((b) => b.isDefault)?.id;\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { BucketAccessLevel, Config, NeonApi, NeonBranchSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonEndpointSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot } from "@neon/config";
1
+ import { BucketAccessLevel, Config, NeonApi, NeonBranchSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonEndpointSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRealtimeSnapshot } from "@neon/config";
2
2
 
3
3
  //#region src/lib/pull-config.d.ts
4
4
  interface PullConfigOptions {
@@ -12,6 +12,11 @@ interface PullConfigOptions {
12
12
  apiHost?: string;
13
13
  /** Inject a custom NeonApi adapter (primarily for tests). */
14
14
  api?: NeonApi;
15
+ /**
16
+ * Read the branch's Realtime state. Off by default: Realtime is only on Neon's staging
17
+ * API, and production answers the endpoint with HTTP 500 rather than 404.
18
+ */
19
+ realtime?: boolean;
15
20
  }
16
21
  /**
17
22
  * Live Preview-feature state read back from a branch. Surfaced alongside `config` rather
@@ -54,7 +59,8 @@ interface PulledBranchConfig {
54
59
  };
55
60
  /**
56
61
  * The branch's live state expressed as a {@link Config}: static `auth` / `dataApi`
57
- * toggles, any object-storage `preview.buckets`, plus a `branch` closure carrying the
62
+ * toggles, Realtime under `preview.realtime`, any object-storage `preview.buckets`, plus
63
+ * a `branch` closure carrying the
58
64
  * branch's lifecycle/compute tuning. Buckets are included here (not just in
59
65
  * {@link PulledBranchConfig.preview}) because they round-trip cleanly — name + access
60
66
  * level is all a {@link Config} needs — so the no-policy env path (`neon dev` /
@@ -82,6 +88,8 @@ declare function buildPulledBranchConfig(project: NeonProjectSnapshot, branch: N
82
88
  authEnabled?: boolean;
83
89
  /** Whether a Neon Data API integration is enabled on the branch. */
84
90
  dataApiEnabled?: boolean;
91
+ /** Realtime state when the adapter supports the branch endpoint. */
92
+ realtime?: NeonRealtimeSnapshot | null;
85
93
  }): PulledBranchConfig;
86
94
  //#endregion
87
95
  export { PullConfigOptions, PulledBranchConfig, PulledPreview, buildPulledBranchConfig, pullConfig };
@@ -1 +1 @@
1
- {"version":3,"file":"pull-config.d.ts","names":["BucketAccessLevel","Config","NeonApi","NeonBranchSnapshot","NeonBucketSnapshot","NeonCredentialMeta","NeonEndpointSnapshot","NeonFunctionSnapshot","NeonProjectSnapshot","PullConfigOptions","PulledPreview","Array","PulledBranchConfig","pullConfig","Promise","buildPulledBranchConfig","BucketAccessLevel","Config","NeonApi","NeonBranchSnapshot","NeonBucketSnapshot","NeonCredentialMeta","NeonEndpointSnapshot","NeonFunctionSnapshot","NeonProjectSnapshot","PullConfigOptions","projectId","branchId","apiKey","apiHost","api","PulledPreview","buckets","Array","name","access","functions","slug","credentials","PulledBranchConfig","project","id","region","pgVersion","orgId","branch","parent","isDefault","protected","expiresAt","config","preview","pullConfig","options","Promise","buildPulledBranchConfig","branches","endpoint","previewState","authEnabled","dataApiEnabled"],"sources":["../../src/lib/pull-config.ts"],"mappings":";;;UAkBiBS,iBAAAA;;EAAAA,SAAAA,EAAAA,MAAAA;EAmBAC;EAAaiB,QAAA,EAAA,MAAA;EACU3B;EAA9BW,MAAAA,CAAAA,EAAAA,MAAAA;EACEA;EAOEN,OAAAA,CAAAA,EAAAA,MAAAA;EAAkB;EAGfO,GAAAA,CAAAA,EArBVV,OAqBUU;AAAkB;AA6B1BX;AAMES;AAAa;AAGxB;AAAgC;AACtBD;AACCG,UApDMF,aAAAA,CAoDNE;EAARE,OAAAA,EAnDOH,KAmDPG,CAAAA;IAAOoB,IAAA,EAAA,MAAA;IAoIMnB,MAAAA,EAvLwBf,iBAuLD;EAAA,CAAA,CAAA;EAC7BQ,SAAAA,EAvLEG,KAuLFH,CAAAA;IACDL,IAAAA,EAAAA,MAAAA;IACEA,IAAAA,EAAAA,MAAAA;EACAG,CAAAA,CAAAA;EAEAF;AACEG;AACGF;AAMbO;AAAkB;;eA7LPP;;UAGGO,kBAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA6BRX;;;;;;YAMES;;iBAGWG,UAAAA,UACZJ,oBACPK,QAAQF;iBAoIKG,uBAAAA,UACNP,6BACDL,8BACEA,gCACAG;WAEAF;aACEG;gBACGF;;;;;IAMbO"}
1
+ {"version":3,"file":"pull-config.d.ts","names":["BucketAccessLevel","Config","NeonApi","NeonBranchSnapshot","NeonBucketSnapshot","NeonCredentialMeta","NeonEndpointSnapshot","NeonFunctionSnapshot","NeonProjectSnapshot","NeonRealtimeSnapshot","PullConfigOptions","PulledPreview","Array","PulledBranchConfig","pullConfig","Promise","buildPulledBranchConfig","BucketAccessLevel","Config","NeonApi","NeonBranchSnapshot","NeonBucketSnapshot","NeonCredentialMeta","NeonEndpointSnapshot","NeonFunctionSnapshot","NeonProjectSnapshot","NeonRealtimeSnapshot","PullConfigOptions","projectId","branchId","apiKey","apiHost","api","realtime","PulledPreview","buckets","Array","name","access","functions","slug","credentials","PulledBranchConfig","project","id","region","pgVersion","orgId","branch","parent","isDefault","protected","expiresAt","config","preview","pullConfig","options","Promise","buildPulledBranchConfig","branches","endpoint","previewState","authEnabled","dataApiEnabled"],"sources":["../../src/lib/pull-config.ts"],"mappings":";;;UAmBiBU,iBAAAA;;EAAAA,SAAAA,EAAAA,MAAAA;EAwBAC;EAAakB,QAAA,EAAA,MAAA;EACU7B;EAA9BY,MAAAA,CAAAA,EAAAA,MAAAA;EACEA;EAOEP,OAAAA,CAAAA,EAAAA,MAAAA;EAAkB;EAGfQ,GAAAA,CAAAA,EA1BVX,OA0BUW;EAAkB;AA8B1BZ;AAMEU;AAAa;EAGFG,QAAAA,CAAAA,EAAAA,OAAU;AAAA;AACtBJ;AACCG;AAARE;AAAO;AAoJV;AAAuC;AAC7BP,UA1MOG,aAAAA,CA0MPH;EACDL,OAAAA,EA1MCS,KA0MDT,CAAAA;IACEA,IAAAA,EAAAA,MAAAA;IACAG,MAAAA,EA5M6BN,iBA4M7BM;EAEAF,CAAAA,CAAAA;EACEG,SAAAA,EA9MDK,KA8MCL,CAAAA;IACGF,IAAAA,EAAAA,MAAAA;IAMHI,IAAAA,EAAAA,MAAAA;EAEVI,CAAAA,CAAAA;EAAkB;;;;;;eAhNPR;;UAGGQ,kBAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA8BRZ;;;;;;YAMEU;;iBAGWG,UAAAA,UACZJ,oBACPK,QAAQF;iBAoJKG,uBAAAA,UACNR,6BACDL,8BACEA,gCACAG;WAEAF;aACEG;gBACGF;;;;;;aAMHI;IAEVI"}
@@ -4,6 +4,7 @@ async function pullConfig(options) {
4
4
  const api = options.api ?? createApiFromOptions(options);
5
5
  const projectId = options.projectId;
6
6
  const branchId = options.branchId;
7
+ const getRealtime = options.realtime ? api.getProjectBranchRealtime?.bind(api) : void 0;
7
8
  const projectRead = started(() => api.getProject(projectId));
8
9
  const listsRead = started(() => Promise.all([started(() => api.listBranches(projectId)), started(() => api.listEndpoints(projectId))]));
9
10
  const databasesRead = started(() => api.listBranchDatabases(projectId, branchId));
@@ -14,7 +15,8 @@ async function pullConfig(options) {
14
15
  started(() => degradeUnavailable(() => api.listBranchFunctions(projectId, branchId), [])),
15
16
  started(() => degradeUnavailable(() => api.listCredentials(projectId, branchId), [])),
16
17
  started(() => api.getNeonAuth(projectId, branchId)),
17
- started(() => probeDatabase ? api.getNeonDataApi(projectId, branchId, probeDatabase) : Promise.resolve(null))
18
+ started(() => probeDatabase ? api.getNeonDataApi(projectId, branchId, probeDatabase) : Promise.resolve(null)),
19
+ started(() => getRealtime ? degradeUnavailable(() => getRealtime(projectId, branchId), null) : Promise.resolve(null))
18
20
  ]);
19
21
  }));
20
22
  const project = await projectRead;
@@ -22,13 +24,14 @@ async function pullConfig(options) {
22
24
  const branch = resolveBranch(branchId, branches);
23
25
  const endpoint = endpoints.find((ep) => ep.type === "read_write" && ep.branchId === branch.id);
24
26
  await databasesRead;
25
- const [buckets, functions, credentials, auth, dataApi] = await previewRead;
27
+ const [buckets, functions, credentials, auth, dataApi, realtime] = await previewRead;
26
28
  return buildPulledBranchConfig(project, branch, branches, endpoint, {
27
29
  buckets,
28
30
  functions,
29
31
  credentials,
30
32
  authEnabled: auth !== null,
31
- dataApiEnabled: dataApi !== null
33
+ dataApiEnabled: dataApi !== null,
34
+ realtime
32
35
  });
33
36
  }
34
37
  /**
@@ -55,15 +58,17 @@ function pickProbeDatabase(databases) {
55
58
  }
56
59
  /**
57
60
  * Run a Preview-feature read, returning `fallback` if the feature is unavailable for the
58
- * project/region (a {@link ErrorCode.FeatureUnavailable} from the adapter). Other errors
59
- * propagate. Used by `pullConfig` so a branch without a Preview feature still mirrors
60
- * cleanly for env resolution / `inspect`, rather than aborting on an unrelated capability.
61
+ * project/region. Most adapters report {@link ErrorCode.FeatureUnavailable}; API hosts where
62
+ * a route is not deployed can instead return a generic 404. The project and branch are
63
+ * validated independently by `pullConfig`, so that route-level 404 is also safe to degrade.
64
+ * Other errors propagate. This lets a branch without a Preview feature still mirror cleanly
65
+ * for env resolution / `inspect`, rather than aborting on an unrelated capability.
61
66
  */
62
67
  async function degradeUnavailable(read, fallback) {
63
68
  try {
64
69
  return await read();
65
70
  } catch (err) {
66
- if (err instanceof PlatformError && err.code === ErrorCode.FeatureUnavailable) return fallback;
71
+ if (err instanceof PlatformError && (err.code === ErrorCode.FeatureUnavailable || err.code === ErrorCode.NotFound && err.details.status === 404)) return fallback;
67
72
  throw err;
68
73
  }
69
74
  }
@@ -84,10 +89,13 @@ function buildPulledBranchConfig(project, branch, branches, endpoint, previewSta
84
89
  }
85
90
  const bucketDefs = {};
86
91
  for (const b of previewState?.buckets ?? []) bucketDefs[b.name] = { access: b.accessLevel };
92
+ const policyPreview = {};
93
+ if (previewState?.realtime?.enabled) policyPreview.realtime = true;
94
+ if (Object.keys(bucketDefs).length > 0) policyPreview.buckets = bucketDefs;
87
95
  const config = {
88
96
  ...previewState?.authEnabled ? { auth: true } : {},
89
97
  ...previewState?.dataApiEnabled ? { dataApi: true } : {},
90
- ...Object.keys(bucketDefs).length > 0 ? { preview: { buckets: bucketDefs } } : {},
98
+ ...Object.keys(policyPreview).length > 0 ? { preview: policyPreview } : {},
91
99
  ...Object.keys(tuning).length > 0 ? { branch: () => tuning } : {}
92
100
  };
93
101
  const result = {
@@ -1 +1 @@
1
- {"version":3,"file":"pull-config.js","names":[],"sources":["../../src/lib/pull-config.ts"],"sourcesContent":["import {\n\ttype BranchTuning,\n\ttype BucketAccessLevel,\n\ttype ComputeSettings,\n\ttype Config,\n\tcreateNeonApiFromOptions,\n\tErrorCode,\n\ttype NeonApi,\n\ttype NeonBranchSnapshot,\n\ttype NeonBucketSnapshot,\n\ttype NeonCredentialMeta,\n\ttype NeonDatabaseSnapshot,\n\ttype NeonEndpointSnapshot,\n\ttype NeonFunctionSnapshot,\n\ttype NeonProjectSnapshot,\n\tPlatformError,\n} from \"@neon/config\";\n\nexport interface PullConfigOptions {\n\t/** Neon project id (`<project>`). Required — the API addresses branches by project. */\n\tprojectId: string;\n\t/** Neon branch id (`br-…`). Required. Resolve names to ids before calling. */\n\tbranchId: string;\n\t/** Neon API key. Falls back to `NEON_API_KEY` / neonctl credentials. */\n\tapiKey?: string;\n\t/** Neon API base URL. Falls back to `NEON_API_HOST`, then production. */\n\tapiHost?: string;\n\t/** Inject a custom NeonApi adapter (primarily for tests). */\n\tapi?: NeonApi;\n}\n\n/**\n * Live Preview-feature state read back from a branch. Surfaced alongside `config` rather\n * than inside it because functions cannot round-trip: the remote only knows the deployed\n * bundle, not the local `source` path a {@link FunctionConfig} requires, so a pulled\n * function is reported as `{ slug, name }` (no `source`).\n */\nexport interface PulledPreview {\n\tbuckets: Array<{ name: string; access: BucketAccessLevel }>;\n\tfunctions: Array<{ slug: string; name: string }>;\n\t/**\n\t * Secret-free metadata for the credentials issued on the branch (Preview). Surfaced so\n\t * `config status` can show issued credentials (id, scopes, last used) without ever\n\t * exposing the one-time `api_token` / `s3_secret_access_key`. Empty when none / the\n\t * credentials endpoint is unavailable for the project.\n\t */\n\tcredentials: NeonCredentialMeta[];\n}\n\nexport interface PulledBranchConfig {\n\tproject: {\n\t\tid: string;\n\t\tname: string;\n\t\tregion: string;\n\t\tpgVersion: number;\n\t\torgId?: string;\n\t};\n\tbranch: {\n\t\tid: string;\n\t\tname: string;\n\t\tparent?: string;\n\t\tisDefault: boolean;\n\t\tprotected: boolean;\n\t\texpiresAt?: string;\n\t};\n\t/**\n\t * The branch's live state expressed as a {@link Config}: static `auth` / `dataApi`\n\t * toggles, any object-storage `preview.buckets`, plus a `branch` closure carrying the\n\t * branch's lifecycle/compute tuning. Buckets are included here (not just in\n\t * {@link PulledBranchConfig.preview}) because they round-trip cleanly — name + access\n\t * level is all a {@link Config} needs — so the no-policy env path (`neon dev` /\n\t * `neon env pull`) can resolve the branch's storage credentials without a local\n\t * `neon.ts`. Preview **functions** are reported only in\n\t * {@link PulledBranchConfig.preview}: they cannot round-trip (the remote has no local\n\t * `source` path). The AI Gateway is omitted from both — it has no branch-level \"enabled\"\n\t * state to read back (it is always available, credential-gated), so `pullConfig` cannot\n\t * tell whether a policy would enable it.\n\t */\n\tconfig: Config;\n\t/**\n\t * Live Preview-feature state, when the branch has any buckets/functions or issued\n\t * credentials. Omitted entirely when there is nothing to report. The AI Gateway is not\n\t * included: it is always available (credential-gated), not per-branch state.\n\t */\n\tpreview?: PulledPreview;\n}\n\nexport async function pullConfig(\n\toptions: PullConfigOptions,\n): Promise<PulledBranchConfig> {\n\tconst api = options.api ?? createApiFromOptions(options);\n\tconst projectId = options.projectId;\n\tconst branchId = options.branchId;\n\n\t// The first three stages need only the project and branch ids, so they start together.\n\t// They are awaited in the order they used to run, so the first error reported is the same\n\t// one as before (project, then branches/endpoints, then the branch lookup, then databases).\n\tconst projectRead = started(() => api.getProject(projectId));\n\tconst listsRead = started(() =>\n\t\tPromise.all([\n\t\t\tstarted(() => api.listBranches(projectId)),\n\t\t\tstarted(() => api.listEndpoints(projectId)),\n\t\t]),\n\t);\n\t// Data API is enabled per branch + database, so resolve a database to probe.\n\tconst databasesRead = started(() =>\n\t\tapi.listBranchDatabases(projectId, branchId),\n\t);\n\t// Preview reads degrade to \"none / disabled\" when the feature isn't available for the\n\t// project/region. `pullConfig` mirrors the branch for env resolution (`neon dev`,\n\t// `neon env pull`) and `inspect` — an unavailable Preview feature should not break those\n\t// (env comes from auth/dataApi/postgres). `pushConfig` is the place that fails on an\n\t// unavailable feature, and only when the policy declares it.\n\t// The group starts together once databases resolve (the Data API probe needs one), as\n\t// before, so which member's error comes first is unchanged.\n\tconst previewRead = started(() =>\n\t\tdatabasesRead.then((databases) => {\n\t\t\tconst probeDatabase = pickProbeDatabase(databases);\n\t\t\treturn Promise.all([\n\t\t\t\tstarted(() =>\n\t\t\t\t\tdegradeUnavailable(\n\t\t\t\t\t\t() => api.listBranchBuckets(projectId, branchId),\n\t\t\t\t\t\t[],\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tstarted(() =>\n\t\t\t\t\tdegradeUnavailable(\n\t\t\t\t\t\t() => api.listBranchFunctions(projectId, branchId),\n\t\t\t\t\t\t[],\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tstarted(() =>\n\t\t\t\t\tdegradeUnavailable(\n\t\t\t\t\t\t() => api.listCredentials(projectId, branchId),\n\t\t\t\t\t\t[],\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tstarted(() => api.getNeonAuth(projectId, branchId)),\n\t\t\t\tstarted(() =>\n\t\t\t\t\tprobeDatabase\n\t\t\t\t\t\t? api.getNeonDataApi(projectId, branchId, probeDatabase)\n\t\t\t\t\t\t: Promise.resolve(null),\n\t\t\t\t),\n\t\t\t]);\n\t\t}),\n\t);\n\n\tconst project = await projectRead;\n\tconst [branches, endpoints] = await listsRead;\n\tconst branch = resolveBranch(branchId, branches);\n\tconst endpoint = endpoints.find(\n\t\t(ep) => ep.type === \"read_write\" && ep.branchId === branch.id,\n\t);\n\tawait databasesRead;\n\tconst [buckets, functions, credentials, auth, dataApi] = await previewRead;\n\n\treturn buildPulledBranchConfig(project, branch, branches, endpoint, {\n\t\tbuckets,\n\t\tfunctions,\n\t\tcredentials,\n\t\tauthEnabled: auth !== null,\n\t\tdataApiEnabled: dataApi !== null,\n\t});\n}\n\n/**\n * Starts a read now and keeps an unread rejection from crashing the process; the caller\n * awaits it (and sees the error) when its turn comes. Also turns a synchronous throw from\n * a custom adapter into a rejection.\n */\nfunction started<T>(read: () => Promise<T>): Promise<T> {\n\tconst promise = Promise.resolve().then(read);\n\tpromise.catch(() => undefined);\n\treturn promise;\n}\n\n/**\n * Pick the database to probe for a Data API integration. Data API is enabled per\n * branch + database; for read-back we only need to know whether *any* database has it\n * on, so prefer the conventional default (`neondb`) and otherwise fall back to the first\n * database. Returns `undefined` when the branch has no databases.\n */\nfunction pickProbeDatabase(\n\tdatabases: NeonDatabaseSnapshot[],\n): string | undefined {\n\tif (databases.length === 0) return undefined;\n\tconst byName = databases.find((d) => d.name === \"neondb\");\n\tif (byName) return byName.name;\n\treturn databases[0].name;\n}\n\n/**\n * Run a Preview-feature read, returning `fallback` if the feature is unavailable for the\n * project/region (a {@link ErrorCode.FeatureUnavailable} from the adapter). Other errors\n * propagate. Used by `pullConfig` so a branch without a Preview feature still mirrors\n * cleanly for env resolution / `inspect`, rather than aborting on an unrelated capability.\n */\nasync function degradeUnavailable<T>(\n\tread: () => Promise<T>,\n\tfallback: T,\n): Promise<T> {\n\ttry {\n\t\treturn await read();\n\t} catch (err) {\n\t\tif (\n\t\t\terr instanceof PlatformError &&\n\t\t\terr.code === ErrorCode.FeatureUnavailable\n\t\t) {\n\t\t\treturn fallback;\n\t\t}\n\t\tthrow err;\n\t}\n}\n\nfunction createApiFromOptions(options: PullConfigOptions): NeonApi {\n\treturn createNeonApiFromOptions(\"pullConfig\", {\n\t\t...(options.apiKey ? { apiKey: options.apiKey } : {}),\n\t\t...(options.apiHost ? { apiHost: options.apiHost } : {}),\n\t});\n}\n\nexport function buildPulledBranchConfig(\n\tproject: NeonProjectSnapshot,\n\tbranch: NeonBranchSnapshot,\n\tbranches: NeonBranchSnapshot[],\n\tendpoint: NeonEndpointSnapshot | undefined,\n\tpreviewState?: {\n\t\tbuckets: NeonBucketSnapshot[];\n\t\tfunctions: NeonFunctionSnapshot[];\n\t\tcredentials?: NeonCredentialMeta[];\n\t\t/** Whether a Neon Auth integration is enabled on the branch. */\n\t\tauthEnabled?: boolean;\n\t\t/** Whether a Neon Data API integration is enabled on the branch. */\n\t\tdataApiEnabled?: boolean;\n\t},\n): PulledBranchConfig {\n\tconst parent = branch.parentId\n\t\t? branches.find((b) => b.id === branch.parentId)\n\t\t: undefined;\n\t// Auth/Data API are static top-level toggles, so a config pulled from a branch with\n\t// them enabled round-trips through `resolveConfig` / `fetchEnv` and the matching\n\t// secrets get injected. Branch lifecycle/compute is per-branch tuning, so it goes in\n\t// the `branch` closure.\n\tconst tuning: BranchTuning = {};\n\tif (parent) tuning.parent = parent.name;\n\t// Deliberately NOT emitting `ttl` from `branch.expiresAt`: policy `ttl` is a\n\t// creation-time *duration*, while `expiresAt` is an absolute timestamp. Feeding the\n\t// timestamp through `parseDuration` (in `resolveConfig`) would throw, breaking\n\t// `fetchEnv` / `neon dev` / `neon env pull` for any branch that has a TTL. The expiry\n\t// is reported faithfully on `branch.expiresAt` above.\n\tif (branch.protected) tuning.protected = true;\n\tif (endpoint) {\n\t\tconst compute = endpointToComputeSettings(endpoint, project);\n\t\tif (compute) tuning.postgres = { computeSettings: compute };\n\t}\n\t// Buckets round-trip cleanly (name + access level), so they belong in the config the\n\t// env path resolves from — this is what lets `neon dev` / `neon env pull` inject the\n\t// branch's object-storage credentials (AWS_*) with no local neon.ts. Functions are\n\t// deliberately NOT emitted here (they can't round-trip: the remote has no `source`\n\t// path) and neither is the AI Gateway (no branch-level enabled state to detect, only a\n\t// credential) — both would otherwise turn a read-back into a bogus policy declaration.\n\tconst bucketDefs: Record<string, { access: BucketAccessLevel }> = {};\n\tfor (const b of previewState?.buckets ?? []) {\n\t\tbucketDefs[b.name] = { access: b.accessLevel };\n\t}\n\tconst config: Config = {\n\t\t...(previewState?.authEnabled ? { auth: true } : {}),\n\t\t...(previewState?.dataApiEnabled ? { dataApi: true } : {}),\n\t\t...(Object.keys(bucketDefs).length > 0\n\t\t\t? { preview: { buckets: bucketDefs } }\n\t\t\t: {}),\n\t\t...(Object.keys(tuning).length > 0 ? { branch: () => tuning } : {}),\n\t};\n\tconst result: PulledBranchConfig = {\n\t\tproject: {\n\t\t\tid: project.id,\n\t\t\tname: project.name,\n\t\t\tregion: project.regionId,\n\t\t\tpgVersion: project.pgVersion,\n\t\t\t...(project.orgId ? { orgId: project.orgId } : {}),\n\t\t},\n\t\tbranch: {\n\t\t\tid: branch.id,\n\t\t\tname: branch.name,\n\t\t\t...(parent ? { parent: parent.name } : {}),\n\t\t\tisDefault: branch.isDefault,\n\t\t\tprotected: branch.protected,\n\t\t\t...(branch.expiresAt ? { expiresAt: branch.expiresAt } : {}),\n\t\t},\n\t\tconfig,\n\t};\n\tconst preview = previewState ? buildPulledPreview(previewState) : undefined;\n\tif (preview) result.preview = preview;\n\treturn result;\n}\n\n/**\n * Reverse-engineer the {@link PulledPreview} from remote snapshots. Returns `undefined` when\n * the branch has no Preview features so the field can be omitted entirely.\n */\nfunction buildPulledPreview(state: {\n\tbuckets: NeonBucketSnapshot[];\n\tfunctions: NeonFunctionSnapshot[];\n\tcredentials?: NeonCredentialMeta[];\n}): PulledPreview | undefined {\n\tconst credentials = state.credentials ?? [];\n\tif (\n\t\tstate.buckets.length === 0 &&\n\t\tstate.functions.length === 0 &&\n\t\tcredentials.length === 0\n\t) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\tbuckets: state.buckets.map((b) => ({\n\t\t\tname: b.name,\n\t\t\taccess: b.accessLevel,\n\t\t})),\n\t\tfunctions: state.functions.map((f) => ({\n\t\t\tslug: f.slug,\n\t\t\tname: f.name,\n\t\t})),\n\t\tcredentials,\n\t};\n}\n\nfunction resolveBranch(\n\tbranchId: string,\n\tbranches: NeonBranchSnapshot[],\n): NeonBranchSnapshot {\n\tconst match = branches.find((b) => b.id === branchId);\n\tif (match) return match;\n\tthrow new PlatformError(\n\t\tErrorCode.BranchNotFound,\n\t\t[\n\t\t\t`pullConfig: branch id ${JSON.stringify(branchId)} not found on project.`,\n\t\t\t`Available branches: ${branches.map((b) => `${b.name} (${b.id})`).join(\", \") || \"(none)\"}.`,\n\t\t].join(\" \"),\n\t\t{\n\t\t\tdetails: {\n\t\t\t\tbranchId,\n\t\t\t\tavailable: branches.map((b) => b.id),\n\t\t\t},\n\t\t},\n\t);\n}\n\nfunction endpointToComputeSettings(\n\tendpoint: NeonEndpointSnapshot,\n\tproject: NeonProjectSnapshot,\n): ComputeSettings | undefined {\n\tconst defaults = project.defaultEndpointSettings;\n\tconst out: ComputeSettings = {};\n\tif (\n\t\tendpoint.autoscalingLimitMinCu !== undefined &&\n\t\tendpoint.autoscalingLimitMinCu !== defaults?.autoscalingLimitMinCu\n\t) {\n\t\tout.autoscalingLimitMinCu = endpoint.autoscalingLimitMinCu;\n\t}\n\tif (\n\t\tendpoint.autoscalingLimitMaxCu !== undefined &&\n\t\tendpoint.autoscalingLimitMaxCu !== defaults?.autoscalingLimitMaxCu\n\t) {\n\t\tout.autoscalingLimitMaxCu = endpoint.autoscalingLimitMaxCu;\n\t}\n\tif (\n\t\tendpoint.suspendTimeout !== undefined &&\n\t\tendpoint.suspendTimeout !== defaults?.suspendTimeout\n\t) {\n\t\tout.suspendTimeout = endpoint.suspendTimeout;\n\t}\n\treturn Object.keys(out).length > 0 ? out : undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pull-config.js","names":[],"sources":["../../src/lib/pull-config.ts"],"sourcesContent":["import {\n\ttype BranchTuning,\n\ttype BucketAccessLevel,\n\ttype ComputeSettings,\n\ttype Config,\n\tcreateNeonApiFromOptions,\n\tErrorCode,\n\ttype NeonApi,\n\ttype NeonBranchSnapshot,\n\ttype NeonBucketSnapshot,\n\ttype NeonCredentialMeta,\n\ttype NeonDatabaseSnapshot,\n\ttype NeonEndpointSnapshot,\n\ttype NeonFunctionSnapshot,\n\ttype NeonProjectSnapshot,\n\ttype NeonRealtimeSnapshot,\n\tPlatformError,\n} from \"@neon/config\";\n\nexport interface PullConfigOptions {\n\t/** Neon project id (`<project>`). Required — the API addresses branches by project. */\n\tprojectId: string;\n\t/** Neon branch id (`br-…`). Required. Resolve names to ids before calling. */\n\tbranchId: string;\n\t/** Neon API key. Falls back to `NEON_API_KEY` / neonctl credentials. */\n\tapiKey?: string;\n\t/** Neon API base URL. Falls back to `NEON_API_HOST`, then production. */\n\tapiHost?: string;\n\t/** Inject a custom NeonApi adapter (primarily for tests). */\n\tapi?: NeonApi;\n\t/**\n\t * Read the branch's Realtime state. Off by default: Realtime is only on Neon's staging\n\t * API, and production answers the endpoint with HTTP 500 rather than 404.\n\t */\n\trealtime?: boolean;\n}\n\n/**\n * Live Preview-feature state read back from a branch. Surfaced alongside `config` rather\n * than inside it because functions cannot round-trip: the remote only knows the deployed\n * bundle, not the local `source` path a {@link FunctionConfig} requires, so a pulled\n * function is reported as `{ slug, name }` (no `source`).\n */\nexport interface PulledPreview {\n\tbuckets: Array<{ name: string; access: BucketAccessLevel }>;\n\tfunctions: Array<{ slug: string; name: string }>;\n\t/**\n\t * Secret-free metadata for the credentials issued on the branch (Preview). Surfaced so\n\t * `config status` can show issued credentials (id, scopes, last used) without ever\n\t * exposing the one-time `api_token` / `s3_secret_access_key`. Empty when none / the\n\t * credentials endpoint is unavailable for the project.\n\t */\n\tcredentials: NeonCredentialMeta[];\n}\n\nexport interface PulledBranchConfig {\n\tproject: {\n\t\tid: string;\n\t\tname: string;\n\t\tregion: string;\n\t\tpgVersion: number;\n\t\torgId?: string;\n\t};\n\tbranch: {\n\t\tid: string;\n\t\tname: string;\n\t\tparent?: string;\n\t\tisDefault: boolean;\n\t\tprotected: boolean;\n\t\texpiresAt?: string;\n\t};\n\t/**\n\t * The branch's live state expressed as a {@link Config}: static `auth` / `dataApi`\n\t * toggles, Realtime under `preview.realtime`, any object-storage `preview.buckets`, plus\n\t * a `branch` closure carrying the\n\t * branch's lifecycle/compute tuning. Buckets are included here (not just in\n\t * {@link PulledBranchConfig.preview}) because they round-trip cleanly — name + access\n\t * level is all a {@link Config} needs — so the no-policy env path (`neon dev` /\n\t * `neon env pull`) can resolve the branch's storage credentials without a local\n\t * `neon.ts`. Preview **functions** are reported only in\n\t * {@link PulledBranchConfig.preview}: they cannot round-trip (the remote has no local\n\t * `source` path). The AI Gateway is omitted from both — it has no branch-level \"enabled\"\n\t * state to read back (it is always available, credential-gated), so `pullConfig` cannot\n\t * tell whether a policy would enable it.\n\t */\n\tconfig: Config;\n\t/**\n\t * Live Preview-feature state, when the branch has any buckets/functions or issued\n\t * credentials. Omitted entirely when there is nothing to report. The AI Gateway is not\n\t * included: it is always available (credential-gated), not per-branch state.\n\t */\n\tpreview?: PulledPreview;\n}\n\nexport async function pullConfig(\n\toptions: PullConfigOptions,\n): Promise<PulledBranchConfig> {\n\tconst api = options.api ?? createApiFromOptions(options);\n\tconst projectId = options.projectId;\n\tconst branchId = options.branchId;\n\tconst getRealtime = options.realtime\n\t\t? api.getProjectBranchRealtime?.bind(api)\n\t\t: undefined;\n\n\t// The first three stages need only the project and branch ids, so they start together.\n\t// They are awaited in the order they used to run, so the first error reported is the same\n\t// one as before (project, then branches/endpoints, then the branch lookup, then databases).\n\tconst projectRead = started(() => api.getProject(projectId));\n\tconst listsRead = started(() =>\n\t\tPromise.all([\n\t\t\tstarted(() => api.listBranches(projectId)),\n\t\t\tstarted(() => api.listEndpoints(projectId)),\n\t\t]),\n\t);\n\t// Data API is enabled per branch + database, so resolve a database to probe.\n\tconst databasesRead = started(() =>\n\t\tapi.listBranchDatabases(projectId, branchId),\n\t);\n\t// Preview reads degrade to \"none / disabled\" when the feature isn't available for the\n\t// project/region. `pullConfig` mirrors the branch for env resolution (`neon dev`,\n\t// `neon env pull`) and `inspect` — an unavailable Preview feature should not break those\n\t// (env comes from auth/dataApi/postgres). `pushConfig` is the place that fails on an\n\t// unavailable feature, and only when the policy declares it.\n\t// The group starts together once databases resolve (the Data API probe needs one), as\n\t// before, so which member's error comes first is unchanged.\n\tconst previewRead = started(() =>\n\t\tdatabasesRead.then((databases) => {\n\t\t\tconst probeDatabase = pickProbeDatabase(databases);\n\t\t\treturn Promise.all([\n\t\t\t\tstarted(() =>\n\t\t\t\t\tdegradeUnavailable(\n\t\t\t\t\t\t() => api.listBranchBuckets(projectId, branchId),\n\t\t\t\t\t\t[],\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tstarted(() =>\n\t\t\t\t\tdegradeUnavailable(\n\t\t\t\t\t\t() => api.listBranchFunctions(projectId, branchId),\n\t\t\t\t\t\t[],\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tstarted(() =>\n\t\t\t\t\tdegradeUnavailable(\n\t\t\t\t\t\t() => api.listCredentials(projectId, branchId),\n\t\t\t\t\t\t[],\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tstarted(() => api.getNeonAuth(projectId, branchId)),\n\t\t\t\tstarted(() =>\n\t\t\t\t\tprobeDatabase\n\t\t\t\t\t\t? api.getNeonDataApi(projectId, branchId, probeDatabase)\n\t\t\t\t\t\t: Promise.resolve(null),\n\t\t\t\t),\n\t\t\t\tstarted(() =>\n\t\t\t\t\tgetRealtime\n\t\t\t\t\t\t? degradeUnavailable(\n\t\t\t\t\t\t\t\t() => getRealtime(projectId, branchId),\n\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: Promise.resolve(null),\n\t\t\t\t),\n\t\t\t]);\n\t\t}),\n\t);\n\n\tconst project = await projectRead;\n\tconst [branches, endpoints] = await listsRead;\n\tconst branch = resolveBranch(branchId, branches);\n\tconst endpoint = endpoints.find(\n\t\t(ep) => ep.type === \"read_write\" && ep.branchId === branch.id,\n\t);\n\tawait databasesRead;\n\tconst [buckets, functions, credentials, auth, dataApi, realtime] =\n\t\tawait previewRead;\n\n\treturn buildPulledBranchConfig(project, branch, branches, endpoint, {\n\t\tbuckets,\n\t\tfunctions,\n\t\tcredentials,\n\t\tauthEnabled: auth !== null,\n\t\tdataApiEnabled: dataApi !== null,\n\t\trealtime,\n\t});\n}\n\n/**\n * Starts a read now and keeps an unread rejection from crashing the process; the caller\n * awaits it (and sees the error) when its turn comes. Also turns a synchronous throw from\n * a custom adapter into a rejection.\n */\nfunction started<T>(read: () => Promise<T>): Promise<T> {\n\tconst promise = Promise.resolve().then(read);\n\tpromise.catch(() => undefined);\n\treturn promise;\n}\n\n/**\n * Pick the database to probe for a Data API integration. Data API is enabled per\n * branch + database; for read-back we only need to know whether *any* database has it\n * on, so prefer the conventional default (`neondb`) and otherwise fall back to the first\n * database. Returns `undefined` when the branch has no databases.\n */\nfunction pickProbeDatabase(\n\tdatabases: NeonDatabaseSnapshot[],\n): string | undefined {\n\tif (databases.length === 0) return undefined;\n\tconst byName = databases.find((d) => d.name === \"neondb\");\n\tif (byName) return byName.name;\n\treturn databases[0].name;\n}\n\n/**\n * Run a Preview-feature read, returning `fallback` if the feature is unavailable for the\n * project/region. Most adapters report {@link ErrorCode.FeatureUnavailable}; API hosts where\n * a route is not deployed can instead return a generic 404. The project and branch are\n * validated independently by `pullConfig`, so that route-level 404 is also safe to degrade.\n * Other errors propagate. This lets a branch without a Preview feature still mirror cleanly\n * for env resolution / `inspect`, rather than aborting on an unrelated capability.\n */\nasync function degradeUnavailable<T>(\n\tread: () => Promise<T>,\n\tfallback: T,\n): Promise<T> {\n\ttry {\n\t\treturn await read();\n\t} catch (err) {\n\t\tif (\n\t\t\terr instanceof PlatformError &&\n\t\t\t(err.code === ErrorCode.FeatureUnavailable ||\n\t\t\t\t(err.code === ErrorCode.NotFound && err.details.status === 404))\n\t\t) {\n\t\t\treturn fallback;\n\t\t}\n\t\tthrow err;\n\t}\n}\n\nfunction createApiFromOptions(options: PullConfigOptions): NeonApi {\n\treturn createNeonApiFromOptions(\"pullConfig\", {\n\t\t...(options.apiKey ? { apiKey: options.apiKey } : {}),\n\t\t...(options.apiHost ? { apiHost: options.apiHost } : {}),\n\t});\n}\n\nexport function buildPulledBranchConfig(\n\tproject: NeonProjectSnapshot,\n\tbranch: NeonBranchSnapshot,\n\tbranches: NeonBranchSnapshot[],\n\tendpoint: NeonEndpointSnapshot | undefined,\n\tpreviewState?: {\n\t\tbuckets: NeonBucketSnapshot[];\n\t\tfunctions: NeonFunctionSnapshot[];\n\t\tcredentials?: NeonCredentialMeta[];\n\t\t/** Whether a Neon Auth integration is enabled on the branch. */\n\t\tauthEnabled?: boolean;\n\t\t/** Whether a Neon Data API integration is enabled on the branch. */\n\t\tdataApiEnabled?: boolean;\n\t\t/** Realtime state when the adapter supports the branch endpoint. */\n\t\trealtime?: NeonRealtimeSnapshot | null;\n\t},\n): PulledBranchConfig {\n\tconst parent = branch.parentId\n\t\t? branches.find((b) => b.id === branch.parentId)\n\t\t: undefined;\n\t// Auth and Data API are static top-level toggles, while Realtime is static under\n\t// `preview.realtime`. A config pulled from a branch with them enabled round-trips through\n\t// `resolveConfig` / `fetchEnv` and the matching secrets get injected. Branch\n\t// lifecycle/compute is per-branch tuning, so it goes in the `branch` closure.\n\tconst tuning: BranchTuning = {};\n\tif (parent) tuning.parent = parent.name;\n\t// Deliberately NOT emitting `ttl` from `branch.expiresAt`: policy `ttl` is a\n\t// creation-time *duration*, while `expiresAt` is an absolute timestamp. Feeding the\n\t// timestamp through `parseDuration` (in `resolveConfig`) would throw, breaking\n\t// `fetchEnv` / `neon dev` / `neon env pull` for any branch that has a TTL. The expiry\n\t// is reported faithfully on `branch.expiresAt` above.\n\tif (branch.protected) tuning.protected = true;\n\tif (endpoint) {\n\t\tconst compute = endpointToComputeSettings(endpoint, project);\n\t\tif (compute) tuning.postgres = { computeSettings: compute };\n\t}\n\t// Buckets round-trip cleanly (name + access level), so they belong in the config the\n\t// env path resolves from — this is what lets `neon dev` / `neon env pull` inject the\n\t// branch's object-storage credentials (AWS_*) with no local neon.ts. Functions are\n\t// deliberately NOT emitted here (they can't round-trip: the remote has no `source`\n\t// path) and neither is the AI Gateway (no branch-level enabled state to detect, only a\n\t// credential) — both would otherwise turn a read-back into a bogus policy declaration.\n\tconst bucketDefs: Record<string, { access: BucketAccessLevel }> = {};\n\tfor (const b of previewState?.buckets ?? []) {\n\t\tbucketDefs[b.name] = { access: b.accessLevel };\n\t}\n\tconst policyPreview: NonNullable<Config[\"preview\"]> = {};\n\tif (previewState?.realtime?.enabled) policyPreview.realtime = true;\n\tif (Object.keys(bucketDefs).length > 0) policyPreview.buckets = bucketDefs;\n\tconst config: Config = {\n\t\t...(previewState?.authEnabled ? { auth: true } : {}),\n\t\t...(previewState?.dataApiEnabled ? { dataApi: true } : {}),\n\t\t...(Object.keys(policyPreview).length > 0\n\t\t\t? { preview: policyPreview }\n\t\t\t: {}),\n\t\t...(Object.keys(tuning).length > 0 ? { branch: () => tuning } : {}),\n\t};\n\tconst result: PulledBranchConfig = {\n\t\tproject: {\n\t\t\tid: project.id,\n\t\t\tname: project.name,\n\t\t\tregion: project.regionId,\n\t\t\tpgVersion: project.pgVersion,\n\t\t\t...(project.orgId ? { orgId: project.orgId } : {}),\n\t\t},\n\t\tbranch: {\n\t\t\tid: branch.id,\n\t\t\tname: branch.name,\n\t\t\t...(parent ? { parent: parent.name } : {}),\n\t\t\tisDefault: branch.isDefault,\n\t\t\tprotected: branch.protected,\n\t\t\t...(branch.expiresAt ? { expiresAt: branch.expiresAt } : {}),\n\t\t},\n\t\tconfig,\n\t};\n\tconst preview = previewState ? buildPulledPreview(previewState) : undefined;\n\tif (preview) result.preview = preview;\n\treturn result;\n}\n\n/**\n * Reverse-engineer the {@link PulledPreview} from remote snapshots. Returns `undefined` when\n * the branch has no Preview features so the field can be omitted entirely.\n */\nfunction buildPulledPreview(state: {\n\tbuckets: NeonBucketSnapshot[];\n\tfunctions: NeonFunctionSnapshot[];\n\tcredentials?: NeonCredentialMeta[];\n}): PulledPreview | undefined {\n\tconst credentials = state.credentials ?? [];\n\tif (\n\t\tstate.buckets.length === 0 &&\n\t\tstate.functions.length === 0 &&\n\t\tcredentials.length === 0\n\t) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\tbuckets: state.buckets.map((b) => ({\n\t\t\tname: b.name,\n\t\t\taccess: b.accessLevel,\n\t\t})),\n\t\tfunctions: state.functions.map((f) => ({\n\t\t\tslug: f.slug,\n\t\t\tname: f.name,\n\t\t})),\n\t\tcredentials,\n\t};\n}\n\nfunction resolveBranch(\n\tbranchId: string,\n\tbranches: NeonBranchSnapshot[],\n): NeonBranchSnapshot {\n\tconst match = branches.find((b) => b.id === branchId);\n\tif (match) return match;\n\tthrow new PlatformError(\n\t\tErrorCode.BranchNotFound,\n\t\t[\n\t\t\t`pullConfig: branch id ${JSON.stringify(branchId)} not found on project.`,\n\t\t\t`Available branches: ${branches.map((b) => `${b.name} (${b.id})`).join(\", \") || \"(none)\"}.`,\n\t\t].join(\" \"),\n\t\t{\n\t\t\tdetails: {\n\t\t\t\tbranchId,\n\t\t\t\tavailable: branches.map((b) => b.id),\n\t\t\t},\n\t\t},\n\t);\n}\n\nfunction endpointToComputeSettings(\n\tendpoint: NeonEndpointSnapshot,\n\tproject: NeonProjectSnapshot,\n): ComputeSettings | undefined {\n\tconst defaults = project.defaultEndpointSettings;\n\tconst out: ComputeSettings = {};\n\tif (\n\t\tendpoint.autoscalingLimitMinCu !== undefined &&\n\t\tendpoint.autoscalingLimitMinCu !== defaults?.autoscalingLimitMinCu\n\t) {\n\t\tout.autoscalingLimitMinCu = endpoint.autoscalingLimitMinCu;\n\t}\n\tif (\n\t\tendpoint.autoscalingLimitMaxCu !== undefined &&\n\t\tendpoint.autoscalingLimitMaxCu !== defaults?.autoscalingLimitMaxCu\n\t) {\n\t\tout.autoscalingLimitMaxCu = endpoint.autoscalingLimitMaxCu;\n\t}\n\tif (\n\t\tendpoint.suspendTimeout !== undefined &&\n\t\tendpoint.suspendTimeout !== defaults?.suspendTimeout\n\t) {\n\t\tout.suspendTimeout = endpoint.suspendTimeout;\n\t}\n\treturn Object.keys(out).length > 0 ? out : undefined;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"push-config.d.ts","names":["Config","ConflictReport","NeonApi","PushResult","FunctionBundler","PushConfigOptions","PushConfirmContext","Promise","pushConfig","FunctionBundler","Config","ConflictReport","NeonApi","PushResult","PushConfigOptions","projectId","branchId","apiKey","apiHost","api","branchExists","updateExisting","allowProtectedBranch","confirm","context","PushConfirmContext","Promise","beforeMutations","bundleFunction","dryRun","branchName","protectedBranch","overrideUpdates","overrides","pushConfig","config","options"],"sources":["../../src/lib/push-config.ts"],"mappings":";;;;UAmCiBK,iBAAAA;;AAAjB;AAAkC;AAoB3BH;AA8CcI;EAAiCC,SAAAA,EAAAA,MAAAA;EAMtBA;AAEdH;AAAe;AAmBjC;EAgCsBI,QAAAA,EAAAA,MAAU;EAAA;EACvBR,MAAAA,CAAAA,EAAAA,MAAAA;EACCK;EACCF,OAAAA,CAAAA,EAAAA,MAAAA;EAARI;AAAO;;;QA5GHL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBA8CcI,iCAAiCC;;;;;;iCAMtBA;;mBAEdH;;;;;;;;;;;;;;;;;;UAmBDE,kBAAAA;;;;;;;;;;;;;;;;;;;;sBAoBIL;;;;;;;;;;;iBAYCO,UAAAA,SACbR,iBACCK,oBACPE,QAAQJ"}
1
+ {"version":3,"file":"push-config.d.ts","names":["Config","ConflictReport","NeonApi","PushResult","FunctionBundler","PushConfigOptions","PushConfirmContext","Promise","pushConfig","FunctionBundler","Config","ConflictReport","NeonApi","PushResult","PushConfigOptions","projectId","branchId","apiKey","apiHost","api","branchExists","updateExisting","allowProtectedBranch","confirm","context","PushConfirmContext","Promise","beforeMutations","bundleFunction","dryRun","branchName","protectedBranch","overrideUpdates","overrides","pushConfig","config","options"],"sources":["../../src/lib/push-config.ts"],"mappings":";;;;UAoCiBK,iBAAAA;;AAAjB;AAAkC;AAoB3BH;AA8CcI;EAAiCC,SAAAA,EAAAA,MAAAA;EAMtBA;AAEdH;AAAe;AAmBjC;EAgCsBI,QAAAA,EAAAA,MAAU;EAAA;EACvBR,MAAAA,CAAAA,EAAAA,MAAAA;EACCK;EACCF,OAAAA,CAAAA,EAAAA,MAAAA;EAARI;AAAO;;;QA5GHL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBA8CcI,iCAAiCC;;;;;;iCAMtBA;;mBAEdH;;;;;;;;;;;;;;;;;;UAmBDE,kBAAAA;;;;;;;;;;;;;;;;;;;;sBAoBIL;;;;;;;;;;;iBAYCO,UAAAA,SACbR,iBACCK,oBACPE,QAAQJ"}
@@ -34,6 +34,8 @@ async function pushConfig(config, options) {
34
34
  isProtected: branch.protected,
35
35
  ...branch.expiresAt ? { expiresAt: branch.expiresAt } : {}
36
36
  });
37
+ const realtimeApi = hasRealtimePolicy(resolved) ? requireRealtimeApi(api) : void 0;
38
+ const realtimeRead = realtimeApi ? started(() => realtimeApi.getProjectBranchRealtime(remoteProject.id, branch.id)) : void 0;
37
39
  const servicesRead = started(() => resolveServiceState({
38
40
  api,
39
41
  projectId: remoteProject.id,
@@ -56,6 +58,7 @@ async function pushConfig(config, options) {
56
58
  endpoint: endpoints.find((ep) => ep.type === "read_write" && ep.branchId === branch.id),
57
59
  services
58
60
  };
61
+ if (realtimeRead) remote.realtime = await realtimeRead;
59
62
  if (previewRead) remote.preview = await previewRead;
60
63
  const diff = diffConfig(resolved, remote, { updateExisting: true });
61
64
  const needsOverrideConfirm = diff.plan.filter(isOverrideStep).length > 0 && !updateExisting;
@@ -130,7 +133,7 @@ async function pushConfig(config, options) {
130
133
  return result;
131
134
  }
132
135
  function isOverrideStep(step) {
133
- return step.kind === "update-branch-ttl" || step.kind === "update-branch-protected" || step.kind === "update-endpoint" || step.kind === "update-data-api" || step.kind === "disable-data-api" || step.kind === "retarget-custom-domain";
136
+ return step.kind === "update-branch-ttl" || step.kind === "update-branch-protected" || step.kind === "update-endpoint" || step.kind === "update-realtime" || step.kind === "disable-realtime" || step.kind === "update-data-api" || step.kind === "disable-data-api" || step.kind === "retarget-custom-domain";
134
137
  }
135
138
  /**
136
139
  * Build an {@link AppliedChange} from a {@link PlanStep} without calling the Neon API.
@@ -140,6 +143,26 @@ function isOverrideStep(step) {
140
143
  */
141
144
  function synthesizeAppliedChange(step) {
142
145
  switch (step.kind) {
146
+ case "enable-realtime": return {
147
+ kind: "service",
148
+ action: "create",
149
+ identifier: "realtime",
150
+ ...step.input?.allowedOrigins !== void 0 ? { details: { allowedOrigins: step.input.allowedOrigins } } : {}
151
+ };
152
+ case "update-realtime": return {
153
+ kind: "service",
154
+ action: "update",
155
+ identifier: "realtime",
156
+ details: {
157
+ field: "allowedOrigins",
158
+ allowedOrigins: step.input.allowedOrigins
159
+ }
160
+ };
161
+ case "disable-realtime": return {
162
+ kind: "service",
163
+ action: "delete",
164
+ identifier: "realtime"
165
+ };
143
166
  case "update-branch-ttl": return {
144
167
  kind: "branch",
145
168
  action: "update",
@@ -347,6 +370,13 @@ async function pickServiceDatabaseName(api, projectId, branchId) {
347
370
  }
348
371
  async function applyStep(step, ctx) {
349
372
  switch (step.kind) {
373
+ case "enable-realtime":
374
+ case "update-realtime":
375
+ await requireRealtimeApi(ctx.api).enableProjectBranchRealtime(ctx.remoteProjectId, step.branchId, step.input);
376
+ return synthesizeAppliedChange(step);
377
+ case "disable-realtime":
378
+ await requireRealtimeApi(ctx.api).disableProjectBranchRealtime(ctx.remoteProjectId, step.branchId);
379
+ return synthesizeAppliedChange(step);
350
380
  case "update-branch-ttl": {
351
381
  const updated = await ctx.api.updateBranch(ctx.remoteProjectId, step.branchId, { expiresAt: step.expiresAt ?? null });
352
382
  ctx.branchById.set(updated.id, updated);
@@ -537,6 +567,20 @@ async function applyStep(step, ctx) {
537
567
  }
538
568
  }
539
569
  }
570
+ function hasRealtimePolicy(resolved) {
571
+ return resolved.realtimePolicy !== void 0 && resolved.realtimePolicy !== "omitted";
572
+ }
573
+ function requireRealtimeApi(api) {
574
+ const get = api.getProjectBranchRealtime;
575
+ const enable = api.enableProjectBranchRealtime;
576
+ const disable = api.disableProjectBranchRealtime;
577
+ if (!get || !enable || !disable) throw new PlatformError(ErrorCode.FeatureUnavailable, "This NeonApi adapter does not implement Realtime. Implement getProjectBranchRealtime, enableProjectBranchRealtime, and disableProjectBranchRealtime, or remove preview.realtime from neon.ts.");
578
+ return {
579
+ getProjectBranchRealtime: get.bind(api),
580
+ enableProjectBranchRealtime: enable.bind(api),
581
+ disableProjectBranchRealtime: disable.bind(api)
582
+ };
583
+ }
540
584
  /**
541
585
  * Add each deployed function's invocation URL to its applied-change `details` so callers
542
586
  * (e.g. neonctl) can show users where to call the function right after a push.
@@ -1 +1 @@
1
- {"version":3,"file":"push-config.js","names":[],"sources":["../../src/lib/push-config.ts"],"sourcesContent":["import {\n\ttype AppliedChange,\n\ttype Config,\n\ttype ConflictReport,\n\ttype CreateTriggerInput,\n\tcreateNeonApiFromOptions,\n\tdiffConfig,\n\tErrorCode,\n\ttype NeonApi,\n\ttype NeonBranchSnapshot,\n\ttype NeonCustomDomainSnapshot,\n\ttype PlanStep,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n\ttype PushResult,\n\ttype RemotePreviewState,\n\ttype RemoteServiceState,\n\ttype RemoteState,\n\ttype ResolvedFunctionConfig,\n\ttype ResolvedFunctionTrigger,\n\ttype ResolvedPreviewConfig,\n\tresolveConfig,\n\ttype UpdateTriggerInput,\n} from \"@neon/config\";\nimport type { FunctionBundler } from \"./function-bundle.js\";\n\n// Eager loading would evaluate esbuild for callers that provide their own bundler.\nconst makeDefaultBundleFunction =\n\t(onWarning: (message: string) => void): FunctionBundler =>\n\tasync (fn: ResolvedFunctionConfig): Promise<Uint8Array> => {\n\t\tconst { buildFunctionBundle } = await import(\"./function-bundle.js\");\n\t\treturn buildFunctionBundle(fn, { onWarning });\n\t};\n\nexport interface PushConfigOptions {\n\t/**\n\t * Neon project id. **Required** — the management API addresses every branch through\n\t * its project, so there is no way to push without it. `pushConfig` never creates a\n\t * project; resolve the id yourself (e.g. via neonctl) and pass it in.\n\t */\n\tprojectId: string;\n\t/**\n\t * Neon branch id (`br-…`). **Required.** `pushConfig` never creates a branch — it must\n\t * already exist on the project. Resolve names to ids before calling.\n\t */\n\tbranchId: string;\n\t/** Neon API key. Falls back to `NEON_API_KEY` / neonctl credentials. Ignored when `api` is supplied. */\n\tapiKey?: string;\n\t/** Neon API base URL. Falls back to `NEON_API_HOST`, then production. */\n\tapiHost?: string;\n\t/**\n\t * Inject a custom NeonApi adapter. Primarily used by tests; production callers can rely\n\t * on the default real adapter built from `apiKey`.\n\t */\n\tapi?: NeonApi;\n\t/**\n\t * Whether to evaluate the policy as if the target branch **already exists** (the value of\n\t * `branch.exists` passed to the `defineConfig({ branch: (branch) => … })` closure). Defaults to `true`.\n\t *\n\t * Set to `false` to evaluate the policy as a **branch creation** — used by\n\t * {@link createBranch} right after it provisions a new branch, so creation-time tuning\n\t * gated on `!branch.exists` (TTL, compute settings, `parent`) actually resolves instead of\n\t * hitting the \"existing branch, leave as-is\" path. Only affects policy evaluation; the\n\t * branch must still physically exist on Neon (`pushConfig` never creates one).\n\t */\n\tbranchExists?: boolean;\n\t/**\n\t * Auto-confirm overriding existing remote settings.\n\t *\n\t * When `true`, mutable drift on the selected branch (TTL, `protected` flag, compute\n\t * settings) is applied as actual mutations and the override-confirm prompt is\n\t * skipped. When `false` (default) the behaviour depends on whether `confirm` is\n\t * supplied:\n\t * - With `confirm`: the callback is asked whether to apply the override.\n\t * - Without `confirm`: drift is reported as a `PushConflictError` (legacy\n\t * non-interactive default — preserved so programmatic SDK callers don't\n\t * silently start mutating remote state).\n\t */\n\tupdateExisting?: boolean;\n\t/**\n\t * Auto-confirm pushing to a protected branch.\n\t *\n\t * When `true`, no protected-branch confirmation is asked. When `false` (default):\n\t * - With `confirm`: the callback is asked.\n\t * - Without `confirm`: the push proceeds (legacy SDK default).\n\t */\n\tallowProtectedBranch?: boolean;\n\t/**\n\t * Optional confirmation callback. Invoked once with a single context object before\n\t * any mutations run when the push needs confirmation: pushing to a protected\n\t * branch (unless `allowProtectedBranch` is `true`) and/or applying mutable drift\n\t * (unless `updateExisting` is `true`).\n\t *\n\t * Both prompts collapse into a single callback invocation when both apply, so the\n\t * CLI can render one combined \"are you sure?\" prompt.\n\t *\n\t * Resolves to `true` to proceed, `false` to abort with {@link PushAbortedError}.\n\t *\n\t * Never invoked on `dryRun`.\n\t */\n\tconfirm?: (context: PushConfirmContext) => boolean | Promise<boolean>;\n\t/**\n\t * Runs once after {@link confirm} approves (or was not needed) and before the first\n\t * mutation or function bundle. A throw aborts the push with nothing changed by it.\n\t * Never invoked on `dryRun`.\n\t */\n\tbeforeMutations?: () => void | Promise<void>;\n\t/** Inject to deploy without this package loading esbuild. */\n\tbundleFunction?: FunctionBundler;\n\t/**\n\t * When `true`, compute the full plan against the live remote state but **do not\n\t * execute any mutations**. The resulting `PushResult.applied` array records every\n\t * change that *would* run on a real push (with the same action / identifier / details\n\t * shape, so the existing CLI summary formatter just works), and conflicts are\n\t * reported instead of thrown.\n\t *\n\t * Used by `plan(config, branchId)` and any caller that wants a \"would this push do\n\t * something dangerous?\" check before invoking `pushConfig` for real.\n\t */\n\tdryRun?: boolean;\n}\n\n/**\n * Context handed to a {@link PushConfigOptions.confirm} callback. Both flags can be\n * `true` simultaneously when the push targets a protected branch *and* would override\n * existing settings — render a single combined prompt covering both reasons.\n */\nexport interface PushConfirmContext {\n\t/** Name of the target branch on Neon. */\n\tbranchName: string;\n\t/**\n\t * `true` when the target branch has the `protected` flag on Neon and the caller\n\t * did not pass `allowProtectedBranch: true`.\n\t */\n\tprotectedBranch: boolean;\n\t/**\n\t * `true` when the plan would override existing remote settings (TTL, `protected`\n\t * flag, compute settings on an existing endpoint) and the caller did not pass\n\t * `updateExisting: true`. Additive operations (enabling Neon Auth / Data API for\n\t * the first time) are **not** counted here — those are unambiguous and never\n\t * prompt.\n\t */\n\toverrideUpdates: boolean;\n\t/**\n\t * The settings that would be overridden, as current → desired, so the caller can show\n\t * what it is asking about. Empty when only {@link protectedBranch} applies.\n\t */\n\toverrides: readonly ConflictReport[];\n}\n\n/**\n * Push a Neon branch policy to a specific project + branch.\n *\n * Filesystem- and env-agnostic: the caller supplies an already-validated `Config` object\n * (from `defineConfig` / `loadConfigFromFile`) and explicit `projectId` + `branch` in\n * `options`. `pushConfig` performs no `.neon` lookups and reads no `NEON_*` env vars except the API credential/host resolution documented on `apiKey`/`apiHost`.\n *\n * It will **not** create a project or branch — both must already exist on Neon.\n */\nexport async function pushConfig(\n\tconfig: Config,\n\toptions: PushConfigOptions,\n): Promise<PushResult> {\n\tconst api = options.api ?? createApiFromOptions(options);\n\tconst projectId = options.projectId;\n\n\t// Collected from the built-in bundler and returned on the result. A caller that injects\n\t// its own `bundleFunction` reports for itself, so this stays empty for them.\n\tconst warnings: string[] = [];\n\n\tconst dryRun = options.dryRun === true;\n\tconst updateExisting = options.updateExisting === true;\n\tconst allowProtectedBranch = options.allowProtectedBranch === true;\n\n\t// Same scheduling as `pullConfig`: independent reads start together and are awaited in\n\t// the order they used to run, so the first error reported is unchanged.\n\tconst projectRead = started(() => api.getProject(projectId));\n\tconst listsRead = started(() =>\n\t\tPromise.all([\n\t\t\thandled(api.listBranches(projectId)),\n\t\t\thandled(api.listEndpoints(projectId)),\n\t\t]),\n\t);\n\tconst remoteProject = await projectRead;\n\tconst [branches, endpoints] = await listsRead;\n\tconst branch = resolveRemoteBranch(options.branchId, branches);\n\tconst resolved = resolveConfig(config, {\n\t\tname: branch.name,\n\t\tid: branch.id,\n\t\texists: options.branchExists !== false,\n\t\t...(branch.parentId ? { parentId: branch.parentId } : {}),\n\t\tisDefault: branch.isDefault,\n\t\tisProtected: branch.protected,\n\t\t...(branch.expiresAt ? { expiresAt: branch.expiresAt } : {}),\n\t});\n\tconst servicesRead = started(() =>\n\t\tresolveServiceState({\n\t\t\tapi,\n\t\t\tprojectId: remoteProject.id,\n\t\t\tbranch,\n\t\t\twantsAuth: resolved.authEnabled,\n\t\t\twantsDataApi:\n\t\t\t\tresolved.dataApiEnabled ||\n\t\t\t\tresolved.dataApiPolicy === \"disabled\",\n\t\t}),\n\t);\n\t// Only fetch Preview state when the policy actually uses it — and within that, only the\n\t// specific features the policy declares. So a policy that uses functions never probes\n\t// the AI Gateway, and `apply`/`plan` only fail on a Preview feature being unavailable\n\t// (404/503) when the policy actually asks for it.\n\tconst desiredPreview = resolved.preview;\n\tconst previewRead = desiredPreview\n\t\t? started(() =>\n\t\t\t\tresolvePreviewState({\n\t\t\t\t\tapi,\n\t\t\t\t\tprojectId: remoteProject.id,\n\t\t\t\t\tbranchId: branch.id,\n\t\t\t\t\tdesired: desiredPreview,\n\t\t\t\t\twantsTriggers: (resolved.triggers?.length ?? 0) > 0,\n\t\t\t\t}),\n\t\t\t)\n\t\t: undefined;\n\tconst services = await servicesRead;\n\tconst remote: RemoteState = {\n\t\tprojectId: remoteProject.id,\n\t\tbranch,\n\t\tendpoint: endpoints.find(\n\t\t\t(ep) => ep.type === \"read_write\" && ep.branchId === branch.id,\n\t\t),\n\t\tservices,\n\t};\n\tif (previewRead) {\n\t\tremote.preview = await previewRead;\n\t}\n\n\t// Always compute the plan with `updateExisting: true` so we can see what *would* be\n\t// overridden. The decision of whether to apply / prompt / fail is gated below using\n\t// the recorded steps.\n\tconst diff = diffConfig(resolved, remote, { updateExisting: true });\n\tconst overrideSteps = diff.plan.filter(isOverrideStep);\n\tconst needsOverrideConfirm = overrideSteps.length > 0 && !updateExisting;\n\tconst needsProtectedConfirm = branch.protected && !allowProtectedBranch;\n\n\tif (!dryRun && diff.conflicts.length > 0) {\n\t\tthrow new PushConflictError(diff.conflicts);\n\t}\n\n\tif (!dryRun && (needsOverrideConfirm || needsProtectedConfirm)) {\n\t\tif (options.confirm) {\n\t\t\tconst ok = await options.confirm({\n\t\t\t\tbranchName: branch.name,\n\t\t\t\tprotectedBranch: needsProtectedConfirm,\n\t\t\t\toverrideUpdates: needsOverrideConfirm,\n\t\t\t\t// The non-overriding diff reports exactly the drift as conflicts; the\n\t\t\t\t// override-able plan above has already ruled out every other conflict.\n\t\t\t\toverrides: needsOverrideConfirm\n\t\t\t\t\t? diffConfig(resolved, remote, { updateExisting: false })\n\t\t\t\t\t\t\t.conflicts\n\t\t\t\t\t: [],\n\t\t\t});\n\t\t\tif (!ok) {\n\t\t\t\tconst reasons: (\"protected-branch\" | \"override-updates\")[] = [];\n\t\t\t\tif (needsProtectedConfirm) reasons.push(\"protected-branch\");\n\t\t\t\tif (needsOverrideConfirm) reasons.push(\"override-updates\");\n\t\t\t\tthrow new PushAbortedError(branch.name, reasons);\n\t\t\t}\n\t\t} else if (needsOverrideConfirm) {\n\t\t\t// Legacy non-interactive fallback: surface the would-be drift as a\n\t\t\t// `PushConflictError` so programmatic callers that skipped both\n\t\t\t// `updateExisting` and `confirm` see the previous fail-fast behavior.\n\t\t\tconst legacy = diffConfig(resolved, remote, {\n\t\t\t\tupdateExisting: false,\n\t\t\t});\n\t\t\tthrow new PushConflictError(legacy.conflicts);\n\t\t}\n\t\t// Protected branch + no confirm callback: legacy default proceeds without\n\t\t// any extra check (no programmatic regression).\n\t}\n\n\tif (!dryRun) await options.beforeMutations?.();\n\n\tconst applied: AppliedChange[] = [\n\t\t{ kind: \"branch\", action: \"noop\", identifier: branch.name },\n\t];\n\n\tconst branchById = new Map(branches.map((b) => [b.id, b] as const));\n\tconst branchByName = new Map(branches.map((b) => [b.name, b] as const));\n\tconst ctx: ApplyContext = {\n\t\tapi,\n\t\tremoteProjectId: remoteProject.id,\n\t\tbranchById,\n\t\tbranchByName,\n\t\tbundleFunction:\n\t\t\toptions.bundleFunction ??\n\t\t\tmakeDefaultBundleFunction((message) => {\n\t\t\t\twarnings.push(message);\n\t\t\t}),\n\t\tdeploymentIdBySlug: new Map(),\n\t};\n\n\tfor (const step of diff.plan) {\n\t\tconst change = dryRun\n\t\t\t? synthesizeAppliedChange(step)\n\t\t\t: await applyStep(step, ctx);\n\t\tapplied.push(change);\n\t}\n\n\t// Surface each deployed function's invocation URL on its applied change so callers\n\t// (e.g. neonctl) can show users where to call it right after a push.\n\tawait enrichFunctionInvocationUrls({\n\t\tapi,\n\t\tprojectId: remoteProject.id,\n\t\tbranchId: branch.id,\n\t\tplan: diff.plan,\n\t\tapplied,\n\t\tpreview: remote.preview,\n\t\tdryRun,\n\t});\n\n\tconst result: PushResult = {\n\t\tprojectId: remoteProject.id,\n\t\tbranchId: branch.id,\n\t\tbranchName: branch.name,\n\t\tdryRun,\n\t\tapplied,\n\t\tconflicts: diff.conflicts,\n\t\twarnings,\n\t};\n\tif (remoteProject.orgId) result.orgId = remoteProject.orgId;\n\tenrichDeclaredCustomDomains({\n\t\tresult,\n\t\tpreview: remote.preview,\n\t\tfunctions: resolved.preview?.functions ?? [],\n\t\tapplied,\n\t\twarnings,\n\t});\n\treturn result;\n}\n\nfunction isOverrideStep(step: PlanStep): boolean {\n\treturn (\n\t\tstep.kind === \"update-branch-ttl\" ||\n\t\tstep.kind === \"update-branch-protected\" ||\n\t\tstep.kind === \"update-endpoint\" ||\n\t\tstep.kind === \"update-data-api\" ||\n\t\tstep.kind === \"disable-data-api\" ||\n\t\tstep.kind === \"retarget-custom-domain\"\n\t);\n}\n\n/**\n * Build an {@link AppliedChange} from a {@link PlanStep} without calling the Neon API.\n * Used by dry-run mode so callers see the same record shape they would on a live push,\n * just with no side effects. Identifiers are the branch names from the plan; any\n * sub-resource ids (`branchId`, `endpointId`) flow through unchanged when known.\n */\nfunction synthesizeAppliedChange(step: PlanStep): AppliedChange {\n\tswitch (step.kind) {\n\t\tcase \"update-branch-ttl\":\n\t\t\treturn {\n\t\t\t\tkind: \"branch\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: step.branchName,\n\t\t\t\tdetails: { field: \"ttl\", expiresAt: step.expiresAt },\n\t\t\t};\n\t\tcase \"update-branch-protected\":\n\t\t\treturn {\n\t\t\t\tkind: \"branch\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: step.branchName,\n\t\t\t\tdetails: { field: \"protected\", protected: step.protected },\n\t\t\t};\n\t\tcase \"update-endpoint\":\n\t\t\treturn {\n\t\t\t\tkind: \"branch\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: step.branchName,\n\t\t\t\tdetails: {\n\t\t\t\t\tfield: \"computeSettings\",\n\t\t\t\t\tendpointId: step.endpointId,\n\t\t\t\t\tsettings: step.settings,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"enable-auth\":\n\t\t\t// Pure branch on/off toggle: the target branch is redundant (same on\n\t\t\t// every row) and the database is auto-derived, not policy-chosen — so\n\t\t\t// there is nothing meaningful to surface in the change summary.\n\t\t\treturn { kind: \"service\", action: \"create\", identifier: \"auth\" };\n\t\tcase \"enable-data-api\":\n\t\t\treturn { kind: \"service\", action: \"create\", identifier: \"dataApi\" };\n\t\tcase \"update-data-api\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: \"dataApi\",\n\t\t\t\tdetails: { field: \"settings\", settings: step.settings },\n\t\t\t};\n\t\tcase \"disable-data-api\":\n\t\t\treturn { kind: \"service\", action: \"delete\", identifier: \"dataApi\" };\n\t\tcase \"create-bucket\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: `bucket:${step.bucketName}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tbucketName: step.bucketName,\n\t\t\t\t\taccessLevel: step.accessLevel,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"deploy-function\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\t// The first deployment creates the function; a later one updates it.\n\t\t\t\taction: step.functionExists ? \"update\" : \"create\",\n\t\t\t\tidentifier: `function:${step.fn.slug}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tslug: step.fn.slug,\n\t\t\t\t\tsource: step.fn.source,\n\t\t\t\t\truntime: step.fn.runtime,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"create-trigger\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: `trigger:${step.functionSlug}:${step.trigger.name}`,\n\t\t\t\tdetails: triggerChangeDetails(step.functionSlug, step.trigger),\n\t\t\t};\n\t\tcase \"update-trigger\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: `trigger:${step.functionSlug}:${step.trigger.name}`,\n\t\t\t\tdetails: triggerChangeDetails(step.functionSlug, step.trigger),\n\t\t\t};\n\t\tcase \"register-custom-domain\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: `domain:${step.domain}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tdomain: step.domain,\n\t\t\t\t\tslug: step.functionSlug,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"retarget-custom-domain\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: `domain:${step.domain}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tdomain: step.domain,\n\t\t\t\t\tslug: step.functionSlug,\n\t\t\t\t\tpreviousSlug: step.previousSlug,\n\t\t\t\t},\n\t\t\t};\n\t}\n}\n\nfunction createApiFromOptions(options: PushConfigOptions): NeonApi {\n\treturn createNeonApiFromOptions(\"pushConfig\", {\n\t\t...(options.apiKey ? { apiKey: options.apiKey } : {}),\n\t\t...(options.apiHost ? { apiHost: options.apiHost } : {}),\n\t});\n}\n\nfunction resolveRemoteBranch(\n\tbranchId: string,\n\tbranches: NeonBranchSnapshot[],\n): NeonBranchSnapshot {\n\tconst found = branches.find((b) => b.id === branchId);\n\tif (found) return found;\n\tthrow new PlatformError(\n\t\tErrorCode.BranchNotFound,\n\t\t[\n\t\t\t`pushConfig: branch id ${JSON.stringify(branchId)} does not exist on the project.`,\n\t\t\t`Available branches: ${branches.map((b) => `${b.name} (${b.id})`).join(\", \") || \"(none)\"}.`,\n\t\t\t\"Pass an existing branch id, or create the branch first with the neonctl CLI.\",\n\t\t].join(\" \"),\n\t\t{ details: { branchId, available: branches.map((b) => b.id) } },\n\t);\n}\n\n/**\n * Starts a read now and keeps an unread rejection from crashing the process; the caller\n * awaits it (and sees the error) when its turn comes. The read is called synchronously and\n * its own promise returned, so errors surface in the same order as a direct call; a\n * synchronous throw becomes the returned rejection.\n */\nfunction started<T>(read: () => Promise<T>): Promise<T> {\n\tlet promise: Promise<T>;\n\ttry {\n\t\tpromise = read();\n\t} catch (error) {\n\t\tpromise = Promise.reject(error);\n\t}\n\tpromise.catch(() => undefined);\n\treturn promise;\n}\n\n/**\n * Marks a `Promise.all` member's rejection as handled, so a later member's synchronous\n * throw cannot leave it unobserved. `Promise.all` still reports it.\n */\nfunction handled<T>(promise: Promise<T>): Promise<T> {\n\tpromise.catch(() => undefined);\n\treturn promise;\n}\n\n/**\n * Pre-fetch the current state of branch-scoped integrations on the selected branch.\n */\nasync function resolveServiceState(args: {\n\tapi: NeonApi;\n\tprojectId: string;\n\tbranch: NeonBranchSnapshot;\n\twantsAuth: boolean;\n\twantsDataApi: boolean;\n}): Promise<RemoteServiceState> {\n\tconst { api, projectId, branch, wantsAuth, wantsDataApi } = args;\n\tif (!wantsAuth && !wantsDataApi) {\n\t\treturn {\n\t\t\tdatabaseName: \"neondb\",\n\t\t\tauthEnabled: false,\n\t\t\tdataApiEnabled: false,\n\t\t};\n\t}\n\n\tconst databaseName = await pickServiceDatabaseName(\n\t\tapi,\n\t\tprojectId,\n\t\tbranch.id,\n\t);\n\n\tconst [auth, dataApi] = await Promise.all([\n\t\twantsAuth\n\t\t\t? handled(api.getNeonAuth(projectId, branch.id))\n\t\t\t: Promise.resolve(null),\n\t\twantsDataApi\n\t\t\t? handled(api.getNeonDataApi(projectId, branch.id, databaseName))\n\t\t\t: Promise.resolve(null),\n\t]);\n\tconst result: RemoteServiceState = {\n\t\tdatabaseName,\n\t\tauthEnabled: auth !== null,\n\t\tdataApiEnabled: dataApi !== null,\n\t};\n\t// Carry the current Data API settings (when reported) so the diff can detect settings\n\t// drift and plan an update. `null` distinguishes \"enabled but not reported\" from \"absent\".\n\tif (dataApi) result.dataApiSettings = dataApi.settings ?? null;\n\treturn result;\n}\n\n/**\n * Pre-fetch the current state of branch-scoped Preview features (buckets, functions) so the\n * diff can be computed additively. Only called when the policy has a `preview` block.\n *\n * The AI Gateway is not probed: it is always available (credential-gated, not per-branch\n * provisioned), so `preview.aiGateway` produces no plan step — it only drives the branch\n * credential's `ai_gateway:invoke` scope and the gateway env vars (`@neon/env`).\n */\nasync function resolvePreviewState(args: {\n\tapi: NeonApi;\n\tprojectId: string;\n\tbranchId: string;\n\tdesired: ResolvedPreviewConfig;\n\twantsTriggers: boolean;\n}): Promise<RemotePreviewState> {\n\tconst { api, projectId, branchId, desired, wantsTriggers } = args;\n\t// Read only the Preview features the policy declares: undeclared features can never\n\t// produce a plan step (see diffConfig), so probing them is pure waste — and would make\n\t// `plan`/`apply` fail on a feature the user didn't ask for if it's unavailable in the\n\t// project/region. A declared-but-unavailable feature still throws (failing the push),\n\t// which is the intended signal to enable it first.\n\tconst wantsCustomDomains = desired.functions.some(\n\t\t(fn) => (fn.customDomains?.length ?? 0) > 0,\n\t);\n\tconst customDomainApi = wantsCustomDomains\n\t\t? requireCustomDomainApi(api)\n\t\t: undefined;\n\tconst [buckets, functions, triggers, customDomains] = await Promise.all([\n\t\tdesired.buckets.length > 0\n\t\t\t? handled(api.listBranchBuckets(projectId, branchId))\n\t\t\t: Promise.resolve([]),\n\t\tdesired.functions.length > 0\n\t\t\t? handled(api.listBranchFunctions(projectId, branchId))\n\t\t\t: Promise.resolve([]),\n\t\twantsTriggers\n\t\t\t? handled(api.listBranchTriggers(projectId, branchId))\n\t\t\t: Promise.resolve([]),\n\t\tcustomDomainApi\n\t\t\t? handled(\n\t\t\t\t\tcustomDomainApi.listBranchCustomDomains(\n\t\t\t\t\t\tprojectId,\n\t\t\t\t\t\tbranchId,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t: Promise.resolve([]),\n\t]);\n\tconst preview: RemotePreviewState = { buckets, functions, triggers };\n\tif (wantsCustomDomains) preview.customDomains = customDomains;\n\treturn preview;\n}\n\n/**\n * Resolve the database name for a Data API integration. Auto-pick when the branch has\n * exactly one database; otherwise fall back to Neon's default (`neondb`) so the call\n * stays useful even on branches with multiple databases — push doesn't have a way to\n * surface a \"pick one\" prompt the way `fetchEnv` does.\n */\nasync function pickServiceDatabaseName(\n\tapi: NeonApi,\n\tprojectId: string,\n\tbranchId: string,\n): Promise<string> {\n\tconst databases = await api.listBranchDatabases(projectId, branchId);\n\tif (databases.length === 1) return databases[0].name;\n\tconst neondb = databases.find((d) => d.name === \"neondb\");\n\tif (neondb) return neondb.name;\n\treturn databases[0]?.name ?? \"neondb\";\n}\n\ninterface ApplyContext {\n\tapi: NeonApi;\n\tremoteProjectId: string;\n\tbranchById: Map<string, NeonBranchSnapshot>;\n\tbranchByName: Map<string, NeonBranchSnapshot>;\n\tbundleFunction: FunctionBundler;\n\tdeploymentIdBySlug: Map<string, number>;\n}\n\nasync function applyStep(\n\tstep: PlanStep,\n\tctx: ApplyContext,\n): Promise<AppliedChange> {\n\tswitch (step.kind) {\n\t\tcase \"update-branch-ttl\": {\n\t\t\tconst updated = await ctx.api.updateBranch(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\t{\n\t\t\t\t\texpiresAt: step.expiresAt ?? null,\n\t\t\t\t},\n\t\t\t);\n\t\t\tctx.branchById.set(updated.id, updated);\n\t\t\tctx.branchByName.set(updated.name, updated);\n\t\t\treturn {\n\t\t\t\tkind: \"branch\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: updated.name,\n\t\t\t\tdetails: { field: \"ttl\", expiresAt: step.expiresAt },\n\t\t\t};\n\t\t}\n\t\tcase \"update-branch-protected\": {\n\t\t\tconst updated = await ctx.api.updateBranch(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\t{ protected: step.protected },\n\t\t\t);\n\t\t\tctx.branchById.set(updated.id, updated);\n\t\t\tctx.branchByName.set(updated.name, updated);\n\t\t\treturn {\n\t\t\t\tkind: \"branch\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: updated.name,\n\t\t\t\tdetails: { field: \"protected\", protected: step.protected },\n\t\t\t};\n\t\t}\n\t\tcase \"update-endpoint\": {\n\t\t\tconst updated = await ctx.api.updateEndpoint(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.endpointId,\n\t\t\t\tstep.settings,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"branch\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: step.branchName,\n\t\t\t\tdetails: {\n\t\t\t\t\tfield: \"computeSettings\",\n\t\t\t\t\tendpointId: updated.id,\n\t\t\t\t\tsettings: step.settings,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tcase \"enable-auth\": {\n\t\t\tawait ctx.api.enableNeonAuth(ctx.remoteProjectId, step.branchId, {\n\t\t\t\t...(step.databaseName\n\t\t\t\t\t? { databaseName: step.databaseName }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: \"auth\",\n\t\t\t};\n\t\t}\n\t\tcase \"enable-data-api\": {\n\t\t\tawait ctx.api.enableProjectBranchDataApi(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tstep.databaseName,\n\t\t\t\tstep.input,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: \"dataApi\",\n\t\t\t};\n\t\t}\n\t\tcase \"update-data-api\": {\n\t\t\tawait ctx.api.updateProjectBranchDataApi(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tstep.databaseName,\n\t\t\t\tstep.settings,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: \"dataApi\",\n\t\t\t\tdetails: { field: \"settings\", settings: step.settings },\n\t\t\t};\n\t\t}\n\t\tcase \"disable-data-api\": {\n\t\t\tawait ctx.api.deleteProjectBranchDataApi(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tstep.databaseName,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"delete\",\n\t\t\t\tidentifier: \"dataApi\",\n\t\t\t};\n\t\t}\n\t\tcase \"create-bucket\": {\n\t\t\tawait ctx.api.createBranchBucket(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\t{ name: step.bucketName, accessLevel: step.accessLevel },\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: `bucket:${step.bucketName}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tbucketName: step.bucketName,\n\t\t\t\t\taccessLevel: step.accessLevel,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tcase \"deploy-function\": {\n\t\t\tconst bundle = await ctx.bundleFunction(step.fn);\n\t\t\t// Neon creates the function on its first deployment — there is no separate\n\t\t\t// create call — so a single deploy both creates (when absent) and ships code.\n\t\t\tconst deployment = await ctx.api.deployBranchFunction(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tstep.fn.slug,\n\t\t\t\t{\n\t\t\t\t\tbundle,\n\t\t\t\t\truntime: step.fn.runtime,\n\t\t\t\t\tenvironment: step.fn.env,\n\t\t\t\t},\n\t\t\t);\n\t\t\tctx.deploymentIdBySlug.set(step.fn.slug, deployment.id);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: step.functionExists ? \"update\" : \"create\",\n\t\t\t\tidentifier: `function:${step.fn.slug}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tslug: step.fn.slug,\n\t\t\t\t\tsource: step.fn.source,\n\t\t\t\t\truntime: step.fn.runtime,\n\t\t\t\t\tdeploymentId: deployment.id,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tcase \"create-trigger\": {\n\t\t\tawait ctx.api.createBranchTrigger(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tcreateTriggerInput(step.functionSlug, step.trigger),\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: `trigger:${step.functionSlug}:${step.trigger.name}`,\n\t\t\t\tdetails: triggerChangeDetails(step.functionSlug, step.trigger),\n\t\t\t};\n\t\t}\n\t\tcase \"update-trigger\": {\n\t\t\tawait ctx.api.updateBranchTrigger(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tstep.triggerId,\n\t\t\t\tupdateTriggerInput(step.functionSlug, step.trigger),\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: `trigger:${step.functionSlug}:${step.trigger.name}`,\n\t\t\t\tdetails: triggerChangeDetails(step.functionSlug, step.trigger),\n\t\t\t};\n\t\t}\n\t\tcase \"register-custom-domain\": {\n\t\t\tconst methods = requireCustomDomainApi(ctx.api);\n\t\t\tlet snapshot: NeonCustomDomainSnapshot;\n\t\t\ttry {\n\t\t\t\tsnapshot = await methods.registerBranchCustomDomain(\n\t\t\t\t\tctx.remoteProjectId,\n\t\t\t\t\tstep.branchId,\n\t\t\t\t\t{ domain: step.domain, functionSlug: step.functionSlug },\n\t\t\t\t);\n\t\t\t} catch (err) {\n\t\t\t\tthrow rewriteCustomDomainConflict(err, step.domain);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: `domain:${step.domain}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tdomain: snapshot.domain,\n\t\t\t\t\tslug: step.functionSlug,\n\t\t\t\t\tcnameTarget: snapshot.cnameTarget,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tcase \"retarget-custom-domain\": {\n\t\t\tconst methods = requireCustomDomainApi(ctx.api);\n\t\t\tconst deploymentId = ctx.deploymentIdBySlug.get(step.functionSlug);\n\t\t\tif (deploymentId === undefined) {\n\t\t\t\tthrow new PlatformError(\n\t\t\t\t\tErrorCode.ServerError,\n\t\t\t\t\t`Cannot retarget a custom domain onto ${JSON.stringify(step.functionSlug)}: this apply did not deploy that function.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait waitForCompletedFunctionDeployment({\n\t\t\t\tapi: ctx.api,\n\t\t\t\tprojectId: ctx.remoteProjectId,\n\t\t\t\tbranchId: step.branchId,\n\t\t\t\tslug: step.functionSlug,\n\t\t\t\tdeploymentId,\n\t\t\t});\n\t\t\tconst observed = (\n\t\t\t\tawait methods.listBranchCustomDomains(\n\t\t\t\t\tctx.remoteProjectId,\n\t\t\t\t\tstep.branchId,\n\t\t\t\t)\n\t\t\t).find((item) => item.domain === step.domain);\n\t\t\tif (\n\t\t\t\tobserved === undefined ||\n\t\t\t\tobserved.entityType !== \"function\" ||\n\t\t\t\tobserved.entityId !== step.previousSlug\n\t\t\t) {\n\t\t\t\tconst seen =\n\t\t\t\t\tobserved === undefined\n\t\t\t\t\t\t? \"no registration\"\n\t\t\t\t\t\t: `${observed.entityType} ${JSON.stringify(observed.entityId)}`;\n\t\t\t\tthrow new PlatformError(\n\t\t\t\t\tErrorCode.Conflict,\n\t\t\t\t\t`Cannot retarget ${JSON.stringify(step.domain)}: planned owner was function ${JSON.stringify(step.previousSlug)}; observed ${seen}. DELETE was not attempted.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait methods.deleteBranchCustomDomain(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tstep.domain,\n\t\t\t);\n\t\t\tlet snapshot: NeonCustomDomainSnapshot;\n\t\t\ttry {\n\t\t\t\tsnapshot = await methods.registerBranchCustomDomain(\n\t\t\t\t\tctx.remoteProjectId,\n\t\t\t\t\tstep.branchId,\n\t\t\t\t\t{ domain: step.domain, functionSlug: step.functionSlug },\n\t\t\t\t);\n\t\t\t} catch (err) {\n\t\t\t\tconst rewritten = rewriteCustomDomainConflict(err, step.domain);\n\t\t\t\tconst message =\n\t\t\t\t\trewritten instanceof PlatformError\n\t\t\t\t\t\t? rewritten.message\n\t\t\t\t\t\t: rewritten instanceof Error\n\t\t\t\t\t\t\t? rewritten.message\n\t\t\t\t\t\t\t: String(rewritten);\n\t\t\t\tthrow new PlatformError(\n\t\t\t\t\trewritten instanceof PlatformError\n\t\t\t\t\t\t? rewritten.code\n\t\t\t\t\t\t: ErrorCode.ServerError,\n\t\t\t\t\t`Deleted the previous registration of ${JSON.stringify(step.domain)} (function ${JSON.stringify(step.previousSlug)}) but failed to register it on ${JSON.stringify(step.functionSlug)}. Inspect current ownership with \\`neon function domains list\\` before recovering. ${message}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tcause: rewritten instanceof Error ? rewritten : err,\n\t\t\t\t\t\tdetails:\n\t\t\t\t\t\t\trewritten instanceof PlatformError\n\t\t\t\t\t\t\t\t? { ...rewritten.details }\n\t\t\t\t\t\t\t\t: {},\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: `domain:${step.domain}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tdomain: snapshot.domain,\n\t\t\t\t\tslug: step.functionSlug,\n\t\t\t\t\tpreviousSlug: step.previousSlug,\n\t\t\t\t\tcnameTarget: snapshot.cnameTarget,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t}\n}\n\n/**\n * Add each deployed function's invocation URL to its applied-change `details` so callers\n * (e.g. neonctl) can show users where to call the function right after a push.\n *\n * The URL is read from the preview snapshot already fetched for the diff, which lists every\n * existing function with its `invocationUrl`. A function created by its *first* deployment in\n * this push is not in that snapshot, so when one is present we re-list the branch's functions\n * once to learn its freshly-minted URL. Skipped on dry-run (nothing was created) and\n * best-effort otherwise: a failed re-list omits the URL rather than failing a push that has\n * already applied.\n */\nasync function enrichFunctionInvocationUrls(args: {\n\tapi: NeonApi;\n\tprojectId: string;\n\tbranchId: string;\n\tplan: PlanStep[];\n\tapplied: AppliedChange[];\n\tpreview: RemotePreviewState | undefined;\n\tdryRun: boolean;\n}): Promise<void> {\n\tconst { api, projectId, branchId, plan, applied, preview, dryRun } = args;\n\tconst deployedSlugs = plan.flatMap((step) =>\n\t\tstep.kind === \"deploy-function\" ? [step.fn.slug] : [],\n\t);\n\tif (deployedSlugs.length === 0) return;\n\n\tconst urlBySlug = new Map<string, string>(\n\t\t(preview?.functions ?? []).map(\n\t\t\t(fn) => [fn.slug, fn.invocationUrl] as const,\n\t\t),\n\t);\n\n\t// A first-time deploy creates the function, so its URL isn't in the pre-fetch; re-list\n\t// once when any deployed slug is still missing a URL.\n\tconst hasMissingUrl = deployedSlugs.some((slug) => !urlBySlug.has(slug));\n\tif (hasMissingUrl && !dryRun) {\n\t\ttry {\n\t\t\tfor (const fn of await api.listBranchFunctions(\n\t\t\t\tprojectId,\n\t\t\t\tbranchId,\n\t\t\t)) {\n\t\t\t\turlBySlug.set(fn.slug, fn.invocationUrl);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Push already succeeded; surface what we can rather than failing here.\n\t\t}\n\t}\n\n\tfor (const change of applied) {\n\t\tconst slug = functionSlugFromIdentifier(change.identifier);\n\t\tif (slug === undefined) continue;\n\t\tconst invocationUrl = urlBySlug.get(slug);\n\t\tif (invocationUrl === undefined) continue;\n\t\tchange.details = { ...change.details, invocationUrl };\n\t}\n}\n\n/** Pull the function slug out of a `function:<slug>` applied-change identifier. */\nfunction functionSlugFromIdentifier(identifier: string): string | undefined {\n\tconst prefix = \"function:\";\n\treturn identifier.startsWith(prefix)\n\t\t? identifier.slice(prefix.length)\n\t\t: undefined;\n}\n\nasync function waitForCompletedFunctionDeployment(args: {\n\tapi: NeonApi;\n\tprojectId: string;\n\tbranchId: string;\n\tslug: string;\n\tdeploymentId: number;\n}): Promise<void> {\n\tconst get = args.api.getBranchFunction;\n\tif (!get) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.FeatureUnavailable,\n\t\t\t`Cannot retarget a custom domain onto ${JSON.stringify(args.slug)}: this NeonApi adapter does not implement getBranchFunction, so apply cannot confirm the function finished deploying.`,\n\t\t);\n\t}\n\tconst intervalMs =\n\t\tNumber(process.env.NEON_FUNCTIONS_POLL_INTERVAL_MS) || 2000;\n\tconst timeoutMs =\n\t\tNumber(process.env.NEON_FUNCTIONS_POLL_TIMEOUT_MS) || 600_000;\n\tconst deadline = Date.now() + timeoutMs;\n\tfor (;;) {\n\t\tconst fn = await get.call(\n\t\t\targs.api,\n\t\t\targs.projectId,\n\t\t\targs.branchId,\n\t\t\targs.slug,\n\t\t);\n\t\tconst dep = fn.currentDeployment;\n\t\t// GET can still report the previous deployment after this apply's POST returns.\n\t\tif (dep !== undefined && dep.id > args.deploymentId) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.ServerError,\n\t\t\t\t`Cannot retarget a custom domain onto ${JSON.stringify(args.slug)}: current deployment is ${dep.id}, this apply submitted ${args.deploymentId}; left the previous custom-domain registration in place.`,\n\t\t\t);\n\t\t}\n\t\tif (dep !== undefined && dep.id === args.deploymentId) {\n\t\t\tif (dep.status === \"completed\") return;\n\t\t\tif (dep.status === \"failed\") {\n\t\t\t\tthrow new PlatformError(\n\t\t\t\t\tErrorCode.ServerError,\n\t\t\t\t\t`Deployment of function ${JSON.stringify(args.slug)} failed; left the previous custom-domain registration in place.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (Date.now() >= deadline) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.ServerError,\n\t\t\t\t`Timed out waiting for function ${JSON.stringify(args.slug)} to finish deploying; left the previous custom-domain registration in place.`,\n\t\t\t);\n\t\t}\n\t\tawait new Promise((resolve) => setTimeout(resolve, intervalMs));\n\t}\n}\n\nfunction requireCustomDomainApi(api: NeonApi): {\n\tlistBranchCustomDomains: NonNullable<NeonApi[\"listBranchCustomDomains\"]>;\n\tregisterBranchCustomDomain: NonNullable<\n\t\tNeonApi[\"registerBranchCustomDomain\"]\n\t>;\n\tdeleteBranchCustomDomain: NonNullable<NeonApi[\"deleteBranchCustomDomain\"]>;\n} {\n\tconst list = api.listBranchCustomDomains;\n\tconst register = api.registerBranchCustomDomain;\n\tconst remove = api.deleteBranchCustomDomain;\n\tif (!list || !register || !remove) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.FeatureUnavailable,\n\t\t\t\"This NeonApi adapter does not implement custom domains. Implement listBranchCustomDomains, registerBranchCustomDomain, and deleteBranchCustomDomain, or remove customDomains from neon.ts.\",\n\t\t);\n\t}\n\treturn {\n\t\tlistBranchCustomDomains: list.bind(api),\n\t\tregisterBranchCustomDomain: register.bind(api),\n\t\tdeleteBranchCustomDomain: remove.bind(api),\n\t};\n}\n\nfunction rewriteCustomDomainConflict(err: unknown, domain: string): unknown {\n\tif (!(err instanceof PlatformError) || err.code !== ErrorCode.Conflict) {\n\t\treturn err;\n\t}\n\tconst neonMessage =\n\t\ttypeof err.details.neonMessage === \"string\"\n\t\t\t? err.details.neonMessage\n\t\t\t: undefined;\n\tconst requestId =\n\t\ttypeof err.details.requestId === \"string\"\n\t\t\t? err.details.requestId\n\t\t\t: undefined;\n\tconst status =\n\t\ttypeof err.details.status === \"number\" ? err.details.status : undefined;\n\tconst apiParts = [\n\t\tstatus !== undefined ? `HTTP ${status}` : undefined,\n\t\tneonMessage ? `Neon API said: \"${neonMessage}\"` : undefined,\n\t\trequestId ? `request id ${requestId}` : undefined,\n\t].filter((part): part is string => part !== undefined);\n\treturn new PlatformError(\n\t\tErrorCode.Conflict,\n\t\t[\n\t\t\t`Hostname ${JSON.stringify(domain)} is already registered to another resource.`,\n\t\t\tapiParts.length > 0 ? `(${apiParts.join(\"; \")})` : undefined,\n\t\t\t\"Declare it only on the branch that owns it (use the branch closure), or delete it there first with `neon function domains delete`.\",\n\t\t]\n\t\t\t.filter((part): part is string => part !== undefined)\n\t\t\t.join(\" \"),\n\t\t{ cause: err, details: { ...err.details } },\n\t);\n}\n\nfunction enrichDeclaredCustomDomains(args: {\n\tresult: PushResult;\n\tpreview: RemotePreviewState | undefined;\n\tfunctions: ResolvedFunctionConfig[];\n\tapplied: AppliedChange[];\n\twarnings: string[];\n}): void {\n\tconst declared: Array<{ domain: string; slug: string }> = [];\n\tfor (const fn of args.functions) {\n\t\tfor (const domain of fn.customDomains ?? []) {\n\t\t\tdeclared.push({ domain, slug: fn.slug });\n\t\t}\n\t}\n\tif (declared.length === 0) return;\n\n\tconst blockedDomains = new Set(\n\t\targs.result.conflicts.flatMap((conflict) => {\n\t\t\tif (conflict.field !== \"customDomain\") return [];\n\t\t\tconst match = /^custom domain \"([^\"]+)\"/.exec(conflict.reason);\n\t\t\treturn match?.[1] !== undefined ? [match[1]] : [];\n\t\t}),\n\t);\n\n\tconst cnameByDomain = new Map<string, string>();\n\tfor (const remote of args.preview?.customDomains ?? []) {\n\t\tif (blockedDomains.has(remote.domain)) continue;\n\t\tcnameByDomain.set(remote.domain, remote.cnameTarget);\n\t}\n\tfor (const change of args.applied) {\n\t\tconst domain =\n\t\t\ttypeof change.details?.domain === \"string\"\n\t\t\t\t? change.details.domain\n\t\t\t\t: undefined;\n\t\tconst cnameTarget = change.details?.cnameTarget;\n\t\tif (domain !== undefined && typeof cnameTarget === \"string\") {\n\t\t\tcnameByDomain.set(domain, cnameTarget);\n\t\t}\n\t}\n\n\targs.result.customDomains = declared.map(({ domain, slug }) => {\n\t\tconst entry: { domain: string; slug: string; cnameTarget?: string } = {\n\t\t\tdomain,\n\t\t\tslug,\n\t\t};\n\t\tconst cnameTarget = cnameByDomain.get(domain);\n\t\tif (cnameTarget !== undefined) entry.cnameTarget = cnameTarget;\n\t\tif (cnameTarget === \"\") {\n\t\t\targs.warnings.push(\n\t\t\t\t`No CNAME target for ${domain}; this region has no custom-domains front door.`,\n\t\t\t);\n\t\t}\n\t\treturn entry;\n\t});\n}\n\nfunction triggerChangeDetails(\n\tfunctionSlug: string,\n\ttrigger: ResolvedFunctionTrigger,\n): Record<string, unknown> {\n\tif (trigger.type === \"schedule\") {\n\t\treturn {\n\t\t\tfunctionSlug,\n\t\t\ttype: trigger.type,\n\t\t\tcron: trigger.cron,\n\t\t\tenabled: trigger.enabled,\n\t\t};\n\t}\n\treturn {\n\t\tfunctionSlug,\n\t\ttype: trigger.type,\n\t\tbucketName: trigger.bucketName,\n\t\t...(trigger.prefix !== undefined ? { prefix: trigger.prefix } : {}),\n\t\tenabled: trigger.enabled,\n\t};\n}\n\nfunction createTriggerInput(\n\tfunctionSlug: string,\n\ttrigger: ResolvedFunctionTrigger,\n): CreateTriggerInput {\n\tif (trigger.type === \"schedule\") {\n\t\treturn {\n\t\t\ttype: \"schedule\",\n\t\t\tname: trigger.name,\n\t\t\tfunctionSlug,\n\t\t\tcron: trigger.cron,\n\t\t\tfunctionPath: trigger.functionPath,\n\t\t\tenabled: trigger.enabled,\n\t\t};\n\t}\n\treturn {\n\t\ttype: \"storage_object_created\",\n\t\tname: trigger.name,\n\t\tfunctionSlug,\n\t\tbucketName: trigger.bucketName,\n\t\t...(trigger.prefix !== undefined ? { prefix: trigger.prefix } : {}),\n\t\tfunctionPath: trigger.functionPath,\n\t\tenabled: trigger.enabled,\n\t};\n}\n\nfunction updateTriggerInput(\n\tfunctionSlug: string,\n\ttrigger: ResolvedFunctionTrigger,\n): UpdateTriggerInput {\n\tif (trigger.type === \"schedule\") {\n\t\treturn {\n\t\t\ttype: \"schedule\",\n\t\t\tname: trigger.name,\n\t\t\tfunctionSlug,\n\t\t\tcron: trigger.cron,\n\t\t\tfunctionPath: trigger.functionPath,\n\t\t\tenabled: trigger.enabled,\n\t\t};\n\t}\n\treturn {\n\t\ttype: \"storage_object_created\",\n\t\tname: trigger.name,\n\t\tfunctionSlug,\n\t\tbucketName: trigger.bucketName,\n\t\t...(trigger.prefix !== undefined ? { prefix: trigger.prefix } : {}),\n\t\tfunctionPath: trigger.functionPath,\n\t\tenabled: trigger.enabled,\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"push-config.js","names":[],"sources":["../../src/lib/push-config.ts"],"sourcesContent":["import {\n\ttype AppliedChange,\n\ttype Config,\n\ttype ConflictReport,\n\ttype CreateTriggerInput,\n\tcreateNeonApiFromOptions,\n\tdiffConfig,\n\tErrorCode,\n\ttype NeonApi,\n\ttype NeonBranchSnapshot,\n\ttype NeonCustomDomainSnapshot,\n\ttype PlanStep,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n\ttype PushResult,\n\ttype RemotePreviewState,\n\ttype RemoteServiceState,\n\ttype RemoteState,\n\ttype ResolvedBranchConfig,\n\ttype ResolvedFunctionConfig,\n\ttype ResolvedFunctionTrigger,\n\ttype ResolvedPreviewConfig,\n\tresolveConfig,\n\ttype UpdateTriggerInput,\n} from \"@neon/config\";\nimport type { FunctionBundler } from \"./function-bundle.js\";\n\n// Eager loading would evaluate esbuild for callers that provide their own bundler.\nconst makeDefaultBundleFunction =\n\t(onWarning: (message: string) => void): FunctionBundler =>\n\tasync (fn: ResolvedFunctionConfig): Promise<Uint8Array> => {\n\t\tconst { buildFunctionBundle } = await import(\"./function-bundle.js\");\n\t\treturn buildFunctionBundle(fn, { onWarning });\n\t};\n\nexport interface PushConfigOptions {\n\t/**\n\t * Neon project id. **Required** — the management API addresses every branch through\n\t * its project, so there is no way to push without it. `pushConfig` never creates a\n\t * project; resolve the id yourself (e.g. via neonctl) and pass it in.\n\t */\n\tprojectId: string;\n\t/**\n\t * Neon branch id (`br-…`). **Required.** `pushConfig` never creates a branch — it must\n\t * already exist on the project. Resolve names to ids before calling.\n\t */\n\tbranchId: string;\n\t/** Neon API key. Falls back to `NEON_API_KEY` / neonctl credentials. Ignored when `api` is supplied. */\n\tapiKey?: string;\n\t/** Neon API base URL. Falls back to `NEON_API_HOST`, then production. */\n\tapiHost?: string;\n\t/**\n\t * Inject a custom NeonApi adapter. Primarily used by tests; production callers can rely\n\t * on the default real adapter built from `apiKey`.\n\t */\n\tapi?: NeonApi;\n\t/**\n\t * Whether to evaluate the policy as if the target branch **already exists** (the value of\n\t * `branch.exists` passed to the `defineConfig({ branch: (branch) => … })` closure). Defaults to `true`.\n\t *\n\t * Set to `false` to evaluate the policy as a **branch creation** — used by\n\t * {@link createBranch} right after it provisions a new branch, so creation-time tuning\n\t * gated on `!branch.exists` (TTL, compute settings, `parent`) actually resolves instead of\n\t * hitting the \"existing branch, leave as-is\" path. Only affects policy evaluation; the\n\t * branch must still physically exist on Neon (`pushConfig` never creates one).\n\t */\n\tbranchExists?: boolean;\n\t/**\n\t * Auto-confirm overriding existing remote settings.\n\t *\n\t * When `true`, mutable drift on the selected branch (TTL, `protected` flag, compute\n\t * settings) is applied as actual mutations and the override-confirm prompt is\n\t * skipped. When `false` (default) the behaviour depends on whether `confirm` is\n\t * supplied:\n\t * - With `confirm`: the callback is asked whether to apply the override.\n\t * - Without `confirm`: drift is reported as a `PushConflictError` (legacy\n\t * non-interactive default — preserved so programmatic SDK callers don't\n\t * silently start mutating remote state).\n\t */\n\tupdateExisting?: boolean;\n\t/**\n\t * Auto-confirm pushing to a protected branch.\n\t *\n\t * When `true`, no protected-branch confirmation is asked. When `false` (default):\n\t * - With `confirm`: the callback is asked.\n\t * - Without `confirm`: the push proceeds (legacy SDK default).\n\t */\n\tallowProtectedBranch?: boolean;\n\t/**\n\t * Optional confirmation callback. Invoked once with a single context object before\n\t * any mutations run when the push needs confirmation: pushing to a protected\n\t * branch (unless `allowProtectedBranch` is `true`) and/or applying mutable drift\n\t * (unless `updateExisting` is `true`).\n\t *\n\t * Both prompts collapse into a single callback invocation when both apply, so the\n\t * CLI can render one combined \"are you sure?\" prompt.\n\t *\n\t * Resolves to `true` to proceed, `false` to abort with {@link PushAbortedError}.\n\t *\n\t * Never invoked on `dryRun`.\n\t */\n\tconfirm?: (context: PushConfirmContext) => boolean | Promise<boolean>;\n\t/**\n\t * Runs once after {@link confirm} approves (or was not needed) and before the first\n\t * mutation or function bundle. A throw aborts the push with nothing changed by it.\n\t * Never invoked on `dryRun`.\n\t */\n\tbeforeMutations?: () => void | Promise<void>;\n\t/** Inject to deploy without this package loading esbuild. */\n\tbundleFunction?: FunctionBundler;\n\t/**\n\t * When `true`, compute the full plan against the live remote state but **do not\n\t * execute any mutations**. The resulting `PushResult.applied` array records every\n\t * change that *would* run on a real push (with the same action / identifier / details\n\t * shape, so the existing CLI summary formatter just works), and conflicts are\n\t * reported instead of thrown.\n\t *\n\t * Used by `plan(config, branchId)` and any caller that wants a \"would this push do\n\t * something dangerous?\" check before invoking `pushConfig` for real.\n\t */\n\tdryRun?: boolean;\n}\n\n/**\n * Context handed to a {@link PushConfigOptions.confirm} callback. Both flags can be\n * `true` simultaneously when the push targets a protected branch *and* would override\n * existing settings — render a single combined prompt covering both reasons.\n */\nexport interface PushConfirmContext {\n\t/** Name of the target branch on Neon. */\n\tbranchName: string;\n\t/**\n\t * `true` when the target branch has the `protected` flag on Neon and the caller\n\t * did not pass `allowProtectedBranch: true`.\n\t */\n\tprotectedBranch: boolean;\n\t/**\n\t * `true` when the plan would override existing remote settings (TTL, `protected`\n\t * flag, compute settings on an existing endpoint) and the caller did not pass\n\t * `updateExisting: true`. Additive operations (enabling Neon Auth / Data API for\n\t * the first time) are **not** counted here — those are unambiguous and never\n\t * prompt.\n\t */\n\toverrideUpdates: boolean;\n\t/**\n\t * The settings that would be overridden, as current → desired, so the caller can show\n\t * what it is asking about. Empty when only {@link protectedBranch} applies.\n\t */\n\toverrides: readonly ConflictReport[];\n}\n\n/**\n * Push a Neon branch policy to a specific project + branch.\n *\n * Filesystem- and env-agnostic: the caller supplies an already-validated `Config` object\n * (from `defineConfig` / `loadConfigFromFile`) and explicit `projectId` + `branch` in\n * `options`. `pushConfig` performs no `.neon` lookups and reads no `NEON_*` env vars except the API credential/host resolution documented on `apiKey`/`apiHost`.\n *\n * It will **not** create a project or branch — both must already exist on Neon.\n */\nexport async function pushConfig(\n\tconfig: Config,\n\toptions: PushConfigOptions,\n): Promise<PushResult> {\n\tconst api = options.api ?? createApiFromOptions(options);\n\tconst projectId = options.projectId;\n\n\t// Collected from the built-in bundler and returned on the result. A caller that injects\n\t// its own `bundleFunction` reports for itself, so this stays empty for them.\n\tconst warnings: string[] = [];\n\n\tconst dryRun = options.dryRun === true;\n\tconst updateExisting = options.updateExisting === true;\n\tconst allowProtectedBranch = options.allowProtectedBranch === true;\n\n\t// Same scheduling as `pullConfig`: independent reads start together and are awaited in\n\t// the order they used to run, so the first error reported is unchanged.\n\tconst projectRead = started(() => api.getProject(projectId));\n\tconst listsRead = started(() =>\n\t\tPromise.all([\n\t\t\thandled(api.listBranches(projectId)),\n\t\t\thandled(api.listEndpoints(projectId)),\n\t\t]),\n\t);\n\tconst remoteProject = await projectRead;\n\tconst [branches, endpoints] = await listsRead;\n\tconst branch = resolveRemoteBranch(options.branchId, branches);\n\tconst resolved = resolveConfig(config, {\n\t\tname: branch.name,\n\t\tid: branch.id,\n\t\texists: options.branchExists !== false,\n\t\t...(branch.parentId ? { parentId: branch.parentId } : {}),\n\t\tisDefault: branch.isDefault,\n\t\tisProtected: branch.protected,\n\t\t...(branch.expiresAt ? { expiresAt: branch.expiresAt } : {}),\n\t});\n\tconst realtimeApi = hasRealtimePolicy(resolved)\n\t\t? requireRealtimeApi(api)\n\t\t: undefined;\n\tconst realtimeRead = realtimeApi\n\t\t? started(() =>\n\t\t\t\trealtimeApi.getProjectBranchRealtime(\n\t\t\t\t\tremoteProject.id,\n\t\t\t\t\tbranch.id,\n\t\t\t\t),\n\t\t\t)\n\t\t: undefined;\n\tconst servicesRead = started(() =>\n\t\tresolveServiceState({\n\t\t\tapi,\n\t\t\tprojectId: remoteProject.id,\n\t\t\tbranch,\n\t\t\twantsAuth: resolved.authEnabled,\n\t\t\twantsDataApi:\n\t\t\t\tresolved.dataApiEnabled ||\n\t\t\t\tresolved.dataApiPolicy === \"disabled\",\n\t\t}),\n\t);\n\t// Only fetch Preview state when the policy actually uses it — and within that, only the\n\t// specific features the policy declares. So a policy that uses functions never probes\n\t// the AI Gateway, and `apply`/`plan` only fail on a Preview feature being unavailable\n\t// (404/503) when the policy actually asks for it.\n\tconst desiredPreview = resolved.preview;\n\tconst previewRead = desiredPreview\n\t\t? started(() =>\n\t\t\t\tresolvePreviewState({\n\t\t\t\t\tapi,\n\t\t\t\t\tprojectId: remoteProject.id,\n\t\t\t\t\tbranchId: branch.id,\n\t\t\t\t\tdesired: desiredPreview,\n\t\t\t\t\twantsTriggers: (resolved.triggers?.length ?? 0) > 0,\n\t\t\t\t}),\n\t\t\t)\n\t\t: undefined;\n\tconst services = await servicesRead;\n\tconst remote: RemoteState = {\n\t\tprojectId: remoteProject.id,\n\t\tbranch,\n\t\tendpoint: endpoints.find(\n\t\t\t(ep) => ep.type === \"read_write\" && ep.branchId === branch.id,\n\t\t),\n\t\tservices,\n\t};\n\tif (realtimeRead) {\n\t\tremote.realtime = await realtimeRead;\n\t}\n\tif (previewRead) {\n\t\tremote.preview = await previewRead;\n\t}\n\n\t// Always compute the plan with `updateExisting: true` so we can see what *would* be\n\t// overridden. The decision of whether to apply / prompt / fail is gated below using\n\t// the recorded steps.\n\tconst diff = diffConfig(resolved, remote, { updateExisting: true });\n\tconst overrideSteps = diff.plan.filter(isOverrideStep);\n\tconst needsOverrideConfirm = overrideSteps.length > 0 && !updateExisting;\n\tconst needsProtectedConfirm = branch.protected && !allowProtectedBranch;\n\n\tif (!dryRun && diff.conflicts.length > 0) {\n\t\tthrow new PushConflictError(diff.conflicts);\n\t}\n\n\tif (!dryRun && (needsOverrideConfirm || needsProtectedConfirm)) {\n\t\tif (options.confirm) {\n\t\t\tconst ok = await options.confirm({\n\t\t\t\tbranchName: branch.name,\n\t\t\t\tprotectedBranch: needsProtectedConfirm,\n\t\t\t\toverrideUpdates: needsOverrideConfirm,\n\t\t\t\t// The non-overriding diff reports exactly the drift as conflicts; the\n\t\t\t\t// override-able plan above has already ruled out every other conflict.\n\t\t\t\toverrides: needsOverrideConfirm\n\t\t\t\t\t? diffConfig(resolved, remote, { updateExisting: false })\n\t\t\t\t\t\t\t.conflicts\n\t\t\t\t\t: [],\n\t\t\t});\n\t\t\tif (!ok) {\n\t\t\t\tconst reasons: (\"protected-branch\" | \"override-updates\")[] = [];\n\t\t\t\tif (needsProtectedConfirm) reasons.push(\"protected-branch\");\n\t\t\t\tif (needsOverrideConfirm) reasons.push(\"override-updates\");\n\t\t\t\tthrow new PushAbortedError(branch.name, reasons);\n\t\t\t}\n\t\t} else if (needsOverrideConfirm) {\n\t\t\t// Legacy non-interactive fallback: surface the would-be drift as a\n\t\t\t// `PushConflictError` so programmatic callers that skipped both\n\t\t\t// `updateExisting` and `confirm` see the previous fail-fast behavior.\n\t\t\tconst legacy = diffConfig(resolved, remote, {\n\t\t\t\tupdateExisting: false,\n\t\t\t});\n\t\t\tthrow new PushConflictError(legacy.conflicts);\n\t\t}\n\t\t// Protected branch + no confirm callback: legacy default proceeds without\n\t\t// any extra check (no programmatic regression).\n\t}\n\n\tif (!dryRun) await options.beforeMutations?.();\n\n\tconst applied: AppliedChange[] = [\n\t\t{ kind: \"branch\", action: \"noop\", identifier: branch.name },\n\t];\n\n\tconst branchById = new Map(branches.map((b) => [b.id, b] as const));\n\tconst branchByName = new Map(branches.map((b) => [b.name, b] as const));\n\tconst ctx: ApplyContext = {\n\t\tapi,\n\t\tremoteProjectId: remoteProject.id,\n\t\tbranchById,\n\t\tbranchByName,\n\t\tbundleFunction:\n\t\t\toptions.bundleFunction ??\n\t\t\tmakeDefaultBundleFunction((message) => {\n\t\t\t\twarnings.push(message);\n\t\t\t}),\n\t\tdeploymentIdBySlug: new Map(),\n\t};\n\n\tfor (const step of diff.plan) {\n\t\tconst change = dryRun\n\t\t\t? synthesizeAppliedChange(step)\n\t\t\t: await applyStep(step, ctx);\n\t\tapplied.push(change);\n\t}\n\n\t// Surface each deployed function's invocation URL on its applied change so callers\n\t// (e.g. neonctl) can show users where to call it right after a push.\n\tawait enrichFunctionInvocationUrls({\n\t\tapi,\n\t\tprojectId: remoteProject.id,\n\t\tbranchId: branch.id,\n\t\tplan: diff.plan,\n\t\tapplied,\n\t\tpreview: remote.preview,\n\t\tdryRun,\n\t});\n\n\tconst result: PushResult = {\n\t\tprojectId: remoteProject.id,\n\t\tbranchId: branch.id,\n\t\tbranchName: branch.name,\n\t\tdryRun,\n\t\tapplied,\n\t\tconflicts: diff.conflicts,\n\t\twarnings,\n\t};\n\tif (remoteProject.orgId) result.orgId = remoteProject.orgId;\n\tenrichDeclaredCustomDomains({\n\t\tresult,\n\t\tpreview: remote.preview,\n\t\tfunctions: resolved.preview?.functions ?? [],\n\t\tapplied,\n\t\twarnings,\n\t});\n\treturn result;\n}\n\nfunction isOverrideStep(step: PlanStep): boolean {\n\treturn (\n\t\tstep.kind === \"update-branch-ttl\" ||\n\t\tstep.kind === \"update-branch-protected\" ||\n\t\tstep.kind === \"update-endpoint\" ||\n\t\tstep.kind === \"update-realtime\" ||\n\t\tstep.kind === \"disable-realtime\" ||\n\t\tstep.kind === \"update-data-api\" ||\n\t\tstep.kind === \"disable-data-api\" ||\n\t\tstep.kind === \"retarget-custom-domain\"\n\t);\n}\n\n/**\n * Build an {@link AppliedChange} from a {@link PlanStep} without calling the Neon API.\n * Used by dry-run mode so callers see the same record shape they would on a live push,\n * just with no side effects. Identifiers are the branch names from the plan; any\n * sub-resource ids (`branchId`, `endpointId`) flow through unchanged when known.\n */\nfunction synthesizeAppliedChange(step: PlanStep): AppliedChange {\n\tswitch (step.kind) {\n\t\tcase \"enable-realtime\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: \"realtime\",\n\t\t\t\t...(step.input?.allowedOrigins !== undefined\n\t\t\t\t\t? { details: { allowedOrigins: step.input.allowedOrigins } }\n\t\t\t\t\t: {}),\n\t\t\t};\n\t\tcase \"update-realtime\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: \"realtime\",\n\t\t\t\tdetails: {\n\t\t\t\t\tfield: \"allowedOrigins\",\n\t\t\t\t\tallowedOrigins: step.input.allowedOrigins,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"disable-realtime\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"delete\",\n\t\t\t\tidentifier: \"realtime\",\n\t\t\t};\n\t\tcase \"update-branch-ttl\":\n\t\t\treturn {\n\t\t\t\tkind: \"branch\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: step.branchName,\n\t\t\t\tdetails: { field: \"ttl\", expiresAt: step.expiresAt },\n\t\t\t};\n\t\tcase \"update-branch-protected\":\n\t\t\treturn {\n\t\t\t\tkind: \"branch\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: step.branchName,\n\t\t\t\tdetails: { field: \"protected\", protected: step.protected },\n\t\t\t};\n\t\tcase \"update-endpoint\":\n\t\t\treturn {\n\t\t\t\tkind: \"branch\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: step.branchName,\n\t\t\t\tdetails: {\n\t\t\t\t\tfield: \"computeSettings\",\n\t\t\t\t\tendpointId: step.endpointId,\n\t\t\t\t\tsettings: step.settings,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"enable-auth\":\n\t\t\t// Pure branch on/off toggle: the target branch is redundant (same on\n\t\t\t// every row) and the database is auto-derived, not policy-chosen — so\n\t\t\t// there is nothing meaningful to surface in the change summary.\n\t\t\treturn { kind: \"service\", action: \"create\", identifier: \"auth\" };\n\t\tcase \"enable-data-api\":\n\t\t\treturn { kind: \"service\", action: \"create\", identifier: \"dataApi\" };\n\t\tcase \"update-data-api\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: \"dataApi\",\n\t\t\t\tdetails: { field: \"settings\", settings: step.settings },\n\t\t\t};\n\t\tcase \"disable-data-api\":\n\t\t\treturn { kind: \"service\", action: \"delete\", identifier: \"dataApi\" };\n\t\tcase \"create-bucket\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: `bucket:${step.bucketName}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tbucketName: step.bucketName,\n\t\t\t\t\taccessLevel: step.accessLevel,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"deploy-function\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\t// The first deployment creates the function; a later one updates it.\n\t\t\t\taction: step.functionExists ? \"update\" : \"create\",\n\t\t\t\tidentifier: `function:${step.fn.slug}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tslug: step.fn.slug,\n\t\t\t\t\tsource: step.fn.source,\n\t\t\t\t\truntime: step.fn.runtime,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"create-trigger\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: `trigger:${step.functionSlug}:${step.trigger.name}`,\n\t\t\t\tdetails: triggerChangeDetails(step.functionSlug, step.trigger),\n\t\t\t};\n\t\tcase \"update-trigger\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: `trigger:${step.functionSlug}:${step.trigger.name}`,\n\t\t\t\tdetails: triggerChangeDetails(step.functionSlug, step.trigger),\n\t\t\t};\n\t\tcase \"register-custom-domain\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: `domain:${step.domain}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tdomain: step.domain,\n\t\t\t\t\tslug: step.functionSlug,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"retarget-custom-domain\":\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: `domain:${step.domain}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tdomain: step.domain,\n\t\t\t\t\tslug: step.functionSlug,\n\t\t\t\t\tpreviousSlug: step.previousSlug,\n\t\t\t\t},\n\t\t\t};\n\t}\n}\n\nfunction createApiFromOptions(options: PushConfigOptions): NeonApi {\n\treturn createNeonApiFromOptions(\"pushConfig\", {\n\t\t...(options.apiKey ? { apiKey: options.apiKey } : {}),\n\t\t...(options.apiHost ? { apiHost: options.apiHost } : {}),\n\t});\n}\n\nfunction resolveRemoteBranch(\n\tbranchId: string,\n\tbranches: NeonBranchSnapshot[],\n): NeonBranchSnapshot {\n\tconst found = branches.find((b) => b.id === branchId);\n\tif (found) return found;\n\tthrow new PlatformError(\n\t\tErrorCode.BranchNotFound,\n\t\t[\n\t\t\t`pushConfig: branch id ${JSON.stringify(branchId)} does not exist on the project.`,\n\t\t\t`Available branches: ${branches.map((b) => `${b.name} (${b.id})`).join(\", \") || \"(none)\"}.`,\n\t\t\t\"Pass an existing branch id, or create the branch first with the neonctl CLI.\",\n\t\t].join(\" \"),\n\t\t{ details: { branchId, available: branches.map((b) => b.id) } },\n\t);\n}\n\n/**\n * Starts a read now and keeps an unread rejection from crashing the process; the caller\n * awaits it (and sees the error) when its turn comes. The read is called synchronously and\n * its own promise returned, so errors surface in the same order as a direct call; a\n * synchronous throw becomes the returned rejection.\n */\nfunction started<T>(read: () => Promise<T>): Promise<T> {\n\tlet promise: Promise<T>;\n\ttry {\n\t\tpromise = read();\n\t} catch (error) {\n\t\tpromise = Promise.reject(error);\n\t}\n\tpromise.catch(() => undefined);\n\treturn promise;\n}\n\n/**\n * Marks a `Promise.all` member's rejection as handled, so a later member's synchronous\n * throw cannot leave it unobserved. `Promise.all` still reports it.\n */\nfunction handled<T>(promise: Promise<T>): Promise<T> {\n\tpromise.catch(() => undefined);\n\treturn promise;\n}\n\n/**\n * Pre-fetch the current state of branch-scoped integrations on the selected branch.\n */\nasync function resolveServiceState(args: {\n\tapi: NeonApi;\n\tprojectId: string;\n\tbranch: NeonBranchSnapshot;\n\twantsAuth: boolean;\n\twantsDataApi: boolean;\n}): Promise<RemoteServiceState> {\n\tconst { api, projectId, branch, wantsAuth, wantsDataApi } = args;\n\tif (!wantsAuth && !wantsDataApi) {\n\t\treturn {\n\t\t\tdatabaseName: \"neondb\",\n\t\t\tauthEnabled: false,\n\t\t\tdataApiEnabled: false,\n\t\t};\n\t}\n\n\tconst databaseName = await pickServiceDatabaseName(\n\t\tapi,\n\t\tprojectId,\n\t\tbranch.id,\n\t);\n\n\tconst [auth, dataApi] = await Promise.all([\n\t\twantsAuth\n\t\t\t? handled(api.getNeonAuth(projectId, branch.id))\n\t\t\t: Promise.resolve(null),\n\t\twantsDataApi\n\t\t\t? handled(api.getNeonDataApi(projectId, branch.id, databaseName))\n\t\t\t: Promise.resolve(null),\n\t]);\n\tconst result: RemoteServiceState = {\n\t\tdatabaseName,\n\t\tauthEnabled: auth !== null,\n\t\tdataApiEnabled: dataApi !== null,\n\t};\n\t// Carry the current Data API settings (when reported) so the diff can detect settings\n\t// drift and plan an update. `null` distinguishes \"enabled but not reported\" from \"absent\".\n\tif (dataApi) result.dataApiSettings = dataApi.settings ?? null;\n\treturn result;\n}\n\n/**\n * Pre-fetch the current state of branch-scoped Preview features (buckets, functions) so the\n * diff can be computed additively. Only called when the policy has a `preview` block.\n *\n * The AI Gateway is not probed: it is always available (credential-gated, not per-branch\n * provisioned), so `preview.aiGateway` produces no plan step — it only drives the branch\n * credential's `ai_gateway:invoke` scope and the gateway env vars (`@neon/env`).\n */\nasync function resolvePreviewState(args: {\n\tapi: NeonApi;\n\tprojectId: string;\n\tbranchId: string;\n\tdesired: ResolvedPreviewConfig;\n\twantsTriggers: boolean;\n}): Promise<RemotePreviewState> {\n\tconst { api, projectId, branchId, desired, wantsTriggers } = args;\n\t// Read only the Preview features the policy declares: undeclared features can never\n\t// produce a plan step (see diffConfig), so probing them is pure waste — and would make\n\t// `plan`/`apply` fail on a feature the user didn't ask for if it's unavailable in the\n\t// project/region. A declared-but-unavailable feature still throws (failing the push),\n\t// which is the intended signal to enable it first.\n\tconst wantsCustomDomains = desired.functions.some(\n\t\t(fn) => (fn.customDomains?.length ?? 0) > 0,\n\t);\n\tconst customDomainApi = wantsCustomDomains\n\t\t? requireCustomDomainApi(api)\n\t\t: undefined;\n\tconst [buckets, functions, triggers, customDomains] = await Promise.all([\n\t\tdesired.buckets.length > 0\n\t\t\t? handled(api.listBranchBuckets(projectId, branchId))\n\t\t\t: Promise.resolve([]),\n\t\tdesired.functions.length > 0\n\t\t\t? handled(api.listBranchFunctions(projectId, branchId))\n\t\t\t: Promise.resolve([]),\n\t\twantsTriggers\n\t\t\t? handled(api.listBranchTriggers(projectId, branchId))\n\t\t\t: Promise.resolve([]),\n\t\tcustomDomainApi\n\t\t\t? handled(\n\t\t\t\t\tcustomDomainApi.listBranchCustomDomains(\n\t\t\t\t\t\tprojectId,\n\t\t\t\t\t\tbranchId,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t: Promise.resolve([]),\n\t]);\n\tconst preview: RemotePreviewState = { buckets, functions, triggers };\n\tif (wantsCustomDomains) preview.customDomains = customDomains;\n\treturn preview;\n}\n\n/**\n * Resolve the database name for a Data API integration. Auto-pick when the branch has\n * exactly one database; otherwise fall back to Neon's default (`neondb`) so the call\n * stays useful even on branches with multiple databases — push doesn't have a way to\n * surface a \"pick one\" prompt the way `fetchEnv` does.\n */\nasync function pickServiceDatabaseName(\n\tapi: NeonApi,\n\tprojectId: string,\n\tbranchId: string,\n): Promise<string> {\n\tconst databases = await api.listBranchDatabases(projectId, branchId);\n\tif (databases.length === 1) return databases[0].name;\n\tconst neondb = databases.find((d) => d.name === \"neondb\");\n\tif (neondb) return neondb.name;\n\treturn databases[0]?.name ?? \"neondb\";\n}\n\ninterface ApplyContext {\n\tapi: NeonApi;\n\tremoteProjectId: string;\n\tbranchById: Map<string, NeonBranchSnapshot>;\n\tbranchByName: Map<string, NeonBranchSnapshot>;\n\tbundleFunction: FunctionBundler;\n\tdeploymentIdBySlug: Map<string, number>;\n}\n\nasync function applyStep(\n\tstep: PlanStep,\n\tctx: ApplyContext,\n): Promise<AppliedChange> {\n\tswitch (step.kind) {\n\t\tcase \"enable-realtime\":\n\t\tcase \"update-realtime\": {\n\t\t\tawait requireRealtimeApi(ctx.api).enableProjectBranchRealtime(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tstep.input,\n\t\t\t);\n\t\t\treturn synthesizeAppliedChange(step);\n\t\t}\n\t\tcase \"disable-realtime\": {\n\t\t\tawait requireRealtimeApi(ctx.api).disableProjectBranchRealtime(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t);\n\t\t\treturn synthesizeAppliedChange(step);\n\t\t}\n\t\tcase \"update-branch-ttl\": {\n\t\t\tconst updated = await ctx.api.updateBranch(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\t{\n\t\t\t\t\texpiresAt: step.expiresAt ?? null,\n\t\t\t\t},\n\t\t\t);\n\t\t\tctx.branchById.set(updated.id, updated);\n\t\t\tctx.branchByName.set(updated.name, updated);\n\t\t\treturn {\n\t\t\t\tkind: \"branch\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: updated.name,\n\t\t\t\tdetails: { field: \"ttl\", expiresAt: step.expiresAt },\n\t\t\t};\n\t\t}\n\t\tcase \"update-branch-protected\": {\n\t\t\tconst updated = await ctx.api.updateBranch(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\t{ protected: step.protected },\n\t\t\t);\n\t\t\tctx.branchById.set(updated.id, updated);\n\t\t\tctx.branchByName.set(updated.name, updated);\n\t\t\treturn {\n\t\t\t\tkind: \"branch\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: updated.name,\n\t\t\t\tdetails: { field: \"protected\", protected: step.protected },\n\t\t\t};\n\t\t}\n\t\tcase \"update-endpoint\": {\n\t\t\tconst updated = await ctx.api.updateEndpoint(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.endpointId,\n\t\t\t\tstep.settings,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"branch\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: step.branchName,\n\t\t\t\tdetails: {\n\t\t\t\t\tfield: \"computeSettings\",\n\t\t\t\t\tendpointId: updated.id,\n\t\t\t\t\tsettings: step.settings,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tcase \"enable-auth\": {\n\t\t\tawait ctx.api.enableNeonAuth(ctx.remoteProjectId, step.branchId, {\n\t\t\t\t...(step.databaseName\n\t\t\t\t\t? { databaseName: step.databaseName }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: \"auth\",\n\t\t\t};\n\t\t}\n\t\tcase \"enable-data-api\": {\n\t\t\tawait ctx.api.enableProjectBranchDataApi(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tstep.databaseName,\n\t\t\t\tstep.input,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: \"dataApi\",\n\t\t\t};\n\t\t}\n\t\tcase \"update-data-api\": {\n\t\t\tawait ctx.api.updateProjectBranchDataApi(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tstep.databaseName,\n\t\t\t\tstep.settings,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: \"dataApi\",\n\t\t\t\tdetails: { field: \"settings\", settings: step.settings },\n\t\t\t};\n\t\t}\n\t\tcase \"disable-data-api\": {\n\t\t\tawait ctx.api.deleteProjectBranchDataApi(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tstep.databaseName,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"delete\",\n\t\t\t\tidentifier: \"dataApi\",\n\t\t\t};\n\t\t}\n\t\tcase \"create-bucket\": {\n\t\t\tawait ctx.api.createBranchBucket(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\t{ name: step.bucketName, accessLevel: step.accessLevel },\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: `bucket:${step.bucketName}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tbucketName: step.bucketName,\n\t\t\t\t\taccessLevel: step.accessLevel,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tcase \"deploy-function\": {\n\t\t\tconst bundle = await ctx.bundleFunction(step.fn);\n\t\t\t// Neon creates the function on its first deployment — there is no separate\n\t\t\t// create call — so a single deploy both creates (when absent) and ships code.\n\t\t\tconst deployment = await ctx.api.deployBranchFunction(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tstep.fn.slug,\n\t\t\t\t{\n\t\t\t\t\tbundle,\n\t\t\t\t\truntime: step.fn.runtime,\n\t\t\t\t\tenvironment: step.fn.env,\n\t\t\t\t},\n\t\t\t);\n\t\t\tctx.deploymentIdBySlug.set(step.fn.slug, deployment.id);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: step.functionExists ? \"update\" : \"create\",\n\t\t\t\tidentifier: `function:${step.fn.slug}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tslug: step.fn.slug,\n\t\t\t\t\tsource: step.fn.source,\n\t\t\t\t\truntime: step.fn.runtime,\n\t\t\t\t\tdeploymentId: deployment.id,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tcase \"create-trigger\": {\n\t\t\tawait ctx.api.createBranchTrigger(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tcreateTriggerInput(step.functionSlug, step.trigger),\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: `trigger:${step.functionSlug}:${step.trigger.name}`,\n\t\t\t\tdetails: triggerChangeDetails(step.functionSlug, step.trigger),\n\t\t\t};\n\t\t}\n\t\tcase \"update-trigger\": {\n\t\t\tawait ctx.api.updateBranchTrigger(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tstep.triggerId,\n\t\t\t\tupdateTriggerInput(step.functionSlug, step.trigger),\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: `trigger:${step.functionSlug}:${step.trigger.name}`,\n\t\t\t\tdetails: triggerChangeDetails(step.functionSlug, step.trigger),\n\t\t\t};\n\t\t}\n\t\tcase \"register-custom-domain\": {\n\t\t\tconst methods = requireCustomDomainApi(ctx.api);\n\t\t\tlet snapshot: NeonCustomDomainSnapshot;\n\t\t\ttry {\n\t\t\t\tsnapshot = await methods.registerBranchCustomDomain(\n\t\t\t\t\tctx.remoteProjectId,\n\t\t\t\t\tstep.branchId,\n\t\t\t\t\t{ domain: step.domain, functionSlug: step.functionSlug },\n\t\t\t\t);\n\t\t\t} catch (err) {\n\t\t\t\tthrow rewriteCustomDomainConflict(err, step.domain);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"create\",\n\t\t\t\tidentifier: `domain:${step.domain}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tdomain: snapshot.domain,\n\t\t\t\t\tslug: step.functionSlug,\n\t\t\t\t\tcnameTarget: snapshot.cnameTarget,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tcase \"retarget-custom-domain\": {\n\t\t\tconst methods = requireCustomDomainApi(ctx.api);\n\t\t\tconst deploymentId = ctx.deploymentIdBySlug.get(step.functionSlug);\n\t\t\tif (deploymentId === undefined) {\n\t\t\t\tthrow new PlatformError(\n\t\t\t\t\tErrorCode.ServerError,\n\t\t\t\t\t`Cannot retarget a custom domain onto ${JSON.stringify(step.functionSlug)}: this apply did not deploy that function.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait waitForCompletedFunctionDeployment({\n\t\t\t\tapi: ctx.api,\n\t\t\t\tprojectId: ctx.remoteProjectId,\n\t\t\t\tbranchId: step.branchId,\n\t\t\t\tslug: step.functionSlug,\n\t\t\t\tdeploymentId,\n\t\t\t});\n\t\t\tconst observed = (\n\t\t\t\tawait methods.listBranchCustomDomains(\n\t\t\t\t\tctx.remoteProjectId,\n\t\t\t\t\tstep.branchId,\n\t\t\t\t)\n\t\t\t).find((item) => item.domain === step.domain);\n\t\t\tif (\n\t\t\t\tobserved === undefined ||\n\t\t\t\tobserved.entityType !== \"function\" ||\n\t\t\t\tobserved.entityId !== step.previousSlug\n\t\t\t) {\n\t\t\t\tconst seen =\n\t\t\t\t\tobserved === undefined\n\t\t\t\t\t\t? \"no registration\"\n\t\t\t\t\t\t: `${observed.entityType} ${JSON.stringify(observed.entityId)}`;\n\t\t\t\tthrow new PlatformError(\n\t\t\t\t\tErrorCode.Conflict,\n\t\t\t\t\t`Cannot retarget ${JSON.stringify(step.domain)}: planned owner was function ${JSON.stringify(step.previousSlug)}; observed ${seen}. DELETE was not attempted.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait methods.deleteBranchCustomDomain(\n\t\t\t\tctx.remoteProjectId,\n\t\t\t\tstep.branchId,\n\t\t\t\tstep.domain,\n\t\t\t);\n\t\t\tlet snapshot: NeonCustomDomainSnapshot;\n\t\t\ttry {\n\t\t\t\tsnapshot = await methods.registerBranchCustomDomain(\n\t\t\t\t\tctx.remoteProjectId,\n\t\t\t\t\tstep.branchId,\n\t\t\t\t\t{ domain: step.domain, functionSlug: step.functionSlug },\n\t\t\t\t);\n\t\t\t} catch (err) {\n\t\t\t\tconst rewritten = rewriteCustomDomainConflict(err, step.domain);\n\t\t\t\tconst message =\n\t\t\t\t\trewritten instanceof PlatformError\n\t\t\t\t\t\t? rewritten.message\n\t\t\t\t\t\t: rewritten instanceof Error\n\t\t\t\t\t\t\t? rewritten.message\n\t\t\t\t\t\t\t: String(rewritten);\n\t\t\t\tthrow new PlatformError(\n\t\t\t\t\trewritten instanceof PlatformError\n\t\t\t\t\t\t? rewritten.code\n\t\t\t\t\t\t: ErrorCode.ServerError,\n\t\t\t\t\t`Deleted the previous registration of ${JSON.stringify(step.domain)} (function ${JSON.stringify(step.previousSlug)}) but failed to register it on ${JSON.stringify(step.functionSlug)}. Inspect current ownership with \\`neon function domains list\\` before recovering. ${message}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tcause: rewritten instanceof Error ? rewritten : err,\n\t\t\t\t\t\tdetails:\n\t\t\t\t\t\t\trewritten instanceof PlatformError\n\t\t\t\t\t\t\t\t? { ...rewritten.details }\n\t\t\t\t\t\t\t\t: {},\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkind: \"service\",\n\t\t\t\taction: \"update\",\n\t\t\t\tidentifier: `domain:${step.domain}`,\n\t\t\t\tdetails: {\n\t\t\t\t\tdomain: snapshot.domain,\n\t\t\t\t\tslug: step.functionSlug,\n\t\t\t\t\tpreviousSlug: step.previousSlug,\n\t\t\t\t\tcnameTarget: snapshot.cnameTarget,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t}\n}\n\nfunction hasRealtimePolicy(resolved: ResolvedBranchConfig): boolean {\n\treturn (\n\t\tresolved.realtimePolicy !== undefined &&\n\t\tresolved.realtimePolicy !== \"omitted\"\n\t);\n}\n\nfunction requireRealtimeApi(api: NeonApi): {\n\tgetProjectBranchRealtime: NonNullable<NeonApi[\"getProjectBranchRealtime\"]>;\n\tenableProjectBranchRealtime: NonNullable<\n\t\tNeonApi[\"enableProjectBranchRealtime\"]\n\t>;\n\tdisableProjectBranchRealtime: NonNullable<\n\t\tNeonApi[\"disableProjectBranchRealtime\"]\n\t>;\n} {\n\tconst get = api.getProjectBranchRealtime;\n\tconst enable = api.enableProjectBranchRealtime;\n\tconst disable = api.disableProjectBranchRealtime;\n\tif (!get || !enable || !disable) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.FeatureUnavailable,\n\t\t\t\"This NeonApi adapter does not implement Realtime. Implement getProjectBranchRealtime, enableProjectBranchRealtime, and disableProjectBranchRealtime, or remove preview.realtime from neon.ts.\",\n\t\t);\n\t}\n\treturn {\n\t\tgetProjectBranchRealtime: get.bind(api),\n\t\tenableProjectBranchRealtime: enable.bind(api),\n\t\tdisableProjectBranchRealtime: disable.bind(api),\n\t};\n}\n\n/**\n * Add each deployed function's invocation URL to its applied-change `details` so callers\n * (e.g. neonctl) can show users where to call the function right after a push.\n *\n * The URL is read from the preview snapshot already fetched for the diff, which lists every\n * existing function with its `invocationUrl`. A function created by its *first* deployment in\n * this push is not in that snapshot, so when one is present we re-list the branch's functions\n * once to learn its freshly-minted URL. Skipped on dry-run (nothing was created) and\n * best-effort otherwise: a failed re-list omits the URL rather than failing a push that has\n * already applied.\n */\nasync function enrichFunctionInvocationUrls(args: {\n\tapi: NeonApi;\n\tprojectId: string;\n\tbranchId: string;\n\tplan: PlanStep[];\n\tapplied: AppliedChange[];\n\tpreview: RemotePreviewState | undefined;\n\tdryRun: boolean;\n}): Promise<void> {\n\tconst { api, projectId, branchId, plan, applied, preview, dryRun } = args;\n\tconst deployedSlugs = plan.flatMap((step) =>\n\t\tstep.kind === \"deploy-function\" ? [step.fn.slug] : [],\n\t);\n\tif (deployedSlugs.length === 0) return;\n\n\tconst urlBySlug = new Map<string, string>(\n\t\t(preview?.functions ?? []).map(\n\t\t\t(fn) => [fn.slug, fn.invocationUrl] as const,\n\t\t),\n\t);\n\n\t// A first-time deploy creates the function, so its URL isn't in the pre-fetch; re-list\n\t// once when any deployed slug is still missing a URL.\n\tconst hasMissingUrl = deployedSlugs.some((slug) => !urlBySlug.has(slug));\n\tif (hasMissingUrl && !dryRun) {\n\t\ttry {\n\t\t\tfor (const fn of await api.listBranchFunctions(\n\t\t\t\tprojectId,\n\t\t\t\tbranchId,\n\t\t\t)) {\n\t\t\t\turlBySlug.set(fn.slug, fn.invocationUrl);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Push already succeeded; surface what we can rather than failing here.\n\t\t}\n\t}\n\n\tfor (const change of applied) {\n\t\tconst slug = functionSlugFromIdentifier(change.identifier);\n\t\tif (slug === undefined) continue;\n\t\tconst invocationUrl = urlBySlug.get(slug);\n\t\tif (invocationUrl === undefined) continue;\n\t\tchange.details = { ...change.details, invocationUrl };\n\t}\n}\n\n/** Pull the function slug out of a `function:<slug>` applied-change identifier. */\nfunction functionSlugFromIdentifier(identifier: string): string | undefined {\n\tconst prefix = \"function:\";\n\treturn identifier.startsWith(prefix)\n\t\t? identifier.slice(prefix.length)\n\t\t: undefined;\n}\n\nasync function waitForCompletedFunctionDeployment(args: {\n\tapi: NeonApi;\n\tprojectId: string;\n\tbranchId: string;\n\tslug: string;\n\tdeploymentId: number;\n}): Promise<void> {\n\tconst get = args.api.getBranchFunction;\n\tif (!get) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.FeatureUnavailable,\n\t\t\t`Cannot retarget a custom domain onto ${JSON.stringify(args.slug)}: this NeonApi adapter does not implement getBranchFunction, so apply cannot confirm the function finished deploying.`,\n\t\t);\n\t}\n\tconst intervalMs =\n\t\tNumber(process.env.NEON_FUNCTIONS_POLL_INTERVAL_MS) || 2000;\n\tconst timeoutMs =\n\t\tNumber(process.env.NEON_FUNCTIONS_POLL_TIMEOUT_MS) || 600_000;\n\tconst deadline = Date.now() + timeoutMs;\n\tfor (;;) {\n\t\tconst fn = await get.call(\n\t\t\targs.api,\n\t\t\targs.projectId,\n\t\t\targs.branchId,\n\t\t\targs.slug,\n\t\t);\n\t\tconst dep = fn.currentDeployment;\n\t\t// GET can still report the previous deployment after this apply's POST returns.\n\t\tif (dep !== undefined && dep.id > args.deploymentId) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.ServerError,\n\t\t\t\t`Cannot retarget a custom domain onto ${JSON.stringify(args.slug)}: current deployment is ${dep.id}, this apply submitted ${args.deploymentId}; left the previous custom-domain registration in place.`,\n\t\t\t);\n\t\t}\n\t\tif (dep !== undefined && dep.id === args.deploymentId) {\n\t\t\tif (dep.status === \"completed\") return;\n\t\t\tif (dep.status === \"failed\") {\n\t\t\t\tthrow new PlatformError(\n\t\t\t\t\tErrorCode.ServerError,\n\t\t\t\t\t`Deployment of function ${JSON.stringify(args.slug)} failed; left the previous custom-domain registration in place.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (Date.now() >= deadline) {\n\t\t\tthrow new PlatformError(\n\t\t\t\tErrorCode.ServerError,\n\t\t\t\t`Timed out waiting for function ${JSON.stringify(args.slug)} to finish deploying; left the previous custom-domain registration in place.`,\n\t\t\t);\n\t\t}\n\t\tawait new Promise((resolve) => setTimeout(resolve, intervalMs));\n\t}\n}\n\nfunction requireCustomDomainApi(api: NeonApi): {\n\tlistBranchCustomDomains: NonNullable<NeonApi[\"listBranchCustomDomains\"]>;\n\tregisterBranchCustomDomain: NonNullable<\n\t\tNeonApi[\"registerBranchCustomDomain\"]\n\t>;\n\tdeleteBranchCustomDomain: NonNullable<NeonApi[\"deleteBranchCustomDomain\"]>;\n} {\n\tconst list = api.listBranchCustomDomains;\n\tconst register = api.registerBranchCustomDomain;\n\tconst remove = api.deleteBranchCustomDomain;\n\tif (!list || !register || !remove) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.FeatureUnavailable,\n\t\t\t\"This NeonApi adapter does not implement custom domains. Implement listBranchCustomDomains, registerBranchCustomDomain, and deleteBranchCustomDomain, or remove customDomains from neon.ts.\",\n\t\t);\n\t}\n\treturn {\n\t\tlistBranchCustomDomains: list.bind(api),\n\t\tregisterBranchCustomDomain: register.bind(api),\n\t\tdeleteBranchCustomDomain: remove.bind(api),\n\t};\n}\n\nfunction rewriteCustomDomainConflict(err: unknown, domain: string): unknown {\n\tif (!(err instanceof PlatformError) || err.code !== ErrorCode.Conflict) {\n\t\treturn err;\n\t}\n\tconst neonMessage =\n\t\ttypeof err.details.neonMessage === \"string\"\n\t\t\t? err.details.neonMessage\n\t\t\t: undefined;\n\tconst requestId =\n\t\ttypeof err.details.requestId === \"string\"\n\t\t\t? err.details.requestId\n\t\t\t: undefined;\n\tconst status =\n\t\ttypeof err.details.status === \"number\" ? err.details.status : undefined;\n\tconst apiParts = [\n\t\tstatus !== undefined ? `HTTP ${status}` : undefined,\n\t\tneonMessage ? `Neon API said: \"${neonMessage}\"` : undefined,\n\t\trequestId ? `request id ${requestId}` : undefined,\n\t].filter((part): part is string => part !== undefined);\n\treturn new PlatformError(\n\t\tErrorCode.Conflict,\n\t\t[\n\t\t\t`Hostname ${JSON.stringify(domain)} is already registered to another resource.`,\n\t\t\tapiParts.length > 0 ? `(${apiParts.join(\"; \")})` : undefined,\n\t\t\t\"Declare it only on the branch that owns it (use the branch closure), or delete it there first with `neon function domains delete`.\",\n\t\t]\n\t\t\t.filter((part): part is string => part !== undefined)\n\t\t\t.join(\" \"),\n\t\t{ cause: err, details: { ...err.details } },\n\t);\n}\n\nfunction enrichDeclaredCustomDomains(args: {\n\tresult: PushResult;\n\tpreview: RemotePreviewState | undefined;\n\tfunctions: ResolvedFunctionConfig[];\n\tapplied: AppliedChange[];\n\twarnings: string[];\n}): void {\n\tconst declared: Array<{ domain: string; slug: string }> = [];\n\tfor (const fn of args.functions) {\n\t\tfor (const domain of fn.customDomains ?? []) {\n\t\t\tdeclared.push({ domain, slug: fn.slug });\n\t\t}\n\t}\n\tif (declared.length === 0) return;\n\n\tconst blockedDomains = new Set(\n\t\targs.result.conflicts.flatMap((conflict) => {\n\t\t\tif (conflict.field !== \"customDomain\") return [];\n\t\t\tconst match = /^custom domain \"([^\"]+)\"/.exec(conflict.reason);\n\t\t\treturn match?.[1] !== undefined ? [match[1]] : [];\n\t\t}),\n\t);\n\n\tconst cnameByDomain = new Map<string, string>();\n\tfor (const remote of args.preview?.customDomains ?? []) {\n\t\tif (blockedDomains.has(remote.domain)) continue;\n\t\tcnameByDomain.set(remote.domain, remote.cnameTarget);\n\t}\n\tfor (const change of args.applied) {\n\t\tconst domain =\n\t\t\ttypeof change.details?.domain === \"string\"\n\t\t\t\t? change.details.domain\n\t\t\t\t: undefined;\n\t\tconst cnameTarget = change.details?.cnameTarget;\n\t\tif (domain !== undefined && typeof cnameTarget === \"string\") {\n\t\t\tcnameByDomain.set(domain, cnameTarget);\n\t\t}\n\t}\n\n\targs.result.customDomains = declared.map(({ domain, slug }) => {\n\t\tconst entry: { domain: string; slug: string; cnameTarget?: string } = {\n\t\t\tdomain,\n\t\t\tslug,\n\t\t};\n\t\tconst cnameTarget = cnameByDomain.get(domain);\n\t\tif (cnameTarget !== undefined) entry.cnameTarget = cnameTarget;\n\t\tif (cnameTarget === \"\") {\n\t\t\targs.warnings.push(\n\t\t\t\t`No CNAME target for ${domain}; this region has no custom-domains front door.`,\n\t\t\t);\n\t\t}\n\t\treturn entry;\n\t});\n}\n\nfunction triggerChangeDetails(\n\tfunctionSlug: string,\n\ttrigger: ResolvedFunctionTrigger,\n): Record<string, unknown> {\n\tif (trigger.type === \"schedule\") {\n\t\treturn {\n\t\t\tfunctionSlug,\n\t\t\ttype: trigger.type,\n\t\t\tcron: trigger.cron,\n\t\t\tenabled: trigger.enabled,\n\t\t};\n\t}\n\treturn {\n\t\tfunctionSlug,\n\t\ttype: trigger.type,\n\t\tbucketName: trigger.bucketName,\n\t\t...(trigger.prefix !== undefined ? { prefix: trigger.prefix } : {}),\n\t\tenabled: trigger.enabled,\n\t};\n}\n\nfunction createTriggerInput(\n\tfunctionSlug: string,\n\ttrigger: ResolvedFunctionTrigger,\n): CreateTriggerInput {\n\tif (trigger.type === \"schedule\") {\n\t\treturn {\n\t\t\ttype: \"schedule\",\n\t\t\tname: trigger.name,\n\t\t\tfunctionSlug,\n\t\t\tcron: trigger.cron,\n\t\t\tfunctionPath: trigger.functionPath,\n\t\t\tenabled: trigger.enabled,\n\t\t};\n\t}\n\treturn {\n\t\ttype: \"storage_object_created\",\n\t\tname: trigger.name,\n\t\tfunctionSlug,\n\t\tbucketName: trigger.bucketName,\n\t\t...(trigger.prefix !== undefined ? { prefix: trigger.prefix } : {}),\n\t\tfunctionPath: trigger.functionPath,\n\t\tenabled: trigger.enabled,\n\t};\n}\n\nfunction updateTriggerInput(\n\tfunctionSlug: string,\n\ttrigger: ResolvedFunctionTrigger,\n): UpdateTriggerInput {\n\tif (trigger.type === \"schedule\") {\n\t\treturn {\n\t\t\ttype: \"schedule\",\n\t\t\tname: trigger.name,\n\t\t\tfunctionSlug,\n\t\t\tcron: trigger.cron,\n\t\t\tfunctionPath: trigger.functionPath,\n\t\t\tenabled: trigger.enabled,\n\t\t};\n\t}\n\treturn {\n\t\ttype: \"storage_object_created\",\n\t\tname: trigger.name,\n\t\tfunctionSlug,\n\t\tbucketName: trigger.bucketName,\n\t\t...(trigger.prefix !== undefined ? { prefix: trigger.prefix } : {}),\n\t\tfunctionPath: trigger.functionPath,\n\t\tenabled: trigger.enabled,\n\t};\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neon/config-runtime",
3
- "version": "1.8.0",
3
+ "version": "1.9.1",
4
4
  "description": "Imperative runtime for @neon/config: inspect/plan/apply a neon.ts policy against the Neon API and bundle + deploy Neon Functions. Pulls in esbuild; import this from CLIs and CI, not from neon.ts.",
5
5
  "keywords": [
6
6
  "neon",
@@ -47,14 +47,14 @@
47
47
  "tsdown": "^0.14.1",
48
48
  "typescript": "^5.9.0",
49
49
  "vitest": "^3.0.9",
50
- "@neon/e2e-harness": "0.0.0",
51
- "@neon/sdk": "7.0.1"
50
+ "@neon/sdk": "7.2.0",
51
+ "@neon/e2e-harness": "0.0.0"
52
52
  },
53
53
  "dependencies": {
54
54
  "@vercel/nft": "^1.10.2",
55
55
  "esbuild": "^0.28.1",
56
56
  "fflate": "^0.8.3",
57
- "@neon/config": "1.8.6"
57
+ "@neon/config": "1.9.1"
58
58
  },
59
59
  "engines": {
60
60
  "node": ">=20.19.0"