### Run Basic Error Examples with pnpm Source: https://github.com/shi-rudo/base-error-ts/blob/main/examples/README.md Demonstrates how to install dependencies and run specific TypeScript examples using pnpm and tsx. This is useful for testing individual error handling scenarios. ```bash # Install dependencies first pnpm install # Run a specific example pnpm tsx examples/basic-usage.ts pnpm tsx examples/error-handling.ts pnpm tsx examples/problem-details-example.ts pnpm tsx examples/error-response-builder-example.ts ``` -------------------------------- ### Define Custom Error Classes with BaseError (TypeScript) Source: https://context7.com/shi-rudo/base-error-ts/llms.txt Demonstrates how to create custom error classes extending `BaseError` for automatic name inference, timestamps, and error cause chains. Includes examples for basic custom errors, errors with additional properties, and errors with cause chains. Also shows JSON serialization. ```typescript import { BaseError } from "@shirudo/base-error"; // Define a custom error class with automatic name inference class UserNotFoundError extends BaseError<"UserNotFoundError"> { constructor(userId: string) { super(`User ${userId} not found`); // Add user-friendly message for end users this.withUserMessage("The requested user could not be found."); } } // Define an error with additional properties class ValidationError extends BaseError<"ValidationError"> { constructor( message: string, public readonly field?: string, ) { super(message); } } // Define an error with cause chain support class DatabaseError extends BaseError<"DatabaseError"> { constructor(message: string, cause?: unknown) { super(message, cause); } } // Usage try { throw new UserNotFoundError("user-123"); } catch (error) { if (error instanceof UserNotFoundError) { console.log(error.name); // "UserNotFoundError" console.log(error.message); // "User user-123 not found" console.log(error.timestamp); // 1704067200000 (epoch ms) console.log(error.timestampIso); // "2025-01-01T00:00:00.000Z" console.log(error.stack); // Filtered stack trace } } // Error with cause chain try { throw new Error("Connection refused"); } catch (dbError) { throw new DatabaseError("Failed to fetch user data", dbError); } // Output: [DatabaseError] Failed to fetch user data // Caused by: Error: Connection refused // JSON serialization const error = new ValidationError("Invalid email format", "email"); console.log(JSON.stringify(error, null, 2)); // { // "name": "ValidationError", // "message": "Invalid email format", // "timestamp": 1704067200000, // "timestampIso": "2025-01-01T00:00:00.000Z", // "stack": "...", // "cause": null // } ``` -------------------------------- ### Fluent API for User Messages (TypeScript) Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md Illustrates the fluent API provided by BaseError for managing user messages. It shows how to chain `withUserMessage` and `addLocalizedMessage` calls for concise initialization of a `ValidationError`. The example also demonstrates retrieving messages with different language preferences and the prevention of duplicate localized messages, along with using `updateLocalizedMessage`. ```typescript import { BaseError } from "@shirudo/base-error"; class ValidationError extends BaseError<"ValidationError"> { constructor(field: string, technicalReason: string) { super(`Validation failed for field '${field}': ${technicalReason}`); // Chain method calls for fluent API this.withUserMessage("Please check your input and try again.") .addLocalizedMessage("en", "Please check your input and try again.") .addLocalizedMessage( "es", "Por favor, revise su entrada e inténtelo de nuevo.", ) .addLocalizedMessage("fr", "Veuillez vérifier votre saisie et réessayer.") .addLocalizedMessage( "de", "Bitte überprüfen Sie Ihre Eingabe und versuchen Sie es erneut.", ); } } const error = new ValidationError("email", "invalid format"); // Get message with different language preferences error.getUserMessage(); // Default message error.getUserMessage({ preferredLang: "es" }); // Spanish message error.getUserMessage({ preferredLang: "it", fallbackLang: "en" }); // English (fallback) error.getUserMessage({ preferredLang: "pt", fallbackLang: "it" }); // Default message (no match) // Duplicate prevention try { error.addLocalizedMessage("en", "Another English message"); // Throws error } catch (e) { console.log(e.message); // "Localized message for language 'en' already exists..." } // Use updateLocalizedMessage to intentionally overwrite error.updateLocalizedMessage("en", "Updated English message"); // Works fine ``` -------------------------------- ### Integrate Retry Logic with StructuredError Source: https://context7.com/shi-rudo/base-error-ts/llms.txt Implement automatic retry mechanisms for transient errors using the `retryable` flag provided by `StructuredError`. This example demonstrates a generic `withRetry` function that handles retrying asynchronous operations based on the error's retryable status and includes exponential backoff. ```typescript import { StructuredError } from "@shirudo/base-error"; // Generic retry function using retryable flag async function withRetry( fn: () => Promise, maxAttempts: number = 3, ): Promise { let lastError: unknown; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fn(); } catch (error) { lastError = error; // Check if error is retryable if ( error instanceof StructuredError && error.retryable && attempt < maxAttempts ) { console.log(`Attempt ${attempt} failed, retrying...`); await new Promise(r => setTimeout(r, 1000 * attempt)); // Exponential backoff continue; } // Non-retryable or last attempt - throw immediately throw error; } } throw lastError; } // Example: API client with retry class ApiError extends StructuredError { constructor(code: string, message: string, retryable: boolean) { super({ code, category: "API", retryable, message }); } } async function fetchUserWithRetry(userId: string) { return withRetry(async () => { const response = await fetch(`/api/users/${userId}`); if (response.status === 503) { throw new ApiError("SERVICE_UNAVAILABLE", "Service temporarily unavailable", true); } if (response.status === 404) { throw new ApiError("NOT_FOUND", `User ${userId} not found`, false); // Won't retry } return response.json(); }); } ``` -------------------------------- ### JSON Serialization of Errors with User Messages (TypeScript) Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md Shows how BaseError automatically includes user-friendly and localized messages when an error object is serialized to JSON. The example demonstrates the structure of the JSON output, highlighting the `userMessage` and `localizedMessages` fields. ```typescript const error = new ValidationError("email", "invalid format"); console.log(JSON.stringify(error, null, 2)); // Output: // { // "name": "ValidationError", // "message": "Validation failed for field 'email': invalid format", // "timestamp": 1704067200000, // "timestampIso": "2025-01-01T00:00:00.000Z", // "stack": "...", // "userMessage": "Please check your input and try again.", // "localizedMessages": { // "en": "Please check your input and try again.", // "es": "Por favor, revise su entrada e inténtelo de nuevo.", // "fr": "Veuillez vérifier votre saisie et réessayer.", // "de": "Bitte überprüfen Sie Ihre Eingabe und versuchen Sie es erneut." // } // } ``` -------------------------------- ### Automatic Name Inference Example (TypeScript) Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md Illustrates BaseError's automatic name inference feature, where the error name is derived from the class name, simplifying error definition. ```typescript import { BaseError } from "@shirudo/base-error"; class UserNotFoundError extends BaseError<"UserNotFoundError"> { constructor(userId: string) { super(`User ${userId} not found`); // Name is automatically inferred } } class ValidationError extends BaseError<"ValidationError"> { constructor(field: string, message: string, cause?: unknown) { super(`Validation failed for ${field}: ${message}`, cause); } } ``` -------------------------------- ### Create Structured Errors with Metadata Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md Demonstrates how to create `StructuredError` instances, which extend `BaseError` by adding fields for error codes, categories, retryability, and detailed context. This provides a comprehensive way to represent and handle errors with rich metadata. ```typescript import { StructuredError } from "@shirudo/base-error"; // Create a structured error with full metadata const error = new StructuredError({ code: "VALIDATION_FAILED", category: "CLIENT_ERROR", retryable: false, message: "Email format is invalid", details: { field: "email", value: "not-an-email" }, }); // All fields are strongly typed and accessible console.log(error.code); // "VALIDATION_FAILED" console.log(error.category); // "CLIENT_ERROR" console.log(error.retryable); // false console.log(error.details); // { field: "email", value: "not-an-email" } // All BaseError features work seamlessly error.withUserMessage("Please enter a valid email address"); console.log(JSON.stringify(error, null, 2)); ``` -------------------------------- ### Implement Language Fallback Strategy for User Messages Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md Demonstrates how to use the `getUserMessage` method with a three-tier fallback strategy: preferred language, fallback language, and a default message. This ensures users receive the most appropriate message based on available translations. ```typescript const error = new ValidationError("email", "invalid format"); // Only set some languages error .withUserMessage("Default message") .addLocalizedMessage("en", "English message") .addLocalizedMessage("fr", "French message"); // Fallback examples error.getUserMessage({ preferredLang: "fr" }); // → "French message" error.getUserMessage({ preferredLang: "es", fallbackLang: "en" }); // → "English message" error.getUserMessage({ preferredLang: "es", fallbackLang: "de" }); // → "Default message" error.getUserMessage({ preferredLang: "es" }); // → "Default message" ``` -------------------------------- ### Create API Error Responses Directly with createErrorResponse Source: https://context7.com/shi-rudo/base-error-ts/llms.txt Shows how to directly create error and success response objects using `createErrorResponse` and `createSuccessResponse` functions. This method is suitable for simpler error constructions without needing the builder pattern. ```typescript import { createErrorResponse, createSuccessResponse } from "@shirudo/base-error"; // Minimal - just code and category (retryable defaults to false) const simpleError = createErrorResponse({ code: "UNAUTHORIZED", category: "AUTH", }); // With context const errorWithCtx = createErrorResponse({ code: "USER_NOT_FOUND", category: "NOT_FOUND", ctx: { message: "User 123 not found", httpStatusCode: 404 }, }); // Full options const fullError = createErrorResponse({ code: "RATE_LIMITED", category: "RATE_LIMIT", retryable: true, traceId: "trace-abc-123", ctx: { message: "Too many requests", httpStatusCode: 429 }, details: { retryAfter: 60 }, }); // Success response const success = createSuccessResponse({ data: { id: "123", name: "John" }, }); ``` -------------------------------- ### Create Structured Errors with Metadata using StructuredError Source: https://context7.com/shi-rudo/base-error-ts/llms.txt Illustrates how to use the StructuredError class, which extends BaseError, to include standardized metadata like error codes, categories, retryability, and custom details. This enables more robust programmatic error handling. It requires the '@shirudo/base-error' package. ```typescript import { StructuredError } from "@shirudo/base-error"; // Basic usage with all metadata const error = new StructuredError({ code: "VALIDATION_FAILED", category: "CLIENT_ERROR", retryable: false, message: "Email format is invalid", details: { field: "email", value: "not-an-email" }, }); console.log(error.code); // "VALIDATION_FAILED" console.log(error.category); // "CLIENT_ERROR" console.log(error.retryable); // false console.log(error.details); // { field: "email", value: "not-an-email" } // All BaseError features work seamlessly error.withUserMessage("Please enter a valid email address"); console.log(JSON.stringify(error, null, 2)); // { // "name": "VALIDATION_FAILED", // "message": "Email format is invalid", // "code": "VALIDATION_FAILED", // "category": "CLIENT_ERROR", // "retryable": false, // "details": { "field": "email", "value": "not-an-email" }, // "userMessage": "Please enter a valid email address", // ... // } ``` -------------------------------- ### Convert Errors to API Response Format with StructuredError Source: https://context7.com/shi-rudo/base-error-ts/llms.txt Demonstrates how to use the `StructuredError` class to convert various error types into a standardized API response format using the `toErrorResponse()` method. This is useful for both RPC and HTTP APIs, allowing for consistent error reporting. ```typescript import { StructuredError } from "@shirudo/base-error"; const error = new StructuredError({ code: "USER_NOT_FOUND", category: "NOT_FOUND", retryable: false, message: "User with id 123 not found", details: { userId: "123" }, }); const response = error.toErrorResponse({ httpStatusCode: 404, messageLocalized: { locale: "en", message: "User not found" }, traceId: "trace-abc-123", }); console.log(JSON.stringify(response, null, 2)); ``` -------------------------------- ### Build API Error Responses Fluently with ErrorResponseBuilder Source: https://context7.com/shi-rudo/base-error-ts/llms.txt Illustrates the use of the `ErrorResponseBuilder` for type-safe and fluent construction of API error responses. This pattern simplifies the creation of complex error objects by chaining method calls. ```typescript import { errorResponse, successResponse } from "@shirudo/base-error"; // Build error response with fluent API const error = errorResponse({ code: "USER_NOT_FOUND", category: "NOT_FOUND", retryable: false, }) .httpStatus(404) .message("User with id 123 not found") .localized("en", "User not found") .localized("ja", "ユーザーが見つかりません") .traceId("trace-abc-123") .withCtx({ method: "GET", path: "/api/users/123", timestamp: new Date().toISOString(), requestId: "req-xyz-789", }) .details({ userId: "123", resource: "users" }) .build(); console.log(JSON.stringify(error, null, 2)); // Success response for comparison const success = successResponse({ id: "123", name: "John", email: "john@example.com", }); console.log(JSON.stringify(success, null, 2)); // Void success response const voidSuccess = successResponse(); ``` -------------------------------- ### Create Custom Error with Automatic Name Inference (TypeScript) Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md Demonstrates how to create a custom error class extending BaseError, leveraging automatic name inference for the error type. It includes adding a user-friendly message for end-users. ```typescript import { BaseError } from "@shirudo/base-error"; // Create a custom error class using automatic name inference class UserNotFoundError extends BaseError<"UserNotFoundError"> { constructor(userId: string) { super(`User ${userId} not found`); // Optional: Add user-friendly message for end users this.withUserMessage("The requested user could not be found."); } } // Throw the error throw new UserNotFoundError("user-123"); ``` -------------------------------- ### Type Narrowing for Custom Errors with `instanceof` in TypeScript Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md Demonstrates how to use the `instanceof` operator in TypeScript to narrow down the type of caught errors, specifically when working with custom error classes that extend `BaseError`. This allows for safe access to error-specific properties and methods. ```typescript import { BaseError } from "@shirudo/base-error"; class NotFoundError extends BaseError<"NotFoundError"> { constructor(resourceId: string) { super(`Resource ${resourceId} not found`); // Using automatic name inference } } class ValidationError extends BaseError<"ValidationError"> { constructor(field: string, message: string) { super(`${field}: ${message}`); // Using automatic name inference this.field = field; } field: string; } function handleError(error: unknown) { // Type narrowing with instanceof if (error instanceof NotFoundError) { // TypeScript knows this is a NotFoundError // error.name has IntelliSense and is typed as "NotFoundError" console.log(`Got a ${error.name} with message: ${error.message}`); // Handle 404 case } else if (error instanceof ValidationError) { // TypeScript knows this is a ValidationError // error.name is typed as "ValidationError" and field is available console.log(`Validation failed for field: ${error.field}`); console.log(`Error type: ${error.name}, message: ${error.message}`); // Handle validation error } else if (error instanceof BaseError) { // TypeScript knows this is some kind of BaseError // error.name is typed based on the generic parameter console.log(`Unknown error type: ${error.name}`); console.log(`Occurred at: ${error.timestampIso}`); } else { console.log("Unknown error:", error); } } ``` -------------------------------- ### Define User-Friendly Localized Error Messages with BaseError Source: https://context7.com/shi-rudo/base-error-ts/llms.txt Demonstrates how to extend BaseError to create custom error types with default and localized user-friendly messages. It covers setting technical messages, adding multiple language localizations, and retrieving messages with preferred language fallbacks. Dependencies include the '@shirudo/base-error' package. ```typescript import { BaseError } from "@shirudo/base-error"; class UserNotFoundError extends BaseError<"UserNotFoundError"> { constructor(userId: string) { super(`User with id ${userId} not found in database lookup`); // Technical message // Set default user-friendly message and add localizations this.withUserMessage(`User ${userId} was not found.`) .addLocalizedMessage("en", "User not found. Please check the user ID and try again.") .addLocalizedMessage("es", "Usuario no encontrado. Verifique el ID de usuario e inténtelo de nuevo.") .addLocalizedMessage("fr", "Utilisateur introuvable. Veuillez vérifier l'ID utilisateur et réessayer.") .addLocalizedMessage("de", "Benutzer nicht gefunden. Bitte überprüfen Sie die Benutzer-ID."); } } // Usage with language fallback try { throw new UserNotFoundError("user-123"); } catch (error) { if (error instanceof UserNotFoundError) { // Get message with preferred language const userMessage = error.getUserMessage({ preferredLang: "es" }); console.log(userMessage); // "Usuario no encontrado..." // Fallback to another language if preferred not available const fallbackMsg = error.getUserMessage({ preferredLang: "it", // Not available fallbackLang: "en" // Falls back to English }); console.log(fallbackMsg); // "User not found. Please check the user ID..." // Get default message when no language match const defaultMsg = error.getUserMessage({ preferredLang: "pt", fallbackLang: "ja" }); console.log(defaultMsg); // "User user-123 was not found." (default) // Technical message for logging console.log(error.message); // "User with id user-123 not found in database lookup" } } // Update existing localized message // Assuming 'error' is an instance of UserNotFoundError // error.updateLocalizedMessage("en", "Updated English message"); // JSON includes user messages // console.log(JSON.stringify(error, null, 2)); // { // "name": "UserNotFoundError", // "message": "User with id user-123 not found in database lookup", // "userMessage": "User user-123 was not found.", // "localizedMessages": { // "en": "User not found. Please check the user ID and try again.", // "es": "Usuario no encontrado...", // ... // }, // ... // } ``` -------------------------------- ### Define and Handle Errors with Union Types Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md Illustrates creating custom error classes that extend `BaseError` and utilize union types for specific error codes. This approach enforces type safety and provides a structured way to handle different error scenarios. ```typescript import { BaseError } from "@shirudo/base-error"; // Define your error codes as a union type type ErrorCode = | "USER_NOT_FOUND" | "USER_NOT_AUTHORIZED" | "USER_NOT_AUTHENTICATED" | "USER_QUOTA_LIMIT_REACHED"; // Base class for all user-related errors class UserError extends BaseError { constructor( public readonly code: T, message: string, public readonly userId?: string, cause?: unknown, ) { super(message, cause); this.code = code; } // Override toJSON to include the error code toJSON() { return { ...super.toJSON(), code: this.code, userId: this.userId, }; } } // Specific error classes class UserNotFoundError extends UserError<"USER_NOT_FOUND"> { constructor(userId: string) { super("USER_NOT_FOUND", `User with ID ${userId} was not found`, userId); } } class UserNotAuthorizedError extends UserError<"USER_NOT_AUTHORIZED"> { constructor(userId: string, resource: string) { super( "USER_NOT_AUTHORIZED", `User ${userId} is not authorized to access ${resource}`, userId, ); } } // Type-safe error handling function handleUserError(error: unknown): void { if (error instanceof UserError) { // TypeScript knows the error code is from the ErrorCode union switch (error.code) { case "USER_NOT_FOUND": console.log("→ Redirecting to user registration page"); break; case "USER_NOT_AUTHORIZED": console.log("→ Redirecting to access denied page"); break; case "USER_NOT_AUTHENTICATED": console.log("→ Redirecting to login page"); break; case "USER_QUOTA_LIMIT_REACHED": console.log("→ Showing upgrade options"); break; } } } ``` -------------------------------- ### JSON Serialization with Custom Properties (TypeScript) Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md Demonstrates how to extend BaseError and override the `toJSON` method to include custom properties in the JSON representation of the error, facilitating structured logging. ```typescript import { BaseError } from "@shirudo/base-error"; class ApiError extends BaseError<"ApiError"> { constructor(statusCode: number, message: string, cause?: unknown) { super(message, cause); // Using automatic name inference this.statusCode = statusCode; } statusCode: number; // Override toJSON to include custom properties toJSON() { const json = super.toJSON(); return { ...json, statusCode: this.statusCode, }; } } const error = new ApiError(404, "Resource not found"); console.log(JSON.stringify(error, null, 2)); ``` -------------------------------- ### Define Custom Error with Localized User Messages (TypeScript) Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md Demonstrates how to extend BaseError to create a custom error class (`UserNotFoundError`) that includes a technical message, a default user-friendly message, and multiple localized messages for different languages. It shows the usage within a try-catch block to retrieve the appropriate user message. ```typescript import { BaseError } from "@shirudo/base-error"; class UserNotFoundError extends BaseError<"UserNotFoundError"> { constructor(userId: string) { super(`User with id ${userId} not found in database lookup`); // Technical message // Set user-friendly message this.withUserMessage(`User ${userId} was not found.`); // Add localized messages this.addLocalizedMessage( "en", "User not found. Please check the user ID and try again.", ) .addLocalizedMessage( "es", "Usuario no encontrado. Verifique el ID de usuario e inténtelo de nuevo.", ) .addLocalizedMessage( "fr", "Utilisateur introuvable. Veuillez vérifier l'ID utilisateur et réessayer.", ) .addLocalizedMessage( "de", "Benutzer nicht gefunden. Bitte überprüfen Sie die Benutzer-ID und versuchen Sie es erneut.", ); } } // Usage in error handling try { throw new UserNotFoundError("user-123"); } catch (error) { if (error instanceof UserNotFoundError) { // Get localized message based on user preference const userMessage = error.getUserMessage({ preferredLang: "es", fallbackLang: "en", }); console.log("User message:", userMessage); // "Usuario no encontrado..." // Technical message for logging console.log("Technical message:", error.message); // "User with id user-123 not found..." } } ``` -------------------------------- ### Wrap Errors with Cause (TypeScript) Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md Shows how to wrap lower-level errors with more context using BaseError. This is useful for preserving the error cause chain, especially in environments that may not natively support it. ```typescript import { BaseError } from "@shirudo/base-error"; class DatabaseError extends BaseError<"DatabaseError"> { constructor(message: string, cause?: unknown) { super(message, cause); } } class UserServiceError extends BaseError<"UserServiceError"> { constructor(message: string, cause?: unknown) { super(message, cause); } } try { // Some database operation that fails throw new Error("Connection refused"); } catch (dbError) { // Wrap the low-level error with more context throw new UserServiceError("Failed to fetch user data", dbError); } ``` -------------------------------- ### Create Typed Domain-Specific Error Classes with TypeScript Source: https://context7.com/shi-rudo/base-error-ts/llms.txt Define custom, type-safe error classes for specific domains, such as database operations. This allows for detailed error codes, categories, and associated data, enhancing error handling and debugging. It relies on the `@shirudo/base-error` library. ```typescript import { StructuredError } from "@shirudo/base-error"; // Define typed error codes and categories type DatabaseErrorCode = "CONNECTION_FAILED" | "QUERY_TIMEOUT" | "DEADLOCK"; type DatabaseCategory = "CONNECTION" | "EXECUTION" | "CONCURRENCY"; interface DatabaseErrorDetails { query?: string; duration?: number; connectionId?: string; } // Create domain-specific error class class DatabaseError extends StructuredError< DatabaseErrorCode, DatabaseCategory, DatabaseErrorDetails > { constructor( code: DatabaseErrorCode, message: string, details?: DatabaseErrorDetails, cause?: unknown, ) { const category = code === "CONNECTION_FAILED" ? "CONNECTION" : code === "QUERY_TIMEOUT" ? "EXECUTION" : "CONCURRENCY"; super({ code, category, retryable: code !== "DEADLOCK", // Deadlocks are not retryable message, details, cause, }); } } // Usage with full type safety try { throw new DatabaseError( "QUERY_TIMEOUT", "Query exceeded 30 second timeout", { query: "SELECT * FROM users", duration: 30000 } ); } catch (error) { if (error instanceof DatabaseError) { console.log(`Database error: ${error.code}`); // "QUERY_TIMEOUT" console.log(`Category: ${error.category}`); // "EXECUTION" console.log(`Can retry: ${error.retryable}`); // true console.log(`Query: ${error.details?.query}`); // "SELECT * FROM users" console.log(`Duration: ${error.details?.duration}`); // 30000 } } ``` -------------------------------- ### Convert Errors to RFC 9457 Problem Details Format Source: https://context7.com/shi-rudo/base-error-ts/llms.txt Standardize error responses for HTTP APIs by converting `StructuredError` instances to the RFC 9457 Problem Details format. This method allows for inclusion of standard fields like `status`, `detail`, `type`, `title`, `instance`, and custom fields from the error's `details` property. ```typescript import { StructuredError } from "@shirudo/base-error"; const error = new StructuredError({ code: "USER_NOT_FOUND", category: "NOT_FOUND", retryable: false, message: "User with id 123 not found", details: { userId: "123", searchedIn: "users_table" }, }); // Basic conversion to Problem Details const problem = error.toProblemDetails({ status: 404 }); console.log(JSON.stringify(problem, null, 2)); // { // "status": 404, // "detail": "User with id 123 not found", // "code": "USER_NOT_FOUND", // "category": "NOT_FOUND", // "retryable": false, // "userId": "123", // "searchedIn": "users_table" // } // Full RFC 9457 fields const fullProblem = error.toProblemDetails({ status: 404, type: "https://api.example.com/errors/user-not-found", title: "User Not Found", instance: "/users/123", traceId: "trace-abc-123", }); console.log(JSON.stringify(fullProblem, null, 2)); // { // "type": "https://api.example.com/errors/user-not-found", // "title": "User Not Found", // "status": 404, // "detail": "User with id 123 not found", // "instance": "/users/123", // "code": "USER_NOT_FOUND", // "category": "NOT_FOUND", // "retryable": false, // "traceId": "trace-abc-123", // "userId": "123", // "searchedIn": "users_table" // } ``` -------------------------------- ### API Response Types with Discriminated Unions Source: https://context7.com/shi-rudo/base-error-ts/llms.txt Leverage Shirudo's `ApiResponse`, `SuccessResponse`, and `ErrorResponse` types to build type-safe API responses using discriminated unions. This ensures clarity and safety when handling both successful and error states in API interactions. ```typescript import type { ApiResponse, SuccessResponse, ErrorResponse, ErrorDetails, LocalizedMessage, ProblemDetails } from "@shirudo/base-error"; // Define your API's error types type MyErrorCode = "NOT_FOUND" | "VALIDATION_FAILED" | "UNAUTHORIZED"; type MyCategory = "CLIENT_ERROR" | "AUTH_ERROR"; // Type-safe API handler async function getUser(id: string): Promise> { const user = await db.findUser(id); if (!user) { return { isSuccess: false, error: { code: "NOT_FOUND", category: "CLIENT_ERROR", retryable: false, ctx: { message: `User ${id} not found`, httpStatusCode: 404 }, details: { userId: id }, }, }; } return { isSuccess: true, data: user, }; } // Type narrowing with discriminated union const response = await getUser("123"); if (response.isSuccess) { // TypeScript knows this is SuccessResponse console.log(response.data.name); } else { // TypeScript knows this is ErrorResponse console.log(response.error.code); console.log(response.error.ctx.message); } ``` -------------------------------- ### Create Domain-Specific Error Classes with TypeScript Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md Defines custom error classes like `DatabaseError` by extending `StructuredError`. This allows for type-safe error codes, categories, and details, enhancing error management. It demonstrates how to structure errors with specific attributes and handle them with full type safety. ```typescript import { StructuredError } from "@shirudo/base-error"; // Define your error codes and categories type DatabaseErrorCode = "CONNECTION_FAILED" | "QUERY_TIMEOUT" | "DEADLOCK"; type DatabaseCategory = "CONNECTION" | "EXECUTION" | "CONCURRENCY"; interface DatabaseErrorDetails { query?: string; duration?: number; connectionId?: string; } class DatabaseError extends StructuredError< DatabaseErrorCode, DatabaseCategory, DatabaseErrorDetails > { constructor( code: DatabaseErrorCode, message: string, details?: DatabaseErrorDetails, cause?: unknown, ) { const category = code === "CONNECTION_FAILED" ? "CONNECTION" : code === "QUERY_TIMEOUT" ? "EXECUTION" : "CONCURRENCY"; super({ code, category, retryable: code !== "DEADLOCK", message, details, cause, }); } } // Usage with full type safety try { throw new DatabaseError("QUERY_TIMEOUT", "Query exceeded 30 second timeout", { query: "SELECT * FROM users", duration: 30000, }); } catch (error) { if (error instanceof DatabaseError) { console.log(`Database error: ${error.code}`); console.log(`Category: ${error.category}`); console.log(`Can retry: ${error.retryable}`); console.log(`Query: ${error.details?.query}`); } } ``` -------------------------------- ### Runtime Assertions with Guard Function (TypeScript) Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md The `guard` function enforces runtime assertions, throwing a provided `BaseError` instance when a condition is falsy. It enables TypeScript type narrowing and works with any truthy/falsy values, preserving error context and stack traces. ```typescript import { BaseError, guard } from "@shirudo/base-error"; class UserNotFoundError extends BaseError<"UserNotFoundError"> { constructor(userId: string) { super(`User ${userId} not found`); } } class ValidationError extends BaseError<"ValidationError"> { constructor(message: string) { super(message); } } // Basic usage function processUser(user: User | null) { // Assert that user exists, throw custom error if not guard(user, new UserNotFoundError("current-user")); // TypeScript now knows user is not null console.log(user.name); // No TypeScript error } // Validation example function validateEmail(email: string) { const isValid = email.includes("@") && email.includes("."); guard(isValid, new ValidationError("Invalid email format")); // Continue with valid email return email.toLowerCase(); } // Works with any truthy/falsy values function processArray(items: unknown[]) { guard(items.length > 0, new ValidationError("Array cannot be empty")); // Process non-empty array return items.map((item) => String(item)); } ``` -------------------------------- ### Integrate Error Handling with Retry Logic in TypeScript Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md Implements a generic `withRetry` function that handles asynchronous operations and automatically retries them based on error properties. It supports exponential backoff and checks for `StructuredError.retryable` before retrying, ensuring robust fault tolerance. ```typescript async function withRetry( fn: () => Promise, maxAttempts: number = 3, ): Promise { let lastError: unknown; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fn(); } catch (error) { lastError = error; // Check if error is retryable if ( error instanceof StructuredError && error.retryable && attempt < maxAttempts ) { console.log(`Attempt ${attempt} failed, retrying...`); await sleep(1000 * attempt); // Exponential backoff continue; } // Non-retryable or last attempt throw error; } } throw lastError; } // Usage const result = await withRetry(async () => { // This might throw a retryable StructuredError return await fetchUserFromDatabase(userId); }); ``` -------------------------------- ### Type Guards for BaseError, StructuredError, and Retryable Checks Source: https://context7.com/shi-rudo/base-error-ts/llms.txt Utilize type guard functions like `isBaseError`, `isStructuredError`, and `isRetryable` to safely narrow down error types within catch blocks. These guards help in conditionally accessing specific error properties and determining retryability. ```typescript import { BaseError, StructuredError, isBaseError, isStructuredError, isRetryable } from "@shirudo/base-error"; async function handleOperation() { try { await someOperation(); } catch (error) { // Check if it's any BaseError if (isBaseError(error)) { console.log(error.timestamp); // TypeScript knows this exists console.log(error.timestampIso); console.log(error.message); } // Check if it's a StructuredError with metadata if (isStructuredError(error)) { console.log(error.code); // TypeScript knows this exists console.log(error.category); console.log(error.retryable); console.log(error.details); } // Check if error is retryable (duck-typing, works with any object) if (isRetryable(error)) { // TypeScript knows error.retryable === true console.log("Safe to retry this operation"); await retryOperation(); } else { console.log("Do not retry, handle error immediately"); throw error; } } } // isRetryable works with any object that has retryable: true const customError = { retryable: true, message: "Timeout" }; if (isRetryable(customError)) { console.log("This is retryable!"); } ``` -------------------------------- ### BaseError Class Definition (TypeScript) Source: https://github.com/shi-rudo/base-error-ts/blob/main/README.md The `BaseError` class extends the native `Error` class, providing automatic name inference, timestamping, and methods for managing user-friendly messages, including localization. It is designed for creating structured and type-safe errors. ```typescript class BaseError extends Error { // Constructor with automatic name inference constructor(message: string, cause?: unknown); // Properties readonly name: T; // Error type name (automatically inferred) readonly timestamp: number; // Epoch-ms timestamp readonly timestampIso: string; // ISO-8601 timestamp readonly stack?: string; // Stack trace readonly cause?: unknown; // Error cause (if provided) // Methods toJSON(): Record; // Serialize to JSON // User Message Methods (v2.1+) withUserMessage(message: string): this; // Set default user-friendly message addLocalizedMessage(lang: string, message: string): this; // Add localized message (prevents duplicates) updateLocalizedMessage(lang: string, message: string): this; // Update/set localized message (allows overwriting) getUserMessage(options?: { preferredLang?: string; fallbackLang?: string; }): string | undefined; // Get appropriate user message } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.