@effector-tanstack-query/core 0.4.0 → 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/createBaseQuery.cjs +23 -0
- package/dist/createBaseQuery.cjs.map +1 -1
- package/dist/createBaseQuery.d.cts +23 -1
- package/dist/createBaseQuery.d.ts +23 -1
- package/dist/createBaseQuery.js +23 -0
- package/dist/createBaseQuery.js.map +1 -1
- package/dist/createCacheAction.cjs +60 -0
- package/dist/createCacheAction.cjs.map +1 -0
- package/dist/createCacheAction.d.cts +66 -0
- package/dist/createCacheAction.d.ts +66 -0
- package/dist/createCacheAction.js +56 -0
- package/dist/createCacheAction.js.map +1 -0
- package/dist/createInfiniteQuery.cjs +2 -1
- package/dist/createInfiniteQuery.cjs.map +1 -1
- package/dist/createInfiniteQuery.js +2 -1
- package/dist/createInfiniteQuery.js.map +1 -1
- package/dist/createQuery.cjs +2 -1
- package/dist/createQuery.cjs.map +1 -1
- package/dist/createQuery.js +2 -1
- package/dist/createQuery.js.map +1 -1
- package/dist/index.cjs +13 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types.d.cts +29 -0
- package/dist/types.d.ts +29 -0
- package/package.json +9 -5
- package/src/createBaseQuery.ts +67 -1
- package/src/createCacheAction.ts +172 -0
- package/src/createInfiniteQuery.ts +1 -0
- package/src/createQuery.ts +1 -0
- package/src/index.ts +11 -0
- package/src/types.ts +29 -0
package/dist/createBaseQuery.cjs
CHANGED
|
@@ -37,6 +37,8 @@ function createBaseQuery(explicitClient, options, config) {
|
|
|
37
37
|
const isFetchingUpdated = effector.createEvent();
|
|
38
38
|
const fetchStatusUpdated = effector.createEvent();
|
|
39
39
|
const isPlaceholderDataUpdated = effector.createEvent();
|
|
40
|
+
const finishedSuccess = effector.createEvent();
|
|
41
|
+
const finishedFailure = effector.createEvent();
|
|
40
42
|
const $data = effector.createStore(void 0, {
|
|
41
43
|
skipVoid: false,
|
|
42
44
|
...sidConfig(name, "$data")
|
|
@@ -89,7 +91,11 @@ function createBaseQuery(explicitClient, options, config) {
|
|
|
89
91
|
const dispatchIsPlaceholderData = effector.scopeBind(isPlaceholderDataUpdated, {
|
|
90
92
|
safe: true
|
|
91
93
|
});
|
|
94
|
+
const dispatchFinishedSuccess = effector.scopeBind(finishedSuccess, { safe: true });
|
|
95
|
+
const dispatchFinishedFailure = effector.scopeBind(finishedFailure, { safe: true });
|
|
92
96
|
const dispatchExtras = extras?.bindDispatcher();
|
|
97
|
+
let lastDataUpdatedAt = -1;
|
|
98
|
+
let lastErrorUpdatedAt = -1;
|
|
93
99
|
observerSubscriptions.get(observer)?.();
|
|
94
100
|
observer.setOptions({
|
|
95
101
|
...observer.options,
|
|
@@ -108,6 +114,19 @@ function createBaseQuery(explicitClient, options, config) {
|
|
|
108
114
|
dispatchFetchStatus(result.fetchStatus);
|
|
109
115
|
dispatchIsPlaceholderData(result.isPlaceholderData);
|
|
110
116
|
dispatchExtras?.(result);
|
|
117
|
+
if (lastDataUpdatedAt === -1) {
|
|
118
|
+
lastDataUpdatedAt = result.dataUpdatedAt;
|
|
119
|
+
lastErrorUpdatedAt = result.errorUpdatedAt;
|
|
120
|
+
} else {
|
|
121
|
+
if (result.dataUpdatedAt > lastDataUpdatedAt && result.status === "success" && !result.isPlaceholderData) {
|
|
122
|
+
lastDataUpdatedAt = result.dataUpdatedAt;
|
|
123
|
+
dispatchFinishedSuccess(result.data);
|
|
124
|
+
}
|
|
125
|
+
if (result.errorUpdatedAt > lastErrorUpdatedAt && result.status === "error") {
|
|
126
|
+
lastErrorUpdatedAt = result.errorUpdatedAt;
|
|
127
|
+
dispatchFinishedFailure(result.error);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
111
130
|
};
|
|
112
131
|
const unsubscribe = observer.subscribe(dispatch);
|
|
113
132
|
observerSubscriptions.set(observer, unsubscribe);
|
|
@@ -197,6 +216,10 @@ function createBaseQuery(explicitClient, options, config) {
|
|
|
197
216
|
refresh,
|
|
198
217
|
mounted,
|
|
199
218
|
unmounted,
|
|
219
|
+
finished: {
|
|
220
|
+
success: finishedSuccess,
|
|
221
|
+
failure: finishedFailure
|
|
222
|
+
},
|
|
200
223
|
...extras?.stores ?? {}
|
|
201
224
|
};
|
|
202
225
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/createBaseQuery.ts"],"names":["resolveKey","resolveEnabled","createStore","$queryClient","createEvent","attach","scopeBind","sample","combine"],"mappings":"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","file":"createBaseQuery.cjs","sourcesContent":["import {\n attach,\n combine,\n createEvent,\n createStore,\n sample,\n scopeBind,\n} from 'effector'\nimport type { EventCallable, Store } from 'effector'\nimport type {\n FetchStatus,\n QueryClient,\n QueryKey,\n QueryStatus,\n} from '@tanstack/query-core'\nimport { $queryClient } from './queryClient'\nimport { resolveEnabled, resolveKey } from './resolve'\nimport type { EffectorQueryKey, StoreOrValue } from './types'\n\n/**\n * The minimal shape of an observer that createBaseQuery knows how to drive.\n * Both QueryObserver and InfiniteQueryObserver satisfy this.\n */\nexport interface BaseObserverLike<TResult> {\n options: { queryKey: QueryKey; _defaulted?: boolean; queryHash?: string }\n setOptions(options: any): void\n subscribe(listener: (result: TResult) => void): () => void\n getCurrentResult(): TResult\n destroy(): void\n}\n\n/**\n * The subset of observer result fields that createBaseQuery wires up\n * into stores common to all query flavors.\n */\nexport interface BaseObserverResult<TData, TError> {\n data: TData | undefined\n error: TError | null\n status: QueryStatus\n isFetching: boolean\n fetchStatus: FetchStatus\n isPlaceholderData: boolean\n}\n\nexport interface BaseQueryStores<TData, TError, TObserver> {\n $data: Store<TData | undefined>\n $error: Store<TError | null>\n $status: Store<QueryStatus>\n $isPending: Store<boolean>\n $isFetching: Store<boolean>\n $isSuccess: Store<boolean>\n $isError: Store<boolean>\n $isPlaceholderData: Store<boolean>\n $fetchStatus: Store<FetchStatus>\n /**\n * Per-scope observer. Populated on first `mounted()` via attach over\n * `$queryClient` — every fork scope has its own Observer instance bound\n * to the scope's QueryClient. Read scope-aware via `useUnit($observer)`.\n */\n $observer: Store<TObserver | null>\n /**\n * Resolved QueryClient store. If the factory was called with an explicit\n * client, this is a frozen store of that client. Otherwise it's the global\n * `$queryClient`, which honors `fork({ values })` overrides.\n */\n $queryClient: Store<QueryClient | null>\n /** Internal — used by the React suspense hooks. */\n $resolvedKey: Store<QueryKey>\n /** Internal — used by the React suspense hooks. */\n $enabled: Store<boolean>\n refresh: EventCallable<void>\n mounted: EventCallable<void>\n unmounted: EventCallable<void>\n}\n\nexport interface BaseQueryOptions {\n queryKey: EffectorQueryKey\n enabled?: StoreOrValue<boolean>\n /**\n * Pre-resolved reactive `refetchInterval`. The per-flavor factory extracts\n * the original option, and — if it's a Store — passes the Store here while\n * stripping the value from the observer constructor options. Static values\n * and function forms continue to flow through `restOptions` to the\n * observer.\n */\n reactiveRefetchInterval?: Store<number | false | undefined>\n name?: string\n}\n\nconst SID_PREFIX = '@tanstack/query-effector'\n\nconst warnedNames = new Set<string>()\n\nexport function warnMissingName(role: string): void {\n if (typeof process === 'undefined' || process.env.NODE_ENV === 'production') {\n return\n }\n if (warnedNames.has(role)) return\n warnedNames.add(role)\n // eslint-disable-next-line no-console\n console.warn(\n `[@tanstack/query-effector] ${role} created without a \"name\" — internal stores will be excluded from serialize(scope). ` +\n `Pass a unique \"name\" to enable SSR via fork({ values: serialize(scope) }).`,\n )\n}\n\nexport function sidConfig(\n name: string | undefined,\n role: string,\n): { sid: string; name: string } | {} {\n if (!name) return {}\n return {\n sid: `${SID_PREFIX}.${name}.${role}`,\n name: `${name}.${role}`,\n }\n}\n\nexport interface ExtrasSetup<TResult, TObserver, TExtraStores> {\n /** Extra stores/events merged into the final result object. */\n stores: TExtraStores\n /**\n * Invoked inside the mount effect. Must scope-bind any extra events\n * and return a function that dispatches extra fields from the observer\n * result. The returned dispatcher is called on every subscription\n * notification alongside the base dispatcher.\n */\n bindDispatcher: () => (result: TResult) => void\n /**\n * Lets a flavor wire its own per-observer effects (e.g.\n * fetchNextPage / fetchPreviousPage for infinite queries). Receives the\n * per-scope `$observer` store so the flavor can build attach-based\n * effects that resolve the observer from the current scope.\n */\n setupEffects?: (params: { $observer: Store<TObserver | null> }) => void\n}\n\nexport interface CreateBaseQueryConfig<\n TData,\n TError,\n TResult extends BaseObserverResult<TData, TError>,\n TObserver extends BaseObserverLike<TResult>,\n TExtraStores,\n> {\n /** Build the observer for the current scope. Receives the resolved client. */\n createObserver: (\n queryClient: QueryClient,\n initial: { queryKey: QueryKey; enabled: boolean },\n ) => TObserver\n /**\n * Hook for query flavors that need additional stores/events (e.g. infinite\n * query's hasNextPage, fetchNextPage). Called once at factory time.\n */\n setupExtras?: () => ExtrasSetup<TResult, TObserver, TExtraStores>\n}\n\nexport function createBaseQuery<\n TData,\n TError,\n TResult extends BaseObserverResult<TData, TError>,\n TObserver extends BaseObserverLike<TResult>,\n TExtraStores = {},\n>(\n explicitClient: QueryClient | null,\n options: BaseQueryOptions,\n config: CreateBaseQueryConfig<TData, TError, TResult, TObserver, TExtraStores>,\n): BaseQueryStores<TData, TError, TObserver> & TExtraStores {\n const { name, reactiveRefetchInterval: $reactiveRefetchInterval } = options\n const $resolvedKey = resolveKey(options.queryKey)\n const $enabled = resolveEnabled(options.enabled)\n\n // If an explicit client is passed, the factory is locked to it. fork()\n // values cannot override the captured value because $effectiveClient is a\n // brand-new store (not the global one). When no explicit client is passed,\n // we route through $queryClient — which respects fork({ values }) for\n // per-scope isolation.\n const $effectiveClient: Store<QueryClient | null> = explicitClient\n ? createStore(explicitClient as QueryClient | null, {\n serialize: 'ignore',\n })\n : $queryClient\n\n const dataUpdated = createEvent<TData | undefined>()\n const errorUpdated = createEvent<TError | null>()\n const statusUpdated = createEvent<QueryStatus>()\n const isFetchingUpdated = createEvent<boolean>()\n const fetchStatusUpdated = createEvent<FetchStatus>()\n const isPlaceholderDataUpdated = createEvent<boolean>()\n\n const $data = createStore<TData | undefined>(undefined, {\n skipVoid: false,\n ...sidConfig(name, '$data'),\n }).on(dataUpdated, (_, v) => v)\n const $error = createStore<TError | null>(null, {\n skipVoid: false,\n ...sidConfig(name, '$error'),\n }).on(errorUpdated, (_, v) => v)\n const $status = createStore<QueryStatus>('pending', {\n ...sidConfig(name, '$status'),\n }).on(statusUpdated, (_, v) => v)\n const $isFetching = createStore(false, {\n ...sidConfig(name, '$isFetching'),\n }).on(isFetchingUpdated, (_, v) => v)\n const $fetchStatus = createStore<FetchStatus>('idle', {\n ...sidConfig(name, '$fetchStatus'),\n }).on(fetchStatusUpdated, (_, v) => v)\n const $isPlaceholderData = createStore(false, {\n ...sidConfig(name, '$isPlaceholderData'),\n }).on(isPlaceholderDataUpdated, (_, v) => v)\n\n // Derived stores via .map don't accept sid in their config — effector's\n // serialize() captures source-store values, and derived stores recompute\n // automatically on the client after fork({ values }).\n const $isPending = $status.map((s) => s === 'pending')\n const $isSuccess = $status.map((s) => s === 'success')\n const $isError = $status.map((s) => s === 'error')\n\n // Per-scope observer storage. Carries runtime-only references\n // (subscriptions, callbacks) — must never participate in serialization.\n const $observer = createStore<TObserver | null>(null, {\n serialize: 'ignore',\n })\n const observerCreated = createEvent<TObserver>()\n $observer.on(observerCreated, (_, obs) => obs)\n\n // Per-observer unsubscribe handles. WeakMap so abandoned observers (e.g.\n // a scope that was discarded without unmount) are GC'able.\n const observerSubscriptions = new WeakMap<TObserver, () => void>()\n\n const extras = config.setupExtras?.()\n extras?.setupEffects?.({ $observer })\n\n // Runs once per mount. Creates the observer for the current scope (if not\n // yet created) and attaches the subscription. scopeBind({ safe: true })\n // reliably captures the fork scope here because this effect is triggered\n // directly from allSettled(mounted). Bound dispatchers are captured in the\n // observer callback's closure and reused for all subsequent notifications\n // (including after key/enabled changes).\n const mountFx = attach({\n source: { qc: $effectiveClient, observer: $observer },\n effect: (\n { qc, observer: existingObserver },\n {\n key,\n enabled,\n refetchInterval,\n }: {\n key: QueryKey\n enabled: boolean\n refetchInterval: number | false | undefined\n },\n ) => {\n if (!qc) {\n throw new Error(\n '[@tanstack/query-effector] No QueryClient is set. Call setQueryClient(qc) before mounting, ' +\n 'pass it to fork({ values: [[$queryClient, qc]] }), or pass it explicitly to the factory.',\n )\n }\n\n const observer =\n existingObserver ??\n config.createObserver(qc, { queryKey: key, enabled })\n\n const dispatchData = scopeBind(dataUpdated, { safe: true })\n const dispatchError = scopeBind(errorUpdated, { safe: true })\n const dispatchStatus = scopeBind(statusUpdated, { safe: true })\n const dispatchIsFetching = scopeBind(isFetchingUpdated, { safe: true })\n const dispatchFetchStatus = scopeBind(fetchStatusUpdated, { safe: true })\n const dispatchIsPlaceholderData = scopeBind(isPlaceholderDataUpdated, {\n safe: true,\n })\n const dispatchExtras = extras?.bindDispatcher()\n\n observerSubscriptions.get(observer)?.()\n observer.setOptions({\n ...observer.options,\n queryKey: key,\n enabled,\n // Only override refetchInterval when the user provided a reactive\n // Store — otherwise the static value (or function) from the observer\n // constructor wins.\n ...($reactiveRefetchInterval ? { refetchInterval } : {}),\n })\n\n const dispatch = (result: TResult) => {\n dispatchData(result.data)\n dispatchError(result.error)\n dispatchStatus(result.status)\n dispatchIsFetching(result.isFetching)\n dispatchFetchStatus(result.fetchStatus)\n dispatchIsPlaceholderData(result.isPlaceholderData)\n dispatchExtras?.(result)\n }\n\n const unsubscribe = observer.subscribe(dispatch)\n observerSubscriptions.set(observer, unsubscribe)\n\n // Emit the current state immediately — observer.subscribe() may not\n // fire the callback synchronously when cached data already matches\n // the observer's initial result (e.g. staleTime + setQueryData).\n // This mirrors react-query's getOptimisticResult() on mount.\n dispatch(observer.getCurrentResult())\n\n return observer\n },\n })\n\n sample({ clock: mountFx.doneData, target: observerCreated })\n\n // Runs when key / enabled / reactive refetchInterval change after mount.\n // Only updates observer options — subscription + dispatchers were already\n // wired in mountFx.\n const updateObserverFx = attach({\n source: $observer,\n effect: (\n observer,\n {\n key,\n enabled,\n refetchInterval,\n }: {\n key: QueryKey\n enabled: boolean\n refetchInterval: number | false | undefined\n },\n ) => {\n if (!observer) return\n // Strip _defaulted and queryHash so defaultQueryOptions() recomputes\n // the hash for the new key. Without this, the old hash is preserved and\n // QueryObserver#updateQuery() finds the old query — no key switch, no fetch.\n const {\n _defaulted: _d,\n queryHash: _h,\n ...baseOptions\n } = observer.options as typeof observer.options & {\n _defaulted?: boolean\n queryHash?: string\n }\n observer.setOptions({\n ...baseOptions,\n queryKey: key,\n enabled,\n ...($reactiveRefetchInterval ? { refetchInterval } : {}),\n })\n },\n })\n\n const mounted = createEvent<void>()\n const unmounted = createEvent<void>()\n const $isMounted = createStore(false, {\n ...sidConfig(name, '$isMounted'),\n })\n .on(mounted, () => true)\n .on(unmounted, () => false)\n\n // Combine of all reactive options that drive observer.setOptions. Built once\n // so mountFx and updateObserverFx see the same shape. When the user didn't\n // pass a reactive `refetchInterval`, we fall back to a static-`false` store\n // (its emitted value is never read — the spread is guarded by the original\n // `$reactiveRefetchInterval` reference).\n const $observerOptions = combine({\n key: $resolvedKey,\n enabled: $enabled,\n refetchInterval:\n $reactiveRefetchInterval ??\n createStore<number | false | undefined>(false),\n })\n\n sample({\n clock: mounted,\n source: $observerOptions,\n target: mountFx,\n })\n\n sample({\n clock: $observerOptions,\n source: $observerOptions,\n filter: $isMounted,\n target: updateObserverFx,\n })\n\n // Single effect: tear down subscription + destroy + clear $observer.\n // Doing all three in one effect avoids ordering ambiguity vs. separate\n // events that all sample from `unmounted`.\n const observerDestroyed = createEvent<void>()\n $observer.on(observerDestroyed, () => null)\n\n const unmountFx = attach({\n source: $observer,\n effect: (observer) => {\n if (!observer) return\n observerSubscriptions.get(observer)?.()\n observerSubscriptions.delete(observer)\n observer.destroy()\n },\n })\n sample({ clock: unmounted, target: unmountFx })\n sample({ clock: unmountFx.finally, target: observerDestroyed })\n\n const refresh = createEvent<void>()\n const refreshFx = attach({\n source: { qc: $effectiveClient, key: $resolvedKey },\n effect: ({ qc, key }) => {\n if (!qc) return\n return qc.invalidateQueries({ queryKey: key })\n },\n })\n sample({ clock: refresh, target: refreshFx })\n\n return {\n $data,\n $error,\n $status,\n $isPending,\n $isFetching,\n $isSuccess,\n $isError,\n $isPlaceholderData,\n $fetchStatus,\n $observer,\n $queryClient: $effectiveClient,\n $resolvedKey,\n $enabled,\n refresh,\n mounted,\n unmounted,\n ...(extras?.stores ?? ({} as TExtraStores)),\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/createBaseQuery.ts"],"names":["resolveKey","resolveEnabled","createStore","$queryClient","createEvent","attach","scopeBind","sample","combine"],"mappings":"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","file":"createBaseQuery.cjs","sourcesContent":["import {\n attach,\n combine,\n createEvent,\n createStore,\n sample,\n scopeBind,\n} from 'effector'\nimport type { Event, EventCallable, Store } from 'effector'\nimport type {\n FetchStatus,\n QueryClient,\n QueryKey,\n QueryStatus,\n} from '@tanstack/query-core'\nimport { $queryClient } from './queryClient'\nimport { resolveEnabled, resolveKey } from './resolve'\nimport type { EffectorQueryKey, StoreOrValue } from './types'\n\n/**\n * The minimal shape of an observer that createBaseQuery knows how to drive.\n * Both QueryObserver and InfiniteQueryObserver satisfy this.\n */\nexport interface BaseObserverLike<TResult> {\n options: { queryKey: QueryKey; _defaulted?: boolean; queryHash?: string }\n setOptions(options: any): void\n subscribe(listener: (result: TResult) => void): () => void\n getCurrentResult(): TResult\n destroy(): void\n}\n\n/**\n * The subset of observer result fields that createBaseQuery wires up\n * into stores common to all query flavors.\n */\nexport interface BaseObserverResult<TData, TError> {\n data: TData | undefined\n error: TError | null\n status: QueryStatus\n isFetching: boolean\n fetchStatus: FetchStatus\n isPlaceholderData: boolean\n /**\n * Timestamp (ms) of the last successful data resolution. Monotonically\n * increases per successful fetch — used to detect newly-finished fetches\n * for the `finished.success` lifecycle event.\n */\n dataUpdatedAt: number\n /**\n * Timestamp (ms) of the last error. Increments per failed fetch — used to\n * detect newly-finished failures for the `finished.failure` lifecycle event.\n */\n errorUpdatedAt: number\n}\n\nexport interface BaseQueryStores<TData, TError, TObserver> {\n $data: Store<TData | undefined>\n $error: Store<TError | null>\n $status: Store<QueryStatus>\n $isPending: Store<boolean>\n $isFetching: Store<boolean>\n $isSuccess: Store<boolean>\n $isError: Store<boolean>\n $isPlaceholderData: Store<boolean>\n $fetchStatus: Store<FetchStatus>\n /**\n * Per-scope observer. Populated on first `mounted()` via attach over\n * `$queryClient` — every fork scope has its own Observer instance bound\n * to the scope's QueryClient. Read scope-aware via `useUnit($observer)`.\n */\n $observer: Store<TObserver | null>\n /**\n * Resolved QueryClient store. If the factory was called with an explicit\n * client, this is a frozen store of that client. Otherwise it's the global\n * `$queryClient`, which honors `fork({ values })` overrides.\n */\n $queryClient: Store<QueryClient | null>\n /** Internal — used by the React suspense hooks. */\n $resolvedKey: Store<QueryKey>\n /** Internal — used by the React suspense hooks. */\n $enabled: Store<boolean>\n refresh: EventCallable<void>\n mounted: EventCallable<void>\n unmounted: EventCallable<void>\n /**\n * Lifecycle events for `sample`-driven reactions to fetch completion.\n * `success` fires with the (post-`select`) data on every newly-finished\n * successful fetch; `failure` fires with the error on every failed fetch.\n * Neither fires for the baseline state observed on mount (e.g. hydrated\n * cache) — they track *new* fetches, not initial observability.\n */\n finished: {\n success: Event<TData>\n failure: Event<TError>\n }\n}\n\nexport interface BaseQueryOptions {\n queryKey: EffectorQueryKey\n enabled?: StoreOrValue<boolean>\n /**\n * Pre-resolved reactive `refetchInterval`. The per-flavor factory extracts\n * the original option, and — if it's a Store — passes the Store here while\n * stripping the value from the observer constructor options. Static values\n * and function forms continue to flow through `restOptions` to the\n * observer.\n */\n reactiveRefetchInterval?: Store<number | false | undefined>\n name?: string\n}\n\nconst SID_PREFIX = '@tanstack/query-effector'\n\nconst warnedNames = new Set<string>()\n\nexport function warnMissingName(role: string): void {\n if (typeof process === 'undefined' || process.env.NODE_ENV === 'production') {\n return\n }\n if (warnedNames.has(role)) return\n warnedNames.add(role)\n // eslint-disable-next-line no-console\n console.warn(\n `[@tanstack/query-effector] ${role} created without a \"name\" — internal stores will be excluded from serialize(scope). ` +\n `Pass a unique \"name\" to enable SSR via fork({ values: serialize(scope) }).`,\n )\n}\n\nexport function sidConfig(\n name: string | undefined,\n role: string,\n): { sid: string; name: string } | {} {\n if (!name) return {}\n return {\n sid: `${SID_PREFIX}.${name}.${role}`,\n name: `${name}.${role}`,\n }\n}\n\nexport interface ExtrasSetup<TResult, TObserver, TExtraStores> {\n /** Extra stores/events merged into the final result object. */\n stores: TExtraStores\n /**\n * Invoked inside the mount effect. Must scope-bind any extra events\n * and return a function that dispatches extra fields from the observer\n * result. The returned dispatcher is called on every subscription\n * notification alongside the base dispatcher.\n */\n bindDispatcher: () => (result: TResult) => void\n /**\n * Lets a flavor wire its own per-observer effects (e.g.\n * fetchNextPage / fetchPreviousPage for infinite queries). Receives the\n * per-scope `$observer` store so the flavor can build attach-based\n * effects that resolve the observer from the current scope.\n */\n setupEffects?: (params: { $observer: Store<TObserver | null> }) => void\n}\n\nexport interface CreateBaseQueryConfig<\n TData,\n TError,\n TResult extends BaseObserverResult<TData, TError>,\n TObserver extends BaseObserverLike<TResult>,\n TExtraStores,\n> {\n /** Build the observer for the current scope. Receives the resolved client. */\n createObserver: (\n queryClient: QueryClient,\n initial: { queryKey: QueryKey; enabled: boolean },\n ) => TObserver\n /**\n * Hook for query flavors that need additional stores/events (e.g. infinite\n * query's hasNextPage, fetchNextPage). Called once at factory time.\n */\n setupExtras?: () => ExtrasSetup<TResult, TObserver, TExtraStores>\n}\n\nexport function createBaseQuery<\n TData,\n TError,\n TResult extends BaseObserverResult<TData, TError>,\n TObserver extends BaseObserverLike<TResult>,\n TExtraStores = {},\n>(\n explicitClient: QueryClient | null,\n options: BaseQueryOptions,\n config: CreateBaseQueryConfig<TData, TError, TResult, TObserver, TExtraStores>,\n): BaseQueryStores<TData, TError, TObserver> & TExtraStores {\n const { name, reactiveRefetchInterval: $reactiveRefetchInterval } = options\n const $resolvedKey = resolveKey(options.queryKey)\n const $enabled = resolveEnabled(options.enabled)\n\n // If an explicit client is passed, the factory is locked to it. fork()\n // values cannot override the captured value because $effectiveClient is a\n // brand-new store (not the global one). When no explicit client is passed,\n // we route through $queryClient — which respects fork({ values }) for\n // per-scope isolation.\n const $effectiveClient: Store<QueryClient | null> = explicitClient\n ? createStore(explicitClient as QueryClient | null, {\n serialize: 'ignore',\n })\n : $queryClient\n\n const dataUpdated = createEvent<TData | undefined>()\n const errorUpdated = createEvent<TError | null>()\n const statusUpdated = createEvent<QueryStatus>()\n const isFetchingUpdated = createEvent<boolean>()\n const fetchStatusUpdated = createEvent<FetchStatus>()\n const isPlaceholderDataUpdated = createEvent<boolean>()\n\n // Lifecycle events. Created once at factory time; dispatched per-scope via\n // scopeBind inside the mount effect so `allSettled` / fork isolation work.\n const finishedSuccess = createEvent<TData>()\n const finishedFailure = createEvent<TError>()\n\n const $data = createStore<TData | undefined>(undefined, {\n skipVoid: false,\n ...sidConfig(name, '$data'),\n }).on(dataUpdated, (_, v) => v)\n const $error = createStore<TError | null>(null, {\n skipVoid: false,\n ...sidConfig(name, '$error'),\n }).on(errorUpdated, (_, v) => v)\n const $status = createStore<QueryStatus>('pending', {\n ...sidConfig(name, '$status'),\n }).on(statusUpdated, (_, v) => v)\n const $isFetching = createStore(false, {\n ...sidConfig(name, '$isFetching'),\n }).on(isFetchingUpdated, (_, v) => v)\n const $fetchStatus = createStore<FetchStatus>('idle', {\n ...sidConfig(name, '$fetchStatus'),\n }).on(fetchStatusUpdated, (_, v) => v)\n const $isPlaceholderData = createStore(false, {\n ...sidConfig(name, '$isPlaceholderData'),\n }).on(isPlaceholderDataUpdated, (_, v) => v)\n\n // Derived stores via .map don't accept sid in their config — effector's\n // serialize() captures source-store values, and derived stores recompute\n // automatically on the client after fork({ values }).\n const $isPending = $status.map((s) => s === 'pending')\n const $isSuccess = $status.map((s) => s === 'success')\n const $isError = $status.map((s) => s === 'error')\n\n // Per-scope observer storage. Carries runtime-only references\n // (subscriptions, callbacks) — must never participate in serialization.\n const $observer = createStore<TObserver | null>(null, {\n serialize: 'ignore',\n })\n const observerCreated = createEvent<TObserver>()\n $observer.on(observerCreated, (_, obs) => obs)\n\n // Per-observer unsubscribe handles. WeakMap so abandoned observers (e.g.\n // a scope that was discarded without unmount) are GC'able.\n const observerSubscriptions = new WeakMap<TObserver, () => void>()\n\n const extras = config.setupExtras?.()\n extras?.setupEffects?.({ $observer })\n\n // Runs once per mount. Creates the observer for the current scope (if not\n // yet created) and attaches the subscription. scopeBind({ safe: true })\n // reliably captures the fork scope here because this effect is triggered\n // directly from allSettled(mounted). Bound dispatchers are captured in the\n // observer callback's closure and reused for all subsequent notifications\n // (including after key/enabled changes).\n const mountFx = attach({\n source: { qc: $effectiveClient, observer: $observer },\n effect: (\n { qc, observer: existingObserver },\n {\n key,\n enabled,\n refetchInterval,\n }: {\n key: QueryKey\n enabled: boolean\n refetchInterval: number | false | undefined\n },\n ) => {\n if (!qc) {\n throw new Error(\n '[@tanstack/query-effector] No QueryClient is set. Call setQueryClient(qc) before mounting, ' +\n 'pass it to fork({ values: [[$queryClient, qc]] }), or pass it explicitly to the factory.',\n )\n }\n\n const observer =\n existingObserver ??\n config.createObserver(qc, { queryKey: key, enabled })\n\n const dispatchData = scopeBind(dataUpdated, { safe: true })\n const dispatchError = scopeBind(errorUpdated, { safe: true })\n const dispatchStatus = scopeBind(statusUpdated, { safe: true })\n const dispatchIsFetching = scopeBind(isFetchingUpdated, { safe: true })\n const dispatchFetchStatus = scopeBind(fetchStatusUpdated, { safe: true })\n const dispatchIsPlaceholderData = scopeBind(isPlaceholderDataUpdated, {\n safe: true,\n })\n const dispatchFinishedSuccess = scopeBind(finishedSuccess, { safe: true })\n const dispatchFinishedFailure = scopeBind(finishedFailure, { safe: true })\n const dispatchExtras = extras?.bindDispatcher()\n\n // Per-mount, per-scope baseline for lifecycle events. The first\n // notification (the immediate getCurrentResult() emit below, or the\n // observer's first callback) establishes the baseline without firing —\n // so hydrated cache data on mount doesn't dispatch `finished.success`.\n // Subsequent increments of dataUpdatedAt / errorUpdatedAt are genuine\n // new fetches and do fire.\n let lastDataUpdatedAt = -1\n let lastErrorUpdatedAt = -1\n\n observerSubscriptions.get(observer)?.()\n observer.setOptions({\n ...observer.options,\n queryKey: key,\n enabled,\n // Only override refetchInterval when the user provided a reactive\n // Store — otherwise the static value (or function) from the observer\n // constructor wins.\n ...($reactiveRefetchInterval ? { refetchInterval } : {}),\n })\n\n const dispatch = (result: TResult) => {\n dispatchData(result.data)\n dispatchError(result.error)\n dispatchStatus(result.status)\n dispatchIsFetching(result.isFetching)\n dispatchFetchStatus(result.fetchStatus)\n dispatchIsPlaceholderData(result.isPlaceholderData)\n dispatchExtras?.(result)\n\n if (lastDataUpdatedAt === -1) {\n // Baseline — record current timestamps without emitting.\n lastDataUpdatedAt = result.dataUpdatedAt\n lastErrorUpdatedAt = result.errorUpdatedAt\n } else {\n // A newly-resolved successful fetch. Guard against placeholderData,\n // which carries status 'success' but never advances dataUpdatedAt.\n if (\n result.dataUpdatedAt > lastDataUpdatedAt &&\n result.status === 'success' &&\n !result.isPlaceholderData\n ) {\n lastDataUpdatedAt = result.dataUpdatedAt\n dispatchFinishedSuccess(result.data as TData)\n }\n if (\n result.errorUpdatedAt > lastErrorUpdatedAt &&\n result.status === 'error'\n ) {\n lastErrorUpdatedAt = result.errorUpdatedAt\n dispatchFinishedFailure(result.error as TError)\n }\n }\n }\n\n const unsubscribe = observer.subscribe(dispatch)\n observerSubscriptions.set(observer, unsubscribe)\n\n // Emit the current state immediately — observer.subscribe() may not\n // fire the callback synchronously when cached data already matches\n // the observer's initial result (e.g. staleTime + setQueryData).\n // This mirrors react-query's getOptimisticResult() on mount.\n dispatch(observer.getCurrentResult())\n\n return observer\n },\n })\n\n sample({ clock: mountFx.doneData, target: observerCreated })\n\n // Runs when key / enabled / reactive refetchInterval change after mount.\n // Only updates observer options — subscription + dispatchers were already\n // wired in mountFx.\n const updateObserverFx = attach({\n source: $observer,\n effect: (\n observer,\n {\n key,\n enabled,\n refetchInterval,\n }: {\n key: QueryKey\n enabled: boolean\n refetchInterval: number | false | undefined\n },\n ) => {\n if (!observer) return\n // Strip _defaulted and queryHash so defaultQueryOptions() recomputes\n // the hash for the new key. Without this, the old hash is preserved and\n // QueryObserver#updateQuery() finds the old query — no key switch, no fetch.\n const {\n _defaulted: _d,\n queryHash: _h,\n ...baseOptions\n } = observer.options as typeof observer.options & {\n _defaulted?: boolean\n queryHash?: string\n }\n observer.setOptions({\n ...baseOptions,\n queryKey: key,\n enabled,\n ...($reactiveRefetchInterval ? { refetchInterval } : {}),\n })\n },\n })\n\n const mounted = createEvent<void>()\n const unmounted = createEvent<void>()\n const $isMounted = createStore(false, {\n ...sidConfig(name, '$isMounted'),\n })\n .on(mounted, () => true)\n .on(unmounted, () => false)\n\n // Combine of all reactive options that drive observer.setOptions. Built once\n // so mountFx and updateObserverFx see the same shape. When the user didn't\n // pass a reactive `refetchInterval`, we fall back to a static-`false` store\n // (its emitted value is never read — the spread is guarded by the original\n // `$reactiveRefetchInterval` reference).\n const $observerOptions = combine({\n key: $resolvedKey,\n enabled: $enabled,\n refetchInterval:\n $reactiveRefetchInterval ??\n createStore<number | false | undefined>(false),\n })\n\n sample({\n clock: mounted,\n source: $observerOptions,\n target: mountFx,\n })\n\n sample({\n clock: $observerOptions,\n source: $observerOptions,\n filter: $isMounted,\n target: updateObserverFx,\n })\n\n // Single effect: tear down subscription + destroy + clear $observer.\n // Doing all three in one effect avoids ordering ambiguity vs. separate\n // events that all sample from `unmounted`.\n const observerDestroyed = createEvent<void>()\n $observer.on(observerDestroyed, () => null)\n\n const unmountFx = attach({\n source: $observer,\n effect: (observer) => {\n if (!observer) return\n observerSubscriptions.get(observer)?.()\n observerSubscriptions.delete(observer)\n observer.destroy()\n },\n })\n sample({ clock: unmounted, target: unmountFx })\n sample({ clock: unmountFx.finally, target: observerDestroyed })\n\n const refresh = createEvent<void>()\n const refreshFx = attach({\n source: { qc: $effectiveClient, key: $resolvedKey },\n effect: ({ qc, key }) => {\n if (!qc) return\n return qc.invalidateQueries({ queryKey: key })\n },\n })\n sample({ clock: refresh, target: refreshFx })\n\n return {\n $data,\n $error,\n $status,\n $isPending,\n $isFetching,\n $isSuccess,\n $isError,\n $isPlaceholderData,\n $fetchStatus,\n $observer,\n $queryClient: $effectiveClient,\n $resolvedKey,\n $enabled,\n refresh,\n mounted,\n unmounted,\n finished: {\n success: finishedSuccess,\n failure: finishedFailure,\n },\n ...(extras?.stores ?? ({} as TExtraStores)),\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Store, EventCallable } from 'effector';
|
|
1
|
+
import { Store, EventCallable, Event } from 'effector';
|
|
2
2
|
import { QueryKey, QueryStatus, FetchStatus, QueryClient } from '@tanstack/query-core';
|
|
3
3
|
import { EffectorQueryKey, StoreOrValue } from './types.cjs';
|
|
4
4
|
|
|
@@ -28,6 +28,17 @@ interface BaseObserverResult<TData, TError> {
|
|
|
28
28
|
isFetching: boolean;
|
|
29
29
|
fetchStatus: FetchStatus;
|
|
30
30
|
isPlaceholderData: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Timestamp (ms) of the last successful data resolution. Monotonically
|
|
33
|
+
* increases per successful fetch — used to detect newly-finished fetches
|
|
34
|
+
* for the `finished.success` lifecycle event.
|
|
35
|
+
*/
|
|
36
|
+
dataUpdatedAt: number;
|
|
37
|
+
/**
|
|
38
|
+
* Timestamp (ms) of the last error. Increments per failed fetch — used to
|
|
39
|
+
* detect newly-finished failures for the `finished.failure` lifecycle event.
|
|
40
|
+
*/
|
|
41
|
+
errorUpdatedAt: number;
|
|
31
42
|
}
|
|
32
43
|
interface BaseQueryStores<TData, TError, TObserver> {
|
|
33
44
|
$data: Store<TData | undefined>;
|
|
@@ -58,6 +69,17 @@ interface BaseQueryStores<TData, TError, TObserver> {
|
|
|
58
69
|
refresh: EventCallable<void>;
|
|
59
70
|
mounted: EventCallable<void>;
|
|
60
71
|
unmounted: EventCallable<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Lifecycle events for `sample`-driven reactions to fetch completion.
|
|
74
|
+
* `success` fires with the (post-`select`) data on every newly-finished
|
|
75
|
+
* successful fetch; `failure` fires with the error on every failed fetch.
|
|
76
|
+
* Neither fires for the baseline state observed on mount (e.g. hydrated
|
|
77
|
+
* cache) — they track *new* fetches, not initial observability.
|
|
78
|
+
*/
|
|
79
|
+
finished: {
|
|
80
|
+
success: Event<TData>;
|
|
81
|
+
failure: Event<TError>;
|
|
82
|
+
};
|
|
61
83
|
}
|
|
62
84
|
interface BaseQueryOptions {
|
|
63
85
|
queryKey: EffectorQueryKey;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Store, EventCallable } from 'effector';
|
|
1
|
+
import { Store, EventCallable, Event } from 'effector';
|
|
2
2
|
import { QueryKey, QueryStatus, FetchStatus, QueryClient } from '@tanstack/query-core';
|
|
3
3
|
import { EffectorQueryKey, StoreOrValue } from './types.js';
|
|
4
4
|
|
|
@@ -28,6 +28,17 @@ interface BaseObserverResult<TData, TError> {
|
|
|
28
28
|
isFetching: boolean;
|
|
29
29
|
fetchStatus: FetchStatus;
|
|
30
30
|
isPlaceholderData: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Timestamp (ms) of the last successful data resolution. Monotonically
|
|
33
|
+
* increases per successful fetch — used to detect newly-finished fetches
|
|
34
|
+
* for the `finished.success` lifecycle event.
|
|
35
|
+
*/
|
|
36
|
+
dataUpdatedAt: number;
|
|
37
|
+
/**
|
|
38
|
+
* Timestamp (ms) of the last error. Increments per failed fetch — used to
|
|
39
|
+
* detect newly-finished failures for the `finished.failure` lifecycle event.
|
|
40
|
+
*/
|
|
41
|
+
errorUpdatedAt: number;
|
|
31
42
|
}
|
|
32
43
|
interface BaseQueryStores<TData, TError, TObserver> {
|
|
33
44
|
$data: Store<TData | undefined>;
|
|
@@ -58,6 +69,17 @@ interface BaseQueryStores<TData, TError, TObserver> {
|
|
|
58
69
|
refresh: EventCallable<void>;
|
|
59
70
|
mounted: EventCallable<void>;
|
|
60
71
|
unmounted: EventCallable<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Lifecycle events for `sample`-driven reactions to fetch completion.
|
|
74
|
+
* `success` fires with the (post-`select`) data on every newly-finished
|
|
75
|
+
* successful fetch; `failure` fires with the error on every failed fetch.
|
|
76
|
+
* Neither fires for the baseline state observed on mount (e.g. hydrated
|
|
77
|
+
* cache) — they track *new* fetches, not initial observability.
|
|
78
|
+
*/
|
|
79
|
+
finished: {
|
|
80
|
+
success: Event<TData>;
|
|
81
|
+
failure: Event<TError>;
|
|
82
|
+
};
|
|
61
83
|
}
|
|
62
84
|
interface BaseQueryOptions {
|
|
63
85
|
queryKey: EffectorQueryKey;
|
package/dist/createBaseQuery.js
CHANGED
|
@@ -35,6 +35,8 @@ function createBaseQuery(explicitClient, options, config) {
|
|
|
35
35
|
const isFetchingUpdated = createEvent();
|
|
36
36
|
const fetchStatusUpdated = createEvent();
|
|
37
37
|
const isPlaceholderDataUpdated = createEvent();
|
|
38
|
+
const finishedSuccess = createEvent();
|
|
39
|
+
const finishedFailure = createEvent();
|
|
38
40
|
const $data = createStore(void 0, {
|
|
39
41
|
skipVoid: false,
|
|
40
42
|
...sidConfig(name, "$data")
|
|
@@ -87,7 +89,11 @@ function createBaseQuery(explicitClient, options, config) {
|
|
|
87
89
|
const dispatchIsPlaceholderData = scopeBind(isPlaceholderDataUpdated, {
|
|
88
90
|
safe: true
|
|
89
91
|
});
|
|
92
|
+
const dispatchFinishedSuccess = scopeBind(finishedSuccess, { safe: true });
|
|
93
|
+
const dispatchFinishedFailure = scopeBind(finishedFailure, { safe: true });
|
|
90
94
|
const dispatchExtras = extras?.bindDispatcher();
|
|
95
|
+
let lastDataUpdatedAt = -1;
|
|
96
|
+
let lastErrorUpdatedAt = -1;
|
|
91
97
|
observerSubscriptions.get(observer)?.();
|
|
92
98
|
observer.setOptions({
|
|
93
99
|
...observer.options,
|
|
@@ -106,6 +112,19 @@ function createBaseQuery(explicitClient, options, config) {
|
|
|
106
112
|
dispatchFetchStatus(result.fetchStatus);
|
|
107
113
|
dispatchIsPlaceholderData(result.isPlaceholderData);
|
|
108
114
|
dispatchExtras?.(result);
|
|
115
|
+
if (lastDataUpdatedAt === -1) {
|
|
116
|
+
lastDataUpdatedAt = result.dataUpdatedAt;
|
|
117
|
+
lastErrorUpdatedAt = result.errorUpdatedAt;
|
|
118
|
+
} else {
|
|
119
|
+
if (result.dataUpdatedAt > lastDataUpdatedAt && result.status === "success" && !result.isPlaceholderData) {
|
|
120
|
+
lastDataUpdatedAt = result.dataUpdatedAt;
|
|
121
|
+
dispatchFinishedSuccess(result.data);
|
|
122
|
+
}
|
|
123
|
+
if (result.errorUpdatedAt > lastErrorUpdatedAt && result.status === "error") {
|
|
124
|
+
lastErrorUpdatedAt = result.errorUpdatedAt;
|
|
125
|
+
dispatchFinishedFailure(result.error);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
109
128
|
};
|
|
110
129
|
const unsubscribe = observer.subscribe(dispatch);
|
|
111
130
|
observerSubscriptions.set(observer, unsubscribe);
|
|
@@ -195,6 +214,10 @@ function createBaseQuery(explicitClient, options, config) {
|
|
|
195
214
|
refresh,
|
|
196
215
|
mounted,
|
|
197
216
|
unmounted,
|
|
217
|
+
finished: {
|
|
218
|
+
success: finishedSuccess,
|
|
219
|
+
failure: finishedFailure
|
|
220
|
+
},
|
|
198
221
|
...extras?.stores ?? {}
|
|
199
222
|
};
|
|
200
223
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/createBaseQuery.ts"],"names":[],"mappings":"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","file":"createBaseQuery.js","sourcesContent":["import {\n attach,\n combine,\n createEvent,\n createStore,\n sample,\n scopeBind,\n} from 'effector'\nimport type { EventCallable, Store } from 'effector'\nimport type {\n FetchStatus,\n QueryClient,\n QueryKey,\n QueryStatus,\n} from '@tanstack/query-core'\nimport { $queryClient } from './queryClient'\nimport { resolveEnabled, resolveKey } from './resolve'\nimport type { EffectorQueryKey, StoreOrValue } from './types'\n\n/**\n * The minimal shape of an observer that createBaseQuery knows how to drive.\n * Both QueryObserver and InfiniteQueryObserver satisfy this.\n */\nexport interface BaseObserverLike<TResult> {\n options: { queryKey: QueryKey; _defaulted?: boolean; queryHash?: string }\n setOptions(options: any): void\n subscribe(listener: (result: TResult) => void): () => void\n getCurrentResult(): TResult\n destroy(): void\n}\n\n/**\n * The subset of observer result fields that createBaseQuery wires up\n * into stores common to all query flavors.\n */\nexport interface BaseObserverResult<TData, TError> {\n data: TData | undefined\n error: TError | null\n status: QueryStatus\n isFetching: boolean\n fetchStatus: FetchStatus\n isPlaceholderData: boolean\n}\n\nexport interface BaseQueryStores<TData, TError, TObserver> {\n $data: Store<TData | undefined>\n $error: Store<TError | null>\n $status: Store<QueryStatus>\n $isPending: Store<boolean>\n $isFetching: Store<boolean>\n $isSuccess: Store<boolean>\n $isError: Store<boolean>\n $isPlaceholderData: Store<boolean>\n $fetchStatus: Store<FetchStatus>\n /**\n * Per-scope observer. Populated on first `mounted()` via attach over\n * `$queryClient` — every fork scope has its own Observer instance bound\n * to the scope's QueryClient. Read scope-aware via `useUnit($observer)`.\n */\n $observer: Store<TObserver | null>\n /**\n * Resolved QueryClient store. If the factory was called with an explicit\n * client, this is a frozen store of that client. Otherwise it's the global\n * `$queryClient`, which honors `fork({ values })` overrides.\n */\n $queryClient: Store<QueryClient | null>\n /** Internal — used by the React suspense hooks. */\n $resolvedKey: Store<QueryKey>\n /** Internal — used by the React suspense hooks. */\n $enabled: Store<boolean>\n refresh: EventCallable<void>\n mounted: EventCallable<void>\n unmounted: EventCallable<void>\n}\n\nexport interface BaseQueryOptions {\n queryKey: EffectorQueryKey\n enabled?: StoreOrValue<boolean>\n /**\n * Pre-resolved reactive `refetchInterval`. The per-flavor factory extracts\n * the original option, and — if it's a Store — passes the Store here while\n * stripping the value from the observer constructor options. Static values\n * and function forms continue to flow through `restOptions` to the\n * observer.\n */\n reactiveRefetchInterval?: Store<number | false | undefined>\n name?: string\n}\n\nconst SID_PREFIX = '@tanstack/query-effector'\n\nconst warnedNames = new Set<string>()\n\nexport function warnMissingName(role: string): void {\n if (typeof process === 'undefined' || process.env.NODE_ENV === 'production') {\n return\n }\n if (warnedNames.has(role)) return\n warnedNames.add(role)\n // eslint-disable-next-line no-console\n console.warn(\n `[@tanstack/query-effector] ${role} created without a \"name\" — internal stores will be excluded from serialize(scope). ` +\n `Pass a unique \"name\" to enable SSR via fork({ values: serialize(scope) }).`,\n )\n}\n\nexport function sidConfig(\n name: string | undefined,\n role: string,\n): { sid: string; name: string } | {} {\n if (!name) return {}\n return {\n sid: `${SID_PREFIX}.${name}.${role}`,\n name: `${name}.${role}`,\n }\n}\n\nexport interface ExtrasSetup<TResult, TObserver, TExtraStores> {\n /** Extra stores/events merged into the final result object. */\n stores: TExtraStores\n /**\n * Invoked inside the mount effect. Must scope-bind any extra events\n * and return a function that dispatches extra fields from the observer\n * result. The returned dispatcher is called on every subscription\n * notification alongside the base dispatcher.\n */\n bindDispatcher: () => (result: TResult) => void\n /**\n * Lets a flavor wire its own per-observer effects (e.g.\n * fetchNextPage / fetchPreviousPage for infinite queries). Receives the\n * per-scope `$observer` store so the flavor can build attach-based\n * effects that resolve the observer from the current scope.\n */\n setupEffects?: (params: { $observer: Store<TObserver | null> }) => void\n}\n\nexport interface CreateBaseQueryConfig<\n TData,\n TError,\n TResult extends BaseObserverResult<TData, TError>,\n TObserver extends BaseObserverLike<TResult>,\n TExtraStores,\n> {\n /** Build the observer for the current scope. Receives the resolved client. */\n createObserver: (\n queryClient: QueryClient,\n initial: { queryKey: QueryKey; enabled: boolean },\n ) => TObserver\n /**\n * Hook for query flavors that need additional stores/events (e.g. infinite\n * query's hasNextPage, fetchNextPage). Called once at factory time.\n */\n setupExtras?: () => ExtrasSetup<TResult, TObserver, TExtraStores>\n}\n\nexport function createBaseQuery<\n TData,\n TError,\n TResult extends BaseObserverResult<TData, TError>,\n TObserver extends BaseObserverLike<TResult>,\n TExtraStores = {},\n>(\n explicitClient: QueryClient | null,\n options: BaseQueryOptions,\n config: CreateBaseQueryConfig<TData, TError, TResult, TObserver, TExtraStores>,\n): BaseQueryStores<TData, TError, TObserver> & TExtraStores {\n const { name, reactiveRefetchInterval: $reactiveRefetchInterval } = options\n const $resolvedKey = resolveKey(options.queryKey)\n const $enabled = resolveEnabled(options.enabled)\n\n // If an explicit client is passed, the factory is locked to it. fork()\n // values cannot override the captured value because $effectiveClient is a\n // brand-new store (not the global one). When no explicit client is passed,\n // we route through $queryClient — which respects fork({ values }) for\n // per-scope isolation.\n const $effectiveClient: Store<QueryClient | null> = explicitClient\n ? createStore(explicitClient as QueryClient | null, {\n serialize: 'ignore',\n })\n : $queryClient\n\n const dataUpdated = createEvent<TData | undefined>()\n const errorUpdated = createEvent<TError | null>()\n const statusUpdated = createEvent<QueryStatus>()\n const isFetchingUpdated = createEvent<boolean>()\n const fetchStatusUpdated = createEvent<FetchStatus>()\n const isPlaceholderDataUpdated = createEvent<boolean>()\n\n const $data = createStore<TData | undefined>(undefined, {\n skipVoid: false,\n ...sidConfig(name, '$data'),\n }).on(dataUpdated, (_, v) => v)\n const $error = createStore<TError | null>(null, {\n skipVoid: false,\n ...sidConfig(name, '$error'),\n }).on(errorUpdated, (_, v) => v)\n const $status = createStore<QueryStatus>('pending', {\n ...sidConfig(name, '$status'),\n }).on(statusUpdated, (_, v) => v)\n const $isFetching = createStore(false, {\n ...sidConfig(name, '$isFetching'),\n }).on(isFetchingUpdated, (_, v) => v)\n const $fetchStatus = createStore<FetchStatus>('idle', {\n ...sidConfig(name, '$fetchStatus'),\n }).on(fetchStatusUpdated, (_, v) => v)\n const $isPlaceholderData = createStore(false, {\n ...sidConfig(name, '$isPlaceholderData'),\n }).on(isPlaceholderDataUpdated, (_, v) => v)\n\n // Derived stores via .map don't accept sid in their config — effector's\n // serialize() captures source-store values, and derived stores recompute\n // automatically on the client after fork({ values }).\n const $isPending = $status.map((s) => s === 'pending')\n const $isSuccess = $status.map((s) => s === 'success')\n const $isError = $status.map((s) => s === 'error')\n\n // Per-scope observer storage. Carries runtime-only references\n // (subscriptions, callbacks) — must never participate in serialization.\n const $observer = createStore<TObserver | null>(null, {\n serialize: 'ignore',\n })\n const observerCreated = createEvent<TObserver>()\n $observer.on(observerCreated, (_, obs) => obs)\n\n // Per-observer unsubscribe handles. WeakMap so abandoned observers (e.g.\n // a scope that was discarded without unmount) are GC'able.\n const observerSubscriptions = new WeakMap<TObserver, () => void>()\n\n const extras = config.setupExtras?.()\n extras?.setupEffects?.({ $observer })\n\n // Runs once per mount. Creates the observer for the current scope (if not\n // yet created) and attaches the subscription. scopeBind({ safe: true })\n // reliably captures the fork scope here because this effect is triggered\n // directly from allSettled(mounted). Bound dispatchers are captured in the\n // observer callback's closure and reused for all subsequent notifications\n // (including after key/enabled changes).\n const mountFx = attach({\n source: { qc: $effectiveClient, observer: $observer },\n effect: (\n { qc, observer: existingObserver },\n {\n key,\n enabled,\n refetchInterval,\n }: {\n key: QueryKey\n enabled: boolean\n refetchInterval: number | false | undefined\n },\n ) => {\n if (!qc) {\n throw new Error(\n '[@tanstack/query-effector] No QueryClient is set. Call setQueryClient(qc) before mounting, ' +\n 'pass it to fork({ values: [[$queryClient, qc]] }), or pass it explicitly to the factory.',\n )\n }\n\n const observer =\n existingObserver ??\n config.createObserver(qc, { queryKey: key, enabled })\n\n const dispatchData = scopeBind(dataUpdated, { safe: true })\n const dispatchError = scopeBind(errorUpdated, { safe: true })\n const dispatchStatus = scopeBind(statusUpdated, { safe: true })\n const dispatchIsFetching = scopeBind(isFetchingUpdated, { safe: true })\n const dispatchFetchStatus = scopeBind(fetchStatusUpdated, { safe: true })\n const dispatchIsPlaceholderData = scopeBind(isPlaceholderDataUpdated, {\n safe: true,\n })\n const dispatchExtras = extras?.bindDispatcher()\n\n observerSubscriptions.get(observer)?.()\n observer.setOptions({\n ...observer.options,\n queryKey: key,\n enabled,\n // Only override refetchInterval when the user provided a reactive\n // Store — otherwise the static value (or function) from the observer\n // constructor wins.\n ...($reactiveRefetchInterval ? { refetchInterval } : {}),\n })\n\n const dispatch = (result: TResult) => {\n dispatchData(result.data)\n dispatchError(result.error)\n dispatchStatus(result.status)\n dispatchIsFetching(result.isFetching)\n dispatchFetchStatus(result.fetchStatus)\n dispatchIsPlaceholderData(result.isPlaceholderData)\n dispatchExtras?.(result)\n }\n\n const unsubscribe = observer.subscribe(dispatch)\n observerSubscriptions.set(observer, unsubscribe)\n\n // Emit the current state immediately — observer.subscribe() may not\n // fire the callback synchronously when cached data already matches\n // the observer's initial result (e.g. staleTime + setQueryData).\n // This mirrors react-query's getOptimisticResult() on mount.\n dispatch(observer.getCurrentResult())\n\n return observer\n },\n })\n\n sample({ clock: mountFx.doneData, target: observerCreated })\n\n // Runs when key / enabled / reactive refetchInterval change after mount.\n // Only updates observer options — subscription + dispatchers were already\n // wired in mountFx.\n const updateObserverFx = attach({\n source: $observer,\n effect: (\n observer,\n {\n key,\n enabled,\n refetchInterval,\n }: {\n key: QueryKey\n enabled: boolean\n refetchInterval: number | false | undefined\n },\n ) => {\n if (!observer) return\n // Strip _defaulted and queryHash so defaultQueryOptions() recomputes\n // the hash for the new key. Without this, the old hash is preserved and\n // QueryObserver#updateQuery() finds the old query — no key switch, no fetch.\n const {\n _defaulted: _d,\n queryHash: _h,\n ...baseOptions\n } = observer.options as typeof observer.options & {\n _defaulted?: boolean\n queryHash?: string\n }\n observer.setOptions({\n ...baseOptions,\n queryKey: key,\n enabled,\n ...($reactiveRefetchInterval ? { refetchInterval } : {}),\n })\n },\n })\n\n const mounted = createEvent<void>()\n const unmounted = createEvent<void>()\n const $isMounted = createStore(false, {\n ...sidConfig(name, '$isMounted'),\n })\n .on(mounted, () => true)\n .on(unmounted, () => false)\n\n // Combine of all reactive options that drive observer.setOptions. Built once\n // so mountFx and updateObserverFx see the same shape. When the user didn't\n // pass a reactive `refetchInterval`, we fall back to a static-`false` store\n // (its emitted value is never read — the spread is guarded by the original\n // `$reactiveRefetchInterval` reference).\n const $observerOptions = combine({\n key: $resolvedKey,\n enabled: $enabled,\n refetchInterval:\n $reactiveRefetchInterval ??\n createStore<number | false | undefined>(false),\n })\n\n sample({\n clock: mounted,\n source: $observerOptions,\n target: mountFx,\n })\n\n sample({\n clock: $observerOptions,\n source: $observerOptions,\n filter: $isMounted,\n target: updateObserverFx,\n })\n\n // Single effect: tear down subscription + destroy + clear $observer.\n // Doing all three in one effect avoids ordering ambiguity vs. separate\n // events that all sample from `unmounted`.\n const observerDestroyed = createEvent<void>()\n $observer.on(observerDestroyed, () => null)\n\n const unmountFx = attach({\n source: $observer,\n effect: (observer) => {\n if (!observer) return\n observerSubscriptions.get(observer)?.()\n observerSubscriptions.delete(observer)\n observer.destroy()\n },\n })\n sample({ clock: unmounted, target: unmountFx })\n sample({ clock: unmountFx.finally, target: observerDestroyed })\n\n const refresh = createEvent<void>()\n const refreshFx = attach({\n source: { qc: $effectiveClient, key: $resolvedKey },\n effect: ({ qc, key }) => {\n if (!qc) return\n return qc.invalidateQueries({ queryKey: key })\n },\n })\n sample({ clock: refresh, target: refreshFx })\n\n return {\n $data,\n $error,\n $status,\n $isPending,\n $isFetching,\n $isSuccess,\n $isError,\n $isPlaceholderData,\n $fetchStatus,\n $observer,\n $queryClient: $effectiveClient,\n $resolvedKey,\n $enabled,\n refresh,\n mounted,\n unmounted,\n ...(extras?.stores ?? ({} as TExtraStores)),\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/createBaseQuery.ts"],"names":[],"mappings":"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","file":"createBaseQuery.js","sourcesContent":["import {\n attach,\n combine,\n createEvent,\n createStore,\n sample,\n scopeBind,\n} from 'effector'\nimport type { Event, EventCallable, Store } from 'effector'\nimport type {\n FetchStatus,\n QueryClient,\n QueryKey,\n QueryStatus,\n} from '@tanstack/query-core'\nimport { $queryClient } from './queryClient'\nimport { resolveEnabled, resolveKey } from './resolve'\nimport type { EffectorQueryKey, StoreOrValue } from './types'\n\n/**\n * The minimal shape of an observer that createBaseQuery knows how to drive.\n * Both QueryObserver and InfiniteQueryObserver satisfy this.\n */\nexport interface BaseObserverLike<TResult> {\n options: { queryKey: QueryKey; _defaulted?: boolean; queryHash?: string }\n setOptions(options: any): void\n subscribe(listener: (result: TResult) => void): () => void\n getCurrentResult(): TResult\n destroy(): void\n}\n\n/**\n * The subset of observer result fields that createBaseQuery wires up\n * into stores common to all query flavors.\n */\nexport interface BaseObserverResult<TData, TError> {\n data: TData | undefined\n error: TError | null\n status: QueryStatus\n isFetching: boolean\n fetchStatus: FetchStatus\n isPlaceholderData: boolean\n /**\n * Timestamp (ms) of the last successful data resolution. Monotonically\n * increases per successful fetch — used to detect newly-finished fetches\n * for the `finished.success` lifecycle event.\n */\n dataUpdatedAt: number\n /**\n * Timestamp (ms) of the last error. Increments per failed fetch — used to\n * detect newly-finished failures for the `finished.failure` lifecycle event.\n */\n errorUpdatedAt: number\n}\n\nexport interface BaseQueryStores<TData, TError, TObserver> {\n $data: Store<TData | undefined>\n $error: Store<TError | null>\n $status: Store<QueryStatus>\n $isPending: Store<boolean>\n $isFetching: Store<boolean>\n $isSuccess: Store<boolean>\n $isError: Store<boolean>\n $isPlaceholderData: Store<boolean>\n $fetchStatus: Store<FetchStatus>\n /**\n * Per-scope observer. Populated on first `mounted()` via attach over\n * `$queryClient` — every fork scope has its own Observer instance bound\n * to the scope's QueryClient. Read scope-aware via `useUnit($observer)`.\n */\n $observer: Store<TObserver | null>\n /**\n * Resolved QueryClient store. If the factory was called with an explicit\n * client, this is a frozen store of that client. Otherwise it's the global\n * `$queryClient`, which honors `fork({ values })` overrides.\n */\n $queryClient: Store<QueryClient | null>\n /** Internal — used by the React suspense hooks. */\n $resolvedKey: Store<QueryKey>\n /** Internal — used by the React suspense hooks. */\n $enabled: Store<boolean>\n refresh: EventCallable<void>\n mounted: EventCallable<void>\n unmounted: EventCallable<void>\n /**\n * Lifecycle events for `sample`-driven reactions to fetch completion.\n * `success` fires with the (post-`select`) data on every newly-finished\n * successful fetch; `failure` fires with the error on every failed fetch.\n * Neither fires for the baseline state observed on mount (e.g. hydrated\n * cache) — they track *new* fetches, not initial observability.\n */\n finished: {\n success: Event<TData>\n failure: Event<TError>\n }\n}\n\nexport interface BaseQueryOptions {\n queryKey: EffectorQueryKey\n enabled?: StoreOrValue<boolean>\n /**\n * Pre-resolved reactive `refetchInterval`. The per-flavor factory extracts\n * the original option, and — if it's a Store — passes the Store here while\n * stripping the value from the observer constructor options. Static values\n * and function forms continue to flow through `restOptions` to the\n * observer.\n */\n reactiveRefetchInterval?: Store<number | false | undefined>\n name?: string\n}\n\nconst SID_PREFIX = '@tanstack/query-effector'\n\nconst warnedNames = new Set<string>()\n\nexport function warnMissingName(role: string): void {\n if (typeof process === 'undefined' || process.env.NODE_ENV === 'production') {\n return\n }\n if (warnedNames.has(role)) return\n warnedNames.add(role)\n // eslint-disable-next-line no-console\n console.warn(\n `[@tanstack/query-effector] ${role} created without a \"name\" — internal stores will be excluded from serialize(scope). ` +\n `Pass a unique \"name\" to enable SSR via fork({ values: serialize(scope) }).`,\n )\n}\n\nexport function sidConfig(\n name: string | undefined,\n role: string,\n): { sid: string; name: string } | {} {\n if (!name) return {}\n return {\n sid: `${SID_PREFIX}.${name}.${role}`,\n name: `${name}.${role}`,\n }\n}\n\nexport interface ExtrasSetup<TResult, TObserver, TExtraStores> {\n /** Extra stores/events merged into the final result object. */\n stores: TExtraStores\n /**\n * Invoked inside the mount effect. Must scope-bind any extra events\n * and return a function that dispatches extra fields from the observer\n * result. The returned dispatcher is called on every subscription\n * notification alongside the base dispatcher.\n */\n bindDispatcher: () => (result: TResult) => void\n /**\n * Lets a flavor wire its own per-observer effects (e.g.\n * fetchNextPage / fetchPreviousPage for infinite queries). Receives the\n * per-scope `$observer` store so the flavor can build attach-based\n * effects that resolve the observer from the current scope.\n */\n setupEffects?: (params: { $observer: Store<TObserver | null> }) => void\n}\n\nexport interface CreateBaseQueryConfig<\n TData,\n TError,\n TResult extends BaseObserverResult<TData, TError>,\n TObserver extends BaseObserverLike<TResult>,\n TExtraStores,\n> {\n /** Build the observer for the current scope. Receives the resolved client. */\n createObserver: (\n queryClient: QueryClient,\n initial: { queryKey: QueryKey; enabled: boolean },\n ) => TObserver\n /**\n * Hook for query flavors that need additional stores/events (e.g. infinite\n * query's hasNextPage, fetchNextPage). Called once at factory time.\n */\n setupExtras?: () => ExtrasSetup<TResult, TObserver, TExtraStores>\n}\n\nexport function createBaseQuery<\n TData,\n TError,\n TResult extends BaseObserverResult<TData, TError>,\n TObserver extends BaseObserverLike<TResult>,\n TExtraStores = {},\n>(\n explicitClient: QueryClient | null,\n options: BaseQueryOptions,\n config: CreateBaseQueryConfig<TData, TError, TResult, TObserver, TExtraStores>,\n): BaseQueryStores<TData, TError, TObserver> & TExtraStores {\n const { name, reactiveRefetchInterval: $reactiveRefetchInterval } = options\n const $resolvedKey = resolveKey(options.queryKey)\n const $enabled = resolveEnabled(options.enabled)\n\n // If an explicit client is passed, the factory is locked to it. fork()\n // values cannot override the captured value because $effectiveClient is a\n // brand-new store (not the global one). When no explicit client is passed,\n // we route through $queryClient — which respects fork({ values }) for\n // per-scope isolation.\n const $effectiveClient: Store<QueryClient | null> = explicitClient\n ? createStore(explicitClient as QueryClient | null, {\n serialize: 'ignore',\n })\n : $queryClient\n\n const dataUpdated = createEvent<TData | undefined>()\n const errorUpdated = createEvent<TError | null>()\n const statusUpdated = createEvent<QueryStatus>()\n const isFetchingUpdated = createEvent<boolean>()\n const fetchStatusUpdated = createEvent<FetchStatus>()\n const isPlaceholderDataUpdated = createEvent<boolean>()\n\n // Lifecycle events. Created once at factory time; dispatched per-scope via\n // scopeBind inside the mount effect so `allSettled` / fork isolation work.\n const finishedSuccess = createEvent<TData>()\n const finishedFailure = createEvent<TError>()\n\n const $data = createStore<TData | undefined>(undefined, {\n skipVoid: false,\n ...sidConfig(name, '$data'),\n }).on(dataUpdated, (_, v) => v)\n const $error = createStore<TError | null>(null, {\n skipVoid: false,\n ...sidConfig(name, '$error'),\n }).on(errorUpdated, (_, v) => v)\n const $status = createStore<QueryStatus>('pending', {\n ...sidConfig(name, '$status'),\n }).on(statusUpdated, (_, v) => v)\n const $isFetching = createStore(false, {\n ...sidConfig(name, '$isFetching'),\n }).on(isFetchingUpdated, (_, v) => v)\n const $fetchStatus = createStore<FetchStatus>('idle', {\n ...sidConfig(name, '$fetchStatus'),\n }).on(fetchStatusUpdated, (_, v) => v)\n const $isPlaceholderData = createStore(false, {\n ...sidConfig(name, '$isPlaceholderData'),\n }).on(isPlaceholderDataUpdated, (_, v) => v)\n\n // Derived stores via .map don't accept sid in their config — effector's\n // serialize() captures source-store values, and derived stores recompute\n // automatically on the client after fork({ values }).\n const $isPending = $status.map((s) => s === 'pending')\n const $isSuccess = $status.map((s) => s === 'success')\n const $isError = $status.map((s) => s === 'error')\n\n // Per-scope observer storage. Carries runtime-only references\n // (subscriptions, callbacks) — must never participate in serialization.\n const $observer = createStore<TObserver | null>(null, {\n serialize: 'ignore',\n })\n const observerCreated = createEvent<TObserver>()\n $observer.on(observerCreated, (_, obs) => obs)\n\n // Per-observer unsubscribe handles. WeakMap so abandoned observers (e.g.\n // a scope that was discarded without unmount) are GC'able.\n const observerSubscriptions = new WeakMap<TObserver, () => void>()\n\n const extras = config.setupExtras?.()\n extras?.setupEffects?.({ $observer })\n\n // Runs once per mount. Creates the observer for the current scope (if not\n // yet created) and attaches the subscription. scopeBind({ safe: true })\n // reliably captures the fork scope here because this effect is triggered\n // directly from allSettled(mounted). Bound dispatchers are captured in the\n // observer callback's closure and reused for all subsequent notifications\n // (including after key/enabled changes).\n const mountFx = attach({\n source: { qc: $effectiveClient, observer: $observer },\n effect: (\n { qc, observer: existingObserver },\n {\n key,\n enabled,\n refetchInterval,\n }: {\n key: QueryKey\n enabled: boolean\n refetchInterval: number | false | undefined\n },\n ) => {\n if (!qc) {\n throw new Error(\n '[@tanstack/query-effector] No QueryClient is set. Call setQueryClient(qc) before mounting, ' +\n 'pass it to fork({ values: [[$queryClient, qc]] }), or pass it explicitly to the factory.',\n )\n }\n\n const observer =\n existingObserver ??\n config.createObserver(qc, { queryKey: key, enabled })\n\n const dispatchData = scopeBind(dataUpdated, { safe: true })\n const dispatchError = scopeBind(errorUpdated, { safe: true })\n const dispatchStatus = scopeBind(statusUpdated, { safe: true })\n const dispatchIsFetching = scopeBind(isFetchingUpdated, { safe: true })\n const dispatchFetchStatus = scopeBind(fetchStatusUpdated, { safe: true })\n const dispatchIsPlaceholderData = scopeBind(isPlaceholderDataUpdated, {\n safe: true,\n })\n const dispatchFinishedSuccess = scopeBind(finishedSuccess, { safe: true })\n const dispatchFinishedFailure = scopeBind(finishedFailure, { safe: true })\n const dispatchExtras = extras?.bindDispatcher()\n\n // Per-mount, per-scope baseline for lifecycle events. The first\n // notification (the immediate getCurrentResult() emit below, or the\n // observer's first callback) establishes the baseline without firing —\n // so hydrated cache data on mount doesn't dispatch `finished.success`.\n // Subsequent increments of dataUpdatedAt / errorUpdatedAt are genuine\n // new fetches and do fire.\n let lastDataUpdatedAt = -1\n let lastErrorUpdatedAt = -1\n\n observerSubscriptions.get(observer)?.()\n observer.setOptions({\n ...observer.options,\n queryKey: key,\n enabled,\n // Only override refetchInterval when the user provided a reactive\n // Store — otherwise the static value (or function) from the observer\n // constructor wins.\n ...($reactiveRefetchInterval ? { refetchInterval } : {}),\n })\n\n const dispatch = (result: TResult) => {\n dispatchData(result.data)\n dispatchError(result.error)\n dispatchStatus(result.status)\n dispatchIsFetching(result.isFetching)\n dispatchFetchStatus(result.fetchStatus)\n dispatchIsPlaceholderData(result.isPlaceholderData)\n dispatchExtras?.(result)\n\n if (lastDataUpdatedAt === -1) {\n // Baseline — record current timestamps without emitting.\n lastDataUpdatedAt = result.dataUpdatedAt\n lastErrorUpdatedAt = result.errorUpdatedAt\n } else {\n // A newly-resolved successful fetch. Guard against placeholderData,\n // which carries status 'success' but never advances dataUpdatedAt.\n if (\n result.dataUpdatedAt > lastDataUpdatedAt &&\n result.status === 'success' &&\n !result.isPlaceholderData\n ) {\n lastDataUpdatedAt = result.dataUpdatedAt\n dispatchFinishedSuccess(result.data as TData)\n }\n if (\n result.errorUpdatedAt > lastErrorUpdatedAt &&\n result.status === 'error'\n ) {\n lastErrorUpdatedAt = result.errorUpdatedAt\n dispatchFinishedFailure(result.error as TError)\n }\n }\n }\n\n const unsubscribe = observer.subscribe(dispatch)\n observerSubscriptions.set(observer, unsubscribe)\n\n // Emit the current state immediately — observer.subscribe() may not\n // fire the callback synchronously when cached data already matches\n // the observer's initial result (e.g. staleTime + setQueryData).\n // This mirrors react-query's getOptimisticResult() on mount.\n dispatch(observer.getCurrentResult())\n\n return observer\n },\n })\n\n sample({ clock: mountFx.doneData, target: observerCreated })\n\n // Runs when key / enabled / reactive refetchInterval change after mount.\n // Only updates observer options — subscription + dispatchers were already\n // wired in mountFx.\n const updateObserverFx = attach({\n source: $observer,\n effect: (\n observer,\n {\n key,\n enabled,\n refetchInterval,\n }: {\n key: QueryKey\n enabled: boolean\n refetchInterval: number | false | undefined\n },\n ) => {\n if (!observer) return\n // Strip _defaulted and queryHash so defaultQueryOptions() recomputes\n // the hash for the new key. Without this, the old hash is preserved and\n // QueryObserver#updateQuery() finds the old query — no key switch, no fetch.\n const {\n _defaulted: _d,\n queryHash: _h,\n ...baseOptions\n } = observer.options as typeof observer.options & {\n _defaulted?: boolean\n queryHash?: string\n }\n observer.setOptions({\n ...baseOptions,\n queryKey: key,\n enabled,\n ...($reactiveRefetchInterval ? { refetchInterval } : {}),\n })\n },\n })\n\n const mounted = createEvent<void>()\n const unmounted = createEvent<void>()\n const $isMounted = createStore(false, {\n ...sidConfig(name, '$isMounted'),\n })\n .on(mounted, () => true)\n .on(unmounted, () => false)\n\n // Combine of all reactive options that drive observer.setOptions. Built once\n // so mountFx and updateObserverFx see the same shape. When the user didn't\n // pass a reactive `refetchInterval`, we fall back to a static-`false` store\n // (its emitted value is never read — the spread is guarded by the original\n // `$reactiveRefetchInterval` reference).\n const $observerOptions = combine({\n key: $resolvedKey,\n enabled: $enabled,\n refetchInterval:\n $reactiveRefetchInterval ??\n createStore<number | false | undefined>(false),\n })\n\n sample({\n clock: mounted,\n source: $observerOptions,\n target: mountFx,\n })\n\n sample({\n clock: $observerOptions,\n source: $observerOptions,\n filter: $isMounted,\n target: updateObserverFx,\n })\n\n // Single effect: tear down subscription + destroy + clear $observer.\n // Doing all three in one effect avoids ordering ambiguity vs. separate\n // events that all sample from `unmounted`.\n const observerDestroyed = createEvent<void>()\n $observer.on(observerDestroyed, () => null)\n\n const unmountFx = attach({\n source: $observer,\n effect: (observer) => {\n if (!observer) return\n observerSubscriptions.get(observer)?.()\n observerSubscriptions.delete(observer)\n observer.destroy()\n },\n })\n sample({ clock: unmounted, target: unmountFx })\n sample({ clock: unmountFx.finally, target: observerDestroyed })\n\n const refresh = createEvent<void>()\n const refreshFx = attach({\n source: { qc: $effectiveClient, key: $resolvedKey },\n effect: ({ qc, key }) => {\n if (!qc) return\n return qc.invalidateQueries({ queryKey: key })\n },\n })\n sample({ clock: refresh, target: refreshFx })\n\n return {\n $data,\n $error,\n $status,\n $isPending,\n $isFetching,\n $isSuccess,\n $isError,\n $isPlaceholderData,\n $fetchStatus,\n $observer,\n $queryClient: $effectiveClient,\n $resolvedKey,\n $enabled,\n refresh,\n mounted,\n unmounted,\n finished: {\n success: finishedSuccess,\n failure: finishedFailure,\n },\n ...(extras?.stores ?? ({} as TExtraStores)),\n }\n}\n"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var effector = require('effector');
|
|
4
|
+
var queryClient_cjs = require('./queryClient.cjs');
|
|
5
|
+
var resolve_cjs = require('./resolve.cjs');
|
|
6
|
+
|
|
7
|
+
// src/createCacheAction.ts
|
|
8
|
+
function buildCacheAction(action, explicitClient, options) {
|
|
9
|
+
const { queryKey, ...restFilters } = options;
|
|
10
|
+
const $effectiveClient = explicitClient ? effector.createStore(explicitClient, {
|
|
11
|
+
serialize: "ignore"
|
|
12
|
+
}) : queryClient_cjs.$queryClient;
|
|
13
|
+
const $resolvedKey = queryKey ? resolve_cjs.resolveKey(queryKey) : effector.createStore(void 0, { skipVoid: false });
|
|
14
|
+
const run = effector.createEvent();
|
|
15
|
+
const runFx = effector.attach({
|
|
16
|
+
source: { qc: $effectiveClient, key: $resolvedKey },
|
|
17
|
+
effect: ({ qc, key }) => {
|
|
18
|
+
if (!qc) return;
|
|
19
|
+
const filters = { ...restFilters };
|
|
20
|
+
if (key !== void 0) filters.queryKey = key;
|
|
21
|
+
return action(qc, filters);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
effector.sample({ clock: run, target: runFx });
|
|
25
|
+
return run;
|
|
26
|
+
}
|
|
27
|
+
function parseArgs(arg1, arg2) {
|
|
28
|
+
if (arg2 !== void 0) return [arg1, arg2];
|
|
29
|
+
return [null, arg1];
|
|
30
|
+
}
|
|
31
|
+
function createCancel(arg1, arg2) {
|
|
32
|
+
const [explicitClient, options] = parseArgs(arg1, arg2);
|
|
33
|
+
return buildCacheAction(
|
|
34
|
+
(qc, filters) => qc.cancelQueries(filters),
|
|
35
|
+
explicitClient,
|
|
36
|
+
options
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
function createRemove(arg1, arg2) {
|
|
40
|
+
const [explicitClient, options] = parseArgs(arg1, arg2);
|
|
41
|
+
return buildCacheAction(
|
|
42
|
+
(qc, filters) => qc.removeQueries(filters),
|
|
43
|
+
explicitClient,
|
|
44
|
+
options
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
function createReset(arg1, arg2) {
|
|
48
|
+
const [explicitClient, options] = parseArgs(arg1, arg2);
|
|
49
|
+
return buildCacheAction(
|
|
50
|
+
(qc, filters) => qc.resetQueries(filters),
|
|
51
|
+
explicitClient,
|
|
52
|
+
options
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
exports.createCancel = createCancel;
|
|
57
|
+
exports.createRemove = createRemove;
|
|
58
|
+
exports.createReset = createReset;
|
|
59
|
+
//# sourceMappingURL=createCacheAction.cjs.map
|
|
60
|
+
//# sourceMappingURL=createCacheAction.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/createCacheAction.ts"],"names":["createStore","$queryClient","resolveKey","createEvent","attach","sample"],"mappings":";;;;;;;AA2CA,SAAS,gBAAA,CACP,MAAA,EACA,cAAA,EACA,OAAA,EACqB;AACrB,EAAA,MAAM,EAAE,QAAA,EAAU,GAAG,WAAA,EAAY,GAAI,OAAA;AAKrC,EAAA,MAAM,gBAAA,GAA8C,cAAA,GAChDA,oBAAA,CAAY,cAAA,EAAsC;AAAA,IAChD,SAAA,EAAW;AAAA,GACZ,CAAA,GACDC,4BAAA;AAIJ,EAAA,MAAM,YAAA,GAA4C,QAAA,GAC9CC,sBAAA,CAAW,QAAQ,CAAA,GACnBF,qBAAkC,MAAA,EAAW,EAAE,QAAA,EAAU,KAAA,EAAO,CAAA;AAEpE,EAAA,MAAM,MAAMG,oBAAA,EAAkB;AAE9B,EAAA,MAAM,QAAQC,eAAA,CAAO;AAAA,IACnB,MAAA,EAAQ,EAAE,EAAA,EAAI,gBAAA,EAAkB,KAAK,YAAA,EAAa;AAAA,IAClD,MAAA,EAAQ,CAAC,EAAE,EAAA,EAAI,KAAI,KAAM;AACvB,MAAA,IAAI,CAAC,EAAA,EAAI;AACT,MAAA,MAAM,OAAA,GAAwB,EAAE,GAAG,WAAA,EAAY;AAC/C,MAAA,IAAI,GAAA,KAAQ,MAAA,EAAW,OAAA,CAAQ,QAAA,GAAW,GAAA;AAC1C,MAAA,OAAO,MAAA,CAAO,IAAI,OAAO,CAAA;AAAA,IAC3B;AAAA,GACD,CAAA;AAED,EAAAC,eAAA,CAAO,EAAE,KAAA,EAAO,GAAA,EAAK,MAAA,EAAQ,OAAO,CAAA;AAEpC,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,SAAA,CACP,MACA,IAAA,EAC0C;AAC1C,EAAA,IAAI,IAAA,KAAS,MAAA,EAAW,OAAO,CAAC,MAAqB,IAAI,CAAA;AACzD,EAAA,OAAO,CAAC,MAAM,IAA0B,CAAA;AAC1C;AAoBO,SAAS,YAAA,CACd,MACA,IAAA,EACqB;AACrB,EAAA,MAAM,CAAC,cAAA,EAAgB,OAAO,CAAA,GAAI,SAAA,CAAU,MAAM,IAAI,CAAA;AACtD,EAAA,OAAO,gBAAA;AAAA,IACL,CAAC,EAAA,EAAI,OAAA,KAAY,EAAA,CAAG,cAAc,OAAO,CAAA;AAAA,IACzC,cAAA;AAAA,IACA;AAAA,GACF;AACF;AAgBO,SAAS,YAAA,CACd,MACA,IAAA,EACqB;AACrB,EAAA,MAAM,CAAC,cAAA,EAAgB,OAAO,CAAA,GAAI,SAAA,CAAU,MAAM,IAAI,CAAA;AACtD,EAAA,OAAO,gBAAA;AAAA,IACL,CAAC,EAAA,EAAI,OAAA,KAAY,EAAA,CAAG,cAAc,OAAO,CAAA;AAAA,IACzC,cAAA;AAAA,IACA;AAAA,GACF;AACF;AAiBO,SAAS,WAAA,CACd,MACA,IAAA,EACqB;AACrB,EAAA,MAAM,CAAC,cAAA,EAAgB,OAAO,CAAA,GAAI,SAAA,CAAU,MAAM,IAAI,CAAA;AACtD,EAAA,OAAO,gBAAA;AAAA,IACL,CAAC,EAAA,EAAI,OAAA,KAAY,EAAA,CAAG,aAAa,OAAO,CAAA;AAAA,IACxC,cAAA;AAAA,IACA;AAAA,GACF;AACF","file":"createCacheAction.cjs","sourcesContent":["import { attach, createEvent, createStore, sample } from 'effector'\nimport type { EventCallable, Store } from 'effector'\nimport type { QueryClient, QueryFilters, QueryKey } from '@tanstack/query-core'\nimport { $queryClient } from './queryClient'\nimport { resolveKey } from './resolve'\nimport type { EffectorQueryKey } from './types'\n\n/**\n * Options shared by `createCancel` / `createRemove` / `createReset`.\n *\n * Structurally a `QueryFilters` (from `@tanstack/query-core`) with the\n * `queryKey` field widened to the reactive `EffectorQueryKey` shape — drop a\n * `Store` anywhere in the array and the action resolves it on every call.\n *\n * `queryKey` is **optional**: omit it to target *all* queries, mirroring\n * `queryClient.cancelQueries()` / `removeQueries()` / `resetQueries()` with no\n * filters.\n */\nexport interface CacheActionOptions extends Omit<QueryFilters, 'queryKey'> {\n /**\n * Key (or key prefix) to act on. Supports the same reactive shape as\n * `createQuery.queryKey`. Omit to match every query in the cache.\n */\n queryKey?: EffectorQueryKey\n}\n\n/** Distinct named aliases so each factory documents its own option type. */\nexport type CreateCancelOptions = CacheActionOptions\nexport type CreateRemoveOptions = CacheActionOptions\nexport type CreateResetOptions = CacheActionOptions\n\n/**\n * The QueryClient method a given action drives. Receives the resolved filters\n * (with `queryKey` already merged in when present). May be sync (`removeQueries`\n * returns `void`) or async (`cancelQueries` / `resetQueries` return a Promise).\n */\ntype CacheActionRunner = (qc: QueryClient, filters: QueryFilters) => unknown\n\n/**\n * Shared builder. Returns a `void` event that, when fired, runs `action`\n * against the resolved `QueryClient` with the resolved filters. Mirrors\n * `createInvalidate`'s locking + reactive-key + per-scope semantics exactly.\n */\nfunction buildCacheAction(\n action: CacheActionRunner,\n explicitClient: QueryClient | null,\n options: CacheActionOptions,\n): EventCallable<void> {\n const { queryKey, ...restFilters } = options\n\n // Same locking semantics as the other factories: explicit client freezes the\n // store, default flows through global $queryClient (and respects\n // fork({ values: [[$queryClient, qc]] }) for per-scope isolation).\n const $effectiveClient: Store<QueryClient | null> = explicitClient\n ? createStore(explicitClient as QueryClient | null, {\n serialize: 'ignore',\n })\n : $queryClient\n\n // No queryKey → a store of `undefined`, so the effect omits the field and the\n // action matches all queries.\n const $resolvedKey: Store<QueryKey | undefined> = queryKey\n ? resolveKey(queryKey)\n : createStore<QueryKey | undefined>(undefined, { skipVoid: false })\n\n const run = createEvent<void>()\n\n const runFx = attach({\n source: { qc: $effectiveClient, key: $resolvedKey },\n effect: ({ qc, key }) => {\n if (!qc) return\n const filters: QueryFilters = { ...restFilters }\n if (key !== undefined) filters.queryKey = key\n return action(qc, filters)\n },\n })\n\n sample({ clock: run, target: runFx })\n\n return run\n}\n\nfunction parseArgs(\n arg1: QueryClient | CacheActionOptions,\n arg2?: CacheActionOptions,\n): [QueryClient | null, CacheActionOptions] {\n if (arg2 !== undefined) return [arg1 as QueryClient, arg2]\n return [null, arg1 as CacheActionOptions]\n}\n\n/**\n * Builds a `sample`-friendly event that **cancels** in-flight queries on the\n * resolved `QueryClient` (without removing cached data). Wraps\n * `queryClient.cancelQueries` — async, so `await allSettled(cancel, { scope })`\n * waits for cancellation to settle.\n *\n * @example Cancel a user's queries on logout\n * const cancelUserQueries = createCancel({ queryKey: ['user', $userId] })\n * sample({ clock: logoutClicked, target: cancelUserQueries })\n *\n * @example Explicit client (same back-compat overload as createInvalidate)\n * const cancelAll = createCancel(queryClient, {})\n */\nexport function createCancel(options: CacheActionOptions): EventCallable<void>\nexport function createCancel(\n queryClient: QueryClient,\n options: CacheActionOptions,\n): EventCallable<void>\nexport function createCancel(\n arg1: QueryClient | CacheActionOptions,\n arg2?: CacheActionOptions,\n): EventCallable<void> {\n const [explicitClient, options] = parseArgs(arg1, arg2)\n return buildCacheAction(\n (qc, filters) => qc.cancelQueries(filters),\n explicitClient,\n options,\n )\n}\n\n/**\n * Builds a `sample`-friendly event that **removes** matching entries from the\n * cache entirely. Wraps `queryClient.removeQueries` — synchronous (no Promise).\n * The next mount of a removed query starts from a pending state.\n *\n * @example Drop stale cache on navigation\n * const removeStale = createRemove({ queryKey: ['stale-cache'] })\n * sample({ clock: navigated, target: removeStale })\n */\nexport function createRemove(options: CacheActionOptions): EventCallable<void>\nexport function createRemove(\n queryClient: QueryClient,\n options: CacheActionOptions,\n): EventCallable<void>\nexport function createRemove(\n arg1: QueryClient | CacheActionOptions,\n arg2?: CacheActionOptions,\n): EventCallable<void> {\n const [explicitClient, options] = parseArgs(arg1, arg2)\n return buildCacheAction(\n (qc, filters) => qc.removeQueries(filters),\n explicitClient,\n options,\n )\n}\n\n/**\n * Builds a `sample`-friendly event that **resets** matching queries back to\n * their initial state and refetches any active observers. Wraps\n * `queryClient.resetQueries` — async, so `await allSettled(reset, { scope })`\n * waits for the refetch to settle.\n *\n * @example Reset search results when the filters are cleared\n * const resetSearch = createReset({ queryKey: ['search'] })\n * sample({ clock: filtersCleared, target: resetSearch })\n */\nexport function createReset(options: CacheActionOptions): EventCallable<void>\nexport function createReset(\n queryClient: QueryClient,\n options: CacheActionOptions,\n): EventCallable<void>\nexport function createReset(\n arg1: QueryClient | CacheActionOptions,\n arg2?: CacheActionOptions,\n): EventCallable<void> {\n const [explicitClient, options] = parseArgs(arg1, arg2)\n return buildCacheAction(\n (qc, filters) => qc.resetQueries(filters),\n explicitClient,\n options,\n )\n}\n"]}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { EventCallable } from 'effector';
|
|
2
|
+
import { QueryFilters, QueryClient } from '@tanstack/query-core';
|
|
3
|
+
import { EffectorQueryKey } from './types.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Options shared by `createCancel` / `createRemove` / `createReset`.
|
|
7
|
+
*
|
|
8
|
+
* Structurally a `QueryFilters` (from `@tanstack/query-core`) with the
|
|
9
|
+
* `queryKey` field widened to the reactive `EffectorQueryKey` shape — drop a
|
|
10
|
+
* `Store` anywhere in the array and the action resolves it on every call.
|
|
11
|
+
*
|
|
12
|
+
* `queryKey` is **optional**: omit it to target *all* queries, mirroring
|
|
13
|
+
* `queryClient.cancelQueries()` / `removeQueries()` / `resetQueries()` with no
|
|
14
|
+
* filters.
|
|
15
|
+
*/
|
|
16
|
+
interface CacheActionOptions extends Omit<QueryFilters, 'queryKey'> {
|
|
17
|
+
/**
|
|
18
|
+
* Key (or key prefix) to act on. Supports the same reactive shape as
|
|
19
|
+
* `createQuery.queryKey`. Omit to match every query in the cache.
|
|
20
|
+
*/
|
|
21
|
+
queryKey?: EffectorQueryKey;
|
|
22
|
+
}
|
|
23
|
+
/** Distinct named aliases so each factory documents its own option type. */
|
|
24
|
+
type CreateCancelOptions = CacheActionOptions;
|
|
25
|
+
type CreateRemoveOptions = CacheActionOptions;
|
|
26
|
+
type CreateResetOptions = CacheActionOptions;
|
|
27
|
+
/**
|
|
28
|
+
* Builds a `sample`-friendly event that **cancels** in-flight queries on the
|
|
29
|
+
* resolved `QueryClient` (without removing cached data). Wraps
|
|
30
|
+
* `queryClient.cancelQueries` — async, so `await allSettled(cancel, { scope })`
|
|
31
|
+
* waits for cancellation to settle.
|
|
32
|
+
*
|
|
33
|
+
* @example Cancel a user's queries on logout
|
|
34
|
+
* const cancelUserQueries = createCancel({ queryKey: ['user', $userId] })
|
|
35
|
+
* sample({ clock: logoutClicked, target: cancelUserQueries })
|
|
36
|
+
*
|
|
37
|
+
* @example Explicit client (same back-compat overload as createInvalidate)
|
|
38
|
+
* const cancelAll = createCancel(queryClient, {})
|
|
39
|
+
*/
|
|
40
|
+
declare function createCancel(options: CacheActionOptions): EventCallable<void>;
|
|
41
|
+
declare function createCancel(queryClient: QueryClient, options: CacheActionOptions): EventCallable<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Builds a `sample`-friendly event that **removes** matching entries from the
|
|
44
|
+
* cache entirely. Wraps `queryClient.removeQueries` — synchronous (no Promise).
|
|
45
|
+
* The next mount of a removed query starts from a pending state.
|
|
46
|
+
*
|
|
47
|
+
* @example Drop stale cache on navigation
|
|
48
|
+
* const removeStale = createRemove({ queryKey: ['stale-cache'] })
|
|
49
|
+
* sample({ clock: navigated, target: removeStale })
|
|
50
|
+
*/
|
|
51
|
+
declare function createRemove(options: CacheActionOptions): EventCallable<void>;
|
|
52
|
+
declare function createRemove(queryClient: QueryClient, options: CacheActionOptions): EventCallable<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Builds a `sample`-friendly event that **resets** matching queries back to
|
|
55
|
+
* their initial state and refetches any active observers. Wraps
|
|
56
|
+
* `queryClient.resetQueries` — async, so `await allSettled(reset, { scope })`
|
|
57
|
+
* waits for the refetch to settle.
|
|
58
|
+
*
|
|
59
|
+
* @example Reset search results when the filters are cleared
|
|
60
|
+
* const resetSearch = createReset({ queryKey: ['search'] })
|
|
61
|
+
* sample({ clock: filtersCleared, target: resetSearch })
|
|
62
|
+
*/
|
|
63
|
+
declare function createReset(options: CacheActionOptions): EventCallable<void>;
|
|
64
|
+
declare function createReset(queryClient: QueryClient, options: CacheActionOptions): EventCallable<void>;
|
|
65
|
+
|
|
66
|
+
export { type CacheActionOptions, type CreateCancelOptions, type CreateRemoveOptions, type CreateResetOptions, createCancel, createRemove, createReset };
|