Skip to main content
jg-packages

Search

    HTTP requests

    jg-fetch

    A fetch wrapper that never throws: timeouts, retries that honour Retry-After, response size caps, and API envelopes.

    v0.3.0UniversalESMMIT

    npm install jg-fetch

    Usage

    request resolves to { data, error: null, meta } or { data: null, error, meta }, and never throws:

    ts
    import { request } from 'jg-fetch';
    
    const { data, error, meta } = await request<IUser>('https://api.example.com/users/1');
    if (error) {
      error.kind; // what failed, such as 'TIMEOUT', 'NETWORK_ERROR', or 'HTTP_ERROR'
      error.status; // 404, or null when no response arrived
    } else {
      data; // IUser
    }
    meta.attempts; // 1

    Read a jg-api-response envelope, validate its data, and send a fresh token on every attempt:

    ts
    import { request } from 'jg-fetch';
    import { z } from 'zod';
    
    const User = z.object({ id: z.number(), name: z.string() });
    
    const { data, error } = await request('/users/me', {
      baseUrl: 'https://api.example.com',
      parseAs: 'envelope', // resolves to the envelope's data
      schema: User, // data is { id: number; name: string }
      headers: async () => ({ authorization: `Bearer ${await getIdToken()}` }),
    });
    if (error?.kind === 'API_ERROR') {
      error.code; // the envelope error's code, such as 'USER_NOT_FOUND'
      error.message; // the envelope error's message
      error.data; // the envelope error's data, or null without any
      error.body; // the whole envelope
    }

    When a credential can expire, such as an ID token, refresh it and repeat the attempt at once, without using up a retry:

    ts
    await request('/users/me', {
      baseUrl,
      headers: async () => ({ authorization: `Bearer ${await getIdToken()}` }),
      // returning true repeats the attempt; once per call unless maxCredentialRefreshes says more
      refreshCredentials: async ({ status, signal }) => {
        if (status !== 401) {
          return false;
        }
        await refreshIdToken(signal);
        return true;
      },
    });

    Send JSON, query parameters, or any other body:

    ts
    await request('/orders', {
      baseUrl,
      method: 'POST',
      body: { items: [1, 2] }, // sent as JSON, with Content-Type: application/json
      query: { notify: true, tags: ['a', 'b'] }, // ?notify=true&tags=a&tags=b
    });
    await request('/avatar', { baseUrl, method: 'PUT', body: formData }); // the browser sets the multipart type

    A string, Blob, ArrayBuffer or view of one, FormData, URLSearchParams, or ReadableStream is sent as it is. Any other body, such as a Map, a Date, or a number, fails with INVALID_BODY before the request is sent, because fetch would turn it into text such as [object Map].

    Read other kinds of responses with parseAs: 'json' (the default), 'envelope', 'text', 'bytes', 'blob', 'response' for the unread Response, or 'none'. The data’s type follows it.

    Timeouts and retries

    Option Default What it does
    timeoutSeconds 15 Limits the whole call, retries and waits included.
    attemptTimeoutSeconds none Limits each attempt; an attempt that runs out retries.
    retryDelaysSeconds [3, 5] The waits before each retry. [] turns retries off.
    retryMethods GET, HEAD, OPTIONS The methods that may retry. Add POST only for requests that are safe to repeat.
    retryStatusCodes 408, 429, 500, 502, 503, 504 The statuses that may retry. 400–405, 409, 410, 413, and 422 never do.
    nonRetryableErrorCodes none API error codes that never retry.
    maxRetryAfterSeconds 30 The longest Retry-After a retry waits for.
    maxResponseBytes 10 MiB The largest body the buffered modes read.

    Network errors, attempt timeouts, and retryable statuses retry. A 429 retries only with Retry-After, and every retry waits the longer of its delay and Retry-After. When Retry-After asks for more than maxRetryAfterSeconds, or more than the time left, the call stops and the error carries retryAfterMs. A stream body never retries.

    Pass signal to cancel: its abort reports ABORTED, or TIMEOUT when its reason is a TimeoutError, such as AbortSignal.timeout(5000)’s.

    Errors

    The error is a FetchException, an Exception from jg-exception:

    Field Holds
    kind What failed, one of ERRORS
    code, message The envelope error’s code and message for an API_ERROR, otherwise the kind and its message
    status, headers, body The response’s status, headers, and body, parsed as JSON when it is JSON
    data The envelope error’s data for an API_ERROR, null when it has none; otherwise undefined
    retryAfterMs The wait Retry-After asked for
    method, url, attempts, durationMs The request, without its query string or fragment
    cause The original error

    Messages never include the URL or the body, and url and meta.url drop the query string and fragment, where tokens such as ?key= sit.

    Reading headers across origins

    A browser lets the page read only a few response headers from another origin. To read Retry-After, a cf-ray, or any custom header, the API must list them in Access-Control-Expose-Headers. Otherwise headers.get() returns null, and a 429 never retries, because its Retry-After can’t be read.

    Generated from TSDoc

    API reference

    Every export of [email protected], 26 in all, with its signature, its errors, and an example.

    Functions

    parseRetryAfterMs

    function

    Parses a Retry-After header into the milliseconds to wait. It accepts a delay in seconds, such as 120, or an HTTP date, such as Wed, 21 Oct 2015 07:28:00 GMT, whose wait is counted from nowMs. A date in the past waits 0, and a wait longer than MAX_TIMEOUT_SECONDS is clamped to it. For a header with several values, such as a WebSocket handshake's, the first one counts.

    Signature
    parseRetryAfterMs(
      value: string | readonly string[] | null | undefined,
      nowMs?: number,
    ): number | null

    Parameters

    valuestring | readonly string[] | null | undefined

    The header's value, or its values.

    nowMs?number

    The current time, in milliseconds since the epoch. Defaults to Date.now().

    Defaults to ....

    Returns

    number | null

    The milliseconds to wait, or null when the value is missing or invalid.

    Example
    import { parseRetryAfterMs } from 'jg-fetch';
    
    parseRetryAfterMs('120'); // 120000
    parseRetryAfterMs('Wed, 21 Oct 2015 07:28:30 GMT', Date.parse('Wed, 21 Oct 2015 07:28:00 GMT')); // 30000
    parseRetryAfterMs('soon'); // null

    request

    function

    Sends an HTTP request and resolves to its data or its error, never throwing. It retries network errors, attempt timeouts, and retryable statuses for the methods that may retry, waiting retryDelaysSeconds between attempts, or longer when the server sends Retry-After, all within timeoutSeconds. Each attempt sends a fresh Request. With parseAs 'envelope', it reads a jg-api-response envelope and resolves to its data, or to API_ERROR with the API's own code. With refreshCredentials, an attempt that fails with a response, such as a 401, can refresh the credentials and repeat at once, up to maxCredentialRefreshes times, without using up a retry.

    Signature
    request(
      url: string | URL,
      options: IRequestOptions<string> & { parseAs: "text" },
    ): Promise<IRequestResult<string>>

    Parameters

    urlstring | URL

    The URL, absolute or relative to baseUrl.

    optionsIRequestOptions<string> & { parseAs: "text" }

    The method, query, headers, body, how to read the response, and the timeouts and retries.

    Returns

    Promise<IRequestResult<string>>

    A promise that resolves to { data, error: null, meta } or { data: null, error, meta }, where error is a FetchException.

    Signature
    request(
      url: string | URL,
      options: IRequestOptions<Uint8Array<ArrayBufferLike>> & { parseAs: "bytes" },
    ): Promise<IRequestResult<Uint8Array<ArrayBufferLike>>>

    Parameters

    urlstring | URL

    The URL, absolute or relative to baseUrl.

    optionsIRequestOptions<Uint8Array<ArrayBufferLike>> & { parseAs: "bytes" }

    The method, query, headers, body, how to read the response, and the timeouts and retries.

    Returns

    Promise<IRequestResult<Uint8Array<ArrayBufferLike>>>

    A promise that resolves to { data, error: null, meta } or { data: null, error, meta }, where error is a FetchException.

    Signature
    request(
      url: string | URL,
      options: IRequestOptions<Blob> & { parseAs: "blob" },
    ): Promise<IRequestResult<Blob>>

    Parameters

    urlstring | URL

    The URL, absolute or relative to baseUrl.

    optionsIRequestOptions<Blob> & { parseAs: "blob" }

    The method, query, headers, body, how to read the response, and the timeouts and retries.

    Returns

    Promise<IRequestResult<Blob>>

    A promise that resolves to { data, error: null, meta } or { data: null, error, meta }, where error is a FetchException.

    Signature
    request(
      url: string | URL,
      options: IRequestOptions<Response> & { parseAs: "response" },
    ): Promise<IRequestResult<Response>>

    Parameters

    urlstring | URL

    The URL, absolute or relative to baseUrl.

    optionsIRequestOptions<Response> & { parseAs: "response" }

    The method, query, headers, body, how to read the response, and the timeouts and retries.

    Returns

    Promise<IRequestResult<Response>>

    A promise that resolves to { data, error: null, meta } or { data: null, error, meta }, where error is a FetchException.

    Signature
    request(
      url: string | URL,
      options: IRequestOptions<undefined> & { parseAs: "none" },
    ): Promise<IRequestResult<undefined>>

    Parameters

    urlstring | URL

    The URL, absolute or relative to baseUrl.

    optionsIRequestOptions<undefined> & { parseAs: "none" }

    The method, query, headers, body, how to read the response, and the timeouts and retries.

    Returns

    Promise<IRequestResult<undefined>>

    A promise that resolves to { data, error: null, meta } or { data: null, error, meta }, where error is a FetchException.

    Signature
    request<T = unknown>(
      url: string | URL,
      options?: IRequestOptions<T>,
    ): Promise<IRequestResult<T>>

    Parameters

    urlstring | URL

    The URL, absolute or relative to baseUrl.

    options?IRequestOptions<T>

    The method, query, headers, body, how to read the response, and the timeouts and retries.

    Returns

    Promise<IRequestResult<T>>

    A promise that resolves to { data, error: null, meta } or { data: null, error, meta }, where error is a FetchException.

    Example 1
    import { request } from 'jg-fetch';
    
    const { data, error } = await request<IUser>('/users/1', {
      baseUrl: 'https://api.example.com',
      parseAs: 'envelope',
      headers: async () => ({ authorization: `Bearer ${await getToken()}` }),
    });
    if (error) {
      error.kind; // such as 'API_ERROR' or 'TIMEOUT'
    }
    Example 2
    import { request } from 'jg-fetch';
    
    const { data: html } = await request('https://example.com', { parseAs: 'text' }); // string | null

    Classes

    FetchException

    class

    The error request returns when a call fails, never throws. kind says what failed, one of the ERRORS codes. For an API error, code, message, and data are the envelope error's; otherwise code is the kind. Its message never includes the URL or the body.

    Members

    • codeproperty
      string
    • dataproperty
      IJsonValue | undefined
    • severityproperty
      "expected" | "critical"
    • shouldLogproperty
      boolean
    • toJSONmethod
      toJSON(): IExceptionJson

      Converts the exception to a plain object, which JSON.stringify calls.

    • toStringmethod
      toString(): string

      Describes the exception in one line, with its code.

    • kindproperty
      "INVALID_URL" | "INVALID_OPTIONS" | "INVALID_HEADERS" | "INVALID_BODY" | "NETWORK_ERROR" | "TIMEOUT" | "ABORTED" | "HTTP_ERROR" | "API_ERROR" | "PARSE_ERROR" | "ENVELOPE_INVALID" | "RESPONSE_INVALID" | "RESPONSE_TOO_LARGE" | "CREDENTIALS_REFRESH_FAILED"

      what failed, one of the ERRORS codes

    • statusproperty
      number | null

      the HTTP status, or null when no response arrived

    • headersproperty
      Headers | null

      the response's headers, or null when no response arrived

    • bodyproperty
      unknown

      the response body: parsed JSON when it is JSON, otherwise its text

    • retryAfterMsproperty
      number | null

      the wait the server asked for with Retry-After, in milliseconds, or null without one

    • methodproperty
      IHttpMethod

      the request's method

    • urlproperty
      string

      the request's URL, without its query string or fragment

    • attemptsproperty
      number

      the number of attempts made

    • durationMsproperty
      number

      the milliseconds the whole call took

    • constructorconstructor
      new FetchException(kind: "INVALID_URL" | "INVALID_OPTIONS" | "INVALID_HEADERS" | "INVALID_BODY" | "NETWORK_ERROR" | "TIMEOUT" | "ABORTED" | "HTTP_ERROR" | "API_ERROR" | "PARSE_ERROR" | "ENVELOPE_INVALID" | "RESPONSE_INVALID" | "RESPONSE_TOO_LARGE" | "CREDENTIALS_REFRESH_FAILED", init: IFetchExceptionInit)
    Example
    import { request } from 'jg-fetch';
    
    const { data, error } = await request<IUser>('/users/1', { baseUrl, parseAs: 'envelope' });
    if (error) {
      error.kind; // 'API_ERROR'
      error.code; // 'USER_NOT_FOUND', the envelope error's code
      error.data; // { id: 1 }, the envelope error's data
      error.status; // 404
    }

    Constants

    DEFAULT_MAX_RESPONSE_BYTES

    const

    the largest response body the buffered parseAs modes read, in bytes: 10 MiB

    Declaration
    const DEFAULT_MAX_RESPONSE_BYTES: 10485760

    DEFAULT_MAX_RETRY_AFTER_SECONDS

    const

    the longest Retry-After wait a retry accepts, in seconds, unless maxRetryAfterSeconds says otherwise

    Declaration
    const DEFAULT_MAX_RETRY_AFTER_SECONDS: 30

    DEFAULT_RETRY_DELAYS_SECONDS

    const

    the waits before each retry, in seconds: two retries, after 3 and then 5 seconds

    Declaration
    const DEFAULT_RETRY_DELAYS_SECONDS: readonly number[]

    DEFAULT_RETRY_METHODS

    const

    the methods that retry by default, which are safe to repeat

    Declaration
    const DEFAULT_RETRY_METHODS: readonly IHttpMethod[]

    DEFAULT_RETRY_STATUS_CODES

    const

    the statuses that retry by default, because a later attempt can succeed

    Declaration
    const DEFAULT_RETRY_STATUS_CODES: readonly number[]

    DEFAULT_TIMEOUT_SECONDS

    const

    the seconds a whole call may take, retries and waits included, unless timeoutSeconds says otherwise

    Declaration
    const DEFAULT_TIMEOUT_SECONDS: 15

    ERRORS

    const

    the codes for every error request reports, which FetchException's kind holds

    Declaration
    const ERRORS: { INVALID_URL: "INVALID_URL"; INVALID_OPTIONS: "INVALID_OPTIONS"; INVALID_HEADERS: "INVALID_HEADERS"; INVALID_BODY: "INVALID_BODY"; NETWORK_ERROR: "NETWORK_ERROR"; TIMEOUT: "TIMEOUT"; ABORTED: "ABORTED"; HTTP_ERROR: "HTTP_ERROR"; API_ERROR: "API_ERROR"; PARSE_ERROR: "PARSE_ERROR"; ENVELOPE_INVALID: "ENVELOPE_INVALID"; RESPONSE_INVALID: "RESPONSE_INVALID"; RESPONSE_TOO_LARGE: "RESPONSE_TOO_LARGE"; CREDENTIALS_REFRESH_FAILED: "CREDENTIALS_REFRESH_FAILED" }

    MAX_TIMEOUT_SECONDS

    const

    the longest timeout a timer can hold, in seconds, which is 2^31 - 1 milliseconds

    Declaration
    const MAX_TIMEOUT_SECONDS: 2147483

    NON_RETRYABLE_STATUS_CODES

    const

    the statuses that never retry, even when retryStatusCodes lists them

    Declaration
    const NON_RETRYABLE_STATUS_CODES: readonly number[]

    Types

    IAttemptContext

    type

    what a headers function receives on each attempt

    Declaration
    type IAttemptContext = {
        attempt: number;
        signal: AbortSignal;
    };

    Members

    • attemptproperty
      number

      the attempt's number, starting at 1

    • signalproperty
      AbortSignal

      aborts when the attempt is cancelled, for work such as refreshing a token

    ICredentialFailure

    type

    what refreshCredentials receives when an attempt fails with a response

    Declaration
    type ICredentialFailure = {
        status: number;
        code: string;
        refreshes: number;
        signal: AbortSignal;
    };

    Members

    • statusproperty
      number

      the response's HTTP status, such as 401

    • codeproperty
      string

      the error's code: the envelope error's own code, or HTTP_ERROR

    • refreshesproperty
      number

      the refreshes this call already made

    • signalproperty
      AbortSignal

      aborts when the call is cancelled, by its timeout or your signal, for the refresh's own work

    IFetchErrorKind

    type

    the kind of a failed request, one of the ERRORS codes

    Declaration
    type IFetchErrorKind = keyof typeof ERRORS;

    IFetchExceptionInit

    type

    what a FetchException carries besides its kind

    Declaration
    type IFetchExceptionInit = {
        message?: string;
        code?: string;
        data?: IJsonValue;
        status?: number | null;
        headers?: Headers | null;
        body?: unknown;
        retryAfterMs?: number | null;
        method: IHttpMethod;
        url: string;
        attempts: number;
        durationMs: number;
        cause?: unknown;
    };

    Members

    • messageproperty
      string

      the message. Defaults to the kind's message

    • codeproperty
      string

      the code. Defaults to the kind; an API error's own code takes its place

    • dataproperty
      IJsonValue

      the envelope error's data, for an API error

    • statusproperty
      number | null

      the HTTP status, or null when no response arrived

    • headersproperty
      Headers | null

      the response's headers, or null when no response arrived

    • bodyproperty
      unknown

      the response body: parsed JSON when it is JSON, otherwise its text

    • retryAfterMsproperty
      number | null

      the wait the server asked for with Retry-After, in milliseconds

    • methodproperty
      IHttpMethod

      the request's method

    • urlproperty
      string

      the request's URL, without its query string or fragment

    • attemptsproperty
      number

      the number of attempts made

    • durationMsproperty
      number

      the milliseconds the whole call took

    • causeproperty
      unknown

      the original error, such as a TypeError from fetch or a schema's error

    IHeadersInit

    type

    the headers the Headers constructor accepts: Headers, [name, value] pairs, or a record

    Declaration
    type IHeadersInit = ConstructorParameters<typeof Headers>[0];

    IHttpMethod

    type

    the HTTP methods request sends

    Declaration
    type IHttpMethod = 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';

    IParseAs

    type

    how request reads a successful response: - envelope: a jg-api-response envelope, resolving to its data - json: parsed JSON - text: a string - bytes: a Uint8Array - blob: a Blob - response: the Response itself, unread - none: nothing, the body is discarded

    Declaration
    type IParseAs = 'envelope' | 'json' | 'text' | 'bytes' | 'blob' | 'response' | 'none';

    IQueryParams

    type

    the query parameters appended to the URL. An array repeats the key once per item

    Declaration
    type IQueryParams = Record<string, IQueryScalar | readonly IQueryScalar[]>;

    IQueryScalar

    type

    a query parameter's value. null, undefined, and empty strings are left out

    Declaration
    type IQueryScalar = string | number | boolean | bigint | null | undefined;

    IRequestOptions

    type

    the options request accepts

    Declaration
    type IRequestOptions<T> = {
        method?: IHttpMethod;
        baseUrl?: string | URL;
        query?: IQueryParams;
        headers?: IHeadersInit | ((context: IAttemptContext) => IHeadersInit | Promise<IHeadersInit>);
        body?: RequestInit['body'] | Record<string, unknown> | readonly unknown[];
        parseAs?: IParseAs;
        schema?: ISchema<T>;
        signal?: AbortSignal;
        timeoutSeconds?: number;
        attemptTimeoutSeconds?: number;
        retryDelaysSeconds?: readonly number[];
        retryMethods?: readonly IHttpMethod[];
        retryStatusCodes?: readonly number[];
        nonRetryableErrorCodes?: readonly string[];
        maxRetryAfterSeconds?: number;
        maxResponseBytes?: number;
        init?: Omit<RequestInit, 'method' | 'headers' | 'body' | 'signal'>;
        onRetry?: (context: IRetryContext) => void;
        refreshCredentials?: (failure: ICredentialFailure) => boolean | Promise<boolean>;
        maxCredentialRefreshes?: number;
    };

    Members

    • methodproperty
      IHttpMethod

      the HTTP method. Defaults to 'GET'

    • baseUrlproperty
      string | URL

      the URL a relative url resolves against. A URL that resolves to another origin fails with INVALID_URL

    • queryproperty
      IQueryParams

      the query parameters appended to the URL

    • headersproperty
      IHeadersInit | ((context: IAttemptContext) => IHeadersInit | Promise<IHeadersInit>)

      the headers, or a function that builds them for each attempt, such as to add a fresh token

    • bodyproperty
      RequestInit["body"] | Record<string, unknown> | readonly unknown[]

      the body. Plain objects and arrays are sent as JSON, with Content-Type: application/json unless the headers set one. A string, Blob, ArrayBuffer or view of one, FormData, URLSearchParams, or ReadableStream is sent as it is. Any other value, such as a Map, a Date, or a number, is an INVALID_BODY error, sent nowhere

    • parseAsproperty
      IParseAs

      how a successful response is read. Defaults to 'json'

    • schemaproperty
      ISchema<T>

      validates the parsed data, or the envelope's data, such as a Zod schema

    • signalproperty
      AbortSignal

      aborts the call. An abort whose reason is a TimeoutError, such as AbortSignal.timeout's, reports TIMEOUT, and any other ABORTED

    • timeoutSecondsproperty
      number

      the seconds the whole call may take, retries and waits included. Defaults to DEFAULT_TIMEOUT_SECONDS

    • attemptTimeoutSecondsproperty
      number

      the seconds each attempt may take. An attempt that runs out retries. No limit by default

    • retryDelaysSecondsproperty
      readonly number[]

      the waits before each retry, in seconds; one retry per item. Defaults to DEFAULT_RETRY_DELAYS_SECONDS, and [] turns retries off

    • retryMethodsproperty
      readonly IHttpMethod[]

      the methods that may retry. Defaults to DEFAULT_RETRY_METHODS

    • retryStatusCodesproperty
      readonly number[]

      the statuses that may retry. Defaults to DEFAULT_RETRY_STATUS_CODES, and NON_RETRYABLE_STATUS_CODES never retry

    • nonRetryableErrorCodesproperty
      readonly string[]

      the API error codes, from an envelope's error, that never retry

    • maxRetryAfterSecondsproperty
      number

      the longest Retry-After wait a retry accepts, in seconds. Defaults to DEFAULT_MAX_RETRY_AFTER_SECONDS

    • maxResponseBytesproperty
      number

      the largest body the buffered parseAs modes read, counted as it streams. Defaults to DEFAULT_MAX_RESPONSE_BYTES

    • initproperty
      Omit<RequestInit, "method" | "headers" | "body" | "signal">

      the other fetch options, such as credentials, cache, or redirect

    • onRetryproperty
      (context: IRetryContext) => void

      called before each retry. Whatever it throws is ignored, so request still never throws

    • refreshCredentialsproperty
      (failure: ICredentialFailure) => boolean | Promise<boolean>

      called when an attempt fails with a response, such as a 401, to refresh the credentials the headers function reads. Returning true repeats the attempt at once, for any method; false leaves the failure to the retry rules. Return true only for a credential failure, because the server didn't process the request then. A function that throws ends the call with CREDENTIALS_REFRESH_FAILED. Never called for a streamed body, which can be sent once

    • maxCredentialRefreshesproperty
      number

      the most refreshes a call makes, such as 2 for two kinds of credential. Defaults to 1

    IRequestResult

    type

    what request resolves to: the data and no error, or no data and the error

    Declaration
    type IRequestResult<T> = {
        data: T;
        error: null;
        meta: IResponseMeta;
    } | {
        data: null;
        error: FetchException;
        meta: IResponseMeta;
    };

    IResponseMeta

    type

    what request knows about the last response, successful or not

    Declaration
    type IResponseMeta = {
        status: number | null;
        headers: Headers | null;
        url: string;
        attempts: number;
        durationMs: number;
    };

    Members

    • statusproperty
      number | null

      the HTTP status, or null when no response arrived

    • headersproperty
      Headers | null

      the response's headers, or null when no response arrived

    • urlproperty
      string

      the URL, without its query string or fragment, which can hold tokens

    • attemptsproperty
      number

      the number of attempts made

    • durationMsproperty
      number

      the milliseconds the whole call took, retries and waits included

    IRetryContext

    type

    what onRetry receives before each retry

    Declaration
    type IRetryContext = {
        attempt: number;
        error: FetchException;
        delayMs: number;
    };

    Members

    • attemptproperty
      number

      the attempt that failed, starting at 1

    • errorproperty
      FetchException

      why it failed

    • delayMsproperty
      number

      the milliseconds request waits before the next attempt

    ISchema

    type

    validates parsed data and returns it typed, which a Zod schema does

    Declaration
    type ISchema<T> = {
        parse(value: unknown): T;
    };

    Members

    • parsemethod
      parse(value: unknown): T