{"version":3,"sources":["../src/errors.ts"],"sourcesContent":["import type { ComposeErrorKind, SimulationRevert } from '@lifi/compose-spec';\n\n/**\n * Machine-readable error codes returned by the SDK.\n *\n * - `NETWORK_ERROR` — The HTTP request failed (DNS, timeout, connection refused).\n * - `VALIDATION_ERROR` — The server rejected the request (HTTP 400/422).\n * - `UNAUTHENTICATED` — The request lacks valid authentication credentials (HTTP 401).\n * - `FORBIDDEN` — The server understood the request but refuses to authorise it (HTTP 403).\n * - `SERVER_ERROR` — The server returned a 5xx status.\n * - `RATE_LIMITED` — The server returned HTTP 429.\n * - `NOT_FOUND` — The requested resource does not exist (HTTP 404).\n * - `UNKNOWN_ERROR` — An unexpected error that doesn't fit other categories.\n */\nexport type ComposeErrorCode =\n  | 'NETWORK_ERROR'\n  | 'VALIDATION_ERROR'\n  | 'UNAUTHENTICATED'\n  | 'FORBIDDEN'\n  | 'SERVER_ERROR'\n  | 'RATE_LIMITED'\n  | 'NOT_FOUND'\n  | 'UNKNOWN_ERROR';\n\n/**\n * Error class for all failures originating from the Compose SDK or API.\n *\n * Includes structured metadata beyond the error message to support\n * programmatic error handling.\n *\n * @example\n * ```ts\n * try {\n *   await builder.compile(run);\n * } catch (e) {\n *   if (isComposeError(e) && e.code === 'VALIDATION_ERROR') {\n *     console.error('Invalid request:', e.message, e.path);\n *   }\n * }\n * ```\n */\nexport class ComposeError extends Error {\n  override readonly name = 'ComposeError';\n  /** Machine-readable error category. */\n  readonly code: ComposeErrorCode;\n  /** HTTP status code, when the error originated from an HTTP response. */\n  readonly status?: number;\n  /** The request URL that produced the error. */\n  readonly url?: string;\n  /** Server-provided error kind for finer-grained classification. */\n  readonly kind?: ComposeErrorKind;\n  /** JSON-pointer path to the field that caused a validation error. */\n  readonly path?: string;\n  /**\n   * Simulation revert diagnostics attached to `simulation_revert` errors.\n   * Contains the raw error bytes and decoded error candidates when the\n   * backend can parse the revert reason.\n   */\n  readonly details?: SimulationRevert;\n\n  constructor(\n    code: ComposeErrorCode,\n    message: string,\n    options?: {\n      status?: number;\n      url?: string;\n      cause?: unknown;\n      kind?: ComposeErrorKind;\n      path?: string;\n      details?: SimulationRevert;\n    },\n  ) {\n    super(message, { cause: options?.cause });\n    this.code = code;\n    this.status = options?.status;\n    this.url = options?.url;\n    this.kind = options?.kind;\n    this.path = options?.path;\n    this.details = options?.details;\n  }\n}\n\n/**\n * Type guard that narrows an unknown error to {@link ComposeError}.\n * @param e - The value to check.\n * @returns `true` if `e` is an instance of `ComposeError`.\n */\nexport const isComposeError = (e: unknown): e is ComposeError =>\n  e instanceof ComposeError ||\n  (e instanceof Error && e.name === 'ComposeError' && 'code' in e);\n\nconst STATUS_TO_CODE: ReadonlyMap<number, ComposeErrorCode> = new Map<\n  number,\n  ComposeErrorCode\n>([\n  [400, 'VALIDATION_ERROR'],\n  [401, 'UNAUTHENTICATED'],\n  [403, 'FORBIDDEN'],\n  [404, 'NOT_FOUND'],\n  [422, 'VALIDATION_ERROR'],\n  [429, 'RATE_LIMITED'],\n]);\n\ninterface ServerErrorBody {\n  readonly error?: {\n    readonly kind?: string;\n    readonly message?: string;\n    readonly path?: string;\n    readonly details?: SimulationRevert;\n  };\n}\n\nconst tryParseErrorBody = (body: string): ServerErrorBody | null => {\n  try {\n    return JSON.parse(body) as ServerErrorBody;\n  } catch {\n    return null;\n  }\n};\n\n/**\n * Constructs a {@link ComposeError} from an HTTP error response, extracting\n * structured error details from the response body when available.\n *\n * @param status - The HTTP status code.\n * @param body - The raw response body text.\n * @param url - The request URL that produced the error.\n * @returns A `ComposeError` with the appropriate error code and metadata.\n */\nexport const errorFromHttpResponse = (\n  status: number,\n  body: string,\n  url: string,\n): ComposeError => {\n  const parsed = tryParseErrorBody(body);\n  const serverError = parsed?.error;\n\n  return new ComposeError(\n    STATUS_TO_CODE.get(status) ??\n      (status >= 500 ? 'SERVER_ERROR' : 'UNKNOWN_ERROR'),\n    (serverError?.message ?? body) || `HTTP ${status}`,\n    {\n      status,\n      url,\n      kind: serverError?.kind as ComposeErrorKind | undefined,\n      path: serverError?.path,\n      details: serverError?.details,\n    },\n  );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyCO,MAAM,qBAAqB,MAAM;AAAA,EACpB,OAAO;AAAA;AAAA,EAEhB;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA,EAET,YACE,MACA,SACA,SAQA;AACA,UAAM,SAAS,EAAE,OAAO,SAAS,MAAM,CAAC;AACxC,SAAK,OAAO;AACZ,SAAK,SAAS,SAAS;AACvB,SAAK,MAAM,SAAS;AACpB,SAAK,OAAO,SAAS;AACrB,SAAK,OAAO,SAAS;AACrB,SAAK,UAAU,SAAS;AAAA,EAC1B;AACF;AAOO,MAAM,iBAAiB,CAAC,MAC7B,aAAa,gBACZ,aAAa,SAAS,EAAE,SAAS,kBAAkB,UAAU;AAEhE,MAAM,iBAAwD,oBAAI,IAGhE;AAAA,EACA,CAAC,KAAK,kBAAkB;AAAA,EACxB,CAAC,KAAK,iBAAiB;AAAA,EACvB,CAAC,KAAK,WAAW;AAAA,EACjB,CAAC,KAAK,WAAW;AAAA,EACjB,CAAC,KAAK,kBAAkB;AAAA,EACxB,CAAC,KAAK,cAAc;AACtB,CAAC;AAWD,MAAM,oBAAoB,CAAC,SAAyC;AAClE,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAWO,MAAM,wBAAwB,CACnC,QACA,MACA,QACiB;AACjB,QAAM,SAAS,kBAAkB,IAAI;AACrC,QAAM,cAAc,QAAQ;AAE5B,SAAO,IAAI;AAAA,IACT,eAAe,IAAI,MAAM,MACtB,UAAU,MAAM,iBAAiB;AAAA,KACnC,aAAa,WAAW,SAAS,QAAQ,MAAM;AAAA,IAChD;AAAA,MACE;AAAA,MACA;AAAA,MACA,MAAM,aAAa;AAAA,MACnB,MAAM,aAAa;AAAA,MACnB,SAAS,aAAa;AAAA,IACxB;AAAA,EACF;AACF;","names":[]}