UNPKG

@stacksjs/error-handling

Version:
241 lines (240 loc) 9.4 kB
import { ERROR_PAGE_CSS } from './error-page-styles'; export declare function isFrameworkFrame(file: string): boolean; /** * Render a simple production error page. * * Checks for a userland override at `resources/views/errors/<status>.html` * (or `error.html` as a generic fallback) first; renders the built-in * template only when no custom page is provided. stacksjs/stacks#863. */ export declare function renderProductionErrorPage(status: number): string; /** * Render the contextual hint block (common causes, suggestion, doc link) * for a given HTTP status. Returns an empty string for statuses without * enriched data so the dev page degrades gracefully. */ export declare function renderHttpErrorHints(status: number): string; /** * Create an error handler instance */ export declare function createErrorHandler(config?: ErrorPageConfig): ErrorPageHandler; /** * Render an error page (alias) */ export declare function renderErrorPage(error: Error, status?: number, config?: ErrorPageConfig): Promise<string>; /** * Render error (alias) */ export declare function renderError(error: Error, status?: number): Promise<string>; /** * Create an error response */ export declare function errorResponse(error: Error, status?: number, config?: ErrorPageConfig): Promise<Response>; /** * HTTP error definitions. Each entry includes a doc link, likely causes, // and a concrete suggestion so the dev-mode error page reads like a hint // instead of just "something went wrong". * @defaultValue * ```ts * { * 400: { * status: 400, * title: 'Bad Request', * message: 'The request was malformed or invalid.', * commonCauses: [ 'JSON body is missing or has a syntax error', 'A required field is absent from the payload', 'Content-Type header does not match the body format', ], * suggestion: 'Inspect the request body and Content-Type — most 400s come from malformed JSON or a missing required field.' * }, * 401: { * status: 401, * title: 'Unauthorized', * message: 'Authentication is required to access this resource.', * commonCauses: [ 'No Authorization header was sent', 'The bearer token expired', 'The session cookie was cleared', ], * suggestion: 'Confirm a valid `Authorization: Bearer <token>` header is sent and the token has not expired.' * }, * 403: { * status: 403, * title: 'Forbidden', * message: 'You do not have permission to access this resource.', * commonCauses: [ 'The authenticated user lacks the required ability or role', 'A Gate or policy denied access (see app/Gates.ts)', 'The token was issued without the needed ability', ], * suggestion: 'Check Gates / policies and the abilities encoded in the access token.' * }, * 404: { * status: 404, * title: 'Not Found', * message: 'The requested resource could not be found.', * commonCauses: [ 'The route is not registered in app/Routes.ts', 'A typo in the URL path', 'A model lookup returned no row (ModelNotFoundError)', ], * suggestion: 'Run `buddy route:list` to see registered routes, or verify the model exists with the given id.' * }, * 405: { * status: 405, * title: 'Method Not Allowed', * message: 'The request method is not supported for this resource.', * commonCauses: [ 'The route is registered for a different HTTP method', 'A form posted GET when the route expects POST', ], * suggestion: 'Confirm the HTTP method in `app/Routes.ts` matches what the client sent.' * }, * 408: { * status: 408, * title: 'Request Timeout', * message: 'The request took too long to complete.', * commonCauses: [ 'A long-running query or external API call exceeded the timeout', 'The client uploaded a slow body that stalled', ], * suggestion: 'Move slow work into a queued job, or raise the route timeout if the work is genuinely long.' * }, * 409: { * status: 409, * title: 'Conflict', * message: 'The request conflicts with the current state of the resource.', * commonCauses: [ 'A unique-constraint violation (duplicate email, slug, etc.)', 'Optimistic locking detected a stale write', ], * suggestion: 'Re-fetch the resource and retry, or surface the conflict to the user.' * }, * 410: { * status: 410, * title: 'Gone', * message: 'The requested resource is no longer available.', * commonCauses: ['The resource was permanently deleted', 'A signed URL expired'], * suggestion: 'Issue a fresh signed URL or fall back to the canonical resource.' * }, * 422: { * status: 422, * title: 'Unprocessable Entity', * message: 'The request was well-formed but could not be processed.', * commonCauses: [ 'Validation rules from the action / model rejected the payload', 'A field value is outside the allowed range or shape', ], * suggestion: 'Inspect `errors` in the response body — each key maps to a failing field.' * }, * 429: { * status: 429, * title: 'Too Many Requests', * message: 'You have exceeded the rate limit.', * commonCauses: ['Rate-limit middleware tripped on this IP / token', 'A retry loop is hammering the endpoint'], * suggestion: 'Honor the `Retry-After` response header and back off before retrying.' * }, * 500: { * status: 500, * title: 'Internal Server Error', * message: 'An unexpected error occurred on the server.', * commonCauses: [ 'An unhandled exception in an action or middleware', 'A failing database connection or migration', 'A misconfigured environment variable', ], * suggestion: 'Check server logs for the original stack trace — the error page above shows the throw site in dev.' * }, * 502: { * status: 502, * title: 'Bad Gateway', * message: 'The server received an invalid response from an upstream server.', * commonCauses: ['An upstream HTTP API returned a malformed response', 'A reverse proxy could not reach the origin'], * suggestion: 'Verify the upstream service is healthy and returning the expected content type.' * }, * 503: { * status: 503, * title: 'Service Unavailable', * message: 'The service is temporarily unavailable.', * commonCauses: ['Maintenance mode is enabled', 'A health check is failing', 'A dependency (db, redis, queue) is down'], * suggestion: 'Run `buddy doctor` and check dependent services.' * }, * 504: { * status: 504, * title: 'Gateway Timeout', * message: 'The upstream server did not respond in time.', * commonCauses: ['An upstream HTTP call exceeded its deadline', 'A long-running database query timed out'], * suggestion: 'Move the work to a queued job or raise the upstream timeout if the latency is expected.' * } * } * ``` */ export declare const HTTP_ERRORS: Record<HttpStatusCode, HttpError>; /** * Error Page Rendering - Ignition-style error pages * * Provides beautiful development error pages with full stack traces, * database queries, and request context. */ // Types export declare interface ErrorPageConfig { appName?: string theme?: 'light' | 'dark' | 'auto' showEnvironment?: boolean showQueries?: boolean showRequest?: boolean enableCopyMarkdown?: boolean snippetLines?: number basePaths?: string[] showFrameworkFrames?: boolean } export declare interface RequestContext { method: string url: string headers: Record<string, string> queryParams?: Record<string, string> body?: unknown } export declare interface RoutingContext { controller?: string routeName?: string middleware?: string[] } export declare interface UserContext { id?: string | number email?: string name?: string } export declare interface QueryInfo { query: string time?: number connection?: string } export declare interface StackFrame { file: string line: number column?: number function?: string code?: string } export declare interface CodeSnippet { file: string line: number code: string[] highlight: number } export declare interface EnvironmentContext { nodeVersion?: string platform?: string arch?: string env?: Record<string, string> } export declare interface JobContext { name?: string queue?: string attempts?: number } export declare interface ErrorPageData { error: Error status: number stack: StackFrame[] request?: RequestContext routing?: RoutingContext user?: UserContext queries?: QueryInfo[] environment?: EnvironmentContext job?: JobContext framework?: { name: string, version?: string } } export declare interface HttpError { status: HttpStatusCode title: string message: string docLink?: string commonCauses?: string[] suggestion?: string } export type HttpStatusCode = 400 | 401 | 403 | 404 | 405 | 408 | 409 | 410 | 422 | 429 | 500 | 502 | 503 | 504; /** * Error Page Handler class */ export declare class ErrorPageHandler { constructor(config?: ErrorPageConfig); setFramework(name: string, version?: string): this; setRequest(request: Request | RequestContext): this; setRouting(routing: RoutingContext): this; setUser(user: UserContext): this; addQuery(query: string, time?: number, connection?: string): this; render(error: Error, status?: number): Promise<string>; handleError(error: Error, status?: number): Promise<Response>; } export { ERROR_PAGE_CSS };