Files
2026-09-04 09:04:51 -07:00

40 lines
1.3 KiB
TypeScript

import type { Endpoint } from 'one'
import { isResponse } from 'one'
import { ClientError } from './ClientError'
export function apiRoute(handler: Endpoint) {
return (async (req) => {
try {
const result = handler(req)
const out = result instanceof Promise ? await result : result
if (isResponse(out) && (out.status < 200 || out.status >= 400) && out.body) {
try {
console.info(`Error Response (${out.status}) from ${req.url}:`)
} catch {
// ignore log errors
}
}
return out
} catch (err) {
// a Response thrown by the handler is an intentional result, not an error
if (isResponse(err)) {
return err
}
// a ClientError is a user-facing message the caller is meant to see
if (err instanceof ClientError) {
return Response.json({ error: err.message }, { status: err.status })
}
// anything else is internal: log the detail server-side, return a generic
// body, so internal messages never reach the client
const message = err instanceof Error ? err.message : `${err}`
console.trace(`Error in apiRoute ${req.url}: ${message}`, err)
return Response.json({ error: 'Internal server error' }, { status: 500 })
}
}) satisfies Endpoint
}