UNPKG

@statezero/core

Version:

The type-safe frontend client for StateZero - connect directly to your backend models with zero boilerplate

194 lines (193 loc) 6.59 kB
/** * @typedef {Object} IErrorResponse * @property {number} status - The HTTP status code. * @property {string} type - The error type. * @property {*} detail - The error details. */ /** * @typedef {Object} IErrorDetail * @property {string} message - The error message. * @property {string} code - The error code. */ /** * Base error class for StateZero errors. */ export class StateZeroError extends Error { /** * Creates a new StateZeroError. * * @param {string} message - The error message. * @param {string} code - The error code. * @param {IErrorDetail|Object|string} detail - The error details. * @param {number} status - The HTTP status code. */ constructor(message, code, detail, status) { super(message); this.name = "StateZeroError"; this.code = code; this.detail = detail; this.status = status; Object.setPrototypeOf(this, new.target.prototype); } /** * Returns a full error message including the detail. * * @returns {string} The full error message with details */ getFullMessage() { if (typeof this.detail === 'string') { return `${this.message}: ${this.detail}`; } else if (this.detail && typeof this.detail === 'object') { if (this.detail.message) { return `${this.message}: ${this.detail.message}`; } else { try { return `${this.message}: ${JSON.stringify(this.detail)}`; } catch (e) { return `${this.message}: [Complex detail object]`; } } } return this.message; } } /** * Error class for validation errors. */ export class ValidationError extends StateZeroError { /** * Creates a new ValidationError. * * @param {IErrorDetail|Object|string} detail - The error details. * @param {number} [status=400] - The HTTP status code. */ constructor(detail, status = 400) { super("Validation error", "validation_error", detail, status); this.name = "ValidationError"; } } /** * Error class for "Does Not Exist" errors (renamed from NotFound). */ export class DoesNotExist extends StateZeroError { /** * Creates a new DoesNotExist error. * * @param {IErrorDetail|Object|string} [detail="Does not exist"] - The error details. * @param {number} [status=404] - The HTTP status code. */ constructor(detail = "Does not exist", status = 404) { super("DoesNotExist", "does_not_exist", detail, status); this.name = "DoesNotExist"; } } /** * Error class for permission denied errors. */ export class PermissionDenied extends StateZeroError { /** * Creates a new PermissionDenied error. * * @param {IErrorDetail|Object|string} [detail="Permission denied"] - The error details. * @param {number} [status=403] - The HTTP status code. */ constructor(detail = "Permission denied", status = 403) { super("Permission denied", "permission_denied", detail, status); this.name = "PermissionDenied"; } } /** * Error class for multiple objects returned errors. */ export class MultipleObjectsReturned extends StateZeroError { /** * Creates a new MultipleObjectsReturned error. * * @param {IErrorDetail|Object|string} [detail="Multiple objects returned"] - The error details. * @param {number} [status=500] - The HTTP status code. */ constructor(detail = "Multiple objects returned", status = 500) { super("Multiple objects returned", "multiple_objects_returned", detail, status); this.name = "MultipleObjectsReturned"; } } /** * Error class for AST validation errors. */ export class ASTValidationError extends StateZeroError { /** * Creates a new ASTValidationError. * * @param {IErrorDetail|Object|string} detail - The error details. * @param {number} [status=400] - The HTTP status code. */ constructor(detail, status = 400) { super("Query syntax error", "ast_validation_error", detail, status); this.name = "ASTValidationError"; } } /** * Error class for configuration errors. */ export class ConfigError extends StateZeroError { /** * Creates a new ConfigError. * * @param {IErrorDetail|Object|string} detail - The error details. * @param {number} [status=500] - The HTTP status code. */ constructor(detail, status = 500) { super("Configuration error", "config_error", detail, status); this.name = "ConfigError"; } } /** * Parses a JSON error response from the backend and returns an instance * of the corresponding custom error. * * @param {IErrorResponse} errorResponse - The error response JSON. * @returns {StateZeroError} An instance of a StateZeroError subclass. */ export function parseStateZeroError(errorResponse) { console.log(JSON.stringify(errorResponse)); const { status, type, detail } = errorResponse; // Handle undefined type/status case (like in permission denied) if (type === undefined && detail === 'Invalid token.') { return new PermissionDenied(detail, 403); } switch (type) { // Direct mappings case "ValidationError": return new ValidationError(detail, status); case "NotFound": return new DoesNotExist(detail, status); case "MultipleObjectsReturned": return new MultipleObjectsReturned(detail, status); case "PermissionDenied": return new PermissionDenied(detail, status); case "ASTValidationError": return new ASTValidationError(detail, status); case "ConfigError": return new ConfigError(detail, status); // Django error types that map to our error classes case "FieldError": return new ValidationError(detail, status); case "ValueError": return new ValidationError(detail, status); default: // Fallback to status code based mapping if (status === 400) { return new ValidationError(detail, status); } else if (status === 403) { return new PermissionDenied(detail, status); } else if (status === 404) { return new DoesNotExist(detail, status); } return new StateZeroError("Unknown error", "unknown", detail, status); } }