Files
cfw-autumn/shared/api/billingControls/entityBillingControls.ts
2026-06-08 11:25:54 +01:00

85 lines
2.8 KiB
TypeScript

import { z } from "zod/v4";
import { DbSpendLimitSchema } from "../../models/cusModels/billingControls/spendLimit.js";
import { ApiOverageAllowedSchema } from "./overageAllowed.js";
import { ApiSpendLimitSchema } from "./spendLimit.js";
import { ApiUsageAlertSchema } from "./usageAlert.js";
export const ApiEntityBillingControlsSchema = z.object({
spend_limits: z.array(ApiSpendLimitSchema).optional().meta({
description:
"List of spend limits per feature. Each entry caps overage (overage_limit) and/or windowed usage (usage_limit).",
}),
usage_alerts: z.array(ApiUsageAlertSchema).optional().meta({
description: "List of usage alert configurations per feature.",
}),
overage_allowed: z.array(ApiOverageAllowedSchema).optional().meta({
description:
"List of overage allowed controls per feature. When enabled, usage can exceed balance.",
}),
});
const ApiEntityBillingControlsParamsBaseSchema = z.object({
spend_limits: z.array(DbSpendLimitSchema).optional().meta({
description:
"List of spend limits per feature. Each entry caps overage (overage_limit) and/or windowed usage (usage_limit).",
}),
usage_alerts: z.array(ApiUsageAlertSchema).optional().meta({
description: "List of usage alert configurations per feature.",
}),
overage_allowed: z.array(ApiOverageAllowedSchema).optional().meta({
description:
"List of overage allowed controls per feature. When enabled, usage can exceed balance.",
}),
});
export const ApiEntityBillingControlsParamsSchema =
ApiEntityBillingControlsParamsBaseSchema.check((ctx) => {
const billingControls = ctx.value;
const spendLimitFeatureIds = new Set<string>();
for (const [index, spendLimit] of (
billingControls.spend_limits ?? []
).entries()) {
if (!spendLimit.feature_id) {
continue;
}
if (spendLimitFeatureIds.has(spendLimit.feature_id)) {
ctx.issues.push({
code: "custom",
message: "Only one spend limit entry is allowed per feature_id",
input: spendLimit.feature_id,
path: ["spend_limits", index, "feature_id"],
});
return;
}
spendLimitFeatureIds.add(spendLimit.feature_id);
}
const overageAllowedFeatureIds = new Set<string>();
for (const [index, overageAllowed] of (
billingControls.overage_allowed ?? []
).entries()) {
if (overageAllowedFeatureIds.has(overageAllowed.feature_id)) {
ctx.issues.push({
code: "custom",
message: "Only one overage_allowed entry is allowed per feature_id",
input: overageAllowed.feature_id,
path: ["overage_allowed", index, "feature_id"],
});
return;
}
overageAllowedFeatureIds.add(overageAllowed.feature_id);
}
});
export type ApiEntityBillingControls = z.infer<
typeof ApiEntityBillingControlsSchema
>;
export type ApiEntityBillingControlsParams = z.input<
typeof ApiEntityBillingControlsParamsSchema
>;