Spaces:
Runtime error
Runtime error
File size: 5,939 Bytes
cd8bd0a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | import { z } from "zod";
import {
ACCOUNT_FALLBACK_STRATEGY_VALUES,
ROUTING_STRATEGY_VALUES,
} from "@/shared/constants/routingStrategies";
import { SUPPORTED_BATCH_ENDPOINTS } from "@/shared/constants/batchEndpoints";
import { MAX_REQUEST_BODY_LIMIT_MB, MIN_REQUEST_BODY_LIMIT_MB } from "@/shared/constants/bodySize";
import { COMBO_CONFIG_MODES } from "@/shared/constants/comboConfigMode";
import { providerAllowsOptionalApiKey } from "@/shared/constants/providers";
import { HIDEABLE_SIDEBAR_ITEM_IDS } from "@/shared/constants/sidebarVisibility";
import {
isForbiddenUpstreamHeaderName,
isForbiddenCustomHeaderName,
} from "@/shared/constants/upstreamHeaders";
import { MAX_TIMER_TIMEOUT_MS } from "@/shared/utils/runtimeTimeouts";
import { accessScheduleSchema } from "./misc.ts";
// ββββ API Key Schemas ββββ
export const createKeySchema = z.object({
name: z.string().min(1, "Name is required").max(200),
noLog: z.boolean().optional(),
allowUsageCommand: z.boolean().optional(),
usageLimitEnabled: z.boolean().optional(),
dailyUsageLimitUsd: z.coerce.number().min(0).optional().nullable(),
weeklyUsageLimitUsd: z.coerce.number().min(0).optional().nullable(),
scopes: z.array(z.string().trim().min(1).max(64)).max(32).optional(),
});
export const createSyncTokenSchema = z.object({
name: z.string().trim().min(1, "Name is required").max(200),
});
export const setBudgetSchema = z.object({
apiKeyId: z.string().trim().min(1, "apiKeyId is required"),
// #3537: a limit of 0 means "no limit for this period" (checkBudget only enforces when
// activeLimitUsd > 0). The dashboard sends 0 for unfilled fields, so 0 must be accepted β
// `.positive()` (rejects 0) used to 400 any save that left a field blank. Negatives are
// still rejected by `.min(0)`.
dailyLimitUsd: z.coerce.number().min(0, "dailyLimitUsd must be zero or greater").optional(),
weeklyLimitUsd: z.coerce.number().min(0, "weeklyLimitUsd must be zero or greater").optional(),
monthlyLimitUsd: z.coerce.number().min(0, "monthlyLimitUsd must be zero or greater").optional(),
warningThreshold: z.coerce.number().min(0).max(1).optional(),
resetInterval: z.enum(["daily", "weekly", "monthly"]).optional(),
resetTime: z
.string()
.trim()
.regex(/^\d{2}:\d{2}$/, "resetTime must be in HH:MM format")
.optional(),
});
export const setTokenLimitSchema = z
.object({
id: z.string().trim().min(1).optional(),
apiKeyId: z.string().trim().min(1, "apiKeyId is required"),
scopeType: z.enum(["model", "provider", "global"]),
scopeValue: z.string().trim().default(""),
tokenLimit: z.coerce
.number()
.int("tokenLimit must be an integer")
.positive("tokenLimit must be greater than zero"),
resetInterval: z.enum(["daily", "weekly", "monthly"]).default("monthly"),
resetTime: z
.string()
.trim()
.regex(/^\d{2}:\d{2}$/, "resetTime must be in HH:MM format")
.optional(),
enabled: z.boolean().default(true),
})
.superRefine((value, ctx) => {
if (value.scopeType !== "global" && (!value.scopeValue || value.scopeValue.length === 0)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "scopeValue is required unless scopeType is 'global'",
path: ["scopeValue"],
});
}
});
export const updateKeyPermissionsSchema = z
.object({
name: z.string().trim().min(1).max(200).optional(),
allowedModels: z.array(z.string().trim().min(1)).max(1000).optional(),
allowedCombos: z.array(z.string().trim().min(1).max(200)).max(500).optional(),
allowedConnections: z.array(z.string().uuid()).max(100).optional(),
noLog: z.boolean().optional(),
autoResolve: z.boolean().optional(),
isActive: z.boolean().optional(),
throttleDelayMs: z.number().int().min(0).max(300000).optional(),
isBanned: z.boolean().optional(),
expiresAt: z.string().datetime().nullable().optional(),
maxSessions: z.number().int().min(0).max(10000).optional(),
accessSchedule: z.union([accessScheduleSchema, z.null()]).optional(),
rateLimits: z
.union([
z
.array(
z.object({ limit: z.number().int().positive(), window: z.number().int().positive() })
)
.max(50),
z.null(),
])
.optional(),
scopes: z.array(z.string().trim().min(1).max(64)).max(32).optional(),
allowedEndpoints: z.array(z.string().trim().min(1).max(64)).max(20).optional(),
streamDefaultMode: z.enum(["legacy", "json"]).optional(),
disableNonPublicModels: z.boolean().optional(),
allowUsageCommand: z.boolean().optional(),
usageLimitEnabled: z.boolean().optional(),
dailyUsageLimitUsd: z.coerce.number().min(0).optional().nullable(),
weeklyUsageLimitUsd: z.coerce.number().min(0).optional().nullable(),
})
.superRefine((value, ctx) => {
if (
value.name === undefined &&
value.allowedModels === undefined &&
value.allowedCombos === undefined &&
value.allowedConnections === undefined &&
value.noLog === undefined &&
value.autoResolve === undefined &&
value.isActive === undefined &&
value.throttleDelayMs === undefined &&
value.isBanned === undefined &&
value.expiresAt === undefined &&
value.maxSessions === undefined &&
value.accessSchedule === undefined &&
value.rateLimits === undefined &&
value.scopes === undefined &&
value.allowedEndpoints === undefined &&
value.streamDefaultMode === undefined &&
value.disableNonPublicModels === undefined &&
value.allowUsageCommand === undefined &&
value.usageLimitEnabled === undefined &&
value.dailyUsageLimitUsd === undefined &&
value.weeklyUsageLimitUsd === undefined
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "No valid fields to update",
path: [],
});
}
});
|