@effector-tanstack-query/core 0.1.0

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.
Files changed (65) hide show
  1. package/README.md +40 -0
  2. package/dist/createBaseQuery.cjs +208 -0
  3. package/dist/createBaseQuery.cjs.map +1 -0
  4. package/dist/createBaseQuery.d.cts +114 -0
  5. package/dist/createBaseQuery.d.ts +114 -0
  6. package/dist/createBaseQuery.js +204 -0
  7. package/dist/createBaseQuery.js.map +1 -0
  8. package/dist/createInfiniteQuery.cjs +193 -0
  9. package/dist/createInfiniteQuery.cjs.map +1 -0
  10. package/dist/createInfiniteQuery.d.cts +8 -0
  11. package/dist/createInfiniteQuery.d.ts +8 -0
  12. package/dist/createInfiniteQuery.js +191 -0
  13. package/dist/createInfiniteQuery.js.map +1 -0
  14. package/dist/createInvalidate.cjs +37 -0
  15. package/dist/createInvalidate.cjs.map +1 -0
  16. package/dist/createInvalidate.d.cts +50 -0
  17. package/dist/createInvalidate.d.ts +50 -0
  18. package/dist/createInvalidate.js +35 -0
  19. package/dist/createInvalidate.js.map +1 -0
  20. package/dist/createMutation.cjs +177 -0
  21. package/dist/createMutation.cjs.map +1 -0
  22. package/dist/createMutation.d.cts +7 -0
  23. package/dist/createMutation.d.ts +7 -0
  24. package/dist/createMutation.js +175 -0
  25. package/dist/createMutation.js.map +1 -0
  26. package/dist/createQuery.cjs +98 -0
  27. package/dist/createQuery.cjs.map +1 -0
  28. package/dist/createQuery.d.cts +8 -0
  29. package/dist/createQuery.d.ts +8 -0
  30. package/dist/createQuery.js +96 -0
  31. package/dist/createQuery.js.map +1 -0
  32. package/dist/index.cjs +36 -0
  33. package/dist/index.cjs.map +1 -0
  34. package/dist/index.d.cts +8 -0
  35. package/dist/index.d.ts +8 -0
  36. package/dist/index.js +7 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/queryClient.cjs +20 -0
  39. package/dist/queryClient.cjs.map +1 -0
  40. package/dist/queryClient.d.cts +15 -0
  41. package/dist/queryClient.d.ts +15 -0
  42. package/dist/queryClient.js +17 -0
  43. package/dist/queryClient.js.map +1 -0
  44. package/dist/resolve.cjs +37 -0
  45. package/dist/resolve.cjs.map +1 -0
  46. package/dist/resolve.d.cts +17 -0
  47. package/dist/resolve.d.ts +17 -0
  48. package/dist/resolve.js +33 -0
  49. package/dist/resolve.js.map +1 -0
  50. package/dist/types.cjs +4 -0
  51. package/dist/types.cjs.map +1 -0
  52. package/dist/types.d.cts +209 -0
  53. package/dist/types.d.ts +209 -0
  54. package/dist/types.js +3 -0
  55. package/dist/types.js.map +1 -0
  56. package/package.json +60 -0
  57. package/src/createBaseQuery.ts +428 -0
  58. package/src/createInfiniteQuery.ts +291 -0
  59. package/src/createInvalidate.ts +104 -0
  60. package/src/createMutation.ts +271 -0
  61. package/src/createQuery.ts +155 -0
  62. package/src/index.ts +17 -0
  63. package/src/queryClient.ts +23 -0
  64. package/src/resolve.ts +50 -0
  65. package/src/types.ts +270 -0
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # @effector-tanstack-query/core
2
+
3
+ Core package: [TanStack Query](https://tanstack.com/query) state and
4
+ operations exposed as effector units.
5
+
6
+ - Every observer field (`data`, `status`, `isPending`, …) becomes a `Store<T>`
7
+ - Every imperative action (`refetch`, `fetchNextPage`, `mutate`, `reset`, …) is an `EventCallable`
8
+ - A `Store` placed inside `queryKey` triggers automatic refetch on change
9
+ - SSR works via `dehydrate`/`hydrate` for the cache **and** `serialize(scope)`/`fork({ values })` for the effector graph
10
+
11
+ ```bash
12
+ npm install @effector-tanstack-query/core @tanstack/query-core effector
13
+ ```
14
+
15
+ ```ts
16
+ import { QueryClient } from '@tanstack/query-core'
17
+ import { setQueryClient, createQuery } from '@effector-tanstack-query/core'
18
+
19
+ const queryClient = new QueryClient()
20
+ queryClient.mount()
21
+ setQueryClient(queryClient)
22
+
23
+ const userQuery = createQuery({
24
+ name: 'user',
25
+ queryKey: ['user', 1],
26
+ queryFn: () => fetch('/api/users/1').then((r) => r.json()),
27
+ })
28
+
29
+ userQuery.mounted()
30
+ ```
31
+
32
+ For React hooks see [`@effector-tanstack-query/react`](https://www.npmjs.com/package/@effector-tanstack-query/react).
33
+
34
+ **Full documentation:** https://ilyaagarkov.github.io/effector-tanstack-query/
35
+
36
+ **Source & examples:** https://github.com/ilyaagarkov/effector-tanstack-query
37
+
38
+ ## License
39
+
40
+ MIT
@@ -0,0 +1,208 @@
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/createBaseQuery.ts
8
+ var SID_PREFIX = "@tanstack/query-effector";
9
+ var warnedNames = /* @__PURE__ */ new Set();
10
+ function warnMissingName(role) {
11
+ if (typeof process === "undefined" || process.env.NODE_ENV === "production") {
12
+ return;
13
+ }
14
+ if (warnedNames.has(role)) return;
15
+ warnedNames.add(role);
16
+ console.warn(
17
+ `[@tanstack/query-effector] ${role} created without a "name" \u2014 internal stores will be excluded from serialize(scope). Pass a unique "name" to enable SSR via fork({ values: serialize(scope) }).`
18
+ );
19
+ }
20
+ function sidConfig(name, role) {
21
+ if (!name) return {};
22
+ return {
23
+ sid: `${SID_PREFIX}.${name}.${role}`,
24
+ name: `${name}.${role}`
25
+ };
26
+ }
27
+ function createBaseQuery(explicitClient, options, config) {
28
+ const { name, reactiveRefetchInterval: $reactiveRefetchInterval } = options;
29
+ const $resolvedKey = resolve_cjs.resolveKey(options.queryKey);
30
+ const $enabled = resolve_cjs.resolveEnabled(options.enabled);
31
+ const $effectiveClient = explicitClient ? effector.createStore(explicitClient, {
32
+ serialize: "ignore"
33
+ }) : queryClient_cjs.$queryClient;
34
+ const dataUpdated = effector.createEvent();
35
+ const errorUpdated = effector.createEvent();
36
+ const statusUpdated = effector.createEvent();
37
+ const isFetchingUpdated = effector.createEvent();
38
+ const fetchStatusUpdated = effector.createEvent();
39
+ const isPlaceholderDataUpdated = effector.createEvent();
40
+ const $data = effector.createStore(void 0, {
41
+ skipVoid: false,
42
+ ...sidConfig(name, "$data")
43
+ }).on(dataUpdated, (_, v) => v);
44
+ const $error = effector.createStore(null, {
45
+ skipVoid: false,
46
+ ...sidConfig(name, "$error")
47
+ }).on(errorUpdated, (_, v) => v);
48
+ const $status = effector.createStore("pending", {
49
+ ...sidConfig(name, "$status")
50
+ }).on(statusUpdated, (_, v) => v);
51
+ const $isFetching = effector.createStore(false, {
52
+ ...sidConfig(name, "$isFetching")
53
+ }).on(isFetchingUpdated, (_, v) => v);
54
+ const $fetchStatus = effector.createStore("idle", {
55
+ ...sidConfig(name, "$fetchStatus")
56
+ }).on(fetchStatusUpdated, (_, v) => v);
57
+ const $isPlaceholderData = effector.createStore(false, {
58
+ ...sidConfig(name, "$isPlaceholderData")
59
+ }).on(isPlaceholderDataUpdated, (_, v) => v);
60
+ const $isPending = $status.map((s) => s === "pending");
61
+ const $isSuccess = $status.map((s) => s === "success");
62
+ const $isError = $status.map((s) => s === "error");
63
+ const $observer = effector.createStore(null, {
64
+ serialize: "ignore"
65
+ });
66
+ const observerCreated = effector.createEvent();
67
+ $observer.on(observerCreated, (_, obs) => obs);
68
+ const observerSubscriptions = /* @__PURE__ */ new WeakMap();
69
+ const extras = config.setupExtras?.();
70
+ extras?.setupEffects?.({ $observer });
71
+ const mountFx = effector.attach({
72
+ source: { qc: $effectiveClient, observer: $observer },
73
+ effect: ({ qc, observer: existingObserver }, {
74
+ key,
75
+ enabled,
76
+ refetchInterval
77
+ }) => {
78
+ if (!qc) {
79
+ throw new Error(
80
+ "[@tanstack/query-effector] No QueryClient is set. Call setQueryClient(qc) before mounting, pass it to fork({ values: [[$queryClient, qc]] }), or pass it explicitly to the factory."
81
+ );
82
+ }
83
+ const observer = existingObserver ?? config.createObserver(qc, { queryKey: key, enabled });
84
+ const dispatchData = effector.scopeBind(dataUpdated, { safe: true });
85
+ const dispatchError = effector.scopeBind(errorUpdated, { safe: true });
86
+ const dispatchStatus = effector.scopeBind(statusUpdated, { safe: true });
87
+ const dispatchIsFetching = effector.scopeBind(isFetchingUpdated, { safe: true });
88
+ const dispatchFetchStatus = effector.scopeBind(fetchStatusUpdated, { safe: true });
89
+ const dispatchIsPlaceholderData = effector.scopeBind(isPlaceholderDataUpdated, {
90
+ safe: true
91
+ });
92
+ const dispatchExtras = extras?.bindDispatcher();
93
+ observerSubscriptions.get(observer)?.();
94
+ observer.setOptions({
95
+ ...observer.options,
96
+ queryKey: key,
97
+ enabled,
98
+ // Only override refetchInterval when the user provided a reactive
99
+ // Store — otherwise the static value (or function) from the observer
100
+ // constructor wins.
101
+ ...$reactiveRefetchInterval ? { refetchInterval } : {}
102
+ });
103
+ const dispatch = (result) => {
104
+ dispatchData(result.data);
105
+ dispatchError(result.error);
106
+ dispatchStatus(result.status);
107
+ dispatchIsFetching(result.isFetching);
108
+ dispatchFetchStatus(result.fetchStatus);
109
+ dispatchIsPlaceholderData(result.isPlaceholderData);
110
+ dispatchExtras?.(result);
111
+ };
112
+ const unsubscribe = observer.subscribe(dispatch);
113
+ observerSubscriptions.set(observer, unsubscribe);
114
+ dispatch(observer.getCurrentResult());
115
+ return observer;
116
+ }
117
+ });
118
+ effector.sample({ clock: mountFx.doneData, target: observerCreated });
119
+ const updateObserverFx = effector.attach({
120
+ source: $observer,
121
+ effect: (observer, {
122
+ key,
123
+ enabled,
124
+ refetchInterval
125
+ }) => {
126
+ if (!observer) return;
127
+ const {
128
+ _defaulted: _d,
129
+ queryHash: _h,
130
+ ...baseOptions
131
+ } = observer.options;
132
+ observer.setOptions({
133
+ ...baseOptions,
134
+ queryKey: key,
135
+ enabled,
136
+ ...$reactiveRefetchInterval ? { refetchInterval } : {}
137
+ });
138
+ }
139
+ });
140
+ const mounted = effector.createEvent();
141
+ const unmounted = effector.createEvent();
142
+ const $isMounted = effector.createStore(false, {
143
+ ...sidConfig(name, "$isMounted")
144
+ }).on(mounted, () => true).on(unmounted, () => false);
145
+ const $observerOptions = effector.combine({
146
+ key: $resolvedKey,
147
+ enabled: $enabled,
148
+ refetchInterval: $reactiveRefetchInterval ?? effector.createStore(false)
149
+ });
150
+ effector.sample({
151
+ clock: mounted,
152
+ source: $observerOptions,
153
+ target: mountFx
154
+ });
155
+ effector.sample({
156
+ clock: $observerOptions,
157
+ source: $observerOptions,
158
+ filter: $isMounted,
159
+ target: updateObserverFx
160
+ });
161
+ const observerDestroyed = effector.createEvent();
162
+ $observer.on(observerDestroyed, () => null);
163
+ const unmountFx = effector.attach({
164
+ source: $observer,
165
+ effect: (observer) => {
166
+ if (!observer) return;
167
+ observerSubscriptions.get(observer)?.();
168
+ observerSubscriptions.delete(observer);
169
+ observer.destroy();
170
+ }
171
+ });
172
+ effector.sample({ clock: unmounted, target: unmountFx });
173
+ effector.sample({ clock: unmountFx.finally, target: observerDestroyed });
174
+ const refresh = effector.createEvent();
175
+ const refreshFx = effector.attach({
176
+ source: { qc: $effectiveClient, key: $resolvedKey },
177
+ effect: ({ qc, key }) => {
178
+ if (!qc) return;
179
+ return qc.invalidateQueries({ queryKey: key });
180
+ }
181
+ });
182
+ effector.sample({ clock: refresh, target: refreshFx });
183
+ return {
184
+ $data,
185
+ $error,
186
+ $status,
187
+ $isPending,
188
+ $isFetching,
189
+ $isSuccess,
190
+ $isError,
191
+ $isPlaceholderData,
192
+ $fetchStatus,
193
+ $observer,
194
+ $queryClient: $effectiveClient,
195
+ $resolvedKey,
196
+ $enabled,
197
+ refresh,
198
+ mounted,
199
+ unmounted,
200
+ ...extras?.stores ?? {}
201
+ };
202
+ }
203
+
204
+ exports.createBaseQuery = createBaseQuery;
205
+ exports.sidConfig = sidConfig;
206
+ exports.warnMissingName = warnMissingName;
207
+ //# sourceMappingURL=createBaseQuery.cjs.map
208
+ //# sourceMappingURL=createBaseQuery.cjs.map
@@ -0,0 +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"]}
@@ -0,0 +1,114 @@
1
+ import { Store, EventCallable } from 'effector';
2
+ import { QueryKey, QueryStatus, FetchStatus, QueryClient } from '@tanstack/query-core';
3
+ import { EffectorQueryKey, StoreOrValue } from './types.cjs';
4
+
5
+ /**
6
+ * The minimal shape of an observer that createBaseQuery knows how to drive.
7
+ * Both QueryObserver and InfiniteQueryObserver satisfy this.
8
+ */
9
+ interface BaseObserverLike<TResult> {
10
+ options: {
11
+ queryKey: QueryKey;
12
+ _defaulted?: boolean;
13
+ queryHash?: string;
14
+ };
15
+ setOptions(options: any): void;
16
+ subscribe(listener: (result: TResult) => void): () => void;
17
+ getCurrentResult(): TResult;
18
+ destroy(): void;
19
+ }
20
+ /**
21
+ * The subset of observer result fields that createBaseQuery wires up
22
+ * into stores common to all query flavors.
23
+ */
24
+ interface BaseObserverResult<TData, TError> {
25
+ data: TData | undefined;
26
+ error: TError | null;
27
+ status: QueryStatus;
28
+ isFetching: boolean;
29
+ fetchStatus: FetchStatus;
30
+ isPlaceholderData: boolean;
31
+ }
32
+ interface BaseQueryStores<TData, TError, TObserver> {
33
+ $data: Store<TData | undefined>;
34
+ $error: Store<TError | null>;
35
+ $status: Store<QueryStatus>;
36
+ $isPending: Store<boolean>;
37
+ $isFetching: Store<boolean>;
38
+ $isSuccess: Store<boolean>;
39
+ $isError: Store<boolean>;
40
+ $isPlaceholderData: Store<boolean>;
41
+ $fetchStatus: Store<FetchStatus>;
42
+ /**
43
+ * Per-scope observer. Populated on first `mounted()` via attach over
44
+ * `$queryClient` — every fork scope has its own Observer instance bound
45
+ * to the scope's QueryClient. Read scope-aware via `useUnit($observer)`.
46
+ */
47
+ $observer: Store<TObserver | null>;
48
+ /**
49
+ * Resolved QueryClient store. If the factory was called with an explicit
50
+ * client, this is a frozen store of that client. Otherwise it's the global
51
+ * `$queryClient`, which honors `fork({ values })` overrides.
52
+ */
53
+ $queryClient: Store<QueryClient | null>;
54
+ /** Internal — used by the React suspense hooks. */
55
+ $resolvedKey: Store<QueryKey>;
56
+ /** Internal — used by the React suspense hooks. */
57
+ $enabled: Store<boolean>;
58
+ refresh: EventCallable<void>;
59
+ mounted: EventCallable<void>;
60
+ unmounted: EventCallable<void>;
61
+ }
62
+ interface BaseQueryOptions {
63
+ queryKey: EffectorQueryKey;
64
+ enabled?: StoreOrValue<boolean>;
65
+ /**
66
+ * Pre-resolved reactive `refetchInterval`. The per-flavor factory extracts
67
+ * the original option, and — if it's a Store — passes the Store here while
68
+ * stripping the value from the observer constructor options. Static values
69
+ * and function forms continue to flow through `restOptions` to the
70
+ * observer.
71
+ */
72
+ reactiveRefetchInterval?: Store<number | false | undefined>;
73
+ name?: string;
74
+ }
75
+ declare function warnMissingName(role: string): void;
76
+ declare function sidConfig(name: string | undefined, role: string): {
77
+ sid: string;
78
+ name: string;
79
+ } | {};
80
+ interface ExtrasSetup<TResult, TObserver, TExtraStores> {
81
+ /** Extra stores/events merged into the final result object. */
82
+ stores: TExtraStores;
83
+ /**
84
+ * Invoked inside the mount effect. Must scope-bind any extra events
85
+ * and return a function that dispatches extra fields from the observer
86
+ * result. The returned dispatcher is called on every subscription
87
+ * notification alongside the base dispatcher.
88
+ */
89
+ bindDispatcher: () => (result: TResult) => void;
90
+ /**
91
+ * Lets a flavor wire its own per-observer effects (e.g.
92
+ * fetchNextPage / fetchPreviousPage for infinite queries). Receives the
93
+ * per-scope `$observer` store so the flavor can build attach-based
94
+ * effects that resolve the observer from the current scope.
95
+ */
96
+ setupEffects?: (params: {
97
+ $observer: Store<TObserver | null>;
98
+ }) => void;
99
+ }
100
+ interface CreateBaseQueryConfig<TData, TError, TResult extends BaseObserverResult<TData, TError>, TObserver extends BaseObserverLike<TResult>, TExtraStores> {
101
+ /** Build the observer for the current scope. Receives the resolved client. */
102
+ createObserver: (queryClient: QueryClient, initial: {
103
+ queryKey: QueryKey;
104
+ enabled: boolean;
105
+ }) => TObserver;
106
+ /**
107
+ * Hook for query flavors that need additional stores/events (e.g. infinite
108
+ * query's hasNextPage, fetchNextPage). Called once at factory time.
109
+ */
110
+ setupExtras?: () => ExtrasSetup<TResult, TObserver, TExtraStores>;
111
+ }
112
+ declare function createBaseQuery<TData, TError, TResult extends BaseObserverResult<TData, TError>, TObserver extends BaseObserverLike<TResult>, TExtraStores = {}>(explicitClient: QueryClient | null, options: BaseQueryOptions, config: CreateBaseQueryConfig<TData, TError, TResult, TObserver, TExtraStores>): BaseQueryStores<TData, TError, TObserver> & TExtraStores;
113
+
114
+ export { type BaseObserverLike, type BaseObserverResult, type BaseQueryOptions, type BaseQueryStores, type CreateBaseQueryConfig, type ExtrasSetup, createBaseQuery, sidConfig, warnMissingName };
@@ -0,0 +1,114 @@
1
+ import { Store, EventCallable } from 'effector';
2
+ import { QueryKey, QueryStatus, FetchStatus, QueryClient } from '@tanstack/query-core';
3
+ import { EffectorQueryKey, StoreOrValue } from './types.js';
4
+
5
+ /**
6
+ * The minimal shape of an observer that createBaseQuery knows how to drive.
7
+ * Both QueryObserver and InfiniteQueryObserver satisfy this.
8
+ */
9
+ interface BaseObserverLike<TResult> {
10
+ options: {
11
+ queryKey: QueryKey;
12
+ _defaulted?: boolean;
13
+ queryHash?: string;
14
+ };
15
+ setOptions(options: any): void;
16
+ subscribe(listener: (result: TResult) => void): () => void;
17
+ getCurrentResult(): TResult;
18
+ destroy(): void;
19
+ }
20
+ /**
21
+ * The subset of observer result fields that createBaseQuery wires up
22
+ * into stores common to all query flavors.
23
+ */
24
+ interface BaseObserverResult<TData, TError> {
25
+ data: TData | undefined;
26
+ error: TError | null;
27
+ status: QueryStatus;
28
+ isFetching: boolean;
29
+ fetchStatus: FetchStatus;
30
+ isPlaceholderData: boolean;
31
+ }
32
+ interface BaseQueryStores<TData, TError, TObserver> {
33
+ $data: Store<TData | undefined>;
34
+ $error: Store<TError | null>;
35
+ $status: Store<QueryStatus>;
36
+ $isPending: Store<boolean>;
37
+ $isFetching: Store<boolean>;
38
+ $isSuccess: Store<boolean>;
39
+ $isError: Store<boolean>;
40
+ $isPlaceholderData: Store<boolean>;
41
+ $fetchStatus: Store<FetchStatus>;
42
+ /**
43
+ * Per-scope observer. Populated on first `mounted()` via attach over
44
+ * `$queryClient` — every fork scope has its own Observer instance bound
45
+ * to the scope's QueryClient. Read scope-aware via `useUnit($observer)`.
46
+ */
47
+ $observer: Store<TObserver | null>;
48
+ /**
49
+ * Resolved QueryClient store. If the factory was called with an explicit
50
+ * client, this is a frozen store of that client. Otherwise it's the global
51
+ * `$queryClient`, which honors `fork({ values })` overrides.
52
+ */
53
+ $queryClient: Store<QueryClient | null>;
54
+ /** Internal — used by the React suspense hooks. */
55
+ $resolvedKey: Store<QueryKey>;
56
+ /** Internal — used by the React suspense hooks. */
57
+ $enabled: Store<boolean>;
58
+ refresh: EventCallable<void>;
59
+ mounted: EventCallable<void>;
60
+ unmounted: EventCallable<void>;
61
+ }
62
+ interface BaseQueryOptions {
63
+ queryKey: EffectorQueryKey;
64
+ enabled?: StoreOrValue<boolean>;
65
+ /**
66
+ * Pre-resolved reactive `refetchInterval`. The per-flavor factory extracts
67
+ * the original option, and — if it's a Store — passes the Store here while
68
+ * stripping the value from the observer constructor options. Static values
69
+ * and function forms continue to flow through `restOptions` to the
70
+ * observer.
71
+ */
72
+ reactiveRefetchInterval?: Store<number | false | undefined>;
73
+ name?: string;
74
+ }
75
+ declare function warnMissingName(role: string): void;
76
+ declare function sidConfig(name: string | undefined, role: string): {
77
+ sid: string;
78
+ name: string;
79
+ } | {};
80
+ interface ExtrasSetup<TResult, TObserver, TExtraStores> {
81
+ /** Extra stores/events merged into the final result object. */
82
+ stores: TExtraStores;
83
+ /**
84
+ * Invoked inside the mount effect. Must scope-bind any extra events
85
+ * and return a function that dispatches extra fields from the observer
86
+ * result. The returned dispatcher is called on every subscription
87
+ * notification alongside the base dispatcher.
88
+ */
89
+ bindDispatcher: () => (result: TResult) => void;
90
+ /**
91
+ * Lets a flavor wire its own per-observer effects (e.g.
92
+ * fetchNextPage / fetchPreviousPage for infinite queries). Receives the
93
+ * per-scope `$observer` store so the flavor can build attach-based
94
+ * effects that resolve the observer from the current scope.
95
+ */
96
+ setupEffects?: (params: {
97
+ $observer: Store<TObserver | null>;
98
+ }) => void;
99
+ }
100
+ interface CreateBaseQueryConfig<TData, TError, TResult extends BaseObserverResult<TData, TError>, TObserver extends BaseObserverLike<TResult>, TExtraStores> {
101
+ /** Build the observer for the current scope. Receives the resolved client. */
102
+ createObserver: (queryClient: QueryClient, initial: {
103
+ queryKey: QueryKey;
104
+ enabled: boolean;
105
+ }) => TObserver;
106
+ /**
107
+ * Hook for query flavors that need additional stores/events (e.g. infinite
108
+ * query's hasNextPage, fetchNextPage). Called once at factory time.
109
+ */
110
+ setupExtras?: () => ExtrasSetup<TResult, TObserver, TExtraStores>;
111
+ }
112
+ declare function createBaseQuery<TData, TError, TResult extends BaseObserverResult<TData, TError>, TObserver extends BaseObserverLike<TResult>, TExtraStores = {}>(explicitClient: QueryClient | null, options: BaseQueryOptions, config: CreateBaseQueryConfig<TData, TError, TResult, TObserver, TExtraStores>): BaseQueryStores<TData, TError, TObserver> & TExtraStores;
113
+
114
+ export { type BaseObserverLike, type BaseObserverResult, type BaseQueryOptions, type BaseQueryStores, type CreateBaseQueryConfig, type ExtrasSetup, createBaseQuery, sidConfig, warnMissingName };