src/rest/errors.ts
v0.2.1 · 1.8 KB
// Error classes of the REST read path. A caller must tell "the exchange answered" (HTTP error, a
// known outcome) from "the request may or may not have arrived" (transport) and from "the response
// cannot be trusted" (read/parse). For reads all three mean "not read"; for writes (signer module)
// the distinction decides whether a retry is safe.
/** The exchange answered with a non-2xx status. 4xx is never retried (429 included; see the knowledge base). */
export class LighterHttpError extends Error {
readonly status: number;
readonly path: string;
/** Response body, truncated. */
readonly body: string;
constructor(status: number, path: string, body = '') {
super(`HTTP ${status} on ${path.split('?')[0]}`);
this.name = 'LighterHttpError';
this.status = status;
this.path = path;
this.body = body.slice(0, 500);
}
}
/** Network failure or timeout after all retries. */
export class LighterTransportError extends Error {
readonly path: string;
readonly attempts: number;
constructor(path: string, attempts: number, message: string, options?: { cause?: unknown }) {
super(`${path.split('?')[0]} failed after ${attempts} attempt(s): ${message}`, options);
this.name = 'LighterTransportError';
this.path = path;
this.attempts = attempts;
}
}
/** A 2xx response whose body cannot be trusted as a whole (fail-closed decoding). */
export class LighterReadError extends Error {
constructor(message: string) {
super(message);
this.name = 'LighterReadError';
}
}
/** True for HTTP 5xx, timeouts and network errors: worth a retry on a read. */
export function isRetryableReadError(err: unknown): boolean {
if (err instanceof LighterHttpError) return err.status >= 500;
if (err instanceof LighterReadError) return false;
return true;
}