mirror of https://github.com/buster-so/buster.git
create socket query
This commit is contained in:
parent
51291d44e0
commit
ad02a021ac
|
@ -15,15 +15,22 @@ import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||||
import { RustApiError } from './buster_rest/errors';
|
import { RustApiError } from './buster_rest/errors';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
|
|
||||||
interface CreateQueryProps<T> extends UseQueryOptions {
|
interface CreateQueryProps<TData, TError = unknown> {
|
||||||
queryKey: QueryKey;
|
queryKey: QueryKey;
|
||||||
|
queryFn: () => Promise<TData>;
|
||||||
isUseSession?: boolean;
|
isUseSession?: boolean;
|
||||||
useErrorNotification?: boolean;
|
useErrorNotification?: boolean;
|
||||||
|
enabled?: boolean;
|
||||||
|
initialData?: TData;
|
||||||
|
refetchOnWindowFocus?: boolean;
|
||||||
|
refetchOnMount?: boolean;
|
||||||
|
staleTime?: number;
|
||||||
|
options?: Omit<UseQueryOptions<TData, TError, TData>, 'queryKey' | 'queryFn'>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PREFETCH_STALE_TIME = 1000 * 10;
|
export const PREFETCH_STALE_TIME = 1000 * 10;
|
||||||
|
|
||||||
export const useCreateReactQuery = <T>({
|
export const useCreateReactQuery = <TData, TError = unknown>({
|
||||||
queryKey,
|
queryKey,
|
||||||
queryFn,
|
queryFn,
|
||||||
isUseSession = true,
|
isUseSession = true,
|
||||||
|
@ -33,13 +40,13 @@ export const useCreateReactQuery = <T>({
|
||||||
refetchOnMount = true,
|
refetchOnMount = true,
|
||||||
useErrorNotification = true,
|
useErrorNotification = true,
|
||||||
staleTime,
|
staleTime,
|
||||||
...rest
|
options = {}
|
||||||
}: CreateQueryProps<T>) => {
|
}: CreateQueryProps<TData, TError>) => {
|
||||||
const { openErrorNotification } = useBusterNotifications();
|
const { openErrorNotification } = useBusterNotifications();
|
||||||
const accessToken = useSupabaseContext((state) => state.accessToken);
|
const accessToken = useSupabaseContext((state) => state.accessToken);
|
||||||
const baseEnabled = isUseSession ? !!accessToken : true;
|
const baseEnabled = isUseSession ? !!accessToken : true;
|
||||||
|
|
||||||
const q = useQuery({
|
const q = useQuery<TData, TError>({
|
||||||
queryKey: queryKey,
|
queryKey: queryKey,
|
||||||
queryFn,
|
queryFn,
|
||||||
enabled: baseEnabled && !!enabled,
|
enabled: baseEnabled && !!enabled,
|
||||||
|
@ -48,7 +55,7 @@ export const useCreateReactQuery = <T>({
|
||||||
refetchOnWindowFocus,
|
refetchOnWindowFocus,
|
||||||
refetchOnMount,
|
refetchOnMount,
|
||||||
staleTime,
|
staleTime,
|
||||||
...rest
|
...options
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -35,7 +35,7 @@ interface BusterSocket {
|
||||||
}) => Promise<Parameters<T['callback']>[0]>;
|
}) => Promise<Parameters<T['callback']>[0]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useBusterWebSocketHook = ({
|
const useBusterWebSocketHook = ({
|
||||||
socketURL,
|
socketURL,
|
||||||
accessToken,
|
accessToken,
|
||||||
checkTokenValidity
|
checkTokenValidity
|
||||||
|
@ -195,13 +195,13 @@ export const BusterWebSocketProvider: React.FC<{
|
||||||
const accessToken = useSupabaseContext((state) => state.accessToken);
|
const accessToken = useSupabaseContext((state) => state.accessToken);
|
||||||
const checkTokenValidity = useSupabaseContext((state) => state.checkTokenValidity);
|
const checkTokenValidity = useSupabaseContext((state) => state.checkTokenValidity);
|
||||||
|
|
||||||
const value = useBusterWebSocketHook({
|
const busterSocketHook = useBusterWebSocketHook({
|
||||||
socketURL: BUSTER_WS_URL,
|
socketURL: BUSTER_WS_URL,
|
||||||
accessToken,
|
accessToken,
|
||||||
checkTokenValidity
|
checkTokenValidity
|
||||||
});
|
});
|
||||||
|
|
||||||
return <BusterWebSocket.Provider value={value}>{children}</BusterWebSocket.Provider>;
|
return <BusterWebSocket.Provider value={busterSocketHook}>{children}</BusterWebSocket.Provider>;
|
||||||
});
|
});
|
||||||
BusterWebSocketProvider.displayName = 'BusterWebSocketProvider';
|
BusterWebSocketProvider.displayName = 'BusterWebSocketProvider';
|
||||||
|
|
||||||
|
@ -212,7 +212,3 @@ const useBusterWebSocketSelector = <T,>(
|
||||||
export const useBusterWebSocket = () => {
|
export const useBusterWebSocket = () => {
|
||||||
return useBusterWebSocketSelector((state) => state.busterSocket);
|
return useBusterWebSocketSelector((state) => state.busterSocket);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useBusterWebSocketConnectionStatus = () => {
|
|
||||||
return useBusterWebSocketSelector((state) => state.connectionStatus);
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { UseBusterSocketQueryOptions } from './types';
|
|
||||||
|
|
||||||
export const DEFAULT_OPTIONS: Partial<UseBusterSocketQueryOptions<unknown, unknown>> = {
|
|
||||||
refetchOnWindowFocus: false,
|
|
||||||
refetchOnMount: true,
|
|
||||||
retry: 0,
|
|
||||||
staleTime: 0
|
|
||||||
};
|
|
|
@ -1,12 +0,0 @@
|
||||||
import { BusterSocketRequest, BusterSocketResponse } from '@/api/buster_socket';
|
|
||||||
|
|
||||||
export const isSocketError = (error: unknown): error is Error => {
|
|
||||||
return error instanceof Error;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const transformError = (error: unknown): Error => {
|
|
||||||
if (isSocketError(error)) {
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
return new Error('Unknown WebSocket error occurred');
|
|
||||||
};
|
|
|
@ -1,3 +0,0 @@
|
||||||
export * from './types';
|
|
||||||
export * from './useBusterWebSocketQuery';
|
|
||||||
export * from './helpers';
|
|
|
@ -1,25 +0,0 @@
|
||||||
import type { BusterSocketResponse, BusterSocketResponseRoute } from '@/api/buster_socket';
|
|
||||||
import { UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Infers the response data type from a BusterSocket route
|
|
||||||
*/
|
|
||||||
export type InferBusterSocketResponseData<TRoute extends BusterSocketResponseRoute> = Extract<
|
|
||||||
BusterSocketResponse,
|
|
||||||
{ route: TRoute }
|
|
||||||
>['callback'] extends (d: infer D) => void
|
|
||||||
? D
|
|
||||||
: never;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Socket response configuration with optional error handler
|
|
||||||
*/
|
|
||||||
export type BusterSocketResponseConfig<TRoute extends BusterSocketResponseRoute> = {
|
|
||||||
route: TRoute;
|
|
||||||
onError?: (d: unknown) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface UseBusterSocketQueryOptions<TData, TError = unknown>
|
|
||||||
extends Omit<UseQueryOptions<TData, TError>, 'queryKey' | 'queryFn'> {}
|
|
||||||
|
|
||||||
export type UseBusterSocketQueryResult<TData, TError = unknown> = UseQueryResult<TData, TError>;
|
|
|
@ -203,7 +203,7 @@ export const useUpdateMetricConfig = ({
|
||||||
route: '/metrics/update:updateMetricState',
|
route: '/metrics/update:updateMetricState',
|
||||||
callback: onInitializeMetric
|
callback: onInitializeMetric
|
||||||
}
|
}
|
||||||
}) as Promise<[BusterMetric]>;
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
export * from './react';
|
export * from './react';
|
||||||
export * from './dom';
|
export * from './dom';
|
||||||
export * from './useDebounceSearch';
|
export * from './useDebounceSearch';
|
||||||
|
export * from './useBusterWebSocketQuery';
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { UseQueryOptions } from '@tanstack/react-query';
|
|
||||||
|
|
||||||
export const DEFAULT_OPTIONS: Partial<UseQueryOptions> = {
|
|
||||||
refetchOnWindowFocus: false,
|
|
||||||
refetchOnMount: true,
|
|
||||||
retry: 0,
|
|
||||||
staleTime: 0
|
|
||||||
};
|
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './useBusterWebSocketQuery';
|
|
@ -1,13 +1,22 @@
|
||||||
import { UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
|
import type { BusterSocketResponse, BusterSocketResponseRoute } from '@/api/buster_socket';
|
||||||
import {
|
import { UseQueryResult } from '@tanstack/react-query';
|
||||||
BusterSocketRequestBase,
|
|
||||||
BusterSocketResponseBase
|
|
||||||
} from '@/api/buster_socket/base_interfaces';
|
|
||||||
|
|
||||||
export interface UseBusterSocketQueryOptions<TData, TError = unknown>
|
/**
|
||||||
extends Omit<UseQueryOptions<TData, TError>, 'queryKey' | 'queryFn'> {
|
* Infers the response data type from a BusterSocket route
|
||||||
socketRequest: BusterSocketRequestBase;
|
*/
|
||||||
socketResponse: Omit<BusterSocketResponseBase, 'callback' | 'onError'>;
|
export type InferBusterSocketResponseData<TRoute extends BusterSocketResponseRoute> = Extract<
|
||||||
}
|
BusterSocketResponse,
|
||||||
|
{ route: TRoute }
|
||||||
|
>['callback'] extends (d: infer D) => void
|
||||||
|
? D
|
||||||
|
: never;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Socket response configuration with optional error handler
|
||||||
|
*/
|
||||||
|
export type BusterSocketResponseConfig<TRoute extends BusterSocketResponseRoute> = {
|
||||||
|
route: TRoute;
|
||||||
|
onError?: (d: unknown) => void;
|
||||||
|
};
|
||||||
|
|
||||||
export type UseBusterSocketQueryResult<TData, TError = unknown> = UseQueryResult<TData, TError>;
|
export type UseBusterSocketQueryResult<TData, TError = unknown> = UseQueryResult<TData, TError>;
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { QueryKey, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import type { BusterSocketResponse, BusterSocketResponseRoute } from '@/api/buster_socket';
|
||||||
|
import { useBusterWebSocket } from '@/context/BusterWebSocket';
|
||||||
|
import type {
|
||||||
|
UseBusterSocketQueryResult,
|
||||||
|
InferBusterSocketResponseData,
|
||||||
|
BusterSocketResponseConfig
|
||||||
|
} from './types';
|
||||||
|
import { useMount } from 'ahooks';
|
||||||
|
|
||||||
|
export const useBusterWebSocketOn = <TRoute extends BusterSocketResponseRoute, TError = unknown>(
|
||||||
|
queryKey: QueryKey,
|
||||||
|
socketResponse: BusterSocketResponseConfig<TRoute>
|
||||||
|
): UseBusterSocketQueryResult<InferBusterSocketResponseData<TRoute>, TError> => {
|
||||||
|
const busterSocket = useBusterWebSocket();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
useMount(() => {
|
||||||
|
busterSocket.on({
|
||||||
|
route: socketResponse.route,
|
||||||
|
onError: socketResponse.onError,
|
||||||
|
callback: (d: unknown) => {
|
||||||
|
queryClient.setQueryData(queryKey, d as InferBusterSocketResponseData<TRoute>);
|
||||||
|
queryClient.invalidateQueries({ queryKey });
|
||||||
|
}
|
||||||
|
} as BusterSocketResponse);
|
||||||
|
});
|
||||||
|
|
||||||
|
return useQuery({
|
||||||
|
queryKey
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const ExampleUsage = () => {
|
||||||
|
const { data, isFetched } = useBusterWebSocketOn(['chats', 'get', '123'], {
|
||||||
|
route: '/chats/get:getChat'
|
||||||
|
});
|
||||||
|
};
|
|
@ -1,13 +1,11 @@
|
||||||
import { useQuery, QueryKey, UseQueryOptions } from '@tanstack/react-query';
|
import { QueryKey, UseQueryOptions } from '@tanstack/react-query';
|
||||||
import type {
|
import type {
|
||||||
BusterSocketRequest,
|
BusterSocketRequest,
|
||||||
BusterSocketResponse,
|
BusterSocketResponse,
|
||||||
BusterSocketResponseRoute
|
BusterSocketResponseRoute
|
||||||
} from '@/api/buster_socket';
|
} from '@/api/buster_socket';
|
||||||
import { useBusterWebSocket } from '../useBusterWebSocket';
|
import { useBusterWebSocket } from '@/context/BusterWebSocket';
|
||||||
import { transformError } from './helpers';
|
|
||||||
import type {
|
import type {
|
||||||
UseBusterSocketQueryOptions,
|
|
||||||
UseBusterSocketQueryResult,
|
UseBusterSocketQueryResult,
|
||||||
InferBusterSocketResponseData,
|
InferBusterSocketResponseData,
|
||||||
BusterSocketResponseConfig
|
BusterSocketResponseConfig
|
||||||
|
@ -18,7 +16,10 @@ export function useBusterWebSocketQuery<TRoute extends BusterSocketResponseRoute
|
||||||
queryKey: QueryKey,
|
queryKey: QueryKey,
|
||||||
socketRequest: BusterSocketRequest,
|
socketRequest: BusterSocketRequest,
|
||||||
socketResponse: BusterSocketResponseConfig<TRoute>,
|
socketResponse: BusterSocketResponseConfig<TRoute>,
|
||||||
options?: UseQueryOptions<InferBusterSocketResponseData<TRoute>, TError>
|
options?: Omit<
|
||||||
|
UseQueryOptions<InferBusterSocketResponseData<TRoute>, TError>,
|
||||||
|
'queryKey' | 'queryFn'
|
||||||
|
>
|
||||||
): UseBusterSocketQueryResult<InferBusterSocketResponseData<TRoute>, TError> {
|
): UseBusterSocketQueryResult<InferBusterSocketResponseData<TRoute>, TError> {
|
||||||
const busterSocket = useBusterWebSocket();
|
const busterSocket = useBusterWebSocket();
|
||||||
|
|
||||||
|
@ -39,30 +40,19 @@ export function useBusterWebSocketQuery<TRoute extends BusterSocketResponseRoute
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// return useCreateReactQuery<InferBusterSocketResponseData<TRoute>>({
|
return useCreateReactQuery<InferBusterSocketResponseData<TRoute>, TError>({
|
||||||
// queryKey,
|
|
||||||
// queryFn,
|
|
||||||
// isUseSession: false
|
|
||||||
// });
|
|
||||||
|
|
||||||
return useQuery<
|
|
||||||
InferBusterSocketResponseData<TRoute>,
|
|
||||||
TError,
|
|
||||||
InferBusterSocketResponseData<TRoute>
|
|
||||||
>({
|
|
||||||
queryKey,
|
queryKey,
|
||||||
queryFn,
|
queryFn,
|
||||||
...options
|
isUseSession: false,
|
||||||
|
options
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example usage with automatic type inference
|
// Example usage with automatic type inference
|
||||||
export const ExampleUsage = () => {
|
const ExampleUsage = () => {
|
||||||
const { data, isLoading, error } = useBusterWebSocketQuery(
|
const { data, isLoading, error } = useBusterWebSocketQuery(
|
||||||
['chats', 'get', '123'],
|
['chats', 'get', '123'],
|
||||||
{ route: '/chats/get', payload: { id: '123' } },
|
{ route: '/chats/get', payload: { id: '123' } },
|
||||||
{ route: '/chats/get:getChat' }
|
{ route: '/chats/get:getChat' }
|
||||||
);
|
);
|
||||||
|
|
||||||
useCreateReactQuery;
|
|
||||||
};
|
};
|
Loading…
Reference in New Issue