import { MutationObserver, shouldThrowError, QueriesObserver, noop, QueryClient as QueryClient$1, replaceEqualDeep, hydrate, notifyManager, QueryObserver, InfiniteQueryObserver } from '@tanstack/query-core'; export * from '@tanstack/query-core'; import { createContext, useContext, createRenderEffect, onCleanup, createMemo, createComputed, on, mergeProps, createResource, batch, onMount, createSignal, createEffect } from 'solid-js'; import { createComponent, isServer } from 'solid-js/web'; import { createStore, unwrap, reconcile } from 'solid-js/store'; // src/useQuery.ts var QueryClientContext = createContext(void 0); var useQueryClient = (queryClient) => { if (queryClient) { return queryClient; } const client = useContext(QueryClientContext); if (!client) { throw new Error("No QueryClient set, use QueryClientProvider to set one"); } return client(); }; var QueryClientProvider = (props) => { createRenderEffect((unmount) => { unmount?.(); props.client.mount(); return props.client.unmount.bind(props.client); }); onCleanup(() => props.client.unmount()); return createComponent(QueryClientContext.Provider, { value: () => props.client, get children() { return props.children; } }); }; var IsRestoringContext = createContext(() => false); var useIsRestoring = () => useContext(IsRestoringContext); var IsRestoringProvider = IsRestoringContext.Provider; // src/useBaseQuery.ts function reconcileFn(store, result, reconcileOption, queryHash) { if (reconcileOption === false) return result; if (typeof reconcileOption === "function") { const newData2 = reconcileOption(store.data, result.data); return { ...result, data: newData2 }; } let data = result.data; if (store.data === void 0) { try { data = structuredClone(data); } catch (error) { { if (error instanceof Error) { console.warn( `Unable to correctly reconcile data for query key: ${queryHash}. Possibly because the query data contains data structures that aren't supported by the 'structuredClone' algorithm. Consider using a callback function instead to manage the reconciliation manually. Error Received: ${error.name} - ${error.message}` ); } } } } const newData = reconcile(data, { key: reconcileOption })(store.data); return { ...result, data: newData }; } var hydratableObserverResult = (query, result) => { if (!isServer) return result; const obj = { ...unwrap(result), // During SSR, functions cannot be serialized, so we need to remove them // This is safe because we will add these functions back when the query is hydrated refetch: void 0 }; if ("fetchNextPage" in result) { obj.fetchNextPage = void 0; obj.fetchPreviousPage = void 0; } obj.hydrationData = { state: query.state, queryKey: query.queryKey, queryHash: query.queryHash, ...query.meta && { meta: query.meta } }; return obj; }; function useBaseQuery(options, Observer, queryClient) { const client = createMemo(() => useQueryClient(queryClient?.())); const isRestoring = useIsRestoring(); let unsubscribeQueued = false; const defaultedOptions = createMemo(() => { const defaultOptions = client().defaultQueryOptions(options()); defaultOptions._optimisticResults = isRestoring() ? "isRestoring" : "optimistic"; defaultOptions.structuralSharing = false; if (isServer) { defaultOptions.retry = false; defaultOptions.throwOnError = true; defaultOptions.experimental_prefetchInRender = true; } return defaultOptions; }); const initialOptions = defaultedOptions(); const [observer, setObserver] = createSignal( new Observer(client(), defaultedOptions()) ); let observerResult = observer().getOptimisticResult(defaultedOptions()); const [state, setState] = createStore(observerResult); const createServerSubscriber = (resolve, reject) => { return observer().subscribe((result) => { notifyManager.batchCalls(() => { const query = observer().getCurrentQuery(); const unwrappedResult = hydratableObserverResult(query, result); if (result.data !== void 0 && unwrappedResult.isError) { reject(unwrappedResult.error); unsubscribeIfQueued(); } else { resolve(unwrappedResult); unsubscribeIfQueued(); } })(); }); }; const unsubscribeIfQueued = () => { if (unsubscribeQueued) { unsubscribe?.(); unsubscribeQueued = false; } }; const createClientSubscriber = () => { const obs = observer(); return obs.subscribe((result) => { observerResult = result; queueMicrotask(() => { if (unsubscribe) { refetch(); } }); }); }; function setStateWithReconciliation(res) { const opts = observer().options; const reconcileOptions = opts.reconcile; setState((store) => { return reconcileFn( store, res, reconcileOptions === void 0 ? false : reconcileOptions, opts.queryHash ); }); } function createDeepSignal() { return [ () => state, (v) => { const unwrapped = unwrap(state); if (typeof v === "function") { v = v(unwrapped); } if (v?.hydrationData) { const { hydrationData, ...rest } = v; v = rest; } setStateWithReconciliation(v); } ]; } let unsubscribe = null; let resolver = null; const [queryResource, { refetch }] = createResource( () => { const obs = observer(); return new Promise((resolve, reject) => { resolver = resolve; if (isServer) { unsubscribe = createServerSubscriber(resolve, reject); } else if (!unsubscribe && !isRestoring()) { unsubscribe = createClientSubscriber(); } obs.updateResult(); if (observerResult.isError && !observerResult.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [ observerResult.error, obs.getCurrentQuery() ])) { setStateWithReconciliation(observerResult); return reject(observerResult.error); } if (!observerResult.isLoading) { resolver = null; return resolve( hydratableObserverResult(obs.getCurrentQuery(), observerResult) ); } setStateWithReconciliation(observerResult); }); }, { storage: createDeepSignal, get deferStream() { return options().deferStream; }, /** * If this resource was populated on the server (either sync render, or streamed in over time), onHydrated * will be called. This is the point at which we can hydrate the query cache state, and setup the query subscriber. * * Leveraging onHydrated allows us to plug into the async and streaming support that solidjs resources already support. * * Note that this is only invoked on the client, for queries that were originally run on the server. */ onHydrated(_k, info) { if (info.value && "hydrationData" in info.value) { hydrate(client(), { // @ts-expect-error - hydrationData is not correctly typed internally queries: [{ ...info.value.hydrationData }] }); } if (unsubscribe) return; const newOptions = { ...initialOptions }; if ((initialOptions.staleTime || !initialOptions.initialData) && info.value) { newOptions.refetchOnMount = false; } observer().setOptions(newOptions); setStateWithReconciliation(observer().getOptimisticResult(newOptions)); unsubscribe = createClientSubscriber(); } } ); createComputed( on( client, (c) => { if (unsubscribe) { unsubscribe(); } const newObserver = new Observer(c, defaultedOptions()); unsubscribe = createClientSubscriber(); setObserver(newObserver); }, { defer: true } ) ); createComputed( on( isRestoring, (restoring) => { if (!restoring && !isServer) { refetch(); } }, { defer: true } ) ); onCleanup(() => { if (isServer && queryResource.loading) { unsubscribeQueued = true; return; } if (unsubscribe) { unsubscribe(); unsubscribe = null; } if (resolver && !isServer) { resolver(observerResult); resolver = null; } }); createComputed( on( [observer, defaultedOptions], ([obs, opts]) => { obs.setOptions(opts); setStateWithReconciliation(obs.getOptimisticResult(opts)); refetch(); }, { defer: true } ) ); const handler = { get(target, prop) { if (prop === "data") { if (state.data !== void 0) { return queryResource.latest?.data; } return queryResource()?.data; } return Reflect.get(target, prop); } }; return new Proxy(state, handler); } // src/useQuery.ts function useQuery(options, queryClient) { return useBaseQuery( createMemo(() => options()), QueryObserver, queryClient ); } function useInfiniteQuery(options, queryClient) { return useBaseQuery( createMemo(() => options()), InfiniteQueryObserver, queryClient ); } function useMutation(options, queryClient) { const client = createMemo(() => useQueryClient(queryClient?.())); const observer = new MutationObserver(client(), options()); const mutate = (variables, mutateOptions) => { observer.mutate(variables, mutateOptions).catch(noop); }; const [state, setState] = createStore({ ...observer.getCurrentResult(), mutate, mutateAsync: observer.getCurrentResult().mutate }); createComputed(() => { observer.setOptions(options()); }); createComputed( on( () => state.status, () => { if (state.isError && shouldThrowError(observer.options.throwOnError, [state.error])) { throw state.error; } } ) ); const unsubscribe = observer.subscribe((result) => { setState({ ...result, mutate, mutateAsync: result.mutate }); }); onCleanup(unsubscribe); return state; } function useQueries(queriesOptions, queryClient) { const client = createMemo(() => useQueryClient(queryClient?.())); const isRestoring = useIsRestoring(); const defaultedQueries = createMemo( () => queriesOptions().queries.map( (options) => mergeProps( client().defaultQueryOptions(options), { get _optimisticResults() { return isRestoring() ? "isRestoring" : "optimistic"; } } ) ) ); const observer = new QueriesObserver( client(), defaultedQueries(), queriesOptions().combine ? { combine: queriesOptions().combine } : void 0 ); const [state, setState] = createStore( observer.getOptimisticResult( defaultedQueries(), queriesOptions().combine )[1]() ); createRenderEffect( on( () => queriesOptions().queries.length, () => setState( observer.getOptimisticResult( defaultedQueries(), queriesOptions().combine )[1]() ) ) ); const dataResources = createMemo( on( () => state.length, () => state.map((queryRes) => { const dataPromise = () => new Promise((resolve) => { if (queryRes.isFetching && queryRes.isLoading) return; resolve(unwrap(queryRes.data)); }); return createResource(dataPromise); }) ) ); batch(() => { const dataResources_ = dataResources(); for (let index = 0; index < dataResources_.length; index++) { const dataResource = dataResources_[index]; dataResource[1].mutate(() => unwrap(state[index].data)); dataResource[1].refetch(); } }); let taskQueue = []; const subscribeToObserver = () => observer.subscribe((result) => { taskQueue.push(() => { batch(() => { const dataResources_ = dataResources(); for (let index = 0; index < dataResources_.length; index++) { const dataResource = dataResources_[index]; const unwrappedResult = { ...unwrap(result[index]) }; setState(index, unwrap(unwrappedResult)); dataResource[1].mutate(() => unwrap(state[index].data)); dataResource[1].refetch(); } }); }); queueMicrotask(() => { const taskToRun = taskQueue.pop(); if (taskToRun) taskToRun(); taskQueue = []; }); }); let unsubscribe = noop; createComputed((cleanup) => { cleanup?.(); unsubscribe = isRestoring() ? noop : subscribeToObserver(); return () => queueMicrotask(unsubscribe); }); onCleanup(unsubscribe); onMount(() => { observer.setQueries( defaultedQueries(), queriesOptions().combine ? { combine: queriesOptions().combine } : void 0 ); }); createComputed(() => { observer.setQueries( defaultedQueries(), queriesOptions().combine ? { combine: queriesOptions().combine } : void 0 ); }); const handler = (index) => ({ get(target, prop) { if (prop === "data") { return dataResources()[index][0](); } return Reflect.get(target, prop); } }); const getProxies = () => state.map((s, index) => { return new Proxy(s, handler(index)); }); const [proxyState, setProxyState] = createStore(getProxies()); createRenderEffect(() => setProxyState(getProxies())); return proxyState; } var QueryClient = class extends QueryClient$1 { constructor(config = {}) { super(config); } }; // src/queryOptions.ts function queryOptions(options) { return options; } function useIsFetching(filters, queryClient) { const client = createMemo(() => useQueryClient(queryClient?.())); const queryCache = createMemo(() => client().getQueryCache()); const [fetches, setFetches] = createSignal(client().isFetching(filters?.())); const unsubscribe = queryCache().subscribe(() => { setFetches(client().isFetching(filters?.())); }); onCleanup(unsubscribe); return fetches; } // src/infiniteQueryOptions.ts function infiniteQueryOptions(options) { return options; } // src/mutationOptions.ts function mutationOptions(options) { return options; } function useIsMutating(filters, queryClient) { const client = createMemo(() => useQueryClient(queryClient?.())); const mutationCache = createMemo(() => client().getMutationCache()); const [mutations, setMutations] = createSignal( client().isMutating(filters?.()) ); const unsubscribe = mutationCache().subscribe((_result) => { setMutations(client().isMutating(filters?.())); }); onCleanup(unsubscribe); return mutations; } function getResult(mutationCache, options) { return mutationCache.findAll(options.filters).map( (mutation) => options.select ? options.select(mutation) : mutation.state ); } function useMutationState(options = () => ({}), queryClient) { const client = createMemo(() => useQueryClient(queryClient?.())); const mutationCache = createMemo(() => client().getMutationCache()); const [result, setResult] = createSignal( getResult(mutationCache(), options()) ); createEffect(() => { const unsubscribe = mutationCache().subscribe(() => { const nextResult = replaceEqualDeep( result(), getResult(mutationCache(), options()) ); if (result() !== nextResult) { setResult(nextResult); } }); onCleanup(unsubscribe); }); return result; } // src/index.ts var createQuery = useQuery; var createInfiniteQuery = useInfiniteQuery; var createMutation = useMutation; var createQueries = useQueries; export { IsRestoringProvider, QueryClient, QueryClientContext, QueryClientProvider, createInfiniteQuery, useIsFetching as createIsFetching, useIsMutating as createIsMutating, createMutation, useMutationState as createMutationState, createQueries, createQuery, infiniteQueryOptions, mutationOptions, queryOptions, useInfiniteQuery, useIsFetching, useIsMutating, useIsRestoring, useMutation, useMutationState, useQueries, useQuery, useQueryClient };