UNPKG

@ensnode/ensrainbow-sdk

Version:

ENSRainbow SDK for interacting with the ENSRainbow API.

341 lines (338 loc) 14.2 kB
import { LabelHash, EncodedLabelHash, Label } from 'enssdk'; import { EnsRainbowClientLabelSet, EnsRainbowPublicConfig } from '@ensnode/ensnode-sdk'; /** * Error thrown by {@link EnsRainbowApiClient} methods when the ENSRainbow service responds * with a non-2xx HTTP status code. * * Carries the HTTP status code as a structured property (rather than only embedding it in the * error message) so callers can branch their retry/abort logic on the status — e.g. retry on * `503 Service Unavailable` while ENSRainbow bootstraps, but abort immediately on `404`/`500`, * which usually indicate a misconfigured base URL or a hard server failure. * * Network-level failures (DNS, ECONNREFUSED, fetch parse errors) are *not* wrapped in this * class — they propagate as their original `Error` (typically a `TypeError` from `fetch`), * because such failures are commonly transient during cold start and should remain retryable * by callers. */ declare class EnsRainbowHttpError extends Error { readonly name = "EnsRainbowHttpError"; /** * The HTTP status code returned by the ENSRainbow service. */ readonly status: number; /** * The HTTP status text returned by the ENSRainbow service, if any. */ readonly statusText: string; constructor(message: string, status: number, statusText?: string); } declare namespace EnsRainbow { export type ApiClientOptions = EnsRainbowApiClientOptions; export interface ApiClient { count(): Promise<CountResponse>; /** * Get the public configuration of the ENSRainbow service */ config(): Promise<ENSRainbowPublicConfig>; /** * Heal a labelHash to its original label. * Accepts a strict `LabelHash`, an `EncodedLabelHash` (bracket-enclosed), or any string * that can be normalized (missing `0x` prefix, uppercase hex chars, or 63-char hex). * Returns a `HealBadRequestError` if the input cannot be normalized to a valid labelHash. */ heal(labelHash: LabelHash | EncodedLabelHash | string): Promise<HealResponse>; health(): Promise<HealthResponse>; /** * Check whether the ENSRainbow service has finished bootstrapping and is ready to serve requests. * * Throws when the service is not ready (e.g. 503 while the database is still being downloaded * or validated) so callers can retry. */ ready(): Promise<ReadyResponse>; getOptions(): Readonly<EnsRainbowApiClientOptions>; } type StatusCode = (typeof StatusCode)[keyof typeof StatusCode]; type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode]; export interface HealthResponse { status: "ok"; } /** * Response returned by `GET /ready` when the ENSRainbow service is ready to serve requests. */ export interface ReadyResponse { status: "ok"; } /** * Generic error shape used by endpoints that return 503 Service Unavailable while the * database is still bootstrapping (downloading, extracting, or validating). */ export interface ServiceUnavailableError { status: typeof StatusCode.Error; error: string; errorCode: typeof ErrorCode.ServiceUnavailable; } export interface BaseHealResponse<Status extends StatusCode, Error extends ErrorCode> { status: Status; label?: Label | never; error?: string | never; errorCode?: Error | never; } export interface HealSuccess extends BaseHealResponse<typeof StatusCode.Success, never> { status: typeof StatusCode.Success; label: Label; error?: never; errorCode?: never; } export interface HealNotFoundError extends BaseHealResponse<typeof StatusCode.Error, typeof ErrorCode.NotFound> { status: typeof StatusCode.Error; label?: never; error: string; errorCode: typeof ErrorCode.NotFound; } export interface HealServerError extends BaseHealResponse<typeof StatusCode.Error, typeof ErrorCode.ServerError> { status: typeof StatusCode.Error; label?: never; error: string; errorCode: typeof ErrorCode.ServerError; } export interface HealBadRequestError extends BaseHealResponse<typeof StatusCode.Error, typeof ErrorCode.BadRequest> { status: typeof StatusCode.Error; label?: never; error: string; errorCode: typeof ErrorCode.BadRequest; } export interface HealServiceUnavailableError extends BaseHealResponse<typeof StatusCode.Error, typeof ErrorCode.ServiceUnavailable> { status: typeof StatusCode.Error; label?: never; error: string; errorCode: typeof ErrorCode.ServiceUnavailable; } export type HealResponse = HealSuccess | HealNotFoundError | HealServerError | HealBadRequestError | HealServiceUnavailableError; export type HealError = Exclude<HealResponse, HealSuccess>; /** * Server errors and transient bootstrap errors should not be cached. */ export type CacheableHealResponse = Exclude<HealResponse, HealServerError | HealServiceUnavailableError>; export interface BaseCountResponse<Status extends StatusCode, Error extends ErrorCode> { status: Status; count?: number | never; timestamp?: string | never; error?: string | never; errorCode?: Error | never; } export interface CountSuccess extends BaseCountResponse<typeof StatusCode.Success, never> { status: typeof StatusCode.Success; /** The total count of labels that can be healed by the ENSRainbow instance. Always a * non-negative integer. */ count: number; timestamp: string; error?: never; errorCode?: never; } export interface CountServerError extends BaseCountResponse<typeof StatusCode.Error, typeof ErrorCode.ServerError> { status: typeof StatusCode.Error; count?: never; timestamp?: never; error: string; errorCode: typeof ErrorCode.ServerError; } export interface CountServiceUnavailableError extends BaseCountResponse<typeof StatusCode.Error, typeof ErrorCode.ServiceUnavailable> { status: typeof StatusCode.Error; count?: never; timestamp?: never; error: string; errorCode: typeof ErrorCode.ServiceUnavailable; } export type CountResponse = CountSuccess | CountServerError | CountServiceUnavailableError; /** * Complete public configuration object for ENSRainbow. * * Contains all public configuration information about the ENSRainbow service instance, * including version, label set information, and record counts. */ export type ENSRainbowPublicConfig = EnsRainbowPublicConfig; export { }; } interface EnsRainbowApiClientOptions { /** * The maximum number of `HealResponse` values to cache. * Must be a non-negative integer. * Setting to 0 will disable caching. */ cacheCapacity: number; /** * The URL of an ENSRainbow API endpoint. */ endpointUrl: URL; /** * Optional client label set preferences that the ENSRainbow server at endpointUrl is expected to * support. If provided, enables deterministic heal results across time, such that only * labels from label sets with versions less than or equal to this value will be returned. * Therefore, even if the ENSRainbow server later ingests label sets with greater versions * than this value, the results returned across time can be deterministic. If * provided, heal operations with this EnsRainbowApiClient will validate the ENSRainbow * server manages a compatible label set. If not provided no specific labelSetId validation * will be performed during heal operations. * If `labelSetId` is provided without `labelSetVersion`, the server will use the latest * available version. * If `labelSetVersion` is defined, only labels from sets less than or equal to this value * will be returned. * When `labelSetVersion` is defined, `labelSetId` must also be defined. */ clientLabelSet?: EnsRainbowClientLabelSet; } /** * ENSRainbow API client * * @example * ```typescript * // default options * const client = new EnsRainbowApiClient(); * // custom options * const client = new EnsRainbowApiClient({ * endpointUrl: new URL("https://api.ensrainbow.io"), * }); * ``` */ declare class EnsRainbowApiClient implements EnsRainbow.ApiClient { private readonly options; private readonly cache; private readonly clientLabelSetSearchParams; static readonly DEFAULT_CACHE_CAPACITY = 1000; /** * Create default client options. * * @returns default options */ static defaultOptions(): EnsRainbow.ApiClientOptions; constructor(options?: Partial<EnsRainbow.ApiClientOptions>); /** * Attempt to [heal](https://ensnode.io/ensrainbow/concepts/glossary#heal) a labelHash to its original label. * * Note on returned labels: ENSRainbow returns labels exactly as they are * represented in source rainbow table data. This means: * * - Labels may or may not be ENS-normalized * - Labels can contain any valid string, including dots, null bytes, or be empty * - Clients should handle all possible string values appropriately * * @param labelHash - A labelHash to heal, either as a strict `LabelHash`, an `EncodedLabelHash` * (bracket-enclosed), or any string that can be normalized (missing `0x` prefix, uppercase hex * chars, or 63-char hex are all accepted and normalized automatically). * @returns a `HealResponse` indicating the result of the request and the healed label if successful. * Returns a `HealBadRequestError` if the input cannot be normalized to a valid labelHash. * @throws if the request fails due to network failures, DNS lookup failures, request timeouts, * CORS violations, or Invalid URLs * @example * ```typescript * const response = await client.heal( * "0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc" * ); * * console.log(response); * * // Output: * // { * // status: "success", * // label: "vitalik" * // } * * const notFoundResponse = await client.heal( * "0xf64dc17ae2e2b9b16dbcb8cb05f35a2e6080a5ff1dc53ac0bc48f0e79111f264" * ); * * console.log(notFoundResponse); * * // Output: * // { * // status: "error", * // error: "Label not found", * // errorCode: 404 * // } * ``` */ heal(labelHash: LabelHash | EncodedLabelHash | string): Promise<EnsRainbow.HealResponse>; /** * Get Count of Healable Labels * * @returns a `CountResponse` indicating the result and the timestamp of the request and the * number of healable labels if successful * @throws if the request fails due to network failures, DNS lookup failures, request timeouts, * CORS violations, or Invalid URLs * @example * * const response = await client.count(); * * console.log(response); * * // { * // "status": "success", * // "count": 133856894, * // "timestamp": "2024-01-30T11:18:56Z" * // } * */ count(): Promise<EnsRainbow.CountResponse>; /** * * Simple verification that the service is running, either in your local setup or for the * provided hosted instance. * @returns a status of ENS Rainbow service * @example * * const response = await client.health(); * * console.log(response); * * // { * // "status": "ok", * // } */ health(): Promise<EnsRainbow.HealthResponse>; /** * Check whether the ENSRainbow service is ready (database is downloaded, validated, and open). * * Unlike {@link EnsRainbowApiClient.health}, which is a pure liveness probe that succeeds as soon * as the HTTP server is accepting requests, `ready()` only resolves once the service has finished * bootstrapping its database. Clients that require a usable database (e.g. ENSIndexer) should * poll this method instead of `health()` during startup. * * @throws {EnsRainbowHttpError} if the service responds with a non-2xx status. The thrown * error carries the HTTP `status` so callers can distinguish the retryable bootstrap case * (`503 Service Unavailable`) from likely-non-retryable misconfiguration / server failures * (e.g. `404`, `500`) and abort retries early in the latter cases. * @throws Network/fetch errors (DNS, ECONNREFUSED, etc.) propagate as their original error * type and should generally remain retryable, since they are common during cold start before * the ENSRainbow HTTP server has bound its port. */ ready(): Promise<EnsRainbow.ReadyResponse>; /** * Get the public configuration of the ENSRainbow service. * * @throws {EnsRainbowHttpError} if the service responds with a non-2xx status. */ config(): Promise<EnsRainbow.ENSRainbowPublicConfig>; /** * Get a copy of the current client options. * * @returns a copy of the current client options. */ getOptions(): Readonly<EnsRainbowApiClientOptions>; } /** * Determine if a heal response is an error. * * @param response the heal response to check * @returns true if the response is an error, false otherwise */ declare const isHealError: (response: EnsRainbow.HealResponse) => response is EnsRainbow.HealError; /** * Determine if a heal response is cacheable. * * Server errors at not cachable and should be retried. * * @param response the heal response to check * @returns true if the response is cacheable, false otherwise */ declare const isCacheableHealResponse: (response: EnsRainbow.HealResponse) => response is EnsRainbow.CacheableHealResponse; export { EnsRainbow, EnsRainbowApiClient, type EnsRainbowApiClientOptions, EnsRainbowHttpError, isCacheableHealResponse, isHealError };