mirror of
https://github.com/Sea-Haven-Industries/seahaven-ap.git
synced 2026-09-30 17:23:19 +00:00
57 lines
1.3 KiB
TypeScript
57 lines
1.3 KiB
TypeScript
import { randomUUID } from "node:crypto";
|
|
import type { Context } from "hono";
|
|
import type { ContentfulStatusCode } from "hono/utils/http-status";
|
|
|
|
export type ErrorCode =
|
|
| "UNAUTHENTICATED"
|
|
| "FORBIDDEN"
|
|
| "NOT_FOUND"
|
|
| "VALIDATION_ERROR"
|
|
| "CONFLICT"
|
|
| "INTERNAL_ERROR"
|
|
| "DATABASE_UNAVAILABLE";
|
|
|
|
export class ApiError extends Error {
|
|
constructor(
|
|
readonly status: ContentfulStatusCode,
|
|
readonly code: ErrorCode,
|
|
message: string,
|
|
) {
|
|
super(message);
|
|
this.name = "ApiError";
|
|
}
|
|
}
|
|
|
|
export const CORRELATION_HEADER = "x-correlation-id";
|
|
|
|
export type ErrorEnvelope = {
|
|
error: {
|
|
code: ErrorCode;
|
|
message: string;
|
|
correlationId: string;
|
|
};
|
|
};
|
|
|
|
export function correlationIdFrom(c: Context): string {
|
|
const raw = c.req.header(CORRELATION_HEADER)?.trim();
|
|
if (raw && raw.length <= 128) {
|
|
return raw;
|
|
}
|
|
return randomUUID();
|
|
}
|
|
|
|
export function errorBody(code: ErrorCode, message: string, correlationId: string): ErrorEnvelope {
|
|
return { error: { code, message, correlationId } };
|
|
}
|
|
|
|
export function errorJson(
|
|
c: Context,
|
|
status: ContentfulStatusCode,
|
|
code: ErrorCode,
|
|
message: string,
|
|
correlationId?: string,
|
|
) {
|
|
const id = correlationId ?? correlationIdFrom(c);
|
|
c.header(CORRELATION_HEADER, id);
|
|
return c.json(errorBody(code, message, id), status);
|
|
}
|