All files / src/errors apiErrors.ts

100% Statements 12/12
100% Branches 0/0
100% Functions 6/6
100% Lines 12/12

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                38x     38x 38x                                                                 26x 26x 26x 26x 26x           10x                             16x       1x                 2x      
import { ErrorCode, ErrorResponse } from '../types'
 
/**
 * Base class for all errors thrown by the SDK.
 */
export class SdkError extends Error {
  constructor(
    message: string,
    readonly response?: Response,
    cause?: Error
  ) {
    super(message, { cause })
    this.name = this.constructor.name
  }
}
 
/**
 * Error thrown when an HTTP request to the Fingerprint Server API fails.
 *
 * This is the base class for request-level errors. It is thrown directly when
 * the server responds with an error that does not match the Server API error
 * response shape (for example, an error returned by an intermediate proxy or
 * load balancer).
 *
 * When the response is a structured Server API error, a {@link ServerApiError}
 * (or one of its subclasses, such as {@link TooManyRequestsError}) is thrown
 * instead. Those errors narrow {@link errorCode} to the strongly typed
 * {@link ServerApiError.errorCode}.
 */
export class RequestError<Code extends number = number, Body = unknown> extends SdkError {
  // HTTP Status code
  readonly statusCode: Code
 
  // Best-effort error code. On a plain `RequestError` (non–Server-API responses; see
  // `RequestError.unknown`) this is a placeholder derived from `statusText`, so it is typed as a
  // free-form `string`. `ServerApiError` narrows it to the strongly typed `ErrorCode`.
  readonly errorCode: string
 
  // API error response
  readonly responseBody: Body
 
  // Raw HTTP response
  override readonly response: Response
 
  constructor(message: string, body: Body, statusCode: Code, errorCode: string, response: Response) {
    super(message, response)
    this.responseBody = body
    this.response = response
    this.errorCode = errorCode
    this.statusCode = statusCode
  }
 
  static unknown(response: Response, body?: unknown) {
    // Non–Server-API responses (e.g. proxy or load balancer errors) carry no structured error
    // code, so `statusText` is used as a best-effort placeholder.
    return new RequestError('Unknown error', body, response.status, response.statusText, response)
  }
}
 
/**
 * Error thrown when the Fingerprint Server API returns a structured error
 * response. In addition to the {@link RequestError} properties, it exposes a
 * strongly typed {@link errorCode} describing the reason for the failure.
 */
export class ServerApiError<Code extends number = number> extends RequestError<Code, ErrorResponse> {
  // Narrow the inherited `errorCode` to the strongly typed Server API union. The value is set by
  // the `RequestError` constructor; `declare` only refines its type (no runtime field is emitted).
  declare readonly errorCode: ErrorCode
 
  constructor(body: ErrorResponse, statusCode: Code, response: Response) {
    super(body.error.message, body, statusCode, body.error.code, response)
  }
 
  static fromErrorResponse(body: ErrorResponse, response: Response) {
    return new ServerApiError(body, response.status, response)
  }
}
 
/**
 * Error that indicates that the request was throttled.
 */
export class TooManyRequestsError extends ServerApiError<429> {
  constructor(body: ErrorResponse, response: Response) {
    super(body, 429, response)
  }
}