UNPKG

@smartsamurai/krapi-sdk

Version:

KRAPI TypeScript SDK - Easy-to-use client SDK for connecting to self-hosted KRAPI servers (like Appwrite SDK)

238 lines (210 loc) 6.54 kB
/** * HTTP Error Class for KRAPI SDK * * Provides detailed error information for HTTP requests including: * - HTTP status codes * - Request details (method, URL, headers) * - Response details (status, data) * - Error categorization (network, API, auth, etc.) * * @module http-clients/http-error */ /** * HTTP Error Class * * Extended Error class with HTTP-specific error information. * * @class HttpError * @extends {Error} */ export class HttpError extends Error { /** * HTTP status code (if available) */ public readonly status?: number; /** * HTTP method (GET, POST, PUT, DELETE, etc.) */ public readonly method?: string; /** * Request URL */ public readonly url?: string; /** * Request headers (sanitized - no sensitive data) */ public readonly requestHeaders?: Record<string, string>; /** * Request body/data sent (if available) */ public readonly requestBody?: unknown; /** * Request query parameters (if available) */ public readonly requestQuery?: Record<string, unknown>; /** * Response data from the server (if available) */ public readonly responseData?: unknown; /** * Response headers (if available) */ public readonly responseHeaders?: Record<string, string>; /** * Error code for programmatic error handling */ public readonly code?: string; /** * Whether this is an API error (4xx, 5xx) */ public readonly isApiError: boolean; /** * Whether this is a network error (connection failed, timeout, etc.) */ public readonly isNetworkError: boolean; /** * Whether this is an authentication error (401, 403) */ public readonly isAuthError: boolean; /** * Whether this is a client error (4xx) */ public readonly isClientError: boolean; /** * Whether this is a server error (5xx) */ public readonly isServerError: boolean; /** * Original error object (if wrapped) */ public readonly originalError?: unknown; /** * Create a new HttpError instance * * @param {string} message - Error message * @param {Object} options - Error options * @param {number} [options.status] - HTTP status code * @param {string} [options.method] - HTTP method * @param {string} [options.url] - Request URL * @param {Record<string, string>} [options.requestHeaders] - Request headers * @param {unknown} [options.requestBody] - Request body/data sent * @param {Record<string, unknown>} [options.requestQuery] - Request query parameters * @param {unknown} [options.responseData] - Response data * @param {Record<string, string>} [options.responseHeaders] - Response headers * @param {string} [options.code] - Error code * @param {unknown} [options.originalError] - Original error */ constructor( message: string, options: { status?: number; method?: string; url?: string; requestHeaders?: Record<string, string>; requestBody?: unknown; requestQuery?: Record<string, unknown>; responseData?: unknown; responseHeaders?: Record<string, string>; code?: string; originalError?: unknown; } = {} ) { super(message); this.name = "HttpError"; // Set properties (only if defined to avoid undefined assignment) if (options.status !== undefined) { this.status = options.status; } if (options.method !== undefined) { this.method = options.method; } if (options.url !== undefined) { this.url = options.url; } if (options.requestHeaders !== undefined) { this.requestHeaders = options.requestHeaders; } if (options.requestBody !== undefined) { this.requestBody = options.requestBody; } if (options.requestQuery !== undefined) { this.requestQuery = options.requestQuery; } if (options.responseData !== undefined) { this.responseData = options.responseData; } if (options.responseHeaders !== undefined) { this.responseHeaders = options.responseHeaders; } if (options.code !== undefined) { this.code = options.code; } if (options.originalError !== undefined) { this.originalError = options.originalError; } // Categorize error this.isApiError = options.status !== undefined && options.status >= 400; this.isNetworkError = options.status === undefined; this.isAuthError = options.status === 401 || options.status === 403; this.isClientError = options.status !== undefined && options.status >= 400 && options.status < 500; this.isServerError = options.status !== undefined && options.status >= 500; // Maintain proper stack trace if (Error.captureStackTrace) { Error.captureStackTrace(this, HttpError); } } /** * Get a detailed error message with all available information * * @returns {string} Detailed error message */ getDetailedMessage(): string { const parts: string[] = [this.message]; if (this.status) { parts.push(`(HTTP ${this.status})`); } if (this.method && this.url) { parts.push(`[${this.method} ${this.url}]`); } if (this.code) { parts.push(`[Code: ${this.code}]`); } // Add response data if available and is an object with error/message if (this.responseData && typeof this.responseData === "object") { const response = this.responseData as Record<string, unknown>; if (response.error && typeof response.error === "string") { parts.push(`Backend error: ${response.error}`); } else if (response.message && typeof response.message === "string") { parts.push(`Backend message: ${response.message}`); } } return parts.join(" "); } /** * Convert error to JSON for logging * * @returns {Record<string, unknown>} JSON representation */ toJSON(): Record<string, unknown> { return { name: this.name, message: this.message, status: this.status, method: this.method, url: this.url, code: this.code, isApiError: this.isApiError, isNetworkError: this.isNetworkError, isAuthError: this.isAuthError, isClientError: this.isClientError, isServerError: this.isServerError, requestHeaders: this.requestHeaders, requestBody: this.requestBody, requestQuery: this.requestQuery, responseData: this.responseData, responseHeaders: this.responseHeaders, originalError: this.originalError, stack: this.stack, }; } }