Add base project files including environment example, license, README, .gitignore, error classes, ESLint config, database modules, texture assets, repositories, routes, schemas, services, and server entry point. This establishes the foundational structure for a Yggdrasil-compatible REST API with modular error handling, database setup, and route organization.
119 lines
3.6 KiB
JavaScript
119 lines
3.6 KiB
JavaScript
const DefaultError = require("./DefaultError")
|
|
const YggdrasilError = require("./YggdrasilError")
|
|
const SessionError = require("./SessionError")
|
|
const ServiceError = require("./ServiceError")
|
|
const logger = require("../modules/logger")
|
|
|
|
class ValidationError extends DefaultError {
|
|
constructor(result, config = {}, context = {}) {
|
|
let formattedErrors = []
|
|
if (result && result.error && Array.isArray(result.error.issues)) {
|
|
formattedErrors = result.error.issues.flatMap(issue => {
|
|
if (issue.code === "unrecognized_keys") {
|
|
return issue.keys.map(key => ({
|
|
field: [...issue.path, key].join("."),
|
|
message: "Field not allowed"
|
|
}))
|
|
}
|
|
|
|
if (issue.code === "invalid_union") {
|
|
return {
|
|
field: issue.path.join("."),
|
|
message: "Invalid input format (union mismatch)"
|
|
}
|
|
}
|
|
|
|
return {
|
|
field: issue.path.join("."),
|
|
message: issue.message
|
|
}
|
|
})
|
|
}
|
|
else if (result instanceof Error) {
|
|
formattedErrors = [{
|
|
field: "global",
|
|
message: result.message
|
|
}]
|
|
}
|
|
else if (typeof result === "string") {
|
|
formattedErrors = [{
|
|
field: "global",
|
|
message: result
|
|
}]
|
|
}
|
|
else {
|
|
formattedErrors = [{
|
|
field: "unknown",
|
|
message: "Unknown validation error"
|
|
}]
|
|
}
|
|
|
|
const message = config.message || "Validation failed"
|
|
const statusCode = config.code || 400
|
|
|
|
super(statusCode, message, { errors: formattedErrors })
|
|
|
|
this.config = config
|
|
this.formattedErrors = formattedErrors
|
|
this.context = context
|
|
|
|
this.logError()
|
|
}
|
|
|
|
logError() {
|
|
const { method, path, ip } = this.context
|
|
if (method && path) {
|
|
logger.warn(
|
|
`Validation failed for ${method} ${path} (${this.config.errorFormat || "Standard"}) ` +
|
|
`<IP:${ip || "Unknown"}>`,
|
|
["WEB", "yellow"]
|
|
)
|
|
}
|
|
}
|
|
|
|
serialize() {
|
|
if (this.config.errorFormat === "YggdrasilError") {
|
|
const err = new YggdrasilError(
|
|
this.code,
|
|
this.config.errorName || "IllegalArgumentException",
|
|
this.message,
|
|
JSON.stringify(this.formattedErrors)
|
|
)
|
|
return err.serialize()
|
|
}
|
|
|
|
if (this.config.errorFormat === "SessionError") {
|
|
const err = new SessionError(
|
|
this.code,
|
|
this.config.errorName || "Forbidden",
|
|
this.message,
|
|
this.context.path || ""
|
|
)
|
|
return err.serialize()
|
|
}
|
|
|
|
if (this.config.errorFormat === "ServiceError") {
|
|
const err = new ServiceError(
|
|
this.code,
|
|
this.context.path || "",
|
|
this.config.errorName || "ValidationException",
|
|
this.message,
|
|
this.formattedErrors
|
|
)
|
|
return err.serialize()
|
|
}
|
|
const response = {
|
|
code: this.code,
|
|
message: this.message,
|
|
errors: this.formattedErrors
|
|
}
|
|
|
|
if (this.cause) {
|
|
response.cause = this.cause
|
|
}
|
|
|
|
return response
|
|
}
|
|
}
|
|
|
|
module.exports = ValidationError |