fix: extract validation helpers to fix webpack barrel-file resolution bug

Extracted validateBody, isValidationFailure, and loginSchema from the
935-line schemas.ts barrel file into a dedicated helpers.ts module.
Updated 70 API route files to import directly from helpers.ts.

Root cause: webpack on certain environments fails to resolve exports
from the bottom of large barrel files (schemas.ts), causing
'(0, O.Jb) is not a function' errors in production builds.

Fix: Split validation helpers into a small dedicated module (helpers.ts)
so webpack can correctly resolve all exports regardless of file size.

- TypeScript compiles with 0 errors
- All API routes updated to import from helpers.ts
- schemas.ts re-exports from helpers.ts for backward compatibility
This commit is contained in:
diegosouzapw
2026-03-05 08:05:58 -03:00
parent 5a53c17e81
commit 751ff77b7c
72 changed files with 201 additions and 326 deletions

View File

@@ -3,7 +3,7 @@ import { getSettings } from "@/lib/localDb";
import bcrypt from "bcryptjs";
import { SignJWT } from "jose";
import { cookies } from "next/headers";
import { isValidationFailure, loginSchema, validateBody } from "@/shared/validation/schemas";
import { loginSchema, isValidationFailure, validateBody } from "@/shared/validation/helpers";
// SECURITY: No hardcoded fallback — JWT_SECRET must be configured.
if (!process.env.JWT_SECRET) {

View File

@@ -2,11 +2,8 @@
import { NextResponse } from "next/server";
import { getMitmAlias, setMitmAliasAll } from "@/models";
import {
cliMitmAliasUpdateSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { cliMitmAliasUpdateSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// GET - Get MITM aliases for a tool
export async function GET(request) {

View File

@@ -8,12 +8,8 @@ import {
getCachedPassword,
setCachedPassword,
} from "@/mitm/manager";
import {
cliMitmStartSchema,
cliMitmStopSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { cliMitmStartSchema, cliMitmStopSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// GET - Check MITM status
export async function GET() {

View File

@@ -3,11 +3,8 @@
import { NextResponse } from "next/server";
import { listBackups, restoreBackup, deleteBackup } from "@/shared/services/backupService";
import { ensureCliConfigWriteAllowed } from "@/shared/services/cliRuntime";
import {
cliBackupMutationSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { cliBackupMutationSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
const VALID_TOOLS = ["claude", "codex", "droid", "openclaw", "cline", "kilo"];

View File

@@ -10,11 +10,8 @@ import {
} from "@/shared/services/cliRuntime";
import { createBackup } from "@/shared/services/backupService";
import { saveCliToolLastConfigured, deleteCliToolLastConfigured } from "@/lib/db/cliToolState";
import {
cliSettingsEnvSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { cliSettingsEnvSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// Get claude settings path based on OS
const getClaudeSettingsPath = () => getCliPrimaryConfigPath("claude");

View File

@@ -7,11 +7,8 @@ import os from "os";
import { ensureCliConfigWriteAllowed, getCliRuntimeStatus } from "@/shared/services/cliRuntime";
import { createBackup } from "@/shared/services/backupService";
import { saveCliToolLastConfigured, deleteCliToolLastConfigured } from "@/lib/db/cliToolState";
import {
cliModelConfigSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { cliModelConfigSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
const CLINE_DATA_DIR = path.join(os.homedir(), ".cline", "data");
const GLOBAL_STATE_PATH = path.join(CLINE_DATA_DIR, "globalState.json");

View File

@@ -5,12 +5,8 @@ import fs from "fs/promises";
import path from "path";
import { ensureCliConfigWriteAllowed, getCliConfigPaths } from "@/shared/services/cliRuntime";
import { resolveDataDir } from "@/lib/dataPaths";
import {
codexProfileIdSchema,
codexProfileNameSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { codexProfileIdSchema, codexProfileNameSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
const PROFILES_DIR = path.join(resolveDataDir(), "codex-profiles");

View File

@@ -10,11 +10,8 @@ import {
} from "@/shared/services/cliRuntime";
import { createMultiBackup } from "@/shared/services/backupService";
import { saveCliToolLastConfigured, deleteCliToolLastConfigured } from "@/lib/db/cliToolState";
import {
cliModelConfigSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { cliModelConfigSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
const getCodexConfigPath = () => getCliConfigPaths("codex").config;
const getCodexAuthPath = () => getCliConfigPaths("codex").auth;

View File

@@ -10,11 +10,8 @@ import {
} from "@/shared/services/cliRuntime";
import { createBackup } from "@/shared/services/backupService";
import { saveCliToolLastConfigured, deleteCliToolLastConfigured } from "@/lib/db/cliToolState";
import {
cliModelConfigSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { cliModelConfigSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
const getDroidSettingsPath = () => getCliPrimaryConfigPath("droid");
const getDroidDir = () => path.dirname(getDroidSettingsPath());

View File

@@ -3,11 +3,8 @@ import fs from "fs/promises";
import path from "path";
import os from "os";
import { getRuntimePorts } from "@/lib/runtime/ports";
import {
guideSettingsSaveSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { guideSettingsSaveSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* POST /api/cli-tools/guide-settings/:toolId

View File

@@ -7,11 +7,8 @@ import os from "os";
import { ensureCliConfigWriteAllowed, getCliRuntimeStatus } from "@/shared/services/cliRuntime";
import { createBackup } from "@/shared/services/backupService";
import { saveCliToolLastConfigured, deleteCliToolLastConfigured } from "@/lib/db/cliToolState";
import {
cliModelConfigSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { cliModelConfigSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
const KILO_DATA_DIR = path.join(os.homedir(), ".local", "share", "kilo");
const AUTH_PATH = path.join(KILO_DATA_DIR, "auth.json");

View File

@@ -10,11 +10,8 @@ import {
} from "@/shared/services/cliRuntime";
import { createBackup } from "@/shared/services/backupService";
import { saveCliToolLastConfigured, deleteCliToolLastConfigured } from "@/lib/db/cliToolState";
import {
cliModelConfigSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { cliModelConfigSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
const getOpenClawSettingsPath = () => getCliPrimaryConfigPath("openclaw");
const getOpenClawDir = () => path.dirname(getOpenClawSettingsPath());

View File

@@ -1,6 +1,7 @@
import { NextResponse } from "next/server";
import { validateApiKey, getProviderConnections, updateProviderConnection } from "@/models";
import { cloudCredentialUpdateSchema, isValidationFailure, validateBody } from "@/shared/validation/schemas";
import { cloudCredentialUpdateSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// Update provider credentials (for cloud token refresh)
export async function PUT(request: Request) {

View File

@@ -1,6 +1,7 @@
import { NextResponse } from "next/server";
import { validateApiKey, getModelAliases } from "@/models";
import { cloudResolveAliasSchema, isValidationFailure, validateBody } from "@/shared/validation/schemas";
import { cloudResolveAliasSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// Resolve model alias to provider/model
export async function POST(request: Request) {

View File

@@ -2,7 +2,8 @@ import { NextResponse } from "next/server";
import { validateApiKey, getModelAliases, setModelAlias, isCloudEnabled } from "@/models";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { cloudModelAliasUpdateSchema, isValidationFailure, validateBody } from "@/shared/validation/schemas";
import { cloudModelAliasUpdateSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// PUT /api/cloud/models/alias - Set model alias (for cloud/CLI)
export async function PUT(request: Request) {

View File

@@ -10,7 +10,8 @@ import {
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { validateComboDAG } from "@omniroute/open-sse/services/combo.ts";
import { isValidationFailure, updateComboSchema, validateBody } from "@/shared/validation/schemas";
import { updateComboSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// GET /api/combos/[id] - Get combo by ID
export async function GET(request, { params }) {

View File

@@ -3,7 +3,8 @@ import { getCombos, createCombo, getComboByName, isCloudEnabled } from "@/lib/lo
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { validateComboDAG } from "@omniroute/open-sse/services/combo.ts";
import { createComboSchema, isValidationFailure, validateBody } from "@/shared/validation/schemas";
import { createComboSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// GET /api/combos - Get all combos
export async function GET() {

View File

@@ -1,6 +1,7 @@
import { NextResponse } from "next/server";
import { getComboByName } from "@/lib/localDb";
import { isValidationFailure, testComboSchema, validateBody } from "@/shared/validation/schemas";
import { testComboSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* POST /api/combos/test - Quick test a combo

View File

@@ -1,10 +1,7 @@
import { NextResponse } from "next/server";
import { listDbBackups, restoreDbBackup, backupDbFile } from "@/lib/localDb";
import {
dbBackupRestoreSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { dbBackupRestoreSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* PUT /api/db-backups — Trigger a manual backup snapshot.

View File

@@ -1,6 +1,7 @@
import { NextResponse } from "next/server";
import { listSuites, runSuite } from "@/lib/evals/evalRunner";
import { evalRunSuiteSchema, isValidationFailure, validateBody } from "@/shared/validation/schemas";
import { evalRunSuiteSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
export async function GET() {
try {

View File

@@ -1,11 +1,7 @@
import { NextResponse } from "next/server";
import { getAllFallbackChains, registerFallback, removeFallback } from "@/domain/fallbackPolicy";
import {
isValidationFailure,
registerFallbackSchema,
removeFallbackSchema,
validateBody,
} from "@/shared/validation/schemas";
import { registerFallbackSchema, removeFallbackSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
export async function GET() {
try {

View File

@@ -7,11 +7,8 @@ import {
} from "@/lib/localDb";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import {
isValidationFailure,
updateKeyPermissionsSchema,
validateBody,
} from "@/shared/validation/schemas";
import { updateKeyPermissionsSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// GET /api/keys/[id] - Get single API key
export async function GET(request, { params }) {

View File

@@ -2,7 +2,8 @@ import { NextResponse } from "next/server";
import { getApiKeys, createApiKey, isCloudEnabled } from "@/lib/localDb";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { createKeySchema, isValidationFailure, validateBody } from "@/shared/validation/schemas";
import { createKeySchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// GET /api/keys - List API keys
export async function GET() {

View File

@@ -3,11 +3,8 @@ import { getModelAliases, setModelAlias, deleteModelAlias, isCloudEnabled } from
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { isAuthenticated } from "@/shared/utils/apiAuth";
import {
cloudModelAliasUpdateSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { cloudModelAliasUpdateSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// GET /api/models/alias - Get all aliases
export async function GET(request) {

View File

@@ -4,11 +4,8 @@ import {
clearModelUnavailability,
getUnavailableCount,
} from "@/domain/modelAvailability";
import {
clearModelAvailabilitySchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { clearModelAvailabilitySchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
export async function GET() {
try {

View File

@@ -1,11 +1,8 @@
import { NextResponse } from "next/server";
import { getModelAliases, setModelAlias, getProviderConnections } from "@/models";
import { AI_MODELS } from "@/shared/constants/config";
import {
isValidationFailure,
updateModelAliasSchema,
validateBody,
} from "@/shared/validation/schemas";
import { updateModelAliasSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// GET /api/models - Get models with aliases (only from active providers by default)
export async function GET(request: Request) {

View File

@@ -18,12 +18,11 @@ import { startLocalServer } from "@/lib/oauth/utils/server";
import { getProxyConfig } from "@/lib/localDb";
import { runWithProxyContext } from "@omniroute/open-sse/utils/proxyFetch.ts";
import {
isValidationFailure,
jsonObjectSchema,
oauthExchangeSchema,
oauthPollSchema,
validateBody,
} from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// Use globalThis to persist callback server state across Next.js HMR reloads
if (!globalThis.__codexCallbackState) {

View File

@@ -3,7 +3,8 @@ import { CursorService } from "@/lib/oauth/services/cursor";
import { createProviderConnection, isCloudEnabled } from "@/models";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { cursorImportSchema, isValidationFailure, validateBody } from "@/shared/validation/schemas";
import { cursorImportSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* POST /api/oauth/cursor/import

View File

@@ -3,7 +3,8 @@ import { KiroService } from "@/lib/oauth/services/kiro";
import { createProviderConnection, isCloudEnabled } from "@/models";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { isValidationFailure, kiroImportSchema, validateBody } from "@/shared/validation/schemas";
import { kiroImportSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* POST /api/oauth/kiro/import

View File

@@ -3,11 +3,8 @@ import { KiroService } from "@/lib/oauth/services/kiro";
import { createProviderConnection, isCloudEnabled } from "@/models";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import {
isValidationFailure,
kiroSocialExchangeSchema,
validateBody,
} from "@/shared/validation/schemas";
import { kiroSocialExchangeSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* POST /api/oauth/kiro/social-exchange

View File

@@ -1,7 +1,8 @@
import { NextResponse } from "next/server";
import { getAllCircuitBreakerStatuses } from "@/shared/utils/circuitBreaker";
import { getLockedIdentifiers, forceUnlock } from "@/domain/lockoutPolicy";
import { isValidationFailure, policyActionSchema, validateBody } from "@/shared/validation/schemas";
import { policyActionSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
export async function GET() {
try {

View File

@@ -1,10 +1,7 @@
import { NextResponse } from "next/server";
import { getPricing, updatePricing, resetPricing, resetAllPricing } from "@/lib/localDb";
import {
isValidationFailure,
updatePricingSchema,
validateBody,
} from "@/shared/validation/schemas";
import { updatePricingSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* GET /api/pricing

View File

@@ -5,11 +5,8 @@ import {
removeCustomModel,
} from "@/lib/localDb";
import { isAuthenticated } from "@/shared/utils/apiAuth";
import {
isValidationFailure,
providerModelMutationSchema,
validateBody,
} from "@/shared/validation/schemas";
import { providerModelMutationSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* GET /api/provider-models?provider=<id>

View File

@@ -7,11 +7,8 @@ import {
updateProviderConnection,
updateProviderNode,
} from "@/models";
import {
isValidationFailure,
updateProviderNodeSchema,
validateBody,
} from "@/shared/validation/schemas";
import { updateProviderNodeSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
type JsonRecord = Record<string, unknown>;

View File

@@ -5,11 +5,8 @@ import {
ANTHROPIC_COMPATIBLE_PREFIX,
} from "@/shared/constants/providers";
import { generateId } from "@/shared/utils";
import {
createProviderNodeSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { createProviderNodeSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
const OPENAI_COMPATIBLE_DEFAULTS = {
baseUrl: "https://api.openai.com/v1",

View File

@@ -1,9 +1,6 @@
import { NextResponse } from "next/server";
import {
isValidationFailure,
providerNodeValidateSchema,
validateBody,
} from "@/shared/validation/schemas";
import { providerNodeValidateSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// POST /api/provider-nodes/validate - Validate API key against base URL
export async function POST(request) {

View File

@@ -7,11 +7,8 @@ import {
} from "@/models";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import {
isValidationFailure,
updateProviderConnectionSchema,
validateBody,
} from "@/shared/validation/schemas";
import { updateProviderConnectionSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// GET /api/providers/[id] - Get single connection
export async function GET(request: Request, { params }: { params: Promise<{ id: string }> }) {

View File

@@ -12,11 +12,8 @@ import {
} from "@/shared/constants/providers";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import {
createProviderSchema,
isValidationFailure,
validateBody,
} from "@/shared/validation/schemas";
import { createProviderSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// GET /api/providers - List all connections
export async function GET() {

View File

@@ -8,11 +8,8 @@ import {
ANTHROPIC_COMPATIBLE_PREFIX,
} from "@/shared/constants/providers";
import { testSingleConnection } from "../[id]/test/route";
import {
isValidationFailure,
providersBatchTestSchema,
validateBody,
} from "@/shared/validation/schemas";
import { providersBatchTestSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// Determine auth type group for a provider id
function getAuthGroup(providerId) {

View File

@@ -5,11 +5,8 @@ import {
isAnthropicCompatibleProvider,
} from "@/shared/constants/providers";
import { validateProviderApiKey } from "@/lib/providers/validation";
import {
isValidationFailure,
validateBody,
validateProviderApiKeySchema,
} from "@/shared/validation/schemas";
import { validateProviderApiKeySchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
// POST /api/providers/validate - Validate API key with provider
export async function POST(request) {

View File

@@ -8,11 +8,8 @@ import {
getRateLimitStatus,
getAllRateLimitStatus,
} from "@omniroute/open-sse/services/rateLimitManager.ts";
import {
isValidationFailure,
toggleRateLimitSchema,
validateBody,
} from "@/shared/validation/schemas";
import { toggleRateLimitSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
type JsonRecord = Record<string, unknown>;

View File

@@ -1,10 +1,7 @@
import { NextResponse } from "next/server";
import { getSettings, updateSettings } from "@/lib/localDb";
import {
isValidationFailure,
updateResilienceSchema,
validateBody,
} from "@/shared/validation/schemas";
import { updateResilienceSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
type JsonRecord = Record<string, unknown>;

View File

@@ -5,12 +5,8 @@ import {
resetStats,
} from "@omniroute/open-sse/services/backgroundTaskDetector.ts";
import { updateSettings } from "@/lib/db/settings";
import {
isValidationFailure,
jsonObjectSchema,
resetStatsActionSchema,
validateBody,
} from "@/shared/validation/schemas";
import { jsonObjectSchema, resetStatsActionSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* GET /api/settings/background-degradation

View File

@@ -1,10 +1,7 @@
import { NextResponse } from "next/server";
import { getSettings, updateSettings } from "@/lib/localDb";
import {
isValidationFailure,
updateComboDefaultsSchema,
validateBody,
} from "@/shared/validation/schemas";
import { updateComboDefaultsSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* GET /api/settings/combo-defaults

View File

@@ -9,11 +9,8 @@ import {
tempBanIP,
removeTempBan,
} from "@omniroute/open-sse/services/ipFilter.ts";
import {
isValidationFailure,
updateIpFilterSchema,
validateBody,
} from "@/shared/validation/schemas";
import { updateIpFilterSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
export async function GET() {
try {

View File

@@ -10,11 +10,10 @@ import {
import { getSettings, updateSettings } from "@/lib/db/settings";
import {
addModelAliasSchema,
isValidationFailure,
removeModelAliasSchema,
updateModelAliasesSchema,
validateBody,
} from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* GET /api/settings/model-aliases

View File

@@ -6,11 +6,8 @@ import {
resolveProxyForConnection,
} from "../../../../lib/localDb";
import { clearDispatcherCache } from "@omniroute/open-sse/utils/proxyDispatcher";
import {
isValidationFailure,
updateProxyConfigSchema,
validateBody,
} from "@/shared/validation/schemas";
import { updateProxyConfigSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import type { z } from "zod";
const BASE_SUPPORTED_PROXY_TYPES = new Set(["http", "https"]);

View File

@@ -5,7 +5,8 @@ import {
proxyConfigToUrl,
proxyUrlForLogs,
} from "@omniroute/open-sse/utils/proxyDispatcher.ts";
import { isValidationFailure, testProxySchema, validateBody } from "@/shared/validation/schemas";
import { testProxySchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
const BASE_SUPPORTED_PROXY_TYPES = new Set(["http", "https"]);

View File

@@ -1,11 +1,8 @@
import { NextResponse } from "next/server";
import { getSettings, updateSettings } from "@/lib/localDb";
import bcrypt from "bcryptjs";
import {
isValidationFailure,
updateRequireLoginSchema,
validateBody,
} from "@/shared/validation/schemas";
import { updateRequireLoginSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
export async function GET() {
try {

View File

@@ -3,11 +3,8 @@ import { getSettings, updateSettings } from "@/lib/localDb";
import { clearHealthCheckLogCache } from "@/lib/tokenHealthCheck";
import bcrypt from "bcryptjs";
import { getRuntimePorts } from "@/lib/runtime/ports";
import {
isValidationFailure,
updateSettingsSchema,
validateBody,
} from "@/shared/validation/schemas";
import { updateSettingsSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
export async function GET() {
try {

View File

@@ -4,11 +4,8 @@ import {
getSystemPromptConfig,
} from "@omniroute/open-sse/services/systemPrompt.ts";
import { updateSettings } from "@/lib/localDb";
import {
isValidationFailure,
updateSystemPromptSchema,
validateBody,
} from "@/shared/validation/schemas";
import { updateSystemPromptSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
export async function GET() {
try {

View File

@@ -5,11 +5,8 @@ import {
getThinkingBudgetConfig,
ThinkingMode,
} from "@omniroute/open-sse/services/thinkingBudget.ts";
import {
isValidationFailure,
updateThinkingBudgetSchema,
validateBody,
} from "@/shared/validation/schemas";
import { updateThinkingBudgetSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
export async function GET() {
try {

View File

@@ -5,7 +5,8 @@ import { syncToCloud, fetchWithTimeout, CLOUD_URL } from "@/lib/cloudSync";
import fs from "fs/promises";
import path from "path";
import os from "os";
import { cloudSyncActionSchema, isValidationFailure, validateBody } from "@/shared/validation/schemas";
import { cloudSyncActionSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* GET /api/sync/cloud

View File

@@ -1,10 +1,7 @@
import { NextResponse } from "next/server";
import { detectFormat } from "@omniroute/open-sse/services/provider.ts";
import {
isValidationFailure,
translatorDetectSchema,
validateBody,
} from "@/shared/validation/schemas";
import { translatorDetectSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* POST /api/translator/detect

View File

@@ -1,11 +1,8 @@
import { NextResponse } from "next/server";
import fs from "fs";
import path from "path";
import {
isValidationFailure,
translatorSaveSchema,
validateBody,
} from "@/shared/validation/schemas";
import { translatorSaveSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
export async function POST(request) {
let rawBody;

View File

@@ -8,11 +8,8 @@ import {
import { getProviderConnections } from "@/lib/localDb";
import { toJsonErrorPayload } from "@/shared/utils/upstreamError";
import { logTranslationEvent } from "@/lib/translatorEvents";
import {
isValidationFailure,
translatorSendSchema,
validateBody,
} from "@/shared/validation/schemas";
import { translatorSendSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
function getProviderBaseUrl(providerSpecificData: unknown): string | undefined {
if (!providerSpecificData || typeof providerSpecificData !== "object") return undefined;

View File

@@ -8,11 +8,8 @@ import {
import { translateRequest } from "@omniroute/open-sse/translator/index.ts";
import { FORMATS } from "@omniroute/open-sse/translator/formats.ts";
import { getProviderConnections } from "@/lib/localDb";
import {
isValidationFailure,
translatorTranslateSchema,
validateBody,
} from "@/shared/validation/schemas";
import { translatorTranslateSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
type JsonRecord = Record<string, unknown>;

View File

@@ -1,6 +1,7 @@
import { NextResponse } from "next/server";
import { getCostSummary, setBudget, checkBudget } from "@/domain/costRules";
import { isValidationFailure, setBudgetSchema, validateBody } from "@/shared/validation/schemas";
import { setBudgetSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
export async function GET(request) {
try {

View File

@@ -5,11 +5,8 @@ import { parseSpeechModel, getSpeechProvider } from "@omniroute/open-sse/config/
import { errorResponse } from "@omniroute/open-sse/utils/error.ts";
import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
import { enforceApiKeyPolicy } from "@/shared/utils/apiKeyPolicy";
import {
isValidationFailure,
v1AudioSpeechSchema,
validateBody,
} from "@/shared/validation/schemas";
import { v1AudioSpeechSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* Handle CORS preflight

View File

@@ -10,7 +10,8 @@ import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
import * as log from "@/sse/utils/logger";
import { toJsonErrorPayload } from "@/shared/utils/upstreamError";
import { enforceApiKeyPolicy } from "@/shared/utils/apiKeyPolicy";
import { isValidationFailure, v1EmbeddingsSchema, validateBody } from "@/shared/validation/schemas";
import { v1EmbeddingsSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* Handle CORS preflight

View File

@@ -11,11 +11,8 @@ import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
import * as log from "@/sse/utils/logger";
import { toJsonErrorPayload } from "@/shared/utils/upstreamError";
import { enforceApiKeyPolicy } from "@/shared/utils/apiKeyPolicy";
import {
isValidationFailure,
v1ImageGenerationSchema,
validateBody,
} from "@/shared/validation/schemas";
import { v1ImageGenerationSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* Handle CORS preflight

View File

@@ -1,9 +1,6 @@
import { CORS_HEADERS } from "@/shared/utils/cors";
import {
isValidationFailure,
v1CountTokensSchema,
validateBody,
} from "@/shared/validation/schemas";
import { v1CountTokensSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* Handle CORS preflight

View File

@@ -5,7 +5,8 @@ import { parseModerationModel } from "@omniroute/open-sse/config/moderationRegis
import { errorResponse } from "@omniroute/open-sse/utils/error.ts";
import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
import { enforceApiKeyPolicy } from "@/shared/utils/apiKeyPolicy";
import { isValidationFailure, v1ModerationSchema, validateBody } from "@/shared/validation/schemas";
import { v1ModerationSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* Handle CORS preflight

View File

@@ -11,11 +11,8 @@ import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
import * as log from "@/sse/utils/logger";
import { toJsonErrorPayload } from "@/shared/utils/upstreamError";
import { enforceApiKeyPolicy } from "@/shared/utils/apiKeyPolicy";
import {
isValidationFailure,
v1ImageGenerationSchema,
validateBody,
} from "@/shared/validation/schemas";
import { v1ImageGenerationSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* Handle CORS preflight

View File

@@ -4,11 +4,8 @@ import { initTranslators } from "@omniroute/open-sse/translator/index.ts";
import { errorResponse } from "@omniroute/open-sse/utils/error.ts";
import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
import { getRegistryEntry } from "@omniroute/open-sse/config/providerRegistry.ts";
import {
isValidationFailure,
providerChatCompletionSchema,
validateBody,
} from "@/shared/validation/schemas";
import { providerChatCompletionSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
let initialized = false;

View File

@@ -6,7 +6,8 @@ import { getProviderCredentials, extractApiKey, isValidApiKey } from "@/sse/serv
import { handleEmbedding } from "@omniroute/open-sse/handlers/embeddings.ts";
import * as log from "@/sse/utils/logger";
import { enforceApiKeyPolicy } from "@/shared/utils/apiKeyPolicy";
import { isValidationFailure, v1EmbeddingsSchema, validateBody } from "@/shared/validation/schemas";
import { v1EmbeddingsSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* Handle CORS preflight

View File

@@ -7,11 +7,8 @@ import { getImageProvider } from "@omniroute/open-sse/config/imageRegistry.ts";
import * as log from "@/sse/utils/logger";
import { toJsonErrorPayload } from "@/shared/utils/upstreamError";
import { enforceApiKeyPolicy } from "@/shared/utils/apiKeyPolicy";
import {
isValidationFailure,
v1ImageGenerationSchema,
validateBody,
} from "@/shared/validation/schemas";
import { v1ImageGenerationSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* Handle CORS preflight

View File

@@ -5,7 +5,8 @@ import { parseRerankModel } from "@omniroute/open-sse/config/rerankRegistry.ts";
import { errorResponse } from "@omniroute/open-sse/utils/error.ts";
import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
import { enforceApiKeyPolicy } from "@/shared/utils/apiKeyPolicy";
import { isValidationFailure, v1RerankSchema, validateBody } from "@/shared/validation/schemas";
import { v1RerankSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* Handle CORS preflight

View File

@@ -11,11 +11,8 @@ import { HTTP_STATUS } from "@omniroute/open-sse/config/constants.ts";
import * as log from "@/sse/utils/logger";
import { toJsonErrorPayload } from "@/shared/utils/upstreamError";
import { enforceApiKeyPolicy } from "@/shared/utils/apiKeyPolicy";
import {
isValidationFailure,
v1ImageGenerationSchema,
validateBody,
} from "@/shared/validation/schemas";
import { v1ImageGenerationSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
/**
* Handle CORS preflight

View File

@@ -1,11 +1,8 @@
import { CORS_ORIGIN } from "@/shared/utils/cors";
import { handleChat } from "@/sse/handlers/chat";
import { initTranslators } from "@omniroute/open-sse/translator/index.ts";
import {
isValidationFailure,
v1betaGeminiGenerateSchema,
validateBody,
} from "@/shared/validation/schemas";
import { v1betaGeminiGenerateSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
let initialized = false;

View File

@@ -0,0 +1,60 @@
import { z } from "zod";
export const loginSchema = z.object({
password: z.string().min(1, "Password is required").max(200),
});
type ValidationErrorDetail = {
field: string;
message: string;
};
type ValidationErrorPayload = {
message: string;
details: ValidationErrorDetail[];
};
type ValidationSuccess<TData> = {
success: true;
data: TData;
};
type ValidationFailure = {
success: false;
error: ValidationErrorPayload;
};
export type ValidationResult<TData> = ValidationSuccess<TData> | ValidationFailure;
// ──── Helper ────
/**
* Parse and validate request body with a Zod schema.
* Returns { success: true, data } or { success: false, error }.
*/
export function validateBody<TSchema extends z.ZodTypeAny>(
schema: TSchema,
body: unknown
): ValidationResult<z.infer<TSchema>> {
const result = schema.safeParse(body);
if (result.success) {
return { success: true, data: result.data };
}
const issues = Array.isArray(result.error?.issues) ? result.error.issues : [];
return {
success: false,
error: {
message: "Invalid request",
details: issues.map((e) => ({
field: e.path.join("."),
message: e.message,
})),
},
};
}
export function isValidationFailure<TData>(
validation: ValidationResult<TData>
): validation is ValidationFailure {
return validation.success === false;
}

View File

@@ -1,26 +1,9 @@
import { z } from "zod";
type ValidationErrorDetail = {
field: string;
message: string;
};
type ValidationErrorPayload = {
message: string;
details: ValidationErrorDetail[];
};
type ValidationSuccess<TData> = {
success: true;
data: TData;
};
type ValidationFailure = {
success: false;
error: ValidationErrorPayload;
};
export type ValidationResult<TData> = ValidationSuccess<TData> | ValidationFailure;
// Re-export validation helpers from dedicated module to avoid webpack barrel-file
// optimization bug that truncates exports from large files.
export { validateBody, isValidationFailure } from "./helpers";
export type { ValidationResult } from "./helpers";
// ──── Provider Schemas ────
@@ -899,36 +882,3 @@ export const guideSettingsSaveSchema = z.object({
apiKey: z.string().optional(),
model: z.string().trim().min(1, "Model is required"),
});
// ──── Helper ────
/**
* Parse and validate request body with a Zod schema.
* Returns { success: true, data } or { success: false, error }.
*/
export function validateBody<TSchema extends z.ZodTypeAny>(
schema: TSchema,
body: unknown
): ValidationResult<z.infer<TSchema>> {
const result = schema.safeParse(body);
if (result.success) {
return { success: true, data: result.data };
}
const issues = Array.isArray(result.error?.issues) ? result.error.issues : [];
return {
success: false,
error: {
message: "Invalid request",
details: issues.map((e) => ({
field: e.path.join("."),
message: e.message,
})),
},
};
}
export function isValidationFailure<TData>(
validation: ValidationResult<TData>
): validation is ValidationFailure {
return validation.success === false;
}