Spaces:
Runtime error
Runtime error
| 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"; | |
| export const proxyConfigSchema = z | |
| .object({ | |
| type: z | |
| .preprocess( | |
| (value) => (typeof value === "string" ? value.trim().toLowerCase() : value), | |
| z.enum(["http", "https", "socks5"]) | |
| ) | |
| .optional(), | |
| host: z.string().trim().min(1).optional(), | |
| port: z.coerce.number().int().min(1).max(65535).optional(), | |
| username: z.string().optional(), | |
| password: z.string().optional(), | |
| }) | |
| .strict(); | |
| export const updateProxyConfigSchema = z | |
| .object({ | |
| proxy: proxyConfigSchema.nullable().optional(), | |
| global: proxyConfigSchema.nullable().optional(), | |
| providers: z.record(z.string().trim().min(1), proxyConfigSchema.nullable()).optional(), | |
| combos: z.record(z.string().trim().min(1), proxyConfigSchema.nullable()).optional(), | |
| keys: z.record(z.string().trim().min(1), proxyConfigSchema.nullable()).optional(), | |
| level: z.enum(["global", "provider", "combo", "key"]).optional(), | |
| id: z.string().optional(), | |
| }) | |
| .strict() | |
| .superRefine((value, ctx) => { | |
| const hasPayload = | |
| value.proxy !== undefined || | |
| value.global !== undefined || | |
| value.providers !== undefined || | |
| value.combos !== undefined || | |
| value.keys !== undefined || | |
| value.level !== undefined; | |
| if (!hasPayload) { | |
| ctx.addIssue({ | |
| code: z.ZodIssueCode.custom, | |
| message: "No valid fields to update", | |
| path: [], | |
| }); | |
| } | |
| if (value.level !== undefined && value.proxy === undefined) { | |
| ctx.addIssue({ | |
| code: z.ZodIssueCode.custom, | |
| message: "proxy is required when level is provided", | |
| path: ["proxy"], | |
| }); | |
| } | |
| if (value.level && value.level !== "global" && !value.id?.trim()) { | |
| ctx.addIssue({ | |
| code: z.ZodIssueCode.custom, | |
| message: "id is required for provider/combo/key level updates", | |
| path: ["id"], | |
| }); | |
| } | |
| }); | |
| export const testProxySchema = z.object({ | |
| proxy: z.object({ | |
| type: z.string().optional(), | |
| host: z.string().trim().min(1, "proxy.host is required"), | |
| port: z.union([z.string(), z.number()]), | |
| username: z.string().optional(), | |
| password: z.string().optional(), | |
| }), | |
| }); | |
| export const inlineProxyAssignmentSchema = z | |
| .object({ | |
| scope: z.enum(["global", "provider", "account", "combo", "key"]), | |
| scopeId: z.string().trim().nullable().optional(), | |
| }) | |
| .strict() | |
| .superRefine((value, ctx) => { | |
| if (value.scope !== "global" && !value.scopeId?.trim()) { | |
| ctx.addIssue({ | |
| code: z.ZodIssueCode.custom, | |
| message: "scopeId is required for non-global scope", | |
| path: ["scopeId"], | |
| }); | |
| } | |
| }); | |
| export const proxyRegistryFieldsSchema = z | |
| .object({ | |
| name: z.string().trim().min(1, "name is required").max(120), | |
| type: z | |
| .preprocess( | |
| (value) => (typeof value === "string" ? value.trim().toLowerCase() : value), | |
| z.enum(["http", "https", "socks5", "vercel", "deno", "cloudflare"]) | |
| ) | |
| .optional() | |
| .default("http"), | |
| host: z.string().trim().min(1, "host is required").max(255), | |
| port: z.coerce.number().int().min(1).max(65535), | |
| username: z.string().optional(), | |
| password: z.string().optional(), | |
| region: z.string().trim().max(64).nullable().optional(), | |
| notes: z.string().trim().max(1000).nullable().optional(), | |
| status: z.enum(["active", "inactive"]).optional().default("active"), | |
| source: z | |
| .enum([ | |
| "manual", | |
| "oneproxy", | |
| "dashboard-custom", | |
| "vercel-relay", | |
| "deno-relay", | |
| "cloudflare-relay", | |
| ]) | |
| .optional(), | |
| // Address-family egress policy (#3777): "auto" keeps the prior dual-stack behavior; | |
| // "ipv4"/"ipv6" pin the connection to that family (no v4 leak under an IPv6-only proxy). | |
| family: z.enum(["auto", "ipv4", "ipv6"]).optional().default("auto"), | |
| }) | |
| .strict(); | |
| export const createProxyRegistrySchema = proxyRegistryFieldsSchema | |
| .extend({ | |
| assignment: inlineProxyAssignmentSchema.optional(), | |
| }) | |
| .strict(); | |
| export const updateProxyRegistrySchema = proxyRegistryFieldsSchema | |
| .partial() | |
| .extend({ | |
| id: z.string().trim().min(1, "id is required"), | |
| assignment: inlineProxyAssignmentSchema.optional(), | |
| }) | |
| .strict(); | |
| export const bulkImportProxiesSchema = z | |
| .object({ | |
| items: z | |
| .array(proxyRegistryFieldsSchema) | |
| .min(1, "At least one proxy is required") | |
| .max(100, "Maximum 100 proxies per import"), | |
| }) | |
| .strict(); | |
| export const proxyAssignmentSchema = z | |
| .object({ | |
| scope: z.enum(["global", "provider", "account", "combo", "key"]), | |
| scopeId: z.string().trim().nullable().optional(), | |
| proxyId: z.string().trim().nullable().optional(), | |
| }) | |
| .strict() | |
| .superRefine((value, ctx) => { | |
| if (value.scope !== "global" && !value.scopeId?.trim()) { | |
| ctx.addIssue({ | |
| code: z.ZodIssueCode.custom, | |
| message: "scopeId is required for provider/account/combo/key scope", | |
| path: ["scopeId"], | |
| }); | |
| } | |
| }); | |
| export const bulkProxyAssignmentSchema = z | |
| .object({ | |
| scope: z.enum(["global", "provider", "account", "combo", "key"]), | |
| scopeIds: z.array(z.string().trim().min(1)).optional().default([]), | |
| proxyId: z.string().trim().nullable().optional(), | |
| }) | |
| .strict() | |
| .superRefine((value, ctx) => { | |
| if ( | |
| value.scope !== "global" && | |
| (!Array.isArray(value.scopeIds) || value.scopeIds.length === 0) | |
| ) { | |
| ctx.addIssue({ | |
| code: z.ZodIssueCode.custom, | |
| message: "scopeIds is required for provider/account/combo/key scope", | |
| path: ["scopeIds"], | |
| }); | |
| } | |
| }); |