import type { Messages } from "./i18n/index.ts"; export type ErrorI18nKey = keyof Messages["error"]; export interface ErrorOpts { i18nKey?: ErrorI18nKey; i18nVars?: Record; } export function formatError(err: unknown): string { return err instanceof Error ? err.message : String(err); } export function isUniqueConstraintError(err: unknown): boolean { if (!(err instanceof Error) || !("code" in err)) return false; const code = (err as { code: unknown }).code; return ( code === "SQLITE_CONSTRAINT_PRIMARYKEY" || code === "SQLITE_CONSTRAINT_UNIQUE" ); } export class AppError extends Error { readonly statusCode: number; readonly i18nKey: ErrorI18nKey | null; readonly i18nVars: Record | null; constructor(message: string, statusCode: number, opts?: ErrorOpts) { super(message); this.statusCode = statusCode; this.i18nKey = opts?.i18nKey ?? null; this.i18nVars = opts?.i18nVars ?? null; } } export class NotFoundError extends AppError { constructor(message = "Not found", opts?: ErrorOpts) { super(message, 404, opts); } } export class ForbiddenError extends AppError { constructor(message = "Forbidden", opts?: ErrorOpts) { super(message, 403, opts); } } export class WikiRemovedError extends AppError { constructor(message = "This wiki has been removed", opts?: ErrorOpts) { super(message, 410, opts); } } export class PdsWriteError extends AppError { constructor(message: string, opts?: ErrorOpts) { super(message, 502, opts); } } export class ValidationError extends AppError { constructor(message: string, opts?: ErrorOpts) { super(message, 400, opts); } } export class ImportError extends AppError { constructor(message: string, opts?: ErrorOpts) { super(message, 400, opts); } }