hono-ban 0.2.4 → 0.2.6

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.
Files changed (47) hide show
  1. package/dist/esm/formatters/index.js +1 -0
  2. package/dist/esm/index.js +1 -311
  3. package/package.json +9 -24
  4. package/dist/cjs/formatters/rfc7807/index.js +0 -364
  5. package/dist/cjs/formatters/rfc7807/index.js.map +0 -16
  6. package/dist/cjs/index.js +0 -271
  7. package/dist/cjs/index.js.map +0 -16
  8. package/dist/esm/formatters/rfc7807/index.js +0 -333
  9. package/dist/esm/formatters/rfc7807/index.js.map +0 -16
  10. package/dist/esm/index.js.map +0 -16
  11. package/src/__tests__/core/convert-error.test.ts +0 -158
  12. package/src/__tests__/core/create-error.test.ts +0 -113
  13. package/src/__tests__/core/format-error.test.ts +0 -162
  14. package/src/__tests__/factories/factories.test.ts +0 -380
  15. package/src/__tests__/formatters/default-formatter.test.ts +0 -117
  16. package/src/__tests__/middleware/README.md +0 -49
  17. package/src/__tests__/middleware/ban-middleware.test.ts.disabled +0 -23
  18. package/src/__tests__/utils/sanitize.test.ts +0 -117
  19. package/src/__tests__/utils/validate.test.ts +0 -35
  20. package/src/constants/index.ts +0 -6
  21. package/src/constants/status-codes.ts +0 -52
  22. package/src/core/convert-error.ts +0 -74
  23. package/src/core/create-error.ts +0 -65
  24. package/src/core/format-error.ts +0 -76
  25. package/src/core/index.ts +0 -8
  26. package/src/factories/client-errors.ts +0 -492
  27. package/src/factories/index.ts +0 -7
  28. package/src/factories/server-errors.ts +0 -230
  29. package/src/formatters/default/index.ts +0 -72
  30. package/src/formatters/index.ts +0 -13
  31. package/src/formatters/interfaces.ts +0 -7
  32. package/src/formatters/rfc7807/formatter.ts +0 -105
  33. package/src/formatters/rfc7807/hooks.ts +0 -73
  34. package/src/formatters/rfc7807/index.ts +0 -20
  35. package/src/formatters/rfc7807/schemas.ts +0 -88
  36. package/src/index.ts +0 -23
  37. package/src/middleware/ban-middleware.ts +0 -77
  38. package/src/middleware/index.ts +0 -6
  39. package/src/types/common.ts +0 -14
  40. package/src/types/error.ts +0 -46
  41. package/src/types/formatter.ts +0 -61
  42. package/src/types/index.ts +0 -11
  43. package/src/types/options.ts +0 -71
  44. package/src/types/rfc7807.ts +0 -93
  45. package/src/utils/index.ts +0 -7
  46. package/src/utils/sanitize.ts +0 -34
  47. package/src/utils/validate.ts +0 -24
@@ -1,16 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/constants/status-codes.ts", "../../src/formatters/rfc7807/schemas.ts", "../../src/formatters/rfc7807/formatter.ts", "../../src/formatters/rfc7807/hooks.ts", "../../src/utils/validate.ts", "../../src/core/create-error.ts", "../../src/factories/client-errors.ts"],
4
- "sourcesContent": [
5
- "/**\n * HTTP status code constants\n * @module hono-ban/constants/status-codes\n */\n\nimport type { ErrorStatusCode } from \"../types/error\";\n\n/**\n * Map of HTTP error status codes to their default messages\n */\nexport const STATUS_CODES: Record<ErrorStatusCode, string> = {\n 400: \"Bad Request\",\n 401: \"Unauthorized\",\n 402: \"Payment Required\",\n 403: \"Forbidden\",\n 404: \"Not Found\",\n 405: \"Method Not Allowed\",\n 406: \"Not Acceptable\",\n 407: \"Proxy Authentication Required\",\n 408: \"Request Timeout\",\n 409: \"Conflict\",\n 410: \"Gone\",\n 411: \"Length Required\",\n 412: \"Precondition Failed\",\n 413: \"Payload Too Large\",\n 414: \"URI Too Long\",\n 415: \"Unsupported Media Type\",\n 416: \"Range Not Satisfiable\",\n 417: \"Expectation Failed\",\n 418: \"I'm a teapot\",\n 421: \"Misdirected Request\",\n 422: \"Unprocessable Entity\",\n 423: \"Locked\",\n 424: \"Failed Dependency\",\n 425: \"Too Early\",\n 426: \"Upgrade Required\",\n 428: \"Precondition Required\",\n 429: \"Too Many Requests\",\n 431: \"Request Header Fields Too Large\",\n 451: \"Unavailable For Legal Reasons\",\n 500: \"Internal Server Error\",\n 501: \"Not Implemented\",\n 502: \"Bad Gateway\",\n 503: \"Service Unavailable\",\n 504: \"Gateway Timeout\",\n 505: \"HTTP Version Not Supported\",\n 506: \"Variant Also Negotiates\",\n 507: \"Insufficient Storage\",\n 508: \"Loop Detected\",\n 510: \"Not Extended\",\n 511: \"Network Authentication Required\",\n};\n",
6
- "/**\n * Zod schemas for RFC 7807 Problem Details\n * @module hono-ban/formatters/rfc7807/schemas\n */\n\nimport { z } from \"@hono/zod-openapi\";\n\n/**\n * Schema for RFC 7807 validation error parameters\n */\nexport const RFC7807ValidationParamSchema = z.object({\n name: z.string().openapi({\n example: \"username\",\n description: \"The field name that failed validation\",\n }),\n reason: z.string().openapi({\n example: \"String must contain at least 3 character(s)\",\n description: \"The reason for validation failure\",\n }),\n});\n\n/**\n * Schema for RFC 7807 constraint violations\n */\nexport const RFC7807ConstraintViolationSchema = z.object({\n name: z.string().openapi({\n example: \"email\",\n description: \"The field name that violated a constraint\",\n }),\n reason: z.string().openapi({\n example: \"Email already exists\",\n description: \"The reason for the constraint violation\",\n }),\n resource: z.string().openapi({\n example: \"user\",\n description: \"The resource type that contains the constraint\",\n }),\n constraint: z.string().openapi({\n example: \"unique\",\n description: \"The type of constraint that was violated\",\n }),\n});\n\n/**\n * Schema for additional error data in RFC 7807 problem details\n */\nexport const RFC7807ErrorDataSchema = z.object({\n \"invalid-params\": z.array(RFC7807ValidationParamSchema).optional(),\n violations: z.array(RFC7807ConstraintViolationSchema).optional(),\n});\n\n/**\n * Schema for complete RFC 7807 problem details\n */\nexport const RFC7807DetailsSchema = z\n .object({\n type: z.string().url().openapi({\n example: \"https://api.example.com/problems/validation-error\",\n description: \"A URI reference that identifies the problem type\",\n }),\n title: z.string().openapi({\n example: \"Validation Failed\",\n description: \"A short, human-readable summary of the problem type\",\n }),\n status: z.number().int().min(400).max(599).openapi({\n example: 400,\n description: \"The HTTP status code\",\n }),\n\n // Optional fields per RFC7807\n detail: z.string().optional().openapi({\n example: \"The request contains invalid fields\",\n description:\n \"A human-readable explanation specific to this occurrence of the problem\",\n }),\n instance: z.string().url().optional().openapi({\n example: \"urn:uuid:6b56944d-5e89-4b4d-9ca7-c1be3d1f0e3f\",\n description:\n \"A URI reference that identifies the specific occurrence of the problem\",\n }),\n\n // Extensions for validation errors\n timestamp: z.string().datetime().optional().openapi({\n example: \"2025-02-26T12:34:56.789Z\",\n description: \"When the error occurred\",\n }),\n })\n .merge(RFC7807ErrorDataSchema);\n",
7
- "/**\n * RFC 7807 Problem Details formatter implementation\n * @module hono-ban/formatters/rfc7807/formatter\n */\n\nimport { z } from \"@hono/zod-openapi\";\nimport { STATUS_CODES } from \"../../constants\";\nimport type { BanError, ErrorFormatter } from \"../../types\";\nimport type {\n RFC7807Details,\n RFC7807ErrorData,\n RFC7807ValidationParam,\n RFC7807FormatterOptions as RFC7807Options,\n} from \"../../types\";\nimport {\n RFC7807ConstraintViolationSchema,\n RFC7807DetailsSchema,\n RFC7807ValidationParamSchema,\n} from \"./schemas\";\n\n/**\n * Create an RFC 7807 Problem Details formatter\n */\nexport function createRFC7807Formatter(\n options: RFC7807Options = {}\n): ErrorFormatter {\n const baseUrl = options.baseUrl || \"https://api.example.com/problems\";\n\n return {\n contentType: \"application/problem+json\",\n\n format<T extends RFC7807ErrorData>(error: BanError<T>): RFC7807Details {\n const base = {\n type: `${baseUrl}/${error.status}`,\n title: STATUS_CODES[error.status] || \"Unknown Error\",\n status: error.status,\n detail: error.message,\n instance: `urn:uuid:${crypto.randomUUID()}`,\n timestamp: new Date().toISOString(),\n };\n\n // Handle validation errors\n if (error.data?.[\"invalid-params\"]) {\n return RFC7807DetailsSchema.parse({\n ...base,\n \"invalid-params\": error.data[\"invalid-params\"],\n });\n }\n\n // Handle constraint violations\n if (error.data?.violations) {\n return RFC7807DetailsSchema.parse({\n ...base,\n violations: error.data.violations,\n });\n }\n\n return RFC7807DetailsSchema.parse(base);\n },\n };\n}\n\n/**\n * Create validation error data in RFC 7807 format\n */\nexport function createRFC7807ValidationError(params: RFC7807ValidationParam[]) {\n return {\n \"invalid-params\": RFC7807ValidationParamSchema.array().parse(params),\n };\n}\n\n/**\n * Convert Zod validation errors to RFC 7807 format\n */\nexport function createRFC7807ZodValidationError(error: z.ZodError) {\n return {\n \"invalid-params\": RFC7807ValidationParamSchema.array().parse(\n error.errors.map((e) => ({\n name: e.path.join(\".\"),\n reason: e.message,\n }))\n ),\n };\n}\n\n/**\n * Create constraint violation data in RFC 7807 format\n */\nexport function createRFC7807ConstraintViolation(\n name: string,\n reason: string,\n resource: string,\n constraint: string = \"unique\"\n) {\n return {\n violations: RFC7807ConstraintViolationSchema.array().parse([\n {\n name,\n reason,\n resource,\n constraint,\n },\n ]),\n };\n}\n",
8
- "/**\n * RFC 7807 Problem Details hooks for Hono applications\n * @module hono-ban/formatters/rfc7807/hooks\n */\n\nimport { ZodError } from \"zod\";\nimport { Hook } from \"@hono/zod-openapi\";\nimport { Env } from \"hono\";\nimport { badRequest } from \"../../factories\";\nimport type {\n RFC7807FormatterOptions as RFC7807Options,\n BanOptions,\n} from \"../../types\";\nimport { createRFC7807ZodValidationError } from \"./formatter\";\n\n/**\n * Create a Hono hook that formats validation errors using RFC 7807\n *\n * This hook throws a badRequest error that will be caught and processed by the ban middleware.\n * You can provide options to override the default behavior of the middleware.\n *\n * @example\n * // Basic usage - inherits all settings from middleware\n * app.openapi(route, handler, { onError: createRFC7807Hook() });\n *\n * @example\n * // With custom message\n * app.openapi(route, handler, {\n * onError: createRFC7807Hook({ message: \"Custom validation error\" })\n * });\n *\n * @example\n * // With custom formatter and sanitization\n * app.openapi(route, handler, {\n * onError: createRFC7807Hook({\n * formatter: customFormatter,\n * sanitize: ['password', 'token']\n * })\n * });\n */\nexport function createRFC7807Hook<E extends Env = Env>(\n options?: RFC7807Options & Partial<BanOptions>\n): Hook<any, E, any, any> {\n return (result, c) => {\n if (\n !result.success &&\n \"error\" in result &&\n result.error instanceof ZodError\n ) {\n // Create the validation error data\n const validationData = createRFC7807ZodValidationError(result.error);\n\n // Throw badRequest with both the validation data and any override options\n throw badRequest({\n message: options?.message || \"Validation Error\",\n data: validationData,\n // Pass through any override options\n formatter: options?.formatter,\n headers: options?.headers,\n sanitize: options?.sanitize,\n includeStackTrace: options?.includeStackTrace,\n });\n }\n };\n}\n\n/**\n * Pre-configured RFC 7807 hook with default options\n *\n * This is a convenience export that uses the default options.\n * It will throw a badRequest error that will be caught and processed by the ban middleware.\n */\nexport const rfc7807Hook = createRFC7807Hook<Env>();\n",
9
- "/**\n * Validation utilities\n * @module hono-ban/utils/validate\n */\n\nimport type { ErrorStatusCode } from \"../types/error\";\n\n/**\n * Validate and normalize HTTP error status code\n * @param code - Status code to validate\n */\nexport function validateStatusCode(code: number): ErrorStatusCode {\n // Handle invalid inputs\n if (typeof code !== \"number\" || isNaN(code)) {\n return 500;\n }\n\n // Ensure code is in error range\n if (code < 400 || code >= 600) {\n return 500;\n }\n\n return code as ErrorStatusCode;\n}\n",
10
- "/**\n * Error creation utilities\n * @module hono-ban/core/create-error\n */\n\nimport { STATUS_CODES } from \"../constants/status-codes\";\nimport type { BanError, BanOptions } from \"../types\";\nimport { validateStatusCode } from \"../utils/validate\";\n\n/**\n * Create a new error object with the given options\n * @param options - Error creation options\n * @returns A BanError object\n *\n * @example\n * // Basic usage\n * const error = createError({ statusCode: 404, message: \"User not found\" });\n *\n * @example\n * // With custom data\n * const error = createError({\n * statusCode: 400,\n * message: \"Validation failed\",\n * data: { field: \"email\", issue: \"invalid format\" }\n * });\n */\nexport function createError<T = unknown>(options: BanOptions<T>): BanError<T> {\n // Validate and normalize status code\n const status = validateStatusCode(options.statusCode ?? 500);\n\n // Create the error object\n const error: BanError<T> = {\n status,\n message: options.message ?? STATUS_CODES[status],\n isBan: true,\n };\n\n // Add optional properties\n if (options.data !== undefined) {\n error.data = options.data;\n }\n\n if (options.headers) {\n error.headers = { ...options.headers };\n }\n\n if (options.allow) {\n error.allow = Array.isArray(options.allow)\n ? [...options.allow]\n : [options.allow];\n }\n\n if (options.cause) {\n error.cause = options.cause;\n // Keep cause stack separately rather than overwriting the main stack\n if (options.cause instanceof Error) {\n error.causeStack = options.cause.stack;\n }\n }\n\n // Always capture a fresh stack trace for the BanError itself\n Error.captureStackTrace(error, createError);\n\n return error;\n}\n",
11
- "/**\n * Client error factory functions (4xx)\n * @module hono-ban/factories/client-errors\n */\n\nimport type { BanError, BanOptions, ErrorStatusCode } from \"../types\";\nimport { createError } from \"../core\";\n\n/**\n * Helper function to reduce duplication\n * @param statusCode - HTTP status code\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nfunction createErrorWithStatus<T>(\n statusCode: ErrorStatusCode,\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n if (typeof messageOrOptions === \"string\") {\n return createError<T>({\n ...options,\n statusCode,\n message: messageOrOptions,\n });\n }\n return createError<T>({ ...messageOrOptions, ...options, statusCode });\n}\n\n/**\n * Create a 400 Bad Request error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function badRequest<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 400 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 401 Unauthorized error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function unauthorized<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 401 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 402 Payment Required error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function paymentRequired<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 402 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 403 Forbidden error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function forbidden<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 403 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 404 Not Found error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function notFound<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 404 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 405 Method Not Allowed error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function methodNotAllowed<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 405 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 406 Not Acceptable error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function notAcceptable<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 406 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 407 Proxy Authentication Required error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function proxyAuthRequired<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 407 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 408 Request Timeout error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function clientTimeout<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 408 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 409 Conflict error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function conflict<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 409 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 410 Gone error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function resourceGone<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 410 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 411 Length Required error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function lengthRequired<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 411 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 412 Precondition Failed error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function preconditionFailed<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 412 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 413 Payload Too Large error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function entityTooLarge<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 413 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 414 URI Too Long error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function uriTooLong<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 414 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 415 Unsupported Media Type error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function unsupportedMediaType<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 415 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 416 Range Not Satisfiable error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function rangeNotSatisfiable<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 416 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 417 Expectation Failed error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function expectationFailed<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 417 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 418 I'm a Teapot error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function teapot<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 418 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 421 Misdirected Request error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function misdirectedRequest<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 421 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 422 Unprocessable Entity error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function badData<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 422 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 423 Locked error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function locked<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 423 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 424 Failed Dependency error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function failedDependency<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 424 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 425 Too Early error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function tooEarly<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 425 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 426 Upgrade Required error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function upgradeRequired<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 426 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 428 Precondition Required error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function preconditionRequired<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 428 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 429 Too Many Requests error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function tooManyRequests<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 429 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 431 Request Header Fields Too Large error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function headerFieldsTooLarge<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 431 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 451 Unavailable For Legal Reasons error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function illegal<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 451 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n"
12
- ],
13
- "mappings": "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ACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,YAAyB,CACvC,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,cAA2B,CACzC,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,kBAA+B,CAC7C,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,cAA2B,CACzC,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,UAAuB,CACrC,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,oBAAiC,CAC/C,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,mBAAgC,CAC9C,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,iBAA8B,CAC5C,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,MAAmB,CACjC,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,kBAA+B,CAC7C,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,OAAoB,CAClC,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,MAAmB,CACjC,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,gBAA6B,CAC3C,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,QAAqB,CACnC,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,eAA4B,CAC1C,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,oBAAiC,CAC/C,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,eAA4B,CAC1C,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,oBAAiC,CAC/C,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;AAQK,SAAS,OAAoB,CAClC,kBACA,SACa;AAAA,EACb,OAAO,sBACL,KACA,kBACA,OACF;AAAA;;;AHlcK,SAAS,iBAAsC,CACpD,SACwB;AAAA,EACxB,OAAO,CAAC,QAAQ,MAAM;AAAA,IACpB,KACG,OAAO,WACR,WAAW,UACX,OAAO,iBAAiB,UACxB;AAAA,MAEA,MAAM,iBAAiB,gCAAgC,OAAO,KAAK;AAAA,MAGnE,MAAM,WAAW;AAAA,QACf,SAAS,SAAS,WAAW;AAAA,QAC7B,MAAM;AAAA,QAEN,WAAW,SAAS;AAAA,QACpB,SAAS,SAAS;AAAA,QAClB,UAAU,SAAS;AAAA,QACnB,mBAAmB,SAAS;AAAA,MAC9B,CAAC;AAAA,IACH;AAAA;AAAA;AAUG,IAAM,cAAc,kBAAuB;",
14
- "debugId": "70213BB604F8C2D564756E2164756E21",
15
- "names": []
16
- }
@@ -1,16 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/core/convert-error.ts", "../../src/core/format-error.ts", "../../src/utils/sanitize.ts", "../../src/formatters/default/index.ts", "../../src/factories/server-errors.ts", "../../src/middleware/ban-middleware.ts", "../../src/index.ts"],
4
- "sourcesContent": [
5
- "/**\n * Error conversion utilities\n * @module hono-ban/core/convert-error\n */\n\nimport type { BanError, BanOptions } from \"../types\";\nimport { createError } from \"./create-error\";\n\n/**\n * Type guard to check if a value is a BanError\n * @param err - Value to check\n * @param statusCode - Optional status code to match\n */\nexport function isBanError(err: unknown, statusCode?: number): err is BanError {\n return (\n typeof err === \"object\" &&\n err !== null &&\n \"isBan\" in err &&\n err.isBan === true &&\n (!statusCode || (err as BanError).status === statusCode)\n );\n}\n\n/**\n * Convert any error into a BanError\n * @param err - Error to convert\n * @param options - Additional options\n */\nexport function convertToBanError<T = unknown>(\n err: unknown,\n options: BanOptions<T> = {}\n): BanError<T> {\n // If already a BanError, merge options\n if (isBanError(err)) {\n const merged: BanError<T> = {\n status: options.statusCode ?? err.status,\n message: options.message ?? err.message,\n isBan: true,\n data: (options.data !== undefined ? options.data : err.data) as\n | T\n | undefined,\n headers: {\n ...err.headers,\n ...options.headers,\n },\n allow: options.allow\n ? Array.isArray(options.allow)\n ? [...options.allow]\n : [options.allow]\n : err.allow,\n cause: options.cause ?? err.cause,\n stack: err.stack,\n };\n\n return merged;\n }\n\n // Convert Error instance\n if (err instanceof Error) {\n return createError<T>({\n ...options,\n message: options.message ?? err.message,\n cause: err,\n });\n }\n\n // Handle unknown error types\n return createError<T>({\n ...options,\n message:\n options.message ?? (typeof err === \"string\" ? err : \"Unknown error\"),\n cause: err,\n });\n}\n",
6
- "/**\n * Error formatting utilities\n * @module hono-ban/core/format-error\n */\n\nimport { STATUS_CODES } from \"../constants\";\nimport type { BanError, ErrorFormatter, FormatOptions } from \"../types\";\n\n/**\n * Format an error using the provided formatter\n * @param error - Error to format\n * @param formatter - Formatter to use\n * @param options - Formatting options\n */\nexport function formatError(\n error: BanError,\n formatter: ErrorFormatter,\n options: FormatOptions = {}\n): unknown {\n // Directly format the error without caching\n return formatter.format(\n error,\n options.headers,\n options.sanitize,\n options.includeStackTrace\n );\n}\n\n/**\n * Create a Response object from a formatted error\n * @param error - Error to create response from\n * @param formatted - Formatted error output\n */\nexport function createErrorResponse(\n error: BanError,\n formatted: unknown\n): Response {\n const headers = new Headers({\n \"Content-Type\": \"application/json\",\n ...error.headers,\n });\n\n if (error.allow?.length) {\n headers.set(\"Allow\", error.allow.join(\", \"));\n }\n\n // Check if this is a developer error in production\n const isDeveloperError =\n error.data &&\n typeof error.data === \"object\" &&\n \"isDeveloperError\" in error.data &&\n error.data.isDeveloperError === true;\n\n // Sanitize developer errors in production\n if (isDeveloperError && process.env.NODE_ENV === \"production\") {\n // Create a sanitized version without sensitive data\n const sanitizedFormatted = {\n statusCode: error.status,\n payload: {\n statusCode: error.status,\n error: STATUS_CODES[error.status],\n message: \"An internal server error occurred\",\n },\n };\n\n return new Response(JSON.stringify(sanitizedFormatted), {\n status: error.status,\n headers,\n });\n }\n\n return new Response(JSON.stringify(formatted), {\n status: error.status,\n headers,\n });\n}\n",
7
- "/**\n * Sanitization utilities\n * @module hono-ban/utils/sanitize\n */\n\n/**\n * Recursively sanitize an object by removing specified keys\n * @param obj - Object to sanitize\n * @param keysToRemove - Keys to remove from object\n */\nexport function sanitizeObject(\n obj: unknown,\n keysToRemove: readonly string[]\n): unknown {\n if (!keysToRemove.length) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => sanitizeObject(item, keysToRemove));\n }\n\n if (obj !== null && typeof obj === \"object\") {\n return Object.entries(obj).reduce((acc, [key, value]) => {\n if (keysToRemove.includes(key)) {\n return acc;\n }\n acc[key] = sanitizeObject(value, keysToRemove);\n return acc;\n }, {} as Record<string, unknown>);\n }\n\n return obj;\n}\n",
8
- "/**\n * Default error formatter implementation\n * @module hono-ban/formatters/default\n */\n\nimport { STATUS_CODES } from \"../../constants\";\nimport type { BanError, DefaultErrorOutput, Headers } from \"../../types\";\nimport { sanitizeObject } from \"../../utils\";\n\n/**\n * Default JSON formatter maintaining backward compatibility\n */\nexport const defaultFormatter = {\n contentType: \"application/json\",\n\n /**\n * Format an error into a standardized output structure\n * @param error - Error to format\n * @param headers - Headers for HTTP response (not included in response body)\n * @param sanitize - Fields to remove from output\n * @param includeStackTrace - Whether to include stack traces\n */\n format(\n error: BanError,\n headers: Headers = {}, // Headers are used for HTTP headers, not included in response body\n sanitize: readonly string[] = [],\n includeStackTrace = false\n ): DefaultErrorOutput {\n const { status, message, data } = error;\n\n // Build base payload\n const payload: DefaultErrorOutput[\"payload\"] = {\n statusCode: status,\n error: STATUS_CODES[status] || \"Unknown Error\",\n };\n\n // Add optional fields\n if (typeof message === \"string\") {\n payload.message = message;\n }\n\n const isDeveloperError =\n data &&\n typeof data === \"object\" &&\n \"isDeveloperError\" in data &&\n data.isDeveloperError === true;\n\n if (includeStackTrace || isDeveloperError) {\n if (error.stack) {\n payload.stack = error.stack;\n }\n if (error.causeStack) {\n payload.causeStack = error.causeStack;\n }\n }\n\n if (data !== undefined) {\n payload.data = data;\n }\n\n // Create output structure\n const output: DefaultErrorOutput = {\n statusCode: status,\n payload: sanitizeObject(\n payload,\n sanitize\n ) as DefaultErrorOutput[\"payload\"],\n };\n\n return output;\n },\n};\n",
9
- "/**\n * Server error factory functions (5xx)\n * @module hono-ban/factories/server-errors\n */\n\nimport type { BanError, BanOptions, ErrorStatusCode } from \"../types\";\nimport { createError } from \"../core\";\n\n/**\n * Helper function to reduce duplication\n * @param statusCode - HTTP status code\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nfunction createErrorWithStatus<T>(\n statusCode: ErrorStatusCode,\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n if (typeof messageOrOptions === \"string\") {\n return createError<T>({\n ...options,\n statusCode,\n message: messageOrOptions,\n });\n }\n return createError<T>({ ...messageOrOptions, ...options, statusCode });\n}\n\n/**\n * Create a 500 Internal Server Error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function internal<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 500 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 501 Not Implemented error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function notImplemented<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 501 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 502 Bad Gateway error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function badGateway<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 502 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 503 Service Unavailable error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function serverUnavailable<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 503 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 504 Gateway Timeout error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function gatewayTimeout<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 504 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 505 HTTP Version Not Supported error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function httpVersionNotSupported<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 505 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 506 Variant Also Negotiates error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function variantAlsoNegotiates<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 506 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 507 Insufficient Storage error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function insufficientStorage<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 507 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 508 Loop Detected error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function loopDetected<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 508 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 510 Not Extended error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function notExtended<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 510 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 511 Network Authentication Required error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function networkAuthRequired<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n return createErrorWithStatus(\n 511 as ErrorStatusCode,\n messageOrOptions,\n options\n );\n}\n\n/**\n * Create a 500 Internal Server Error marked as a developer error\n * @param messageOrOptions - Error message or options\n * @param options - Additional options\n */\nexport function badImplementation<T = unknown>(\n messageOrOptions?: string | Partial<BanOptions<T>>,\n options?: Partial<BanOptions<T>>\n): BanError<T> {\n const mergedOptions =\n typeof messageOrOptions === \"string\"\n ? { ...options, message: messageOrOptions }\n : { ...messageOrOptions, ...options };\n\n const mergedData = {\n isDeveloperError: true,\n ...((mergedOptions.data as Record<string, unknown>) || {}),\n } as unknown as T;\n\n return createError<T>({\n ...mergedOptions,\n statusCode: 500 as ErrorStatusCode,\n data: mergedData,\n });\n}\n",
10
- "/**\n * Error handling middleware\n * @module hono-ban/middleware/ban-middleware\n */\n\nimport type { MiddlewareHandler } from \"hono\";\nimport { convertToBanError, formatError, createErrorResponse } from \"../core\";\nimport { defaultFormatter } from \"../formatters\";\nimport type { BanMiddlewareOptions } from \"../types\";\n\n/**\n * Default middleware options\n */\nconst DEFAULT_OPTIONS: Required<BanMiddlewareOptions> = {\n formatter: defaultFormatter,\n sanitize: [],\n includeStackTrace: false,\n headers: {},\n};\n\n/**\n * Create error handling middleware\n * @param options - Middleware configuration options\n *\n * @example\n * // Simple usage\n * app.use(ban());\n *\n * @example\n * // Advanced usage\n * app.use(ban({\n * formatter: customFormatter,\n * sanitize: ['password', 'token'],\n * includeStackTrace: process.env.NODE_ENV !== 'production'\n * }));\n */\nexport function ban(options: BanMiddlewareOptions = {}): MiddlewareHandler {\n const resolvedOptions: Required<BanMiddlewareOptions> = {\n ...DEFAULT_OPTIONS,\n ...options,\n formatter: options.formatter\n ? options.formatter\n : DEFAULT_OPTIONS.formatter,\n headers: {\n ...DEFAULT_OPTIONS.headers,\n ...options.headers,\n },\n sanitize: [...DEFAULT_OPTIONS.sanitize, ...(options.sanitize || [])],\n };\n\n // Return the middleware function that uses the pre-merged options\n return async (_, next) => {\n try {\n await next();\n } catch (err) {\n // Get the pre-resolved formatter instance\n const formatter = resolvedOptions.formatter;\n\n const error = convertToBanError(err, {\n formatter,\n headers: resolvedOptions.headers,\n sanitize: resolvedOptions.sanitize,\n includeStackTrace: resolvedOptions.includeStackTrace,\n });\n\n // Format the error using pre-resolved options\n const formatted = formatError(error, formatter, {\n headers: resolvedOptions.headers,\n sanitize: resolvedOptions.sanitize,\n includeStackTrace: resolvedOptions.includeStackTrace,\n });\n\n // Create and return response\n return createErrorResponse(error, formatted);\n }\n };\n}\n",
11
- "/**\n * Main entry point for hono-ban\n * @module hono-ban\n */\n\n// Export core functionality\nexport * from \"./core\";\n\n// Export formatters\nexport * from \"./formatters\";\n\n// Export error factories\nexport * from \"./factories\";\n\n// Export constants\nexport * from \"./constants\";\n\n// Export types\nexport * from \"./types\";\n\n// Export middleware as default\nimport { ban } from \"./middleware\";\nexport default ban;\n"
12
- ],
13
- "mappings": "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",
14
- "debugId": "4A7C3F0FCA1780B264756E2164756E21",
15
- "names": []
16
- }
@@ -1,158 +0,0 @@
1
- import { describe, it, expect } from "bun:test";
2
- import { isBanError, convertToBanError } from "../../core/convert-error";
3
- import { createError } from "../../core/create-error";
4
-
5
- describe("isBanError", () => {
6
- it("returns true for valid BanError objects", () => {
7
- const error = createError({ statusCode: 404 });
8
- expect(isBanError(error)).toBe(true);
9
- });
10
-
11
- it("returns false for regular Error objects", () => {
12
- const error = new Error("Regular error");
13
- expect(isBanError(error)).toBe(false);
14
- });
15
-
16
- it("returns false for null values", () => {
17
- expect(isBanError(null)).toBe(false);
18
- });
19
-
20
- it("returns false for undefined values", () => {
21
- expect(isBanError(undefined)).toBe(false);
22
- });
23
-
24
- it("returns false for objects without isBan property", () => {
25
- const obj = { status: 404, message: "Not found" };
26
- expect(isBanError(obj)).toBe(false);
27
- });
28
-
29
- it("returns false for objects with incorrect isBan value", () => {
30
- const obj = { status: 404, message: "Not found", isBan: false };
31
- expect(isBanError(obj)).toBe(false);
32
- });
33
-
34
- it("returns true when statusCode matches", () => {
35
- const error = createError({ statusCode: 404 });
36
- expect(isBanError(error, 404)).toBe(true);
37
- });
38
-
39
- it("returns false when statusCode doesn't match", () => {
40
- const error = createError({ statusCode: 404 });
41
- expect(isBanError(error, 500)).toBe(false);
42
- });
43
- });
44
-
45
- describe("convertToBanError", () => {
46
- it("returns the original error if already a BanError", () => {
47
- const original = createError({ statusCode: 404, message: "Not found" });
48
- const converted = convertToBanError(original);
49
-
50
- expect(converted.status).toBe(404);
51
- expect(converted.message).toBe("Not found");
52
- expect(converted.isBan).toBe(true);
53
- });
54
-
55
- it("converts a standard Error to BanError", () => {
56
- const original = new Error("Standard error");
57
- const converted = convertToBanError(original);
58
-
59
- expect(converted.status).toBe(500);
60
- expect(converted.message).toBe("Standard error");
61
- expect(converted.isBan).toBe(true);
62
- expect(converted.cause).toBe(original);
63
- });
64
-
65
- it("converts a string to BanError", () => {
66
- const converted = convertToBanError("String error");
67
-
68
- expect(converted.status).toBe(500);
69
- expect(converted.message).toBe("String error");
70
- expect(converted.isBan).toBe(true);
71
- });
72
-
73
- it("converts unknown values to BanError with default message", () => {
74
- const converted = convertToBanError(123);
75
-
76
- expect(converted.status).toBe(500);
77
- expect(converted.message).toBe("Unknown error");
78
- expect(converted.isBan).toBe(true);
79
- });
80
-
81
- it("applies custom options when converting", () => {
82
- const original = new Error("Original error");
83
- const converted = convertToBanError(original, {
84
- statusCode: 400,
85
- message: "Custom message",
86
- data: { field: "test" },
87
- });
88
-
89
- expect(converted.status).toBe(400);
90
- expect(converted.message).toBe("Custom message");
91
- expect(converted.data).toEqual({ field: "test" });
92
- expect(converted.cause).toBe(original);
93
- });
94
-
95
- it("merges options with existing BanError", () => {
96
- const original = createError({
97
- statusCode: 404,
98
- message: "Not found",
99
- data: { id: "123" },
100
- headers: { "X-Original": "value" },
101
- });
102
-
103
- const converted = convertToBanError(original, {
104
- statusCode: 400,
105
- message: "Bad request",
106
- data: { field: "test" },
107
- headers: { "X-New": "newvalue" },
108
- });
109
-
110
- expect(converted.status).toBe(400);
111
- expect(converted.message).toBe("Bad request");
112
- expect(converted.data).toEqual({ field: "test" });
113
- expect(converted.headers).toEqual({
114
- "X-Original": "value",
115
- "X-New": "newvalue",
116
- });
117
- });
118
-
119
- it("preserves the original BanError's allow property if not overridden", () => {
120
- const original = createError({
121
- statusCode: 405,
122
- allow: ["GET", "POST"],
123
- });
124
-
125
- const converted = convertToBanError(original, {
126
- statusCode: 400,
127
- });
128
-
129
- expect(converted.allow).toEqual(["GET", "POST"]);
130
- });
131
-
132
- it("overrides the original BanError's allow property when specified", () => {
133
- const original = createError({
134
- statusCode: 405,
135
- allow: ["GET", "POST"],
136
- });
137
-
138
- const converted = convertToBanError(original, {
139
- allow: "PUT",
140
- });
141
-
142
- expect(converted.allow).toEqual(["PUT"]);
143
- });
144
-
145
- it("preserves stack trace from original BanError", () => {
146
- const original = createError({ statusCode: 500 });
147
- const converted = convertToBanError(original);
148
-
149
- // Both should have stack traces
150
- expect(original.stack).toBeDefined();
151
- expect(converted.stack).toBeDefined();
152
-
153
- // If both stacks exist, they should be the same
154
- if (original.stack && converted.stack) {
155
- expect(converted.stack).toBe(original.stack);
156
- }
157
- });
158
- });
@@ -1,113 +0,0 @@
1
- import { describe, it, expect } from "bun:test";
2
- import { createError } from "../../core/create-error";
3
- import { STATUS_CODES } from "../../constants";
4
-
5
- describe("createError", () => {
6
- it("creates a basic error with default 500 status", () => {
7
- const error = createError({});
8
- expect(error.isBan).toBe(true);
9
- expect(error.status).toBe(500);
10
- expect(error.message).toBe(STATUS_CODES[500]);
11
- });
12
-
13
- it("creates an error with a custom message", () => {
14
- const error = createError({ statusCode: 400, message: "custom message" });
15
- expect(error.status).toBe(400);
16
- expect(error.message).toBe("custom message");
17
- });
18
-
19
- it("normalizes invalid status codes to 500", () => {
20
- // @ts-expect-error - Testing invalid status code
21
- const error = createError({ statusCode: 200, message: "message" });
22
- expect(error.status).toBe(500);
23
- expect(error.message).toBe("message");
24
- });
25
-
26
- it("adds optional properties when provided", () => {
27
- const testData = { field: "email", reason: "invalid format" };
28
- const testHeaders = { "X-Custom-Header": "test" };
29
- const testAllow = ["GET", "POST"];
30
-
31
- const error = createError({
32
- statusCode: 400,
33
- message: "Bad Request",
34
- data: testData,
35
- headers: testHeaders,
36
- allow: testAllow,
37
- });
38
-
39
- expect(error.status).toBe(400);
40
- expect(error.message).toBe("Bad Request");
41
- expect(error.data).toEqual(testData);
42
- expect(error.headers).toEqual(testHeaders);
43
- expect(error.allow).toEqual(testAllow);
44
- });
45
-
46
- it("handles string allow value by converting to array", () => {
47
- const error = createError({
48
- statusCode: 405,
49
- allow: "GET",
50
- });
51
-
52
- expect(error.allow).toEqual(["GET"]);
53
- });
54
-
55
- it("captures cause and causeStack from Error instances", () => {
56
- const cause = new Error("Original error");
57
- const error = createError({
58
- statusCode: 500,
59
- cause,
60
- });
61
-
62
- expect(error.cause).toBe(cause);
63
- expect(typeof error.causeStack).toBe("string");
64
- });
65
-
66
- it("captures a stack trace", () => {
67
- const error = createError({});
68
- expect(error.stack).toBeDefined();
69
- });
70
-
71
- it("creates an error with a specific status code", () => {
72
- const error = createError({ statusCode: 404 });
73
- expect(error.status).toBe(404);
74
- expect(error.message).toBe(STATUS_CODES[404]);
75
- });
76
-
77
- it("creates an error with both status code and message", () => {
78
- const error = createError({ statusCode: 403, message: "Forbidden access" });
79
- expect(error.status).toBe(403);
80
- expect(error.message).toBe("Forbidden access");
81
- });
82
-
83
- it("preserves the original headers object", () => {
84
- const headers = { "X-Test": "value" };
85
- const error = createError({ headers });
86
-
87
- // Ensure headers are copied, not referenced
88
- expect(error.headers).toEqual(headers);
89
- expect(error.headers).not.toBe(headers);
90
-
91
- // Modify the original headers
92
- headers["X-Test"] = "modified";
93
-
94
- // Error headers should remain unchanged
95
- expect(error.headers?.["X-Test"]).toBe("value");
96
- });
97
-
98
- it("preserves the original allow array", () => {
99
- const allow = ["GET", "POST"];
100
- const error = createError({ allow });
101
-
102
- // Ensure allow is copied, not referenced
103
- expect(error.allow).toEqual(allow);
104
- expect(error.allow).not.toBe(allow);
105
-
106
- // Modify the original array
107
- allow.push("PUT");
108
-
109
- // Error allow should remain unchanged
110
- expect(error.allow?.length).toBe(2);
111
- expect(error.allow).toEqual(["GET", "POST"]);
112
- });
113
- });
@@ -1,162 +0,0 @@
1
- import { describe, it, expect, mock } from "bun:test";
2
- import { formatError, createErrorResponse } from "../../core/format-error";
3
- import { createError } from "../../core/create-error";
4
- import type { BanError, ErrorFormatter } from "../../types";
5
-
6
- describe("formatError", () => {
7
- it("calls the formatter with the error", () => {
8
- const error = createError({ statusCode: 404, message: "Not found" });
9
-
10
- const mockFormatter: ErrorFormatter = {
11
- contentType: "application/json",
12
- format: mock((err) => ({ formatted: true, status: err.status })),
13
- };
14
-
15
- const result = formatError(error, mockFormatter);
16
-
17
- expect(mockFormatter.format).toHaveBeenCalledWith(
18
- error,
19
- undefined,
20
- undefined,
21
- undefined
22
- );
23
- expect(result).toEqual({ formatted: true, status: 404 });
24
- });
25
-
26
- it("passes options to the formatter", () => {
27
- const error = createError({ statusCode: 500 });
28
- const headers = { "X-Test": "value" };
29
- const sanitize = ["password", "token"];
30
-
31
- const mockFormatter: ErrorFormatter = {
32
- contentType: "application/json",
33
- format: mock(() => ({ formatted: true })),
34
- };
35
-
36
- formatError(error, mockFormatter, {
37
- headers,
38
- sanitize,
39
- includeStackTrace: true,
40
- });
41
-
42
- expect(mockFormatter.format).toHaveBeenCalledWith(
43
- error,
44
- headers,
45
- sanitize,
46
- true
47
- );
48
- });
49
- });
50
-
51
- describe("createErrorResponse", () => {
52
- it("creates a Response with the formatted error", () => {
53
- const error = createError({ statusCode: 400, message: "Bad request" });
54
- const formatted = { statusCode: 400, message: "Bad request" };
55
-
56
- const response = createErrorResponse(error, formatted);
57
-
58
- expect(response).toBeInstanceOf(Response);
59
- expect(response.status).toBe(400);
60
- expect(response.headers.get("Content-Type")).toBe("application/json");
61
- });
62
-
63
- it("includes custom headers from the error", () => {
64
- const error = createError({
65
- statusCode: 400,
66
- headers: { "X-Custom": "value" },
67
- });
68
-
69
- const response = createErrorResponse(error, {});
70
-
71
- expect(response.headers.get("X-Custom")).toBe("value");
72
- });
73
-
74
- it("adds Allow header for errors with allow property", () => {
75
- const error = createError({
76
- statusCode: 405,
77
- allow: ["GET", "POST"],
78
- });
79
-
80
- const response = createErrorResponse(error, {});
81
-
82
- expect(response.headers.get("Allow")).toBe("GET, POST");
83
- });
84
-
85
- it("sanitizes developer errors in production", async () => {
86
- // Mock process.env.NODE_ENV
87
- const originalNodeEnv = process.env.NODE_ENV;
88
- process.env.NODE_ENV = "production";
89
-
90
- try {
91
- const error = createError({
92
- statusCode: 500,
93
- message: "Internal server error with sensitive details",
94
- data: { isDeveloperError: true, sensitiveInfo: "secret" },
95
- });
96
-
97
- const formatted = {
98
- statusCode: 500,
99
- payload: {
100
- message: "Original error message",
101
- data: { sensitiveInfo: "secret" },
102
- },
103
- };
104
-
105
- const response = createErrorResponse(error, formatted);
106
-
107
- // Get the response body as text
108
- const responseText = await response.text();
109
- const body = JSON.parse(responseText) as {
110
- statusCode: number;
111
- payload: {
112
- statusCode: number;
113
- error: string;
114
- message: string;
115
- data?: unknown;
116
- };
117
- };
118
-
119
- // Should use sanitized message
120
- expect(body.payload.message).toBe("An internal server error occurred");
121
- // Should not include sensitive data
122
- expect(body.payload.data).toBeUndefined();
123
- } finally {
124
- // Restore original NODE_ENV
125
- process.env.NODE_ENV = originalNodeEnv;
126
- }
127
- });
128
-
129
- it("preserves the original formatted error in non-production", async () => {
130
- // Mock process.env.NODE_ENV
131
- const originalNodeEnv = process.env.NODE_ENV;
132
- process.env.NODE_ENV = "development";
133
-
134
- try {
135
- const error = createError({
136
- statusCode: 500,
137
- message: "Detailed error",
138
- data: { isDeveloperError: true, details: "stack trace" },
139
- });
140
-
141
- const formatted = {
142
- statusCode: 500,
143
- payload: {
144
- message: "Detailed error",
145
- data: { details: "stack trace" },
146
- },
147
- };
148
-
149
- const response = createErrorResponse(error, formatted);
150
-
151
- // Get the response body as text
152
- const responseText = await response.text();
153
- const responseJson = JSON.parse(responseText);
154
-
155
- // The response body should match the original formatted error
156
- expect(responseJson).toEqual(formatted);
157
- } finally {
158
- // Restore original NODE_ENV
159
- process.env.NODE_ENV = originalNodeEnv;
160
- }
161
- });
162
- });