import * as React from 'react';
import React__default, { ReactElement, Component, ReactNode } from 'react';

declare type Cache = {
    getValue: () => Record<string, QueryResponse>;
    setValue: (value: Record<string, QueryResponse>) => void;
    setResponse: (action: Action, value: QueryResponse) => void;
    getResponse: (action: Action) => QueryResponse | undefined;
    removeResponse: (action: Action) => void;
    getPayload: (action: Action) => any;
    updatePayload: (action: Action, payload: any) => void;
    on: (event: CacheStoreEvent, cb: () => void) => void;
    off: (event: CacheStoreEvent, cb: () => void) => void;
};
declare type CacheStoreEvent = 'updated';

declare type SuspenseCacheItem = {
    fetch: any;
    response?: QueryResponse;
};
declare type SuspenseCache = {
    get: (action: Action) => SuspenseCacheItem;
    add: (action: Action, value: SuspenseCacheItem) => void;
    remove: (action: Action) => void;
};

declare type Method = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS';
declare type ResponseType = 'arrayBuffer' | 'blob' | 'json' | 'text' | 'formData';
interface ActionConfig {
    emitErrorForStatuses?: number[];
}
interface Action<R = any, Ext = any> {
    endpoint: string;
    method: Method;
    body?: any;
    headers?: {
        [propName: string]: string;
    };
    credentials?: RequestCredentials;
    cache?: RequestCache;
    mode?: RequestMode;
    referrerPolicy?: ReferrerPolicy;
    referrer?: string;
    integrity?: string;
    keepalive?: boolean;
    redirect?: RequestRedirect;
    signal?: AbortSignal | null;
    window?: any;
    config?: ActionConfig & Ext;
    responseType?: ResponseType;
}
declare type QueryResponse<T = any> = {
    status?: number;
    error: boolean;
    errorObject?: any;
    payload?: T;
    headers?: Headers;
};
declare type UseQueryResponse<T> = {
    loading: boolean;
    abort: () => void;
    reset: () => void;
    query: () => Promise<QueryResponse<T>>;
} & QueryResponse<T>;
declare type UseMutationResponse<S, T> = {
    abort: () => void;
    loading: boolean;
    mutate: (action: S) => Promise<QueryResponse<T>>;
    reset: () => void;
} & QueryResponse<T>;
declare type UseBulkMutationResponse<S, T> = {
    abort: () => void;
    loading: boolean;
    mutate: (actions: S[]) => Promise<(QueryResponse<T> | undefined)[]>;
    reset: () => void;
    responses: (QueryResponse<T> | undefined)[];
};
declare type UseParameterizedQuery<S, T> = {
    abort: () => void;
    loading: boolean;
    query: (action: S) => Promise<QueryResponse<T>>;
    reset: () => void;
} & QueryResponse<T>;
declare type Client<R = any> = {
    query: <T>(action: Action<T, R>, skipCache?: boolean) => Promise<QueryResponse<T>>;
    cache: Cache;
    suspenseCache: SuspenseCache;
};
declare type ClientOptions<T> = {
    requestInterceptors?: RequestInterceptor<T>[];
    responseInterceptors?: ResponseInterceptor<T, any>[];
    fetch?: (input: RequestInfo, init?: Partial<Action> & RequestInit) => Promise<Response>;
    dedupingInterval?: number;
};
declare type RequestInterceptor<T = any> = (client: Client<T>) => (action: Action<any, T>) => Promise<Action<any, T>>;
declare type ResponseInterceptor<T = any, R = any> = (client: Client<T>) => (action: Action<R, T>, response: QueryResponse<R>) => Promise<QueryResponse<R>>;

declare type HandleRequestInterceptors<R> = (action: Action<any, R>, interceptors: RequestInterceptor<R>[]) => Promise<Action<any, R>>;
declare type HandleResponseInterceptors<R> = (action: Action<any, R>, response: QueryResponse<any>, interceptors: ResponseInterceptor<R, any>[]) => Promise<QueryResponse<any>>;
declare const createClient: <R = any>(clientOptions?: ClientOptions<R>) => Client;

declare class QueryError extends Error {
    response: QueryResponse;
    constructor(message: string, response: QueryResponse);
}

declare type UseQueryOptionsType = Partial<{
    initFetch: boolean;
    skipCache: boolean;
    pollInterval: number;
}>;
declare const useQuery: <T = any, R = any>(action: Action<T, R>, { initFetch, skipCache, pollInterval }?: UseQueryOptionsType) => {
    status?: number | undefined;
    error: boolean;
    errorObject?: any;
    payload?: T | undefined;
    headers?: Headers | undefined;
    abort: () => void;
    loading: boolean;
    query: () => Promise<QueryResponse<T>>;
    reset: () => void;
};

declare type ActionCreator$3<S, R, T> = (action: S) => Action<T, R>;
declare const useMutation: <T = any, R = {}, S = any>(actionCreator: ActionCreator$3<S, R, T>) => UseMutationResponse<S, T>;

declare type ActionCreator$2<S, R, T> = (action: S) => Action<T, R>;
declare const useBulkMutation: <T = any, R = {}, S = any>(actionCreator: ActionCreator$2<S, R, T>) => UseBulkMutationResponse<S, T>;

declare const useSuspenseQuery: <T, R = any>(action: Action<T, R>) => {
    query: () => void;
    status?: number | undefined;
    error: boolean;
    errorObject?: any;
    payload?: T | undefined;
    headers?: Headers | undefined;
};

declare const useCachedResponse: <T = any, R = {}>(action: Action<T, R>) => QueryResponse<any> | undefined;

declare type ClientContextType = {
    query: <T = any, R = any>(actionInit: Action<T, R>, skipCache?: boolean) => Promise<QueryResponse<T>>;
    cache: Cache;
    suspenseCache: SuspenseCache;
};

declare const useClient: () => ClientContextType;

declare type ActionCreator$1<S, R, T> = (action: S) => Action<T, R>;
declare const useParameterizedQuery: <T = any, R = {}, S = any>(actionCreator: ActionCreator$1<S, R, T>) => UseParameterizedQuery<S, T>;

declare type QueryApi<T> = {
    loading: boolean;
    query: () => Promise<QueryResponse<T>>;
    reset: () => void;
    abort: () => void;
} & QueryResponse<T>;
declare type QueryProps<T, R> = {
    initFetch?: boolean;
    action: Action<T, R>;
    children: (props: QueryApi<T>) => any;
};

declare const Query: <T = any, R = any>({ action, children, initFetch }: QueryProps<T, R>) => any;

declare type ActionCreator<S, R, T> = (action: S) => Action<T, R>;
declare type MutationApi<T, S> = {
    loading: boolean;
    mutate: (action: S) => Promise<QueryResponse<T>>;
    reset: () => void;
    abort: () => void;
} & QueryResponse<T>;
declare type MutationProps<T, R, S> = {
    actionCreator: ActionCreator<S, R, T>;
    children: (props: MutationApi<T, S>) => any;
};

declare const Mutation: <T = any, R = any, S = any>({ actionCreator, children }: MutationProps<T, R, S>) => any;

declare type SuspenseQueryProps<T, R> = {
    action: Action<T, R>;
    children: (props: QueryResponse<T>) => any;
};

declare const SuspenseQuery: <T = any, R = any>({ action, children }: SuspenseQueryProps<T, R>) => any;

declare type ErrorQueryBoundaryProps = {
    fallback: (response: QueryResponse, restart: () => void) => ReactElement;
    statuses: number[];
};
declare type ErrorQueryBoundaryState = {
    hasError: boolean;
    response?: QueryResponse;
};

declare class QueryErrorBoundary extends Component<ErrorQueryBoundaryProps, ErrorQueryBoundaryState> {
    static getDerivedStateFromError(error: Error): {
        hasError: boolean;
        response: QueryResponse<any>;
    } | undefined;
    state: ErrorQueryBoundaryState;
    constructor(props: ErrorQueryBoundaryProps);
    restart: () => void;
    render(): React__default.ReactNode;
}

declare const ClientContext: React.Context<ClientContextType>;

declare const ClientContextProvider: ({ client, children }: {
    client: Client;
    children: ReactNode;
}) => JSX.Element;

export { Action, ActionConfig, Client, ClientContext, ClientContextProvider, ClientOptions, HandleRequestInterceptors, HandleResponseInterceptors, Mutation, Query, QueryError, QueryErrorBoundary, QueryResponse, RequestInterceptor, ResponseInterceptor, SuspenseQuery, UseQueryResponse, createClient, useBulkMutation, useCachedResponse, useClient, useMutation, useParameterizedQuery, useQuery, useSuspenseQuery };
