@neondatabase/config 0.2.1 → 0.4.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,4 +1,4 @@
1
- import { parseDuration, parseSuspendTimeout } from "./duration.js";
1
+ import { parseBranchTtl, parseSuspendTimeout } from "./duration.js";
2
2
  import { isWildcardPattern, validatePattern } from "./patterns.js";
3
3
  import { z } from "zod";
4
4
  //#region src/lib/schema.ts
@@ -51,13 +51,21 @@ const computeSettingsSchema = z.strictObject({
51
51
  message: `autoscalingLimitMinCu (${min}) must be <= autoscalingLimitMaxCu (${max})`
52
52
  });
53
53
  });
54
+ /** Object form of a service toggle (`{ enabled?: boolean }`). */
54
55
  const serviceToggleSchema = z.strictObject({ enabled: z.boolean().optional() });
56
+ /** A service toggle as written in a policy: `boolean` or `{ enabled?: boolean }`. */
57
+ const serviceToggleInputSchema = z.union([z.boolean(), serviceToggleSchema]);
55
58
  const postgresConfigSchema = z.strictObject({ computeSettings: computeSettingsSchema.optional() });
56
59
  /**
57
60
  * Branch-unique function slug. Mirrors the Neon Functions API path-segment rule
58
61
  * (`platform/internal/platform/functions/name.go`): 1–20 lowercase letters and digits.
62
+ * Used as the **key schema** of the `preview.functions` record, so a bad slug fails
63
+ * validation with a path pointing at the offending key and duplicate slugs are impossible
64
+ * by construction (object keys are unique).
59
65
  */
60
66
  const functionSlugSchema = z.string().regex(/^[a-z0-9]{1,20}$/, "function slug must be 1-20 lowercase letters and digits (no hyphens or other characters)");
67
+ /** Bucket name: 1–255 chars. Used as the key schema of the `preview.buckets` record. */
68
+ const bucketNameSchema = z.string().min(1).max(255);
61
69
  /**
62
70
  * Per-function environment map. Every value must be a defined string: a `process.env.X`
63
71
  * that is unset surfaces as `undefined` and is rejected here (rather than silently
@@ -79,79 +87,47 @@ const functionDevConfigSchema = z.strictObject({
79
87
  port: devPortSchema.optional(),
80
88
  portless: z.boolean().optional()
81
89
  });
82
- const functionConfigSchema = z.strictObject({
83
- slug: functionSlugSchema,
90
+ const runtimeSchema = z.literal("nodejs24");
91
+ /**
92
+ * Static definition of a function (existence). The slug is the record key (validated by
93
+ * {@link functionSlugSchema}), so it is not a field here. Deploy tuning (`runtime`) lives
94
+ * in the `branch` closure, not here.
95
+ */
96
+ const functionDefSchema = z.strictObject({
84
97
  name: z.string().min(1).max(255),
85
98
  source: z.string().min(1),
86
99
  env: functionEnvSchema.optional(),
87
- runtime: z.literal("nodejs24").optional(),
88
- memoryMib: z.union([
89
- z.literal(256),
90
- z.literal(512),
91
- z.literal(1024),
92
- z.literal(2048),
93
- z.literal(4096),
94
- z.literal(8192)
95
- ]).optional(),
96
100
  dev: functionDevConfigSchema.optional()
97
101
  });
98
- const bucketConfigSchema = z.strictObject({
99
- name: z.string().min(1).max(255),
100
- access: z.union([z.literal("private"), z.literal("public_read")]).optional()
101
- });
102
- const previewConfigSchema = z.strictObject({
103
- functions: z.array(functionConfigSchema).optional(),
104
- buckets: z.array(bucketConfigSchema).optional(),
105
- aiGateway: serviceToggleSchema.optional()
106
- }).superRefine((preview, ctx) => {
107
- assertUnique({
108
- ctx,
109
- path: ["functions"],
110
- items: preview.functions ?? [],
111
- key: (fn) => fn.slug,
112
- label: "function slug"
113
- });
114
- assertUnique({
115
- ctx,
116
- path: ["buckets"],
117
- items: preview.buckets ?? [],
118
- key: (bucket) => bucket.name,
119
- label: "bucket name"
120
- });
102
+ /** Static definition of a bucket (existence). Name is the record key. */
103
+ const bucketDefSchema = z.strictObject({ access: z.union([z.literal("private"), z.literal("public_read")]).optional() });
104
+ /** Static, beta Preview feature set: AI Gateway toggle + functions/buckets records. */
105
+ const previewInputSchema = z.strictObject({
106
+ aiGateway: serviceToggleInputSchema.optional(),
107
+ functions: z.record(functionSlugSchema, functionDefSchema).optional(),
108
+ buckets: z.record(bucketNameSchema, bucketDefSchema).optional()
121
109
  });
110
+ /** Per-function deploy tuning returned by the `branch` closure. */
111
+ const functionTuningSchema = z.strictObject({ runtime: runtimeSchema.optional() });
112
+ /** Per-branch Preview tuning. Keys must be slugs declared in the static `preview`. */
113
+ const previewTuningSchema = z.strictObject({ functions: z.record(functionSlugSchema, functionTuningSchema).optional() });
122
114
  /**
123
- * Flag duplicate keys within a Preview collection so a typo in two function slugs (or two
124
- * buckets) surfaces as a config error rather than the second silently clobbering the first
125
- * at apply time.
115
+ * The object returned by the `branch` closure. Validated on every `resolveConfig` call so
116
+ * tuning errors point at the concrete branch target that triggered them.
126
117
  */
127
- function assertUnique(args) {
128
- const { ctx, path, items, key, label } = args;
129
- const seen = /* @__PURE__ */ new Set();
130
- items.forEach((item, index) => {
131
- const value = key(item);
132
- if (seen.has(value)) ctx.addIssue({
133
- code: "custom",
134
- path: [...path, index],
135
- message: `duplicate ${label}: ${JSON.stringify(value)}`
136
- });
137
- seen.add(value);
138
- });
139
- }
140
- const branchConfigSchema = z.strictObject({
118
+ const branchTuningSchema = z.strictObject({
141
119
  parent: z.string().optional(),
142
120
  protected: z.boolean().optional(),
143
121
  ttl: z.union([z.string(), z.number()]).optional().superRefine((value, ctx) => {
144
122
  if (value === void 0) return;
145
- const result = parseDuration(value);
123
+ const result = parseBranchTtl(value);
146
124
  if ("error" in result) ctx.addIssue({
147
125
  code: "custom",
148
126
  message: result.error
149
127
  });
150
128
  }),
151
129
  postgres: postgresConfigSchema.optional(),
152
- auth: serviceToggleSchema.optional(),
153
- dataApi: serviceToggleSchema.optional(),
154
- preview: previewConfigSchema.optional()
130
+ preview: previewTuningSchema.optional()
155
131
  }).superRefine((cfg, ctx) => {
156
132
  validateParentReference({
157
133
  ctx,
@@ -159,6 +135,17 @@ const branchConfigSchema = z.strictObject({
159
135
  parent: cfg.parent
160
136
  });
161
137
  });
138
+ /**
139
+ * The top-level object accepted by `defineConfig`. The `branch` closure is validated
140
+ * structurally as a function here; its returned tuning is validated per-evaluation by
141
+ * {@link branchTuningSchema} inside `resolveConfig`.
142
+ */
143
+ const configInputSchema = z.strictObject({
144
+ auth: serviceToggleInputSchema.optional(),
145
+ dataApi: serviceToggleInputSchema.optional(),
146
+ preview: previewInputSchema.optional(),
147
+ branch: z.custom((value) => typeof value === "function", { message: "branch must be a function: `branch: (branch) => ({ … })`" }).optional()
148
+ });
162
149
  function validateParentReference(args) {
163
150
  const { ctx, path, parent } = args;
164
151
  if (parent === void 0) return;
@@ -174,10 +161,6 @@ function validateParentReference(args) {
174
161
  message: `parent must be a concrete branch name (no wildcards), got "${parent}"`
175
162
  });
176
163
  }
177
- const configSchema = z.function({
178
- input: [z.unknown()],
179
- output: z.unknown()
180
- });
181
164
  /**
182
165
  * Convert the structured {@link z.ZodError} produced by `configSchema.safeParse` into the
183
166
  * `string[]` shape used by {@link import("./errors.js").ConfigValidationError}.
@@ -210,6 +193,6 @@ function normaliseIssueMessage(issue) {
210
193
  return issue.message;
211
194
  }
212
195
  //#endregion
213
- export { branchConfigSchema, bucketConfigSchema, computeSettingsSchema, configSchema, formatZodIssues, functionConfigSchema, postgresConfigSchema, previewConfigSchema, serviceToggleSchema };
196
+ export { branchTuningSchema, bucketDefSchema, computeSettingsSchema, configInputSchema, formatZodIssues, functionDefSchema, functionTuningSchema, postgresConfigSchema, previewInputSchema, serviceToggleInputSchema, serviceToggleSchema };
214
197
 
215
198
  //# sourceMappingURL=schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","names":[],"sources":["../../src/lib/schema.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { parseDuration, parseSuspendTimeout } from \"./duration.js\";\nimport { isWildcardPattern, validatePattern } from \"./patterns.js\";\n\n/**\n * Zod schema for {@link import(\"./types.js\").ComputeSettings}.\n *\n * - CU values must be one of: 0.25, 0.5, 1, 2, 4, 8\n * - `suspendTimeout` can be:\n * - `false` (never suspend)\n * - duration string like \"5m\", \"1h\" (must be 60s-604800s when parsed)\n * - number in seconds (60-604800, or -1/0 for special values)\n * - `undefined` (use platform default)\n *\n * Cross-field invariants (min <= max) are enforced via `superRefine`.\n */\nexport const computeSettingsSchema = z\n\t.strictObject({\n\t\tautoscalingLimitMinCu: z\n\t\t\t.union([\n\t\t\t\tz.literal(0.25),\n\t\t\t\tz.literal(0.5),\n\t\t\t\tz.literal(1),\n\t\t\t\tz.literal(2),\n\t\t\t\tz.literal(4),\n\t\t\t\tz.literal(8),\n\t\t\t])\n\t\t\t.optional(),\n\t\tautoscalingLimitMaxCu: z\n\t\t\t.union([\n\t\t\t\tz.literal(0.25),\n\t\t\t\tz.literal(0.5),\n\t\t\t\tz.literal(1),\n\t\t\t\tz.literal(2),\n\t\t\t\tz.literal(4),\n\t\t\t\tz.literal(8),\n\t\t\t])\n\t\t\t.optional(),\n\t\tsuspendTimeout: z\n\t\t\t.union([z.literal(false), z.string(), z.number()])\n\t\t\t.optional()\n\t\t\t.superRefine((value, ctx) => {\n\t\t\t\tif (value === undefined) return; // undefined is valid (use platform default)\n\t\t\t\tconst result = parseSuspendTimeout(value);\n\t\t\t\tif (\"error\" in result) {\n\t\t\t\t\tctx.addIssue({\n\t\t\t\t\t\tcode: \"custom\",\n\t\t\t\t\t\tmessage: result.error,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}),\n\t})\n\t.superRefine((settings, ctx) => {\n\t\tconst { autoscalingLimitMinCu: min, autoscalingLimitMaxCu: max } =\n\t\t\tsettings;\n\t\tif (min !== undefined && max !== undefined && min > max) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: \"custom\",\n\t\t\t\tpath: [\"autoscalingLimitMinCu\"],\n\t\t\t\tmessage: `autoscalingLimitMinCu (${min}) must be <= autoscalingLimitMaxCu (${max})`,\n\t\t\t});\n\t\t}\n\t});\n\nexport const serviceToggleSchema = z.strictObject({\n\tenabled: z.boolean().optional(),\n});\n\nexport const postgresConfigSchema = z.strictObject({\n\tcomputeSettings: computeSettingsSchema.optional(),\n});\n\n/**\n * Branch-unique function slug. Mirrors the Neon Functions API path-segment rule\n * (`platform/internal/platform/functions/name.go`): 1–20 lowercase letters and digits.\n */\nconst functionSlugSchema = z\n\t.string()\n\t.regex(\n\t\t/^[a-z0-9]{1,20}$/,\n\t\t\"function slug must be 1-20 lowercase letters and digits (no hyphens or other characters)\",\n\t);\n\n/**\n * Per-function environment map. Every value must be a defined string: a `process.env.X`\n * that is unset surfaces as `undefined` and is rejected here (rather than silently\n * shipping `undefined` into the deployment).\n */\nconst functionEnvSchema = z.record(z.string(), z.string());\n\n/**\n * TCP port for a function's local dev server. Excludes 0 (which means \"any port\" to the OS\n * — `neon dev` expresses \"pick one for me\" by omitting `port`, not by passing 0).\n */\nconst devPortSchema = z.number().int().min(1).max(65535);\n\n/**\n * Local-dev settings for a function (`neon dev` only; never affects deploy). `port` and\n * `portless` are independent: when `portless` is true, portless assigns the port itself\n * (so `port` is ignored); otherwise `port` is bound exactly when set, or a free port is\n * found when omitted.\n */\nconst functionDevConfigSchema = z.strictObject({\n\tport: devPortSchema.optional(),\n\tportless: z.boolean().optional(),\n});\n\nexport const functionConfigSchema = z.strictObject({\n\tslug: functionSlugSchema,\n\tname: z.string().min(1).max(255),\n\tsource: z.string().min(1),\n\tenv: functionEnvSchema.optional(),\n\truntime: z.literal(\"nodejs24\").optional(),\n\tmemoryMib: z\n\t\t.union([\n\t\t\tz.literal(256),\n\t\t\tz.literal(512),\n\t\t\tz.literal(1024),\n\t\t\tz.literal(2048),\n\t\t\tz.literal(4096),\n\t\t\tz.literal(8192),\n\t\t])\n\t\t.optional(),\n\tdev: functionDevConfigSchema.optional(),\n});\n\nexport const bucketConfigSchema = z.strictObject({\n\tname: z.string().min(1).max(255),\n\taccess: z\n\t\t.union([z.literal(\"private\"), z.literal(\"public_read\")])\n\t\t.optional(),\n});\n\nexport const previewConfigSchema = z\n\t.strictObject({\n\t\tfunctions: z.array(functionConfigSchema).optional(),\n\t\tbuckets: z.array(bucketConfigSchema).optional(),\n\t\taiGateway: serviceToggleSchema.optional(),\n\t})\n\t.superRefine((preview, ctx) => {\n\t\tassertUnique({\n\t\t\tctx,\n\t\t\tpath: [\"functions\"],\n\t\t\titems: preview.functions ?? [],\n\t\t\tkey: (fn) => fn.slug,\n\t\t\tlabel: \"function slug\",\n\t\t});\n\t\tassertUnique({\n\t\t\tctx,\n\t\t\tpath: [\"buckets\"],\n\t\t\titems: preview.buckets ?? [],\n\t\t\tkey: (bucket) => bucket.name,\n\t\t\tlabel: \"bucket name\",\n\t\t});\n\t});\n\n/**\n * Flag duplicate keys within a Preview collection so a typo in two function slugs (or two\n * buckets) surfaces as a config error rather than the second silently clobbering the first\n * at apply time.\n */\nfunction assertUnique<T>(args: {\n\tctx: z.RefinementCtx;\n\tpath: (string | number)[];\n\titems: T[];\n\tkey: (item: T) => string;\n\tlabel: string;\n}): void {\n\tconst { ctx, path, items, key, label } = args;\n\tconst seen = new Set<string>();\n\titems.forEach((item, index) => {\n\t\tconst value = key(item);\n\t\tif (seen.has(value)) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: \"custom\",\n\t\t\t\tpath: [...path, index],\n\t\t\t\tmessage: `duplicate ${label}: ${JSON.stringify(value)}`,\n\t\t\t});\n\t\t}\n\t\tseen.add(value);\n\t});\n}\n\nexport const branchConfigSchema = z\n\t.strictObject({\n\t\tparent: z.string().optional(),\n\t\tprotected: z.boolean().optional(),\n\t\tttl: z\n\t\t\t.union([z.string(), z.number()])\n\t\t\t.optional()\n\t\t\t.superRefine((value, ctx) => {\n\t\t\t\tif (value === undefined) return;\n\t\t\t\tconst result = parseDuration(value);\n\t\t\t\tif (\"error\" in result) {\n\t\t\t\t\tctx.addIssue({ code: \"custom\", message: result.error });\n\t\t\t\t}\n\t\t\t}),\n\t\tpostgres: postgresConfigSchema.optional(),\n\t\tauth: serviceToggleSchema.optional(),\n\t\tdataApi: serviceToggleSchema.optional(),\n\t\tpreview: previewConfigSchema.optional(),\n\t})\n\t.superRefine((cfg, ctx) => {\n\t\tvalidateParentReference({\n\t\t\tctx,\n\t\t\tpath: [\"parent\"],\n\t\t\tparent: cfg.parent,\n\t\t});\n\t});\n\nfunction validateParentReference(args: {\n\tctx: z.RefinementCtx;\n\tpath: (string | number)[];\n\tparent: string | undefined;\n}): void {\n\tconst { ctx, path, parent } = args;\n\tif (parent === undefined) return;\n\n\tconst patternCheck = validatePattern(parent);\n\tif (\"error\" in patternCheck) {\n\t\tctx.addIssue({ code: \"custom\", path, message: patternCheck.error });\n\t} else if (isWildcardPattern(parent)) {\n\t\tctx.addIssue({\n\t\t\tcode: \"custom\",\n\t\t\tpath,\n\t\t\tmessage: `parent must be a concrete branch name (no wildcards), got \"${parent}\"`,\n\t\t});\n\t}\n}\n\nexport const configSchema = z.function({\n\tinput: [z.unknown()],\n\toutput: z.unknown(),\n});\n\n/**\n * Convert the structured {@link z.ZodError} produced by `configSchema.safeParse` into the\n * `string[]` shape used by {@link import(\"./errors.js\").ConfigValidationError}.\n *\n * Issue paths are rendered as dot-separated property accesses (`postgres.computeSettings`)\n * and unknown-key issues from `strictObject` are normalised so the message contains the\n * substring \"unknown key\" — keeping pre-zod assertions in test suites and downstream tools\n * stable.\n */\nexport function formatZodIssues(error: z.ZodError): string[] {\n\treturn error.issues.map((issue) => {\n\t\tconst path = renderPath(issue.path);\n\t\tconst message = normaliseIssueMessage(issue);\n\t\treturn path ? `${path}: ${message}` : message;\n\t});\n}\n\nfunction renderPath(path: ReadonlyArray<PropertyKey>): string {\n\tlet out = \"\";\n\tfor (const segment of path) {\n\t\tif (typeof segment === \"number\") out += `[${segment}]`;\n\t\telse if (out === \"\") out += String(segment);\n\t\telse out += `.${String(segment)}`;\n\t}\n\treturn out;\n}\n\nfunction normaliseIssueMessage(issue: z.core.$ZodIssue): string {\n\tif (issue.code === \"unrecognized_keys\") {\n\t\tconst keys = (issue as z.core.$ZodIssueUnrecognizedKeys).keys ?? [];\n\t\tconst formatted = keys.map((k) => JSON.stringify(k)).join(\", \");\n\t\treturn `unknown key${keys.length === 1 ? \"\" : \"s\"}: ${formatted}`;\n\t}\n\treturn issue.message;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"schema.js","names":[],"sources":["../../src/lib/schema.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { parseBranchTtl, parseSuspendTimeout } from \"./duration.js\";\nimport { isWildcardPattern, validatePattern } from \"./patterns.js\";\n\n/**\n * Zod schema for {@link import(\"./types.js\").ComputeSettings}.\n *\n * - CU values must be one of: 0.25, 0.5, 1, 2, 4, 8\n * - `suspendTimeout` can be:\n * - `false` (never suspend)\n * - duration string like \"5m\", \"1h\" (must be 60s-604800s when parsed)\n * - number in seconds (60-604800, or -1/0 for special values)\n * - `undefined` (use platform default)\n *\n * Cross-field invariants (min <= max) are enforced via `superRefine`.\n */\nexport const computeSettingsSchema = z\n\t.strictObject({\n\t\tautoscalingLimitMinCu: z\n\t\t\t.union([\n\t\t\t\tz.literal(0.25),\n\t\t\t\tz.literal(0.5),\n\t\t\t\tz.literal(1),\n\t\t\t\tz.literal(2),\n\t\t\t\tz.literal(4),\n\t\t\t\tz.literal(8),\n\t\t\t])\n\t\t\t.optional(),\n\t\tautoscalingLimitMaxCu: z\n\t\t\t.union([\n\t\t\t\tz.literal(0.25),\n\t\t\t\tz.literal(0.5),\n\t\t\t\tz.literal(1),\n\t\t\t\tz.literal(2),\n\t\t\t\tz.literal(4),\n\t\t\t\tz.literal(8),\n\t\t\t])\n\t\t\t.optional(),\n\t\tsuspendTimeout: z\n\t\t\t.union([z.literal(false), z.string(), z.number()])\n\t\t\t.optional()\n\t\t\t.superRefine((value, ctx) => {\n\t\t\t\tif (value === undefined) return; // undefined is valid (use platform default)\n\t\t\t\tconst result = parseSuspendTimeout(value);\n\t\t\t\tif (\"error\" in result) {\n\t\t\t\t\tctx.addIssue({\n\t\t\t\t\t\tcode: \"custom\",\n\t\t\t\t\t\tmessage: result.error,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}),\n\t})\n\t.superRefine((settings, ctx) => {\n\t\tconst { autoscalingLimitMinCu: min, autoscalingLimitMaxCu: max } =\n\t\t\tsettings;\n\t\tif (min !== undefined && max !== undefined && min > max) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: \"custom\",\n\t\t\t\tpath: [\"autoscalingLimitMinCu\"],\n\t\t\t\tmessage: `autoscalingLimitMinCu (${min}) must be <= autoscalingLimitMaxCu (${max})`,\n\t\t\t});\n\t\t}\n\t});\n\n/** Object form of a service toggle (`{ enabled?: boolean }`). */\nexport const serviceToggleSchema = z.strictObject({\n\tenabled: z.boolean().optional(),\n});\n\n/** A service toggle as written in a policy: `boolean` or `{ enabled?: boolean }`. */\nexport const serviceToggleInputSchema = z.union([\n\tz.boolean(),\n\tserviceToggleSchema,\n]);\n\nexport const postgresConfigSchema = z.strictObject({\n\tcomputeSettings: computeSettingsSchema.optional(),\n});\n\n/**\n * Branch-unique function slug. Mirrors the Neon Functions API path-segment rule\n * (`platform/internal/platform/functions/name.go`): 1–20 lowercase letters and digits.\n * Used as the **key schema** of the `preview.functions` record, so a bad slug fails\n * validation with a path pointing at the offending key and duplicate slugs are impossible\n * by construction (object keys are unique).\n */\nconst functionSlugSchema = z\n\t.string()\n\t.regex(\n\t\t/^[a-z0-9]{1,20}$/,\n\t\t\"function slug must be 1-20 lowercase letters and digits (no hyphens or other characters)\",\n\t);\n\n/** Bucket name: 1–255 chars. Used as the key schema of the `preview.buckets` record. */\nconst bucketNameSchema = z.string().min(1).max(255);\n\n/**\n * Per-function environment map. Every value must be a defined string: a `process.env.X`\n * that is unset surfaces as `undefined` and is rejected here (rather than silently\n * shipping `undefined` into the deployment).\n */\nconst functionEnvSchema = z.record(z.string(), z.string());\n\n/**\n * TCP port for a function's local dev server. Excludes 0 (which means \"any port\" to the OS\n * — `neon dev` expresses \"pick one for me\" by omitting `port`, not by passing 0).\n */\nconst devPortSchema = z.number().int().min(1).max(65535);\n\n/**\n * Local-dev settings for a function (`neon dev` only; never affects deploy). `port` and\n * `portless` are independent: when `portless` is true, portless assigns the port itself\n * (so `port` is ignored); otherwise `port` is bound exactly when set, or a free port is\n * found when omitted.\n */\nconst functionDevConfigSchema = z.strictObject({\n\tport: devPortSchema.optional(),\n\tportless: z.boolean().optional(),\n});\n\nconst runtimeSchema = z.literal(\"nodejs24\");\n\n/**\n * Static definition of a function (existence). The slug is the record key (validated by\n * {@link functionSlugSchema}), so it is not a field here. Deploy tuning (`runtime`) lives\n * in the `branch` closure, not here.\n */\nexport const functionDefSchema = z.strictObject({\n\tname: z.string().min(1).max(255),\n\tsource: z.string().min(1),\n\tenv: functionEnvSchema.optional(),\n\tdev: functionDevConfigSchema.optional(),\n});\n\n/** Static definition of a bucket (existence). Name is the record key. */\nexport const bucketDefSchema = z.strictObject({\n\taccess: z\n\t\t.union([z.literal(\"private\"), z.literal(\"public_read\")])\n\t\t.optional(),\n});\n\n/** Static, beta Preview feature set: AI Gateway toggle + functions/buckets records. */\nexport const previewInputSchema = z.strictObject({\n\taiGateway: serviceToggleInputSchema.optional(),\n\tfunctions: z.record(functionSlugSchema, functionDefSchema).optional(),\n\tbuckets: z.record(bucketNameSchema, bucketDefSchema).optional(),\n});\n\n/** Per-function deploy tuning returned by the `branch` closure. */\nexport const functionTuningSchema = z.strictObject({\n\truntime: runtimeSchema.optional(),\n});\n\n/** Per-branch Preview tuning. Keys must be slugs declared in the static `preview`. */\nconst previewTuningSchema = z.strictObject({\n\tfunctions: z.record(functionSlugSchema, functionTuningSchema).optional(),\n});\n\n/**\n * The object returned by the `branch` closure. Validated on every `resolveConfig` call so\n * tuning errors point at the concrete branch target that triggered them.\n */\nexport const branchTuningSchema = z\n\t.strictObject({\n\t\tparent: z.string().optional(),\n\t\tprotected: z.boolean().optional(),\n\t\tttl: z\n\t\t\t.union([z.string(), z.number()])\n\t\t\t.optional()\n\t\t\t.superRefine((value, ctx) => {\n\t\t\t\tif (value === undefined) return;\n\t\t\t\tconst result = parseBranchTtl(value);\n\t\t\t\tif (\"error\" in result) {\n\t\t\t\t\tctx.addIssue({ code: \"custom\", message: result.error });\n\t\t\t\t}\n\t\t\t}),\n\t\tpostgres: postgresConfigSchema.optional(),\n\t\tpreview: previewTuningSchema.optional(),\n\t})\n\t.superRefine((cfg, ctx) => {\n\t\tvalidateParentReference({\n\t\t\tctx,\n\t\t\tpath: [\"parent\"],\n\t\t\tparent: cfg.parent,\n\t\t});\n\t});\n\n/**\n * The top-level object accepted by `defineConfig`. The `branch` closure is validated\n * structurally as a function here; its returned tuning is validated per-evaluation by\n * {@link branchTuningSchema} inside `resolveConfig`.\n */\nexport const configInputSchema = z.strictObject({\n\tauth: serviceToggleInputSchema.optional(),\n\tdataApi: serviceToggleInputSchema.optional(),\n\tpreview: previewInputSchema.optional(),\n\tbranch: z\n\t\t.custom<(...args: unknown[]) => unknown>(\n\t\t\t(value) => typeof value === \"function\",\n\t\t\t{\n\t\t\t\tmessage:\n\t\t\t\t\t\"branch must be a function: `branch: (branch) => ({ … })`\",\n\t\t\t},\n\t\t)\n\t\t.optional(),\n});\n\nfunction validateParentReference(args: {\n\tctx: z.RefinementCtx;\n\tpath: (string | number)[];\n\tparent: string | undefined;\n}): void {\n\tconst { ctx, path, parent } = args;\n\tif (parent === undefined) return;\n\n\tconst patternCheck = validatePattern(parent);\n\tif (\"error\" in patternCheck) {\n\t\tctx.addIssue({ code: \"custom\", path, message: patternCheck.error });\n\t} else if (isWildcardPattern(parent)) {\n\t\tctx.addIssue({\n\t\t\tcode: \"custom\",\n\t\t\tpath,\n\t\t\tmessage: `parent must be a concrete branch name (no wildcards), got \"${parent}\"`,\n\t\t});\n\t}\n}\n\n/**\n * Convert the structured {@link z.ZodError} produced by `configSchema.safeParse` into the\n * `string[]` shape used by {@link import(\"./errors.js\").ConfigValidationError}.\n *\n * Issue paths are rendered as dot-separated property accesses (`postgres.computeSettings`)\n * and unknown-key issues from `strictObject` are normalised so the message contains the\n * substring \"unknown key\" — keeping pre-zod assertions in test suites and downstream tools\n * stable.\n */\nexport function formatZodIssues(error: z.ZodError): string[] {\n\treturn error.issues.map((issue) => {\n\t\tconst path = renderPath(issue.path);\n\t\tconst message = normaliseIssueMessage(issue);\n\t\treturn path ? `${path}: ${message}` : message;\n\t});\n}\n\nfunction renderPath(path: ReadonlyArray<PropertyKey>): string {\n\tlet out = \"\";\n\tfor (const segment of path) {\n\t\tif (typeof segment === \"number\") out += `[${segment}]`;\n\t\telse if (out === \"\") out += String(segment);\n\t\telse out += `.${String(segment)}`;\n\t}\n\treturn out;\n}\n\nfunction normaliseIssueMessage(issue: z.core.$ZodIssue): string {\n\tif (issue.code === \"unrecognized_keys\") {\n\t\tconst keys = (issue as z.core.$ZodIssueUnrecognizedKeys).keys ?? [];\n\t\tconst formatted = keys.map((k) => JSON.stringify(k)).join(\", \");\n\t\treturn `unknown key${keys.length === 1 ? \"\" : \"s\"}: ${formatted}`;\n\t}\n\treturn issue.message;\n}\n"],"mappings":"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"}
@@ -4,6 +4,43 @@
4
4
  * Most plans support 0.25, 0.5, 1, 2, 4, 8. Higher values may be available on Business plans.
5
5
  */
6
6
  type ComputeUnit = 0.25 | 0.5 | 1 | 2 | 4 | 8;
7
+ /** Time units accepted in a {@link DurationString}: seconds, minutes, hours, days, weeks. */
8
+ type DurationUnit = "s" | "m" | "h" | "d" | "w";
9
+ /**
10
+ * A Neon duration string: a positive integer **followed by a unit** — `s` (seconds),
11
+ * `m` (minutes), `h` (hours), `d` (days), or `w` (weeks). Used by
12
+ * {@link ComputeSettings.suspendTimeout} and {@link BranchTuning.ttl}.
13
+ *
14
+ * A **unit is required**: a bare numeric string like `"7"` is rejected at the type level. To
15
+ * express a raw number of seconds, pass a `number` (`300`) — not a string (`"300"`). This
16
+ * removes the old ambiguity where `"7"` silently meant 7 *seconds* instead of, say, `"7d"`.
17
+ *
18
+ * @example "5m" // 5 minutes
19
+ * @example "1h" // 1 hour
20
+ * @example "7d" // 7 days
21
+ */
22
+ type DurationString = `${number}${DurationUnit}`;
23
+ /**
24
+ * Autocomplete suggestions for {@link ComputeSettings.suspendTimeout}. Every value sits inside
25
+ * the Neon API's allowed scale-to-zero band: **60s–604800s** (1 minute – 1 week). This is *not*
26
+ * a closed set — the field also accepts any other {@link DurationString} or a `number` of
27
+ * seconds; out-of-range values type-check but are rejected at apply time.
28
+ */
29
+ type SuspendTimeoutSuggestion = "1m" | "5m" | "15m" | "30m" | "1h" | "6h" | "12h" | "1d" | "7d";
30
+ /**
31
+ * Autocomplete suggestions for {@link BranchTuning.ttl}. Every value sits within the Neon API's
32
+ * branch-expiration limit (**max 30 days** from creation; the Console's own presets are 1h / 1d
33
+ * / 7d). This is *not* a closed set — the field also accepts any other {@link DurationString} or
34
+ * a `number` of seconds; values over 30 days are rejected at apply time.
35
+ */
36
+ type TtlSuggestion = "1h" | "6h" | "12h" | "1d" | "3d" | "7d" | "14d" | "30d";
37
+ /**
38
+ * Compose a field's duration type: its curated autocomplete `Suggestions` plus the open
39
+ * `DurationString` template (so any `<integer><unit>` string still type-checks) and a `number`
40
+ * of seconds. Intersecting the template arm with `NonNullable<unknown>` stops TypeScript from
41
+ * collapsing the literal suggestions into the template, which is what preserves the autocomplete.
42
+ */
43
+ type DurationField<Suggestions extends DurationString> = Suggestions | (DurationString & NonNullable<unknown>) | number;
7
44
  /**
8
45
  * Compute settings applied to the read/write endpoint of a branch.
9
46
  *
@@ -25,19 +62,26 @@ interface ComputeSettings {
25
62
  */
26
63
  autoscalingLimitMaxCu?: ComputeUnit;
27
64
  /**
28
- * How long to wait before suspending an idle compute.
65
+ * How long an idle compute waits before suspending (Neon's scale-to-zero). Accepts a
66
+ * {@link DurationString} (autocompletes common values), a number of seconds, or `false`.
29
67
  *
30
68
  * - `false` — never suspend (always-on compute)
31
- * - `"5m"` duration string (supports "30s", "5m", "1h", "7d", etc)
32
- * - `300` custom timeout in seconds (60-604800)
33
- * - `undefined` use Neon platform default (currently 300s / 5 minutes)
69
+ * - {@link DurationString} — e.g. `"5m"`; autocompletes the in-range values `"1m"`, `"5m"`,
70
+ * `"15m"`, `"30m"`, `"1h"`, `"6h"`, `"12h"`, `"1d"`, `"7d"`, and accepts any other
71
+ * `<integer><unit>` (units: `s`, `m`, `h`, `d`, `w`). A **unit is required** for raw
72
+ * seconds pass a `number`, not a string.
73
+ * - `number` — custom timeout in **seconds**, must be in `60`–`604800` (1 minute to 1 week)
74
+ * - `undefined` — use the Neon platform default (currently 300s / 5 minutes)
34
75
  *
35
- * @example false // never suspend
36
- * @example "5m" // 5 minutes
37
- * @example "1h" // 1 hour
38
- * @example 300 // 5 minutes in seconds
76
+ * Whichever form you use, the resolved timeout must fall in `60`–`604800` seconds (the Neon
77
+ * API limit); the suggestions are all within that band, anything else is checked at apply.
78
+ *
79
+ * @example false // never suspend (always-on)
80
+ * @example "5m" // suspend after 5 minutes idle
81
+ * @example "1h" // suspend after 1 hour idle
82
+ * @example 300 // 5 minutes, expressed in seconds
39
83
  */
40
- suspendTimeout?: false | "5m" | "1h" | string | number;
84
+ suspendTimeout?: false | DurationField<SuspendTimeoutSuggestion>;
41
85
  }
42
86
  /**
43
87
  * Read-only descriptor of the branch a {@link Config} policy is being evaluated for — the
@@ -61,10 +105,26 @@ interface BranchTarget {
61
105
  /** Current expiration timestamp from Neon, when set. */
62
106
  expiresAt?: string;
63
107
  }
108
+ /**
109
+ * Object form of a branch-scoped service toggle. `{}` or `{ enabled: true }` enables it;
110
+ * `{ enabled: false }` opts out. Used as the object half of {@link ServiceToggleInput}.
111
+ */
64
112
  interface ServiceToggle {
65
113
  /** Defaults to `true` when the service namespace is present. Set `false` to opt out. */
66
114
  enabled?: boolean;
67
115
  }
116
+ /**
117
+ * How a branch-scoped service (Neon Auth, Data API, AI Gateway) is toggled in a policy.
118
+ *
119
+ * - `true` / `{}` / `{ enabled: true }` — enabled.
120
+ * - `false` / `{ enabled: false }` — disabled.
121
+ * - omitted (`undefined`) — not part of the policy at all.
122
+ *
123
+ * These toggles are **static** (they live in the top-level `defineConfig({ … })` object,
124
+ * not in the per-branch `branch` closure) so the secret set they imply can be derived at
125
+ * the type level — that's what makes `NeonEnv<typeof config>` exact.
126
+ */
127
+ type ServiceToggleInput = boolean | ServiceToggle;
68
128
  interface PostgresConfig {
69
129
  computeSettings?: ComputeSettings;
70
130
  }
@@ -74,11 +134,6 @@ interface PostgresConfig {
74
134
  * non-breaking, type-checked change.
75
135
  */
76
136
  type FunctionRuntime = "nodejs24";
77
- /**
78
- * Memory sizes (MiB) accepted by the Neon Functions deploy API. Mirrors the
79
- * `memory_mib` enum in the spec.
80
- */
81
- type FunctionMemoryMib = 256 | 512 | 1024 | 2048 | 4096 | 8192;
82
137
  /**
83
138
  * Local-development settings for a function, used by `neon dev` when it serves every
84
139
  * function declared in `neon.ts` (i.e. invoked with no `--source`). Never affects deploy.
@@ -104,20 +159,21 @@ interface FunctionDevConfig {
104
159
  portless?: boolean;
105
160
  }
106
161
  /**
107
- * A single Neon Function deployed to a branch (Preview feature).
162
+ * Static definition of a Neon Function (Preview feature). Declares that the function
163
+ * **exists** on every branch; its branch-unique slug is the **record key** in
164
+ * {@link PreviewInput.functions} (not a field here), so slugs are statically enumerable,
165
+ * cannot duplicate, and the `branch` closure can only tune slugs that are declared here.
108
166
  *
109
167
  * A function is invoked like a Cloudflare/Vercel handler — its source module
110
168
  * `export default { fetch }` or `export async function handler(req): Response`. The
111
- * `source` path is bundled (esbuild) and uploaded as a deployment; the newest
112
- * deployment becomes active.
169
+ * `source` path is bundled (esbuild) and uploaded as a deployment; the newest deployment
170
+ * becomes active.
171
+ *
172
+ * Runtime tuning is **not** here — it varies per branch and lives in the `branch` closure
173
+ * (see {@link FunctionTuning}). Memory is fixed by the platform policy for now and is not
174
+ * user-configurable.
113
175
  */
114
- interface FunctionConfig {
115
- /**
116
- * Branch-unique slug used as the path segment in the function's invocation URL.
117
- * Immutable once created. 1–20 lowercase letters and digits: `^[a-z0-9]{1,20}$`.
118
- * @example "hellofn"
119
- */
120
- slug: string;
176
+ interface FunctionDef {
121
177
  /** Free-form display name. @example "Hello World" */
122
178
  name: string;
123
179
  /**
@@ -132,16 +188,16 @@ interface FunctionConfig {
132
188
  */
133
189
  source: string;
134
190
  /**
135
- * Environment variables injected into the deployed function. Every value must be a
136
- * defined string a `process.env.X` that is `undefined` (unset) errors at validation
137
- * time rather than silently shipping `undefined`.
138
- * @example { RESEND_API_KEY: process.env.RESEND_API_KEY }
191
+ * Environment variables injected into the deployed function, keyed by the var name the
192
+ * function reads at runtime. The **keys** are static (preserved at the type level so
193
+ * `parseEnv(config, "<slug>").function.<key>` is typed); the **values** are arbitrary
194
+ * strings evaluated when `neon.ts` is loaded (typically `process.env.X`) and uploaded
195
+ * at `config apply`. Every value must be a defined string — a `process.env.X` that is
196
+ * `undefined` (unset) errors at validation time rather than silently shipping
197
+ * `undefined`.
198
+ * @example { resendApiKey: process.env.RESEND_API_KEY ?? "" }
139
199
  */
140
200
  env?: Record<string, string>;
141
- /** Runtime to execute the function with. Defaults to `"nodejs24"`. */
142
- runtime?: FunctionRuntime;
143
- /** Memory allotted to each invocation, in MiB. Defaults to `512`. */
144
- memoryMib?: FunctionMemoryMib;
145
201
  /**
146
202
  * Local-development settings used by `neon dev` when serving every function from
147
203
  * `neon.ts`. Ignored at deploy time. See {@link FunctionDevConfig}.
@@ -151,11 +207,11 @@ interface FunctionConfig {
151
207
  /** Anonymous-access level for a branchable object-storage bucket. */
152
208
  type BucketAccessLevel = "private" | "public_read";
153
209
  /**
154
- * A branchable object-storage bucket on a branch (Preview feature).
210
+ * Static definition of a branchable object-storage bucket (Preview feature). The bucket's
211
+ * name is the **record key** in {@link PreviewInput.buckets}, so names are statically
212
+ * enumerable and cannot duplicate.
155
213
  */
156
- interface BucketConfig {
157
- /** Bucket name, unique within a branch. 1–255 chars. */
158
- name: string;
214
+ interface BucketDef {
159
215
  /**
160
216
  * Anonymous access level. `private` (default) requires authenticated reads/writes;
161
217
  * `public_read` allows anonymous GetObject/HeadObject.
@@ -163,49 +219,109 @@ interface BucketConfig {
163
219
  access?: BucketAccessLevel;
164
220
  }
165
221
  /**
166
- * Branch-scoped Preview features. Grouped under `preview` to signal they are backed by
167
- * Neon `x-stability-level: beta` endpoints and may change before GA.
222
+ * Static, branch-scoped **Preview** features. Grouped under `preview` to signal they are
223
+ * backed by Neon `x-stability-level: beta` endpoints and may change before GA. Everything
224
+ * here is existential (it determines what exists on the branch); per-branch tuning lives in
225
+ * the `branch` closure.
168
226
  */
169
- interface PreviewConfig {
170
- /** Functions to deploy on the branch. */
171
- functions?: FunctionConfig[];
172
- /** Object-storage buckets to create on the branch. */
173
- buckets?: BucketConfig[];
227
+ interface PreviewInput {
174
228
  /** Enable/disable the AI Gateway on the branch (toggle, like auth / dataApi). */
175
- aiGateway?: ServiceToggle;
229
+ aiGateway?: ServiceToggleInput;
230
+ /** Functions to deploy, keyed by branch-unique slug (`^[a-z0-9]{1,20}$`). */
231
+ functions?: Record<string, FunctionDef>;
232
+ /** Object-storage buckets to create, keyed by bucket name. */
233
+ buckets?: Record<string, BucketDef>;
176
234
  }
177
- interface BranchConfigBase {
235
+ /**
236
+ * Per-branch deploy tuning for a single function. Returned (per slug) by the `branch`
237
+ * closure. Deliberately **cannot** change the function's existence, source, name, env
238
+ * **keys**, or memory — only runtime selection is currently configurable — so the static
239
+ * secret/function set stays sound.
240
+ */
241
+ interface FunctionTuning {
242
+ /** Runtime to execute the function with. Defaults to `"nodejs24"`. */
243
+ runtime?: FunctionRuntime;
244
+ }
245
+ /**
246
+ * Per-branch tuning of Preview features. Only existing function slugs (those declared in
247
+ * the static {@link PreviewInput.functions}) may be tuned — `Slug` is constrained to the
248
+ * declared keys by {@link BranchTuningFn}.
249
+ */
250
+ interface PreviewTuning<Slug extends string = string> {
251
+ functions?: Partial<Record<Slug, FunctionTuning>>;
252
+ }
253
+ /**
254
+ * The per-branch tuning object returned by the `branch` closure. It can adjust branch
255
+ * lifecycle (`parent`, `ttl`, `protected`), Postgres compute settings, and per-function
256
+ * deploy tuning — but **cannot** add/remove services or functions. That guarantee is what
257
+ * keeps the static secret set (and therefore `NeonEnv`) exact.
258
+ */
259
+ interface BranchTuning<Slug extends string = string> {
178
260
  /** Parent branch name used when creating a new branch. Not a Postgres setting. */
179
261
  parent?: string;
180
- /** Time-to-live applied when creating a new branch, or reconciled on existing branches. */
181
- ttl?: string | number;
262
+ /**
263
+ * Branch time-to-live: how long after creation the branch should auto-expire. Applied
264
+ * when creating a new branch and reconciled on existing branches (when `updateExisting`
265
+ * is set). Accepts a {@link DurationString} (autocompletes common values) or a number of
266
+ * seconds. Omit to keep the branch indefinitely.
267
+ *
268
+ * - {@link DurationString} — e.g. `"7d"`; autocompletes `"1h"`, `"6h"`, `"12h"`, `"1d"`,
269
+ * `"3d"`, `"7d"`, `"14d"`, `"30d"`, and accepts any other `<integer><unit>` (units: `s`,
270
+ * `m`, `h`, `d`, `w` — e.g. `"12h"`, `"2w"`). A **unit is required** — `"7"` is rejected;
271
+ * for raw seconds pass a `number`.
272
+ * - `number` — custom TTL in **seconds** (e.g. `3600`)
273
+ * - `undefined` — no expiry; the branch persists until explicitly deleted
274
+ *
275
+ * The Neon API caps branch expiration at **30 days** from creation, so the resolved TTL must
276
+ * be `> 0` and `<= 30d`; the suggestions stay within that limit and anything longer is
277
+ * rejected at apply.
278
+ *
279
+ * @example "1d" // ephemeral preview branch: expires a day after creation
280
+ * @example "7d" // one-week TTL
281
+ * @example "30d" // the maximum the API allows
282
+ * @example 3600 // 1 hour, expressed in seconds
283
+ */
284
+ ttl?: DurationField<TtlSuggestion>;
182
285
  /** Whether the selected branch should be protected. Undefined means "leave as-is". */
183
286
  protected?: boolean;
184
287
  postgres?: PostgresConfig;
185
- /**
186
- * Branch-scoped Preview features (functions, object-storage buckets, AI Gateway).
187
- * Backed by Neon `x-stability-level: beta` endpoints see {@link PreviewConfig}.
188
- */
189
- preview?: PreviewConfig;
288
+ preview?: PreviewTuning<Slug>;
289
+ }
290
+ /** Extract the declared function slugs from a {@link PreviewInput} for closure typing. */
291
+ type FunctionSlugsOf<Preview extends PreviewInput | undefined> = Preview extends {
292
+ functions: infer F;
293
+ } ? Extract<keyof F, string> : string;
294
+ /**
295
+ * Signature of the `branch` closure. Generic over the static {@link PreviewInput} so the
296
+ * `preview.functions` keys it may tune are constrained to the slugs actually declared.
297
+ */
298
+ type BranchTuningFn<Preview extends PreviewInput | undefined = PreviewInput | undefined> = (branch: BranchTarget) => BranchTuning<FunctionSlugsOf<Preview>>;
299
+ /**
300
+ * A validated Neon branch policy — the value `defineConfig({ … })` returns and `neon.ts`
301
+ * default-exports.
302
+ *
303
+ * Split into a **static** existential set (top-level `auth` / `dataApi` GA toggles plus the
304
+ * beta `preview` block) and a **dynamic** per-branch `branch` closure for tuning. The
305
+ * static half is what makes the secret set — and therefore `NeonEnv<typeof config>` and
306
+ * `parseEnv` — exact; the closure can tune but never change what exists.
307
+ *
308
+ * Generic over the three static fields so the type system can read the exact toggle/slug
309
+ * literals; the defaults make the bare `Config` a usable "any policy" type for runtime
310
+ * function signatures.
311
+ */
312
+ interface Config<Auth extends ServiceToggleInput | undefined = ServiceToggleInput | undefined, DataApi extends ServiceToggleInput | undefined = ServiceToggleInput | undefined, Preview extends PreviewInput | undefined = PreviewInput | undefined> {
313
+ /** Neon Auth integration toggle (GA). Static — drives `NeonEnv.auth`. */
314
+ auth?: Auth;
315
+ /** Neon Data API integration toggle (GA). Static — drives `NeonEnv.dataApi`. */
316
+ dataApi?: DataApi;
317
+ /** Beta (Preview) feature set: AI Gateway, functions, buckets. Static. */
318
+ preview?: Preview;
319
+ /** Per-branch tuning closure. Cannot change the static existential set. */
320
+ branch?: BranchTuningFn<Preview>;
190
321
  }
191
- type BranchServiceConfig = {
192
- auth?: never;
193
- dataApi?: never;
194
- } | {
195
- auth: ServiceToggle;
196
- dataApi?: never;
197
- } | {
198
- auth?: never;
199
- dataApi: ServiceToggle;
200
- } | {
201
- auth: ServiceToggle;
202
- dataApi: ServiceToggle;
203
- };
204
- type BranchConfig = BranchConfigBase & BranchServiceConfig;
205
- type Config = (branch: BranchTarget) => BranchConfig;
206
322
  /**
207
- * A function with all deploy defaults applied. `resolveConfig` fills in `runtime` and
208
- * `memoryMib` so downstream diff/apply never has to re-derive them.
323
+ * A function with all deploy defaults applied. `resolveConfig` fills in `runtime` so
324
+ * downstream diff/apply never has to re-derive it.
209
325
  */
210
326
  interface ResolvedFunctionConfig {
211
327
  slug: string;
@@ -213,9 +329,8 @@ interface ResolvedFunctionConfig {
213
329
  source: string;
214
330
  env: Record<string, string>;
215
331
  runtime: FunctionRuntime;
216
- memoryMib: FunctionMemoryMib;
217
332
  /**
218
- * Local-development settings, passed through untouched from {@link FunctionConfig.dev}
333
+ * Local-development settings, passed through untouched from {@link FunctionDef.dev}
219
334
  * (no defaults applied). Only consumed by `neon dev`; deploy ignores it.
220
335
  */
221
336
  dev?: FunctionDevConfig;
@@ -226,7 +341,7 @@ interface ResolvedBucketConfig {
226
341
  access: BucketAccessLevel;
227
342
  }
228
343
  /**
229
- * Normalized {@link PreviewConfig}. Only present on {@link ResolvedBranchConfig} when the
344
+ * Normalized {@link PreviewInput}. Only present on {@link ResolvedBranchConfig} when the
230
345
  * policy returned a `preview` block. `aiGatewayEnabled` follows the same
231
346
  * "present-and-not-`false`" semantics as `authEnabled` / `dataApiEnabled`.
232
347
  */
@@ -289,5 +404,5 @@ interface PushResult {
289
404
  conflicts: ConflictReport[];
290
405
  }
291
406
  //#endregion
292
- export { AppliedChange, BranchConfig, BranchTarget, BucketAccessLevel, BucketConfig, ComputeSettings, ComputeUnit, Config, ConflictReport, FunctionConfig, FunctionDevConfig, FunctionMemoryMib, FunctionRuntime, PostgresConfig, PreviewConfig, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceToggle };
407
+ export { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConflictReport, DurationString, DurationUnit, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceToggle, ServiceToggleInput };
293
408
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/lib/types.ts"],"mappings":";;AAIA;AASA;;AAMyB,KAfb,WAAA,GAea,IAAA,GAAA,GAAA,GAAA,CAAA,GAAA,CAAA,GAAA,CAAA,GAAA,CAAA;;AAMW;AAuBpC;AAiBA;AAKA;AASA;AAMA;AAciB,UAtFA,eAAA,CAsFiB;EAqBjB;;;;;uBAmCV,CAAA,EAxIkB,WAwIlB;EAAiB;AAIxB;AAKA;AAcA;;uBAEa,CAAA,EA3JY,WA2JZ;;;AAIa;AACzB;;;;AAcuB;AAAA;;;;;gBAOW,CAAA,EAAA,KAAA,GAAA,IAAA,GAAA,IAAA,GAAA,MAAA,GAAA,MAAA;AAAa;AAEhD;;;;AAAiE;AAEjE;AAAkB,UAlKD,YAAA,CAkKC;;MAA6B,EAAA,MAAA;EAAY;EAM1C,EAAA,CAAA,EAAA,MAAA;EAAsB;QAIjC,EAAA,OAAA;;UAEM,CAAA,EAAA,MAAA;;EAKY,SAAA,CAAA,EAAA,OAAA;EAIP;EAUA,WAAA,CAAA,EAAA,OAAA;EAAqB;WAC1B,CAAA,EAAA,MAAA;;AACkB,UAlLb,aAAA,CAkLa;EAIb;EAAoB,OAAA,CAAA,EAAA,OAAA;;AAO1B,UAxLM,cAAA,CAwLN;EAAqB,eAAA,CAAA,EAvLb,eAuLa;AAMhC;AAkBA;AAYA;;;;AAW0B,KA9Nd,eAAA,GA8Nc,UAAA;;;;;KAxNd,iBAAA;;;;;;;;;;;;;UAcK,iBAAA;;;;;;;;;;;;;;;;;;;;UAqBA,cAAA;;;;;;;;;;;;;;;;;;;;;;;;;;QA0BV;;YAEI;;cAEE;;;;;QAKN;;;KAIK,iBAAA;;;;UAKK,YAAA;;;;;;;WAOP;;;;;;UAOO,aAAA;;cAEJ;;YAEF;;cAEE;;UAGH,gBAAA;;;;;;;aAOE;;;;;YAKD;;KAGN,mBAAA;;;;QAEM;;;;WACiB;;QACjB;WAAwB;;KAEvB,YAAA,GAAe,mBAAmB;KAElC,MAAA,YAAkB,iBAAiB;;;;;UAM9B,sBAAA;;;;OAIX;WACI;aACE;;;;;QAKL;;;UAIU,oBAAA;;UAER;;;;;;;UAQQ,qBAAA;aACL;WACF;;;UAIO,oBAAA;;;;aAIL;;;YAGD;;;;;UAMM,aAAA;;;;;;;;YAQN;;;;;;;;;UAUM,cAAA;;;;;;;;;;;UAYA,UAAA;;;;;;;;;;WAUP;aACE"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/lib/types.ts"],"mappings":";;AAIA;AAGA;AAeA;AAQK,KA1BO,WAAA,GA0BP,IAAA,GAAwB,GAAA,GAAA,CAAA,GAAA,CAAA,GAAA,CAAA,GAAA,CAAA;AAAA;AAyBxB,KAhDO,YAAA,GAgDM,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GAAA;;;;;;AAEc;AAUhC;;;;;;AAiCuC;AAStB,KAvFL,cAAA,GAuFiB,GAAA,MAAA,GAvFY,YAuFZ,EAAA;AAqB7B;AAgBA;AAEA;AASA;AAcA;AA4BA;KAzKK,wBAAA,GAyKuB,IAAA,GAAA,IAAA,GAAA,KAAA,GAAA,KAAA,GAAA,IAAA,GAAA,IAAA,GAAA,KAAA,GAAA,IAAA,GAAA,IAAA;;;AA6BJ;AAIxB;AAOA;AAcA;KA9MK,aAAA,GA8MwB,IAAA,GAAA,IAAA,GAAA,KAAA,GAAA,IAAA,GAAA,IAAA,GAAA,IAAA,GAAA,KAAA,GAAA,KAAA;;;;;;AAMZ;AASjB,KArNK,aAqNY,CAAA,oBArNsB,cAuNb,CAAA,GAtNvB,WAsNuB,GAAA,CArNtB,cAqNsB,GArNL,WAqNK,CAAA,OAAA,CAAA,CAAA,GAAA,MAAA;AAQ1B;;;;;;AACoB;AASH,UA7NA,eAAA,CA6NY;EAAA;;;;;uBA6BlB,CAAA,EApPc,WAoPd;EAAa;AACvB;;;;uBAOiB,CAAA,EAtPO,WAsPP;;AAAP;AAOX;;;;;;;;AAE0C;AAe1C;;;;;;;;;gBAYW,CAAA,EAAA,KAAA,GArQe,aAqQf,CArQ6B,wBAqQ7B,CAAA;;;;AAIa;AAOxB;;;AAKU,UA5QO,YAAA,CA4QP;;EAKc,IAAA,EAAA,MAAA;EAIP;EAUA,EAAA,CAAA,EAAA,MAAA;EAAqB;QAC1B,EAAA,OAAA;;EACkB,QAAA,CAAA,EAAA,MAAA;EAIb;EAAoB,SAAA,CAAA,EAAA,OAAA;;aAO1B,CAAA,EAAA,OAAA;EAAqB;EAMf,SAAA,CAAA,EAAA,MAAa;AAkB9B;AAYA;;;;AAW0B,UAtUT,aAAA,CAsUS;;;;;;;;;;;;;;;KAtTd,kBAAA,aAA+B;UAE1B,cAAA;oBACE;;;;;;;KAQP,eAAA;;;;;;;;;;;;;UAcK,iBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;UA4BA,WAAA;;;;;;;;;;;;;;;;;;;;;;;;QAwBV;;;;;QAKA;;;KAIK,iBAAA;;;;;;UAOK,SAAA;;;;;WAKP;;;;;;;;UASO,YAAA;;cAEJ;;cAEA,eAAe;;YAEjB,eAAe;;;;;;;;UAST,cAAA;;YAEN;;;;;;;UAQM;cACJ,QAAQ,OAAO,MAAM;;;;;;;;UASjB;;;;;;;;;;;;;;;;;;;;;;;;;QAyBV,cAAc;;;aAGT;YACD,cAAc;;;KAIpB,gCAAgC,4BACpC;;IAGG,cAAc;;;;;KAON,+BACK,2BAA2B,qCAC/B,iBAAiB,aAAa,gBAAgB;;;;;;;;;;;;;;UAe1C,oBACH,iCACV,gDAEa,iCACb,gDAEa,2BAA2B;;SAGpC;;YAEG;;YAEA;;WAED,eAAe;;;;;;UAOR,sBAAA;;;;OAIX;WACI;;;;;QAKH;;;UAIU,oBAAA;;UAER;;;;;;;UAQQ,qBAAA;aACL;WACF;;;UAIO,oBAAA;;;;aAIL;;;YAGD;;;;;UAMM,aAAA;;;;;;;;YAQN;;;;;;;;;UAUM,cAAA;;;;;;;;;;;UAYA,UAAA;;;;;;;;;;WAUP;aACE"}