{"version":3,"sources":["../src/errors.ts"],"sourcesContent":["import type {\n  ComposeErrorKind,\n  ComposeRouteErrorKind,\n  FailedPreparedOp,\n  GenericComposeErrorKind,\n  SimulationRevert,\n} from '@lifi/compose-spec';\nimport z from 'zod';\n\nimport {\n  parseServerErrorBody,\n  type ServerErrorBody,\n} from './responseSchemas.js';\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/** Version details returned when the backend rejects an outdated SDK. */\nexport interface ComposeSdkOutdated {\n  readonly sdkVersion: string;\n  readonly serverVersion: string;\n  readonly minimumSdkVersion: string;\n}\n\n/**\n * Version details attached when the SDK is ahead of the backend it reached.\n * Raised by the backend's version gate, or by the SDK itself when the\n * `x-lifi-composer-version` response header names an older contract than the\n * one this SDK was built against.\n */\nexport interface ComposeServerOutdated {\n  readonly sdkVersion: string;\n  readonly serverVersion: string;\n}\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 | ComposeRouteErrorKind;\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   * The prepared ops that failed, attached to `preparation_error` errors.\n   * Each entry carries the `callId` of the failing node so callers can drop\n   * the unroutable legs and resubmit a smaller flow.\n   */\n  readonly failedOps?: readonly FailedPreparedOp[];\n  /**\n   * The `callId`s of the prepared ops that succeeded, attached to\n   * `preparation_error` errors alongside {@link ComposeError.failedOps}.\n   */\n  readonly succeededOps?: readonly string[];\n  /** Version details attached only to `sdk_outdated` errors. */\n  readonly sdkOutdated?: ComposeSdkOutdated;\n  /** Version details attached only to `server_outdated` errors. */\n  readonly serverOutdated?: ComposeServerOutdated;\n\n  constructor(\n    code: ComposeErrorCode,\n    message: string,\n    options?: {\n      status?: number;\n      url?: string;\n      cause?: unknown;\n      kind?: ComposeErrorKind | ComposeRouteErrorKind;\n      path?: string;\n      details?: SimulationRevert;\n      failedOps?: readonly FailedPreparedOp[];\n      succeededOps?: readonly string[];\n      sdkOutdated?: ComposeSdkOutdated;\n      serverOutdated?: ComposeServerOutdated;\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    this.failedOps = options?.failedOps;\n    this.succeededOps = options?.succeededOps;\n    this.sdkOutdated = options?.sdkOutdated;\n    this.serverOutdated = options?.serverOutdated;\n  }\n}\n\n/**\n * The per-op preparation diagnostics carried by `preparation_error` responses,\n * with both arrays known to be present. Produced by narrowing with\n * {@link isComposePreparationError}.\n */\nexport interface ComposePreparationOps {\n  readonly failedOps: readonly FailedPreparedOp[];\n  readonly succeededOps: readonly string[];\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\n/**\n * Type guard for `preparation_error` failures (HTTP 422): a mixed basket where\n * some prepared ops failed and others succeeded. Narrows both\n * {@link ComposeError.failedOps} and {@link ComposeError.succeededOps} to\n * present, so callers can read them without a cast or a truthiness check.\n *\n * @param e - The value to check.\n * @returns `true` if `e` is a `ComposeError` carrying per-op preparation diagnostics.\n *\n * @example\n * ```ts\n * try {\n *   await builder.compile(run);\n * } catch (e) {\n *   if (isComposePreparationError(e)) {\n *     console.error('Failed ops:', e.failedOps);\n *     console.error('Succeeded ops:', e.succeededOps);\n *   }\n * }\n * ```\n */\nexport const isComposePreparationError = (\n  e: unknown,\n): e is ComposeError & ComposePreparationOps =>\n  isComposeError(e) &&\n  e.kind === 'preparation_error' &&\n  Array.isArray(e.failedOps) &&\n  Array.isArray(e.succeededOps);\n\n// `isComposeError` accepts a structurally-similar error by name, so an error\n// raised by a *second* copy of this package in the dependency tree reaches the\n// guard below without its `sdkOutdated` field being type-guaranteed. Parse it.\nconst sdkOutdatedSchema = z.object({\n  sdkVersion: z.string(),\n  serverVersion: z.string(),\n  minimumSdkVersion: z.string(),\n});\n\n/**\n * Narrows an outdated-SDK rejection to its required version details.\n *\n * @example\n * ```ts\n * try {\n *   await builder.compile(run);\n * } catch (e) {\n *   if (isComposeSdkOutdatedError(e)) {\n *     console.error(`Upgrade to at least ${e.sdkOutdated.minimumSdkVersion}`);\n *     return;\n *   }\n *   throw e;\n * }\n * ```\n */\nexport const isComposeSdkOutdatedError = (\n  e: unknown,\n): e is ComposeError & { readonly sdkOutdated: ComposeSdkOutdated } =>\n  isComposeError(e) &&\n  e.kind === 'sdk_outdated' &&\n  sdkOutdatedSchema.safeParse(e.sdkOutdated).success;\n\nconst serverOutdatedSchema = z.object({\n  sdkVersion: z.string(),\n  serverVersion: z.string(),\n});\n\n/**\n * Narrows a server-behind-SDK rejection to its required version details.\n *\n * This is the deploy-window error: the SDK on npm is ahead of the backend that\n * answered. Pin the SDK to the server's `major.minor`, or wait for the rollout.\n *\n * @example\n * ```ts\n * try {\n *   await builder.compile(run);\n * } catch (e) {\n *   if (isComposeServerOutdatedError(e)) {\n *     console.error(`Server serves ${e.serverOutdated.serverVersion}`);\n *     return;\n *   }\n *   throw e;\n * }\n * ```\n */\nexport const isComposeServerOutdatedError = (\n  e: unknown,\n): e is ComposeError & { readonly serverOutdated: ComposeServerOutdated } =>\n  isComposeError(e) &&\n  e.kind === 'server_outdated' &&\n  serverOutdatedSchema.safeParse(e.serverOutdated).success;\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\nconst tryParseErrorBody = (body: string): ServerErrorBody | null => {\n  let json: unknown;\n  try {\n    json = JSON.parse(body);\n  } catch {\n    return null;\n  }\n  return parseServerErrorBody(json);\n};\n\n/**\n * Extracts the version triple an `sdk_outdated` or `server_outdated` envelope\n * carries. The slots reuse the same schemas the type guards narrow with. Zod\n * strips keys the schema does not declare, so the parsed value is exactly the\n * triple; a partial payload fails the parse and yields `undefined` rather than\n * a half-populated object.\n */\nconst readVersionSlots = (serverError: ServerErrorBody['error']) => ({\n  sdkOutdated:\n    serverError?.kind === 'sdk_outdated'\n      ? sdkOutdatedSchema.safeParse(serverError).data\n      : undefined,\n  serverOutdated:\n    serverError?.kind === 'server_outdated'\n      ? serverOutdatedSchema.safeParse(serverError).data\n      : undefined,\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  const { sdkOutdated, serverOutdated } = readVersionSlots(serverError);\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\n        ComposeErrorKind | ComposeRouteErrorKind | undefined,\n      path: serverError?.path,\n      details: serverError?.details,\n      // The wire schema types `kind` as a bare string; the server only ever\n      // reports generic kinds for individual ops.\n      failedOps: serverError?.failedOps?.map((op) => ({\n        ...op,\n        kind: op.kind as GenericComposeErrorKind,\n      })),\n      succeededOps: serverError?.succeededOps,\n      sdkOutdated,\n      serverOutdated,\n    },\n  );\n};\n"],"mappings":"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","names":["z"]}