mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-16 11:52:26 +03:00
Boarded together with Phases 2, 4, 5 (#12051, #12053, #12055) and validated in one combined worktree: typecheck:core, check:file-size, check:changelog-integrity, check:complexity, check:cognitive-complexity, check:cycles, check-db-rules all green. Mechanical import-path migration only, no behavior change. Thanks for the phased, well-tested cleanup.
149 lines
4.6 KiB
TypeScript
149 lines
4.6 KiB
TypeScript
import {
|
|
createProxy,
|
|
createProxyAndAssign,
|
|
deleteProxyById,
|
|
getProxyById,
|
|
getProxyWhereUsed,
|
|
updateProxy,
|
|
updateProxyAndAssign,
|
|
} from "@/lib/db/proxies";
|
|
import { createErrorResponse, createErrorResponseFromUnknown } from "@/lib/api/errorResponse";
|
|
import { createProxyRegistrySchema, updateProxyRegistrySchema } from "@/shared/validation/schemas";
|
|
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
|
|
import { clearDispatcherCache } from "@omniroute/open-sse/utils/proxyDispatcher";
|
|
|
|
async function readJsonBody(request: Request) {
|
|
try {
|
|
return { ok: true as const, body: await request.json() };
|
|
} catch {
|
|
return {
|
|
ok: false as const,
|
|
response: createErrorResponse({
|
|
status: 400,
|
|
message: "Invalid JSON body",
|
|
type: "invalid_request",
|
|
}),
|
|
};
|
|
}
|
|
}
|
|
|
|
export async function resolveProxyLookupResponse(
|
|
searchParams: URLSearchParams,
|
|
whereUsedParam: string
|
|
): Promise<Response | null> {
|
|
const id = searchParams.get("id");
|
|
const whereUsed = searchParams.get(whereUsedParam) === "1";
|
|
|
|
if (id && whereUsed) {
|
|
const usage = await getProxyWhereUsed(id);
|
|
return Response.json(usage);
|
|
}
|
|
|
|
if (!id) {
|
|
return null;
|
|
}
|
|
|
|
const proxy = await getProxyById(id, { includeSecrets: false });
|
|
if (!proxy) {
|
|
return createErrorResponse({ status: 404, message: "Proxy not found", type: "not_found" });
|
|
}
|
|
return Response.json(proxy);
|
|
}
|
|
|
|
export async function handleProxyCreate(request: Request) {
|
|
const parsed = await readJsonBody(request);
|
|
if (!parsed.ok) return parsed.response;
|
|
|
|
try {
|
|
const validation = validateBody(createProxyRegistrySchema, parsed.body);
|
|
if (isValidationFailure(validation)) {
|
|
return createErrorResponse({
|
|
status: 400,
|
|
message: validation.error.message,
|
|
details: validation.error.details,
|
|
type: "invalid_request",
|
|
});
|
|
}
|
|
|
|
const { assignment, ...proxyFields } = validation.data;
|
|
if (assignment) {
|
|
const result = await createProxyAndAssign(proxyFields, assignment);
|
|
clearDispatcherCache();
|
|
return Response.json({ ...result.proxy, assignment: result.assignment }, { status: 201 });
|
|
}
|
|
|
|
const created = await createProxy(proxyFields);
|
|
return Response.json(created, { status: 201 });
|
|
} catch (error) {
|
|
return createErrorResponseFromUnknown(error, "Failed to create proxy");
|
|
}
|
|
}
|
|
|
|
export async function handleProxyUpdate(request: Request) {
|
|
const parsed = await readJsonBody(request);
|
|
if (!parsed.ok) return parsed.response;
|
|
|
|
try {
|
|
const validation = validateBody(updateProxyRegistrySchema, parsed.body);
|
|
if (isValidationFailure(validation)) {
|
|
return createErrorResponse({
|
|
status: 400,
|
|
message: validation.error.message,
|
|
details: validation.error.details,
|
|
type: "invalid_request",
|
|
});
|
|
}
|
|
|
|
const { id, assignment, ...rawChanges } = validation.data;
|
|
// Strip keys the client didn't send — .partial() resolves absent fields to
|
|
// undefined, which would silently overwrite DB values via the spread merge
|
|
// in updateProxyRow. Only include keys the client explicitly provided.
|
|
const changes = Object.fromEntries(
|
|
Object.entries(rawChanges).filter(([_, v]) => v !== undefined)
|
|
);
|
|
if (assignment) {
|
|
const result = await updateProxyAndAssign(id, changes, assignment);
|
|
if (!result?.proxy) {
|
|
return createErrorResponse({ status: 404, message: "Proxy not found", type: "not_found" });
|
|
}
|
|
|
|
clearDispatcherCache();
|
|
return Response.json({ ...result.proxy, assignment: result.assignment });
|
|
}
|
|
|
|
const updated = await updateProxy(id, changes);
|
|
if (!updated) {
|
|
return createErrorResponse({ status: 404, message: "Proxy not found", type: "not_found" });
|
|
}
|
|
|
|
return Response.json(updated);
|
|
} catch (error) {
|
|
return createErrorResponseFromUnknown(error, "Failed to update proxy");
|
|
}
|
|
}
|
|
|
|
export async function handleProxyDelete(request: Request) {
|
|
try {
|
|
const { searchParams } = new URL(request.url);
|
|
const id = searchParams.get("id");
|
|
const force = searchParams.get("force") === "1";
|
|
|
|
if (!id) {
|
|
return createErrorResponse({
|
|
status: 400,
|
|
message: "id is required",
|
|
type: "invalid_request",
|
|
});
|
|
}
|
|
|
|
const deleted = await deleteProxyById(id, { force });
|
|
if (!deleted) {
|
|
return createErrorResponse({ status: 404, message: "Proxy not found", type: "not_found" });
|
|
}
|
|
|
|
return Response.json({ success: true });
|
|
} catch (error) {
|
|
return createErrorResponseFromUnknown(error, "Failed to delete proxy");
|
|
}
|
|
}
|