@hexclave/shared 1.0.61 → 1.0.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{admin-interface-ChuyYSXj.d.ts → admin-interface-D63SFHX_.d.ts} +94 -12
- package/dist/admin-interface-D63SFHX_.d.ts.map +1 -0
- package/dist/{admin-metrics-1yiWGq9z.d.ts → admin-metrics-bsOkw4YQ.d.ts} +15 -15
- package/dist/{admin-metrics-1yiWGq9z.d.ts.map → admin-metrics-bsOkw4YQ.d.ts.map} +1 -1
- package/dist/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js +1 -1
- package/dist/ai/unified-prompts/skill-site-prompt-parts/deployments-skill.d.ts +5 -0
- package/dist/ai/unified-prompts/skill-site-prompt-parts/deployments-skill.d.ts.map +1 -0
- package/dist/ai/unified-prompts/skill-site-prompt-parts/deployments-skill.js +128 -0
- package/dist/ai/unified-prompts/skill-site-prompt-parts/deployments-skill.js.map +1 -0
- package/dist/ai/unified-prompts/skill-site-prompt.d.ts +3 -1
- package/dist/ai/unified-prompts/skill-site-prompt.d.ts.map +1 -1
- package/dist/ai/unified-prompts/skill-site-prompt.js +11 -0
- package/dist/ai/unified-prompts/skill-site-prompt.js.map +1 -1
- package/dist/apps/apps-config.d.ts +6 -0
- package/dist/apps/apps-config.d.ts.map +1 -1
- package/dist/apps/apps-config.js +6 -0
- package/dist/apps/apps-config.js.map +1 -1
- package/dist/{client-interface-C4H4gn_G.d.ts → client-interface-DvkciaL0.d.ts} +10 -10
- package/dist/{client-interface-C4H4gn_G.d.ts.map → client-interface-DvkciaL0.d.ts.map} +1 -1
- package/dist/config/schema-fuzzer.test.js +38 -1
- package/dist/config/schema-fuzzer.test.js.map +1 -1
- package/dist/config/schema.d.ts +2 -2
- package/dist/config/schema.js +45 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/config-authoring.d.ts +1 -1
- package/dist/{current-user-BCkMYzHx.d.ts → current-user-BBoN3hsn.d.ts} +17 -17
- package/dist/{current-user-BCkMYzHx.d.ts.map → current-user-BBoN3hsn.d.ts.map} +1 -1
- package/dist/{email-outbox-BRZiK0ZG.d.ts → email-outbox-CqzwInBL.d.ts} +313 -313
- package/dist/{email-outbox-BRZiK0ZG.d.ts.map → email-outbox-CqzwInBL.d.ts.map} +1 -1
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js +1 -1
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/deployments-skill.d.ts +5 -0
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/deployments-skill.d.ts.map +1 -0
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/deployments-skill.js +128 -0
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/deployments-skill.js.map +1 -0
- package/dist/esm/ai/unified-prompts/skill-site-prompt.d.ts +3 -1
- package/dist/esm/ai/unified-prompts/skill-site-prompt.d.ts.map +1 -1
- package/dist/esm/ai/unified-prompts/skill-site-prompt.js +10 -1
- package/dist/esm/ai/unified-prompts/skill-site-prompt.js.map +1 -1
- package/dist/esm/apps/apps-config.d.ts +6 -0
- package/dist/esm/apps/apps-config.d.ts.map +1 -1
- package/dist/esm/apps/apps-config.js +6 -0
- package/dist/esm/apps/apps-config.js.map +1 -1
- package/dist/esm/config/schema-fuzzer.test.js +38 -1
- package/dist/esm/config/schema-fuzzer.test.js.map +1 -1
- package/dist/esm/config/schema.d.ts +249 -119
- package/dist/esm/config/schema.d.ts.map +1 -1
- package/dist/esm/config/schema.js +42 -1
- package/dist/esm/config/schema.js.map +1 -1
- package/dist/esm/interface/admin-interface.d.ts +83 -1
- package/dist/esm/interface/admin-interface.d.ts.map +1 -1
- package/dist/esm/interface/admin-interface.js +48 -0
- package/dist/esm/interface/admin-interface.js.map +1 -1
- package/dist/esm/interface/admin-metrics.d.ts +14 -14
- package/dist/esm/interface/conversations.d.ts +37 -37
- package/dist/esm/interface/crud/current-user.d.ts +16 -16
- package/dist/esm/interface/crud/email-outbox.d.ts +312 -312
- package/dist/esm/interface/crud/invoices.d.ts +2 -2
- package/dist/esm/interface/crud/products.d.ts +23 -23
- package/dist/esm/interface/crud/project-api-keys.d.ts +4 -4
- package/dist/esm/interface/crud/projects.d.ts +59 -59
- package/dist/esm/interface/crud/team-member-profiles.d.ts +32 -32
- package/dist/esm/interface/crud/transactions.d.ts +29 -29
- package/dist/esm/interface/crud/transactions.d.ts.map +1 -1
- package/dist/esm/interface/crud/users.d.ts +22 -22
- package/dist/esm/interface/plan-usage.d.ts +1 -1
- package/dist/esm/interface/webhooks.d.ts +4 -4
- package/dist/esm/known-errors.d.ts +4 -4
- package/dist/esm/schema-fields.d.ts +12 -12
- package/dist/esm/sessions.d.ts +9 -9
- package/dist/esm/utils/tar.d.ts +26 -0
- package/dist/esm/utils/tar.d.ts.map +1 -0
- package/dist/esm/utils/tar.js +136 -0
- package/dist/esm/utils/tar.js.map +1 -0
- package/dist/helpers/password.d.ts +1 -1
- package/dist/helpers/production-mode.d.ts +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/interface/admin-interface.d.ts +3 -3
- package/dist/interface/admin-interface.js +48 -0
- package/dist/interface/admin-interface.js.map +1 -1
- package/dist/interface/admin-metrics.d.ts +1 -1
- package/dist/interface/client-interface.d.ts +1 -1
- package/dist/interface/conversations.d.ts +37 -37
- package/dist/interface/crud/current-user.d.ts +1 -1
- package/dist/interface/crud/email-outbox.d.ts +1 -1
- package/dist/interface/crud/invoices.d.ts +1 -1
- package/dist/interface/crud/products.d.ts +1 -1
- package/dist/interface/crud/project-api-keys.d.ts +1 -1
- package/dist/interface/crud/projects.d.ts +1 -1
- package/dist/interface/crud/team-member-profiles.d.ts +1 -1
- package/dist/interface/crud/transactions.d.ts +1 -1
- package/dist/interface/crud/users.d.ts +1 -1
- package/dist/interface/plan-usage.d.ts +1 -1
- package/dist/interface/server-interface.d.ts +1 -1
- package/dist/interface/webhooks.d.ts +1 -1
- package/dist/{invoices-BGLLnTlR.d.ts → invoices-CHo9YKbI.d.ts} +3 -3
- package/dist/{invoices-BGLLnTlR.d.ts.map → invoices-CHo9YKbI.d.ts.map} +1 -1
- package/dist/{known-errors-Bhd0JAgh.d.ts → known-errors-Bm4a61wL.d.ts} +5 -5
- package/dist/{known-errors-Bhd0JAgh.d.ts.map → known-errors-Bm4a61wL.d.ts.map} +1 -1
- package/dist/known-errors.d.ts +1 -1
- package/dist/{plan-usage-COq9I00z.d.ts → plan-usage-BaDxcLZ1.d.ts} +2 -2
- package/dist/{plan-usage-COq9I00z.d.ts.map → plan-usage-BaDxcLZ1.d.ts.map} +1 -1
- package/dist/{products-BkPf1X78.d.ts → products-D4o8A2W0.d.ts} +24 -24
- package/dist/{products-BkPf1X78.d.ts.map → products-D4o8A2W0.d.ts.map} +1 -1
- package/dist/{project-api-keys-CK9SIo0q.d.ts → project-api-keys--7V5X_UW.d.ts} +5 -5
- package/dist/{project-api-keys-CK9SIo0q.d.ts.map → project-api-keys--7V5X_UW.d.ts.map} +1 -1
- package/dist/{projects-CVqfljhv.d.ts → projects-BX5Y50kJ.d.ts} +60 -60
- package/dist/{projects-CVqfljhv.d.ts.map → projects-BX5Y50kJ.d.ts.map} +1 -1
- package/dist/{schema-BPMGhu_7.d.ts → schema-dJ_7rUCO.d.ts} +250 -120
- package/dist/schema-dJ_7rUCO.d.ts.map +1 -0
- package/dist/{schema-fields-C8sIQVTq.d.ts → schema-fields-DZtDQEEO.d.ts} +13 -13
- package/dist/{schema-fields-C8sIQVTq.d.ts.map → schema-fields-DZtDQEEO.d.ts.map} +1 -1
- package/dist/schema-fields.d.ts +1 -1
- package/dist/{server-interface-CRp4VVZh.d.ts → server-interface-Ra_vIHP4.d.ts} +8 -8
- package/dist/{server-interface-CRp4VVZh.d.ts.map → server-interface-Ra_vIHP4.d.ts.map} +1 -1
- package/dist/{sessions-COluKK6_.d.ts → sessions-CI-0TBQb.d.ts} +11 -11
- package/dist/{sessions-COluKK6_.d.ts.map → sessions-CI-0TBQb.d.ts.map} +1 -1
- package/dist/sessions.d.ts +1 -1
- package/dist/{team-member-profiles-CgYXR-Rx.d.ts → team-member-profiles-BoDEqx-0.d.ts} +33 -33
- package/dist/{team-member-profiles-CgYXR-Rx.d.ts.map → team-member-profiles-BoDEqx-0.d.ts.map} +1 -1
- package/dist/{transactions-7q13mxhG.d.ts → transactions-CHNUJ42J.d.ts} +30 -30
- package/dist/transactions-CHNUJ42J.d.ts.map +1 -0
- package/dist/{users-7MKfEyyq.d.ts → users-DHNRwoSz.d.ts} +24 -24
- package/dist/{users-7MKfEyyq.d.ts.map → users-DHNRwoSz.d.ts.map} +1 -1
- package/dist/utils/tar.d.ts +26 -0
- package/dist/utils/tar.d.ts.map +1 -0
- package/dist/utils/tar.js +138 -0
- package/dist/utils/tar.js.map +1 -0
- package/dist/{webhooks-C5gG85Ce.d.ts → webhooks-8Ts1Clcb.d.ts} +5 -5
- package/dist/{webhooks-C5gG85Ce.d.ts.map → webhooks-8Ts1Clcb.d.ts.map} +1 -1
- package/package.json +1 -1
- package/src/ai/unified-prompts/skill-site-prompt-parts/deployments-skill.ts +128 -0
- package/src/ai/unified-prompts/skill-site-prompt.ts +15 -0
- package/src/apps/apps-config.ts +9 -0
- package/src/config/schema-fuzzer.test.ts +37 -0
- package/src/config/schema.ts +193 -0
- package/src/interface/admin-interface.ts +173 -0
- package/src/utils/tar.tsx +261 -0
- package/dist/admin-interface-ChuyYSXj.d.ts.map +0 -1
- package/dist/schema-BPMGhu_7.d.ts.map +0 -1
- package/dist/transactions-7q13mxhG.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","names":[],"sources":["../../../src/config/schema.ts"],"mappings":";;;;;;;cAqBa,YAAA;AAAA,KACD,WAAA,UAAqB,YAAY;AAAA;EAAA,UAO1B,oBAAA;IACf,qCAAqC;EAAA;AAAA;AARzC;;;AAAA,cAsBa,mBAAA,EAAmB,KAAA,CAAA,YAAA;;;;;;;GAS9B,KAAA,CAAA,SAAA;;;;;;cA4FW,oBAAA,EAAoB,KAAA,CAAA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","names":[],"sources":["../../../src/config/schema.ts"],"mappings":"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"}
|
|
@@ -127,6 +127,29 @@ const branchPaymentsSchema = yupObject({
|
|
|
127
127
|
});
|
|
128
128
|
const branchDomain = yupObject({});
|
|
129
129
|
const branchOnboardingSchema = yupObject({ requireEmailVerification: yupBoolean() });
|
|
130
|
+
const DEPLOYMENT_ENV_VAR_KEY_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
131
|
+
const DEPLOYMENT_SECRET_KEY_REGEX = /^[a-zA-Z0-9_-]+$/;
|
|
132
|
+
const DEPLOYMENT_CONNECTION_VALUE_REGEX = /^[a-zA-Z0-9_-]+\.[A-Za-z0-9_]+$/;
|
|
133
|
+
const deploymentEnvVarSchema = yupObject({
|
|
134
|
+
type: yupString().oneOf(["secret", "connection"]).optional(),
|
|
135
|
+
value: yupString().when("type", ([type], schema) => {
|
|
136
|
+
switch (type) {
|
|
137
|
+
case "secret": return schema.oneOf([void 0], "deployment env vars with type \"secret\" must not have a value — the value is supplied at deploy time via `hexclave deploy --secret <key>=<value>`");
|
|
138
|
+
case "connection": return schema.defined().matches(DEPLOYMENT_CONNECTION_VALUE_REGEX, "deployment env vars with type \"connection\" must reference a service output like \"hexclave.projectId\"");
|
|
139
|
+
default: return schema.defined();
|
|
140
|
+
}
|
|
141
|
+
}),
|
|
142
|
+
key: yupString().when("type", ([type], schema) => type === "secret" ? schema.defined().matches(DEPLOYMENT_SECRET_KEY_REGEX, "deployment secret keys must contain only letters, numbers, underscores, and hyphens") : schema.oneOf([void 0], "deployment env vars may only have a key when their type is \"secret\""))
|
|
143
|
+
});
|
|
144
|
+
const branchDeploymentsSchema = yupObject({ services: yupRecord(userSpecifiedIdSchema("serviceId").notOneOf(["hexclave"], "The service id \"hexclave\" is reserved for the managed Hexclave service"), yupObject({
|
|
145
|
+
type: yupString().oneOf(["vercel"]).defined(),
|
|
146
|
+
framework: yupString().optional(),
|
|
147
|
+
installCommand: yupString().optional(),
|
|
148
|
+
buildCommand: yupString().optional(),
|
|
149
|
+
outputDirectory: yupString().optional(),
|
|
150
|
+
rootDirectory: yupString().optional(),
|
|
151
|
+
env: yupRecord(yupString().matches(DEPLOYMENT_ENV_VAR_KEY_REGEX, "deployment env var keys must start with a letter or underscore and contain only letters, digits, and underscores"), deploymentEnvVarSchema)
|
|
152
|
+
})) });
|
|
130
153
|
const branchConfigSchema = canNoLongerBeOverridden(projectConfigSchema, ["sourceOfTruth", "project"]).concat(yupObject({
|
|
131
154
|
rbac: branchRbacSchema,
|
|
132
155
|
teams: yupObject({
|
|
@@ -145,6 +168,7 @@ const branchConfigSchema = canNoLongerBeOverridden(projectConfigSchema, ["source
|
|
|
145
168
|
templates: schemaFields.emailTemplateListSchema
|
|
146
169
|
}),
|
|
147
170
|
payments: branchPaymentsSchema,
|
|
171
|
+
"deployments-alpha": branchDeploymentsSchema,
|
|
148
172
|
dataVault: yupObject({ stores: yupRecord(userSpecifiedIdSchema("storeId"), yupObject({ displayName: yupString() })) })
|
|
149
173
|
}));
|
|
150
174
|
const environmentAnalyticsSchema = yupObject({ queryFolders: yupRecord(userSpecifiedIdSchema("folderId"), yupObject({
|
|
@@ -261,6 +285,10 @@ function migrateConfigOverride(type, oldUnmigratedConfigOverride) {
|
|
|
261
285
|
});
|
|
262
286
|
if (type === "project") res = removeProperty(res, (p) => p[0] === "sourceOfTruth");
|
|
263
287
|
if (type === "branch") res = removeProperty(res, (p) => p[0] === "dbSync");
|
|
288
|
+
if (isBranchOrHigher) {
|
|
289
|
+
res = renameProperty(res, "deployments", "deployments-alpha");
|
|
290
|
+
res = renameProperty(res, "apps.installed.deployments", "deployments-alpha");
|
|
291
|
+
}
|
|
264
292
|
return res;
|
|
265
293
|
}
|
|
266
294
|
function removeProperty(obj, pathCond) {
|
|
@@ -427,6 +455,19 @@ const organizationConfigDefaults = {
|
|
|
427
455
|
type: void 0,
|
|
428
456
|
connectionString: void 0
|
|
429
457
|
}) },
|
|
458
|
+
"deployments-alpha": { services: (key) => ({
|
|
459
|
+
type: void 0,
|
|
460
|
+
framework: void 0,
|
|
461
|
+
installCommand: void 0,
|
|
462
|
+
buildCommand: void 0,
|
|
463
|
+
outputDirectory: void 0,
|
|
464
|
+
rootDirectory: void 0,
|
|
465
|
+
env: (envVarKey) => ({
|
|
466
|
+
type: void 0,
|
|
467
|
+
value: void 0,
|
|
468
|
+
key: void 0
|
|
469
|
+
})
|
|
470
|
+
}) },
|
|
430
471
|
dataVault: { stores: (key) => ({ displayName: "Unnamed Vault" }) },
|
|
431
472
|
analytics: { queryFolders: (key) => ({
|
|
432
473
|
displayName: "Unnamed Folder",
|
|
@@ -726,6 +767,6 @@ typeAssert()();
|
|
|
726
767
|
typeAssert()();
|
|
727
768
|
typeAssertExtends()();
|
|
728
769
|
//#endregion
|
|
729
|
-
export { applyBranchDefaults, applyEnvironmentDefaults, applyOrganizationDefaults, applyProjectDefaults, assertNoConfigOverrideErrors, branchConfigSchema, branchPaymentsSchema, configLevels, environmentConfigSchema, getConfigOverrideErrors, getIncompleteConfigWarnings, migrateConfigOverride, organizationConfigSchema, projectConfigSchema, sanitizeBranchConfig, sanitizeEnvironmentConfig, sanitizeOrganizationConfig, sanitizeProjectConfig };
|
|
770
|
+
export { DEPLOYMENT_CONNECTION_VALUE_REGEX, DEPLOYMENT_ENV_VAR_KEY_REGEX, DEPLOYMENT_SECRET_KEY_REGEX, applyBranchDefaults, applyEnvironmentDefaults, applyOrganizationDefaults, applyProjectDefaults, assertNoConfigOverrideErrors, branchConfigSchema, branchPaymentsSchema, configLevels, deploymentEnvVarSchema, environmentConfigSchema, getConfigOverrideErrors, getIncompleteConfigWarnings, migrateConfigOverride, organizationConfigSchema, projectConfigSchema, sanitizeBranchConfig, sanitizeEnvironmentConfig, sanitizeOrganizationConfig, sanitizeProjectConfig };
|
|
730
771
|
|
|
731
772
|
//# sourceMappingURL=schema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","names":["stringSchema","objectSchema","yup"],"sources":["../../../src/config/schema.ts"],"sourcesContent":["// TODO: rename this file to spaghetti.ts because that's the kind of code here\n\n// IMPORTANT\n// WHENEVER YOU MAKE BACKWARDS-INCOMPATIBLE CHANGES TO THE CONFIG SCHEMA, YOU MUST UPDATE THE MIGRATION FUNCTIONS BELOW.\n// OTHERWISE THINGS WILL GO BOOM!!\n\nimport * as yup from \"yup\";\nimport { ALL_APPS } from \"../apps/apps-config\";\nimport { DEFAULT_EMAIL_TEMPLATES, DEFAULT_EMAIL_THEMES, DEFAULT_EMAIL_THEME_ID } from \"../helpers/emails\";\nimport * as schemaFields from \"../schema-fields\";\nimport { productSchema, userSpecifiedIdSchema, yupBoolean, yupDate, yupMixed, yupNever, yupNumber, yupObject, yupRecord, yupString, yupTuple, yupUnion } from \"../schema-fields\";\nimport { SUPPORTED_CURRENCIES } from \"../utils/currency-constants\";\nimport { HexclaveAssertionError } from \"../utils/errors\";\nimport { allProviders, allProviderTypes } from \"../utils/oauth\";\nimport { DeepFilterUndefined, DeepMerge, DeepRequiredOrUndefined, filterUndefined, get, getOrUndefined, has, isObjectLike, mapValues, set, typedAssign, typedEntries, typedFromEntries } from \"../utils/objects\";\nimport { Result } from \"../utils/results\";\nimport { stringCompare } from \"../utils/strings\";\nimport { CollapseObjectUnion, Expand, IntersectAll, IsUnion, typeAssert, typeAssertExtends, typeAssertIs } from \"../utils/types\";\nimport { Config, NormalizationError, NormalizesTo, assertNormalized, getInvalidConfigReason, normalize } from \"./format\";\nimport { migrateCatalogsToProductLines } from \"./migrate-catalogs-to-product-lines\";\n\nexport const configLevels = ['project', 'branch', 'environment', 'organization'] as const;\nexport type ConfigLevel = typeof configLevels[number];\nconst permissionRegex = /^\\$?[a-z0-9_:]+$/;\nconst customPermissionRegex = /^[a-z0-9_:]+$/;\nconst providerIdRegex = /^[a-z0-9_-]+$/;\n\ndeclare module \"yup\" {\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n export interface CustomSchemaMetadata {\n hexclaveConfigCanNoLongerBeOverridden?: true,\n }\n}\n\nfunction canNoLongerBeOverridden<T extends yup.AnyObjectSchema, K extends string[]>(schema: T, keys: K): yup.Schema<Omit<yup.InferType<T>, K[number]>, T['__context'], Omit<T['__default'], K[number]>, T['__flags']> {\n const notOmitted = schema.concat(yupObject(\n Object.fromEntries(keys.map(key => [key, schema.getNested(key).meta({ hexclaveConfigCanNoLongerBeOverridden: true })]))\n ));\n return notOmitted as any;\n}\n\n/**\n * All fields that can be overridden at this level.\n */\nexport const projectConfigSchema = yupObject({\n sourceOfTruth: yupUnion(\n yupObject({\n type: yupString().oneOf(['hosted']).defined(),\n }),\n ),\n project: yupObject({\n requirePublishableClientKey: yupBoolean(),\n }),\n});\n\n// --- NEW RBAC Schema ---\nconst branchRbacDefaultPermissions = yupRecord(\n yupString().matches(permissionRegex),\n yupBoolean().isTrue().optional(),\n);\n\nconst branchRbacSchema = yupObject({\n permissions: yupRecord(\n yupString().matches(customPermissionRegex),\n yupObject({\n description: yupString().optional(),\n scope: yupString().oneOf(['team', 'project']).optional(),\n containedPermissionIds: yupRecord(\n yupString().matches(permissionRegex),\n yupBoolean().isTrue().optional()\n ).optional(),\n }).optional(),\n ),\n defaultPermissions: yupObject({\n teamCreator: branchRbacDefaultPermissions,\n teamMember: branchRbacDefaultPermissions,\n signUp: branchRbacDefaultPermissions,\n }),\n});\n// --- END NEW RBAC Schema ---\n\n// --- NEW API Keys Schema ---\nconst branchApiKeysSchema = yupObject({\n enabled: yupObject({\n team: yupBoolean(),\n user: yupBoolean(),\n }),\n});\n// --- END NEW API Keys Schema ---\n\n// --- NEW Apps Schema ---\nconst appIds = Object.keys(ALL_APPS) as (keyof typeof ALL_APPS)[];\nconst branchAppsSchema = yupObject({\n installed: yupRecord(\n yupString().oneOf(appIds),\n yupObject({\n enabled: yupBoolean(),\n }),\n ),\n});\n// --- END NEW Apps Schema ---\n\n\nconst branchAuthSchema = yupObject({\n allowSignUp: yupBoolean(),\n password: yupObject({\n allowSignIn: yupBoolean(),\n }),\n otp: yupObject({\n allowSignIn: yupBoolean(),\n }),\n passkey: yupObject({\n allowSignIn: yupBoolean(),\n }),\n oauth: yupObject({\n accountMergeStrategy: yupString().oneOf(['link_method', 'raise_error', 'allow_duplicates']).optional(),\n providers: yupRecord(\n yupString().matches(permissionRegex),\n yupObject({\n type: yupString().oneOf(allProviderTypes).optional(),\n allowSignIn: yupBoolean(),\n allowConnectedAccounts: yupBoolean(),\n }),\n ),\n }),\n signUpRules: yupRecord(\n userSpecifiedIdSchema(\"signUpRuleId\"),\n yupObject({\n enabled: yupBoolean(),\n displayName: yupString(),\n // Priority for rule ordering (higher number = higher priority, evaluated first)\n // Rules with same priority are sorted alphabetically by ID\n priority: yupNumber().integer().min(0),\n // CEL expression string - evaluated against signup context\n // Example: 'email.endsWith(\"@gmail.com\") && authMethod == \"password\"'\n condition: yupString(),\n action: yupObject({\n type: yupString().oneOf(['allow', 'reject', 'restrict', 'log']).defined(),\n message: yupString().optional(), // for reject action custom message (internal use, not shown to user)\n }),\n }),\n ),\n signUpRulesDefaultAction: yupString().oneOf(['allow', 'reject']),\n});\n\nexport const branchPaymentsSchema = yupObject({\n blockNewPurchases: yupBoolean(),\n autoPay: yupObject({\n interval: schemaFields.dayIntervalSchema,\n }).optional(),\n productLines: yupRecord(\n userSpecifiedIdSchema(\"productLineId\"),\n yupObject({\n displayName: yupString().optional(),\n customerType: schemaFields.customerTypeSchema,\n }),\n ).meta({ openapiField: { description: 'The product lines that products can be in. All products in a product line (besides add-ons) are mutually exclusive.', exampleValue: { \"product-line-id\": { displayName: \"My Product Line\", customerType: \"user\" } } } }),\n products: yupRecord(\n userSpecifiedIdSchema(\"productId\"),\n productSchema,\n ),\n items: yupRecord(\n userSpecifiedIdSchema(\"itemId\"),\n yupObject({\n displayName: yupString().optional(),\n customerType: schemaFields.customerTypeSchema,\n }),\n ),\n}).optional().test(\n 'product-customer-type-matches-product-line',\n 'Product customer type must match its product line customer type',\n function(this: yup.TestContext<yup.AnyObject>, value) {\n if (!value) return true;\n const products = value.products;\n if (!isObjectLike(products)) return true;\n\n const productLines = value.productLines;\n for (const [productId, product] of Object.entries(products)) {\n if (!isObjectLike(product)) continue;\n const productLineId = product.productLineId;\n if (typeof productLineId !== \"string\" || productLineId.length === 0) continue;\n const productLine = isObjectLike(productLines) ? getOrUndefined(productLines, productLineId) : undefined;\n if (productLine === undefined) {\n return this.createError({\n message: `Product \"${productId}\" specifies product line ID \"${productLineId}\", but that product line does not exist`,\n path: `${this.path}.products.${productId}.productLineId`,\n });\n }\n if (!isObjectLike(productLine)) continue;\n if (product.customerType !== productLine.customerType) {\n return this.createError({\n message: `Product \"${productId}\" has customer type \"${product.customerType}\" but its product line \"${productLineId}\" has customer type \"${productLine.customerType}\"`,\n path: `${this.path}.products.${productId}.customerType`,\n });\n }\n }\n return true;\n }\n);\nimport.meta.vitest?.test(\"branchPaymentsSchema accepts partial payments config without products\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n blockNewPurchases: true,\n }, { abortEarly: false })).resolves.toMatchObject({\n blockNewPurchases: true,\n });\n});\n\nimport.meta.vitest?.test(\"branchPaymentsSchema accepts product lines without products\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n productLines: {\n pro: {\n displayName: \"Pro\",\n customerType: \"user\",\n },\n },\n }, { abortEarly: false })).resolves.toMatchObject({\n productLines: {\n pro: {\n displayName: \"Pro\",\n customerType: \"user\",\n },\n },\n });\n});\n\nimport.meta.vitest?.test(\"branchPaymentsSchema rejects a product that references a missing product line\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n products: {\n pro: {\n customerType: \"user\",\n productLineId: \"missing-line\",\n prices: {},\n },\n },\n }, { abortEarly: false })).rejects.toThrowErrorMatchingInlineSnapshot(`[ValidationError: Product \"pro\" specifies product line ID \"missing-line\", but that product line does not exist]`);\n});\n\nimport.meta.vitest?.test(\"branchPaymentsSchema rejects null product entries without throwing a raw TypeError\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n products: {\n pro: null,\n },\n }, { abortEarly: false })).rejects.toThrowErrorMatchingInlineSnapshot(`[ValidationError: products cannot be null]`);\n});\n\nimport.meta.vitest?.test(\"branchPaymentsSchema rejects null product line entries without throwing a raw TypeError\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n productLines: {\n teamLine: null,\n },\n products: {\n pro: {\n customerType: \"user\",\n productLineId: \"teamLine\",\n prices: {},\n },\n },\n }, { abortEarly: false })).rejects.toThrowErrorMatchingInlineSnapshot(`[ValidationError: productLines cannot be null]`);\n});\n\nimport.meta.vitest?.test(\"branchPaymentsSchema rejects a product whose customer type differs from its product line\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n productLines: {\n teamLine: {\n customerType: \"team\",\n },\n },\n products: {\n pro: {\n customerType: \"user\",\n productLineId: \"teamLine\",\n prices: {},\n },\n },\n }, { abortEarly: false })).rejects.toThrowErrorMatchingInlineSnapshot(`[ValidationError: Product \"pro\" has customer type \"user\" but its product line \"teamLine\" has customer type \"team\"]`);\n});\n\nimport.meta.vitest?.test(\"branchPaymentsSchema lets productLineId schema reject empty IDs\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n products: {\n pro: {\n customerType: \"user\",\n productLineId: \"\",\n prices: {},\n },\n },\n }, { abortEarly: false })).rejects.toThrowErrorMatchingInlineSnapshot(`[ValidationError: productLineId must contain only letters, numbers, underscores, and hyphens, and not start with a hyphen]`);\n});\n\nconst branchDomain = yupObject({});\n\nconst branchOnboardingSchema = yupObject({\n requireEmailVerification: yupBoolean(),\n});\n\n\nexport const branchConfigSchema = canNoLongerBeOverridden(projectConfigSchema, [\n \"sourceOfTruth\",\n \"project\",\n]).concat(yupObject({\n rbac: branchRbacSchema,\n\n teams: yupObject({\n createPersonalTeamOnSignUp: yupBoolean(),\n allowClientTeamCreation: yupBoolean(),\n }),\n\n users: yupObject({\n allowClientUserDeletion: yupBoolean(),\n }),\n\n onboarding: branchOnboardingSchema,\n\n apiKeys: branchApiKeysSchema,\n\n apps: branchAppsSchema,\n\n domains: branchDomain,\n\n auth: branchAuthSchema,\n\n emails: yupObject({\n selectedThemeId: schemaFields.emailThemeSchema,\n themes: schemaFields.emailThemeListSchema,\n templates: schemaFields.emailTemplateListSchema,\n }),\n\n payments: branchPaymentsSchema,\n\n\n dataVault: yupObject({\n stores: yupRecord(\n userSpecifiedIdSchema(\"storeId\"),\n yupObject({\n displayName: yupString(),\n }),\n ),\n }),\n}));\n\n\n// --- Analytics Schema (environment config only - not pushable) ---\nconst environmentAnalyticsSchema = yupObject({\n queryFolders: yupRecord(\n userSpecifiedIdSchema(\"folderId\"),\n yupObject({\n displayName: yupString(),\n sortOrder: yupNumber().optional(),\n queries: yupRecord(\n userSpecifiedIdSchema(\"queryId\"),\n yupObject({\n displayName: yupString(),\n sqlQuery: yupString(), // SQL query string (not English language)\n description: yupString().optional(),\n }),\n ),\n }),\n ),\n});\n// --- END Analytics Schema ---\n\nexport const environmentConfigSchema = branchConfigSchema.concat(yupObject({\n auth: branchConfigSchema.getNested(\"auth\").concat(yupObject({\n oauth: branchConfigSchema.getNested(\"auth\").getNested(\"oauth\").concat(yupObject({\n providers: yupRecord(\n yupString().matches(providerIdRegex),\n yupObject({\n type: yupString().oneOf(allProviderTypes).optional(),\n isShared: yupBoolean(),\n clientId: schemaFields.oauthClientIdSchema.optional(),\n clientSecret: schemaFields.oauthClientSecretSchema.optional(),\n customCallbackUrl: schemaFields.oauthCustomCallbackUrlSchema.optional().when('isShared', {\n is: true,\n then: (schema) => schema.oneOf([undefined], 'customCallbackUrl cannot be set for shared OAuth providers'),\n otherwise: (schema) => schema,\n }),\n facebookConfigId: schemaFields.oauthFacebookConfigIdSchema.optional(),\n microsoftTenantId: schemaFields.oauthMicrosoftTenantIdSchema.optional(),\n appleBundles: yupRecord(\n userSpecifiedIdSchema(\"appleBundleId\"),\n yupObject({\n bundleId: schemaFields.oauthAppleBundleIdSchema,\n }),\n ).optional(),\n // Custom OIDC provider fields (only used when type is \"custom_oidc\")\n issuerUrl: schemaFields.oauthIssuerUrlSchema.optional(),\n scope: schemaFields.oauthScopeSchema.optional(),\n displayName: yupString().optional(),\n allowSignIn: yupBoolean().optional(),\n allowConnectedAccounts: yupBoolean().optional(),\n }),\n ),\n })),\n })),\n\n emails: branchConfigSchema.getNested(\"emails\").concat(yupObject({\n server: yupObject({\n isShared: yupBoolean(),\n provider: yupString().oneOf(['resend', 'smtp', 'managed']).optional(),\n host: schemaFields.emailHostSchema.optional().nonEmpty(),\n port: schemaFields.emailPortSchema.optional(),\n username: schemaFields.emailUsernameSchema.optional().nonEmpty(),\n password: schemaFields.emailPasswordSchema.optional().nonEmpty().when(['provider', 'isShared'], {\n is: (provider: string | undefined, isShared: boolean) => provider === 'managed' && isShared === false,\n then: (schema) => schema.defined(\"Password is required when using managed email provider\"),\n otherwise: (schema) => schema.optional(),\n }),\n senderName: schemaFields.emailSenderNameSchema.optional().nonEmpty(),\n senderEmail: schemaFields.emailSenderEmailSchema.optional().nonEmpty(),\n managedSubdomain: yupString().optional().nonEmpty().when(['provider', 'isShared'], {\n is: (provider: string | undefined, isShared: boolean) => provider === 'managed' && isShared === false,\n then: (schema) => schema.defined(\"Managed subdomain is required when using managed email provider\"),\n otherwise: (schema) => schema.optional(),\n }),\n managedSenderLocalPart: yupString().optional().nonEmpty().when(['provider', 'isShared'], {\n is: (provider: string | undefined, isShared: boolean) => provider === 'managed' && isShared === false,\n then: (schema) => schema.defined(\"Managed sender local part is required when using managed email provider\"),\n otherwise: (schema) => schema.optional(),\n }),\n }),\n })),\n\n domains: branchConfigSchema.getNested(\"domains\").concat(yupObject({\n allowLocalhost: yupBoolean(),\n trustedDomains: yupRecord(\n userSpecifiedIdSchema(\"trustedDomainId\"),\n yupObject({\n baseUrl: schemaFields.wildcardUrlSchema.max(300), // TODO: replace with wildcardProtocolAndDomainSchema (this will require a migration as some configs have domains that are not valid wildcard protocol and domain patterns)\n handlerPath: schemaFields.handlerPathSchema.max(300),\n }),\n ),\n })),\n\n payments: branchConfigSchema.getNested(\"payments\").concat(yupObject({\n testMode: yupBoolean(),\n })),\n\n dbSync: yupObject({\n externalDatabases: yupRecord(\n userSpecifiedIdSchema(\"externalDatabaseId\"),\n yupObject({\n type: yupString().oneOf([\"postgres\"]).defined(),\n connectionString: yupString().when(\"type\", {\n is: \"postgres\",\n then: (schema) => schema.defined(),\n otherwise: (schema) => schema.optional(),\n }),\n }),\n ),\n }),\n\n analytics: environmentAnalyticsSchema,\n customDashboards: schemaFields.customDashboardsSchema,\n}));\n\nexport const organizationConfigSchema = environmentConfigSchema.concat(yupObject({}));\n\n\n// Migration functions\n//\n// These are used to migrate old config overrides to the new format on the database.\n//\n// THEY SHOULD NOT BE USED FOR ANY OTHER PURPOSE. They should not be used for default values. They should not be used\n// for sanitization. Instead, use the applicable functions for that.\n//\n// We run these migrations over the database when we do a big migration. USE THESE SPARINGLY. USE OTHER METHODS WHENEVER\n// POSSIBLE.\n//\n// The result of this function should be reproducible, and should not contain ANY randomness/non-determinism.\nexport function migrateConfigOverride(type: \"project\" | \"branch\" | \"environment\" | \"organization\", oldUnmigratedConfigOverride: any): any {\n const isBranchOrHigher = [\"branch\", \"environment\", \"organization\"].includes(type);\n const isEnvironmentOrHigher = [\"environment\", \"organization\"].includes(type);\n\n let res = oldUnmigratedConfigOverride;\n\n // BEGIN 2025-07-28: emails.theme is now emails.selectedThemeId\n if (isBranchOrHigher) {\n res = renameProperty(res, \"emails.theme\", \"selectedThemeId\");\n }\n // END\n\n // BEGIN 2025-07-28: domains.trustedDomains can no longer be an array\n if (isEnvironmentOrHigher) {\n res = mapProperty(res, p => p.join(\".\") === \"domains.trustedDomains\", (value) => {\n if (Array.isArray(value)) {\n return typedFromEntries(value.map((v, i) => [`${i}`, v]));\n }\n return value;\n });\n }\n // END\n\n // BEGIN 2025-07-28: themeList and templateList have been renamed (this was before the email release, so they're safe to remove)\n if (isBranchOrHigher) {\n res = removeProperty(res, p => p.join(\".\") === \"emails.themeList\");\n res = removeProperty(res, p => p.join(\".\") === \"emails.templateList\");\n }\n // END\n\n // BEGIN 2025-07-28: sourceOfTruth was mistakenly written to the environment config in some cases, so let's remove it\n if (isBranchOrHigher) {\n res = removeProperty(res, p => p.join(\".\") === \"sourceOfTruth\");\n }\n // END\n\n // BEGIN 2025-08-25: stripeAccountId and stripeAccountSetupComplete are unused, so let's remove them\n if (isBranchOrHigher) {\n res = removeProperty(res, p => p.join(\".\") === \"payments.stripeAccountId\");\n res = removeProperty(res, p => p.join(\".\") === \"payments.stripeAccountSetupComplete\");\n }\n // END\n\n // BEGIN 2025-08-25: payments.items.default is no longer used, so let's remove it\n if (isBranchOrHigher) {\n res = removeProperty(res, p => p.length === 4 && p[0] === \"payments\" && p[1] === \"items\" && p[3] === \"default\");\n }\n // END\n\n // BEGIN 2025-09-23: payments.offers is now payments.products\n if (isBranchOrHigher) {\n res = renameProperty(res, \"payments.offers\", \"products\");\n }\n // END\n\n // BEGIN 2025-09-23: payments.groups is now payments.catalogs\n if (isBranchOrHigher) {\n res = renameProperty(res, \"payments.groups\", \"catalogs\");\n }\n // END\n\n // BEGIN 2025-09-23: payments.products.*.groupId is now payments.products.*.catalogId\n if (isBranchOrHigher) {\n res = renameProperty(res, (p) => p.length === 4 && p[0] === \"payments\" && p[1] === \"products\" && p[3] === \"groupId\", (p) => \"catalogId\");\n }\n // END\n\n // BEGIN 2025-10-29: Removed workflows and everything associated with it\n if (isBranchOrHigher) {\n res = removeProperty(res, p => p[0] === \"workflows\");\n res = removeProperty(res, p => p[0] === \"apps\" && p[1] === \"installed\" && p[2] === \"workflows\");\n }\n // END\n\n // BEGIN 2026-01-14: payments.catalogs is now payments.productLines (with customerType inferred from products) and payments.products.*.catalogId is now payments.products.*.productLineId\n if (isBranchOrHigher) {\n res = migrateCatalogsToProductLines(res);\n }\n // END\n\n // BEGIN 2026-04-21: `include-by-default` product prices are no longer supported. Rewrite to an empty price map so legacy configs continue to load.\n if (isBranchOrHigher) {\n // Match `payments.products.<productId>.prices` regardless of how many segments the\n // product-ID portion contributes. mapProperty splits dot-notation override keys on\n // \".\", so a product whose ID itself contains \".\" (e.g. \"my.product\") would produce\n // a path with >4 segments and silently miss an exact-length match.\n res = mapProperty(res, p => p.length >= 4 && p[0] === \"payments\" && p[1] === \"products\" && p[p.length - 1] === \"prices\", (value) => {\n if (value === \"include-by-default\") return {};\n return value;\n });\n }\n // END\n\n // BEGIN 2026-05-23: external source-of-truth config was never used and is no longer supported.\n // Drop the override so legacy Neon/Postgres configs continue to render as the hosted default.\n if (type === \"project\") {\n res = removeProperty(res, p => p[0] === \"sourceOfTruth\");\n }\n // END\n\n // BEGIN 2026-07-01: dbSync.externalDatabases contains environment-specific connection strings.\n // It should never be rendered from branch config, which can be read by branch-scoped tools.\n if (type === \"branch\") {\n res = removeProperty(res, p => p[0] === \"dbSync\");\n }\n // END\n\n // return the result\n return res;\n};\n\nimport.meta.vitest?.test(\"migrateConfigOverride removes legacy sourceOfTruth overrides\", ({ expect }) => {\n expect(migrateConfigOverride(\"project\", {\n sourceOfTruth: {\n type: \"neon\",\n connectionStrings: {\n main: \"postgres://user:password@neon.example.com/database\",\n },\n },\n })).toEqual({});\n\n expect(migrateConfigOverride(\"project\", {\n \"sourceOfTruth.type\": \"postgres\",\n \"sourceOfTruth.connectionString\": \"postgres://user:password@host:5432/database\",\n })).toEqual({});\n});\n\nimport.meta.vitest?.test(\"migrateConfigOverride removes legacy branch-level dbSync overrides\", ({ expect }) => {\n const dbSync = {\n externalDatabases: {\n main: {\n type: \"postgres\",\n connectionString: \"postgres://user:password@host:5432/database\",\n },\n },\n };\n\n expect(migrateConfigOverride(\"branch\", { dbSync })).toEqual({});\n expect(migrateConfigOverride(\"environment\", { dbSync })).toEqual({ dbSync });\n});\n\nfunction removeProperty(obj: Record<string, any>, pathCond: (path: (string | symbol)[]) => boolean): any {\n return mapProperty(obj, pathCond, () => undefined);\n}\n\nfunction mapProperty(obj: Record<string, any>, pathCond: (path: string[]) => boolean, mapper: (value: any) => any): any {\n const res: Record<string, any> = Array.isArray(obj) ? [] : {};\n for (const [key, value] of typedEntries(obj)) {\n const path = key.split(\".\");\n if (pathCond(path)) {\n const newValue = mapper(value);\n if (newValue !== undefined) {\n set(res, key, newValue);\n } else {\n // do nothing\n }\n } else if (isObjectLike(value)) {\n set(res, key, mapProperty(value, p => pathCond([...path, ...p]), mapper));\n } else {\n set(res, key, value);\n }\n }\n return res;\n}\nimport.meta.vitest?.test(\"mapProperty - basic property mapping\", ({ expect }) => {\n expect(mapProperty({ a: { b: { c: 1 } } }, p => p.join(\".\") === \"a.b.c\", (value) => value + 1)).toEqual({ a: { b: { c: 2 } } });\n expect(mapProperty({ a: { b: { c: 1 } } }, p => p.join(\".\") === \"a.b.d\", (value) => value + 1)).toEqual({ a: { b: { c: 1 } } });\n expect(mapProperty({ x: 5 }, p => p.join(\".\") === \"x\", (value) => value * 2)).toEqual({ x: 10 });\n expect(mapProperty({ a: { b: { c: 1 } } }, p => p.join(\".\") === \"b.c\", (value) => value * 10)).toEqual({ a: { b: { c: 1 } } });\n expect(mapProperty({ a: 1 }, p => p.join(\".\") === \"b.c\", (value) => value)).toEqual({ a: 1 });\n expect(mapProperty({ \"a.b\": { c: 1 } }, p => p.join(\".\") === \"a.b.c\", (value) => value + 1)).toEqual({ \"a.b\": { c: 2 } });\n\n expect(mapProperty({ a: { b: { c: 1 } } }, p => p.length === 3 && p[0] === \"a\" && p[1] === \"b\", (value) => value + 1)).toEqual({ a: { b: { c: 2 } } });\n\n // The include-by-default migration uses a prefix/suffix path predicate against dot-notation\n // keys: `payments.products.<productId>.prices`, where the product-ID portion may be one or\n // more segments (since override keys are dot-paths and a product ID may itself contain \".\").\n // Verify it matches whether the override is fully nested, dot-notation at the root, a mix,\n // or contains a dotted product ID.\n const sentinelToEmpty = (v: any) => v === \"include-by-default\" ? {} : v;\n const sentinelPred = (p: string[]) => p.length >= 4 && p[0] === \"payments\" && p[1] === \"products\" && p[p.length - 1] === \"prices\";\n expect(mapProperty({ \"payments.products.x.prices\": \"include-by-default\" }, sentinelPred, sentinelToEmpty))\n .toEqual({ \"payments.products.x.prices\": {} });\n expect(mapProperty({ payments: { products: { x: { prices: \"include-by-default\" } } } }, sentinelPred, sentinelToEmpty))\n .toEqual({ payments: { products: { x: { prices: {} } } } });\n expect(mapProperty({ \"payments.products\": { x: { prices: \"include-by-default\" } } }, sentinelPred, sentinelToEmpty))\n .toEqual({ \"payments.products\": { x: { prices: {} } } });\n // Dotted product ID: \"my.product\" expands to two path segments, total 5.\n expect(mapProperty({ \"payments.products.my.product.prices\": \"include-by-default\" }, sentinelPred, sentinelToEmpty))\n .toEqual({ \"payments.products.my.product.prices\": {} });\n});\n\nfunction renameProperty(obj: Record<string, any>, oldPath: string | ((path: string[]) => boolean), newName: string | ((path: string[]) => string)): any {\n const pathCond = typeof oldPath === \"function\" ? oldPath : (p: string[]) => p.join(\".\") === oldPath;\n const pathMapper = typeof newName === \"function\" ? newName : (p: string[]) => (newName as string);\n\n const res: Record<string, any> = Array.isArray(obj) ? [] : {};\n for (const [key, originalValue] of typedEntries(obj)) {\n const path = key.split(\".\");\n\n for (let i = 0; i < path.length; i++) {\n const pathPrefix = path.slice(0, i + 1);\n if (pathCond(pathPrefix)) {\n const name = pathMapper(pathPrefix);\n if (name.includes(\".\")) throw new HexclaveAssertionError(`newName must not contain a dot. Provided: ${name}`);\n path[i] = name;\n }\n }\n\n const value = isObjectLike(originalValue) ? renameProperty(originalValue, p => pathCond([...path, ...p]), p => pathMapper([...path, ...p])) : originalValue;\n set(res, path.join(\".\"), value);\n }\n\n return res;\n}\nimport.meta.vitest?.test(\"renameProperty\", ({ expect }) => {\n // Basic\n expect(renameProperty({ a: 1 }, \"a\", \"b\")).toEqual({ b: 1 });\n expect(renameProperty({ b: { c: 1 } }, \"b.c\", \"d\")).toEqual({ b: { d: 1 } });\n expect(renameProperty({ a: { b: { c: 1 } } }, \"a.b.c\", \"d\")).toEqual({ a: { b: { d: 1 } } });\n expect(renameProperty({ a: { b: { c: 1 } } }, \"a.b.c.d\", \"e\")).toEqual({ a: { b: { c: 1 } } });\n expect(renameProperty({ a: { b: { c: 1 }, \"b.c\": 2 } }, \"b.c\", \"d\")).toEqual({ a: { b: { c: 1 }, \"b.c\": 2 } });\n expect(renameProperty({ a: { \"b.c.d\": 2 } }, \"a.b.c\", \"e\")).toEqual({ a: { \"b.e.d\": 2 } });\n expect(renameProperty({ a: { b: { c: 1 }, \"b.c\": 2 } }, \"a.b.c\", \"d\")).toEqual({ a: { b: { d: 1 }, \"b.d\": 2 } });\n expect(renameProperty({ a: { b: { c: 1, d: 2 } } }, \"a.b.c\", \"d\")).toEqual({ a: { b: { d: 2 } } });\n expect(renameProperty({ a: { b: { d: 2, c: 1 } } }, \"a.b.c\", \"d\")).toEqual({ a: { b: { d: 1 } } });\n\n // Functions\n expect(renameProperty({ a: 1 }, (p) => p.length === 1 && p[0] === \"a\", (p) => \"b\")).toEqual({ b: 1 });\n expect(renameProperty({ a: { b: { c: 1 } } }, (p) => p.length === 3 && p[0] === \"a\" && p[1] === \"b\" && p[2] === \"c\", (p) => \"d\")).toEqual({ a: { b: { d: 1 } } });\n expect(renameProperty({ a: { b: { c: 1 } } }, (p) => false, (p) => \"e\")).toEqual({ a: { b: { c: 1 } } });\n expect(renameProperty({ a: { b: { a: 1 } } }, (p) => p[p.length - 1] === \"a\", (p) => \"c\")).toEqual({ c: { b: { c: 1 } } });\n\n // Errors\n expect(() => renameProperty({ a: 1 }, \"a\", \"b.c\")).toThrow();\n});\n\n\n// Defaults\n// these are objects that are merged together to form the rendered config (see ./README.md)\n// Wherever an object could be used as a value, a function can instead be used to generate the default values on a per-key basis\n// To make sure you don't accidentally forget setting a default value, you must explicitly set fields with no default value to `undefined`.\n// NOTE: These values are the defaults of the schema, NOT the defaults for newly created projects. The values here signify what `null` means for each property. If you want new projects by default to have a certain value set to true, you should update the corresponding function in the backend instead.\nconst projectConfigDefaults = {\n sourceOfTruth: {\n type: 'hosted',\n },\n project: {\n requirePublishableClientKey: false,\n },\n} as const satisfies DefaultsType<ProjectRenderedConfigBeforeDefaults, []>;\n\nconst branchConfigDefaults = {} as const satisfies DefaultsType<BranchRenderedConfigBeforeDefaults, [typeof projectConfigDefaults]>;\n\nconst environmentConfigDefaults = {} as const satisfies DefaultsType<EnvironmentRenderedConfigBeforeDefaults, [typeof branchConfigDefaults, typeof projectConfigDefaults]>;\n\nconst organizationConfigDefaults = {\n rbac: {\n permissions: (key: string) => ({\n containedPermissionIds: (key: string) => undefined,\n description: undefined,\n scope: undefined,\n }),\n defaultPermissions: {\n teamCreator: (key: string) => undefined,\n teamMember: (key: string) => undefined,\n signUp: (key: string) => undefined,\n },\n },\n\n apiKeys: {\n enabled: {\n team: false,\n user: false,\n },\n },\n\n apps: {\n installed: typedFromEntries(appIds.map(appId => [appId, { enabled: false }])) as Record<string, { enabled: boolean } | undefined>,\n },\n\n teams: {\n createPersonalTeamOnSignUp: false,\n allowClientTeamCreation: false,\n },\n\n users: {\n allowClientUserDeletion: false,\n },\n\n onboarding: {\n requireEmailVerification: false,\n },\n\n domains: {\n allowLocalhost: false,\n trustedDomains: (key: string) => ({\n baseUrl: undefined,\n handlerPath: '/handler',\n }) as const,\n },\n\n auth: {\n allowSignUp: true,\n password: {\n allowSignIn: false,\n },\n otp: {\n allowSignIn: false,\n },\n passkey: {\n allowSignIn: false,\n },\n oauth: {\n accountMergeStrategy: 'link_method',\n providers: (key: string) => ({\n type: undefined,\n isShared: true,\n allowSignIn: false,\n allowConnectedAccounts: false,\n clientId: undefined,\n clientSecret: undefined,\n customCallbackUrl: undefined,\n facebookConfigId: undefined,\n microsoftTenantId: undefined,\n appleBundles: undefined,\n }),\n },\n signUpRules: (key: string) => ({\n enabled: false,\n displayName: undefined,\n priority: 0,\n condition: undefined,\n action: {\n type: 'allow',\n message: undefined,\n },\n }),\n signUpRulesDefaultAction: 'allow',\n },\n\n emails: {\n server: {\n isShared: true,\n provider: \"smtp\",\n host: undefined,\n port: undefined,\n username: undefined,\n password: undefined,\n senderName: undefined,\n senderEmail: undefined,\n managedSubdomain: undefined,\n managedSenderLocalPart: undefined,\n },\n selectedThemeId: DEFAULT_EMAIL_THEME_ID,\n themes: typedAssign((key: string) => ({\n displayName: \"Unnamed Theme\",\n tsxSource: \"Error: Theme config is missing TypeScript source code.\",\n }), DEFAULT_EMAIL_THEMES),\n templates: typedAssign((key: string) => ({\n displayName: \"Unnamed Template\",\n tsxSource: \"Error: Template config is missing TypeScript source code.\",\n themeId: undefined,\n }), DEFAULT_EMAIL_TEMPLATES),\n },\n\n payments: {\n blockNewPurchases: false,\n testMode: true,\n autoPay: undefined,\n productLines: (key: string) => ({\n displayName: undefined,\n customerType: undefined,\n }),\n products: (key: string) => ({\n displayName: key,\n productLineId: undefined,\n customerType: \"user\",\n freeTrial: undefined,\n serverOnly: false,\n stackable: undefined,\n isAddOnTo: false,\n prices: (key: string) => ({\n ...typedFromEntries(SUPPORTED_CURRENCIES.map(currency => [currency.code, undefined])),\n interval: undefined,\n serverOnly: false,\n freeTrial: undefined,\n }),\n includedItems: (key: string) => ({\n quantity: 0,\n repeat: \"never\",\n expires: \"when-repeated\",\n }),\n } as const),\n items: (key: string) => ({\n displayName: key,\n customerType: \"user\",\n } as const)\n },\n\n\n dbSync: {\n externalDatabases: (key: string) => ({\n type: undefined,\n connectionString: undefined,\n }),\n },\n\n dataVault: {\n stores: (key: string) => ({\n displayName: \"Unnamed Vault\",\n }),\n },\n\n analytics: {\n queryFolders: (key: string) => ({\n displayName: \"Unnamed Folder\",\n sortOrder: 0,\n queries: (queryKey: string) => ({\n displayName: \"Unnamed Query\",\n sqlQuery: \"\",\n description: undefined,\n }),\n }),\n },\n\n customDashboards: (key: string) => ({\n displayName: \"Unnamed Dashboard\",\n tsxSource: \"Error: Dashboard config is missing source code.\",\n }),\n} as const satisfies DefaultsType<OrganizationRenderedConfigBeforeDefaults, [typeof environmentConfigDefaults, typeof branchConfigDefaults, typeof projectConfigDefaults]>;\n\ntype _DeepOmitDefaultsImpl<T, U> = T extends object ? (\n (\n & /* keys that are both in T and U, *and* the key's value in U is not a subtype of the key's value in T */ { [K in { [Ki in keyof T & keyof U]: U[Ki] extends T[Ki] ? never : Ki }[keyof T & keyof U]]: DeepOmitDefaults<T[K], U[K] & object> }\n & /* keys that are in T but not in U */ { [K in Exclude<keyof T, keyof U>]: T[K] }\n )\n) : T;\ntype DeepOmitDefaults<T, U> = _DeepOmitDefaultsImpl<DeepFilterUndefined<T>, U>;\ntype DefaultsType<T, U extends any[]> = DeepReplaceAllowFunctionsForObjects<DeepOmitDefaults<DeepRequiredOrUndefined<T>, IntersectAll<{ [K in keyof U]: DeepReplaceFunctionsWithObjects<U[K]> }>>>;\ntypeAssertIs<DefaultsType<{ a: { b: Record<string, 123>, c: 456 } }, [{ a: { c: 456 } }]>, { a: { b: ((key: string) => 123) | Record<string, 123 | undefined> & ((key: string) => 123) } }>()();\n\ntype DeepReplaceAllowFunctionsForObjects<T> = T extends object\n ? (\n string extends keyof T\n ? ((arg: Exclude<keyof T, number>) => DeepReplaceAllowFunctionsForObjects<T[keyof T]>) & ({ [K in keyof T]?: DeepReplaceAllowFunctionsForObjects<T[K]> } | {})\n : { [K in keyof T]: DeepReplaceAllowFunctionsForObjects<T[K]> }\n )\n :\n T;\ntype ReplaceFunctionsWithObjects<T> = T & (T extends (arg: infer K extends string) => infer R ? Record<K, R> & object : unknown);\ntype DeepReplaceFunctionsWithObjects<T> = T extends object ? { [K in keyof ReplaceFunctionsWithObjects<T>]: DeepReplaceFunctionsWithObjects<ReplaceFunctionsWithObjects<T>[K]> } : T;\ntypeAssertIs<DeepReplaceFunctionsWithObjects<{ a: { b: 123 } & ((key: string) => number) }>, { a: { b: 123, [key: string]: number } }>()();\n\nfunction deepReplaceFunctionsWithObjects(obj: any, paths: string[] = []): any {\n const subPaths = (key: string) => {\n return paths.filter(p => p.split(\".\").length > 1 && p.split(\".\")[0] === key)\n .map(p => p.split(\".\").slice(1).join(\".\"));\n };\n const currentPaths = [...new Set(paths.map(p => p.split(\".\")[0]))];\n const nonDeepReplaced = {\n ...typeof obj === \"function\" ? filterUndefined(Object.fromEntries(currentPaths.map(k => [k, obj(k)]))) : {},\n ...obj,\n };\n return mapValues(nonDeepReplaced, (v, k) => (isObjectLike(v) ? deepReplaceFunctionsWithObjects(v as any, subPaths(k as string)) : v));\n}\nimport.meta.vitest?.test(\"deepReplaceFunctionsWithObjects\", ({ expect }) => {\n expect(deepReplaceFunctionsWithObjects(() => { })).toEqual({});\n expect(deepReplaceFunctionsWithObjects({ a: 3 })).toEqual({ a: 3 });\n expect(deepReplaceFunctionsWithObjects({ a: () => ({ b: 1 }) })).toEqual({ a: {} });\n expect(deepReplaceFunctionsWithObjects({ a: () => ({ b: 1 }) }, [\"a.c.d\"])).toEqual({ a: { c: { b: 1 } } });\n expect(deepReplaceFunctionsWithObjects(() => ({ b: 1 }), [\"a\"])).toEqual({ a: { b: 1 } });\n expect(deepReplaceFunctionsWithObjects({ a: typedAssign(() => ({}), { b: { c: 1 } }) })).toEqual({ a: { b: { c: 1 } } });\n});\n\ntype ApplyDefaults<D extends object | ((key: string) => unknown), C extends object> = {} extends D ? C : DeepMerge<DeepReplaceFunctionsWithObjects<D>, C>; // the {} extends D makes TypeScript not recurse if the defaults are empty, hence allowing us more recursion until \"type instantiation too deep\" kicks in... it's a total hack, but it works, so hey?\nfunction applyDefaults<D extends object | ((key: string) => unknown), C extends object>(defaults: D, config: C): ApplyDefaults<D, C> {\n const res: any = deepReplaceFunctionsWithObjects(defaults);\n\n outer: for (const [key, mergeValue] of Object.entries(config)) {\n if (!isObjectLike(mergeValue) && mergeValue !== null) {\n set(res, key, mergeValue);\n } else {\n const keyParts = key.split(\".\");\n let baseValue: any = defaults;\n let lastWasFunction = false;\n for (const [index, part] of keyParts.entries()) {\n if (!isObjectLike(baseValue)) {\n set(res, key, mergeValue ?? null);\n continue outer;\n }\n lastWasFunction = false;\n baseValue = has(baseValue, part) ? get(baseValue, part) : (typeof baseValue === 'function' ? (lastWasFunction = true, baseValue as any)(part) : undefined);\n }\n if (lastWasFunction && mergeValue == null) {\n set(res, key, null);\n } else if (!isObjectLike(baseValue)) {\n set(res, key, mergeValue ?? baseValue ?? null);\n } else {\n set(res, key, applyDefaults(baseValue, mergeValue ?? {}) as any);\n }\n }\n }\n return res as any;\n}\nimport.meta.vitest?.test(\"applyDefaults\", ({ expect }) => {\n // Basic\n expect(applyDefaults({ a: 1 }, { a: 2 })).toEqual({ a: 2 });\n expect(applyDefaults({ a: 1 }, { a: null })).toEqual({ a: 1 });\n expect(applyDefaults({}, { a: 1 })).toEqual({ a: 1 });\n expect(applyDefaults({ a: { b: 1 } }, { a: { b: 2 } })).toEqual({ a: { b: 2 } });\n expect(applyDefaults({ a: { b: 1 } }, { a: { c: 2 } })).toEqual({ a: { b: 1, c: 2 } });\n expect(applyDefaults({ a: { b: { c: 1, d: 2 } } }, { a: { b: { d: 3, e: 4 } } })).toEqual({ a: { b: { c: 1, d: 3, e: 4 } } });\n\n // Functions\n expect(applyDefaults((key: string) => ({ b: key }), { a: {} })).toEqual({ a: { b: \"a\" } });\n expect(applyDefaults((key: string) => ({ b: key }), { a: null })).toEqual({ a: null });\n expect(applyDefaults((key1: string) => (key2: string) => ({ a: key1, b: key2 }), { c: { d: {} } })).toEqual({ c: { d: { a: \"c\", b: \"d\" } } });\n expect(applyDefaults({ a: (key: string) => ({ b: key }) }, { a: { c: { d: 1 } } })).toEqual({ a: { c: { b: \"c\", d: 1 } } });\n expect(applyDefaults({ a: (key: string) => ({ b: key }) }, {})).toEqual({ a: {} });\n expect(applyDefaults({ a: (key: string) => ({ b: key }) }, { a: null })).toEqual({ a: {} });\n expect(applyDefaults({ a: (key: string) => ({ c: key }) }, { a: { b: null } })).toEqual({ a: { b: null } });\n expect(applyDefaults({ a: { b: (key: string) => ({ b: key }) } }, {})).toEqual({ a: { b: {} } });\n expect(applyDefaults(typedAssign(() => ({ b: 1 }), { a: { b: 1, c: 2 } }), { a: {} })).toEqual({ a: { b: 1, c: 2 } });\n expect(applyDefaults(typedAssign(() => ({ b: 1 }), { a: { b: 1, c: 2 } }), { d: {} })).toEqual({ a: { b: 1, c: 2 }, d: { b: 1 } });\n\n // Dot notation\n expect(applyDefaults({ a: { b: 1 } }, { \"a.c\": 2 })).toEqual({ a: { b: 1 }, \"a.c\": 2 });\n expect(applyDefaults({ a: { b: 1 } }, { \"a.c\": null })).toEqual({ a: { b: 1 }, \"a.c\": null });\n expect(applyDefaults({ a: { b: 1 } }, { a: { b: 2 }, \"a.b\": null })).toEqual({ a: { b: 2 }, \"a.b\": 1 });\n expect(applyDefaults({ a: { b: { c: 1 } } }, { a: { b: { c: 2 } }, \"a.b.c\": null })).toEqual({ a: { b: { c: 2 } }, \"a.b.c\": 1 });\n expect(applyDefaults({}, { a: { b: 2 }, \"a.b\": null })).toEqual({ a: { b: 2 }, \"a.b\": null });\n expect(applyDefaults({ a: { b: 1, c: 2 } }, { \"a.c\": null })).toEqual({ a: { b: 1, c: 2 }, \"a.c\": 2 });\n expect(applyDefaults({ a: { b: 1, c: () => {} } }, { \"a.c\": null })).toEqual({ a: { b: 1, c: {} }, \"a.c\": {} });\n expect(applyDefaults({ a: { b: 1, c: () => {} } }, { \"a.c.d\": null })).toEqual({ a: { b: 1, c: {} }, \"a.c.d\": null });\n expect(applyDefaults({ a: { b: 1 } }, { \"a.b\": null })).toEqual({ a: { b: 1 }, \"a.b\": 1 });\n expect(applyDefaults({ a: { b: { c: 1 } } }, { \"a.b\": null })).toEqual({ a: { b: { c: 1 } }, \"a.b\": { c: 1 } });\n expect(applyDefaults({ a: {} }, { \"a.b\": null })).toEqual({ a: {}, \"a.b\": null });\n expect(applyDefaults({ a: {} }, { \"a\": { b: 1 }, \"a.b\": null })).toEqual({ a: { b: 1 }, \"a.b\": null });\n expect(applyDefaults({ a: 1 }, { \"a.b\": null })).toEqual({ a: 1, \"a.b\": null });\n expect(applyDefaults({ a: 1 }, { \"a.b\": 2 })).toEqual({ a: 1, \"a.b\": 2 });\n expect(applyDefaults({ a: null }, { \"a.b\": 2 })).toEqual({ a: null, \"a.b\": 2 });\n expect(applyDefaults({ a: { b: { c: 1 } } }, { \"a.b\": { d: 2 } })).toEqual({ a: { b: { c: 1 } }, \"a.b\": { c: 1, d: 2 } });\n expect(applyDefaults({ a: { b: { c: 1 } } }, { \"a.b\": null })).toEqual({ a: { b: { c: 1 } }, \"a.b\": { c: 1 } });\n expect(applyDefaults({ a: { b: { c: { d: 1 } } } }, { \"a.b.c\": {} })).toEqual({ a: { b: { c: { d: 1 } } }, \"a.b.c\": { d: 1 } });\n expect(applyDefaults({ a: () => ({ c: 1 }) }, { \"a.b\": { d: 2 } })).toEqual({ a: {}, \"a.b\": { c: 1, d: 2 } });\n expect(applyDefaults({ a: () => () => ({ d: 1 }) }, { \"a.b\": null })).toEqual({ a: {}, \"a.b\": null });\n expect(applyDefaults({ a: () => () => ({ d: 1 }) }, { \"a.b.c\": {} })).toEqual({ a: {}, \"a.b.c\": { d: 1 } });\n expect(applyDefaults({ a: { b: () => ({ c: 1, d: 2 }) } }, { \"a.b.x-y.c\": 3 })).toEqual({ a: { b: {} }, \"a.b.x-y.c\": 3 });\n expect(applyDefaults({ a: () => ({ c: 1 }) }, { \"a.b.d\": 2 })).toEqual({ a: {}, \"a.b.d\": 2 });\n expect(applyDefaults({ a: () => ({ c: 1 }) }, { \"a.b.d\": 2, \"a.e.d\": 3 })).toEqual({ a: {}, \"a.b.d\": 2, \"a.e.d\": 3 });\n expect(applyDefaults({ a: () => ({ c: 1 }) }, { \"a.b.d\": 2, a: { b: { d: 3 } } })).toEqual({ a: { b: { c: 1, d: 3 } }, \"a.b.d\": 2 });\n expect(applyDefaults({ a: () => ({ c: 1 }) }, { \"a.b.d\": 2, a: { e: { d: 3 } } })).toEqual({ a: { e: { c: 1, d: 3 } }, \"a.b.d\": 2 });\n expect(applyDefaults({ a: () => ({ c: 1 }) }, { \"a.b\": { d: { e: 2 } }, \"a.b.d\": null })).toEqual({ a: {}, \"a.b\": { c: 1, d: { e: 2 } }, \"a.b.d\": null });\n});\n\nexport function applyProjectDefaults<T extends ProjectRenderedConfigBeforeDefaults>(config: T) {\n return applyDefaults(projectConfigDefaults, config);\n}\n\nexport function applyBranchDefaults<T extends BranchRenderedConfigBeforeDefaults>(config: T) {\n return applyDefaults(\n branchConfigDefaults,\n applyDefaults(\n projectConfigDefaults,\n config\n )\n );\n}\n\nexport function applyEnvironmentDefaults<T extends EnvironmentRenderedConfigBeforeDefaults>(config: T): ApplyDefaults<typeof environmentConfigDefaults, ApplyDefaults<typeof branchConfigDefaults, ApplyDefaults<typeof projectConfigDefaults, T>>> {\n return applyDefaults(\n environmentConfigDefaults,\n applyDefaults(\n branchConfigDefaults,\n applyDefaults(\n projectConfigDefaults,\n config\n ) as any\n ) as any\n ) as any;\n}\n\nexport function applyOrganizationDefaults(config: OrganizationRenderedConfigBeforeDefaults): ApplyDefaults<typeof organizationConfigDefaults, ApplyDefaults<typeof environmentConfigDefaults, ApplyDefaults<typeof branchConfigDefaults, ApplyDefaults<typeof projectConfigDefaults, OrganizationRenderedConfigBeforeDefaults>>>> {\n return applyDefaults(\n organizationConfigDefaults,\n applyDefaults(\n environmentConfigDefaults,\n applyDefaults(\n branchConfigDefaults,\n applyDefaults(\n projectConfigDefaults,\n config\n ) as any\n ) as any\n ) as any\n ) as any;\n}\n\n\nexport async function sanitizeProjectConfig<T extends ProjectRenderedConfigBeforeSanitization>(config: T) {\n assertNormalized(config);\n\n return {\n ...config,\n sourceOfTruth: {\n type: 'hosted',\n } as const,\n };\n}\n\nexport async function sanitizeBranchConfig<T extends BranchRenderedConfigBeforeSanitization>(config: T) {\n assertNormalized(config);\n const prepared = await sanitizeProjectConfig(config);\n return {\n ...prepared,\n };\n}\n\nexport async function sanitizeEnvironmentConfig<T extends EnvironmentRenderedConfigBeforeSanitization>(config: T) {\n assertNormalized(config);\n const prepared = await sanitizeBranchConfig(config);\n return {\n ...prepared,\n };\n}\n\nexport async function sanitizeOrganizationConfig(config: OrganizationRenderedConfigBeforeSanitization) {\n assertNormalized(config);\n const prepared = await sanitizeEnvironmentConfig(config);\n\n const themes: typeof prepared.emails.themes = prepared.emails.themes;\n const templates: typeof prepared.emails.templates = config.emails.server.isShared ? DEFAULT_EMAIL_TEMPLATES : prepared.emails.templates;\n\n const products = typedFromEntries(typedEntries(prepared.payments.products).map(([key, product]) => {\n const isAddOnTo = product.isAddOnTo === false ?\n false as const :\n typedFromEntries(Object.keys(product.isAddOnTo).map((key) => [key, true as const]));\n type PriceEntry = Partial<typeof product.prices[string]> & { serverOnly: boolean };\n // `serverOnly` is guaranteed to be a boolean by the applyDefaults step above.\n const prices: Record<string, PriceEntry> = typedFromEntries(typedEntries(product.prices).map(([key, value]) => {\n const data: PriceEntry = { ...value };\n return [key, data];\n }));\n return [key, {\n ...product,\n isAddOnTo,\n prices,\n }];\n }));\n\n const appSortIndices = new Map(Object.keys(ALL_APPS).map((appId, index) => [appId, index]));\n\n // Get all sign-up rules and sort by priority (descending), then by ID (alphabetically)\n // Note: We don't filter out disabled rules here because the dashboard needs to show them\n // The runtime evaluation in sign-up-rules.ts handles skipping disabled rules\n const sortedRuleEntries = typedEntries(prepared.auth.signUpRules)\n .sort((a, b) => {\n const priorityA = a[1].priority;\n const priorityB = b[1].priority;\n if (priorityA !== priorityB) return priorityB - priorityA;\n return stringCompare(a[0], b[0]);\n });\n\n return {\n ...prepared,\n auth: {\n ...prepared.auth,\n oauth: {\n ...prepared.auth.oauth,\n providers: typedFromEntries(typedEntries(prepared.auth.oauth.providers).filter(([key, value]) => value.type !== undefined)),\n },\n signUpRules: typedFromEntries(sortedRuleEntries),\n },\n emails: {\n ...prepared.emails,\n selectedThemeId: has(themes, prepared.emails.selectedThemeId) ? prepared.emails.selectedThemeId : DEFAULT_EMAIL_THEME_ID,\n themes,\n templates,\n },\n payments: {\n ...prepared.payments,\n products\n },\n apps: {\n installed: typedFromEntries(\n typedEntries(prepared.apps.installed)\n .sort(([a], [b]) => appSortIndices.get(a)! - appSortIndices.get(b)!)\n ),\n },\n };\n}\n\n/**\n * Does not require a base config, and hence solely relies on the override itself to validate the config. If it returns\n * no error, you know that the\n *\n * It's crucial that our DB never contains any configs that are not valid according to this function, as this would mean\n * that the config object does not satisfy the ValidatedToHaveNoConfigOverrideErrors type (which is used as an assumption\n * in a whole bunch of places in the code).\n */\nexport async function getConfigOverrideErrors<T extends yup.AnySchema>(schema: T, configOverride: unknown, options: { allowPropertiesThatCanNoLongerBeOverridden?: boolean } = {}): Promise<Result<null, string>> {\n // currently, we go over the schema and ensure that the general requirements for each property are satisfied\n // importantly, we cannot check any cross-property constraints, as those may change depending on the base config\n // also, since overrides can be empty, we cannot have any required properties (TODO: can we have required properties in nested objects? would that even make sense? think about it)\n if (typeof configOverride !== \"object\" || configOverride === null) {\n return Result.error(\"Config override must be a non-null object.\");\n }\n if (Object.getPrototypeOf(configOverride) !== Object.getPrototypeOf({})) {\n return Result.error(\"Config override must be plain old JavaScript object.\");\n }\n\n // Ensure that all keys with dots in them are at the top level of the object, not nested\n const ensureNoDotsInKeys = (obj: unknown): Result<never, string> | undefined => {\n if (typeof obj !== \"object\" || obj === null) {\n return;\n }\n for (const entry of Object.entries(obj)) {\n if (entry[0].includes(\".\")) {\n return Result.error(`Key ${entry[0]} contains a dot, which is not allowed in config override.`);\n }\n const result = ensureNoDotsInKeys(entry[1]);\n if (result) {\n return result;\n }\n }\n return;\n };\n for (const key of Object.keys(configOverride)) {\n const result = ensureNoDotsInKeys(configOverride[key as keyof typeof configOverride]);\n if (result) {\n return result;\n }\n }\n\n // Check config format\n const reason = getInvalidConfigReason(configOverride, { configName: 'override' });\n if (reason) return Result.error(\"Invalid config format: \" + reason);\n\n const getSubSchema = (schema: yup.AnySchema, key: string): yup.AnySchema | undefined => {\n const keyParts = key.split(\".\");\n if (!schema.hasNested(keyParts[0])) {\n return undefined;\n }\n const nestedSchema = schema.getNested(keyParts[0]);\n if (nestedSchema.meta()?.hexclaveConfigCanNoLongerBeOverridden && !options.allowPropertiesThatCanNoLongerBeOverridden) {\n return undefined;\n }\n if (keyParts.length === 1) {\n return nestedSchema;\n } else {\n return getSubSchema(nestedSchema, keyParts.slice(1).join(\".\"));\n }\n };\n\n const getRestrictedSchemaBase = (path: string, schema: yup.AnySchema): yup.AnySchema => {\n const schemaInfo = schema.meta()?.hexclaveSchemaInfo;\n switch (schemaInfo?.type) {\n case \"string\": {\n const stringSchema = schema as yup.StringSchema<any>;\n const description = stringSchema.describe();\n let res = yupString();\n if (description.tests.some(t => t.name === \"uuid\")) {\n res = res.uuid();\n }\n return res;\n }\n case \"number\": {\n return yupNumber();\n }\n case \"boolean\": {\n return yupBoolean();\n }\n case \"date\": {\n return yupDate();\n }\n case \"mixed\": {\n return yupMixed();\n }\n case \"array\": {\n throw new HexclaveAssertionError(`Arrays are not supported in config JSON files (besides tuples). Use a record instead.`, { schemaInfo, schema });\n\n // This is how the implementation would look like, but we don't support arrays in config JSON files (besides tuples)\n // const arraySchema = schema as yup.ArraySchema<any, any, any, any>;\n // const innerType = arraySchema.innerType;\n // return yupArray(innerType ? getRestrictedSchema(path + \".[]\", innerType as any) : undefined());\n }\n case \"tuple\": {\n return yupTuple(schemaInfo.items.map((s, index) => getRestrictedSchema(path + `[${index}]`, s)) as any);\n }\n case \"union\": {\n const schemas = schemaInfo.items;\n const nonObjectSchemas = [...schemas.entries()].filter(([index, s]) => s.meta()?.hexclaveSchemaInfo?.type !== \"object\");\n const objectSchemas = schemas.filter((s): s is yup.ObjectSchema<any> => s.meta()?.hexclaveSchemaInfo?.type === \"object\");\n\n // merge all object schemas into a single schema\n const allObjectSchemaKeys = [...new Set(objectSchemas.flatMap(s => Object.keys(s.fields)))];\n const mergedObjectSchema = yupObject(\n Object.fromEntries(\n allObjectSchemaKeys.map(key => [key, yupUnion(\n ...objectSchemas.flatMap((s, index) => s.hasNested(key) ? [s.getNested(key)] : [])\n )])\n )\n );\n\n return yupUnion(\n ...nonObjectSchemas.map(([index, s]) => getRestrictedSchema(path + `|variant-${index}|`, s)),\n ...objectSchemas.length > 0 ? [getRestrictedSchema(path + (nonObjectSchemas.length > 0 ? `|variant|` : \"\"), mergedObjectSchema)] : [],\n );\n }\n case \"record\": {\n return yupRecord(getRestrictedSchema(path + \".key\", schemaInfo.keySchema) as any, getRestrictedSchema(path + \".value\", schemaInfo.valueSchema));\n }\n case \"object\": {\n const objectSchema = schema as yup.ObjectSchema<any>;\n return yupObject(\n Object.fromEntries(\n Object.entries(objectSchema.fields)\n .map(([key, value]) => [key, getRestrictedSchema(path + \".\" + key, value as any)])\n )\n );\n }\n case \"never\": {\n return yupNever();\n }\n default: {\n throw new HexclaveAssertionError(`Unknown schema info at path ${path}: ${JSON.stringify(schemaInfo)}`, { schemaInfo, schema });\n }\n }\n };\n const getRestrictedSchema = (path: string, schema: yup.AnySchema): yup.AnySchema => {\n let restricted = getRestrictedSchemaBase(path, schema);\n restricted = restricted.nullable();\n const description = schema.describe();\n if (description.oneOf.length > 0) {\n restricted = restricted.oneOf(description.oneOf);\n }\n if (description.notOneOf.length > 0) {\n restricted = restricted.notOneOf(description.notOneOf);\n }\n return restricted;\n };\n\n for (const [key, value] of Object.entries(configOverride)) {\n if (value === undefined) continue;\n if (/^payments\\.products\\.[^.]+\\.prices$/.test(key) && value === \"include-by-default\") {\n return Result.error(`${key} must not be one of the following values: include-by-default`);\n }\n const subSchema = getSubSchema(schema, key);\n if (!subSchema) {\n // find smallest key prefix that is invalid\n const keySplit = key.split(\".\");\n for (let i = 0; i < keySplit.length; i++) {\n const prefix = keySplit.slice(0, i + 1).join(\".\");\n const subSchema = getSubSchema(schema, prefix);\n if (!subSchema) {\n return Result.error(`The key ${JSON.stringify(key)} is not valid (nested object not found in schema: ${JSON.stringify(prefix)}).`);\n }\n }\n throw new HexclaveAssertionError(\"Something weird happened? Sub-schema for key is invalid but no prefix is invalid??\", { key, subSchema });\n }\n let restrictedSchema = getRestrictedSchema(key, subSchema);\n try {\n await restrictedSchema.validate(value, {\n strict: true,\n ...{\n // Although `path` is not part of the yup types, it is actually recognized and does the correct thing\n path: key\n },\n context: {\n noUnknownPathPrefixes: [''],\n },\n });\n } catch (error) {\n if (error instanceof yup.ValidationError) {\n return Result.error(error.message);\n }\n throw error;\n }\n }\n return Result.ok(null);\n}\nexport async function assertNoConfigOverrideErrors<T extends yup.AnySchema>(schema: T, config: unknown, options: { allowPropertiesThatCanNoLongerBeOverridden?: boolean, extraInfo?: any } = {}): Promise<void> {\n const res = await getConfigOverrideErrors(schema, config, options);\n if (res.status === \"error\") throw new HexclaveAssertionError(`Config override is invalid — at a place where it should have already been validated! ${res.error}`, { options, config });\n}\ntype _ValidatedToHaveNoConfigOverrideErrorsImpl<T> =\n IsUnion<T & object> extends true ? _ValidatedToHaveNoConfigOverrideErrorsImpl<CollapseObjectUnion<T & object> | Exclude<T, object>>\n : T extends object ? (T extends any[] ? T : { [K in keyof T]+?: _ValidatedToHaveNoConfigOverrideErrorsImpl<T[K]> })\n : T;\nexport type ValidatedToHaveNoConfigOverrideErrors<T extends yup.AnySchema> = _ValidatedToHaveNoConfigOverrideErrorsImpl<yup.InferType<T>>;\ntypeAssertIs<_ValidatedToHaveNoConfigOverrideErrorsImpl<{ a: string } | { b: number } | boolean>, { a?: string, b?: number } | boolean>()();\ntypeAssertExtends<_ValidatedToHaveNoConfigOverrideErrorsImpl<\"abc\" | 123 | null>, \"abc\" | 123 | null>()();\ntypeAssertExtends<_ValidatedToHaveNoConfigOverrideErrorsImpl<{ a: { b: { c: string } | { d: number } } }>, { a?: { b?: { c?: string, d?: number } } }>()();\n\n/**\n * Checks whether there are any warnings in the incomplete config. A warning doesn't stop the config from being valid,\n * but may require action regardless.\n *\n * The DB can contain configs that are not valid according to this function, as long as they are valid according to\n * the getConfigOverrideErrors function. (This is necessary, because a changing base config may make an override invalid\n * that was previously valid.)\n */\nexport async function getIncompleteConfigWarnings<T extends yup.AnySchema>(schema: T, incompleteConfig: Config): Promise<Result<null, string>> {\n // every rendered config should also be a config override without errors (regardless of whether it has warnings or not)\n const overrideErrors = await getConfigOverrideErrors(schema, incompleteConfig, { allowPropertiesThatCanNoLongerBeOverridden: true });\n if (overrideErrors.status === \"error\") {\n return overrideErrors;\n }\n\n // Check for dot-notation keys that would be silently dropped during rendering.\n // We simulate the rendering pipeline: apply all defaults, then normalize with\n // onDotIntoNonObject: \"ignore\" (same as the actual renderer). Any key that gets\n // dropped during normalization (because a parent doesn't exist or isn't an object)\n // means it dots into nothing — the user's change would be silently lost.\n const withDefaults = applyDefaults(\n organizationConfigDefaults,\n applyDefaults(projectConfigDefaults, incompleteConfig),\n );\n const droppedKeys: string[] = [];\n const normalizedWithDefaults = normalize(withDefaults as Config, { onDotIntoNonObject: \"ignore\", droppedKeys });\n\n // Only report keys that were in the original incomplete config, not anything from defaults\n const incompleteConfigDotKeys = new Set(\n Object.keys(incompleteConfig).filter(k => k.includes('.') && incompleteConfig[k] !== undefined)\n );\n const relevantDroppedKeys = droppedKeys.filter(k => incompleteConfigDotKeys.has(k));\n\n if (relevantDroppedKeys.length > 0) {\n const messages = relevantDroppedKeys.map(key => {\n const segments = key.split('.');\n\n // Walk the normalized config to find the deepest existing parent\n let current: unknown = normalizedWithDefaults;\n let lastExistingIdx = -1;\n for (let i = 0; i < segments.length - 1; i++) {\n if (current != null && typeof current === 'object' && !Array.isArray(current) && segments[i] in (current as Record<string, unknown>)) {\n current = (current as Record<string, unknown>)[segments[i]];\n lastExistingIdx = i;\n } else {\n break;\n }\n }\n\n // The non-existent parent is one level deeper than the last existing segment\n const nonExistentParent = segments.slice(0, lastExistingIdx + 2).join('.');\n\n // Build a suggested nested object notation starting from the non-existent parent\n const remainingSegments = segments.slice(lastExistingIdx + 2);\n let suggestion = '...';\n for (let i = remainingSegments.length - 1; i >= 0; i--) {\n suggestion = `{ ${JSON.stringify(remainingSegments[i])}: ${suggestion} }`;\n }\n suggestion = `{ ${JSON.stringify(nonExistentParent)}: ${suggestion} }`;\n\n return `Dot-notation key ${JSON.stringify(key)} will be silently ignored because it references non-existent parent ${JSON.stringify(nonExistentParent)}. Instead of dot notation, use nested object notation like this: ${suggestion}`;\n });\n\n return Result.error(messages.join('\\n'));\n }\n\n let normalized: Config;\n try {\n normalized = normalize(incompleteConfig, { onDotIntoNull: \"empty-object\" });\n } catch (error) {\n if (error instanceof NormalizationError) {\n return Result.error(`Config is not normalizable. ` + error.message);\n }\n throw error;\n }\n\n // test the schema against the normalized config\n try {\n await schema.validate(normalized, {\n strict: true,\n context: {\n noUnknownPathPrefixes: [''],\n },\n });\n return Result.ok(null);\n } catch (error) {\n if (error instanceof yup.ValidationError) {\n return Result.error(error.message);\n }\n throw error;\n }\n}\nexport type ValidatedToHaveNoIncompleteConfigWarnings<T extends yup.AnySchema> = yup.InferType<T>;\n\n\n// Normalized overrides\n// ex.: { a?: { b?: number, c?: string }, d?: number }\nexport type ProjectConfigNormalizedOverride = Expand<ValidatedToHaveNoConfigOverrideErrors<typeof projectConfigSchema>>;\nexport type BranchConfigNormalizedOverride = Expand<ValidatedToHaveNoConfigOverrideErrors<typeof branchConfigSchema>>;\nexport type EnvironmentConfigNormalizedOverride = Expand<ValidatedToHaveNoConfigOverrideErrors<typeof environmentConfigSchema>>;\nexport type OrganizationConfigNormalizedOverride = Expand<ValidatedToHaveNoConfigOverrideErrors<typeof organizationConfigSchema>>;\n\n\n// Overrides\n// ex.: { a?: null | { b?: null | number, c: string }, d?: null | number, \"a.b\"?: number, \"a.c\"?: string }\nexport type ProjectConfigOverride = NormalizesTo<ProjectConfigNormalizedOverride>;\nexport type BranchConfigOverride = NormalizesTo<BranchConfigNormalizedOverride>;\nexport type EnvironmentConfigOverride = NormalizesTo<EnvironmentConfigNormalizedOverride>;\nexport type OrganizationConfigOverride = NormalizesTo<OrganizationConfigNormalizedOverride>;\n\n// Override overrides (used to update the overrides)\n// ex.: { a?: null | { b?: null | number, c?: string }, d?: null | number, \"a.b\"?: number, \"a.c\"?: string }\nexport type ProjectConfigOverrideOverride = ProjectConfigOverride;\nexport type BranchConfigOverrideOverride = BranchConfigOverride;\nexport type EnvironmentConfigOverrideOverride = EnvironmentConfigOverride;\nexport type OrganizationConfigOverrideOverride = OrganizationConfigOverride;\n\n// Incomplete configs\n// note that we infer these types from the override types, not from the schema types directly, as there is no guarantee\n// that all configs in the DB satisfy the schema (the only guarantee we make is that this once *used* to be true)\nexport type ProjectIncompleteConfig = Expand<ProjectConfigNormalizedOverride>;\nexport type BranchIncompleteConfig = Expand<ProjectIncompleteConfig & BranchConfigNormalizedOverride>;\nexport type EnvironmentIncompleteConfig = Expand<BranchIncompleteConfig & EnvironmentConfigNormalizedOverride>;\nexport type OrganizationIncompleteConfig = Expand<EnvironmentIncompleteConfig & OrganizationConfigNormalizedOverride>;\n\n\n// Rendered configs before defaults, normalization, and sanitization\ntype ProjectRenderedConfigBeforeDefaults = Omit<ProjectIncompleteConfig,\n | keyof BranchConfigNormalizedOverride\n | keyof EnvironmentConfigNormalizedOverride\n | keyof OrganizationConfigNormalizedOverride\n>;\ntype BranchRenderedConfigBeforeDefaults = Omit<BranchIncompleteConfig,\n | keyof EnvironmentConfigNormalizedOverride\n | keyof OrganizationConfigNormalizedOverride\n>;\ntype EnvironmentRenderedConfigBeforeDefaults = Omit<EnvironmentIncompleteConfig,\n | keyof OrganizationConfigNormalizedOverride\n>;\ntype OrganizationRenderedConfigBeforeDefaults = OrganizationIncompleteConfig;\n\n\n// Rendered configs before sanitization\ntype ProjectRenderedConfigBeforeSanitization = Expand<Awaited<ReturnType<typeof applyProjectDefaults<ProjectRenderedConfigBeforeDefaults>>>>;\ntype BranchRenderedConfigBeforeSanitization = Expand<Awaited<ReturnType<typeof applyBranchDefaults<BranchRenderedConfigBeforeDefaults>>>>;\ntype EnvironmentRenderedConfigBeforeSanitization = Expand<Awaited<ReturnType<typeof applyEnvironmentDefaults<EnvironmentRenderedConfigBeforeDefaults>>>>;\ntype OrganizationRenderedConfigBeforeSanitization = Expand<Awaited<ReturnType<typeof applyOrganizationDefaults>>>;\n\n// Rendered configs after defaults, normalization, and sanitization\nexport type ProjectRenderedConfig = Expand<Awaited<ReturnType<typeof sanitizeProjectConfig<ProjectRenderedConfigBeforeSanitization>>>>;\nexport type BranchRenderedConfig = Expand<Awaited<ReturnType<typeof sanitizeBranchConfig<BranchRenderedConfigBeforeSanitization>>>>;\nexport type EnvironmentRenderedConfig = Expand<Awaited<ReturnType<typeof sanitizeEnvironmentConfig<EnvironmentRenderedConfigBeforeSanitization>>>>;\nexport type OrganizationRenderedConfig = Expand<Awaited<ReturnType<typeof sanitizeOrganizationConfig>>>;\n\n// Complete config\nexport type CompleteConfig = OrganizationRenderedConfig;\n\n// Type assertions (just to make sure the types are correct)\nconst __assertEmptyObjectIsValidProjectOverride: ProjectConfigOverride = {};\nconst __assertEmptyObjectIsValidBranchOverride: BranchConfigOverride = {};\nconst __assertEmptyObjectIsValidEnvironmentOverride: EnvironmentConfigOverride = {};\nconst __assertEmptyObjectIsValidOrganizationOverride: OrganizationConfigOverride = {};\ntypeAssertExtends<ProjectRenderedConfig, { \"sourceOfTruth\": any }>()();\ntypeAssertExtends<BranchRenderedConfig, { \"sourceOfTruth\": any }>()();\ntypeAssertExtends<EnvironmentRenderedConfig, { \"sourceOfTruth\": any }>()();\ntypeAssertExtends<OrganizationRenderedConfig, { \"sourceOfTruth\": any }>()();\ntypeAssert<BranchRenderedConfig extends { \"domains\": any } ? false : true>()();\ntypeAssert<EnvironmentRenderedConfig extends { \"domains\": any } ? false : true>()();\ntypeAssertExtends<OrganizationRenderedConfig, { \"domains\": any }>()();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema.js","names":["stringSchema","objectSchema","yup"],"sources":["../../../src/config/schema.ts"],"sourcesContent":["// TODO: rename this file to spaghetti.ts because that's the kind of code here\n\n// IMPORTANT\n// WHENEVER YOU MAKE BACKWARDS-INCOMPATIBLE CHANGES TO THE CONFIG SCHEMA, YOU MUST UPDATE THE MIGRATION FUNCTIONS BELOW.\n// OTHERWISE THINGS WILL GO BOOM!!\n\nimport * as yup from \"yup\";\nimport { ALL_APPS } from \"../apps/apps-config\";\nimport { DEFAULT_EMAIL_TEMPLATES, DEFAULT_EMAIL_THEMES, DEFAULT_EMAIL_THEME_ID } from \"../helpers/emails\";\nimport * as schemaFields from \"../schema-fields\";\nimport { productSchema, userSpecifiedIdSchema, yupBoolean, yupDate, yupMixed, yupNever, yupNumber, yupObject, yupRecord, yupString, yupTuple, yupUnion } from \"../schema-fields\";\nimport { SUPPORTED_CURRENCIES } from \"../utils/currency-constants\";\nimport { HexclaveAssertionError } from \"../utils/errors\";\nimport { allProviders, allProviderTypes } from \"../utils/oauth\";\nimport { DeepFilterUndefined, DeepMerge, DeepRequiredOrUndefined, filterUndefined, get, getOrUndefined, has, isObjectLike, mapValues, set, typedAssign, typedEntries, typedFromEntries } from \"../utils/objects\";\nimport { Result } from \"../utils/results\";\nimport { stringCompare } from \"../utils/strings\";\nimport { CollapseObjectUnion, Expand, IntersectAll, IsUnion, typeAssert, typeAssertExtends, typeAssertIs } from \"../utils/types\";\nimport { Config, NormalizationError, NormalizesTo, assertNormalized, getInvalidConfigReason, normalize } from \"./format\";\nimport { migrateCatalogsToProductLines } from \"./migrate-catalogs-to-product-lines\";\n\nexport const configLevels = ['project', 'branch', 'environment', 'organization'] as const;\nexport type ConfigLevel = typeof configLevels[number];\nconst permissionRegex = /^\\$?[a-z0-9_:]+$/;\nconst customPermissionRegex = /^[a-z0-9_:]+$/;\nconst providerIdRegex = /^[a-z0-9_-]+$/;\n\ndeclare module \"yup\" {\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n export interface CustomSchemaMetadata {\n hexclaveConfigCanNoLongerBeOverridden?: true,\n }\n}\n\nfunction canNoLongerBeOverridden<T extends yup.AnyObjectSchema, K extends string[]>(schema: T, keys: K): yup.Schema<Omit<yup.InferType<T>, K[number]>, T['__context'], Omit<T['__default'], K[number]>, T['__flags']> {\n const notOmitted = schema.concat(yupObject(\n Object.fromEntries(keys.map(key => [key, schema.getNested(key).meta({ hexclaveConfigCanNoLongerBeOverridden: true })]))\n ));\n return notOmitted as any;\n}\n\n/**\n * All fields that can be overridden at this level.\n */\nexport const projectConfigSchema = yupObject({\n sourceOfTruth: yupUnion(\n yupObject({\n type: yupString().oneOf(['hosted']).defined(),\n }),\n ),\n project: yupObject({\n requirePublishableClientKey: yupBoolean(),\n }),\n});\n\n// --- NEW RBAC Schema ---\nconst branchRbacDefaultPermissions = yupRecord(\n yupString().matches(permissionRegex),\n yupBoolean().isTrue().optional(),\n);\n\nconst branchRbacSchema = yupObject({\n permissions: yupRecord(\n yupString().matches(customPermissionRegex),\n yupObject({\n description: yupString().optional(),\n scope: yupString().oneOf(['team', 'project']).optional(),\n containedPermissionIds: yupRecord(\n yupString().matches(permissionRegex),\n yupBoolean().isTrue().optional()\n ).optional(),\n }).optional(),\n ),\n defaultPermissions: yupObject({\n teamCreator: branchRbacDefaultPermissions,\n teamMember: branchRbacDefaultPermissions,\n signUp: branchRbacDefaultPermissions,\n }),\n});\n// --- END NEW RBAC Schema ---\n\n// --- NEW API Keys Schema ---\nconst branchApiKeysSchema = yupObject({\n enabled: yupObject({\n team: yupBoolean(),\n user: yupBoolean(),\n }),\n});\n// --- END NEW API Keys Schema ---\n\n// --- NEW Apps Schema ---\nconst appIds = Object.keys(ALL_APPS) as (keyof typeof ALL_APPS)[];\nconst branchAppsSchema = yupObject({\n installed: yupRecord(\n yupString().oneOf(appIds),\n yupObject({\n enabled: yupBoolean(),\n }),\n ),\n});\n// --- END NEW Apps Schema ---\n\n\nconst branchAuthSchema = yupObject({\n allowSignUp: yupBoolean(),\n password: yupObject({\n allowSignIn: yupBoolean(),\n }),\n otp: yupObject({\n allowSignIn: yupBoolean(),\n }),\n passkey: yupObject({\n allowSignIn: yupBoolean(),\n }),\n oauth: yupObject({\n accountMergeStrategy: yupString().oneOf(['link_method', 'raise_error', 'allow_duplicates']).optional(),\n providers: yupRecord(\n yupString().matches(permissionRegex),\n yupObject({\n type: yupString().oneOf(allProviderTypes).optional(),\n allowSignIn: yupBoolean(),\n allowConnectedAccounts: yupBoolean(),\n }),\n ),\n }),\n signUpRules: yupRecord(\n userSpecifiedIdSchema(\"signUpRuleId\"),\n yupObject({\n enabled: yupBoolean(),\n displayName: yupString(),\n // Priority for rule ordering (higher number = higher priority, evaluated first)\n // Rules with same priority are sorted alphabetically by ID\n priority: yupNumber().integer().min(0),\n // CEL expression string - evaluated against signup context\n // Example: 'email.endsWith(\"@gmail.com\") && authMethod == \"password\"'\n condition: yupString(),\n action: yupObject({\n type: yupString().oneOf(['allow', 'reject', 'restrict', 'log']).defined(),\n message: yupString().optional(), // for reject action custom message (internal use, not shown to user)\n }),\n }),\n ),\n signUpRulesDefaultAction: yupString().oneOf(['allow', 'reject']),\n});\n\nexport const branchPaymentsSchema = yupObject({\n blockNewPurchases: yupBoolean(),\n autoPay: yupObject({\n interval: schemaFields.dayIntervalSchema,\n }).optional(),\n productLines: yupRecord(\n userSpecifiedIdSchema(\"productLineId\"),\n yupObject({\n displayName: yupString().optional(),\n customerType: schemaFields.customerTypeSchema,\n }),\n ).meta({ openapiField: { description: 'The product lines that products can be in. All products in a product line (besides add-ons) are mutually exclusive.', exampleValue: { \"product-line-id\": { displayName: \"My Product Line\", customerType: \"user\" } } } }),\n products: yupRecord(\n userSpecifiedIdSchema(\"productId\"),\n productSchema,\n ),\n items: yupRecord(\n userSpecifiedIdSchema(\"itemId\"),\n yupObject({\n displayName: yupString().optional(),\n customerType: schemaFields.customerTypeSchema,\n }),\n ),\n}).optional().test(\n 'product-customer-type-matches-product-line',\n 'Product customer type must match its product line customer type',\n function(this: yup.TestContext<yup.AnyObject>, value) {\n if (!value) return true;\n const products = value.products;\n if (!isObjectLike(products)) return true;\n\n const productLines = value.productLines;\n for (const [productId, product] of Object.entries(products)) {\n if (!isObjectLike(product)) continue;\n const productLineId = product.productLineId;\n if (typeof productLineId !== \"string\" || productLineId.length === 0) continue;\n const productLine = isObjectLike(productLines) ? getOrUndefined(productLines, productLineId) : undefined;\n if (productLine === undefined) {\n return this.createError({\n message: `Product \"${productId}\" specifies product line ID \"${productLineId}\", but that product line does not exist`,\n path: `${this.path}.products.${productId}.productLineId`,\n });\n }\n if (!isObjectLike(productLine)) continue;\n if (product.customerType !== productLine.customerType) {\n return this.createError({\n message: `Product \"${productId}\" has customer type \"${product.customerType}\" but its product line \"${productLineId}\" has customer type \"${productLine.customerType}\"`,\n path: `${this.path}.products.${productId}.customerType`,\n });\n }\n }\n return true;\n }\n);\nimport.meta.vitest?.test(\"branchPaymentsSchema accepts partial payments config without products\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n blockNewPurchases: true,\n }, { abortEarly: false })).resolves.toMatchObject({\n blockNewPurchases: true,\n });\n});\n\nimport.meta.vitest?.test(\"branchPaymentsSchema accepts product lines without products\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n productLines: {\n pro: {\n displayName: \"Pro\",\n customerType: \"user\",\n },\n },\n }, { abortEarly: false })).resolves.toMatchObject({\n productLines: {\n pro: {\n displayName: \"Pro\",\n customerType: \"user\",\n },\n },\n });\n});\n\nimport.meta.vitest?.test(\"branchPaymentsSchema rejects a product that references a missing product line\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n products: {\n pro: {\n customerType: \"user\",\n productLineId: \"missing-line\",\n prices: {},\n },\n },\n }, { abortEarly: false })).rejects.toThrowErrorMatchingInlineSnapshot(`[ValidationError: Product \"pro\" specifies product line ID \"missing-line\", but that product line does not exist]`);\n});\n\nimport.meta.vitest?.test(\"branchPaymentsSchema rejects null product entries without throwing a raw TypeError\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n products: {\n pro: null,\n },\n }, { abortEarly: false })).rejects.toThrowErrorMatchingInlineSnapshot(`[ValidationError: products cannot be null]`);\n});\n\nimport.meta.vitest?.test(\"branchPaymentsSchema rejects null product line entries without throwing a raw TypeError\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n productLines: {\n teamLine: null,\n },\n products: {\n pro: {\n customerType: \"user\",\n productLineId: \"teamLine\",\n prices: {},\n },\n },\n }, { abortEarly: false })).rejects.toThrowErrorMatchingInlineSnapshot(`[ValidationError: productLines cannot be null]`);\n});\n\nimport.meta.vitest?.test(\"branchPaymentsSchema rejects a product whose customer type differs from its product line\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n productLines: {\n teamLine: {\n customerType: \"team\",\n },\n },\n products: {\n pro: {\n customerType: \"user\",\n productLineId: \"teamLine\",\n prices: {},\n },\n },\n }, { abortEarly: false })).rejects.toThrowErrorMatchingInlineSnapshot(`[ValidationError: Product \"pro\" has customer type \"user\" but its product line \"teamLine\" has customer type \"team\"]`);\n});\n\nimport.meta.vitest?.test(\"branchPaymentsSchema lets productLineId schema reject empty IDs\", async ({ expect }) => {\n await expect(branchPaymentsSchema.validate({\n products: {\n pro: {\n customerType: \"user\",\n productLineId: \"\",\n prices: {},\n },\n },\n }, { abortEarly: false })).rejects.toThrowErrorMatchingInlineSnapshot(`[ValidationError: productLineId must contain only letters, numbers, underscores, and hyphens, and not start with a hyphen]`);\n});\n\nconst branchDomain = yupObject({});\n\nconst branchOnboardingSchema = yupObject({\n requireEmailVerification: yupBoolean(),\n});\n\n// --- Deployments Schema ---\n// Service DEFINITIONS (type, framework, build config, env vars) live in the\n// branch config so they follow the project's config source: pushable from\n// hexclave.config.ts / GitHub, or editable in the dashboard when the config is\n// unlinked. Operational state (Vercel project id, deployment runs, custom\n// domains and their verification) lives in the backend database instead, keyed\n// by the service id.\nexport const DEPLOYMENT_ENV_VAR_KEY_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;\nexport const DEPLOYMENT_SECRET_KEY_REGEX = /^[a-zA-Z0-9_-]+$/;\n// A connection value is `<serviceId>.<outputKey>` — a typed pointer to another\n// service's output (e.g. \"hexclave.projectId\") that the backend resolves at\n// deploy time. This is deliberately its own env var TYPE rather than a\n// `{serviceId.outputKey}` interpolation syntax inside plain values: with\n// interpolation, a literal value that happens to contain `{...}` would be\n// misinterpreted as a reference, so plain values must stay entirely literal.\nexport const DEPLOYMENT_CONNECTION_VALUE_REGEX = /^[a-zA-Z0-9_-]+\\.[A-Za-z0-9_]+$/;\n\n// One env var, discriminated by `type`:\n// - absent (plain): a literal `value`, committed to the config.\n// - \"secret\": only the secret's name (`key`) is in the config; its value must\n// be supplied at deploy time via `hexclave deploy --secret <key>=<value>`\n// and is never persisted by Hexclave.\n// - \"connection\": `value` names another service's output (see the regex\n// comment above); resolved server-side at deploy time.\n// Exported so the backend's deployments API routes validate request bodies\n// with the exact same rules as pushed configs.\nexport const deploymentEnvVarSchema = yupObject({\n type: yupString().oneOf([\"secret\", \"connection\"]).optional(),\n value: yupString().when(\"type\", ([type], schema) => {\n switch (type) {\n case \"secret\": {\n return schema.oneOf([undefined], 'deployment env vars with type \"secret\" must not have a value — the value is supplied at deploy time via `hexclave deploy --secret <key>=<value>`');\n }\n case \"connection\": {\n return schema.defined().matches(DEPLOYMENT_CONNECTION_VALUE_REGEX, 'deployment env vars with type \"connection\" must reference a service output like \"hexclave.projectId\"');\n }\n default: {\n return schema.defined();\n }\n }\n }),\n key: yupString().when(\"type\", ([type], schema) => type === \"secret\"\n ? schema.defined().matches(DEPLOYMENT_SECRET_KEY_REGEX, \"deployment secret keys must contain only letters, numbers, underscores, and hyphens\")\n : schema.oneOf([undefined], 'deployment env vars may only have a key when their type is \"secret\"')),\n});\n\nconst branchDeploymentsSchema = yupObject({\n services: yupRecord(\n // \"hexclave\" is the managed backend's slot on the deployments board; a\n // config entry must never shadow it, so it's rejected at the schema level\n // (not just in the dashboard-create route — pushed configs go through\n // validation too).\n userSpecifiedIdSchema(\"serviceId\").notOneOf([\"hexclave\"], 'The service id \"hexclave\" is reserved for the managed Hexclave service'),\n yupObject({\n // Which platform runs the service. Only Vercel-backed services exist\n // today, but the field is required so configs stay unambiguous once more\n // types are added (every write path must state what it's creating).\n type: yupString().oneOf([\"vercel\"]).defined(),\n framework: yupString().optional(),\n installCommand: yupString().optional(),\n buildCommand: yupString().optional(),\n outputDirectory: yupString().optional(),\n rootDirectory: yupString().optional(),\n env: yupRecord(\n yupString().matches(DEPLOYMENT_ENV_VAR_KEY_REGEX, \"deployment env var keys must start with a letter or underscore and contain only letters, digits, and underscores\"),\n deploymentEnvVarSchema,\n ),\n }),\n ),\n});\n\nimport.meta.vitest?.test(\"branchDeploymentsSchema accepts all three env var types\", async ({ expect }) => {\n await expect(branchDeploymentsSchema.validate({\n services: {\n web: {\n type: \"vercel\",\n rootDirectory: \"./\",\n framework: \"nextjs\",\n env: {\n MY_ENV_VAR: { value: \"true\" },\n DATABASE_CONNECTION_STRING: { type: \"secret\", key: \"db_connection\" },\n NEXT_PUBLIC_HEXCLAVE_PROJECT_ID: { type: \"connection\", value: \"hexclave.projectId\" },\n },\n },\n },\n }, { abortEarly: false })).resolves.toBeDefined();\n});\n\nimport.meta.vitest?.test(\"branchDeploymentsSchema rejects services without a type\", async ({ expect }) => {\n await expect(branchDeploymentsSchema.validate({\n services: {\n web: { framework: \"nextjs\" },\n },\n }, { abortEarly: false })).rejects.toThrow(/type/);\n});\n\nimport.meta.vitest?.test(\"branchDeploymentsSchema rejects invalid env var shapes\", async ({ expect }) => {\n // A secret with an inline value would defeat the whole point of secrets.\n await expect(branchDeploymentsSchema.validate({\n services: { web: { type: \"vercel\", env: { A: { type: \"secret\", key: \"a\", value: \"leaked\" } } } },\n }, { abortEarly: false })).rejects.toThrow(/must not have a value/);\n // A secret without a key can never be filled at deploy time.\n await expect(branchDeploymentsSchema.validate({\n services: { web: { type: \"vercel\", env: { A: { type: \"secret\" } } } },\n }, { abortEarly: false })).rejects.toThrow(/key/);\n // Plain values may not carry a secret key.\n await expect(branchDeploymentsSchema.validate({\n services: { web: { type: \"vercel\", env: { A: { value: \"x\", key: \"a\" } } } },\n }, { abortEarly: false })).rejects.toThrow(/only have a key/);\n // Connections must point at `<serviceId>.<outputKey>` — braces in particular\n // are the OLD interpolation syntax and must not validate.\n await expect(branchDeploymentsSchema.validate({\n services: { web: { type: \"vercel\", env: { A: { type: \"connection\", value: \"{hexclave.projectId}\" } } } },\n }, { abortEarly: false })).rejects.toThrow(/service output/);\n // Env var keys must be valid POSIX-ish env var names.\n await expect(branchDeploymentsSchema.validate({\n services: { web: { type: \"vercel\", env: { \"1BAD\": { value: \"x\" } } } },\n }, { abortEarly: false })).rejects.toThrow(/env var keys/);\n});\n// --- END Deployments Schema ---\n\n\nexport const branchConfigSchema = canNoLongerBeOverridden(projectConfigSchema, [\n \"sourceOfTruth\",\n \"project\",\n]).concat(yupObject({\n rbac: branchRbacSchema,\n\n teams: yupObject({\n createPersonalTeamOnSignUp: yupBoolean(),\n allowClientTeamCreation: yupBoolean(),\n }),\n\n users: yupObject({\n allowClientUserDeletion: yupBoolean(),\n }),\n\n onboarding: branchOnboardingSchema,\n\n apiKeys: branchApiKeysSchema,\n\n apps: branchAppsSchema,\n\n domains: branchDomain,\n\n auth: branchAuthSchema,\n\n emails: yupObject({\n selectedThemeId: schemaFields.emailThemeSchema,\n themes: schemaFields.emailThemeListSchema,\n templates: schemaFields.emailTemplateListSchema,\n }),\n\n payments: branchPaymentsSchema,\n\n \"deployments-alpha\": branchDeploymentsSchema,\n\n dataVault: yupObject({\n stores: yupRecord(\n userSpecifiedIdSchema(\"storeId\"),\n yupObject({\n displayName: yupString(),\n }),\n ),\n }),\n}));\n\n\n// --- Analytics Schema (environment config only - not pushable) ---\nconst environmentAnalyticsSchema = yupObject({\n queryFolders: yupRecord(\n userSpecifiedIdSchema(\"folderId\"),\n yupObject({\n displayName: yupString(),\n sortOrder: yupNumber().optional(),\n queries: yupRecord(\n userSpecifiedIdSchema(\"queryId\"),\n yupObject({\n displayName: yupString(),\n sqlQuery: yupString(), // SQL query string (not English language)\n description: yupString().optional(),\n }),\n ),\n }),\n ),\n});\n// --- END Analytics Schema ---\n\nexport const environmentConfigSchema = branchConfigSchema.concat(yupObject({\n auth: branchConfigSchema.getNested(\"auth\").concat(yupObject({\n oauth: branchConfigSchema.getNested(\"auth\").getNested(\"oauth\").concat(yupObject({\n providers: yupRecord(\n yupString().matches(providerIdRegex),\n yupObject({\n type: yupString().oneOf(allProviderTypes).optional(),\n isShared: yupBoolean(),\n clientId: schemaFields.oauthClientIdSchema.optional(),\n clientSecret: schemaFields.oauthClientSecretSchema.optional(),\n customCallbackUrl: schemaFields.oauthCustomCallbackUrlSchema.optional().when('isShared', {\n is: true,\n then: (schema) => schema.oneOf([undefined], 'customCallbackUrl cannot be set for shared OAuth providers'),\n otherwise: (schema) => schema,\n }),\n facebookConfigId: schemaFields.oauthFacebookConfigIdSchema.optional(),\n microsoftTenantId: schemaFields.oauthMicrosoftTenantIdSchema.optional(),\n appleBundles: yupRecord(\n userSpecifiedIdSchema(\"appleBundleId\"),\n yupObject({\n bundleId: schemaFields.oauthAppleBundleIdSchema,\n }),\n ).optional(),\n // Custom OIDC provider fields (only used when type is \"custom_oidc\")\n issuerUrl: schemaFields.oauthIssuerUrlSchema.optional(),\n scope: schemaFields.oauthScopeSchema.optional(),\n displayName: yupString().optional(),\n allowSignIn: yupBoolean().optional(),\n allowConnectedAccounts: yupBoolean().optional(),\n }),\n ),\n })),\n })),\n\n emails: branchConfigSchema.getNested(\"emails\").concat(yupObject({\n server: yupObject({\n isShared: yupBoolean(),\n provider: yupString().oneOf(['resend', 'smtp', 'managed']).optional(),\n host: schemaFields.emailHostSchema.optional().nonEmpty(),\n port: schemaFields.emailPortSchema.optional(),\n username: schemaFields.emailUsernameSchema.optional().nonEmpty(),\n password: schemaFields.emailPasswordSchema.optional().nonEmpty().when(['provider', 'isShared'], {\n is: (provider: string | undefined, isShared: boolean) => provider === 'managed' && isShared === false,\n then: (schema) => schema.defined(\"Password is required when using managed email provider\"),\n otherwise: (schema) => schema.optional(),\n }),\n senderName: schemaFields.emailSenderNameSchema.optional().nonEmpty(),\n senderEmail: schemaFields.emailSenderEmailSchema.optional().nonEmpty(),\n managedSubdomain: yupString().optional().nonEmpty().when(['provider', 'isShared'], {\n is: (provider: string | undefined, isShared: boolean) => provider === 'managed' && isShared === false,\n then: (schema) => schema.defined(\"Managed subdomain is required when using managed email provider\"),\n otherwise: (schema) => schema.optional(),\n }),\n managedSenderLocalPart: yupString().optional().nonEmpty().when(['provider', 'isShared'], {\n is: (provider: string | undefined, isShared: boolean) => provider === 'managed' && isShared === false,\n then: (schema) => schema.defined(\"Managed sender local part is required when using managed email provider\"),\n otherwise: (schema) => schema.optional(),\n }),\n }),\n })),\n\n domains: branchConfigSchema.getNested(\"domains\").concat(yupObject({\n allowLocalhost: yupBoolean(),\n trustedDomains: yupRecord(\n userSpecifiedIdSchema(\"trustedDomainId\"),\n yupObject({\n baseUrl: schemaFields.wildcardUrlSchema.max(300), // TODO: replace with wildcardProtocolAndDomainSchema (this will require a migration as some configs have domains that are not valid wildcard protocol and domain patterns)\n handlerPath: schemaFields.handlerPathSchema.max(300),\n }),\n ),\n })),\n\n payments: branchConfigSchema.getNested(\"payments\").concat(yupObject({\n testMode: yupBoolean(),\n })),\n\n dbSync: yupObject({\n externalDatabases: yupRecord(\n userSpecifiedIdSchema(\"externalDatabaseId\"),\n yupObject({\n type: yupString().oneOf([\"postgres\"]).defined(),\n connectionString: yupString().when(\"type\", {\n is: \"postgres\",\n then: (schema) => schema.defined(),\n otherwise: (schema) => schema.optional(),\n }),\n }),\n ),\n }),\n\n analytics: environmentAnalyticsSchema,\n customDashboards: schemaFields.customDashboardsSchema,\n}));\n\nexport const organizationConfigSchema = environmentConfigSchema.concat(yupObject({}));\n\n\n// Migration functions\n//\n// These are used to migrate old config overrides to the new format on the database.\n//\n// THEY SHOULD NOT BE USED FOR ANY OTHER PURPOSE. They should not be used for default values. They should not be used\n// for sanitization. Instead, use the applicable functions for that.\n//\n// We run these migrations over the database when we do a big migration. USE THESE SPARINGLY. USE OTHER METHODS WHENEVER\n// POSSIBLE.\n//\n// The result of this function should be reproducible, and should not contain ANY randomness/non-determinism.\nexport function migrateConfigOverride(type: \"project\" | \"branch\" | \"environment\" | \"organization\", oldUnmigratedConfigOverride: any): any {\n const isBranchOrHigher = [\"branch\", \"environment\", \"organization\"].includes(type);\n const isEnvironmentOrHigher = [\"environment\", \"organization\"].includes(type);\n\n let res = oldUnmigratedConfigOverride;\n\n // BEGIN 2025-07-28: emails.theme is now emails.selectedThemeId\n if (isBranchOrHigher) {\n res = renameProperty(res, \"emails.theme\", \"selectedThemeId\");\n }\n // END\n\n // BEGIN 2025-07-28: domains.trustedDomains can no longer be an array\n if (isEnvironmentOrHigher) {\n res = mapProperty(res, p => p.join(\".\") === \"domains.trustedDomains\", (value) => {\n if (Array.isArray(value)) {\n return typedFromEntries(value.map((v, i) => [`${i}`, v]));\n }\n return value;\n });\n }\n // END\n\n // BEGIN 2025-07-28: themeList and templateList have been renamed (this was before the email release, so they're safe to remove)\n if (isBranchOrHigher) {\n res = removeProperty(res, p => p.join(\".\") === \"emails.themeList\");\n res = removeProperty(res, p => p.join(\".\") === \"emails.templateList\");\n }\n // END\n\n // BEGIN 2025-07-28: sourceOfTruth was mistakenly written to the environment config in some cases, so let's remove it\n if (isBranchOrHigher) {\n res = removeProperty(res, p => p.join(\".\") === \"sourceOfTruth\");\n }\n // END\n\n // BEGIN 2025-08-25: stripeAccountId and stripeAccountSetupComplete are unused, so let's remove them\n if (isBranchOrHigher) {\n res = removeProperty(res, p => p.join(\".\") === \"payments.stripeAccountId\");\n res = removeProperty(res, p => p.join(\".\") === \"payments.stripeAccountSetupComplete\");\n }\n // END\n\n // BEGIN 2025-08-25: payments.items.default is no longer used, so let's remove it\n if (isBranchOrHigher) {\n res = removeProperty(res, p => p.length === 4 && p[0] === \"payments\" && p[1] === \"items\" && p[3] === \"default\");\n }\n // END\n\n // BEGIN 2025-09-23: payments.offers is now payments.products\n if (isBranchOrHigher) {\n res = renameProperty(res, \"payments.offers\", \"products\");\n }\n // END\n\n // BEGIN 2025-09-23: payments.groups is now payments.catalogs\n if (isBranchOrHigher) {\n res = renameProperty(res, \"payments.groups\", \"catalogs\");\n }\n // END\n\n // BEGIN 2025-09-23: payments.products.*.groupId is now payments.products.*.catalogId\n if (isBranchOrHigher) {\n res = renameProperty(res, (p) => p.length === 4 && p[0] === \"payments\" && p[1] === \"products\" && p[3] === \"groupId\", (p) => \"catalogId\");\n }\n // END\n\n // BEGIN 2025-10-29: Removed workflows and everything associated with it\n if (isBranchOrHigher) {\n res = removeProperty(res, p => p[0] === \"workflows\");\n res = removeProperty(res, p => p[0] === \"apps\" && p[1] === \"installed\" && p[2] === \"workflows\");\n }\n // END\n\n // BEGIN 2026-01-14: payments.catalogs is now payments.productLines (with customerType inferred from products) and payments.products.*.catalogId is now payments.products.*.productLineId\n if (isBranchOrHigher) {\n res = migrateCatalogsToProductLines(res);\n }\n // END\n\n // BEGIN 2026-04-21: `include-by-default` product prices are no longer supported. Rewrite to an empty price map so legacy configs continue to load.\n if (isBranchOrHigher) {\n // Match `payments.products.<productId>.prices` regardless of how many segments the\n // product-ID portion contributes. mapProperty splits dot-notation override keys on\n // \".\", so a product whose ID itself contains \".\" (e.g. \"my.product\") would produce\n // a path with >4 segments and silently miss an exact-length match.\n res = mapProperty(res, p => p.length >= 4 && p[0] === \"payments\" && p[1] === \"products\" && p[p.length - 1] === \"prices\", (value) => {\n if (value === \"include-by-default\") return {};\n return value;\n });\n }\n // END\n\n // BEGIN 2026-05-23: external source-of-truth config was never used and is no longer supported.\n // Drop the override so legacy Neon/Postgres configs continue to render as the hosted default.\n if (type === \"project\") {\n res = removeProperty(res, p => p[0] === \"sourceOfTruth\");\n }\n // END\n\n // BEGIN 2026-07-01: dbSync.externalDatabases contains environment-specific connection strings.\n // It should never be rendered from branch config, which can be read by branch-scoped tools.\n if (type === \"branch\") {\n res = removeProperty(res, p => p[0] === \"dbSync\");\n }\n // END\n\n // BEGIN 2026-07-24: the deployments app is now `deployments-alpha`, both as its\n // `apps.installed` key and as its top-level config section, so the alpha stage is\n // visible in every hexclave.config.ts that opts into it. Both renames are needed:\n // an installed entry without the config section (or vice versa) is a valid state.\n if (isBranchOrHigher) {\n res = renameProperty(res, \"deployments\", \"deployments-alpha\");\n res = renameProperty(res, \"apps.installed.deployments\", \"deployments-alpha\");\n }\n // END\n\n // return the result\n return res;\n};\n\nimport.meta.vitest?.test(\"migrateConfigOverride removes legacy sourceOfTruth overrides\", ({ expect }) => {\n expect(migrateConfigOverride(\"project\", {\n sourceOfTruth: {\n type: \"neon\",\n connectionStrings: {\n main: \"postgres://user:password@neon.example.com/database\",\n },\n },\n })).toEqual({});\n\n expect(migrateConfigOverride(\"project\", {\n \"sourceOfTruth.type\": \"postgres\",\n \"sourceOfTruth.connectionString\": \"postgres://user:password@host:5432/database\",\n })).toEqual({});\n});\n\nimport.meta.vitest?.test(\"migrateConfigOverride removes legacy branch-level dbSync overrides\", ({ expect }) => {\n const dbSync = {\n externalDatabases: {\n main: {\n type: \"postgres\",\n connectionString: \"postgres://user:password@host:5432/database\",\n },\n },\n };\n\n expect(migrateConfigOverride(\"branch\", { dbSync })).toEqual({});\n expect(migrateConfigOverride(\"environment\", { dbSync })).toEqual({ dbSync });\n});\n\nimport.meta.vitest?.test(\"migrateConfigOverride renames the deployments app to deployments-alpha\", ({ expect }) => {\n const services = { web: { type: \"vercel\", rootDirectory: \"./\" } };\n\n // Fully nested overrides.\n expect(migrateConfigOverride(\"branch\", {\n deployments: { services },\n apps: { installed: { deployments: { enabled: true } } },\n })).toEqual({\n \"deployments-alpha\": { services },\n apps: { installed: { \"deployments-alpha\": { enabled: true } } },\n });\n\n // Dot-notation overrides, which is how the dashboard and the Deployments app\n // itself write single keys. The flat key form is preserved — only the renamed\n // segment changes — so the override keeps overriding exactly one leaf rather\n // than being widened into a whole subtree.\n expect(migrateConfigOverride(\"branch\", {\n \"deployments.services.web.buildCommand\": \"pnpm build\",\n \"apps.installed.deployments.enabled\": true,\n })).toEqual({\n \"deployments-alpha.services.web.buildCommand\": \"pnpm build\",\n \"apps.installed.deployments-alpha.enabled\": true,\n });\n\n // A service literally named \"deployments\" sits below the renamed section and\n // must survive untouched — only the top-level section and the installed-apps\n // entry are renamed.\n expect(migrateConfigOverride(\"branch\", {\n deployments: { services: { deployments: { type: \"vercel\" } } },\n })).toEqual({\n \"deployments-alpha\": { services: { deployments: { type: \"vercel\" } } },\n });\n\n // Already-migrated configs are left alone (the migration must be idempotent,\n // since it re-runs on every read).\n expect(migrateConfigOverride(\"branch\", {\n \"deployments-alpha\": { services },\n })).toEqual({\n \"deployments-alpha\": { services },\n });\n\n // Project level is not branch-or-higher, so nothing is renamed there.\n expect(migrateConfigOverride(\"project\", { deployments: { services } })).toEqual({ deployments: { services } });\n});\n\nfunction removeProperty(obj: Record<string, any>, pathCond: (path: (string | symbol)[]) => boolean): any {\n return mapProperty(obj, pathCond, () => undefined);\n}\n\nfunction mapProperty(obj: Record<string, any>, pathCond: (path: string[]) => boolean, mapper: (value: any) => any): any {\n const res: Record<string, any> = Array.isArray(obj) ? [] : {};\n for (const [key, value] of typedEntries(obj)) {\n const path = key.split(\".\");\n if (pathCond(path)) {\n const newValue = mapper(value);\n if (newValue !== undefined) {\n set(res, key, newValue);\n } else {\n // do nothing\n }\n } else if (isObjectLike(value)) {\n set(res, key, mapProperty(value, p => pathCond([...path, ...p]), mapper));\n } else {\n set(res, key, value);\n }\n }\n return res;\n}\nimport.meta.vitest?.test(\"mapProperty - basic property mapping\", ({ expect }) => {\n expect(mapProperty({ a: { b: { c: 1 } } }, p => p.join(\".\") === \"a.b.c\", (value) => value + 1)).toEqual({ a: { b: { c: 2 } } });\n expect(mapProperty({ a: { b: { c: 1 } } }, p => p.join(\".\") === \"a.b.d\", (value) => value + 1)).toEqual({ a: { b: { c: 1 } } });\n expect(mapProperty({ x: 5 }, p => p.join(\".\") === \"x\", (value) => value * 2)).toEqual({ x: 10 });\n expect(mapProperty({ a: { b: { c: 1 } } }, p => p.join(\".\") === \"b.c\", (value) => value * 10)).toEqual({ a: { b: { c: 1 } } });\n expect(mapProperty({ a: 1 }, p => p.join(\".\") === \"b.c\", (value) => value)).toEqual({ a: 1 });\n expect(mapProperty({ \"a.b\": { c: 1 } }, p => p.join(\".\") === \"a.b.c\", (value) => value + 1)).toEqual({ \"a.b\": { c: 2 } });\n\n expect(mapProperty({ a: { b: { c: 1 } } }, p => p.length === 3 && p[0] === \"a\" && p[1] === \"b\", (value) => value + 1)).toEqual({ a: { b: { c: 2 } } });\n\n // The include-by-default migration uses a prefix/suffix path predicate against dot-notation\n // keys: `payments.products.<productId>.prices`, where the product-ID portion may be one or\n // more segments (since override keys are dot-paths and a product ID may itself contain \".\").\n // Verify it matches whether the override is fully nested, dot-notation at the root, a mix,\n // or contains a dotted product ID.\n const sentinelToEmpty = (v: any) => v === \"include-by-default\" ? {} : v;\n const sentinelPred = (p: string[]) => p.length >= 4 && p[0] === \"payments\" && p[1] === \"products\" && p[p.length - 1] === \"prices\";\n expect(mapProperty({ \"payments.products.x.prices\": \"include-by-default\" }, sentinelPred, sentinelToEmpty))\n .toEqual({ \"payments.products.x.prices\": {} });\n expect(mapProperty({ payments: { products: { x: { prices: \"include-by-default\" } } } }, sentinelPred, sentinelToEmpty))\n .toEqual({ payments: { products: { x: { prices: {} } } } });\n expect(mapProperty({ \"payments.products\": { x: { prices: \"include-by-default\" } } }, sentinelPred, sentinelToEmpty))\n .toEqual({ \"payments.products\": { x: { prices: {} } } });\n // Dotted product ID: \"my.product\" expands to two path segments, total 5.\n expect(mapProperty({ \"payments.products.my.product.prices\": \"include-by-default\" }, sentinelPred, sentinelToEmpty))\n .toEqual({ \"payments.products.my.product.prices\": {} });\n});\n\nfunction renameProperty(obj: Record<string, any>, oldPath: string | ((path: string[]) => boolean), newName: string | ((path: string[]) => string)): any {\n const pathCond = typeof oldPath === \"function\" ? oldPath : (p: string[]) => p.join(\".\") === oldPath;\n const pathMapper = typeof newName === \"function\" ? newName : (p: string[]) => (newName as string);\n\n const res: Record<string, any> = Array.isArray(obj) ? [] : {};\n for (const [key, originalValue] of typedEntries(obj)) {\n const path = key.split(\".\");\n\n for (let i = 0; i < path.length; i++) {\n const pathPrefix = path.slice(0, i + 1);\n if (pathCond(pathPrefix)) {\n const name = pathMapper(pathPrefix);\n if (name.includes(\".\")) throw new HexclaveAssertionError(`newName must not contain a dot. Provided: ${name}`);\n path[i] = name;\n }\n }\n\n const value = isObjectLike(originalValue) ? renameProperty(originalValue, p => pathCond([...path, ...p]), p => pathMapper([...path, ...p])) : originalValue;\n set(res, path.join(\".\"), value);\n }\n\n return res;\n}\nimport.meta.vitest?.test(\"renameProperty\", ({ expect }) => {\n // Basic\n expect(renameProperty({ a: 1 }, \"a\", \"b\")).toEqual({ b: 1 });\n expect(renameProperty({ b: { c: 1 } }, \"b.c\", \"d\")).toEqual({ b: { d: 1 } });\n expect(renameProperty({ a: { b: { c: 1 } } }, \"a.b.c\", \"d\")).toEqual({ a: { b: { d: 1 } } });\n expect(renameProperty({ a: { b: { c: 1 } } }, \"a.b.c.d\", \"e\")).toEqual({ a: { b: { c: 1 } } });\n expect(renameProperty({ a: { b: { c: 1 }, \"b.c\": 2 } }, \"b.c\", \"d\")).toEqual({ a: { b: { c: 1 }, \"b.c\": 2 } });\n expect(renameProperty({ a: { \"b.c.d\": 2 } }, \"a.b.c\", \"e\")).toEqual({ a: { \"b.e.d\": 2 } });\n expect(renameProperty({ a: { b: { c: 1 }, \"b.c\": 2 } }, \"a.b.c\", \"d\")).toEqual({ a: { b: { d: 1 }, \"b.d\": 2 } });\n expect(renameProperty({ a: { b: { c: 1, d: 2 } } }, \"a.b.c\", \"d\")).toEqual({ a: { b: { d: 2 } } });\n expect(renameProperty({ a: { b: { d: 2, c: 1 } } }, \"a.b.c\", \"d\")).toEqual({ a: { b: { d: 1 } } });\n\n // Functions\n expect(renameProperty({ a: 1 }, (p) => p.length === 1 && p[0] === \"a\", (p) => \"b\")).toEqual({ b: 1 });\n expect(renameProperty({ a: { b: { c: 1 } } }, (p) => p.length === 3 && p[0] === \"a\" && p[1] === \"b\" && p[2] === \"c\", (p) => \"d\")).toEqual({ a: { b: { d: 1 } } });\n expect(renameProperty({ a: { b: { c: 1 } } }, (p) => false, (p) => \"e\")).toEqual({ a: { b: { c: 1 } } });\n expect(renameProperty({ a: { b: { a: 1 } } }, (p) => p[p.length - 1] === \"a\", (p) => \"c\")).toEqual({ c: { b: { c: 1 } } });\n\n // Errors\n expect(() => renameProperty({ a: 1 }, \"a\", \"b.c\")).toThrow();\n});\n\n\n// Defaults\n// these are objects that are merged together to form the rendered config (see ./README.md)\n// Wherever an object could be used as a value, a function can instead be used to generate the default values on a per-key basis\n// To make sure you don't accidentally forget setting a default value, you must explicitly set fields with no default value to `undefined`.\n// NOTE: These values are the defaults of the schema, NOT the defaults for newly created projects. The values here signify what `null` means for each property. If you want new projects by default to have a certain value set to true, you should update the corresponding function in the backend instead.\nconst projectConfigDefaults = {\n sourceOfTruth: {\n type: 'hosted',\n },\n project: {\n requirePublishableClientKey: false,\n },\n} as const satisfies DefaultsType<ProjectRenderedConfigBeforeDefaults, []>;\n\nconst branchConfigDefaults = {} as const satisfies DefaultsType<BranchRenderedConfigBeforeDefaults, [typeof projectConfigDefaults]>;\n\nconst environmentConfigDefaults = {} as const satisfies DefaultsType<EnvironmentRenderedConfigBeforeDefaults, [typeof branchConfigDefaults, typeof projectConfigDefaults]>;\n\nconst organizationConfigDefaults = {\n rbac: {\n permissions: (key: string) => ({\n containedPermissionIds: (key: string) => undefined,\n description: undefined,\n scope: undefined,\n }),\n defaultPermissions: {\n teamCreator: (key: string) => undefined,\n teamMember: (key: string) => undefined,\n signUp: (key: string) => undefined,\n },\n },\n\n apiKeys: {\n enabled: {\n team: false,\n user: false,\n },\n },\n\n apps: {\n installed: typedFromEntries(appIds.map(appId => [appId, { enabled: false }])) as Record<string, { enabled: boolean } | undefined>,\n },\n\n teams: {\n createPersonalTeamOnSignUp: false,\n allowClientTeamCreation: false,\n },\n\n users: {\n allowClientUserDeletion: false,\n },\n\n onboarding: {\n requireEmailVerification: false,\n },\n\n domains: {\n allowLocalhost: false,\n trustedDomains: (key: string) => ({\n baseUrl: undefined,\n handlerPath: '/handler',\n }) as const,\n },\n\n auth: {\n allowSignUp: true,\n password: {\n allowSignIn: false,\n },\n otp: {\n allowSignIn: false,\n },\n passkey: {\n allowSignIn: false,\n },\n oauth: {\n accountMergeStrategy: 'link_method',\n providers: (key: string) => ({\n type: undefined,\n isShared: true,\n allowSignIn: false,\n allowConnectedAccounts: false,\n clientId: undefined,\n clientSecret: undefined,\n customCallbackUrl: undefined,\n facebookConfigId: undefined,\n microsoftTenantId: undefined,\n appleBundles: undefined,\n }),\n },\n signUpRules: (key: string) => ({\n enabled: false,\n displayName: undefined,\n priority: 0,\n condition: undefined,\n action: {\n type: 'allow',\n message: undefined,\n },\n }),\n signUpRulesDefaultAction: 'allow',\n },\n\n emails: {\n server: {\n isShared: true,\n provider: \"smtp\",\n host: undefined,\n port: undefined,\n username: undefined,\n password: undefined,\n senderName: undefined,\n senderEmail: undefined,\n managedSubdomain: undefined,\n managedSenderLocalPart: undefined,\n },\n selectedThemeId: DEFAULT_EMAIL_THEME_ID,\n themes: typedAssign((key: string) => ({\n displayName: \"Unnamed Theme\",\n tsxSource: \"Error: Theme config is missing TypeScript source code.\",\n }), DEFAULT_EMAIL_THEMES),\n templates: typedAssign((key: string) => ({\n displayName: \"Unnamed Template\",\n tsxSource: \"Error: Template config is missing TypeScript source code.\",\n themeId: undefined,\n }), DEFAULT_EMAIL_TEMPLATES),\n },\n\n payments: {\n blockNewPurchases: false,\n testMode: true,\n autoPay: undefined,\n productLines: (key: string) => ({\n displayName: undefined,\n customerType: undefined,\n }),\n products: (key: string) => ({\n displayName: key,\n productLineId: undefined,\n customerType: \"user\",\n freeTrial: undefined,\n serverOnly: false,\n stackable: undefined,\n isAddOnTo: false,\n prices: (key: string) => ({\n ...typedFromEntries(SUPPORTED_CURRENCIES.map(currency => [currency.code, undefined])),\n interval: undefined,\n serverOnly: false,\n freeTrial: undefined,\n }),\n includedItems: (key: string) => ({\n quantity: 0,\n repeat: \"never\",\n expires: \"when-repeated\",\n }),\n } as const),\n items: (key: string) => ({\n displayName: key,\n customerType: \"user\",\n } as const)\n },\n\n\n dbSync: {\n externalDatabases: (key: string) => ({\n type: undefined,\n connectionString: undefined,\n }),\n },\n\n \"deployments-alpha\": {\n services: (key: string) => ({\n type: undefined,\n framework: undefined,\n installCommand: undefined,\n buildCommand: undefined,\n outputDirectory: undefined,\n rootDirectory: undefined,\n env: (envVarKey: string) => ({\n type: undefined,\n value: undefined,\n key: undefined,\n }),\n }),\n },\n\n dataVault: {\n stores: (key: string) => ({\n displayName: \"Unnamed Vault\",\n }),\n },\n\n analytics: {\n queryFolders: (key: string) => ({\n displayName: \"Unnamed Folder\",\n sortOrder: 0,\n queries: (queryKey: string) => ({\n displayName: \"Unnamed Query\",\n sqlQuery: \"\",\n description: undefined,\n }),\n }),\n },\n\n customDashboards: (key: string) => ({\n displayName: \"Unnamed Dashboard\",\n tsxSource: \"Error: Dashboard config is missing source code.\",\n }),\n} as const satisfies DefaultsType<OrganizationRenderedConfigBeforeDefaults, [typeof environmentConfigDefaults, typeof branchConfigDefaults, typeof projectConfigDefaults]>;\n\ntype _DeepOmitDefaultsImpl<T, U> = T extends object ? (\n (\n & /* keys that are both in T and U, *and* the key's value in U is not a subtype of the key's value in T */ { [K in { [Ki in keyof T & keyof U]: U[Ki] extends T[Ki] ? never : Ki }[keyof T & keyof U]]: DeepOmitDefaults<T[K], U[K] & object> }\n & /* keys that are in T but not in U */ { [K in Exclude<keyof T, keyof U>]: T[K] }\n )\n) : T;\ntype DeepOmitDefaults<T, U> = _DeepOmitDefaultsImpl<DeepFilterUndefined<T>, U>;\ntype DefaultsType<T, U extends any[]> = DeepReplaceAllowFunctionsForObjects<DeepOmitDefaults<DeepRequiredOrUndefined<T>, IntersectAll<{ [K in keyof U]: DeepReplaceFunctionsWithObjects<U[K]> }>>>;\ntypeAssertIs<DefaultsType<{ a: { b: Record<string, 123>, c: 456 } }, [{ a: { c: 456 } }]>, { a: { b: ((key: string) => 123) | Record<string, 123 | undefined> & ((key: string) => 123) } }>()();\n\ntype DeepReplaceAllowFunctionsForObjects<T> = T extends object\n ? (\n string extends keyof T\n ? ((arg: Exclude<keyof T, number>) => DeepReplaceAllowFunctionsForObjects<T[keyof T]>) & ({ [K in keyof T]?: DeepReplaceAllowFunctionsForObjects<T[K]> } | {})\n : { [K in keyof T]: DeepReplaceAllowFunctionsForObjects<T[K]> }\n )\n :\n T;\ntype ReplaceFunctionsWithObjects<T> = T & (T extends (arg: infer K extends string) => infer R ? Record<K, R> & object : unknown);\ntype DeepReplaceFunctionsWithObjects<T> = T extends object ? { [K in keyof ReplaceFunctionsWithObjects<T>]: DeepReplaceFunctionsWithObjects<ReplaceFunctionsWithObjects<T>[K]> } : T;\ntypeAssertIs<DeepReplaceFunctionsWithObjects<{ a: { b: 123 } & ((key: string) => number) }>, { a: { b: 123, [key: string]: number } }>()();\n\nfunction deepReplaceFunctionsWithObjects(obj: any, paths: string[] = []): any {\n const subPaths = (key: string) => {\n return paths.filter(p => p.split(\".\").length > 1 && p.split(\".\")[0] === key)\n .map(p => p.split(\".\").slice(1).join(\".\"));\n };\n const currentPaths = [...new Set(paths.map(p => p.split(\".\")[0]))];\n const nonDeepReplaced = {\n ...typeof obj === \"function\" ? filterUndefined(Object.fromEntries(currentPaths.map(k => [k, obj(k)]))) : {},\n ...obj,\n };\n return mapValues(nonDeepReplaced, (v, k) => (isObjectLike(v) ? deepReplaceFunctionsWithObjects(v as any, subPaths(k as string)) : v));\n}\nimport.meta.vitest?.test(\"deepReplaceFunctionsWithObjects\", ({ expect }) => {\n expect(deepReplaceFunctionsWithObjects(() => { })).toEqual({});\n expect(deepReplaceFunctionsWithObjects({ a: 3 })).toEqual({ a: 3 });\n expect(deepReplaceFunctionsWithObjects({ a: () => ({ b: 1 }) })).toEqual({ a: {} });\n expect(deepReplaceFunctionsWithObjects({ a: () => ({ b: 1 }) }, [\"a.c.d\"])).toEqual({ a: { c: { b: 1 } } });\n expect(deepReplaceFunctionsWithObjects(() => ({ b: 1 }), [\"a\"])).toEqual({ a: { b: 1 } });\n expect(deepReplaceFunctionsWithObjects({ a: typedAssign(() => ({}), { b: { c: 1 } }) })).toEqual({ a: { b: { c: 1 } } });\n});\n\ntype ApplyDefaults<D extends object | ((key: string) => unknown), C extends object> = {} extends D ? C : DeepMerge<DeepReplaceFunctionsWithObjects<D>, C>; // the {} extends D makes TypeScript not recurse if the defaults are empty, hence allowing us more recursion until \"type instantiation too deep\" kicks in... it's a total hack, but it works, so hey?\nfunction applyDefaults<D extends object | ((key: string) => unknown), C extends object>(defaults: D, config: C): ApplyDefaults<D, C> {\n const res: any = deepReplaceFunctionsWithObjects(defaults);\n\n outer: for (const [key, mergeValue] of Object.entries(config)) {\n if (!isObjectLike(mergeValue) && mergeValue !== null) {\n set(res, key, mergeValue);\n } else {\n const keyParts = key.split(\".\");\n let baseValue: any = defaults;\n let lastWasFunction = false;\n for (const [index, part] of keyParts.entries()) {\n if (!isObjectLike(baseValue)) {\n set(res, key, mergeValue ?? null);\n continue outer;\n }\n lastWasFunction = false;\n baseValue = has(baseValue, part) ? get(baseValue, part) : (typeof baseValue === 'function' ? (lastWasFunction = true, baseValue as any)(part) : undefined);\n }\n if (lastWasFunction && mergeValue == null) {\n set(res, key, null);\n } else if (!isObjectLike(baseValue)) {\n set(res, key, mergeValue ?? baseValue ?? null);\n } else {\n set(res, key, applyDefaults(baseValue, mergeValue ?? {}) as any);\n }\n }\n }\n return res as any;\n}\nimport.meta.vitest?.test(\"applyDefaults\", ({ expect }) => {\n // Basic\n expect(applyDefaults({ a: 1 }, { a: 2 })).toEqual({ a: 2 });\n expect(applyDefaults({ a: 1 }, { a: null })).toEqual({ a: 1 });\n expect(applyDefaults({}, { a: 1 })).toEqual({ a: 1 });\n expect(applyDefaults({ a: { b: 1 } }, { a: { b: 2 } })).toEqual({ a: { b: 2 } });\n expect(applyDefaults({ a: { b: 1 } }, { a: { c: 2 } })).toEqual({ a: { b: 1, c: 2 } });\n expect(applyDefaults({ a: { b: { c: 1, d: 2 } } }, { a: { b: { d: 3, e: 4 } } })).toEqual({ a: { b: { c: 1, d: 3, e: 4 } } });\n\n // Functions\n expect(applyDefaults((key: string) => ({ b: key }), { a: {} })).toEqual({ a: { b: \"a\" } });\n expect(applyDefaults((key: string) => ({ b: key }), { a: null })).toEqual({ a: null });\n expect(applyDefaults((key1: string) => (key2: string) => ({ a: key1, b: key2 }), { c: { d: {} } })).toEqual({ c: { d: { a: \"c\", b: \"d\" } } });\n expect(applyDefaults({ a: (key: string) => ({ b: key }) }, { a: { c: { d: 1 } } })).toEqual({ a: { c: { b: \"c\", d: 1 } } });\n expect(applyDefaults({ a: (key: string) => ({ b: key }) }, {})).toEqual({ a: {} });\n expect(applyDefaults({ a: (key: string) => ({ b: key }) }, { a: null })).toEqual({ a: {} });\n expect(applyDefaults({ a: (key: string) => ({ c: key }) }, { a: { b: null } })).toEqual({ a: { b: null } });\n expect(applyDefaults({ a: { b: (key: string) => ({ b: key }) } }, {})).toEqual({ a: { b: {} } });\n expect(applyDefaults(typedAssign(() => ({ b: 1 }), { a: { b: 1, c: 2 } }), { a: {} })).toEqual({ a: { b: 1, c: 2 } });\n expect(applyDefaults(typedAssign(() => ({ b: 1 }), { a: { b: 1, c: 2 } }), { d: {} })).toEqual({ a: { b: 1, c: 2 }, d: { b: 1 } });\n\n // Dot notation\n expect(applyDefaults({ a: { b: 1 } }, { \"a.c\": 2 })).toEqual({ a: { b: 1 }, \"a.c\": 2 });\n expect(applyDefaults({ a: { b: 1 } }, { \"a.c\": null })).toEqual({ a: { b: 1 }, \"a.c\": null });\n expect(applyDefaults({ a: { b: 1 } }, { a: { b: 2 }, \"a.b\": null })).toEqual({ a: { b: 2 }, \"a.b\": 1 });\n expect(applyDefaults({ a: { b: { c: 1 } } }, { a: { b: { c: 2 } }, \"a.b.c\": null })).toEqual({ a: { b: { c: 2 } }, \"a.b.c\": 1 });\n expect(applyDefaults({}, { a: { b: 2 }, \"a.b\": null })).toEqual({ a: { b: 2 }, \"a.b\": null });\n expect(applyDefaults({ a: { b: 1, c: 2 } }, { \"a.c\": null })).toEqual({ a: { b: 1, c: 2 }, \"a.c\": 2 });\n expect(applyDefaults({ a: { b: 1, c: () => {} } }, { \"a.c\": null })).toEqual({ a: { b: 1, c: {} }, \"a.c\": {} });\n expect(applyDefaults({ a: { b: 1, c: () => {} } }, { \"a.c.d\": null })).toEqual({ a: { b: 1, c: {} }, \"a.c.d\": null });\n expect(applyDefaults({ a: { b: 1 } }, { \"a.b\": null })).toEqual({ a: { b: 1 }, \"a.b\": 1 });\n expect(applyDefaults({ a: { b: { c: 1 } } }, { \"a.b\": null })).toEqual({ a: { b: { c: 1 } }, \"a.b\": { c: 1 } });\n expect(applyDefaults({ a: {} }, { \"a.b\": null })).toEqual({ a: {}, \"a.b\": null });\n expect(applyDefaults({ a: {} }, { \"a\": { b: 1 }, \"a.b\": null })).toEqual({ a: { b: 1 }, \"a.b\": null });\n expect(applyDefaults({ a: 1 }, { \"a.b\": null })).toEqual({ a: 1, \"a.b\": null });\n expect(applyDefaults({ a: 1 }, { \"a.b\": 2 })).toEqual({ a: 1, \"a.b\": 2 });\n expect(applyDefaults({ a: null }, { \"a.b\": 2 })).toEqual({ a: null, \"a.b\": 2 });\n expect(applyDefaults({ a: { b: { c: 1 } } }, { \"a.b\": { d: 2 } })).toEqual({ a: { b: { c: 1 } }, \"a.b\": { c: 1, d: 2 } });\n expect(applyDefaults({ a: { b: { c: 1 } } }, { \"a.b\": null })).toEqual({ a: { b: { c: 1 } }, \"a.b\": { c: 1 } });\n expect(applyDefaults({ a: { b: { c: { d: 1 } } } }, { \"a.b.c\": {} })).toEqual({ a: { b: { c: { d: 1 } } }, \"a.b.c\": { d: 1 } });\n expect(applyDefaults({ a: () => ({ c: 1 }) }, { \"a.b\": { d: 2 } })).toEqual({ a: {}, \"a.b\": { c: 1, d: 2 } });\n expect(applyDefaults({ a: () => () => ({ d: 1 }) }, { \"a.b\": null })).toEqual({ a: {}, \"a.b\": null });\n expect(applyDefaults({ a: () => () => ({ d: 1 }) }, { \"a.b.c\": {} })).toEqual({ a: {}, \"a.b.c\": { d: 1 } });\n expect(applyDefaults({ a: { b: () => ({ c: 1, d: 2 }) } }, { \"a.b.x-y.c\": 3 })).toEqual({ a: { b: {} }, \"a.b.x-y.c\": 3 });\n expect(applyDefaults({ a: () => ({ c: 1 }) }, { \"a.b.d\": 2 })).toEqual({ a: {}, \"a.b.d\": 2 });\n expect(applyDefaults({ a: () => ({ c: 1 }) }, { \"a.b.d\": 2, \"a.e.d\": 3 })).toEqual({ a: {}, \"a.b.d\": 2, \"a.e.d\": 3 });\n expect(applyDefaults({ a: () => ({ c: 1 }) }, { \"a.b.d\": 2, a: { b: { d: 3 } } })).toEqual({ a: { b: { c: 1, d: 3 } }, \"a.b.d\": 2 });\n expect(applyDefaults({ a: () => ({ c: 1 }) }, { \"a.b.d\": 2, a: { e: { d: 3 } } })).toEqual({ a: { e: { c: 1, d: 3 } }, \"a.b.d\": 2 });\n expect(applyDefaults({ a: () => ({ c: 1 }) }, { \"a.b\": { d: { e: 2 } }, \"a.b.d\": null })).toEqual({ a: {}, \"a.b\": { c: 1, d: { e: 2 } }, \"a.b.d\": null });\n});\n\nexport function applyProjectDefaults<T extends ProjectRenderedConfigBeforeDefaults>(config: T) {\n return applyDefaults(projectConfigDefaults, config);\n}\n\nexport function applyBranchDefaults<T extends BranchRenderedConfigBeforeDefaults>(config: T) {\n return applyDefaults(\n branchConfigDefaults,\n applyDefaults(\n projectConfigDefaults,\n config\n )\n );\n}\n\nexport function applyEnvironmentDefaults<T extends EnvironmentRenderedConfigBeforeDefaults>(config: T): ApplyDefaults<typeof environmentConfigDefaults, ApplyDefaults<typeof branchConfigDefaults, ApplyDefaults<typeof projectConfigDefaults, T>>> {\n return applyDefaults(\n environmentConfigDefaults,\n applyDefaults(\n branchConfigDefaults,\n applyDefaults(\n projectConfigDefaults,\n config\n ) as any\n ) as any\n ) as any;\n}\n\nexport function applyOrganizationDefaults(config: OrganizationRenderedConfigBeforeDefaults): ApplyDefaults<typeof organizationConfigDefaults, ApplyDefaults<typeof environmentConfigDefaults, ApplyDefaults<typeof branchConfigDefaults, ApplyDefaults<typeof projectConfigDefaults, OrganizationRenderedConfigBeforeDefaults>>>> {\n return applyDefaults(\n organizationConfigDefaults,\n applyDefaults(\n environmentConfigDefaults,\n applyDefaults(\n branchConfigDefaults,\n applyDefaults(\n projectConfigDefaults,\n config\n ) as any\n ) as any\n ) as any\n ) as any;\n}\n\n\nexport async function sanitizeProjectConfig<T extends ProjectRenderedConfigBeforeSanitization>(config: T) {\n assertNormalized(config);\n\n return {\n ...config,\n sourceOfTruth: {\n type: 'hosted',\n } as const,\n };\n}\n\nexport async function sanitizeBranchConfig<T extends BranchRenderedConfigBeforeSanitization>(config: T) {\n assertNormalized(config);\n const prepared = await sanitizeProjectConfig(config);\n return {\n ...prepared,\n };\n}\n\nexport async function sanitizeEnvironmentConfig<T extends EnvironmentRenderedConfigBeforeSanitization>(config: T) {\n assertNormalized(config);\n const prepared = await sanitizeBranchConfig(config);\n return {\n ...prepared,\n };\n}\n\nexport async function sanitizeOrganizationConfig(config: OrganizationRenderedConfigBeforeSanitization) {\n assertNormalized(config);\n const prepared = await sanitizeEnvironmentConfig(config);\n\n const themes: typeof prepared.emails.themes = prepared.emails.themes;\n const templates: typeof prepared.emails.templates = config.emails.server.isShared ? DEFAULT_EMAIL_TEMPLATES : prepared.emails.templates;\n\n const products = typedFromEntries(typedEntries(prepared.payments.products).map(([key, product]) => {\n const isAddOnTo = product.isAddOnTo === false ?\n false as const :\n typedFromEntries(Object.keys(product.isAddOnTo).map((key) => [key, true as const]));\n type PriceEntry = Partial<typeof product.prices[string]> & { serverOnly: boolean };\n // `serverOnly` is guaranteed to be a boolean by the applyDefaults step above.\n const prices: Record<string, PriceEntry> = typedFromEntries(typedEntries(product.prices).map(([key, value]) => {\n const data: PriceEntry = { ...value };\n return [key, data];\n }));\n return [key, {\n ...product,\n isAddOnTo,\n prices,\n }];\n }));\n\n const appSortIndices = new Map(Object.keys(ALL_APPS).map((appId, index) => [appId, index]));\n\n // Get all sign-up rules and sort by priority (descending), then by ID (alphabetically)\n // Note: We don't filter out disabled rules here because the dashboard needs to show them\n // The runtime evaluation in sign-up-rules.ts handles skipping disabled rules\n const sortedRuleEntries = typedEntries(prepared.auth.signUpRules)\n .sort((a, b) => {\n const priorityA = a[1].priority;\n const priorityB = b[1].priority;\n if (priorityA !== priorityB) return priorityB - priorityA;\n return stringCompare(a[0], b[0]);\n });\n\n return {\n ...prepared,\n auth: {\n ...prepared.auth,\n oauth: {\n ...prepared.auth.oauth,\n providers: typedFromEntries(typedEntries(prepared.auth.oauth.providers).filter(([key, value]) => value.type !== undefined)),\n },\n signUpRules: typedFromEntries(sortedRuleEntries),\n },\n emails: {\n ...prepared.emails,\n selectedThemeId: has(themes, prepared.emails.selectedThemeId) ? prepared.emails.selectedThemeId : DEFAULT_EMAIL_THEME_ID,\n themes,\n templates,\n },\n payments: {\n ...prepared.payments,\n products\n },\n apps: {\n installed: typedFromEntries(\n typedEntries(prepared.apps.installed)\n .sort(([a], [b]) => appSortIndices.get(a)! - appSortIndices.get(b)!)\n ),\n },\n };\n}\n\n/**\n * Does not require a base config, and hence solely relies on the override itself to validate the config. If it returns\n * no error, you know that the\n *\n * It's crucial that our DB never contains any configs that are not valid according to this function, as this would mean\n * that the config object does not satisfy the ValidatedToHaveNoConfigOverrideErrors type (which is used as an assumption\n * in a whole bunch of places in the code).\n */\nexport async function getConfigOverrideErrors<T extends yup.AnySchema>(schema: T, configOverride: unknown, options: { allowPropertiesThatCanNoLongerBeOverridden?: boolean } = {}): Promise<Result<null, string>> {\n // currently, we go over the schema and ensure that the general requirements for each property are satisfied\n // importantly, we cannot check any cross-property constraints, as those may change depending on the base config\n // also, since overrides can be empty, we cannot have any required properties (TODO: can we have required properties in nested objects? would that even make sense? think about it)\n if (typeof configOverride !== \"object\" || configOverride === null) {\n return Result.error(\"Config override must be a non-null object.\");\n }\n if (Object.getPrototypeOf(configOverride) !== Object.getPrototypeOf({})) {\n return Result.error(\"Config override must be plain old JavaScript object.\");\n }\n\n // Ensure that all keys with dots in them are at the top level of the object, not nested\n const ensureNoDotsInKeys = (obj: unknown): Result<never, string> | undefined => {\n if (typeof obj !== \"object\" || obj === null) {\n return;\n }\n for (const entry of Object.entries(obj)) {\n if (entry[0].includes(\".\")) {\n return Result.error(`Key ${entry[0]} contains a dot, which is not allowed in config override.`);\n }\n const result = ensureNoDotsInKeys(entry[1]);\n if (result) {\n return result;\n }\n }\n return;\n };\n for (const key of Object.keys(configOverride)) {\n const result = ensureNoDotsInKeys(configOverride[key as keyof typeof configOverride]);\n if (result) {\n return result;\n }\n }\n\n // Check config format\n const reason = getInvalidConfigReason(configOverride, { configName: 'override' });\n if (reason) return Result.error(\"Invalid config format: \" + reason);\n\n const getSubSchema = (schema: yup.AnySchema, key: string): yup.AnySchema | undefined => {\n const keyParts = key.split(\".\");\n if (!schema.hasNested(keyParts[0])) {\n return undefined;\n }\n const nestedSchema = schema.getNested(keyParts[0]);\n if (nestedSchema.meta()?.hexclaveConfigCanNoLongerBeOverridden && !options.allowPropertiesThatCanNoLongerBeOverridden) {\n return undefined;\n }\n if (keyParts.length === 1) {\n return nestedSchema;\n } else {\n return getSubSchema(nestedSchema, keyParts.slice(1).join(\".\"));\n }\n };\n\n const getRestrictedSchemaBase = (path: string, schema: yup.AnySchema): yup.AnySchema => {\n const schemaInfo = schema.meta()?.hexclaveSchemaInfo;\n switch (schemaInfo?.type) {\n case \"string\": {\n const stringSchema = schema as yup.StringSchema<any>;\n const description = stringSchema.describe();\n let res = yupString();\n if (description.tests.some(t => t.name === \"uuid\")) {\n res = res.uuid();\n }\n return res;\n }\n case \"number\": {\n return yupNumber();\n }\n case \"boolean\": {\n return yupBoolean();\n }\n case \"date\": {\n return yupDate();\n }\n case \"mixed\": {\n return yupMixed();\n }\n case \"array\": {\n throw new HexclaveAssertionError(`Arrays are not supported in config JSON files (besides tuples). Use a record instead.`, { schemaInfo, schema });\n\n // This is how the implementation would look like, but we don't support arrays in config JSON files (besides tuples)\n // const arraySchema = schema as yup.ArraySchema<any, any, any, any>;\n // const innerType = arraySchema.innerType;\n // return yupArray(innerType ? getRestrictedSchema(path + \".[]\", innerType as any) : undefined());\n }\n case \"tuple\": {\n return yupTuple(schemaInfo.items.map((s, index) => getRestrictedSchema(path + `[${index}]`, s)) as any);\n }\n case \"union\": {\n const schemas = schemaInfo.items;\n const nonObjectSchemas = [...schemas.entries()].filter(([index, s]) => s.meta()?.hexclaveSchemaInfo?.type !== \"object\");\n const objectSchemas = schemas.filter((s): s is yup.ObjectSchema<any> => s.meta()?.hexclaveSchemaInfo?.type === \"object\");\n\n // merge all object schemas into a single schema\n const allObjectSchemaKeys = [...new Set(objectSchemas.flatMap(s => Object.keys(s.fields)))];\n const mergedObjectSchema = yupObject(\n Object.fromEntries(\n allObjectSchemaKeys.map(key => [key, yupUnion(\n ...objectSchemas.flatMap((s, index) => s.hasNested(key) ? [s.getNested(key)] : [])\n )])\n )\n );\n\n return yupUnion(\n ...nonObjectSchemas.map(([index, s]) => getRestrictedSchema(path + `|variant-${index}|`, s)),\n ...objectSchemas.length > 0 ? [getRestrictedSchema(path + (nonObjectSchemas.length > 0 ? `|variant|` : \"\"), mergedObjectSchema)] : [],\n );\n }\n case \"record\": {\n return yupRecord(getRestrictedSchema(path + \".key\", schemaInfo.keySchema) as any, getRestrictedSchema(path + \".value\", schemaInfo.valueSchema));\n }\n case \"object\": {\n const objectSchema = schema as yup.ObjectSchema<any>;\n return yupObject(\n Object.fromEntries(\n Object.entries(objectSchema.fields)\n .map(([key, value]) => [key, getRestrictedSchema(path + \".\" + key, value as any)])\n )\n );\n }\n case \"never\": {\n return yupNever();\n }\n default: {\n throw new HexclaveAssertionError(`Unknown schema info at path ${path}: ${JSON.stringify(schemaInfo)}`, { schemaInfo, schema });\n }\n }\n };\n const getRestrictedSchema = (path: string, schema: yup.AnySchema): yup.AnySchema => {\n let restricted = getRestrictedSchemaBase(path, schema);\n restricted = restricted.nullable();\n const description = schema.describe();\n if (description.oneOf.length > 0) {\n restricted = restricted.oneOf(description.oneOf);\n }\n if (description.notOneOf.length > 0) {\n restricted = restricted.notOneOf(description.notOneOf);\n }\n return restricted;\n };\n\n for (const [key, value] of Object.entries(configOverride)) {\n if (value === undefined) continue;\n if (/^payments\\.products\\.[^.]+\\.prices$/.test(key) && value === \"include-by-default\") {\n return Result.error(`${key} must not be one of the following values: include-by-default`);\n }\n const subSchema = getSubSchema(schema, key);\n if (!subSchema) {\n // find smallest key prefix that is invalid\n const keySplit = key.split(\".\");\n for (let i = 0; i < keySplit.length; i++) {\n const prefix = keySplit.slice(0, i + 1).join(\".\");\n const subSchema = getSubSchema(schema, prefix);\n if (!subSchema) {\n return Result.error(`The key ${JSON.stringify(key)} is not valid (nested object not found in schema: ${JSON.stringify(prefix)}).`);\n }\n }\n throw new HexclaveAssertionError(\"Something weird happened? Sub-schema for key is invalid but no prefix is invalid??\", { key, subSchema });\n }\n let restrictedSchema = getRestrictedSchema(key, subSchema);\n try {\n await restrictedSchema.validate(value, {\n strict: true,\n ...{\n // Although `path` is not part of the yup types, it is actually recognized and does the correct thing\n path: key\n },\n context: {\n noUnknownPathPrefixes: [''],\n },\n });\n } catch (error) {\n if (error instanceof yup.ValidationError) {\n return Result.error(error.message);\n }\n throw error;\n }\n }\n return Result.ok(null);\n}\nexport async function assertNoConfigOverrideErrors<T extends yup.AnySchema>(schema: T, config: unknown, options: { allowPropertiesThatCanNoLongerBeOverridden?: boolean, extraInfo?: any } = {}): Promise<void> {\n const res = await getConfigOverrideErrors(schema, config, options);\n if (res.status === \"error\") throw new HexclaveAssertionError(`Config override is invalid — at a place where it should have already been validated! ${res.error}`, { options, config });\n}\ntype _ValidatedToHaveNoConfigOverrideErrorsImpl<T> =\n IsUnion<T & object> extends true ? _ValidatedToHaveNoConfigOverrideErrorsImpl<CollapseObjectUnion<T & object> | Exclude<T, object>>\n : T extends object ? (T extends any[] ? T : { [K in keyof T]+?: _ValidatedToHaveNoConfigOverrideErrorsImpl<T[K]> })\n : T;\nexport type ValidatedToHaveNoConfigOverrideErrors<T extends yup.AnySchema> = _ValidatedToHaveNoConfigOverrideErrorsImpl<yup.InferType<T>>;\ntypeAssertIs<_ValidatedToHaveNoConfigOverrideErrorsImpl<{ a: string } | { b: number } | boolean>, { a?: string, b?: number } | boolean>()();\ntypeAssertExtends<_ValidatedToHaveNoConfigOverrideErrorsImpl<\"abc\" | 123 | null>, \"abc\" | 123 | null>()();\ntypeAssertExtends<_ValidatedToHaveNoConfigOverrideErrorsImpl<{ a: { b: { c: string } | { d: number } } }>, { a?: { b?: { c?: string, d?: number } } }>()();\n\n/**\n * Checks whether there are any warnings in the incomplete config. A warning doesn't stop the config from being valid,\n * but may require action regardless.\n *\n * The DB can contain configs that are not valid according to this function, as long as they are valid according to\n * the getConfigOverrideErrors function. (This is necessary, because a changing base config may make an override invalid\n * that was previously valid.)\n */\nexport async function getIncompleteConfigWarnings<T extends yup.AnySchema>(schema: T, incompleteConfig: Config): Promise<Result<null, string>> {\n // every rendered config should also be a config override without errors (regardless of whether it has warnings or not)\n const overrideErrors = await getConfigOverrideErrors(schema, incompleteConfig, { allowPropertiesThatCanNoLongerBeOverridden: true });\n if (overrideErrors.status === \"error\") {\n return overrideErrors;\n }\n\n // Check for dot-notation keys that would be silently dropped during rendering.\n // We simulate the rendering pipeline: apply all defaults, then normalize with\n // onDotIntoNonObject: \"ignore\" (same as the actual renderer). Any key that gets\n // dropped during normalization (because a parent doesn't exist or isn't an object)\n // means it dots into nothing — the user's change would be silently lost.\n const withDefaults = applyDefaults(\n organizationConfigDefaults,\n applyDefaults(projectConfigDefaults, incompleteConfig),\n );\n const droppedKeys: string[] = [];\n const normalizedWithDefaults = normalize(withDefaults as Config, { onDotIntoNonObject: \"ignore\", droppedKeys });\n\n // Only report keys that were in the original incomplete config, not anything from defaults\n const incompleteConfigDotKeys = new Set(\n Object.keys(incompleteConfig).filter(k => k.includes('.') && incompleteConfig[k] !== undefined)\n );\n const relevantDroppedKeys = droppedKeys.filter(k => incompleteConfigDotKeys.has(k));\n\n if (relevantDroppedKeys.length > 0) {\n const messages = relevantDroppedKeys.map(key => {\n const segments = key.split('.');\n\n // Walk the normalized config to find the deepest existing parent\n let current: unknown = normalizedWithDefaults;\n let lastExistingIdx = -1;\n for (let i = 0; i < segments.length - 1; i++) {\n if (current != null && typeof current === 'object' && !Array.isArray(current) && segments[i] in (current as Record<string, unknown>)) {\n current = (current as Record<string, unknown>)[segments[i]];\n lastExistingIdx = i;\n } else {\n break;\n }\n }\n\n // The non-existent parent is one level deeper than the last existing segment\n const nonExistentParent = segments.slice(0, lastExistingIdx + 2).join('.');\n\n // Build a suggested nested object notation starting from the non-existent parent\n const remainingSegments = segments.slice(lastExistingIdx + 2);\n let suggestion = '...';\n for (let i = remainingSegments.length - 1; i >= 0; i--) {\n suggestion = `{ ${JSON.stringify(remainingSegments[i])}: ${suggestion} }`;\n }\n suggestion = `{ ${JSON.stringify(nonExistentParent)}: ${suggestion} }`;\n\n return `Dot-notation key ${JSON.stringify(key)} will be silently ignored because it references non-existent parent ${JSON.stringify(nonExistentParent)}. Instead of dot notation, use nested object notation like this: ${suggestion}`;\n });\n\n return Result.error(messages.join('\\n'));\n }\n\n let normalized: Config;\n try {\n normalized = normalize(incompleteConfig, { onDotIntoNull: \"empty-object\" });\n } catch (error) {\n if (error instanceof NormalizationError) {\n return Result.error(`Config is not normalizable. ` + error.message);\n }\n throw error;\n }\n\n // test the schema against the normalized config\n try {\n await schema.validate(normalized, {\n strict: true,\n context: {\n noUnknownPathPrefixes: [''],\n },\n });\n return Result.ok(null);\n } catch (error) {\n if (error instanceof yup.ValidationError) {\n return Result.error(error.message);\n }\n throw error;\n }\n}\nexport type ValidatedToHaveNoIncompleteConfigWarnings<T extends yup.AnySchema> = yup.InferType<T>;\n\n\n// Normalized overrides\n// ex.: { a?: { b?: number, c?: string }, d?: number }\nexport type ProjectConfigNormalizedOverride = Expand<ValidatedToHaveNoConfigOverrideErrors<typeof projectConfigSchema>>;\nexport type BranchConfigNormalizedOverride = Expand<ValidatedToHaveNoConfigOverrideErrors<typeof branchConfigSchema>>;\nexport type EnvironmentConfigNormalizedOverride = Expand<ValidatedToHaveNoConfigOverrideErrors<typeof environmentConfigSchema>>;\nexport type OrganizationConfigNormalizedOverride = Expand<ValidatedToHaveNoConfigOverrideErrors<typeof organizationConfigSchema>>;\n\n\n// Overrides\n// ex.: { a?: null | { b?: null | number, c: string }, d?: null | number, \"a.b\"?: number, \"a.c\"?: string }\nexport type ProjectConfigOverride = NormalizesTo<ProjectConfigNormalizedOverride>;\nexport type BranchConfigOverride = NormalizesTo<BranchConfigNormalizedOverride>;\nexport type EnvironmentConfigOverride = NormalizesTo<EnvironmentConfigNormalizedOverride>;\nexport type OrganizationConfigOverride = NormalizesTo<OrganizationConfigNormalizedOverride>;\n\n// Override overrides (used to update the overrides)\n// ex.: { a?: null | { b?: null | number, c?: string }, d?: null | number, \"a.b\"?: number, \"a.c\"?: string }\nexport type ProjectConfigOverrideOverride = ProjectConfigOverride;\nexport type BranchConfigOverrideOverride = BranchConfigOverride;\nexport type EnvironmentConfigOverrideOverride = EnvironmentConfigOverride;\nexport type OrganizationConfigOverrideOverride = OrganizationConfigOverride;\n\n// Incomplete configs\n// note that we infer these types from the override types, not from the schema types directly, as there is no guarantee\n// that all configs in the DB satisfy the schema (the only guarantee we make is that this once *used* to be true)\nexport type ProjectIncompleteConfig = Expand<ProjectConfigNormalizedOverride>;\nexport type BranchIncompleteConfig = Expand<ProjectIncompleteConfig & BranchConfigNormalizedOverride>;\nexport type EnvironmentIncompleteConfig = Expand<BranchIncompleteConfig & EnvironmentConfigNormalizedOverride>;\nexport type OrganizationIncompleteConfig = Expand<EnvironmentIncompleteConfig & OrganizationConfigNormalizedOverride>;\n\n\n// Rendered configs before defaults, normalization, and sanitization\ntype ProjectRenderedConfigBeforeDefaults = Omit<ProjectIncompleteConfig,\n | keyof BranchConfigNormalizedOverride\n | keyof EnvironmentConfigNormalizedOverride\n | keyof OrganizationConfigNormalizedOverride\n>;\ntype BranchRenderedConfigBeforeDefaults = Omit<BranchIncompleteConfig,\n | keyof EnvironmentConfigNormalizedOverride\n | keyof OrganizationConfigNormalizedOverride\n>;\ntype EnvironmentRenderedConfigBeforeDefaults = Omit<EnvironmentIncompleteConfig,\n | keyof OrganizationConfigNormalizedOverride\n>;\ntype OrganizationRenderedConfigBeforeDefaults = OrganizationIncompleteConfig;\n\n\n// Rendered configs before sanitization\ntype ProjectRenderedConfigBeforeSanitization = Expand<Awaited<ReturnType<typeof applyProjectDefaults<ProjectRenderedConfigBeforeDefaults>>>>;\ntype BranchRenderedConfigBeforeSanitization = Expand<Awaited<ReturnType<typeof applyBranchDefaults<BranchRenderedConfigBeforeDefaults>>>>;\ntype EnvironmentRenderedConfigBeforeSanitization = Expand<Awaited<ReturnType<typeof applyEnvironmentDefaults<EnvironmentRenderedConfigBeforeDefaults>>>>;\ntype OrganizationRenderedConfigBeforeSanitization = Expand<Awaited<ReturnType<typeof applyOrganizationDefaults>>>;\n\n// Rendered configs after defaults, normalization, and sanitization\nexport type ProjectRenderedConfig = Expand<Awaited<ReturnType<typeof sanitizeProjectConfig<ProjectRenderedConfigBeforeSanitization>>>>;\nexport type BranchRenderedConfig = Expand<Awaited<ReturnType<typeof sanitizeBranchConfig<BranchRenderedConfigBeforeSanitization>>>>;\nexport type EnvironmentRenderedConfig = Expand<Awaited<ReturnType<typeof sanitizeEnvironmentConfig<EnvironmentRenderedConfigBeforeSanitization>>>>;\nexport type OrganizationRenderedConfig = Expand<Awaited<ReturnType<typeof sanitizeOrganizationConfig>>>;\n\n// Complete config\nexport type CompleteConfig = OrganizationRenderedConfig;\n\n// Type assertions (just to make sure the types are correct)\nconst __assertEmptyObjectIsValidProjectOverride: ProjectConfigOverride = {};\nconst __assertEmptyObjectIsValidBranchOverride: BranchConfigOverride = {};\nconst __assertEmptyObjectIsValidEnvironmentOverride: EnvironmentConfigOverride = {};\nconst __assertEmptyObjectIsValidOrganizationOverride: OrganizationConfigOverride = {};\ntypeAssertExtends<ProjectRenderedConfig, { \"sourceOfTruth\": any }>()();\ntypeAssertExtends<BranchRenderedConfig, { \"sourceOfTruth\": any }>()();\ntypeAssertExtends<EnvironmentRenderedConfig, { \"sourceOfTruth\": any }>()();\ntypeAssertExtends<OrganizationRenderedConfig, { \"sourceOfTruth\": any }>()();\ntypeAssert<BranchRenderedConfig extends { \"domains\": any } ? false : true>()();\ntypeAssert<EnvironmentRenderedConfig extends { \"domains\": any } ? false : true>()();\ntypeAssertExtends<OrganizationRenderedConfig, { \"domains\": any }>()();\n"],"mappings":"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"}
|