import type { SeamActionAttemptFailedError, SeamActionAttemptTimeoutError, SeamHttpApiError, SeamHttpEndpointPaginatedQueryPaths, SeamHttpEndpoints, SeamHttpInvalidInputError, SeamHttpRequest, SeamPageCursor, } from '@seamapi/http' import type { ActionAttempt } from '@seamapi/types/connect' import { type QueryKey, useInfiniteQuery, type UseInfiniteQueryOptions, type UseInfiniteQueryResult, } from '@tanstack/react-query' import { useSeamClient } from 'lib/use-seam-client.js' export type UseSeamInfiniteQueryParameters< T extends SeamHttpEndpointPaginatedQueryPaths, > = Parameters[0] export type UseSeamInfiniteQueryResult< T extends SeamHttpEndpointPaginatedQueryPaths, > = UseInfiniteQueryResult, QueryError> export function useSeamInfiniteQuery< T extends SeamHttpEndpointPaginatedQueryPaths, >( endpointPath: T, parameters: UseSeamInfiniteQueryParameters = {}, options: Parameters[1] & QueryOptions, QueryError> = {}, ): UseSeamInfiniteQueryResult & { queryKey: QueryKey } { const { endpointClient: client, queryKeyPrefixes } = useSeamClient() if ('page_cursor' in (parameters ?? {})) { throw new Error('Cannot use page_cursor with useSeamInfiniteQuery') } const queryKey = [ ...queryKeyPrefixes, ...endpointPath.split('/').filter((v) => v !== ''), parameters ?? {}, ] const result = useInfiniteQuery({ enabled: client != null, ...options, queryKey, initialPageParam: null, getNextPageParam: (lastPage) => lastPage.nextPageCursor, queryFn: async ({ pageParam }) => { if (client == null) return { data: [] as Awaited>, nextPageCursor: null, } // Using @ts-expect-error over any is preferred, but not possible here because TypeScript will run out of memory. // Type assertion is needed here for performance reasons. The types are correct at runtime. const endpoint = client[endpointPath] as (...args: any) => any const request = endpoint(parameters, options) const pages = client.createPaginator(request as SeamHttpRequest) if (pageParam == null) { const [data, { nextPageCursor }] = await pages.firstPage() return { data: data as Awaited>, nextPageCursor, } } // Type assertion is needed for pageParam since the Seam API expects a branded PageCursor type. const [data, { nextPageCursor }] = await pages.nextPage( pageParam as SeamPageCursor, ) return { data: data as Awaited>, nextPageCursor, } }, }) return { ...result, queryKey } } interface QueryData { data: Awaited> nextPageCursor: SeamPageCursor | null } type QueryError = | Error | SeamHttpApiError | SeamHttpInvalidInputError | (QueryData['data'] extends ActionAttempt ? | SeamActionAttemptFailedError['data']> | SeamActionAttemptTimeoutError['data']> : never) type QueryOptions = Omit< UseInfiniteQueryOptions, 'queryKey' | 'queryFn' | 'initialPageParam' | 'getNextPageParam' >