UNPKG

@gaddario98/react-queries

Version:

```bash npm install @gaddario98/base-queries ```

373 lines (355 loc) 18.4 kB
import * as jotai from 'jotai'; import * as jotai_utils from 'jotai/utils'; import * as _tanstack_react_query from '@tanstack/react-query'; import { UseQueryOptions, useQuery, UseMutationOptions, MutateOptions, useMutation, UseMutationResult, QueryClient } from '@tanstack/react-query'; import { NotificationConfig } from '@gaddario98/react-notifications'; import { AxiosRequestConfig } from 'axios'; import * as _gaddario98_react_state from '@gaddario98/react-state'; import { PersistQueryClientOptions } from '@tanstack/react-query-persist-client'; import { PropsWithChildren } from 'react'; type ApiMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; type Endpoint = Record<string, string>; interface QueriesProps<TProps, TResponse, TConverter = null> { endpoint: [keyof Endpoint, string] | [keyof Endpoint]; queryKeyToInvalidate?: Array<string>; headers?: AxiosRequestConfig['headers']; method: ApiMethod; converter?: (props: TProps) => TConverter; customRequest?: (url: string, method: string, data: TProps) => Promise<TResponse>; mutateOptions?: MutateOptions<TResponse, Error, TProps, unknown>; isTest?: boolean; notification?: { success?: NotificationConfig | ((res: TResponse) => NotificationConfig); error?: NotificationConfig | ((error: string) => NotificationConfig); translationOption?: Record<string, any>; }; } interface QueryProps<Key extends string, TResponse> { endpoint: [keyof Endpoint, string] | [keyof Endpoint]; queryKey: Array<string>; enabled: boolean; keyToMap: Key; disableLoading?: boolean; customQueryFn?: () => Promise<TResponse>; headers?: AxiosRequestConfig['headers']; disableAuthControl?: boolean; onDataChanged?: (data: TResponse) => void; onStateChange?: (state: QueryResult<TResponse>) => void; options?: Omit<Parameters<typeof useQuery<TResponse>>['0'], 'queryKey' | 'queryFn'>; } interface CustomQueryOptions<TResponse> extends Omit<UseQueryOptions<TResponse, Error>, 'queryKey' | 'queryFn'> { endpoint: [keyof Endpoint, string] | [keyof Endpoint]; queryKey: Array<string>; headers?: AxiosRequestConfig['headers']; disableAuthControl?: boolean; onDataChanged?: (data: TResponse | undefined) => void; onStateChange?: (state: QueryResult<TResponse>) => void; options?: Omit<Parameters<typeof useQuery<TResponse>>['0'], 'queryKey' | 'queryFn'>; keyToMap?: string; disableLoading?: boolean; customQueryFn?: () => Promise<TResponse>; } interface CustomMutationOptions<TProps, TResponse> extends UseMutationOptions<TResponse, Error, TProps, unknown> { endpoint: [keyof Endpoint, string] | [keyof Endpoint]; method: ApiMethod; headers?: AxiosRequestConfig['headers']; queryKeyToInvalidate?: Array<string>; customRequest?: (url: string, method: string, data: TProps) => Promise<TResponse>; converter?: (props: TProps) => any; isTest?: boolean; notification?: { success?: NotificationConfig | ((res: TResponse) => NotificationConfig); error?: NotificationConfig | ((error: string) => NotificationConfig); translationOption?: Record<string, any>; }; } type QueryDefinition<K extends string, T extends 'query' | 'mutation' | 'websocket', P, R, C = any> = { key: K; props: P; response?: R; converter: C; type: T; }; type QueriesArray = Array<QueryDefinition<string, any, any, any, any>>; type ExtractQuery<Q extends QueriesArray> = Extract<Q[number], { type: 'query'; }>; type ExtractWebSocket<Q extends QueriesArray> = Extract<Q[number], { type: 'websocket'; }>; type ExtractQueryResponse<Q extends QueriesArray, K extends Q[number]['key']> = Extract<Q[number], { key: K; }>; type ExtractMutation<Q extends QueriesArray> = Extract<Q[number], { type: 'mutation'; }>; type CustomMutation<TData = unknown, TError = Error, TVariables = void, TOnMutateResult = unknown> = typeof useMutation<TData, TError, TVariables, TOnMutateResult> & { endpoint: string; }; type AllMutation<Q extends QueriesArray = QueriesArray> = { [K in ExtractMutation<Q>['key']]: ReturnType<CustomMutation<ExtractQueryResponse<Q, K>['response'], Error, ExtractQueryResponse<Q, K>['props'], unknown>> & { endpoint: QueriesProps<any, any>['endpoint']; }; }; type ExtractMutationByKey<Q extends QueriesArray = QueriesArray, K extends ExtractMutation<Q>['key'] = ExtractMutation<Q>['key']> = ReturnType<CustomMutation<ExtractQueryResponse<Q, K>['response'], Error, ExtractQueryResponse<Q, K>['props'], unknown>>; type ExtractQueryByKey<Q extends QueriesArray = QueriesArray, K extends ExtractQuery<Q>['key'] = ExtractQuery<Q>['key']> = { data?: ExtractQueryResponse<Q, K>['response']; isLoading: boolean; isLoadingMapped: boolean; isFetching: boolean; isPending: boolean; error: Error | null; refetch: () => Promise<unknown>; }; interface MutationConfig<TProps = unknown, TResponse = unknown, TConverter = any> extends QueriesProps<TProps, TResponse, TConverter> { method: 'POST' | 'PUT' | 'DELETE' | 'PATCH'; onStateChange?: (state: MutationStateInternal<TResponse>) => void; } interface QueryResult<TResponse> { data?: TResponse; isLoading: boolean; isLoadingMapped: boolean; isFetching: boolean; isPending: boolean; error: Error | null; refetch: () => Promise<unknown>; } type MultipleQueryResponse<Q extends QueriesArray> = { [K in ExtractQuery<Q>['key']]: { data: ExtractQueryResponse<Q, K>['response']; isLoading: boolean; isLoadingMapped: boolean; isFetching: boolean; isPending: boolean; error: Error | null; refetch: () => Promise<unknown>; }; }; interface QueryConfig<K extends string, TResponse> extends CustomQueryOptions<TResponse> { keyToMap: K; } type SingleQueryConfig<Q extends QueryDefinition<any, any, any, any>> = Q extends QueryDefinition<infer K, infer T, infer P, infer R, infer C> ? T extends 'mutation' ? { type: 'mutation'; mutationConfig: MutationConfig<P, R, C>; key: K; } : T extends 'query' ? { type: 'query'; queryConfig?: Omit<QueryConfig<K, R>, 'keyToMap'>; key: K; } : WebSocketDefinition<K> : never; type QueryAtIndex<Q extends QueriesArray, I extends keyof Q> = Q[I] extends QueryDefinition<infer K, infer T, infer P, infer R, infer C> ? QueryDefinition<K, T, P, R, C> : never; type QueryConfigArray<Q extends QueriesArray> = { [I in keyof Q]: SingleQueryConfig<QueryAtIndex<Q, I>>; }; interface ContextValue<Q extends QueriesArray> { allMutation: AllMutation<Q>; allQuery: MultipleQueryResponse<Q>; allWebSocket: MultipleWebSocketResponse<Q[number]['key']>; refreshQueries: () => void; } type MultipleWebSocketResponse<K extends string = string> = { [key in K]: WebSocketResult; }; type MutationItem<Q extends QueriesArray> = Extract<QueryConfigArray<Q>[number], { type: 'mutation'; mutationConfig: any; }>; type QueryItem<Q extends QueriesArray> = Extract<QueryConfigArray<Q>[number], { type: 'query'; }>; interface WebSocketDefinition<TKey extends string = string> { key: TKey; endpoint?: string; onMessage?: (data: any) => void; invalidateQueriesOnMessage?: Array<string>; autoConnect?: boolean; type: 'websocket'; } type WebSocketsArray = Array<WebSocketDefinition<string>>; interface WebSocketResult { lastMessage: any; sendMessage: (message: any) => void; status: 'connecting' | 'open' | 'closed'; } interface MutationStateInternal<TData = unknown> { status: 'idle' | 'pending' | 'success' | 'error'; data: TData | undefined; error: Error | null; submittedAt: number | null; variables: unknown | undefined; } type MutationActionInternal = { type: 'RESET'; key: string; } | { type: 'PENDING'; key: string; submittedAt: number; variables: unknown; } | { type: 'SUCCESS'; key: string; data: unknown; } | { type: 'ERROR'; key: string; error: Error; }; type StringKey<T> = Extract<keyof T, string>; type QueryTopKey<Q extends QueriesArray> = StringKey<MultipleQueryResponse<Q>>; type QuerySubKey<Q extends QueriesArray, K extends QueryTopKey<Q>> = StringKey<MultipleQueryResponse<Q>[K]>; type QueryCompositeKey<Q extends QueriesArray> = { [K in QueryTopKey<Q>]: K | `${K}.${QuerySubKey<Q, K>}`; }[QueryTopKey<Q>]; type QueryValue<Q extends QueriesArray, K extends QueryCompositeKey<Q>> = K extends `${infer Top}.${infer Sub}` ? Top extends QueryTopKey<Q> ? Sub extends QuerySubKey<Q, Top> ? MultipleQueryResponse<Q>[Top][Sub] : never : never : K extends QueryTopKey<Q> ? MultipleQueryResponse<Q>[K] : never; type MutationTopKey<Q extends QueriesArray> = StringKey<AllMutation<Q>>; type MutationSubKey<Q extends QueriesArray, K extends MutationTopKey<Q>> = StringKey<AllMutation<Q>[K]>; type MutationCompositeKey<Q extends QueriesArray> = { [K in MutationTopKey<Q>]: K | `${K}.${MutationSubKey<Q, K>}`; }[MutationTopKey<Q>]; type MutationValue<Q extends QueriesArray, K extends MutationCompositeKey<Q>> = K extends `${infer Top}.${infer Sub}` ? Top extends MutationTopKey<Q> ? Sub extends MutationSubKey<Q, Top> ? AllMutation<Q>[Top][Sub] : never : never : K extends MutationTopKey<Q> ? AllMutation<Q>[K] : never; type GetApiValuesFunction<Q extends QueriesArray> = { <K extends QueryTopKey<Q>>(type: 'query', key: K): MultipleQueryResponse<Q>[K]; <K extends QueryCompositeKey<Q>>(type: 'query', key: K): QueryValue<Q, K>; <K extends QueryCompositeKey<Q>>(type: 'query', key: K, defaultValue: unknown): NonNullable<QueryValue<Q, K>>; <K extends MutationCompositeKey<Q>>(type: 'mutation', key: K, defaultValue: unknown): NonNullable<MutationValue<Q, K>>; <K extends QueryTopKey<Q>>(type: 'query', key: K, defaultValue: MultipleQueryResponse<Q>[K]['data']): MultipleQueryResponse<Q>[K]['data']; <K extends QueryCompositeKey<Q>>(type: 'query', key: K, defaultValue: QueryValue<Q, K>): NonNullable<QueryValue<Q, K>>; <K extends MutationTopKey<Q>>(type: 'mutation', key: K): AllMutation<Q>[K]; <K extends MutationCompositeKey<Q>>(type: 'mutation', key: K): MutationValue<Q, K>; <K extends MutationTopKey<Q>>(type: 'mutation', key: K, defaultValue: AllMutation<Q>[K]['data']): AllMutation<Q>[K]['data']; <K extends MutationCompositeKey<Q>>(type: 'mutation', key: K, defaultValue: MutationValue<Q, K>): NonNullable<MutationValue<Q, K>>; (type: 'query' | 'mutation', key: string, defaultValue?: unknown): unknown; }; type QueryStoreEntry<Q extends QueriesArray = QueriesArray> = QueryResult<Q[number]['response']>; type MutationStoreEntry<Q extends QueriesArray = QueriesArray> = UseMutationResult<Q[number]['response'], Error, Q[number]['props'], unknown>; declare const DEFAULT_QUERY_ENTRY: QueryStoreEntry; declare const DEFAULT_MUTATION_ENTRY: MutationStoreEntry; /** * Global atom storing all query results. * Key format: "scopeId:queryKey" */ declare const queriesAtom: jotai.WritableAtom<Record<string, QueryStoreEntry<QueriesArray>>, [Record<string, QueryStoreEntry<QueriesArray>> | typeof jotai_utils.RESET | ((prev: Record<string, QueryStoreEntry<QueriesArray>>) => Record<string, QueryStoreEntry<QueriesArray>> | typeof jotai_utils.RESET)], void>; /** * Global atom storing all mutation results. * Key format: "scopeId:mutationKey" */ declare const mutationsAtom: jotai.PrimitiveAtom<Record<string, MutationStoreEntry<QueriesArray>>> & { init: Record<string, MutationStoreEntry<QueriesArray>>; }; declare const getCompositeKey: (scopeId: string, key: string) => string; /** * Creates a derived atom for accessing queries of a specific scope. */ declare const createScopeQueriesAtom: (scopeId: string) => jotai.WritableAtom<Record<string, QueryStoreEntry<QueriesArray>>, [update: Record<string, QueryStoreEntry<QueriesArray>>], void>; /** * Creates a derived atom for accessing mutations of a specific scope. */ declare const createScopeMutationsAtom: (scopeId: string) => jotai.WritableAtom<Record<string, MutationStoreEntry<QueriesArray>>, [update: Record<string, MutationStoreEntry<QueriesArray>>], void>; declare const createQuerySelector: <Q extends QueriesArray>(scopeId: string, queryKey: string) => jotai.Atom<QueryStoreEntry<Q>>; declare const createMutationSelector: <Q extends QueriesArray>(scopeId: string, mutationKey: string) => jotai.Atom<MutationStoreEntry<Q>>; interface EncryptionConfig { secretKey: string; enabled?: boolean; encryptFn?: (data: unknown, key: string) => Promise<string>; decryptFn?: (data: string, key: string) => Promise<unknown>; } type ApiConverter<TProps, TConverter> = (props: TProps) => TConverter; interface ApiRequestFnProps<TProps, TConverter = TProps> { url: string; method: ApiMethod; body?: TProps; headers?: AxiosRequestConfig['headers']; converter?: ApiConverter<TProps, TConverter>; } interface ApiNotificationMessage { message: string; type: 'success' | 'error' | 'info' | 'warning'; autoHideDuration?: number; textTransOption?: Record<string, unknown>; ns?: string; } interface ApiConfig { endpoints: Endpoint; requestFn: <TProps, TResponse, TConverter = TProps>(props: ApiRequestFnProps<TProps, TConverter>) => Promise<TResponse>; validateAuthFn?: () => boolean; defaultHeaders?: Record<string, string>; persistOptions?: Omit<PersistQueryClientOptions, 'queryClient'>; queryClient: QueryClient; websocketConfig?: { url: string; onMessage?: (message: unknown) => void; autoConnect?: boolean; }; encryption?: EncryptionConfig; showNotification?: (notification: ApiNotificationMessage) => void; } declare const apiConfigAtom: _gaddario98_react_state.PrimitiveAtom<ApiConfig>; declare const useApiConfigValue: () => ApiConfig; declare const useApiConfigState: () => [ApiConfig, (value: ApiConfig) => void]; declare const useApiConfigReset: () => () => void; declare const useQueryApi: <TResponse>(options: CustomQueryOptions<TResponse>, id?: string) => QueryResult<TResponse>; declare const useMutateApi: <TProps, TResponse>(options: CustomMutationOptions<TProps, TResponse>, id?: string) => _tanstack_react_query.UseMutationResult<TResponse, Error, TProps, unknown>; declare const useMultipleQuery: <Q extends QueriesArray>(settings?: Array<QueryProps<Q[number]["key"], Q[number]["response"]>>) => MultipleQueryResponse<Q>; declare const useMultipleMutation: <Q extends QueriesArray>(configs: Array<MutationItem<Q>>) => AllMutation<Q>; declare const useMultipleWebSocket: <K extends string>(configs?: Array<WebSocketDefinition<K>>) => MultipleWebSocketResponse<K>; interface UseApiOptions { /** * Unique identifier for this scope. Used as the key prefix for Jotai atoms. * @default 'default' */ scopeId?: string; /** * Whether to persist query/mutation results to Jotai atoms. * @default true */ persistToAtoms?: boolean; } /** * Main hook that integrates TanStack Query with Jotai for state persistence. */ declare function useApi<Q extends QueriesArray>(configs: QueryConfigArray<Q>, options?: UseApiOptions): ContextValue<Q>; /** * @deprecated Use options object instead: useApi(configs, { scopeId: 'my-scope' }) */ declare function useApi<Q extends QueriesArray>(configs: QueryConfigArray<Q>, id?: string): ContextValue<Q>; declare const useWebSocket: (endpoint?: string, // specific socket endpoint if different from default options?: { onMessage?: (data: unknown) => void; invalidateQueriesOnMessage?: Array<string>; }) => WebSocketResult; declare const useInvalidateQueries: () => { invalidateQueries: (queryKeys: Array<Array<string>>) => Promise<void>; }; /** * Hook to read all queries for a scope. */ declare function useJotaiQueries<Q extends QueriesArray>(options: { scopeId: string; }): Record<string, QueryStoreEntry<Q>>; /** * Hook to read all mutations for a scope. */ declare function useJotaiMutations<Q extends QueriesArray>(options: { scopeId: string; }): Record<string, MutationStoreEntry<Q>>; interface UseApiValuesProps { scopeId: string; } declare const useApiValues: <Q extends QueriesArray>({ scopeId, }: UseApiValuesProps) => { get: GetApiValuesFunction<Q>; }; declare const QueriesProvider: React.FC<PropsWithChildren>; declare const algorithm: { name: string; length: number; }; declare const str2ab: (str: string) => ArrayBuffer; declare const ab2str: (buf: ArrayBuffer) => string; declare const importKey: (secretKey: string) => Promise<CryptoKey>; declare const encryptData: (data: any, secretKey: string) => Promise<string>; declare const decryptData: (encryptedData: string, secretKey: string) => Promise<any>; declare const apiRequest: <TProps, TResponse, TConverter = TProps>({ method, url, body, headers, converter, }: ApiRequestFnProps<TProps, TConverter>) => Promise<TResponse>; declare const fetchRequest: <TProps, TResponse>(url: string, headers?: AxiosRequestConfig["headers"]) => Promise<TResponse>; export { DEFAULT_MUTATION_ENTRY, DEFAULT_QUERY_ENTRY, QueriesProvider, ab2str, algorithm, apiConfigAtom, apiRequest, createMutationSelector, createQuerySelector, createScopeMutationsAtom, createScopeQueriesAtom, decryptData, encryptData, fetchRequest, getCompositeKey, importKey, mutationsAtom, queriesAtom, str2ab, useApi, useApiConfigReset, useApiConfigState, useApiConfigValue, useApiValues, useInvalidateQueries, useJotaiMutations, useJotaiQueries, useMultipleMutation, useMultipleQuery, useMultipleWebSocket, useMutateApi, useQueryApi, useWebSocket }; export type { AllMutation, ApiConfig, ApiConverter, ApiMethod, ApiNotificationMessage, ApiRequestFnProps, ContextValue, CustomMutation, CustomMutationOptions, CustomQueryOptions, EncryptionConfig, Endpoint, ExtractMutation, ExtractMutationByKey, ExtractQuery, ExtractQueryByKey, ExtractQueryResponse, ExtractWebSocket, GetApiValuesFunction, MultipleQueryResponse, MultipleWebSocketResponse, MutationActionInternal, MutationConfig, MutationItem, MutationStateInternal, MutationStoreEntry, QueriesArray, QueriesProps, QueryAtIndex, QueryConfig, QueryConfigArray, QueryDefinition, QueryItem, QueryProps, QueryResult, QueryStoreEntry, SingleQueryConfig, UseApiOptions, WebSocketDefinition, WebSocketResult, WebSocketsArray };