feat: 全栈 Logger 依赖注入 — DB/Route/AI 层传参 + 前端 Logger + 测试更新 + 归档 add-frontend-logger
This commit is contained in:
@@ -1,12 +1,18 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { CreateConversationRequest, RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { createConversation } from "../../db/conversations";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export async function handleCreateConversation(req: Request, db: Database, mode: RuntimeMode): Promise<Response> {
|
||||
export async function handleCreateConversation(
|
||||
req: Request,
|
||||
db: Database,
|
||||
mode: RuntimeMode,
|
||||
logger: Logger,
|
||||
): Promise<Response> {
|
||||
const url = new URL(req.url);
|
||||
const projectId = url.pathname.split("/")[3];
|
||||
|
||||
@@ -16,14 +22,16 @@ export async function handleCreateConversation(req: Request, db: Database, mode:
|
||||
let body: CreateConversationRequest = {};
|
||||
try {
|
||||
body = (await req.json()) as CreateConversationRequest;
|
||||
} catch {
|
||||
} catch (e: unknown) {
|
||||
logger.warn({ error: e instanceof Error ? e.message : String(e) }, "请求 JSON 解析失败");
|
||||
// empty body is ok, defaults will be used
|
||||
}
|
||||
|
||||
const result = createConversation(db, validated.id, body.modelId);
|
||||
const result = createConversation(db, validated.id, logger, body.modelId);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info({ conversationId: result.conversation.id, projectId: validated.id }, "会话创建成功");
|
||||
return jsonResponse({ conversation: result.conversation }, { mode, status: 201 });
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { deleteConversation, getConversation } from "../../db/conversations";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export function handleDeleteConversation(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleDeleteConversation(req: Request, db: Database, mode: RuntimeMode, logger: Logger): Response {
|
||||
const parts = new URL(req.url).pathname.split("/");
|
||||
const projectId = parts[3];
|
||||
const conversationId = parts[5];
|
||||
@@ -26,10 +27,11 @@ export function handleDeleteConversation(req: Request, db: Database, mode: Runti
|
||||
return jsonResponse(createApiError("会话不属于该项目", 403), { mode, status: 403 });
|
||||
}
|
||||
|
||||
const result = deleteConversation(db, validatedConv.id);
|
||||
const result = deleteConversation(db, validatedConv.id, logger);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info({ conversationId: validatedConv.id }, "会话删除成功");
|
||||
return jsonResponse({ success: true }, { mode });
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { getConversation } from "../../db/conversations";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export function handleGetConversation(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleGetConversation(req: Request, db: Database, mode: RuntimeMode, _logger: Logger): Response {
|
||||
const parts = new URL(req.url).pathname.split("/");
|
||||
const projectId = parts[3];
|
||||
const conversationId = parts[5];
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { listConversations } from "../../db/conversations";
|
||||
import { jsonResponse } from "../../helpers";
|
||||
import { validateIdParam, validatePagination } from "../../middleware";
|
||||
|
||||
export function handleListConversations(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleListConversations(req: Request, db: Database, mode: RuntimeMode, _logger: Logger): Response {
|
||||
const url = new URL(req.url);
|
||||
const projectId = url.pathname.split("/")[3];
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { getConversation, listMessages } from "../../db/conversations";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validateIdParam, validatePagination } from "../../middleware";
|
||||
|
||||
export function handleListMessages(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleListMessages(req: Request, db: Database, mode: RuntimeMode, _logger: Logger): Response {
|
||||
const parts = new URL(req.url).pathname.split("/");
|
||||
const projectId = parts[3];
|
||||
const conversationId = parts[5];
|
||||
|
||||
@@ -29,7 +29,8 @@ export async function handleSendChat(req: Request, db: Database, mode: RuntimeMo
|
||||
let body: { conversationId?: string; messages?: UIMessage[] };
|
||||
try {
|
||||
body = (await req.json()) as typeof body;
|
||||
} catch {
|
||||
} catch (e) {
|
||||
logger.warn({ error: e instanceof Error ? e.message : String(e) }, "请求 JSON 解析失败");
|
||||
return jsonResponse(createApiError("Invalid JSON body", 400), { mode, status: 400 });
|
||||
}
|
||||
|
||||
@@ -64,12 +65,16 @@ export async function handleSendChat(req: Request, db: Database, mode: RuntimeMo
|
||||
?.filter((p) => p.type === "text")
|
||||
.map((p) => p.text)
|
||||
.join("") ?? "";
|
||||
createMessage(db, {
|
||||
content,
|
||||
conversationId: conversation.id,
|
||||
parts: JSON.stringify(lastMsg.parts ?? []),
|
||||
role: "user",
|
||||
});
|
||||
createMessage(
|
||||
db,
|
||||
{
|
||||
content,
|
||||
conversationId: conversation.id,
|
||||
parts: JSON.stringify(lastMsg.parts ?? []),
|
||||
role: "user",
|
||||
},
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
updateConversationTimestamp(db, conversation.id);
|
||||
@@ -114,12 +119,16 @@ export async function handleSendChat(req: Request, db: Database, mode: RuntimeMo
|
||||
.filter((p): p is { text: string; type: "text" } => p.type === "text")
|
||||
.map((p) => p.text)
|
||||
.join("");
|
||||
createMessage(db, {
|
||||
content: text,
|
||||
conversationId: conversation.id,
|
||||
parts: JSON.stringify(responseMessage.parts),
|
||||
role: "assistant",
|
||||
});
|
||||
createMessage(
|
||||
db,
|
||||
{
|
||||
content: text,
|
||||
conversationId: conversation.id,
|
||||
parts: JSON.stringify(responseMessage.parts),
|
||||
role: "assistant",
|
||||
},
|
||||
logger,
|
||||
);
|
||||
updateConversationTimestamp(db, conversation.id);
|
||||
},
|
||||
uiMessages: body.messages,
|
||||
@@ -138,7 +147,7 @@ function generateConversationTitle(
|
||||
logger: Logger,
|
||||
): void {
|
||||
if (firstUserText.length <= 5) {
|
||||
updateConversation(db, conversationId, { title: firstUserText });
|
||||
updateConversation(db, conversationId, { title: firstUserText }, logger);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -149,13 +158,13 @@ function generateConversationTitle(
|
||||
})
|
||||
.then((result) => {
|
||||
const title = result.text.trim().slice(0, 10);
|
||||
updateConversation(db, conversationId, { title: title || firstUserText.slice(0, 10) });
|
||||
updateConversation(db, conversationId, { title: title || firstUserText.slice(0, 10) }, logger);
|
||||
})
|
||||
.catch((titleError: unknown) => {
|
||||
const titleMsg = titleError instanceof Error ? titleError.message : String(titleError);
|
||||
logger.error({ conversationId, error: titleMsg }, "标题生成失败");
|
||||
try {
|
||||
updateConversation(db, conversationId, { title: firstUserText.slice(0, 10) });
|
||||
updateConversation(db, conversationId, { title: firstUserText.slice(0, 10) }, logger);
|
||||
} catch {
|
||||
logger.error({ conversationId }, "标题兜底更新失败");
|
||||
}
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode, UpdateConversationRequest } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { getConversation, updateConversation } from "../../db/conversations";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export async function handleUpdateConversation(req: Request, db: Database, mode: RuntimeMode): Promise<Response> {
|
||||
export async function handleUpdateConversation(
|
||||
req: Request,
|
||||
db: Database,
|
||||
mode: RuntimeMode,
|
||||
logger: Logger,
|
||||
): Promise<Response> {
|
||||
const url = new URL(req.url);
|
||||
const parts = url.pathname.split("/");
|
||||
const projectId = parts[3];
|
||||
@@ -30,7 +36,8 @@ export async function handleUpdateConversation(req: Request, db: Database, mode:
|
||||
let body: UpdateConversationRequest;
|
||||
try {
|
||||
body = (await req.json()) as UpdateConversationRequest;
|
||||
} catch {
|
||||
} catch (e: unknown) {
|
||||
logger.warn({ error: e instanceof Error ? e.message : String(e) }, "请求 JSON 解析失败");
|
||||
return jsonResponse(createApiError("Invalid JSON body", 400), { mode, status: 400 });
|
||||
}
|
||||
|
||||
@@ -38,10 +45,11 @@ export async function handleUpdateConversation(req: Request, db: Database, mode:
|
||||
return jsonResponse(createApiError("至少需要传 modelId 或 title", 400), { mode, status: 400 });
|
||||
}
|
||||
|
||||
const result = updateConversation(db, validatedConv.id, body);
|
||||
const result = updateConversation(db, validatedConv.id, body, logger);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info({ conversationId: result.conversation.id }, "会话更新成功");
|
||||
return jsonResponse({ conversation: result.conversation }, { mode });
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { RuntimeMode } from "../../shared/api";
|
||||
import type { Logger } from "../logger";
|
||||
|
||||
import { createMetaResponse, jsonResponse } from "../helpers";
|
||||
|
||||
export function handleMeta(mode: RuntimeMode, version: string): Response {
|
||||
export function handleMeta(mode: RuntimeMode, version: string, _logger: Logger): Response {
|
||||
return jsonResponse(createMetaResponse(version), { mode });
|
||||
}
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { CreateModelRequest, RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { MODEL_CAPABILITIES } from "../../../shared/api";
|
||||
import { createModel } from "../../db/models";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
|
||||
export async function handleCreateModel(req: Request, db: Database, mode: RuntimeMode): Promise<Response> {
|
||||
export async function handleCreateModel(
|
||||
req: Request,
|
||||
db: Database,
|
||||
mode: RuntimeMode,
|
||||
logger: Logger,
|
||||
): Promise<Response> {
|
||||
let body: CreateModelRequest;
|
||||
try {
|
||||
body = (await req.json()) as CreateModelRequest;
|
||||
} catch {
|
||||
} catch (e: unknown) {
|
||||
logger.warn({ error: e instanceof Error ? e.message : String(e) }, "请求 JSON 解析失败");
|
||||
return jsonResponse(createApiError("Invalid JSON body", 400), { mode, status: 400 });
|
||||
}
|
||||
|
||||
@@ -44,11 +51,15 @@ export async function handleCreateModel(req: Request, db: Database, mode: Runtim
|
||||
const tokenError = validateOptionalPositiveInteger("maxOutputTokens", body.maxOutputTokens);
|
||||
if (tokenError) return jsonResponse(createApiError(tokenError, 400), { mode, status: 400 });
|
||||
|
||||
const result = createModel(db, body);
|
||||
const result = createModel(db, body, logger);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info(
|
||||
{ modelId: result.model.id, name: result.model.name, providerId: result.model.providerId },
|
||||
"模型创建成功",
|
||||
);
|
||||
return jsonResponse(result, { mode, status: 201 });
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { deleteModel } from "../../db/models";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export function handleDeleteModel(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleDeleteModel(req: Request, db: Database, mode: RuntimeMode, logger: Logger): Response {
|
||||
const url = new URL(req.url);
|
||||
const idStr = url.pathname.split("/")[3];
|
||||
|
||||
const validated = validateIdParam(idStr ?? "", mode);
|
||||
if (validated instanceof Response) return validated;
|
||||
|
||||
const result = deleteModel(db, validated.id);
|
||||
const result = deleteModel(db, validated.id, logger);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info({ modelId: validated.id }, "模型删除成功");
|
||||
return new Response(null, { status: 204 });
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { getModel } from "../../db/models";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export function handleGetModel(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleGetModel(req: Request, db: Database, mode: RuntimeMode, _logger: Logger): Response {
|
||||
const url = new URL(req.url);
|
||||
const idStr = url.pathname.split("/")[3];
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { listModels } from "../../db/models";
|
||||
import { jsonResponse } from "../../helpers";
|
||||
import { validatePagination } from "../../middleware";
|
||||
|
||||
export function handleListModels(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleListModels(req: Request, db: Database, mode: RuntimeMode, _logger: Logger): Response {
|
||||
const url = new URL(req.url);
|
||||
const pageParam = url.searchParams.get("page");
|
||||
const pageSizeParam = url.searchParams.get("pageSize");
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode, TestModelRequest } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { testModelConnection } from "../../ai/registry";
|
||||
import { getProvider } from "../../db/providers";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
|
||||
export async function handleTestModelConfig(req: Request, db: Database, mode: RuntimeMode): Promise<Response> {
|
||||
export async function handleTestModelConfig(
|
||||
req: Request,
|
||||
db: Database,
|
||||
mode: RuntimeMode,
|
||||
logger: Logger,
|
||||
): Promise<Response> {
|
||||
let body: TestModelRequest;
|
||||
try {
|
||||
body = (await req.json()) as TestModelRequest;
|
||||
} catch {
|
||||
} catch (e: unknown) {
|
||||
logger.warn({ error: e instanceof Error ? e.message : String(e) }, "请求 JSON 解析失败");
|
||||
return jsonResponse(createApiError("Invalid JSON body", 400), { mode, status: 400 });
|
||||
}
|
||||
|
||||
@@ -30,13 +37,23 @@ export async function handleTestModelConfig(req: Request, db: Database, mode: Ru
|
||||
});
|
||||
}
|
||||
|
||||
const testResult = await testModelConnection({
|
||||
apiKey: providerResult.provider.apiKey,
|
||||
baseUrl: providerResult.provider.baseUrl,
|
||||
modelId: body.modelId,
|
||||
name: providerResult.provider.name,
|
||||
type: providerResult.provider.type,
|
||||
});
|
||||
const testResult = await testModelConnection(
|
||||
{
|
||||
apiKey: providerResult.provider.apiKey,
|
||||
baseUrl: providerResult.provider.baseUrl,
|
||||
modelId: body.modelId,
|
||||
name: providerResult.provider.name,
|
||||
type: providerResult.provider.type,
|
||||
},
|
||||
logger,
|
||||
);
|
||||
|
||||
if (!testResult.ok) {
|
||||
logger.warn(
|
||||
{ message: testResult.message, modelId: body.modelId, providerId: body.providerId },
|
||||
"模型连接测试失败",
|
||||
);
|
||||
}
|
||||
|
||||
return jsonResponse({ modelTestResponse: testResult }, { mode });
|
||||
}
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode, UpdateModelRequest } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { MODEL_CAPABILITIES } from "../../../shared/api";
|
||||
import { updateModel } from "../../db/models";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export async function handleUpdateModel(req: Request, db: Database, mode: RuntimeMode): Promise<Response> {
|
||||
export async function handleUpdateModel(
|
||||
req: Request,
|
||||
db: Database,
|
||||
mode: RuntimeMode,
|
||||
logger: Logger,
|
||||
): Promise<Response> {
|
||||
const url = new URL(req.url);
|
||||
const idStr = url.pathname.split("/")[3];
|
||||
|
||||
@@ -17,7 +23,8 @@ export async function handleUpdateModel(req: Request, db: Database, mode: Runtim
|
||||
let body: UpdateModelRequest;
|
||||
try {
|
||||
body = (await req.json()) as UpdateModelRequest;
|
||||
} catch {
|
||||
} catch (e: unknown) {
|
||||
logger.warn({ error: e instanceof Error ? e.message : String(e) }, "请求 JSON 解析失败");
|
||||
return jsonResponse(createApiError("Invalid JSON body", 400), { mode, status: 400 });
|
||||
}
|
||||
|
||||
@@ -40,11 +47,12 @@ export async function handleUpdateModel(req: Request, db: Database, mode: Runtim
|
||||
const tokenError = validateOptionalPositiveInteger("maxOutputTokens", body.maxOutputTokens);
|
||||
if (tokenError) return jsonResponse(createApiError(tokenError, 400), { mode, status: 400 });
|
||||
|
||||
const result = updateModel(db, validated.id, body);
|
||||
const result = updateModel(db, validated.id, body, logger);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info({ modelId: result.model.id }, "模型更新成功");
|
||||
return jsonResponse(result, { mode });
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { archiveProject } from "../../db/projects";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export function handleArchiveProject(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleArchiveProject(req: Request, db: Database, mode: RuntimeMode, logger: Logger): Response {
|
||||
const url = new URL(req.url);
|
||||
const idStr = url.pathname.split("/")[3];
|
||||
|
||||
const validated = validateIdParam(idStr ?? "", mode);
|
||||
if (validated instanceof Response) return validated;
|
||||
|
||||
const result = archiveProject(db, validated.id);
|
||||
const result = archiveProject(db, validated.id, logger);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info({ projectId: validated.id }, "项目归档成功");
|
||||
return jsonResponse(result, { mode });
|
||||
}
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { CreateProjectRequest, RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { createProject } from "../../db/projects";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
|
||||
export async function handleCreateProject(req: Request, db: Database, mode: RuntimeMode): Promise<Response> {
|
||||
export async function handleCreateProject(
|
||||
req: Request,
|
||||
db: Database,
|
||||
mode: RuntimeMode,
|
||||
logger: Logger,
|
||||
): Promise<Response> {
|
||||
let body: CreateProjectRequest;
|
||||
try {
|
||||
body = (await req.json()) as CreateProjectRequest;
|
||||
} catch {
|
||||
} catch (e: unknown) {
|
||||
logger.warn({ error: e instanceof Error ? e.message : String(e) }, "请求 JSON 解析失败");
|
||||
return jsonResponse(createApiError("Invalid JSON body", 400), { mode, status: 400 });
|
||||
}
|
||||
|
||||
@@ -17,10 +24,11 @@ export async function handleCreateProject(req: Request, db: Database, mode: Runt
|
||||
return jsonResponse(createApiError("name is required", 400), { mode, status: 400 });
|
||||
}
|
||||
|
||||
const result = createProject(db, body);
|
||||
const result = createProject(db, body, logger);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info({ name: result.project.name, projectId: result.project.id }, "项目创建成功");
|
||||
return jsonResponse(result, { mode, status: 201 });
|
||||
}
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { deleteProject } from "../../db/projects";
|
||||
import { createApiError, jsonResponse, parseIdFromUrl } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export function handleDeleteProject(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleDeleteProject(req: Request, db: Database, mode: RuntimeMode, logger: Logger): Response {
|
||||
const url = new URL(req.url);
|
||||
const idStr = parseIdFromUrl(url);
|
||||
|
||||
const validated = validateIdParam(idStr ?? "", mode);
|
||||
if (validated instanceof Response) return validated;
|
||||
|
||||
const result = deleteProject(db, validated.id);
|
||||
const result = deleteProject(db, validated.id, logger);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info({ projectId: validated.id }, "项目删除成功");
|
||||
return new Response(null, { status: 204 });
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { getProject } from "../../db/projects";
|
||||
import { jsonResponse } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export function handleGetProject(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleGetProject(req: Request, db: Database, mode: RuntimeMode, _logger: Logger): Response {
|
||||
const url = new URL(req.url);
|
||||
const idStr = url.pathname.split("/")[3];
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { listProjects } from "../../db/projects";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validatePagination } from "../../middleware";
|
||||
|
||||
export function handleListProjects(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleListProjects(req: Request, db: Database, mode: RuntimeMode, _logger: Logger): Response {
|
||||
const url = new URL(req.url);
|
||||
const pageParam = url.searchParams.get("page");
|
||||
const pageSizeParam = url.searchParams.get("pageSize");
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { restoreProject } from "../../db/projects";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export function handleRestoreProject(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleRestoreProject(req: Request, db: Database, mode: RuntimeMode, logger: Logger): Response {
|
||||
const url = new URL(req.url);
|
||||
const idStr = url.pathname.split("/")[3];
|
||||
|
||||
const validated = validateIdParam(idStr ?? "", mode);
|
||||
if (validated instanceof Response) return validated;
|
||||
|
||||
const result = restoreProject(db, validated.id);
|
||||
const result = restoreProject(db, validated.id, logger);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info({ projectId: validated.id }, "项目恢复成功");
|
||||
return jsonResponse(result, { mode });
|
||||
}
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode, UpdateProjectRequest } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { updateProject } from "../../db/projects";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export async function handleUpdateProject(req: Request, db: Database, mode: RuntimeMode): Promise<Response> {
|
||||
export async function handleUpdateProject(
|
||||
req: Request,
|
||||
db: Database,
|
||||
mode: RuntimeMode,
|
||||
logger: Logger,
|
||||
): Promise<Response> {
|
||||
const url = new URL(req.url);
|
||||
const idStr = url.pathname.split("/")[3];
|
||||
|
||||
@@ -16,7 +22,9 @@ export async function handleUpdateProject(req: Request, db: Database, mode: Runt
|
||||
let body: UpdateProjectRequest;
|
||||
try {
|
||||
body = (await req.json()) as UpdateProjectRequest;
|
||||
} catch {
|
||||
} catch (e: unknown) {
|
||||
logger.warn({ error: e instanceof Error ? e.message : String(e) }, "请求 JSON 解析失败");
|
||||
return jsonResponse(createApiError("Invalid JSON body", 400), { mode, status: 400 });
|
||||
return jsonResponse(createApiError("Invalid JSON body", 400), { mode, status: 400 });
|
||||
}
|
||||
|
||||
@@ -24,10 +32,11 @@ export async function handleUpdateProject(req: Request, db: Database, mode: Runt
|
||||
return jsonResponse(createApiError("At least one of name or description is required", 400), { mode, status: 400 });
|
||||
}
|
||||
|
||||
const result = updateProject(db, validated.id, body);
|
||||
const result = updateProject(db, validated.id, body, logger);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info({ projectId: result.project.id }, "项目更新成功");
|
||||
return jsonResponse(result, { mode });
|
||||
}
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { CreateProviderRequest, RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { createProvider } from "../../db/providers";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
|
||||
export async function handleCreateProvider(req: Request, db: Database, mode: RuntimeMode): Promise<Response> {
|
||||
export async function handleCreateProvider(
|
||||
req: Request,
|
||||
db: Database,
|
||||
mode: RuntimeMode,
|
||||
logger: Logger,
|
||||
): Promise<Response> {
|
||||
let body: CreateProviderRequest;
|
||||
try {
|
||||
body = (await req.json()) as CreateProviderRequest;
|
||||
} catch {
|
||||
} catch (e: unknown) {
|
||||
logger.warn({ error: e instanceof Error ? e.message : String(e) }, "请求 JSON 解析失败");
|
||||
return jsonResponse(createApiError("Invalid JSON body", 400), { mode, status: 400 });
|
||||
}
|
||||
|
||||
@@ -32,10 +39,14 @@ export async function handleCreateProvider(req: Request, db: Database, mode: Run
|
||||
});
|
||||
}
|
||||
|
||||
const result = createProvider(db, body);
|
||||
const result = createProvider(db, body, logger);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info(
|
||||
{ name: result.provider.name, providerId: result.provider.id, type: result.provider.type },
|
||||
"供应商创建成功",
|
||||
);
|
||||
return jsonResponse(result, { mode, status: 201 });
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { getModelsByProviderId } from "../../db/models";
|
||||
import { deleteProvider } from "../../db/providers";
|
||||
import { createApiError, jsonResponse, parseIdFromUrl } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export function handleDeleteProvider(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleDeleteProvider(req: Request, db: Database, mode: RuntimeMode, logger: Logger): Response {
|
||||
const url = new URL(req.url);
|
||||
const idStr = parseIdFromUrl(url);
|
||||
|
||||
@@ -19,10 +20,11 @@ export function handleDeleteProvider(req: Request, db: Database, mode: RuntimeMo
|
||||
return jsonResponse(createApiError("该供应商下存在模型,无法删除", 409), { mode, status: 409 });
|
||||
}
|
||||
|
||||
const result = deleteProvider(db, validated.id);
|
||||
const result = deleteProvider(db, validated.id, logger);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info({ providerId: validated.id }, "供应商删除成功");
|
||||
return new Response(null, { status: 204 });
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { getProvider } from "../../db/providers";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export function handleGetProvider(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleGetProvider(req: Request, db: Database, mode: RuntimeMode, _logger: Logger): Response {
|
||||
const url = new URL(req.url);
|
||||
const idStr = url.pathname.split("/")[3];
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { listProviders } from "../../db/providers";
|
||||
import { jsonResponse } from "../../helpers";
|
||||
import { validatePagination } from "../../middleware";
|
||||
|
||||
export function handleListProviders(req: Request, db: Database, mode: RuntimeMode): Response {
|
||||
export function handleListProviders(req: Request, db: Database, mode: RuntimeMode, _logger: Logger): Response {
|
||||
const url = new URL(req.url);
|
||||
const pageParam = url.searchParams.get("page");
|
||||
const pageSizeParam = url.searchParams.get("pageSize");
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { listProviderOptions } from "../../db/providers";
|
||||
import { jsonResponse } from "../../helpers";
|
||||
|
||||
export function handleListProviderOptions(db: Database, mode: RuntimeMode): Response {
|
||||
export function handleListProviderOptions(db: Database, mode: RuntimeMode, _logger: Logger): Response {
|
||||
return jsonResponse({ items: listProviderOptions(db) }, { mode });
|
||||
}
|
||||
|
||||
@@ -1,29 +1,46 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { CreateProviderRequest, RuntimeMode } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { testProviderConnection } from "../../ai/registry";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
|
||||
export async function handleTestProviderConfig(req: Request, _db: Database, mode: RuntimeMode): Promise<Response> {
|
||||
const validated = await readProviderConfig(req, mode);
|
||||
export async function handleTestProviderConfig(
|
||||
req: Request,
|
||||
db: Database,
|
||||
mode: RuntimeMode,
|
||||
logger: Logger,
|
||||
): Promise<Response> {
|
||||
const validated = await readProviderConfig(req, mode, logger);
|
||||
if (validated instanceof Response) return validated;
|
||||
|
||||
const testResult = await testProviderConnection({
|
||||
apiKey: validated.apiKey,
|
||||
baseUrl: validated.baseUrl,
|
||||
name: validated.name,
|
||||
type: validated.type,
|
||||
});
|
||||
const testResult = await testProviderConnection(
|
||||
{
|
||||
apiKey: validated.apiKey,
|
||||
baseUrl: validated.baseUrl,
|
||||
name: validated.name,
|
||||
type: validated.type,
|
||||
},
|
||||
logger,
|
||||
);
|
||||
|
||||
if (!testResult.ok) {
|
||||
logger.warn({ message: testResult.message, name: validated.name, type: validated.type }, "供应商连接测试失败");
|
||||
}
|
||||
return jsonResponse({ providerTestResponse: testResult }, { mode });
|
||||
}
|
||||
|
||||
async function readProviderConfig(req: Request, mode: RuntimeMode): Promise<CreateProviderRequest | Response> {
|
||||
async function readProviderConfig(
|
||||
req: Request,
|
||||
mode: RuntimeMode,
|
||||
logger: Logger,
|
||||
): Promise<CreateProviderRequest | Response> {
|
||||
let body: CreateProviderRequest;
|
||||
try {
|
||||
body = (await req.json()) as CreateProviderRequest;
|
||||
} catch {
|
||||
} catch (e: unknown) {
|
||||
logger.warn({ error: e instanceof Error ? e.message : String(e) }, "请求 JSON 解析失败");
|
||||
return jsonResponse(createApiError("Invalid JSON body", 400), { mode, status: 400 });
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import type Database from "bun:sqlite";
|
||||
|
||||
import type { RuntimeMode, UpdateProviderRequest } from "../../../shared/api";
|
||||
import type { Logger } from "../../logger";
|
||||
|
||||
import { updateProvider } from "../../db/providers";
|
||||
import { createApiError, jsonResponse } from "../../helpers";
|
||||
import { validateIdParam } from "../../middleware";
|
||||
|
||||
export async function handleUpdateProvider(req: Request, db: Database, mode: RuntimeMode): Promise<Response> {
|
||||
export async function handleUpdateProvider(
|
||||
req: Request,
|
||||
db: Database,
|
||||
mode: RuntimeMode,
|
||||
logger: Logger,
|
||||
): Promise<Response> {
|
||||
const url = new URL(req.url);
|
||||
const idStr = url.pathname.split("/")[3];
|
||||
|
||||
@@ -16,7 +22,8 @@ export async function handleUpdateProvider(req: Request, db: Database, mode: Run
|
||||
let body: UpdateProviderRequest;
|
||||
try {
|
||||
body = (await req.json()) as UpdateProviderRequest;
|
||||
} catch {
|
||||
} catch (e: unknown) {
|
||||
logger.warn({ error: e instanceof Error ? e.message : String(e) }, "请求 JSON 解析失败");
|
||||
return jsonResponse(createApiError("Invalid JSON body", 400), { mode, status: 400 });
|
||||
}
|
||||
|
||||
@@ -27,10 +34,11 @@ export async function handleUpdateProvider(req: Request, db: Database, mode: Run
|
||||
});
|
||||
}
|
||||
|
||||
const result = updateProvider(db, validated.id, body);
|
||||
const result = updateProvider(db, validated.id, body, logger);
|
||||
if ("error" in result) {
|
||||
return jsonResponse(createApiError(result.error, result.status), { mode, status: result.status });
|
||||
}
|
||||
|
||||
logger.info({ providerId: result.provider.id }, "供应商更新成功");
|
||||
return jsonResponse(result, { mode });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user