Files
probably-rendering-one-more…/apps/wiki/src/lib/api.ts
T
codex-bot 9986846c36
wiki CI and deployment / verify-and-deploy (push) Successful in 13m27s
Flatten note tags and store processed media as ordinary resource links
2026-10-26 00:23:02 +08:00

28 lines
1.8 KiB
TypeScript

import type { NextApiRequest, NextApiResponse } from "next";
import { ZodError } from "zod";
export function sameOrigin(req: NextApiRequest) {
const origin=req.headers.origin;
if (origin && new URL(origin).host !== req.headers.host) throw new Error("Cross-origin request rejected");
}
export function apiError(res: NextApiResponse,error: unknown) {
if(error instanceof ZodError) return res.status(400).json({error:"请检查输入内容",issues:error.issues});
const message=error instanceof Error?error.message:"";
const clientMessages:Record<string,string>={
'Character PNG must have transparency':'请上传带真实透明背景的 PNG,透明区域 alpha 为 0,人物内部 alpha 至少为 250',
'Referenced asset does not exist':'引用的素材不存在',
'A media post needs matching content':'素材包需要包含对应类型的素材',
'Cover must reference an image':'封面需要引用一张图片',
'Unsupported image format':'支持 JPG、PNG、WebP、GIF 和 AVIF 图片',
'File has no video stream':'文件中没有可用的画面',
'Select an audio file':'请选择独立的声音文件',
'Unsupported media MIME type':'文件类型不受支持',
};
if(clientMessages[message])return res.status(400).json({error:clientMessages[message]});
const code=(error as {code?:string})?.code;
if(code==='23505')return res.status(409).json({error:'这个网址标识已经存在,请换一个'});
if(code==='23503')return res.status(400).json({error:'引用的分类或素材不存在'});
if(["Invalid cursor","Tag not found","Cross-origin request rejected"].includes(message)) return res.status(400).json({error:message});
console.error("API failure",error instanceof Error?error.message:"Unknown error");
return res.status(500).json({error:"操作没有完成,请稍后重试"});
}