New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

@tanstack/solid-query

Package Overview
Dependencies
Maintainers
6
Versions
443
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tanstack/solid-query - npm Package Compare versions

Comparing version
5.91.3
to
6.0.0-alpha.0
+6
-7
build/_tsup-dts-rollup.d.cts

@@ -6,3 +6,2 @@ import type { Accessor } from 'solid-js';

import { Context } from 'solid-js';
import { ContextProviderComponent } from 'solid-js';
import { DataTag } from '@tanstack/query-core';

@@ -364,5 +363,5 @@ import { dataTagErrorSymbol } from '@tanstack/query-core';

declare const IsRestoringProvider: ContextProviderComponent<Accessor<boolean>>;
export { IsRestoringProvider }
export { IsRestoringProvider as IsRestoringProvider_alias_1 }
declare const IsRestoringContext: Context<Accessor<boolean>>;
export { IsRestoringContext }
export { IsRestoringContext as IsRestoringContext_alias_1 }

@@ -469,3 +468,3 @@ export { isServer }

/**
* QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
* QueriesOptions reducer recursively snapshots function arguments to infer/enforce type param
*/

@@ -517,3 +516,3 @@ declare type QueriesOptions<T extends Array<any>, TResult extends Array<any> = [], TDepth extends ReadonlyArray<number> = []> = TDepth['length'] extends MAXIMUM_DEPTH ? Array<UseQueryOptionsForUseQueries> : T extends [] ? [] : T extends [infer Head] ? [...TResult, GetOptions<Head>] : T extends [infer Head, ...infer Tail] ? QueriesOptions<[

declare const QueryClientContext: Context<(() => QueryClient) | undefined>;
declare const QueryClientContext: Context<(() => QueryClient) | null>;
export { QueryClientContext }

@@ -685,3 +684,3 @@ export { QueryClientContext as QueryClientContext_alias_1 }

export declare function useBaseQuery<TQueryFnData, TError, TData, TQueryData, TQueryKey extends QueryKey>(options: Accessor<UseBaseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>>, Observer: typeof QueryObserver, queryClient?: Accessor<QueryClient>): QueryObserverResult<TData, TError>;
export declare function useBaseQuery<TQueryFnData, TError, TData, TQueryData, TQueryKey extends QueryKey>(options: Accessor<UseBaseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>>, Observer: typeof QueryObserver, queryClient?: Accessor<QueryClient>): Readonly<QueryObserverResult<TData, TError>>;

@@ -688,0 +687,0 @@ declare interface UseBaseQueryOptions<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey> extends OmitKeyof<QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>, 'suspense'> {

@@ -6,3 +6,2 @@ import type { Accessor } from 'solid-js';

import { Context } from 'solid-js';
import { ContextProviderComponent } from 'solid-js';
import { DataTag } from '@tanstack/query-core';

@@ -364,5 +363,5 @@ import { dataTagErrorSymbol } from '@tanstack/query-core';

declare const IsRestoringProvider: ContextProviderComponent<Accessor<boolean>>;
export { IsRestoringProvider }
export { IsRestoringProvider as IsRestoringProvider_alias_1 }
declare const IsRestoringContext: Context<Accessor<boolean>>;
export { IsRestoringContext }
export { IsRestoringContext as IsRestoringContext_alias_1 }

@@ -469,3 +468,3 @@ export { isServer }

/**
* QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
* QueriesOptions reducer recursively snapshots function arguments to infer/enforce type param
*/

@@ -517,3 +516,3 @@ declare type QueriesOptions<T extends Array<any>, TResult extends Array<any> = [], TDepth extends ReadonlyArray<number> = []> = TDepth['length'] extends MAXIMUM_DEPTH ? Array<UseQueryOptionsForUseQueries> : T extends [] ? [] : T extends [infer Head] ? [...TResult, GetOptions<Head>] : T extends [infer Head, ...infer Tail] ? QueriesOptions<[

declare const QueryClientContext: Context<(() => QueryClient) | undefined>;
declare const QueryClientContext: Context<(() => QueryClient) | null>;
export { QueryClientContext }

@@ -685,3 +684,3 @@ export { QueryClientContext as QueryClientContext_alias_1 }

export declare function useBaseQuery<TQueryFnData, TError, TData, TQueryData, TQueryKey extends QueryKey>(options: Accessor<UseBaseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>>, Observer: typeof QueryObserver, queryClient?: Accessor<QueryClient>): QueryObserverResult<TData, TError>;
export declare function useBaseQuery<TQueryFnData, TError, TData, TQueryData, TQueryKey extends QueryKey>(options: Accessor<UseBaseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>>, Observer: typeof QueryObserver, queryClient?: Accessor<QueryClient>): Readonly<QueryObserverResult<TData, TError>>;

@@ -688,0 +687,0 @@ declare interface UseBaseQueryOptions<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey> extends OmitKeyof<QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>, 'suspense'> {

@@ -5,7 +5,6 @@ 'use strict';

var solidJs = require('solid-js');
var web = require('solid-js/web');
var store = require('solid-js/store');
var web = require('@solidjs/web');
// src/useQuery.ts
exports.QueryClientContext = solidJs.createContext(void 0);
exports.QueryClientContext = solidJs.createContext(null);
exports.useQueryClient = (queryClient) => {

@@ -22,9 +21,5 @@ if (queryClient) {

exports.QueryClientProvider = (props) => {
solidJs.createRenderEffect((unmount) => {
unmount?.();
props.client.mount();
return props.client.unmount.bind(props.client);
});
props.client.mount();
solidJs.onCleanup(() => props.client.unmount());
return web.createComponent(exports.QueryClientContext.Provider, {
return web.createComponent(exports.QueryClientContext, {
value: () => props.client,

@@ -36,15 +31,28 @@ get children() {

};
var IsRestoringContext = solidJs.createContext(() => false);
exports.useIsRestoring = () => solidJs.useContext(IsRestoringContext);
exports.IsRestoringProvider = IsRestoringContext.Provider;
exports.IsRestoringContext = solidJs.createContext(() => false);
exports.useIsRestoring = () => solidJs.useContext(exports.IsRestoringContext);
// src/useBaseQuery.ts
function reconcileFn(store$1, result, reconcileOption, queryHash) {
if (reconcileOption === false) return result;
var isServer = typeof window === "undefined";
function _stripFnsForSSR(obj) {
if (!isServer) return obj;
const out = {};
for (const k of Object.keys(obj)) {
if (k === "refetch" || k === "fetchNextPage" || k === "fetchPreviousPage") {
out[k] = void 0;
} else {
out[k] = obj[k];
}
}
return out;
}
function reconcileFn(store, result, reconcileOption, queryHash) {
if (typeof reconcileOption === "function") {
const newData2 = reconcileOption(store$1.data, result.data);
return { ...result, data: newData2 };
const newData = reconcileOption(store.data, result.data);
return { ...result, data: newData };
}
if (reconcileOption === false) return result;
const key = reconcileOption;
let data = result.data;
if (store$1.data === void 0) {
if (store.data === void 0) {
try {

@@ -64,9 +72,12 @@ data = structuredClone(data);

}
const newData = store.reconcile(data, { key: reconcileOption })(store$1.data);
return { ...result, data: newData };
if (store.data !== void 0 && data !== void 0) {
solidJs.reconcile(data, key)(store.data);
return { ...result, data: store.data };
}
return { ...result, data };
}
var hydratableObserverResult = (query, result) => {
if (!web.isServer) return result;
if (!isServer) return result;
const obj = {
...store.unwrap(result),
...solidJs.snapshot(result),
// During SSR, functions cannot be serialized, so we need to remove them

@@ -96,3 +107,3 @@ // This is safe because we will add these functions back when the query is hydrated

defaultOptions.structuralSharing = false;
if (web.isServer) {
if (isServer) {
defaultOptions.retry = false;

@@ -104,12 +115,18 @@ defaultOptions.throwOnError = true;

});
const initialOptions = defaultedOptions();
const [observer, setObserver] = solidJs.createSignal(
new Observer(client(), defaultedOptions())
const observer = new Observer(client(), defaultedOptions());
const trackedDefaultedOptions = solidJs.createMemo(() => defaultedOptions());
solidJs.createRenderEffect(
() => trackedDefaultedOptions(),
(opts) => {
observer.setOptions(opts);
}
);
let observerResult = observer().getOptimisticResult(defaultedOptions());
const [state, setState] = store.createStore(observerResult);
let observerResult = observer.getOptimisticResult(defaultedOptions());
const [state, setState] = solidJs.createStore(
_stripFnsForSSR(observerResult)
);
const createServerSubscriber = (resolve, reject) => {
return observer().subscribe((result) => {
return observer.subscribe((result) => {
queryCore.notifyManager.batchCalls(() => {
const query = observer().getCurrentQuery();
const query = observer.getCurrentQuery();
const unwrappedResult = hydratableObserverResult(query, result);

@@ -133,8 +150,12 @@ if (result.data !== void 0 && unwrappedResult.isError) {

const createClientSubscriber = () => {
const obs = observer();
return obs.subscribe((result) => {
return observer.subscribe((result) => {
const previousResult = observerResult;
observerResult = result;
setStateWithReconciliation(result);
queueMicrotask(() => {
if (unsubscribe) {
refetch();
if (unsubscribe && !disposed && (previousResult.isLoading !== result.isLoading || previousResult.isError !== result.isError)) {
try {
solidJs.refresh(queryResource);
} catch {
}
}

@@ -145,8 +166,9 @@ });

function setStateWithReconciliation(res) {
const opts = observer().options;
const opts = observer.options;
const reconcileOptions = opts.reconcile;
const sanitized = _stripFnsForSSR(res);
setState((store) => {
return reconcileFn(
store,
res,
sanitized,
reconcileOptions === void 0 ? false : reconcileOptions,

@@ -157,107 +179,43 @@ opts.queryHash

}
function createDeepSignal() {
return [
() => state,
(v) => {
const unwrapped = store.unwrap(state);
if (typeof v === "function") {
v = v(unwrapped);
}
if (v?.hydrationData) {
const { hydrationData, ...rest } = v;
v = rest;
}
setStateWithReconciliation(v);
}
];
}
let unsubscribe = null;
let disposed = false;
let resolver = null;
const [queryResource, { refetch }] = solidJs.createResource(
const queryResource = solidJs.createMemo(
() => {
const obs = observer();
const opts = trackedDefaultedOptions();
const restoring = isRestoring();
return new Promise((resolve, reject) => {
resolver = resolve;
if (web.isServer) {
unsubscribe = createServerSubscriber(resolve, reject);
} else if (!unsubscribe && !isRestoring()) {
if (isServer) {
unsubscribe = createServerSubscriber((data) => {
resolve(data);
}, reject);
} else if (!unsubscribe && !restoring) {
unsubscribe = createClientSubscriber();
}
obs.updateResult();
if (observerResult.isError && !observerResult.isFetching && !isRestoring() && queryCore.shouldThrowError(obs.options.throwOnError, [
observerResult.error,
obs.getCurrentQuery()
const currentResult = observer.getOptimisticResult(opts);
observerResult = currentResult;
if (currentResult.isError && !currentResult.isFetching && !restoring && queryCore.shouldThrowError(opts.throwOnError, [
currentResult.error,
observer.getCurrentQuery()
])) {
setStateWithReconciliation(observerResult);
return reject(observerResult.error);
setStateWithReconciliation(currentResult);
return reject(currentResult.error);
}
if (!observerResult.isLoading) {
if (!currentResult.isLoading) {
resolver = null;
setStateWithReconciliation(currentResult);
return resolve(
hydratableObserverResult(obs.getCurrentQuery(), observerResult)
hydratableObserverResult(observer.getCurrentQuery(), currentResult)
);
}
setStateWithReconciliation(observerResult);
queueMicrotask(() => setStateWithReconciliation(currentResult));
});
},
{
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) {
queryCore.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();
}
}
observerResult,
{ ssrSource: "client" }
);
solidJs.createComputed(
solidJs.on(
client,
(c) => {
if (unsubscribe) {
unsubscribe();
}
const newObserver = new Observer(c, defaultedOptions());
unsubscribe = createClientSubscriber();
setObserver(newObserver);
},
{
defer: true
}
)
);
solidJs.createComputed(
solidJs.on(
isRestoring,
(restoring) => {
if (!restoring && !web.isServer) {
refetch();
}
},
{ defer: true }
)
);
solidJs.onCleanup(() => {
if (web.isServer && queryResource.loading) {
disposed = true;
if (isServer && solidJs.isPending(queryResource)) {
unsubscribeQueued = true;

@@ -270,3 +228,3 @@ return;

}
if (resolver && !web.isServer) {
if (resolver && !isServer) {
resolver(observerResult);

@@ -276,25 +234,27 @@ resolver = null;

});
solidJs.createComputed(
solidJs.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;
const errorPassthroughProps = /* @__PURE__ */ new Set([
"error",
"isError",
"failureCount",
"failureReason",
"errorUpdateCount",
"errorUpdatedAt"
]);
return new Proxy(state, {
get(target, prop, receiver) {
if (typeof prop === "symbol") {
return Reflect.get(target, prop, receiver);
}
return Reflect.get(target, prop);
if (errorPassthroughProps.has(prop)) {
return Reflect.get(target, prop, receiver);
}
if (state.isError && !state.isFetching && queryCore.shouldThrowError(observer.options.throwOnError, [
state.error,
observer.getCurrentQuery()
])) {
throw state.error;
}
return Reflect.get(target, prop, receiver);
}
};
return new Proxy(state, handler);
});
}

@@ -320,6 +280,9 @@

const observer = new queryCore.MutationObserver(client(), options());
solidJs.createMemo(() => {
observer.setOptions(options());
});
const mutate = (variables, mutateOptions) => {
observer.mutate(variables, mutateOptions).catch(queryCore.noop);
};
const [state, setState] = store.createStore({
const [state, setState] = solidJs.createStore({
...observer.getCurrentResult(),

@@ -329,23 +292,21 @@ mutate,

});
solidJs.createComputed(() => {
observer.setOptions(options());
});
solidJs.createComputed(
solidJs.on(
() => state.status,
() => {
if (state.isError && queryCore.shouldThrowError(observer.options.throwOnError, [state.error])) {
throw state.error;
}
}
)
);
const unsubscribe = observer.subscribe((result) => {
setState({
setState(() => ({
...result,
mutate,
mutateAsync: result.mutate
});
}));
});
solidJs.onCleanup(unsubscribe);
solidJs.createRenderEffect(
() => {
const isError = state.isError;
const error = state.error;
if (isError && queryCore.shouldThrowError(observer.options.throwOnError, [error])) {
throw error;
}
},
() => {
}
);
return state;

@@ -358,10 +319,7 @@ }

() => queriesOptions().queries.map(
(options) => solidJs.mergeProps(
client().defaultQueryOptions(options),
{
get _optimisticResults() {
return isRestoring() ? "isRestoring" : "optimistic";
}
(options) => solidJs.merge(client().defaultQueryOptions(options), {
get _optimisticResults() {
return isRestoring() ? "isRestoring" : "optimistic";
}
)
})
)

@@ -376,69 +334,36 @@ );

);
const [state, setState] = store.createStore(
observer.getOptimisticResult(
defaultedQueries(),
queriesOptions().combine
)[1]()
const [, getCombinedResult] = observer.getOptimisticResult(
defaultedQueries(),
queriesOptions().combine
);
solidJs.createRenderEffect(
solidJs.on(
() => queriesOptions().queries.length,
() => setState(
observer.getOptimisticResult(
defaultedQueries(),
queriesOptions().combine
)[1]()
)
)
const initialResult = getCombinedResult();
const [state, setState] = solidJs.createStore(
Array.isArray(initialResult) ? initialResult : [initialResult]
);
const dataResources = solidJs.createMemo(
solidJs.on(
() => state.length,
() => state.map((queryRes) => {
const dataPromise = () => new Promise((resolve) => {
if (queryRes.isFetching && queryRes.isLoading) return;
resolve(store.unwrap(queryRes.data));
let unsubscribe = queryCore.noop;
solidJs.createEffect(
() => {
if (!isRestoring()) {
unsubscribe = observer.subscribe((result) => {
setState(
solidJs.reconcile(
[...result],
// Use a key function that returns undefined so reconcile
// uses positional matching and recursively updates nested properties
() => void 0
)
);
});
return solidJs.createResource(dataPromise);
})
)
}
},
() => {
}
);
solidJs.batch(() => {
const dataResources_ = dataResources();
for (let index = 0; index < dataResources_.length; index++) {
const dataResource = dataResources_[index];
dataResource[1].mutate(() => store.unwrap(state[index].data));
dataResource[1].refetch();
}
solidJs.onCleanup(() => {
unsubscribe();
});
let taskQueue = [];
const subscribeToObserver = () => observer.subscribe((result) => {
taskQueue.push(() => {
solidJs.batch(() => {
const dataResources_ = dataResources();
for (let index = 0; index < dataResources_.length; index++) {
const dataResource = dataResources_[index];
const unwrappedResult = { ...store.unwrap(result[index]) };
setState(index, store.unwrap(unwrappedResult));
dataResource[1].mutate(() => store.unwrap(state[index].data));
dataResource[1].refetch();
}
});
});
queueMicrotask(() => {
const taskToRun = taskQueue.pop();
if (taskToRun) taskToRun();
taskQueue = [];
});
});
let unsubscribe = queryCore.noop;
solidJs.createComputed((cleanup) => {
cleanup?.();
unsubscribe = isRestoring() ? queryCore.noop : subscribeToObserver();
return () => queueMicrotask(unsubscribe);
});
solidJs.onCleanup(unsubscribe);
solidJs.onMount(() => {
solidJs.createMemo(() => {
const queries = defaultedQueries();
observer.setQueries(
defaultedQueries(),
queries,
queriesOptions().combine ? {

@@ -448,25 +373,5 @@ combine: queriesOptions().combine

);
return queries;
});
solidJs.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] = store.createStore(getProxies());
solidJs.createRenderEffect(() => setProxyState(getProxies()));
return proxyState;
return state;
}

@@ -526,14 +431,12 @@ exports.QueryClient = class QueryClient extends queryCore.QueryClient {

);
solidJs.createEffect(() => {
const unsubscribe = mutationCache().subscribe(() => {
const unsubscribe = mutationCache().subscribe(() => {
setResult((prev) => {
const nextResult = queryCore.replaceEqualDeep(
result(),
prev,
getResult(mutationCache(), options())
);
if (result() !== nextResult) {
setResult(nextResult);
}
return prev === nextResult ? prev : nextResult;
});
solidJs.onCleanup(unsubscribe);
});
solidJs.onCleanup(unsubscribe);
return result;

@@ -540,0 +443,0 @@ }

@@ -63,3 +63,3 @@ export { DefinedUseBaseQueryResult } from './_tsup-dts-rollup.cjs';

export { useIsRestoring } from './_tsup-dts-rollup.cjs';
export { IsRestoringProvider } from './_tsup-dts-rollup.cjs';
export { IsRestoringContext } from './_tsup-dts-rollup.cjs';
export { focusManager } from './_tsup-dts-rollup.cjs';

@@ -66,0 +66,0 @@ export { environmentManager } from './_tsup-dts-rollup.cjs';

@@ -63,3 +63,3 @@ export { DefinedUseBaseQueryResult } from './_tsup-dts-rollup.js';

export { useIsRestoring } from './_tsup-dts-rollup.js';
export { IsRestoringProvider } from './_tsup-dts-rollup.js';
export { IsRestoringContext } from './_tsup-dts-rollup.js';
export { focusManager } from './_tsup-dts-rollup.js';

@@ -66,0 +66,0 @@ export { environmentManager } from './_tsup-dts-rollup.js';

+155
-252

@@ -1,9 +0,8 @@

import { MutationObserver, shouldThrowError, QueriesObserver, noop, QueryClient as QueryClient$1, replaceEqualDeep, hydrate, notifyManager, QueryObserver, InfiniteQueryObserver } from '@tanstack/query-core';
import { MutationObserver, shouldThrowError, QueriesObserver, QueryClient as QueryClient$1, replaceEqualDeep, noop, 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';
import { createContext, useContext, onCleanup, createMemo, createStore, createRenderEffect, merge, createEffect, reconcile, createSignal, isPending, refresh, snapshot } from 'solid-js';
import { createComponent } from '@solidjs/web';
// src/useQuery.ts
var QueryClientContext = createContext(void 0);
var QueryClientContext = createContext(null);
var useQueryClient = (queryClient) => {

@@ -20,9 +19,5 @@ if (queryClient) {

var QueryClientProvider = (props) => {
createRenderEffect((unmount) => {
unmount?.();
props.client.mount();
return props.client.unmount.bind(props.client);
});
props.client.mount();
onCleanup(() => props.client.unmount());
return createComponent(QueryClientContext.Provider, {
return createComponent(QueryClientContext, {
value: () => props.client,

@@ -36,11 +31,24 @@ get children() {

var useIsRestoring = () => useContext(IsRestoringContext);
var IsRestoringProvider = IsRestoringContext.Provider;
// src/useBaseQuery.ts
var isServer = typeof window === "undefined";
function _stripFnsForSSR(obj) {
if (!isServer) return obj;
const out = {};
for (const k of Object.keys(obj)) {
if (k === "refetch" || k === "fetchNextPage" || k === "fetchPreviousPage") {
out[k] = void 0;
} else {
out[k] = obj[k];
}
}
return out;
}
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 };
const newData = reconcileOption(store.data, result.data);
return { ...result, data: newData };
}
if (reconcileOption === false) return result;
const key = reconcileOption;
let data = result.data;

@@ -62,4 +70,7 @@ if (store.data === void 0) {

}
const newData = reconcile(data, { key: reconcileOption })(store.data);
return { ...result, data: newData };
if (store.data !== void 0 && data !== void 0) {
reconcile(data, key)(store.data);
return { ...result, data: store.data };
}
return { ...result, data };
}

@@ -69,3 +80,3 @@ var hydratableObserverResult = (query, result) => {

const obj = {
...unwrap(result),
...snapshot(result),
// During SSR, functions cannot be serialized, so we need to remove them

@@ -102,12 +113,18 @@ // This is safe because we will add these functions back when the query is hydrated

});
const initialOptions = defaultedOptions();
const [observer, setObserver] = createSignal(
new Observer(client(), defaultedOptions())
const observer = new Observer(client(), defaultedOptions());
const trackedDefaultedOptions = createMemo(() => defaultedOptions());
createRenderEffect(
() => trackedDefaultedOptions(),
(opts) => {
observer.setOptions(opts);
}
);
let observerResult = observer().getOptimisticResult(defaultedOptions());
const [state, setState] = createStore(observerResult);
let observerResult = observer.getOptimisticResult(defaultedOptions());
const [state, setState] = createStore(
_stripFnsForSSR(observerResult)
);
const createServerSubscriber = (resolve, reject) => {
return observer().subscribe((result) => {
return observer.subscribe((result) => {
notifyManager.batchCalls(() => {
const query = observer().getCurrentQuery();
const query = observer.getCurrentQuery();
const unwrappedResult = hydratableObserverResult(query, result);

@@ -131,8 +148,12 @@ if (result.data !== void 0 && unwrappedResult.isError) {

const createClientSubscriber = () => {
const obs = observer();
return obs.subscribe((result) => {
return observer.subscribe((result) => {
const previousResult = observerResult;
observerResult = result;
setStateWithReconciliation(result);
queueMicrotask(() => {
if (unsubscribe) {
refetch();
if (unsubscribe && !disposed && (previousResult.isLoading !== result.isLoading || previousResult.isError !== result.isError)) {
try {
refresh(queryResource);
} catch {
}
}

@@ -143,8 +164,9 @@ });

function setStateWithReconciliation(res) {
const opts = observer().options;
const opts = observer.options;
const reconcileOptions = opts.reconcile;
const sanitized = _stripFnsForSSR(res);
setState((store) => {
return reconcileFn(
store,
res,
sanitized,
reconcileOptions === void 0 ? false : reconcileOptions,

@@ -155,107 +177,43 @@ 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 disposed = false;
let resolver = null;
const [queryResource, { refetch }] = createResource(
const queryResource = createMemo(
() => {
const obs = observer();
const opts = trackedDefaultedOptions();
const restoring = isRestoring();
return new Promise((resolve, reject) => {
resolver = resolve;
if (isServer) {
unsubscribe = createServerSubscriber(resolve, reject);
} else if (!unsubscribe && !isRestoring()) {
unsubscribe = createServerSubscriber((data) => {
resolve(data);
}, reject);
} else if (!unsubscribe && !restoring) {
unsubscribe = createClientSubscriber();
}
obs.updateResult();
if (observerResult.isError && !observerResult.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [
observerResult.error,
obs.getCurrentQuery()
const currentResult = observer.getOptimisticResult(opts);
observerResult = currentResult;
if (currentResult.isError && !currentResult.isFetching && !restoring && shouldThrowError(opts.throwOnError, [
currentResult.error,
observer.getCurrentQuery()
])) {
setStateWithReconciliation(observerResult);
return reject(observerResult.error);
setStateWithReconciliation(currentResult);
return reject(currentResult.error);
}
if (!observerResult.isLoading) {
if (!currentResult.isLoading) {
resolver = null;
setStateWithReconciliation(currentResult);
return resolve(
hydratableObserverResult(obs.getCurrentQuery(), observerResult)
hydratableObserverResult(observer.getCurrentQuery(), currentResult)
);
}
setStateWithReconciliation(observerResult);
queueMicrotask(() => setStateWithReconciliation(currentResult));
});
},
{
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();
}
}
observerResult,
{ ssrSource: "client" }
);
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) {
disposed = true;
if (isServer && isPending(queryResource)) {
unsubscribeQueued = true;

@@ -273,25 +231,27 @@ return;

});
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;
const errorPassthroughProps = /* @__PURE__ */ new Set([
"error",
"isError",
"failureCount",
"failureReason",
"errorUpdateCount",
"errorUpdatedAt"
]);
return new Proxy(state, {
get(target, prop, receiver) {
if (typeof prop === "symbol") {
return Reflect.get(target, prop, receiver);
}
return Reflect.get(target, prop);
if (errorPassthroughProps.has(prop)) {
return Reflect.get(target, prop, receiver);
}
if (state.isError && !state.isFetching && shouldThrowError(observer.options.throwOnError, [
state.error,
observer.getCurrentQuery()
])) {
throw state.error;
}
return Reflect.get(target, prop, receiver);
}
};
return new Proxy(state, handler);
});
}

@@ -317,2 +277,5 @@

const observer = new MutationObserver(client(), options());
createMemo(() => {
observer.setOptions(options());
});
const mutate = (variables, mutateOptions) => {

@@ -326,23 +289,21 @@ observer.mutate(variables, mutateOptions).catch(noop);

});
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({
setState(() => ({
...result,
mutate,
mutateAsync: result.mutate
});
}));
});
onCleanup(unsubscribe);
createRenderEffect(
() => {
const isError = state.isError;
const error = state.error;
if (isError && shouldThrowError(observer.options.throwOnError, [error])) {
throw error;
}
},
() => {
}
);
return state;

@@ -355,10 +316,7 @@ }

() => queriesOptions().queries.map(
(options) => mergeProps(
client().defaultQueryOptions(options),
{
get _optimisticResults() {
return isRestoring() ? "isRestoring" : "optimistic";
}
(options) => merge(client().defaultQueryOptions(options), {
get _optimisticResults() {
return isRestoring() ? "isRestoring" : "optimistic";
}
)
})
)

@@ -373,69 +331,36 @@ );

);
const [, getCombinedResult] = observer.getOptimisticResult(
defaultedQueries(),
queriesOptions().combine
);
const initialResult = getCombinedResult();
const [state, setState] = createStore(
observer.getOptimisticResult(
defaultedQueries(),
queriesOptions().combine
)[1]()
Array.isArray(initialResult) ? initialResult : [initialResult]
);
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));
let unsubscribe = noop;
createEffect(
() => {
if (!isRestoring()) {
unsubscribe = observer.subscribe((result) => {
setState(
reconcile(
[...result],
// Use a key function that returns undefined so reconcile
// uses positional matching and recursively updates nested properties
() => void 0
)
);
});
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();
}
onCleanup(() => {
unsubscribe();
});
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(() => {
createMemo(() => {
const queries = defaultedQueries();
observer.setQueries(
defaultedQueries(),
queries,
queriesOptions().combine ? {

@@ -445,25 +370,5 @@ combine: queriesOptions().combine

);
return queries;
});
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;
return state;
}

@@ -523,14 +428,12 @@ var QueryClient = class extends QueryClient$1 {

);
createEffect(() => {
const unsubscribe = mutationCache().subscribe(() => {
const unsubscribe = mutationCache().subscribe(() => {
setResult((prev) => {
const nextResult = replaceEqualDeep(
result(),
prev,
getResult(mutationCache(), options())
);
if (result() !== nextResult) {
setResult(nextResult);
}
return prev === nextResult ? prev : nextResult;
});
onCleanup(unsubscribe);
});
onCleanup(unsubscribe);
return result;

@@ -545,2 +448,2 @@ }

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 };
export { IsRestoringContext, 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 };

@@ -5,7 +5,6 @@ 'use strict';

var solidJs = require('solid-js');
var web = require('solid-js/web');
var store = require('solid-js/store');
var web = require('@solidjs/web');
// src/useQuery.ts
exports.QueryClientContext = solidJs.createContext(void 0);
exports.QueryClientContext = solidJs.createContext(null);
exports.useQueryClient = (queryClient) => {

@@ -22,9 +21,5 @@ if (queryClient) {

exports.QueryClientProvider = (props) => {
solidJs.createRenderEffect((unmount) => {
unmount?.();
props.client.mount();
return props.client.unmount.bind(props.client);
});
props.client.mount();
solidJs.onCleanup(() => props.client.unmount());
return web.createComponent(exports.QueryClientContext.Provider, {
return web.createComponent(exports.QueryClientContext, {
value: () => props.client,

@@ -36,15 +31,28 @@ get children() {

};
var IsRestoringContext = solidJs.createContext(() => false);
exports.useIsRestoring = () => solidJs.useContext(IsRestoringContext);
exports.IsRestoringProvider = IsRestoringContext.Provider;
exports.IsRestoringContext = solidJs.createContext(() => false);
exports.useIsRestoring = () => solidJs.useContext(exports.IsRestoringContext);
// src/useBaseQuery.ts
function reconcileFn(store$1, result, reconcileOption, queryHash) {
if (reconcileOption === false) return result;
var isServer = typeof window === "undefined";
function _stripFnsForSSR(obj) {
if (!isServer) return obj;
const out = {};
for (const k of Object.keys(obj)) {
if (k === "refetch" || k === "fetchNextPage" || k === "fetchPreviousPage") {
out[k] = void 0;
} else {
out[k] = obj[k];
}
}
return out;
}
function reconcileFn(store, result, reconcileOption, queryHash) {
if (typeof reconcileOption === "function") {
const newData2 = reconcileOption(store$1.data, result.data);
return { ...result, data: newData2 };
const newData = reconcileOption(store.data, result.data);
return { ...result, data: newData };
}
if (reconcileOption === false) return result;
const key = reconcileOption;
let data = result.data;
if (store$1.data === void 0) {
if (store.data === void 0) {
try {

@@ -55,9 +63,12 @@ data = structuredClone(data);

}
const newData = store.reconcile(data, { key: reconcileOption })(store$1.data);
return { ...result, data: newData };
if (store.data !== void 0 && data !== void 0) {
solidJs.reconcile(data, key)(store.data);
return { ...result, data: store.data };
}
return { ...result, data };
}
var hydratableObserverResult = (query, result) => {
if (!web.isServer) return result;
if (!isServer) return result;
const obj = {
...store.unwrap(result),
...solidJs.snapshot(result),
// During SSR, functions cannot be serialized, so we need to remove them

@@ -87,3 +98,3 @@ // This is safe because we will add these functions back when the query is hydrated

defaultOptions.structuralSharing = false;
if (web.isServer) {
if (isServer) {
defaultOptions.retry = false;

@@ -95,12 +106,18 @@ defaultOptions.throwOnError = true;

});
const initialOptions = defaultedOptions();
const [observer, setObserver] = solidJs.createSignal(
new Observer(client(), defaultedOptions())
const observer = new Observer(client(), defaultedOptions());
const trackedDefaultedOptions = solidJs.createMemo(() => defaultedOptions());
solidJs.createRenderEffect(
() => trackedDefaultedOptions(),
(opts) => {
observer.setOptions(opts);
}
);
let observerResult = observer().getOptimisticResult(defaultedOptions());
const [state, setState] = store.createStore(observerResult);
let observerResult = observer.getOptimisticResult(defaultedOptions());
const [state, setState] = solidJs.createStore(
_stripFnsForSSR(observerResult)
);
const createServerSubscriber = (resolve, reject) => {
return observer().subscribe((result) => {
return observer.subscribe((result) => {
queryCore.notifyManager.batchCalls(() => {
const query = observer().getCurrentQuery();
const query = observer.getCurrentQuery();
const unwrappedResult = hydratableObserverResult(query, result);

@@ -124,8 +141,12 @@ if (result.data !== void 0 && unwrappedResult.isError) {

const createClientSubscriber = () => {
const obs = observer();
return obs.subscribe((result) => {
return observer.subscribe((result) => {
const previousResult = observerResult;
observerResult = result;
setStateWithReconciliation(result);
queueMicrotask(() => {
if (unsubscribe) {
refetch();
if (unsubscribe && !disposed && (previousResult.isLoading !== result.isLoading || previousResult.isError !== result.isError)) {
try {
solidJs.refresh(queryResource);
} catch {
}
}

@@ -136,8 +157,9 @@ });

function setStateWithReconciliation(res) {
const opts = observer().options;
const opts = observer.options;
const reconcileOptions = opts.reconcile;
const sanitized = _stripFnsForSSR(res);
setState((store) => {
return reconcileFn(
store,
res,
sanitized,
reconcileOptions === void 0 ? false : reconcileOptions,

@@ -148,107 +170,43 @@ opts.queryHash

}
function createDeepSignal() {
return [
() => state,
(v) => {
const unwrapped = store.unwrap(state);
if (typeof v === "function") {
v = v(unwrapped);
}
if (v?.hydrationData) {
const { hydrationData, ...rest } = v;
v = rest;
}
setStateWithReconciliation(v);
}
];
}
let unsubscribe = null;
let disposed = false;
let resolver = null;
const [queryResource, { refetch }] = solidJs.createResource(
const queryResource = solidJs.createMemo(
() => {
const obs = observer();
const opts = trackedDefaultedOptions();
const restoring = isRestoring();
return new Promise((resolve, reject) => {
resolver = resolve;
if (web.isServer) {
unsubscribe = createServerSubscriber(resolve, reject);
} else if (!unsubscribe && !isRestoring()) {
if (isServer) {
unsubscribe = createServerSubscriber((data) => {
resolve(data);
}, reject);
} else if (!unsubscribe && !restoring) {
unsubscribe = createClientSubscriber();
}
obs.updateResult();
if (observerResult.isError && !observerResult.isFetching && !isRestoring() && queryCore.shouldThrowError(obs.options.throwOnError, [
observerResult.error,
obs.getCurrentQuery()
const currentResult = observer.getOptimisticResult(opts);
observerResult = currentResult;
if (currentResult.isError && !currentResult.isFetching && !restoring && queryCore.shouldThrowError(opts.throwOnError, [
currentResult.error,
observer.getCurrentQuery()
])) {
setStateWithReconciliation(observerResult);
return reject(observerResult.error);
setStateWithReconciliation(currentResult);
return reject(currentResult.error);
}
if (!observerResult.isLoading) {
if (!currentResult.isLoading) {
resolver = null;
setStateWithReconciliation(currentResult);
return resolve(
hydratableObserverResult(obs.getCurrentQuery(), observerResult)
hydratableObserverResult(observer.getCurrentQuery(), currentResult)
);
}
setStateWithReconciliation(observerResult);
queueMicrotask(() => setStateWithReconciliation(currentResult));
});
},
{
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) {
queryCore.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();
}
}
observerResult,
{ ssrSource: "client" }
);
solidJs.createComputed(
solidJs.on(
client,
(c) => {
if (unsubscribe) {
unsubscribe();
}
const newObserver = new Observer(c, defaultedOptions());
unsubscribe = createClientSubscriber();
setObserver(newObserver);
},
{
defer: true
}
)
);
solidJs.createComputed(
solidJs.on(
isRestoring,
(restoring) => {
if (!restoring && !web.isServer) {
refetch();
}
},
{ defer: true }
)
);
solidJs.onCleanup(() => {
if (web.isServer && queryResource.loading) {
disposed = true;
if (isServer && solidJs.isPending(queryResource)) {
unsubscribeQueued = true;

@@ -261,3 +219,3 @@ return;

}
if (resolver && !web.isServer) {
if (resolver && !isServer) {
resolver(observerResult);

@@ -267,25 +225,27 @@ resolver = null;

});
solidJs.createComputed(
solidJs.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;
const errorPassthroughProps = /* @__PURE__ */ new Set([
"error",
"isError",
"failureCount",
"failureReason",
"errorUpdateCount",
"errorUpdatedAt"
]);
return new Proxy(state, {
get(target, prop, receiver) {
if (typeof prop === "symbol") {
return Reflect.get(target, prop, receiver);
}
return Reflect.get(target, prop);
if (errorPassthroughProps.has(prop)) {
return Reflect.get(target, prop, receiver);
}
if (state.isError && !state.isFetching && queryCore.shouldThrowError(observer.options.throwOnError, [
state.error,
observer.getCurrentQuery()
])) {
throw state.error;
}
return Reflect.get(target, prop, receiver);
}
};
return new Proxy(state, handler);
});
}

@@ -311,6 +271,9 @@

const observer = new queryCore.MutationObserver(client(), options());
solidJs.createMemo(() => {
observer.setOptions(options());
});
const mutate = (variables, mutateOptions) => {
observer.mutate(variables, mutateOptions).catch(queryCore.noop);
};
const [state, setState] = store.createStore({
const [state, setState] = solidJs.createStore({
...observer.getCurrentResult(),

@@ -320,23 +283,21 @@ mutate,

});
solidJs.createComputed(() => {
observer.setOptions(options());
});
solidJs.createComputed(
solidJs.on(
() => state.status,
() => {
if (state.isError && queryCore.shouldThrowError(observer.options.throwOnError, [state.error])) {
throw state.error;
}
}
)
);
const unsubscribe = observer.subscribe((result) => {
setState({
setState(() => ({
...result,
mutate,
mutateAsync: result.mutate
});
}));
});
solidJs.onCleanup(unsubscribe);
solidJs.createRenderEffect(
() => {
const isError = state.isError;
const error = state.error;
if (isError && queryCore.shouldThrowError(observer.options.throwOnError, [error])) {
throw error;
}
},
() => {
}
);
return state;

@@ -349,10 +310,7 @@ }

() => queriesOptions().queries.map(
(options) => solidJs.mergeProps(
client().defaultQueryOptions(options),
{
get _optimisticResults() {
return isRestoring() ? "isRestoring" : "optimistic";
}
(options) => solidJs.merge(client().defaultQueryOptions(options), {
get _optimisticResults() {
return isRestoring() ? "isRestoring" : "optimistic";
}
)
})
)

@@ -367,69 +325,36 @@ );

);
const [state, setState] = store.createStore(
observer.getOptimisticResult(
defaultedQueries(),
queriesOptions().combine
)[1]()
const [, getCombinedResult] = observer.getOptimisticResult(
defaultedQueries(),
queriesOptions().combine
);
solidJs.createRenderEffect(
solidJs.on(
() => queriesOptions().queries.length,
() => setState(
observer.getOptimisticResult(
defaultedQueries(),
queriesOptions().combine
)[1]()
)
)
const initialResult = getCombinedResult();
const [state, setState] = solidJs.createStore(
Array.isArray(initialResult) ? initialResult : [initialResult]
);
const dataResources = solidJs.createMemo(
solidJs.on(
() => state.length,
() => state.map((queryRes) => {
const dataPromise = () => new Promise((resolve) => {
if (queryRes.isFetching && queryRes.isLoading) return;
resolve(store.unwrap(queryRes.data));
let unsubscribe = queryCore.noop;
solidJs.createEffect(
() => {
if (!isRestoring()) {
unsubscribe = observer.subscribe((result) => {
setState(
solidJs.reconcile(
[...result],
// Use a key function that returns undefined so reconcile
// uses positional matching and recursively updates nested properties
() => void 0
)
);
});
return solidJs.createResource(dataPromise);
})
)
}
},
() => {
}
);
solidJs.batch(() => {
const dataResources_ = dataResources();
for (let index = 0; index < dataResources_.length; index++) {
const dataResource = dataResources_[index];
dataResource[1].mutate(() => store.unwrap(state[index].data));
dataResource[1].refetch();
}
solidJs.onCleanup(() => {
unsubscribe();
});
let taskQueue = [];
const subscribeToObserver = () => observer.subscribe((result) => {
taskQueue.push(() => {
solidJs.batch(() => {
const dataResources_ = dataResources();
for (let index = 0; index < dataResources_.length; index++) {
const dataResource = dataResources_[index];
const unwrappedResult = { ...store.unwrap(result[index]) };
setState(index, store.unwrap(unwrappedResult));
dataResource[1].mutate(() => store.unwrap(state[index].data));
dataResource[1].refetch();
}
});
});
queueMicrotask(() => {
const taskToRun = taskQueue.pop();
if (taskToRun) taskToRun();
taskQueue = [];
});
});
let unsubscribe = queryCore.noop;
solidJs.createComputed((cleanup) => {
cleanup?.();
unsubscribe = isRestoring() ? queryCore.noop : subscribeToObserver();
return () => queueMicrotask(unsubscribe);
});
solidJs.onCleanup(unsubscribe);
solidJs.onMount(() => {
solidJs.createMemo(() => {
const queries = defaultedQueries();
observer.setQueries(
defaultedQueries(),
queries,
queriesOptions().combine ? {

@@ -439,25 +364,5 @@ combine: queriesOptions().combine

);
return queries;
});
solidJs.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] = store.createStore(getProxies());
solidJs.createRenderEffect(() => setProxyState(getProxies()));
return proxyState;
return state;
}

@@ -517,14 +422,12 @@ exports.QueryClient = class QueryClient extends queryCore.QueryClient {

);
solidJs.createEffect(() => {
const unsubscribe = mutationCache().subscribe(() => {
const unsubscribe = mutationCache().subscribe(() => {
setResult((prev) => {
const nextResult = queryCore.replaceEqualDeep(
result(),
prev,
getResult(mutationCache(), options())
);
if (result() !== nextResult) {
setResult(nextResult);
}
return prev === nextResult ? prev : nextResult;
});
solidJs.onCleanup(unsubscribe);
});
solidJs.onCleanup(unsubscribe);
return result;

@@ -531,0 +434,0 @@ }

@@ -63,3 +63,3 @@ export { DefinedUseBaseQueryResult } from './_tsup-dts-rollup.cjs';

export { useIsRestoring } from './_tsup-dts-rollup.cjs';
export { IsRestoringProvider } from './_tsup-dts-rollup.cjs';
export { IsRestoringContext } from './_tsup-dts-rollup.cjs';
export { focusManager } from './_tsup-dts-rollup.cjs';

@@ -66,0 +66,0 @@ export { environmentManager } from './_tsup-dts-rollup.cjs';

@@ -63,3 +63,3 @@ export { DefinedUseBaseQueryResult } from './_tsup-dts-rollup.js';

export { useIsRestoring } from './_tsup-dts-rollup.js';
export { IsRestoringProvider } from './_tsup-dts-rollup.js';
export { IsRestoringContext } from './_tsup-dts-rollup.js';
export { focusManager } from './_tsup-dts-rollup.js';

@@ -66,0 +66,0 @@ export { environmentManager } from './_tsup-dts-rollup.js';

@@ -1,9 +0,8 @@

import { MutationObserver, shouldThrowError, QueriesObserver, noop, QueryClient as QueryClient$1, replaceEqualDeep, hydrate, notifyManager, QueryObserver, InfiniteQueryObserver } from '@tanstack/query-core';
import { MutationObserver, shouldThrowError, QueriesObserver, QueryClient as QueryClient$1, replaceEqualDeep, noop, 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';
import { createContext, useContext, onCleanup, createMemo, createStore, createRenderEffect, merge, createEffect, reconcile, createSignal, isPending, refresh, snapshot } from 'solid-js';
import { createComponent } from '@solidjs/web';
// src/useQuery.ts
var QueryClientContext = createContext(void 0);
var QueryClientContext = createContext(null);
var useQueryClient = (queryClient) => {

@@ -20,9 +19,5 @@ if (queryClient) {

var QueryClientProvider = (props) => {
createRenderEffect((unmount) => {
unmount?.();
props.client.mount();
return props.client.unmount.bind(props.client);
});
props.client.mount();
onCleanup(() => props.client.unmount());
return createComponent(QueryClientContext.Provider, {
return createComponent(QueryClientContext, {
value: () => props.client,

@@ -36,11 +31,24 @@ get children() {

var useIsRestoring = () => useContext(IsRestoringContext);
var IsRestoringProvider = IsRestoringContext.Provider;
// src/useBaseQuery.ts
var isServer = typeof window === "undefined";
function _stripFnsForSSR(obj) {
if (!isServer) return obj;
const out = {};
for (const k of Object.keys(obj)) {
if (k === "refetch" || k === "fetchNextPage" || k === "fetchPreviousPage") {
out[k] = void 0;
} else {
out[k] = obj[k];
}
}
return out;
}
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 };
const newData = reconcileOption(store.data, result.data);
return { ...result, data: newData };
}
if (reconcileOption === false) return result;
const key = reconcileOption;
let data = result.data;

@@ -53,4 +61,7 @@ if (store.data === void 0) {

}
const newData = reconcile(data, { key: reconcileOption })(store.data);
return { ...result, data: newData };
if (store.data !== void 0 && data !== void 0) {
reconcile(data, key)(store.data);
return { ...result, data: store.data };
}
return { ...result, data };
}

@@ -60,3 +71,3 @@ var hydratableObserverResult = (query, result) => {

const obj = {
...unwrap(result),
...snapshot(result),
// During SSR, functions cannot be serialized, so we need to remove them

@@ -93,12 +104,18 @@ // This is safe because we will add these functions back when the query is hydrated

});
const initialOptions = defaultedOptions();
const [observer, setObserver] = createSignal(
new Observer(client(), defaultedOptions())
const observer = new Observer(client(), defaultedOptions());
const trackedDefaultedOptions = createMemo(() => defaultedOptions());
createRenderEffect(
() => trackedDefaultedOptions(),
(opts) => {
observer.setOptions(opts);
}
);
let observerResult = observer().getOptimisticResult(defaultedOptions());
const [state, setState] = createStore(observerResult);
let observerResult = observer.getOptimisticResult(defaultedOptions());
const [state, setState] = createStore(
_stripFnsForSSR(observerResult)
);
const createServerSubscriber = (resolve, reject) => {
return observer().subscribe((result) => {
return observer.subscribe((result) => {
notifyManager.batchCalls(() => {
const query = observer().getCurrentQuery();
const query = observer.getCurrentQuery();
const unwrappedResult = hydratableObserverResult(query, result);

@@ -122,8 +139,12 @@ if (result.data !== void 0 && unwrappedResult.isError) {

const createClientSubscriber = () => {
const obs = observer();
return obs.subscribe((result) => {
return observer.subscribe((result) => {
const previousResult = observerResult;
observerResult = result;
setStateWithReconciliation(result);
queueMicrotask(() => {
if (unsubscribe) {
refetch();
if (unsubscribe && !disposed && (previousResult.isLoading !== result.isLoading || previousResult.isError !== result.isError)) {
try {
refresh(queryResource);
} catch {
}
}

@@ -134,8 +155,9 @@ });

function setStateWithReconciliation(res) {
const opts = observer().options;
const opts = observer.options;
const reconcileOptions = opts.reconcile;
const sanitized = _stripFnsForSSR(res);
setState((store) => {
return reconcileFn(
store,
res,
sanitized,
reconcileOptions === void 0 ? false : reconcileOptions,

@@ -146,107 +168,43 @@ 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 disposed = false;
let resolver = null;
const [queryResource, { refetch }] = createResource(
const queryResource = createMemo(
() => {
const obs = observer();
const opts = trackedDefaultedOptions();
const restoring = isRestoring();
return new Promise((resolve, reject) => {
resolver = resolve;
if (isServer) {
unsubscribe = createServerSubscriber(resolve, reject);
} else if (!unsubscribe && !isRestoring()) {
unsubscribe = createServerSubscriber((data) => {
resolve(data);
}, reject);
} else if (!unsubscribe && !restoring) {
unsubscribe = createClientSubscriber();
}
obs.updateResult();
if (observerResult.isError && !observerResult.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [
observerResult.error,
obs.getCurrentQuery()
const currentResult = observer.getOptimisticResult(opts);
observerResult = currentResult;
if (currentResult.isError && !currentResult.isFetching && !restoring && shouldThrowError(opts.throwOnError, [
currentResult.error,
observer.getCurrentQuery()
])) {
setStateWithReconciliation(observerResult);
return reject(observerResult.error);
setStateWithReconciliation(currentResult);
return reject(currentResult.error);
}
if (!observerResult.isLoading) {
if (!currentResult.isLoading) {
resolver = null;
setStateWithReconciliation(currentResult);
return resolve(
hydratableObserverResult(obs.getCurrentQuery(), observerResult)
hydratableObserverResult(observer.getCurrentQuery(), currentResult)
);
}
setStateWithReconciliation(observerResult);
queueMicrotask(() => setStateWithReconciliation(currentResult));
});
},
{
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();
}
}
observerResult,
{ ssrSource: "client" }
);
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) {
disposed = true;
if (isServer && isPending(queryResource)) {
unsubscribeQueued = true;

@@ -264,25 +222,27 @@ return;

});
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;
const errorPassthroughProps = /* @__PURE__ */ new Set([
"error",
"isError",
"failureCount",
"failureReason",
"errorUpdateCount",
"errorUpdatedAt"
]);
return new Proxy(state, {
get(target, prop, receiver) {
if (typeof prop === "symbol") {
return Reflect.get(target, prop, receiver);
}
return Reflect.get(target, prop);
if (errorPassthroughProps.has(prop)) {
return Reflect.get(target, prop, receiver);
}
if (state.isError && !state.isFetching && shouldThrowError(observer.options.throwOnError, [
state.error,
observer.getCurrentQuery()
])) {
throw state.error;
}
return Reflect.get(target, prop, receiver);
}
};
return new Proxy(state, handler);
});
}

@@ -308,2 +268,5 @@

const observer = new MutationObserver(client(), options());
createMemo(() => {
observer.setOptions(options());
});
const mutate = (variables, mutateOptions) => {

@@ -317,23 +280,21 @@ observer.mutate(variables, mutateOptions).catch(noop);

});
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({
setState(() => ({
...result,
mutate,
mutateAsync: result.mutate
});
}));
});
onCleanup(unsubscribe);
createRenderEffect(
() => {
const isError = state.isError;
const error = state.error;
if (isError && shouldThrowError(observer.options.throwOnError, [error])) {
throw error;
}
},
() => {
}
);
return state;

@@ -346,10 +307,7 @@ }

() => queriesOptions().queries.map(
(options) => mergeProps(
client().defaultQueryOptions(options),
{
get _optimisticResults() {
return isRestoring() ? "isRestoring" : "optimistic";
}
(options) => merge(client().defaultQueryOptions(options), {
get _optimisticResults() {
return isRestoring() ? "isRestoring" : "optimistic";
}
)
})
)

@@ -364,69 +322,36 @@ );

);
const [, getCombinedResult] = observer.getOptimisticResult(
defaultedQueries(),
queriesOptions().combine
);
const initialResult = getCombinedResult();
const [state, setState] = createStore(
observer.getOptimisticResult(
defaultedQueries(),
queriesOptions().combine
)[1]()
Array.isArray(initialResult) ? initialResult : [initialResult]
);
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));
let unsubscribe = noop;
createEffect(
() => {
if (!isRestoring()) {
unsubscribe = observer.subscribe((result) => {
setState(
reconcile(
[...result],
// Use a key function that returns undefined so reconcile
// uses positional matching and recursively updates nested properties
() => void 0
)
);
});
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();
}
onCleanup(() => {
unsubscribe();
});
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(() => {
createMemo(() => {
const queries = defaultedQueries();
observer.setQueries(
defaultedQueries(),
queries,
queriesOptions().combine ? {

@@ -436,25 +361,5 @@ combine: queriesOptions().combine

);
return queries;
});
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;
return state;
}

@@ -514,14 +419,12 @@ var QueryClient = class extends QueryClient$1 {

);
createEffect(() => {
const unsubscribe = mutationCache().subscribe(() => {
const unsubscribe = mutationCache().subscribe(() => {
setResult((prev) => {
const nextResult = replaceEqualDeep(
result(),
prev,
getResult(mutationCache(), options())
);
if (result() !== nextResult) {
setResult(nextResult);
}
return prev === nextResult ? prev : nextResult;
});
onCleanup(unsubscribe);
});
onCleanup(unsubscribe);
return result;

@@ -536,2 +439,2 @@ }

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 };
export { IsRestoringContext, 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 };
{
"name": "@tanstack/solid-query",
"version": "5.91.3",
"version": "6.0.0-alpha.0",
"description": "Primitives for managing, caching and syncing asynchronous and remote data in Solid",

@@ -52,11 +52,15 @@ "author": "tannerlinsley",

"devDependencies": {
"@babel/core": "^7.28.0",
"@babel/preset-typescript": "^7.18.6",
"@solidjs/testing-library": "^0.8.10",
"@solidjs/web": "2.0.0-beta.2",
"babel-preset-solid": "2.0.0-beta.2",
"npm-run-all2": "^5.0.0",
"solid-js": "^1.9.7",
"solid-js": "2.0.0-beta.2",
"tsup-preset-solid": "^2.2.0",
"vite-plugin-solid": "^2.11.6",
"vite-plugin-solid": "3.0.0-next.2",
"@tanstack/query-test-utils": "0.0.0"
},
"peerDependencies": {
"solid-js": "^1.6.0"
"solid-js": ">=2.0.0-beta.0 <3.0.0"
},

@@ -63,0 +67,0 @@ "scripts": {

@@ -87,2 +87,2 @@ /* istanbul ignore file */

export const createQueries = useQueries
export { useIsRestoring, IsRestoringProvider } from './isRestoring'
export { useIsRestoring, IsRestoringContext } from './isRestoring'
import { createContext, useContext } from 'solid-js'
import type { Accessor } from 'solid-js'
const IsRestoringContext = createContext<Accessor<boolean>>(() => false)
export const IsRestoringContext = createContext<Accessor<boolean>>(() => false)
export const useIsRestoring = () => useContext(IsRestoringContext)
export const IsRestoringProvider = IsRestoringContext.Provider

@@ -1,13 +0,8 @@

import {
createContext,
createRenderEffect,
onCleanup,
useContext,
} from 'solid-js'
import { createContext, onCleanup, useContext } from 'solid-js'
import type { QueryClient } from './QueryClient'
import type { JSX } from 'solid-js'
export const QueryClientContext = createContext<
(() => QueryClient) | undefined
>(undefined)
export const QueryClientContext = createContext<(() => QueryClient) | null>(
null,
)

@@ -35,14 +30,10 @@ export const useQueryClient = (queryClient?: QueryClient) => {

): JSX.Element => {
createRenderEffect<() => void>((unmount) => {
unmount?.()
props.client.mount()
return props.client.unmount.bind(props.client)
})
props.client.mount()
onCleanup(() => props.client.unmount())
return (
<QueryClientContext.Provider value={() => props.client}>
<QueryClientContext value={() => props.client}>
{props.children}
</QueryClientContext.Provider>
</QueryClientContext>
)
}
// Had to disable the lint rule because isServer type is defined as false
// in solid-js/web package. I'll create a GitHub issue with them to see
// why that happens.
import { hydrate, notifyManager, shouldThrowError } from '@tanstack/query-core'
import { isServer } from 'solid-js/web'
import { notifyManager, shouldThrowError } from '@tanstack/query-core'
import {
createComputed,
createMemo,
createResource,
createSignal,
on,
createRenderEffect,
createStore,
isPending,
onCleanup,
reconcile,
refresh,
snapshot,
} from 'solid-js'
import { createStore, reconcile, unwrap } from 'solid-js/store'
import { useQueryClient } from './QueryClientProvider'
import { useIsRestoring } from './isRestoring'
import type { UseBaseQueryOptions } from './types'
import type { Accessor, Signal } from 'solid-js'
import type { Accessor } from 'solid-js'
import type { QueryClient } from './QueryClient'

@@ -27,2 +27,25 @@ import type {

const isServer = typeof window === 'undefined'
/**
* During SSR, Solid's store is serialized by seroval which cannot handle
* functions. Strip `refetch`, `fetchNextPage`, and `fetchPreviousPage`
* from the observer result before it enters the store so serialization
* succeeds. On the client this is a no-op (returns the object as-is).
*/
function _stripFnsForSSR<TData, TError>(
obj: QueryObserverResult<TData, TError>,
): QueryObserverResult<TData, TError> {
if (!isServer) return obj
const out: Record<string, unknown> = {}
for (const k of Object.keys(obj)) {
if (k === 'refetch' || k === 'fetchNextPage' || k === 'fetchPreviousPage') {
out[k] = undefined
} else {
out[k] = (obj as any)[k]
}
}
return out as unknown as QueryObserverResult<TData, TError>
}
function reconcileFn<TData, TError>(

@@ -37,3 +60,2 @@ store: QueryObserverResult<TData, TError>,

): QueryObserverResult<TData, TError> {
if (reconcileOption === false) return result
if (typeof reconcileOption === 'function') {

@@ -43,2 +65,7 @@ const newData = reconcileOption(store.data, result.data as TData)

}
if (reconcileOption === false) return result
const key = reconcileOption
let data = result.data

@@ -61,4 +88,12 @@ if (store.data === undefined) {

}
const newData = reconcile(data, { key: reconcileOption })(store.data)
return { ...result, data: newData } as typeof result
// reconcile() in Solid 2.0 mutates in place and returns void.
// We apply it to store.data so the store's nested signals update.
// On first load (store.data is undefined), there's nothing to reconcile against,
// so we just return the data as-is.
if (store.data !== undefined && data !== undefined) {
reconcile(data, key)(store.data)
// Return result with the existing store.data reference (now reconciled in place)
return { ...result, data: store.data } as typeof result
}
return { ...result, data } as typeof result
}

@@ -82,3 +117,3 @@

const obj: any = {
...unwrap(result),
...snapshot(result),
// During SSR, functions cannot be serialized, so we need to remove them

@@ -146,11 +181,22 @@ // This is safe because we will add these functions back when the query is hydrated

})
const initialOptions = defaultedOptions()
const [observer, setObserver] = createSignal(
new Observer(client(), defaultedOptions()),
const observer = new Observer(client(), defaultedOptions())
// Track options reactively so the queryResource memo re-runs on change.
const trackedDefaultedOptions = createMemo(() => defaultedOptions())
// Apply options in an effect to avoid store writes inside the memo.
// setOptions triggers updateResult → notify → subscription → setState,
// which must run in an effect context in Solid v2.
createRenderEffect(
() => trackedDefaultedOptions(),
(opts) => {
observer.setOptions(opts)
},
)
let observerResult = observer().getOptimisticResult(defaultedOptions())
const [state, setState] =
createStore<QueryObserverResult<TData, TError>>(observerResult)
let observerResult = observer.getOptimisticResult(defaultedOptions())
const [state, setState] = createStore<QueryObserverResult<TData, TError>>(
_stripFnsForSSR(observerResult),
)

@@ -163,5 +209,5 @@ const createServerSubscriber = (

) => {
return observer().subscribe((result) => {
return observer.subscribe((result) => {
notifyManager.batchCalls(() => {
const query = observer().getCurrentQuery()
const query = observer.getCurrentQuery()
const unwrappedResult = hydratableObserverResult(query, result)

@@ -188,8 +234,20 @@

const createClientSubscriber = () => {
const obs = observer()
return obs.subscribe((result) => {
return observer.subscribe((result) => {
const previousResult = observerResult
observerResult = result
setStateWithReconciliation(result)
queueMicrotask(() => {
if (unsubscribe) {
refetch()
if (
unsubscribe &&
!disposed &&
(previousResult.isLoading !== result.isLoading ||
previousResult.isError !== result.isError)
) {
try {
refresh(queryResource)
} catch {
// NotReadyError is expected when refreshing a memo that returns
// a Promise. The Loading boundary handles this during rendering,
// but when refresh is called from a microtask there is no boundary.
}
}

@@ -201,5 +259,5 @@ })

function setStateWithReconciliation(res: typeof observerResult) {
const opts = observer().options
// @ts-expect-error - Reconcile option is not correctly typed internally
const reconcileOptions = opts.reconcile
const opts = observer.options
const reconcileOptions = (opts as any).reconcile
const sanitized = _stripFnsForSSR(res)

@@ -209,3 +267,3 @@ setState((store) => {

store,
res,
sanitized,
reconcileOptions === undefined ? false : reconcileOptions,

@@ -217,21 +275,2 @@ opts.queryHash,

function createDeepSignal<T>(): Signal<T> {
return [
() => state,
(v: any) => {
const unwrapped = unwrap(state)
if (typeof v === 'function') {
v = v(unwrapped)
}
// Hydration data exists on first load after SSR,
// and should be removed from the observer result
if (v?.hydrationData) {
const { hydrationData, ...rest } = v
v = rest
}
setStateWithReconciliation(v)
},
] as Signal<T>
}
/**

@@ -241,2 +280,3 @@ * Unsubscribe is set lazily, so that we can subscribe after hydration when needed.

let unsubscribe: (() => void) | null = null
let disposed = false

@@ -251,111 +291,54 @@ /*

let resolver: ((value: ResourceData) => void) | null = null
const [queryResource, { refetch }] = createResource<ResourceData | undefined>(
const queryResource = createMemo<ResourceData>(
() => {
const obs = observer()
// Read trackedDefaultedOptions to ensure this memo re-runs when options change
const opts = trackedDefaultedOptions()
// Read isRestoring unconditionally so the memo re-runs when it changes
const restoring = isRestoring()
return new Promise((resolve, reject) => {
resolver = resolve
if (isServer) {
unsubscribe = createServerSubscriber(resolve, reject)
} else if (!unsubscribe && !isRestoring()) {
unsubscribe = createServerSubscriber((data) => {
resolve(data as ResourceData)
}, reject)
} else if (!unsubscribe && !restoring) {
unsubscribe = createClientSubscriber()
}
obs.updateResult()
// Use getOptimisticResult instead of updateResult to keep the memo
// free of store writes (updateResult triggers notify → setState).
const currentResult = observer.getOptimisticResult(opts)
observerResult = currentResult
if (
observerResult.isError &&
!observerResult.isFetching &&
!isRestoring() &&
shouldThrowError(obs.options.throwOnError, [
observerResult.error,
obs.getCurrentQuery(),
currentResult.isError &&
!currentResult.isFetching &&
!restoring &&
shouldThrowError(opts.throwOnError, [
currentResult.error,
observer.getCurrentQuery(),
])
) {
setStateWithReconciliation(observerResult)
return reject(observerResult.error)
setStateWithReconciliation(currentResult)
return reject(currentResult.error)
}
if (!observerResult.isLoading) {
if (!currentResult.isLoading) {
resolver = null
setStateWithReconciliation(currentResult)
return resolve(
hydratableObserverResult(obs.getCurrentQuery(), observerResult),
hydratableObserverResult(observer.getCurrentQuery(), currentResult),
)
}
setStateWithReconciliation(observerResult)
// Defer the loading-state store write so it runs outside the memo.
queueMicrotask(() => setStateWithReconciliation(currentResult))
})
},
{
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
/**
* Do not refetch query on mount if query was fetched on server,
* even if `staleTime` is not set.
*/
const newOptions = { ...initialOptions }
if (
(initialOptions.staleTime || !initialOptions.initialData) &&
info.value
) {
newOptions.refetchOnMount = false
}
// Setting the options as an immutable object to prevent
// wonky behavior with observer subscriptions
observer().setOptions(newOptions)
setStateWithReconciliation(observer().getOptimisticResult(newOptions))
unsubscribe = createClientSubscriber()
},
},
observerResult,
{ ssrSource: 'client' },
)
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) {
disposed = true
if (isServer && isPending(queryResource)) {
unsubscribeQueued = true

@@ -374,30 +357,41 @@ return

createComputed(
on(
[observer, defaultedOptions],
([obs, opts]) => {
obs.setOptions(opts)
setStateWithReconciliation(obs.getOptimisticResult(opts))
refetch()
},
{ defer: true },
),
)
// Properties that should never throw — these let users access error info
// even outside an ErrorBoundary.
const errorPassthroughProps = new Set([
'error',
'isError',
'failureCount',
'failureReason',
'errorUpdateCount',
'errorUpdatedAt',
])
const handler = {
get(
target: QueryObserverResult<TData, TError>,
prop: keyof QueryObserverResult<TData, TError>,
): any {
if (prop === 'data') {
if (state.data !== undefined) {
return queryResource.latest?.data
}
return queryResource()?.data
// Return a proxy that throws on property access when throwOnError is enabled
return new Proxy(state, {
get(target, prop, receiver) {
// Always pass through symbols (needed for store internals, iteration, etc.)
if (typeof prop === 'symbol') {
return Reflect.get(target, prop, receiver)
}
return Reflect.get(target, prop)
// Always pass through error-related props without throwing
if (errorPassthroughProps.has(prop)) {
return Reflect.get(target, prop, receiver)
}
// Check throwOnError condition before returning the value
if (
state.isError &&
!state.isFetching &&
shouldThrowError(observer.options.throwOnError, [
state.error,
observer.getCurrentQuery(),
])
) {
throw state.error
}
return Reflect.get(target, prop, receiver)
},
}
return new Proxy(state, handler)
})
}
import { MutationObserver, noop, shouldThrowError } from '@tanstack/query-core'
import { createComputed, createMemo, on, onCleanup } from 'solid-js'
import { createStore } from 'solid-js/store'
import {
createMemo,
createRenderEffect,
createStore,
onCleanup,
} from 'solid-js'
import { useQueryClient } from './QueryClientProvider'

@@ -33,2 +37,7 @@ import type { DefaultError } from '@tanstack/query-core'

// Track options changes and update observer
createMemo(() => {
observer.setOptions(options())
})
const mutate: UseMutateFunction<

@@ -51,26 +60,8 @@ TData,

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({
setState(() => ({
...result,
mutate,
mutateAsync: result.mutate,
})
}))
})

@@ -80,3 +71,22 @@

// Use createRenderEffect to throw errors when throwOnError is set.
// The throw must happen in the compute function (first arg), not the effect
// function, so that the error goes through notifyStatus and gets wrapped as
// a StatusError with a source — which is required for <Errored> boundaries
// to capture it via CollectionQueue.notify.
createRenderEffect(
() => {
const isError = state.isError
const error = state.error
if (
isError &&
shouldThrowError(observer.options.throwOnError, [error as TError])
) {
throw error
}
},
() => {},
)
return state
}

@@ -1,2 +0,2 @@

import { createEffect, createMemo, createSignal, onCleanup } from 'solid-js'
import { createMemo, createSignal, onCleanup } from 'solid-js'
import { replaceEqualDeep } from '@tanstack/query-core'

@@ -41,17 +41,15 @@ import { useQueryClient } from './QueryClientProvider'

createEffect(() => {
const unsubscribe = mutationCache().subscribe(() => {
const unsubscribe = mutationCache().subscribe(() => {
setResult((prev) => {
const nextResult = replaceEqualDeep(
result(),
prev,
getResult(mutationCache(), options()),
)
if (result() !== nextResult) {
setResult(nextResult)
}
return prev === nextResult ? prev : nextResult
})
onCleanup(unsubscribe)
})
onCleanup(unsubscribe)
return result
}
import { QueriesObserver, noop } from '@tanstack/query-core'
import { createStore, unwrap } from 'solid-js/store'
import {
batch,
createComputed,
createEffect,
createMemo,
createRenderEffect,
createResource,
mergeProps,
on,
createStore,
merge,
onCleanup,
onMount,
reconcile,
} from 'solid-js'

@@ -125,3 +121,3 @@ import { useQueryClient } from './QueryClientProvider'

/**
* QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
* QueriesOptions reducer recursively snapshots function arguments to infer/enforce type param
*/

@@ -205,14 +201,11 @@ type QueriesOptions<

queriesOptions().queries.map((options) =>
mergeProps(
client().defaultQueryOptions(options as QueryObserverOptions),
{
get _optimisticResults() {
return isRestoring() ? 'isRestoring' : 'optimistic'
},
merge(client().defaultQueryOptions(options as QueryObserverOptions), {
get _optimisticResults() {
return isRestoring() ? 'isRestoring' : 'optimistic'
},
),
}),
),
)
const observer = new QueriesObserver(
const observer = new QueriesObserver<TCombinedResult>(
client(),

@@ -227,83 +220,48 @@ defaultedQueries(),

const [state, setState] = createStore<TCombinedResult>(
observer.getOptimisticResult(
defaultedQueries(),
(queriesOptions() as QueriesObserverOptions<TCombinedResult>).combine,
)[1](),
// Get initial optimistic result
const [, getCombinedResult] = observer.getOptimisticResult(
defaultedQueries(),
(queriesOptions() as QueriesObserverOptions<TCombinedResult>).combine,
)
createRenderEffect(
on(
() => queriesOptions().queries.length,
() =>
setState(
observer.getOptimisticResult(
defaultedQueries(),
(queriesOptions() as QueriesObserverOptions<TCombinedResult>)
.combine,
)[1](),
),
),
)
const initialResult = getCombinedResult()
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)
}),
),
// Store the combined result in a reactive store
const [state, setState] = createStore<Array<QueryObserverResult>>(
(Array.isArray(initialResult)
? initialResult
: [initialResult]) as Array<QueryObserverResult>,
)
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: Array<() => void> = []
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]) }
// @ts-expect-error typescript pedantry regarding the possible range of index
setState(index, unwrap(unwrappedResult))
dataResource[1].mutate(() => unwrap(state[index]!.data))
dataResource[1].refetch()
}
// Subscribe to the observer for updates reactively.
// When isRestoring is true (persist client is restoring), we defer
// subscription until restoring completes.
let unsubscribe: () => void = noop
createEffect(
() => {
if (!isRestoring()) {
unsubscribe = observer.subscribe((result) => {
setState(
reconcile(
[...result] as Array<QueryObserverResult>,
// Use a key function that returns undefined so reconcile
// uses positional matching and recursively updates nested properties
() => undefined,
),
)
})
})
}
},
() => {},
)
queueMicrotask(() => {
const taskToRun = taskQueue.pop()
if (taskToRun) taskToRun()
taskQueue = []
})
})
let unsubscribe: () => void = noop
createComputed<() => void>((cleanup) => {
cleanup?.()
unsubscribe = isRestoring() ? noop : subscribeToObserver()
// cleanup needs to be scheduled after synchronous effects take place
return () => queueMicrotask(unsubscribe)
onCleanup(() => {
unsubscribe()
})
onCleanup(unsubscribe)
onMount(() => {
// Update observer queries when options change reactively
const trackedDefaultedQueries = createMemo(() => {
const queries = defaultedQueries()
observer.setQueries(
defaultedQueries(),
queries,
queriesOptions().combine

@@ -315,33 +273,9 @@ ? ({

)
return queries
})
createComputed(() => {
observer.setQueries(
defaultedQueries(),
queriesOptions().combine
? ({
combine: queriesOptions().combine,
} as QueriesObserverOptions<TCombinedResult>)
: undefined,
)
})
// Force read of trackedDefaultedQueries to ensure it runs
void trackedDefaultedQueries
const handler = (index: number) => ({
get(target: QueryObserverResult, prop: keyof QueryObserverResult): any {
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 as TCombinedResult
return state as unknown as TCombinedResult
}