FRE-600: Fix code review blockers

- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

84
node_modules/@tanstack/solid-query/src/QueryClient.ts generated vendored Normal file
View File

@@ -0,0 +1,84 @@
import { QueryClient as QueryCoreClient } from '@tanstack/query-core'
import type {
DefaultOptions as CoreDefaultOptions,
DefaultError,
OmitKeyof,
QueryClientConfig as QueryCoreClientConfig,
InfiniteQueryObserverOptions as QueryCoreInfiniteQueryObserverOptions,
QueryObserverOptions as QueryCoreObserverOptions,
QueryKey,
} from '@tanstack/query-core'
export interface QueryObserverOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
TPageParam = never,
> extends OmitKeyof<
QueryCoreObserverOptions<
TQueryFnData,
TError,
TData,
TQueryData,
TQueryKey,
TPageParam
>,
'structuralSharing'
> {
/**
* Set this to a reconciliation key to enable reconciliation between query results.
* Set this to `false` to disable reconciliation between query results.
* Set this to a function which accepts the old and new data and returns resolved data of the same type to implement custom reconciliation logic.
* Defaults reconciliation to false.
*/
reconcile?:
| string
| false
| ((oldData: TData | undefined, newData: TData) => TData)
}
export interface InfiniteQueryObserverOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
> extends OmitKeyof<
QueryCoreInfiniteQueryObserverOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
>,
'structuralSharing'
> {
/**
* Set this to a reconciliation key to enable reconciliation between query results.
* Set this to `false` to disable reconciliation between query results.
* Set this to a function which accepts the old and new data and returns resolved data of the same type to implement custom reconciliation logic.
* Defaults reconciliation to false.
*/
reconcile?:
| string
| false
| ((oldData: TData | undefined, newData: TData) => TData)
}
export interface DefaultOptions<
TError = DefaultError,
> extends CoreDefaultOptions<TError> {
queries?: OmitKeyof<QueryObserverOptions<unknown, TError>, 'queryKey'>
}
export interface QueryClientConfig extends QueryCoreClientConfig {
defaultOptions?: DefaultOptions
}
export class QueryClient extends QueryCoreClient {
constructor(config: QueryClientConfig = {}) {
super(config)
}
}

View File

@@ -0,0 +1,47 @@
import {
createContext,
createRenderEffect,
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 useQueryClient = (queryClient?: QueryClient) => {
if (queryClient) {
return queryClient
}
const client = useContext(QueryClientContext)
if (!client) {
throw new Error('No QueryClient set, use QueryClientProvider to set one')
}
return client()
}
export type QueryClientProviderProps = {
client: QueryClient
children?: JSX.Element
}
export const QueryClientProvider = (
props: QueryClientProviderProps,
): JSX.Element => {
createRenderEffect<() => void>((unmount) => {
unmount?.()
props.client.mount()
return props.client.unmount.bind(props.client)
})
onCleanup(() => props.client.unmount())
return (
<QueryClientContext.Provider value={() => props.client}>
{props.children}
</QueryClientContext.Provider>
)
}

87
node_modules/@tanstack/solid-query/src/index.ts generated vendored Normal file
View File

@@ -0,0 +1,87 @@
/* istanbul ignore file */
import { useQuery } from './useQuery'
import { useInfiniteQuery } from './useInfiniteQuery'
import { useMutation } from './useMutation'
import { useQueries } from './useQueries'
// Re-export core
export * from '@tanstack/query-core'
// Solid Query
export * from './types'
export type {
DefinedUseBaseQueryResult,
DefinedUseInfiniteQueryResult,
DefinedUseQueryResult,
SolidInfiniteQueryOptions,
SolidMutationOptions,
SolidQueryOptions,
UseBaseMutationResult,
UseBaseQueryOptions,
UseBaseQueryResult,
UseInfiniteQueryOptions,
UseInfiniteQueryResult,
UseMutateAsyncFunction,
UseMutateFunction,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
// Aliases (create* and use* are both supported)
UseBaseQueryOptions as CreateBaseQueryOptions,
UseBaseQueryResult as CreateBaseQueryResult,
UseInfiniteQueryOptions as CreateInfiniteQueryOptions,
UseInfiniteQueryResult as CreateInfiniteQueryResult,
UseMutateAsyncFunction as CreateMutateAsyncFunction,
UseMutateFunction as CreateMutateFunction,
UseMutationOptions as CreateMutationOptions,
UseMutationResult as CreateMutationResult,
UseBaseMutationResult as CreateBaseMutationResult,
UseQueryOptions as CreateQueryOptions,
UseQueryResult as CreateQueryResult,
DefinedUseBaseQueryResult as DefinedCreateBaseQueryResult,
DefinedUseInfiniteQueryResult as DefinedCreateInfiniteQueryResult,
DefinedUseQueryResult as DefinedCreateQueryResult,
} from './types'
export { QueryClient } from './QueryClient'
export type {
QueryObserverOptions,
DefaultOptions,
QueryClientConfig,
InfiniteQueryObserverOptions,
} from './QueryClient'
export { useQuery } from './useQuery'
export const createQuery = useQuery
export { queryOptions } from './queryOptions'
export type {
DefinedInitialDataOptions,
UndefinedInitialDataOptions,
} from './queryOptions'
export {
QueryClientContext,
QueryClientProvider,
useQueryClient,
} from './QueryClientProvider'
export type { QueryClientProviderProps } from './QueryClientProvider'
export { useIsFetching } from './useIsFetching'
export { useIsFetching as createIsFetching } from './useIsFetching'
export { useInfiniteQuery }
export const createInfiniteQuery = useInfiniteQuery
export { infiniteQueryOptions } from './infiniteQueryOptions'
export type {
DefinedInitialDataInfiniteOptions,
UndefinedInitialDataInfiniteOptions,
} from './infiniteQueryOptions'
export { useMutation } from './useMutation'
export { mutationOptions } from './mutationOptions'
export const createMutation = useMutation
export { useIsMutating } from './useIsMutating'
export { useIsMutating as createIsMutating } from './useIsMutating'
export { useMutationState } from './useMutationState'
export { useMutationState as createMutationState } from './useMutationState'
export { useQueries } from './useQueries'
export const createQueries = useQueries
export { useIsRestoring, IsRestoringProvider } from './isRestoring'

View File

@@ -0,0 +1,106 @@
import type {
DataTag,
DefaultError,
InfiniteData,
NonUndefinedGuard,
QueryKey,
} from '@tanstack/query-core'
import type { SolidInfiniteQueryOptions } from './types'
import type { Accessor } from 'solid-js'
export type UndefinedInitialDataInfiniteOptions<
TQueryFnData,
TError = DefaultError,
TData = InfiniteData<TQueryFnData>,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
> = Accessor<
SolidInfiniteQueryOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
> & {
initialData?: undefined
}
>
export type DefinedInitialDataInfiniteOptions<
TQueryFnData,
TError = DefaultError,
// should we handle page param correctly
TData = InfiniteData<TQueryFnData>,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
> = Accessor<
SolidInfiniteQueryOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
> & {
initialData:
| NonUndefinedGuard<InfiniteData<TQueryFnData, TPageParam>>
| (() => NonUndefinedGuard<InfiniteData<TQueryFnData, TPageParam>>)
}
>
export function infiniteQueryOptions<
TQueryFnData,
TError = DefaultError,
TData = InfiniteData<TQueryFnData>,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
>(
options: ReturnType<
DefinedInitialDataInfiniteOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
>
>,
): ReturnType<
DefinedInitialDataInfiniteOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
>
> & {
queryKey: DataTag<TQueryKey, InfiniteData<TQueryFnData>>
}
export function infiniteQueryOptions<
TQueryFnData,
TError = DefaultError,
TData = InfiniteData<TQueryFnData>,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
>(
options: ReturnType<
UndefinedInitialDataInfiniteOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
>
>,
): ReturnType<
UndefinedInitialDataInfiniteOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
>
> & {
queryKey: DataTag<TQueryKey, InfiniteData<TQueryFnData>>
}
export function infiniteQueryOptions(options: unknown) {
return options
}

View File

@@ -0,0 +1,7 @@
import { createContext, useContext } from 'solid-js'
import type { Accessor } from 'solid-js'
const IsRestoringContext = createContext<Accessor<boolean>>(() => false)
export const useIsRestoring = () => useContext(IsRestoringContext)
export const IsRestoringProvider = IsRestoringContext.Provider

View File

@@ -0,0 +1,41 @@
import type { DefaultError, WithRequired } from '@tanstack/query-core'
import type { SolidMutationOptions } from './types'
export function mutationOptions<
TData = unknown,
TError = DefaultError,
TVariables = void,
TOnMutateResult = unknown,
>(
options: WithRequired<
SolidMutationOptions<TData, TError, TVariables, TOnMutateResult>,
'mutationKey'
>,
): WithRequired<
SolidMutationOptions<TData, TError, TVariables, TOnMutateResult>,
'mutationKey'
>
export function mutationOptions<
TData = unknown,
TError = DefaultError,
TVariables = void,
TOnMutateResult = unknown,
>(
options: Omit<
SolidMutationOptions<TData, TError, TVariables, TOnMutateResult>,
'mutationKey'
>,
): Omit<
SolidMutationOptions<TData, TError, TVariables, TOnMutateResult>,
'mutationKey'
>
export function mutationOptions<
TData = unknown,
TError = DefaultError,
TVariables = void,
TOnMutateResult = unknown,
>(
options: SolidMutationOptions<TData, TError, TVariables, TOnMutateResult>,
): SolidMutationOptions<TData, TError, TVariables, TOnMutateResult> {
return options
}

59
node_modules/@tanstack/solid-query/src/queryOptions.ts generated vendored Normal file
View File

@@ -0,0 +1,59 @@
import type { DataTag, DefaultError, QueryKey } from '@tanstack/query-core'
import type { SolidQueryOptions } from './types'
import type { Accessor } from 'solid-js'
export type UndefinedInitialDataOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> = Accessor<
SolidQueryOptions<TQueryFnData, TError, TData, TQueryKey> & {
initialData?: undefined
}
>
export type DefinedInitialDataOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> = Accessor<
SolidQueryOptions<TQueryFnData, TError, TData, TQueryKey> & {
initialData: TQueryFnData | (() => TQueryFnData)
}
>
export function queryOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
>(
options: ReturnType<
UndefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>
>,
): ReturnType<
UndefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>
> & {
queryKey: DataTag<TQueryKey, TQueryFnData, TError>
}
export function queryOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
>(
options: ReturnType<
DefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>
>,
): ReturnType<
DefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>
> & {
queryKey: DataTag<TQueryKey, TQueryFnData, TError>
}
export function queryOptions(options: unknown) {
return options
}

200
node_modules/@tanstack/solid-query/src/types.ts generated vendored Normal file
View File

@@ -0,0 +1,200 @@
/* istanbul ignore file */
import type {
DefaultError,
DefinedInfiniteQueryObserverResult,
DefinedQueryObserverResult,
InfiniteQueryObserverResult,
MutateFunction,
MutationObserverOptions,
MutationObserverResult,
OmitKeyof,
Override,
QueryKey,
QueryObserverResult,
} from '@tanstack/query-core'
import type {
InfiniteQueryObserverOptions,
QueryObserverOptions,
} from './QueryClient'
import type { Accessor } from 'solid-js'
export interface UseBaseQueryOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> extends OmitKeyof<
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>,
'suspense'
> {
/**
* Only applicable while rendering queries on the server with streaming.
* Set `deferStream` to `true` to wait for the query to resolve on the server before flushing the stream.
* This can be useful to avoid sending a loading state to the client before the query has resolved.
* Defaults to `false`.
*/
deferStream?: boolean
/**
* @deprecated The `suspense` option has been deprecated in v5 and will be removed in the next major version.
* The `data` property on useQuery is a SolidJS resource and will automatically suspend when the data is loading.
* Setting `suspense` to `false` will be a no-op.
*/
suspense?: boolean
}
export interface SolidQueryOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> extends UseBaseQueryOptions<
TQueryFnData,
TError,
TData,
TQueryFnData,
TQueryKey
> {}
export type UseQueryOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> = Accessor<SolidQueryOptions<TQueryFnData, TError, TData, TQueryKey>>
/* --- Create Query and Create Base Query Types --- */
export type UseBaseQueryResult<
TData = unknown,
TError = DefaultError,
> = QueryObserverResult<TData, TError>
export type UseQueryResult<
TData = unknown,
TError = DefaultError,
> = UseBaseQueryResult<TData, TError>
export type DefinedUseBaseQueryResult<
TData = unknown,
TError = DefaultError,
> = DefinedQueryObserverResult<TData, TError>
export type DefinedUseQueryResult<
TData = unknown,
TError = DefaultError,
> = DefinedUseBaseQueryResult<TData, TError>
/* --- Create Infinite Queries Types --- */
export interface SolidInfiniteQueryOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
> extends OmitKeyof<
InfiniteQueryObserverOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
>,
'queryKey' | 'suspense'
> {
queryKey: TQueryKey
/**
* Only applicable while rendering queries on the server with streaming.
* Set `deferStream` to `true` to wait for the query to resolve on the server before flushing the stream.
* This can be useful to avoid sending a loading state to the client before the query has resolved.
* Defaults to `false`.
*/
deferStream?: boolean
/**
* @deprecated The `suspense` option has been deprecated in v5 and will be removed in the next major version.
* The `data` property on useInfiniteQuery is a SolidJS resource and will automatically suspend when the data is loading.
* Setting `suspense` to `false` will be a no-op.
*/
suspense?: boolean
}
export type UseInfiniteQueryOptions<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
> = Accessor<
SolidInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>
>
export type UseInfiniteQueryResult<
TData = unknown,
TError = DefaultError,
> = InfiniteQueryObserverResult<TData, TError>
export type DefinedUseInfiniteQueryResult<
TData = unknown,
TError = DefaultError,
> = DefinedInfiniteQueryObserverResult<TData, TError>
/* --- Create Mutation Types --- */
export interface SolidMutationOptions<
TData = unknown,
TError = DefaultError,
TVariables = void,
TOnMutateResult = unknown,
> extends OmitKeyof<
MutationObserverOptions<TData, TError, TVariables, TOnMutateResult>,
'_defaulted'
> {}
export type UseMutationOptions<
TData = unknown,
TError = DefaultError,
TVariables = void,
TOnMutateResult = unknown,
> = Accessor<SolidMutationOptions<TData, TError, TVariables, TOnMutateResult>>
export type UseMutateFunction<
TData = unknown,
TError = DefaultError,
TVariables = void,
TOnMutateResult = unknown,
> = (
...args: Parameters<
MutateFunction<TData, TError, TVariables, TOnMutateResult>
>
) => void
export type UseMutateAsyncFunction<
TData = unknown,
TError = DefaultError,
TVariables = void,
TOnMutateResult = unknown,
> = MutateFunction<TData, TError, TVariables, TOnMutateResult>
export type UseBaseMutationResult<
TData = unknown,
TError = DefaultError,
TVariables = unknown,
TOnMutateResult = unknown,
> = Override<
MutationObserverResult<TData, TError, TVariables, TOnMutateResult>,
{ mutate: UseMutateFunction<TData, TError, TVariables, TOnMutateResult> }
> & {
mutateAsync: UseMutateAsyncFunction<
TData,
TError,
TVariables,
TOnMutateResult
>
}
export type UseMutationResult<
TData = unknown,
TError = DefaultError,
TVariables = unknown,
TOnMutateResult = unknown,
> = UseBaseMutationResult<TData, TError, TVariables, TOnMutateResult>

389
node_modules/@tanstack/solid-query/src/useBaseQuery.ts generated vendored Normal file
View File

@@ -0,0 +1,389 @@
// 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 {
createComputed,
createMemo,
createResource,
createSignal,
on,
onCleanup,
} 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 { QueryClient } from './QueryClient'
import type {
Query,
QueryKey,
QueryObserver,
QueryObserverResult,
} from '@tanstack/query-core'
function reconcileFn<TData, TError>(
store: QueryObserverResult<TData, TError>,
result: QueryObserverResult<TData, TError>,
reconcileOption:
| string
| false
| ((oldData: TData | undefined, newData: TData) => TData),
queryHash?: string,
): QueryObserverResult<TData, TError> {
if (reconcileOption === false) return result
if (typeof reconcileOption === 'function') {
const newData = reconcileOption(store.data, result.data as TData)
return { ...result, data: newData } as typeof result
}
let data = result.data
if (store.data === undefined) {
try {
data = structuredClone(data)
} catch (error) {
if (process.env.NODE_ENV !== 'production') {
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.\n\n Error Received: ${error.name} - ${error.message}`,
)
}
}
}
}
const newData = reconcile(data, { key: reconcileOption })(store.data)
return { ...result, data: newData } as typeof result
}
/**
* Solid's `onHydrated` functionality will silently "fail" (hydrate with an empty object)
* if the resource data is not serializable.
*/
const hydratableObserverResult = <
TQueryFnData,
TError,
TData,
TQueryKey extends QueryKey,
TDataHydratable,
>(
query: Query<TQueryFnData, TError, TData, TQueryKey>,
result: QueryObserverResult<TDataHydratable, TError>,
) => {
if (!isServer) return result
const obj: any = {
...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: undefined,
}
// If the query is an infinite query, we need to remove additional properties
if ('fetchNextPage' in result) {
obj.fetchNextPage = undefined
obj.fetchPreviousPage = undefined
}
// We will also attach the dehydrated state of the query to the result
// This will be removed on client after hydration
obj.hydrationData = {
state: query.state,
queryKey: query.queryKey,
queryHash: query.queryHash,
...(query.meta && { meta: query.meta }),
}
return obj
}
// Base Query Function that is used to create the query.
export function useBaseQuery<
TQueryFnData,
TError,
TData,
TQueryData,
TQueryKey extends QueryKey,
>(
options: Accessor<
UseBaseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>
>,
Observer: typeof QueryObserver,
queryClient?: Accessor<QueryClient>,
) {
type ResourceData = QueryObserverResult<TData, TError>
const client = createMemo(() => useQueryClient(queryClient?.()))
const isRestoring = useIsRestoring()
// There are times when we run a query on the server but the resource is never read
// This could lead to times when the queryObserver is unsubscribed before the resource has loaded
// Causing a time out error. To prevent this we will queue the unsubscribe if the cleanup is called
// before the resource has loaded
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
// Enable prefetch during render for SSR - required for createResource to work
// Without this, queries wait for effects which never run on the server
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<QueryObserverResult<TData, TError>>(observerResult)
const createServerSubscriber = (
resolve: (
data: ResourceData | PromiseLike<ResourceData | undefined> | undefined,
) => void,
reject: (reason?: any) => void,
) => {
return observer().subscribe((result) => {
notifyManager.batchCalls(() => {
const query = observer().getCurrentQuery()
const unwrappedResult = hydratableObserverResult(query, result)
if (result.data !== undefined && 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: typeof observerResult) {
const opts = observer().options
// @ts-expect-error - Reconcile option is not correctly typed internally
const reconcileOptions = opts.reconcile
setState((store) => {
return reconcileFn(
store,
res,
reconcileOptions === undefined ? false : reconcileOptions,
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>
}
/**
* Unsubscribe is set lazily, so that we can subscribe after hydration when needed.
*/
let unsubscribe: (() => void) | null = null
/*
Fixes #7275
In a few cases, the observer could unmount before the resource is loaded.
This leads to Suspense boundaries to be suspended indefinitely.
This resolver will be called when the observer is unmounting
but the resource is still in a loading state
*/
let resolver: ((value: ResourceData) => void) | null = null
const [queryResource, { refetch }] = createResource<ResourceData | undefined>(
() => {
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
/**
* 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()
},
},
)
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: QueryObserverResult<TData, TError>,
prop: keyof QueryObserverResult<TData, TError>,
): any {
if (prop === 'data') {
if (state.data !== undefined) {
return queryResource.latest?.data
}
return queryResource()?.data
}
return Reflect.get(target, prop)
},
}
return new Proxy(state, handler)
}

View File

@@ -0,0 +1,76 @@
import { InfiniteQueryObserver } from '@tanstack/query-core'
import { createMemo } from 'solid-js'
import { useBaseQuery } from './useBaseQuery'
import type {
DefaultError,
InfiniteData,
QueryKey,
QueryObserver,
} from '@tanstack/query-core'
import type { QueryClient } from './QueryClient'
import type {
DefinedUseInfiniteQueryResult,
UseInfiniteQueryOptions,
UseInfiniteQueryResult,
} from './types'
import type { Accessor } from 'solid-js'
import type {
DefinedInitialDataInfiniteOptions,
UndefinedInitialDataInfiniteOptions,
} from './infiniteQueryOptions'
export function useInfiniteQuery<
TQueryFnData,
TError = DefaultError,
TData = InfiniteData<TQueryFnData>,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
>(
options: DefinedInitialDataInfiniteOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
>,
queryClient?: Accessor<QueryClient>,
): DefinedUseInfiniteQueryResult<TData, TError>
export function useInfiniteQuery<
TQueryFnData,
TError = DefaultError,
TData = InfiniteData<TQueryFnData>,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
>(
options: UndefinedInitialDataInfiniteOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
>,
queryClient?: Accessor<QueryClient>,
): UseInfiniteQueryResult<TData, TError>
export function useInfiniteQuery<
TQueryFnData,
TError = DefaultError,
TData = InfiniteData<TQueryFnData>,
TQueryKey extends QueryKey = QueryKey,
TPageParam = unknown,
>(
options: UseInfiniteQueryOptions<
TQueryFnData,
TError,
TData,
TQueryKey,
TPageParam
>,
queryClient?: Accessor<QueryClient>,
): UseInfiniteQueryResult<TData, TError> {
return useBaseQuery(
createMemo(() => options()),
InfiniteQueryObserver as typeof QueryObserver,
queryClient,
) as UseInfiniteQueryResult<TData, TError>
}

View File

@@ -0,0 +1,23 @@
import { createMemo, createSignal, onCleanup } from 'solid-js'
import { useQueryClient } from './QueryClientProvider'
import type { QueryFilters } from '@tanstack/query-core'
import type { QueryClient } from './QueryClient'
import type { Accessor } from 'solid-js'
export function useIsFetching(
filters?: Accessor<QueryFilters>,
queryClient?: Accessor<QueryClient>,
): Accessor<number> {
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
}

View File

@@ -0,0 +1,25 @@
import { createMemo, createSignal, onCleanup } from 'solid-js'
import { useQueryClient } from './QueryClientProvider'
import type { MutationFilters } from '@tanstack/query-core'
import type { QueryClient } from './QueryClient'
import type { Accessor } from 'solid-js'
export function useIsMutating(
filters?: Accessor<MutationFilters>,
queryClient?: Accessor<QueryClient>,
): Accessor<number> {
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
}

79
node_modules/@tanstack/solid-query/src/useMutation.ts generated vendored Normal file
View File

@@ -0,0 +1,79 @@
import { MutationObserver, noop, shouldThrowError } from '@tanstack/query-core'
import { createComputed, createMemo, on, onCleanup } from 'solid-js'
import { createStore } from 'solid-js/store'
import { useQueryClient } from './QueryClientProvider'
import type { DefaultError } from '@tanstack/query-core'
import type { QueryClient } from './QueryClient'
import type {
UseMutateFunction,
UseMutationOptions,
UseMutationResult,
} from './types'
import type { Accessor } from 'solid-js'
// HOOK
export function useMutation<
TData = unknown,
TError = DefaultError,
TVariables = void,
TOnMutateResult = unknown,
>(
options: UseMutationOptions<TData, TError, TVariables, TOnMutateResult>,
queryClient?: Accessor<QueryClient>,
): UseMutationResult<TData, TError, TVariables, TOnMutateResult> {
const client = createMemo(() => useQueryClient(queryClient?.()))
const observer = new MutationObserver<
TData,
TError,
TVariables,
TOnMutateResult
>(client(), options())
const mutate: UseMutateFunction<
TData,
TError,
TVariables,
TOnMutateResult
> = (variables, mutateOptions) => {
observer.mutate(variables, mutateOptions).catch(noop)
}
const [state, setState] = createStore<
UseMutationResult<TData, TError, TVariables, TOnMutateResult>
>({
...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
}

View File

@@ -0,0 +1,56 @@
import { createEffect, createMemo, createSignal, onCleanup } from 'solid-js'
import { replaceEqualDeep } from '@tanstack/query-core'
import { useQueryClient } from './QueryClientProvider'
import type {
Mutation,
MutationCache,
MutationFilters,
MutationState,
} from '@tanstack/query-core'
import type { Accessor } from 'solid-js'
import type { QueryClient } from './QueryClient'
type MutationStateOptions<TResult = MutationState> = {
filters?: MutationFilters
select?: (mutation: Mutation) => TResult
}
function getResult<TResult = MutationState>(
mutationCache: MutationCache,
options: MutationStateOptions<TResult>,
): Array<TResult> {
return mutationCache
.findAll(options.filters)
.map(
(mutation): TResult =>
(options.select ? options.select(mutation) : mutation.state) as TResult,
)
}
export function useMutationState<TResult = MutationState>(
options: Accessor<MutationStateOptions<TResult>> = () => ({}),
queryClient?: Accessor<QueryClient>,
): Accessor<Array<TResult>> {
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
}

343
node_modules/@tanstack/solid-query/src/useQueries.ts generated vendored Normal file
View File

@@ -0,0 +1,343 @@
import { QueriesObserver, noop } from '@tanstack/query-core'
import { createStore, unwrap } from 'solid-js/store'
import {
batch,
createComputed,
createMemo,
createRenderEffect,
createResource,
mergeProps,
on,
onCleanup,
onMount,
} from 'solid-js'
import { useQueryClient } from './QueryClientProvider'
import { useIsRestoring } from './isRestoring'
import type { SolidQueryOptions, UseQueryResult } from './types'
import type { Accessor } from 'solid-js'
import type { QueryClient } from './QueryClient'
import type {
DefaultError,
OmitKeyof,
QueriesObserverOptions,
QueriesPlaceholderDataFunction,
QueryFunction,
QueryKey,
QueryObserverOptions,
QueryObserverResult,
ThrowOnError,
} from '@tanstack/query-core'
// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.
// `placeholderData` function does not have a parameter
type UseQueryOptionsForUseQueries<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> = OmitKeyof<
SolidQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
'placeholderData' | 'suspense'
> & {
placeholderData?: TQueryFnData | QueriesPlaceholderDataFunction<TQueryFnData>
/**
* @deprecated The `suspense` option has been deprecated in v5 and will be removed in the next major version.
* The `data` property on useQueries is a plain object and not a SolidJS Resource.
* It will not suspend when the data is loading.
* Setting `suspense` to `true` will be a no-op.
*/
suspense?: boolean
}
// Avoid TS depth-limit error in case of large array literal
type MAXIMUM_DEPTH = 20
// Widen the type of the symbol to enable type inference even if skipToken is not immutable.
type SkipTokenForUseQueries = symbol
type GetOptions<T> =
// Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }
T extends {
queryFnData: infer TQueryFnData
error?: infer TError
data: infer TData
}
? UseQueryOptionsForUseQueries<TQueryFnData, TError, TData>
: T extends { queryFnData: infer TQueryFnData; error?: infer TError }
? UseQueryOptionsForUseQueries<TQueryFnData, TError>
: T extends { data: infer TData; error?: infer TError }
? UseQueryOptionsForUseQueries<unknown, TError, TData>
: // Part 2: responsible for applying explicit type parameter to function arguments, if tuple [TQueryFnData, TError, TData]
T extends [infer TQueryFnData, infer TError, infer TData]
? UseQueryOptionsForUseQueries<TQueryFnData, TError, TData>
: T extends [infer TQueryFnData, infer TError]
? UseQueryOptionsForUseQueries<TQueryFnData, TError>
: T extends [infer TQueryFnData]
? UseQueryOptionsForUseQueries<TQueryFnData>
: // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided
T extends {
queryFn?:
| QueryFunction<infer TQueryFnData, infer TQueryKey>
| SkipTokenForUseQueries
select?: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseQueryOptionsForUseQueries<
TQueryFnData,
unknown extends TError ? DefaultError : TError,
unknown extends TData ? TQueryFnData : TData,
TQueryKey
>
: // Fallback
UseQueryOptionsForUseQueries
type GetResults<T> =
// Part 1: responsible for mapping explicit type parameter to function result, if object
T extends { queryFnData: any; error?: infer TError; data: infer TData }
? UseQueryResult<TData, TError>
: T extends { queryFnData: infer TQueryFnData; error?: infer TError }
? UseQueryResult<TQueryFnData, TError>
: T extends { data: infer TData; error?: infer TError }
? UseQueryResult<TData, TError>
: // Part 2: responsible for mapping explicit type parameter to function result, if tuple
T extends [any, infer TError, infer TData]
? UseQueryResult<TData, TError>
: T extends [infer TQueryFnData, infer TError]
? UseQueryResult<TQueryFnData, TError>
: T extends [infer TQueryFnData]
? UseQueryResult<TQueryFnData>
: // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided
T extends {
queryFn?:
| QueryFunction<infer TQueryFnData, any>
| SkipTokenForUseQueries
select?: (data: any) => infer TData
throwOnError?: ThrowOnError<any, infer TError, any, any>
}
? UseQueryResult<
unknown extends TData ? TQueryFnData : TData,
unknown extends TError ? DefaultError : TError
>
: // Fallback
UseQueryResult
/**
* QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
*/
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<
[...Tail],
[...TResult, GetOptions<Head>],
[...TDepth, 1]
>
: ReadonlyArray<unknown> extends T
? T
: // If T is *some* array but we couldn't assign unknown[] to it, then it must hold some known/homogenous type!
// use this to infer the param types in the case of Array.map() argument
T extends Array<
UseQueryOptionsForUseQueries<
infer TQueryFnData,
infer TError,
infer TData,
infer TQueryKey
>
>
? Array<
UseQueryOptionsForUseQueries<
TQueryFnData,
TError,
TData,
TQueryKey
>
>
: // Fallback
Array<UseQueryOptionsForUseQueries>
/**
* QueriesResults reducer recursively maps type param to results
*/
type QueriesResults<
T extends Array<any>,
TResult extends Array<any> = [],
TDepth extends ReadonlyArray<number> = [],
> = TDepth['length'] extends MAXIMUM_DEPTH
? Array<UseQueryResult>
: T extends []
? []
: T extends [infer Head]
? [...TResult, GetResults<Head>]
: T extends [infer Head, ...infer Tail]
? QueriesResults<
[...Tail],
[...TResult, GetResults<Head>],
[...TDepth, 1]
>
: { [K in keyof T]: GetResults<T[K]> }
export function useQueries<
T extends Array<any>,
TCombinedResult extends QueriesResults<T> = QueriesResults<T>,
>(
queriesOptions: Accessor<{
queries:
| readonly [...QueriesOptions<T>]
| readonly [...{ [K in keyof T]: GetOptions<T[K]> }]
combine?: (result: QueriesResults<T>) => TCombinedResult
}>,
queryClient?: Accessor<QueryClient>,
): TCombinedResult {
const client = createMemo(() => useQueryClient(queryClient?.()))
const isRestoring = useIsRestoring()
const defaultedQueries = createMemo(() =>
queriesOptions().queries.map((options) =>
mergeProps(
client().defaultQueryOptions(options as QueryObserverOptions),
{
get _optimisticResults() {
return isRestoring() ? 'isRestoring' : 'optimistic'
},
},
),
),
)
const observer = new QueriesObserver(
client(),
defaultedQueries(),
queriesOptions().combine
? ({
combine: queriesOptions().combine,
} as QueriesObserverOptions<TCombinedResult>)
: undefined,
)
const [state, setState] = createStore<TCombinedResult>(
observer.getOptimisticResult(
defaultedQueries(),
(queriesOptions() as QueriesObserverOptions<TCombinedResult>).combine,
)[1](),
)
createRenderEffect(
on(
() => queriesOptions().queries.length,
() =>
setState(
observer.getOptimisticResult(
defaultedQueries(),
(queriesOptions() as QueriesObserverOptions<TCombinedResult>)
.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: 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()
}
})
})
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)
onMount(() => {
observer.setQueries(
defaultedQueries(),
queriesOptions().combine
? ({
combine: queriesOptions().combine,
} as QueriesObserverOptions<TCombinedResult>)
: undefined,
)
})
createComputed(() => {
observer.setQueries(
defaultedQueries(),
queriesOptions().combine
? ({
combine: queriesOptions().combine,
} as QueriesObserverOptions<TCombinedResult>)
: undefined,
)
})
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
}

50
node_modules/@tanstack/solid-query/src/useQuery.ts generated vendored Normal file
View File

@@ -0,0 +1,50 @@
import { QueryObserver } from '@tanstack/query-core'
import { createMemo } from 'solid-js'
import { useBaseQuery } from './useBaseQuery'
import type { DefaultError, QueryKey } from '@tanstack/query-core'
import type { QueryClient } from './QueryClient'
import type { Accessor } from 'solid-js'
import type {
DefinedUseQueryResult,
UseQueryOptions,
UseQueryResult,
} from './types'
import type {
DefinedInitialDataOptions,
UndefinedInitialDataOptions,
} from './queryOptions'
export function useQuery<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
>(
options: UndefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>,
queryClient?: () => QueryClient,
): UseQueryResult<TData, TError>
export function useQuery<
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
>(
options: DefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>,
queryClient?: () => QueryClient,
): DefinedUseQueryResult<TData, TError>
export function useQuery<
TQueryFnData,
TError = DefaultError,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
>(
options: UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
queryClient?: Accessor<QueryClient>,
) {
return useBaseQuery(
createMemo(() => options()),
QueryObserver,
queryClient,
)
}