All files / Rindu/utils errors.ts

70.58% Statements 24/34
62.5% Branches 5/8
54.54% Functions 6/11
70.58% Lines 24/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108                            7x 7x 7x 7x 7x   7x 7x         4x                             2x               2x             2x             2x             2x                   7x 7x 7x       8x   3x       6x   2x       4x       2x 2x 2x      
import { Context } from "react";
 
interface ErrorMetadata {
  code?: string;
  timestamp?: string;
  details?: Record<string, unknown>;
}
 
abstract class BaseError extends Error {
  readonly timestamp: string;
  readonly code?: string;
  readonly details?: Record<string, unknown>;
 
  constructor(message: string, metadata: ErrorMetadata = {}) {
    super(message);
    this.name = this.constructor.name;
    this.timestamp = metadata.timestamp ?? new Date().toISOString();
    this.code = metadata.code;
    this.details = metadata.details;
 
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, this.constructor);
    }
  }
 
  static isThisError(error: unknown): error is BaseError {
    return error instanceof this;
  }
 
  toJSON() {
    return {
      name: this.name,
      message: this.message,
      code: this.code,
      timestamp: this.timestamp,
      details: this.details,
      stack: this.stack,
    };
  }
}
 
export class ContextError<T> extends BaseError {
  constructor(context: Context<T | undefined>) {
    const contextName = context.displayName ?? "Context";
    super(`use${contextName} must be used within a ${contextName}Provider`);
    this.name = "ContextError";
  }
}
 
export class TargetElementError extends BaseError {
  constructor(elementId: string) {
    super(`Component needs a target element with id: ${elementId}`);
    this.name = "TargetElementError";
  }
}
 
export class RemoveTrackError extends BaseError {
  constructor() {
    super("Failed to remove tracks");
    this.name = "RemoveTrackError";
  }
}
 
export class CreatePlaylistError extends BaseError {
  constructor() {
    super("Failed to create playlist");
    this.name = "CreatePlaylistError";
  }
}
 
export class HTTPError extends BaseError {
  readonly statusCode: number;
  readonly header?: string;
 
  constructor(
    statusCode: number,
    message: string,
    header?: string,
    metadata?: ErrorMetadata
  ) {
    super(message, metadata);
    this.statusCode = statusCode;
    this.header = header;
  }
}
 
export class BadRequestError extends HTTPError {
  constructor(header?: string, metadata?: ErrorMetadata) {
    super(400, "Bad request", header, metadata);
  }
}
 
export class NotFoundError extends HTTPError {
  constructor(header?: string, metadata?: ErrorMetadata) {
    super(404, "Not found", header, metadata);
  }
}
 
export class TimeOutError extends HTTPError {
  readonly timeoutMs?: number;
 
  constructor(timeoutMs?: number, header?: string, metadata?: ErrorMetadata) {
    const afterMessage = timeoutMs ? ` after ${timeoutMs}ms` : "";
    super(408, `Request timeout${afterMessage}`, header, metadata);
    this.timeoutMs = timeoutMs;
  }
}