elysia
Version:
Ergonomic Framework for Human
326 lines (323 loc) • 9.45 kB
JavaScript
// src/error.ts
import { Value } from "@sinclair/typebox/value";
// src/utils.ts
var hasHeaderShorthand = "toJSON" in new Headers();
var primitiveHooks = [
"start",
"request",
"parse",
"transform",
"resolve",
"beforeHandle",
"afterHandle",
"mapResponse",
"afterResponse",
"trace",
"error",
"stop",
"body",
"headers",
"params",
"query",
"response",
"type",
"detail"
], primitiveHookMap = primitiveHooks.reduce(
(acc, x) => (acc[x] = !0, acc),
{}
);
var isBun2 = typeof Bun < "u", hasBunHash = isBun2 && typeof Bun.hash == "function";
var StatusMap = {
Continue: 100,
"Switching Protocols": 101,
Processing: 102,
"Early Hints": 103,
OK: 200,
Created: 201,
Accepted: 202,
"Non-Authoritative Information": 203,
"No Content": 204,
"Reset Content": 205,
"Partial Content": 206,
"Multi-Status": 207,
"Already Reported": 208,
"Multiple Choices": 300,
"Moved Permanently": 301,
Found: 302,
"See Other": 303,
"Not Modified": 304,
"Temporary Redirect": 307,
"Permanent Redirect": 308,
"Bad Request": 400,
Unauthorized: 401,
"Payment Required": 402,
Forbidden: 403,
"Not Found": 404,
"Method Not Allowed": 405,
"Not Acceptable": 406,
"Proxy Authentication Required": 407,
"Request Timeout": 408,
Conflict: 409,
Gone: 410,
"Length Required": 411,
"Precondition Failed": 412,
"Payload Too Large": 413,
"URI Too Long": 414,
"Unsupported Media Type": 415,
"Range Not Satisfiable": 416,
"Expectation Failed": 417,
"I'm a teapot": 418,
"Misdirected Request": 421,
"Unprocessable Content": 422,
Locked: 423,
"Failed Dependency": 424,
"Too Early": 425,
"Upgrade Required": 426,
"Precondition Required": 428,
"Too Many Requests": 429,
"Request Header Fields Too Large": 431,
"Unavailable For Legal Reasons": 451,
"Internal Server Error": 500,
"Not Implemented": 501,
"Bad Gateway": 502,
"Service Unavailable": 503,
"Gateway Timeout": 504,
"HTTP Version Not Supported": 505,
"Variant Also Negotiates": 506,
"Insufficient Storage": 507,
"Loop Detected": 508,
"Not Extended": 510,
"Network Authentication Required": 511
}, InvertedStatusMap = Object.fromEntries(
Object.entries(StatusMap).map(([k, v]) => [v, k])
);
var encoder = new TextEncoder();
var ELYSIA_FORM_DATA = Symbol("ElysiaFormData"), ELYSIA_REQUEST_ID = Symbol("ElysiaRequestId");
var supportPerMethodInlineHandler = (() => {
if (typeof Bun > "u") return !0;
let semver = Bun.version.split(".");
return !(+semver[0] < 1 || +semver[1] < 2 || +semver[2] < 14);
})();
// src/error.ts
var env = typeof Bun < "u" ? Bun.env : typeof process < "u" ? process?.env : void 0, ERROR_CODE = Symbol("ElysiaErrorCode"), isProduction = (env?.NODE_ENV ?? env?.ENV) === "production", emptyHttpStatus = {
101: void 0,
204: void 0,
205: void 0,
304: void 0,
307: void 0,
308: void 0
}, ElysiaCustomStatusResponse = class {
constructor(code, response) {
let res = response ?? (code in InvertedStatusMap ? (
// @ts-expect-error Always correct
InvertedStatusMap[code]
) : code);
this.code = StatusMap[code] ?? code, code in emptyHttpStatus ? this.response = void 0 : this.response = res;
}
}, status = (code, response) => new ElysiaCustomStatusResponse(code, response), error = status, InternalServerError = class extends Error {
constructor(message) {
super(message ?? "INTERNAL_SERVER_ERROR");
this.code = "INTERNAL_SERVER_ERROR";
this.status = 500;
}
}, NotFoundError = class extends Error {
constructor(message) {
super(message ?? "NOT_FOUND");
this.code = "NOT_FOUND";
this.status = 404;
}
}, ParseError = class extends Error {
constructor(cause) {
super("Bad Request", {
cause
});
this.code = "PARSE";
this.status = 400;
}
}, InvalidCookieSignature = class extends Error {
constructor(key, message) {
super(message ?? `"${key}" has invalid cookie signature`);
this.key = key;
this.code = "INVALID_COOKIE_SIGNATURE";
this.status = 400;
}
}, mapValueError = (error2) => {
if (!error2)
return {
summary: void 0
};
let { message, path, value, type } = error2, property = path.slice(1).replaceAll("/", "."), isRoot = path === "";
switch (type) {
case 42:
return {
...error2,
summary: isRoot ? "Value should not be provided" : `Property '${property}' should not be provided`
};
case 45:
return {
...error2,
summary: isRoot ? "Value is missing" : `Property '${property}' is missing`
};
case 50:
let quoteIndex = message.indexOf("'"), format = message.slice(
quoteIndex + 1,
message.indexOf("'", quoteIndex + 1)
);
return {
...error2,
summary: isRoot ? "Value should be an email" : `Property '${property}' should be ${format}`
};
case 54:
return {
...error2,
summary: `${message.slice(0, 9).trim()} property '${property}' to be ${message.slice(8).trim()} but found: ${value}`
};
case 62:
let union = error2.schema.anyOf.map((x) => `'${x?.format ?? x.type}'`).join(", ");
return {
...error2,
summary: isRoot ? `Value should be one of ${union}` : `Property '${property}' should be one of: ${union}`
};
default:
return { summary: message, ...error2 };
}
}, InvalidFileType = class _InvalidFileType extends Error {
constructor(property, expected, message = `"${property}" has invalid file type`) {
super(message);
this.property = property;
this.expected = expected;
this.message = message;
this.code = "INVALID_FILE_TYPE";
this.status = 422;
Object.setPrototypeOf(this, _InvalidFileType.prototype);
}
toResponse(headers) {
return isProduction ? new Response(
JSON.stringify({
type: "validation",
on: "body"
}),
{
status: 422,
headers: {
...headers,
"content-type": "application/json"
}
}
) : new Response(
JSON.stringify({
type: "validation",
on: "body",
summary: "Invalid file type",
message: this.message,
property: this.property,
expected: this.expected
}),
{
status: 422,
headers: {
...headers,
"content-type": "application/json"
}
}
);
}
}, ValidationError = class _ValidationError extends Error {
constructor(type, validator, value, errors) {
value && typeof value == "object" && value instanceof ElysiaCustomStatusResponse && (value = value.response);
let error2 = errors?.First() || (isProduction ? void 0 : "Errors" in validator ? validator.Errors(value).First() : Value.Errors(validator, value).First()), customError = error2?.schema?.message || error2?.schema?.error !== void 0 ? typeof error2.schema.error == "function" ? error2.schema.error({
type,
validator,
value,
get errors() {
return [...validator.Errors(value)].map(
mapValueError
);
}
}) : error2.schema.error : void 0, accessor = error2?.path || "root", message = "";
if (customError !== void 0)
message = typeof customError == "object" ? JSON.stringify(customError) : customError + "";
else if (isProduction)
message = JSON.stringify({
type: "validation",
on: type,
summary: mapValueError(error2).summary,
message: error2?.message,
found: value
});
else {
let schema = validator?.schema ?? validator, errors2 = "Errors" in validator ? [...validator.Errors(value)].map(mapValueError) : [...Value.Errors(validator, value)].map(mapValueError), expected;
try {
expected = Value.Create(schema);
} catch (error3) {
expected = {
type: "Could not create expected value",
// @ts-expect-error
message: error3?.message,
error: error3
};
}
message = JSON.stringify(
{
type: "validation",
on: type,
summary: mapValueError(error2).summary,
property: accessor,
message: error2?.message,
expected,
found: value,
errors: errors2
},
null,
2
);
}
super(message);
this.type = type;
this.validator = validator;
this.value = value;
this.code = "VALIDATION";
this.status = 422;
Object.setPrototypeOf(this, _ValidationError.prototype);
}
get all() {
return "Errors" in this.validator ? [...this.validator.Errors(this.value)].map(mapValueError) : (
// @ts-ignore
[...Value.Errors(this.validator, this.value)].map(mapValueError)
);
}
static simplifyModel(validator) {
let model = "schema" in validator ? validator.schema : validator;
try {
return Value.Create(model);
} catch {
return model;
}
}
get model() {
return _ValidationError.simplifyModel(this.validator);
}
toResponse(headers) {
return new Response(this.message, {
status: 400,
headers: {
...headers,
"content-type": "application/json"
}
});
}
};
export {
ERROR_CODE,
ElysiaCustomStatusResponse,
InternalServerError,
InvalidCookieSignature,
InvalidFileType,
NotFoundError,
ParseError,
ValidationError,
error,
isProduction,
mapValueError,
status
};