import { Context } from 'hono'; import { Result } from 'neverthrow'; import { ErrorCodes, ErrorWithCode } from 'web-shared/src/types/errors'; import { logger } from 'web-shared/src/lib/logger'; const serializeErrors = (value: unknown): unknown => { if (value instanceof Error) { return { name: value.name, message: value.message, stack: value.stack, cause: value.cause !== undefined ? serializeErrors(value.cause) : undefined, }; } if (Array.isArray(value)) { return value.map(serializeErrors); } if (value !== null && typeof value === 'object') { return Object.fromEntries( Object.entries(value).map(([k, v]) => [k, serializeErrors(v)]), ); } return value; }; /** * Maps a NeverThrow Result to a Hono response * @param c - Hono context * @param result - The Result from neverthrow * @param successHandler - Function to handle successful result * @param errorStatusMap - Map of error codes to HTTP status codes (defaults to 500) * @returns Response */ export const handleResult = >( c: Context, result: Result, successHandler: (value: T) => Response, errorStatusMap?: Partial>, ) => { if (result.isErr()) { const { context, code, message } = result.error; const serializedContext = serializeErrors(context) as | Record | undefined; logger.error({ ...(serializedContext || {}), code }, message); const statusCode = (errorStatusMap?.[code as E['code']] || 500) as number; return c.json( { error: { message: result.error.message, code: result.error.code, context: serializedContext, }, }, statusCode as any, ); } return successHandler(result.value); };