hono-ban 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
HTTP-friendly error objects for [Hono](https://hono.dev), inspired by [Boom](https://github.com/hapijs/boom).
|
|
8
8
|
|
|
9
|
+
> **Warning**: This package is not production-ready. It is under active development with daily updates and could change significantly.
|
|
10
|
+
|
|
9
11
|
## Table of Contents
|
|
10
12
|
|
|
11
13
|
- [Installation](#installation)
|
|
@@ -304,7 +306,7 @@ hono-ban includes several built-in formatters for common error response formats.
|
|
|
304
306
|
|
|
305
307
|
### Default Formatter
|
|
306
308
|
|
|
307
|
-
The default formatter produces a
|
|
309
|
+
The default formatter produces a clean, flat JSON structure with status code, error name, and optional message and data.
|
|
308
310
|
|
|
309
311
|
```typescript
|
|
310
312
|
import { defaultFormatter } from "hono-ban";
|
|
@@ -312,12 +314,9 @@ import { defaultFormatter } from "hono-ban";
|
|
|
312
314
|
// Example output:
|
|
313
315
|
// {
|
|
314
316
|
// "statusCode": 400,
|
|
315
|
-
// "
|
|
316
|
-
//
|
|
317
|
-
//
|
|
318
|
-
// "message": "Invalid input",
|
|
319
|
-
// "data": { "field": "email" }
|
|
320
|
-
// }
|
|
317
|
+
// "error": "Bad Request",
|
|
318
|
+
// "message": "Invalid input",
|
|
319
|
+
// "data": { "field": "email" }
|
|
321
320
|
// }
|
|
322
321
|
```
|
|
323
322
|
|
package/dist/esm/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var Y={400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",407:"Proxy Authentication Required",408:"Request Timeout",409:"Conflict",410:"Gone",411:"Length Required",412:"Precondition Failed",413:"Payload Too Large",414:"URI Too Long",415:"Unsupported Media Type",416:"Range Not Satisfiable",417:"Expectation Failed",418:"I'm a teapot",421:"Misdirected Request",422:"Unprocessable Entity",423:"Locked",424:"Failed Dependency",425:"Too Early",426:"Upgrade Required",428:"Precondition Required",429:"Too Many Requests",431:"Request Header Fields Too Large",451:"Unavailable For Legal Reasons",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout",505:"HTTP Version Not Supported",506:"Variant Also Negotiates",507:"Insufficient Storage",508:"Loop Detected",510:"Not Extended",511:"Network Authentication Required"};function N(x){if(typeof x!=="number"||isNaN(x))return 500;if(x<400||x>=600)return 500;return x}function G(x){let f=N(x.statusCode??500),y={status:f,message:x.message??Y[f],isBan:!0};if(x.data!==void 0)y.data=x.data;if(x.headers)y.headers={...x.headers};if(x.allow)y.allow=Array.isArray(x.allow)?[...x.allow]:[x.allow];if(x.cause){if(y.cause=x.cause,x.cause instanceof Error)y.causeStack=x.cause.stack}return Error.captureStackTrace(y,G),y}function D(x,f){return typeof x==="object"&&x!==null&&"isBan"in x&&x.isBan===!0&&(!f||x.status===f)}function L(x,f={}){if(D(x))return{status:f.statusCode??x.status,message:f.message??x.message,isBan:!0,data:f.data!==void 0?f.data:x.data,headers:{...x.headers,...f.headers},allow:f.allow?Array.isArray(f.allow)?[...f.allow]:[f.allow]:x.allow,cause:f.cause??x.cause,stack:x.stack};if(x instanceof Error)return G({...f,message:f.message??x.message,cause:x});return G({...f,message:f.message??(typeof x==="string"?x:"Unknown error"),cause:x})}function R(x,f,y={}){return f.format(x,y.headers,y.sanitize,y.includeStackTrace)}function _(x,f){let y=new Headers({"Content-Type":"application/json",...x.headers});if(x.allow?.length)y.set("Allow",x.allow.join(", "));let M=x.data&&typeof x.data==="object"&&"isDeveloperError"in x.data&&x.data.isDeveloperError===!0;return new Response(JSON.stringify(f),{status:x.status,headers:y})}function Z(x,f){if(!f.length)return x;if(Array.isArray(x))return x.map((y)=>Z(y,f));if(x!==null&&typeof x==="object")return Object.entries(x).reduce((y,[M,Q])=>{if(f.includes(M))return y;return y[M]=Z(Q,f),y},{});return x}var I={contentType:"application/json",format(x,f={},y=[],M=!1){let{status:Q,message:$,data:J}=x,X={statusCode:Q,error:Y[Q]||"Unknown Error"};if(typeof $==="string")X.message=$;let U=J&&typeof J==="object"&&"isDeveloperError"in J&&J.isDeveloperError===!0;if(M||U){if(x.stack)X.stack=x.stack;if(x.causeStack)X.causeStack=x.causeStack}if(J!==void 0)X.data=J;return Z(X,y)}};import{z as j}from"@hono/zod-openapi";var b=j.object({name:j.string().openapi({example:"username",description:"The field name that failed validation"}),reason:j.string().openapi({example:"String must contain at least 3 character(s)",description:"The reason for validation failure"})}),q=j.object({name:j.string().openapi({example:"email",description:"The field name that violated a constraint"}),reason:j.string().openapi({example:"Email already exists",description:"The reason for the constraint violation"}),resource:j.string().openapi({example:"user",description:"The resource type that contains the constraint"}),constraint:j.string().openapi({example:"unique",description:"The type of constraint that was violated"})}),P=j.object({"invalid-params":j.array(b).optional(),violations:j.array(q).optional()}),V=j.object({type:j.string().url().openapi({example:"https://api.example.com/problems/validation-error",description:"A URI reference that identifies the problem type"}),title:j.string().openapi({example:"Validation Failed",description:"A short, human-readable summary of the problem type"}),status:j.number().int().min(400).max(599).openapi({example:400,description:"The HTTP status code"}),detail:j.string().optional().openapi({example:"The request contains invalid fields",description:"A human-readable explanation specific to this occurrence of the problem"}),instance:j.string().url().optional().openapi({example:"urn:uuid:6b56944d-5e89-4b4d-9ca7-c1be3d1f0e3f",description:"A URI reference that identifies the specific occurrence of the problem"}),timestamp:j.string().datetime().optional().openapi({example:"2025-02-26T12:34:56.789Z",description:"When the error occurred"})}).merge(P);function v(x={}){let f=x.baseUrl||"https://api.example.com/problems";return{contentType:"application/problem+json",format(y){let M={type:`${f}/${y.status}`,title:Y[y.status]||"Unknown Error",status:y.status,detail:y.message,instance:`urn:uuid:${crypto.randomUUID()}`,timestamp:new Date().toISOString()};if(y.data?.["invalid-params"])return V.parse({...M,"invalid-params":y.data["invalid-params"]});if(y.data?.violations)return V.parse({...M,violations:y.data.violations});return V.parse(M)}}}function z(x){return{"invalid-params":b.array().parse(x)}}function B(x){return{"invalid-params":b.array().parse(x.errors.map((f)=>({name:f.path.join("."),reason:f.message})))}}function T(x,f,y,M="unique"){return{violations:q.array().parse([{name:x,reason:f,resource:y,constraint:M}])}}import{ZodError as C}from"zod";function K(x,f,y){if(typeof f==="string")return G({...y,statusCode:x,message:f});return G({...f,...y,statusCode:x})}function A(x,f){return K(400,x,f)}function o(x,f){return K(401,x,f)}function x7(x,f){return K(402,x,f)}function f7(x,f){return K(403,x,f)}function y7(x,f){return K(404,x,f)}function K7(x,f){return K(405,x,f)}function M7(x,f){return K(406,x,f)}function j7(x,f){return K(407,x,f)}function G7(x,f){return K(408,x,f)}function H7(x,f){return K(409,x,f)}function J7(x,f){return K(410,x,f)}function Q7(x,f){return K(411,x,f)}function X7(x,f){return K(412,x,f)}function Y7(x,f){return K(413,x,f)}function $7(x,f){return K(414,x,f)}function b7(x,f){return K(415,x,f)}function V7(x,f){return K(416,x,f)}function Z7(x,f){return K(417,x,f)}function q7(x,f){return K(418,x,f)}function w7(x,f){return K(421,x,f)}function B7(x,f){return K(422,x,f)}function k7(x,f){return K(423,x,f)}function N7(x,f){return K(424,x,f)}function L7(x,f){return K(425,x,f)}function R7(x,f){return K(426,x,f)}function _7(x,f){return K(428,x,f)}function I7(x,f){return K(429,x,f)}function P7(x,f){return K(431,x,f)}function A7(x,f){return K(451,x,f)}function H(x,f,y){if(typeof f==="string")return G({...y,statusCode:x,message:f});return G({...f,...y,statusCode:x})}function D7(x,f){return H(500,x,f)}function v7(x,f){return H(501,x,f)}function z7(x,f){return H(502,x,f)}function T7(x,f){return H(503,x,f)}function C7(x,f){return H(504,x,f)}function l7(x,f){return H(505,x,f)}function W7(x,f){return H(506,x,f)}function h7(x,f){return H(507,x,f)}function S7(x,f){return H(508,x,f)}function d7(x,f){return H(510,x,f)}function E7(x,f){return H(511,x,f)}function u7(x,f){let y=typeof x==="string"?{...f,message:x}:{...x,...f},M={isDeveloperError:!0,...y.data||{}};return G({...y,statusCode:500,data:M})}function F(x){return(f,y)=>{if(!f.success&&"error"in f&&f.error instanceof C){let M=B(f.error);throw A({message:x?.message||"Validation Error",data:M,formatter:x?.formatter,headers:x?.headers,sanitize:x?.sanitize,includeStackTrace:x?.includeStackTrace})}}}var l=F();var w={formatter:I,sanitize:[],includeStackTrace:!1,headers:{}};function k(x={}){let f={...w,...x,formatter:x.formatter?x.formatter:w.formatter,headers:{...w.headers,...x.headers},sanitize:[...w.sanitize,...x.sanitize||[]]};return async(y,M)=>{try{await M()}catch(Q){let $=f.formatter,J=L(Q,{formatter:$,headers:f.headers,sanitize:f.sanitize,includeStackTrace:f.includeStackTrace}),X=R(J,$,{headers:f.headers,sanitize:f.sanitize,includeStackTrace:f.includeStackTrace});return _(J,X)}}}var Jx=k;export{W7 as variantAlsoNegotiates,$7 as uriTooLong,R7 as upgradeRequired,b7 as unsupportedMediaType,o as unauthorized,I7 as tooManyRequests,L7 as tooEarly,q7 as teapot,T7 as serverUnavailable,l as rfc7807Hook,J7 as resourceGone,V7 as rangeNotSatisfiable,j7 as proxyAuthRequired,_7 as preconditionRequired,X7 as preconditionFailed,x7 as paymentRequired,v7 as notImplemented,y7 as notFound,d7 as notExtended,M7 as notAcceptable,E7 as networkAuthRequired,w7 as misdirectedRequest,K7 as methodNotAllowed,S7 as loopDetected,k7 as locked,Q7 as lengthRequired,D as isBanError,D7 as internal,h7 as insufficientStorage,A7 as illegal,l7 as httpVersionNotSupported,P7 as headerFieldsTooLarge,C7 as gatewayTimeout,R as formatError,f7 as forbidden,N7 as failedDependency,Z7 as expectationFailed,Y7 as entityTooLarge,I as defaultFormatter,Jx as default,B as createRFC7807ZodValidationError,z as createRFC7807ValidationError,F as createRFC7807Hook,v as createRFC7807Formatter,T as createRFC7807ConstraintViolation,_ as createErrorResponse,G as createError,L as convertToBanError,H7 as conflict,G7 as clientTimeout,A as badRequest,u7 as badImplementation,z7 as badGateway,B7 as badData,Y as STATUS_CODES,b as RFC7807ValidationParamSchema,P as RFC7807ErrorDataSchema,V as RFC7807DetailsSchema,q as RFC7807ConstraintViolationSchema};
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { BanError, DefaultErrorOutput, Headers } from "../../types";
|
|
6
6
|
/**
|
|
7
|
-
* Default JSON formatter
|
|
7
|
+
* Default JSON formatter with a clean, flat structure
|
|
8
8
|
*/
|
|
9
9
|
export declare const defaultFormatter: {
|
|
10
10
|
contentType: string;
|
|
@@ -6,27 +6,25 @@ import type { BanError } from "./error";
|
|
|
6
6
|
import type { Headers } from "./common";
|
|
7
7
|
/**
|
|
8
8
|
* Default error output structure
|
|
9
|
+
*
|
|
10
|
+
* A simple, flat structure for error responses that follows common API practices
|
|
11
|
+
* while remaining minimal and extensible.
|
|
9
12
|
*/
|
|
10
13
|
export interface DefaultErrorOutput {
|
|
11
14
|
/** HTTP status code */
|
|
12
15
|
statusCode: number;
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/** Additional error data */
|
|
26
|
-
data?: unknown;
|
|
27
|
-
/** Any other properties */
|
|
28
|
-
[key: string]: unknown;
|
|
29
|
-
};
|
|
16
|
+
/** Error name from status code */
|
|
17
|
+
error: string;
|
|
18
|
+
/** Error message if provided */
|
|
19
|
+
message?: string;
|
|
20
|
+
/** Stack trace if enabled */
|
|
21
|
+
stack?: string;
|
|
22
|
+
/** Cause stack trace if available */
|
|
23
|
+
causeStack?: string;
|
|
24
|
+
/** Additional error data */
|
|
25
|
+
data?: unknown;
|
|
26
|
+
/** Any other properties */
|
|
27
|
+
[key: string]: unknown;
|
|
30
28
|
}
|
|
31
29
|
/**
|
|
32
30
|
* Error formatter interface
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono-ban",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "HTTP-friendly error objects for Hono, inspired by Boom",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/esm/index.js",
|
|
7
7
|
"types": "dist/types/index.d.ts",
|
|
8
8
|
"files": [
|
|
9
9
|
"dist/*",
|
|
10
|
-
"LICENSE.md"
|
|
10
|
+
"LICENSE.md",
|
|
11
|
+
"README.md"
|
|
11
12
|
],
|
|
12
13
|
"exports": {
|
|
13
14
|
".": {
|