UNPKG

@shirudo/base-error

Version:

A simple error base class for TypeScript

1 lines 20.6 kB
{"version":3,"sources":["../src/BaseError.ts","../src/utils/guard.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["// src/BaseError.ts\n\n// Import global type augmentations (type-only import)\nimport type {} from \"./types/global.js\";\n\n/**\n * Application-specific base error that works across full Node.js, isolate \"edge\"\n * runtimes (Cloudflare Workers, Deno Deploy, Vercel Edge Functions) and modern\n * browsers. It preserves the native `cause` field where available, falls back\n * gracefully where it is not, and produces the richest stack trace the host\n * can provide.\n *\n * This class includes support for default and localized user-friendly messages.\n *\n * @example\n * ```ts\n * // Using automatic name inference\n * class UserNotFoundError extends BaseError<'UserNotFoundError'> {\n * constructor(userId: string) {\n * super(`User with id ${userId} not found in database lookup`); // Technical message\n * this.withUserMessage(`User ${userId} was not found.`); // User-friendly message\n * }\n * }\n * ```\n */\nexport class BaseError<T extends string> extends Error {\n public readonly name: T;\n\n /** Epoch-ms timestamp (numeric) */\n public readonly timestamp: number = Date.now();\n\n /** ISO-8601 timestamp (string) for log aggregators that prefer text */\n public readonly timestampIso: string = new Date().toISOString();\n\n /** Rich, filtered stack where the host supports it. */\n public readonly stack?: string;\n\n // --- Properties for user-friendly messages ---\n private _defaultUserMessage?: string;\n private _localizedMessages = new Map<string, string>();\n\n /**\n * Creates a new BaseError instance with automatic name inference.\n *\n * @param message – Human-readable explanation (name will be inferred from constructor)\n * @param cause – Optional underlying error or extra context\n */\n // The /*#__PURE__*/ pragma lets tree-shakers know the constructor is side-effect free\n public /*#__PURE__*/ constructor(message: string, cause?: unknown) {\n // Always call super with just message for TypeScript compatibility\n super(message);\n\n // Automatically infer the error name from the constructor name\n this.name = this.constructor.name as T;\n\n // Handle cause with native support when available, fallback otherwise\n if (cause !== undefined) {\n this.#setCause(cause);\n }\n\n // Preserve prototype chain for `instanceof` checks after transpilation.\n Object.setPrototypeOf(this, new.target.prototype);\n\n // Cross-runtime best-effort stack collection\n this.stack = this.#captureStack();\n }\n\n // ————————————————————————————————————————————————————————————————\n // Methods for User-Friendly Messages\n // ————————————————————————————————————————————————————————————————\n\n /**\n * Sets the default user-friendly message.\n * This is used as a fallback when a specific localization is not available.\n * @param message The default user-friendly message (typically in English).\n * @returns The error instance for chaining.\n */\n public withUserMessage(message: string): this {\n this._defaultUserMessage = message;\n return this;\n }\n\n /**\n * Adds a user-friendly message for a specific language.\n * Throws an error if a message for the given language already exists.\n * @param lang The language code (e.g., 'de', 'es', 'fr-CA').\n * @param message The localized message.\n * @returns The error instance for chaining.\n * @throws Error if a message for the given language already exists.\n */\n public addLocalizedMessage(lang: string, message: string): this {\n if (this._localizedMessages.has(lang)) {\n throw new Error(\n `Localized message for language '${lang}' already exists. Use updateLocalizedMessage() to modify existing messages.`,\n );\n }\n this._localizedMessages.set(lang, message);\n return this;\n }\n\n /**\n * Updates or sets a user-friendly message for a specific language.\n * This method allows overwriting existing messages for the same language.\n * @param lang The language code (e.g., 'de', 'es', 'fr-CA').\n * @param message The localized message.\n * @returns The error instance for chaining.\n */\n public updateLocalizedMessage(lang: string, message: string): this {\n this._localizedMessages.set(lang, message);\n return this;\n }\n\n /**\n * Retrieves the most appropriate user-friendly message based on language preference.\n * The fallback order is: preferred language -> fallback language -> default message.\n * @param options - Language preference options.\n * @returns The user-friendly message, or `undefined` if none is set.\n */\n public getUserMessage(options?: {\n preferredLang?: string;\n fallbackLang?: string;\n }): string | undefined {\n const { preferredLang, fallbackLang } = options || {};\n\n // 1. Try to get the message for the preferred language.\n if (preferredLang && this._localizedMessages.has(preferredLang)) {\n return this._localizedMessages.get(preferredLang);\n }\n\n // 2. If not found, try the fallback language (e.g., 'en').\n if (fallbackLang && this._localizedMessages.has(fallbackLang)) {\n return this._localizedMessages.get(fallbackLang);\n }\n\n // 3. If still not found, return the default user message.\n return this._defaultUserMessage;\n }\n\n /** Serialises the error for JSON logs */\n public toJSON(): Record<string, unknown> {\n const { name, message, timestamp, timestampIso, stack } = this;\n const cause = (this as unknown as Record<string, unknown>).cause;\n\n const json: Record<string, unknown> = {\n name,\n message, // The original technical message\n timestamp,\n timestampIso,\n stack,\n cause: this.#serializeCause(cause),\n };\n\n // Add user messages to the JSON output for logging if they exist\n if (this._defaultUserMessage) {\n json.userMessage = this._defaultUserMessage;\n }\n if (this._localizedMessages.size > 0) {\n json.localizedMessages = Object.fromEntries(this._localizedMessages);\n }\n\n return json;\n }\n\n /** Readable one-liner plus optional nested cause. */\n public toString(): string {\n const cause = (this as unknown as Record<string, unknown>).cause;\n return `[${this.name}] ${this.message}${\n cause ? `\\nCaused by: ${cause}` : \"\"\n }`;\n }\n\n // ————————————————————————————————————————————————————————————————\n // Internal helpers\n // ————————————————————————————————————————————————————————————————\n\n /**\n * Sets the cause property using native support when available, with fallback.\n * This provides better compatibility across different JavaScript environments.\n */\n /*#__PURE__*/ #setCause(cause: unknown): void {\n // Try to use native cause support if available\n if (BaseError.#hasNativeCauseSupport()) {\n // For environments with native cause support, we need to reconstruct\n // the error with cause. Since we can't do this in the constructor due to\n // TypeScript limitations, we'll set it manually but make it look native.\n try {\n Object.defineProperty(this, \"cause\", {\n value: cause,\n configurable: true,\n writable: true,\n enumerable: false, // Keep it non-enumerable like native cause\n });\n } catch {\n // Fallback if defineProperty fails\n (this as unknown as Record<string, unknown>).cause = cause;\n }\n } else {\n // For older environments, set cause manually\n try {\n Object.defineProperty(this, \"cause\", {\n value: cause,\n configurable: true,\n writable: true,\n enumerable: false,\n });\n } catch {\n // Final fallback for very old environments\n (this as unknown as Record<string, unknown>).cause = cause;\n }\n }\n }\n\n /**\n * Intelligently serializes the cause for JSON output.\n * Preserves stack traces and nested data instead of just toString().\n */\n /*#__PURE__*/ #serializeCause(cause: unknown): unknown {\n if (cause === undefined || cause === null) {\n return cause;\n }\n\n if (cause instanceof Error) {\n // For Error objects, preserve stack and nested cause\n return {\n name: cause.name,\n message: cause.message,\n stack: cause.stack,\n // Recursively serialize nested causes\n cause: this.#serializeCause(\n (cause as unknown as Record<string, unknown>).cause,\n ),\n };\n }\n\n if (typeof cause === \"object\" && cause !== null) {\n try {\n // For plain objects, try to serialize them directly\n // This preserves structured data that might be useful for debugging\n return JSON.parse(JSON.stringify(cause));\n } catch {\n // If JSON.stringify fails (circular references, etc.), create a more useful representation\n return this.#serializeCircularObject(cause);\n }\n }\n\n // For primitives (string, number, boolean), return as-is\n return cause;\n }\n\n /**\n * Creates a more useful representation of circular objects for debugging.\n * Instead of just \"[object Object]\", it extracts key information.\n */\n /*#__PURE__*/ #serializeCircularObject(obj: object): string {\n const type = obj.constructor?.name || \"Object\";\n const keys = Object.keys(obj).slice(0, 5); // Show first 5 keys\n const keyInfo = keys.length > 0 ? ` with keys: [${keys.join(\", \")}]` : \"\";\n const moreKeys = Object.keys(obj).length > 5 ? \"...\" : \"\";\n\n return `[Circular ${type}${keyInfo}${moreKeys}]`;\n }\n\n /**\n * Detects if the runtime supports native Error cause option.\n * Available in Node.js 16.9+ and modern browsers.\n */\n static /*#__PURE__*/ #hasNativeCauseSupport(): boolean {\n // Simple runtime detection without constructor testing\n // Check if we're in Node.js 16.9+ or modern browser environment\n if (typeof process !== \"undefined\" && process.versions?.node) {\n const [major, minor] = process.versions.node.split(\".\").map(Number);\n return major > 16 || (major === 16 && minor >= 9);\n }\n\n // For browser environments, assume modern browsers support it\n // This is a conservative approach that works with current TypeScript\n return typeof window !== \"undefined\" && \"cause\" in Error.prototype;\n }\n\n /**\n * Captures and filters the stack trace without affecting global state.\n * Filters out internal BaseError frames for cleaner stack traces.\n */\n /*#__PURE__*/ #captureStack(): string | undefined {\n // First, try to capture stack directly on this instance when possible\n if (typeof Error.captureStackTrace === \"function\") {\n // V8/Node.js: Capture stack directly on this instance, excluding constructor\n Error.captureStackTrace(this, this.constructor);\n return this.#filterInternalFrames(this.stack);\n }\n\n // For non-V8 engines, create a temporary error to get the stack\n let tempStack: string | undefined;\n try {\n throw new Error();\n } catch (e) {\n tempStack = (e as Error).stack;\n }\n\n if (!tempStack) {\n return undefined;\n }\n\n // Filter out internal frames and update the header\n return this.#filterInternalFrames(tempStack);\n }\n\n /**\n * Filters out internal BaseError frames and updates the error header.\n * This provides cleaner stack traces by removing implementation details.\n */\n /*#__PURE__*/ #filterInternalFrames(\n stack: string | undefined,\n ): string | undefined {\n if (!stack) {\n return undefined;\n }\n\n const lines = stack.split(\"\\n\");\n const filteredLines: string[] = [];\n\n // Update the header with proper error name and message\n filteredLines.push(`${this.name}: ${this.message}`);\n\n // Filter out internal frames\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n\n // Skip internal BaseError frames\n if (\n line.includes(\"#captureStack\") ||\n line.includes(\"#filterInternalFrames\") ||\n line.includes(\"BaseError.constructor\") ||\n line.includes(\"new BaseError\") ||\n line.includes(\"captureStack_fn\") || // Compiled private method name\n line.includes(\"filterInternalFrames_fn\") || // Compiled private method name\n // Skip the temporary error creation frame\n (line.includes(\"Object.<anonymous>\") && line.includes(\"captureStack\"))\n ) {\n continue;\n }\n\n filteredLines.push(line);\n }\n\n return filteredLines.join(\"\\n\");\n }\n}\n","import type { BaseError } from \"@/BaseError.js\";\n\n/**\n * Asserts that a condition is truthy, throwing the provided error if it's falsy.\n * This function provides TypeScript type narrowing through assertion signatures.\n *\n * @template T - The error name type extending string\n * @param condition - The value to check for truthiness\n * @param error - The BaseError instance to throw if condition is falsy\n * @throws {BaseError<T>} The provided error when condition is falsy\n *\n * @example\n * ```ts\n * const user = getUser();\n * guard(user, new UserNotFoundError(\"User not found\"));\n * // TypeScript now knows user is not null/undefined\n * console.log(user.name);\n * ```\n *\n * @example\n * ```ts\n * guard(isValidEmail(email), new ValidationError(\"Invalid email format\"));\n * // Continues execution only if email is valid\n * ```\n */\nexport function guard<T extends string>(\n condition: unknown,\n error: BaseError<T>,\n): asserts condition {\n if (!condition) {\n throw error;\n }\n}\n"]}