@ic-reactor/react 3.13.0 → 4.0.0-beta.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.
Files changed (174) hide show
  1. package/README.md +234 -787
  2. package/dist/index.d.ts +259 -16
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +470 -23
  5. package/dist/index.js.map +1 -1
  6. package/llms.txt +80 -278
  7. package/package.json +11 -39
  8. package/src/index.tsx +611 -0
  9. package/dist/auth/auth-client-compat.d.ts +0 -122
  10. package/dist/auth/auth-client-compat.d.ts.map +0 -1
  11. package/dist/auth/auth-client-compat.js +0 -162
  12. package/dist/auth/auth-client-compat.js.map +0 -1
  13. package/dist/auth/authentication-manager.d.ts +0 -405
  14. package/dist/auth/authentication-manager.d.ts.map +0 -1
  15. package/dist/auth/authentication-manager.js +0 -1537
  16. package/dist/auth/authentication-manager.js.map +0 -1
  17. package/dist/auth/constants.d.ts +0 -24
  18. package/dist/auth/constants.d.ts.map +0 -1
  19. package/dist/auth/constants.js +0 -24
  20. package/dist/auth/constants.js.map +0 -1
  21. package/dist/auth/createIdentityAttributeHooks.d.ts +0 -14
  22. package/dist/auth/createIdentityAttributeHooks.d.ts.map +0 -1
  23. package/dist/auth/createIdentityAttributeHooks.js +0 -122
  24. package/dist/auth/createIdentityAttributeHooks.js.map +0 -1
  25. package/dist/auth/identity-attributes-manager.d.ts +0 -27
  26. package/dist/auth/identity-attributes-manager.d.ts.map +0 -1
  27. package/dist/auth/identity-attributes-manager.js +0 -191
  28. package/dist/auth/identity-attributes-manager.js.map +0 -1
  29. package/dist/auth/identity-attributes.d.ts +0 -19
  30. package/dist/auth/identity-attributes.d.ts.map +0 -1
  31. package/dist/auth/identity-attributes.js +0 -227
  32. package/dist/auth/identity-attributes.js.map +0 -1
  33. package/dist/auth/index.d.ts +0 -8
  34. package/dist/auth/index.d.ts.map +0 -1
  35. package/dist/auth/index.js +0 -8
  36. package/dist/auth/index.js.map +0 -1
  37. package/dist/auth/local-ii-probe.d.ts +0 -57
  38. package/dist/auth/local-ii-probe.d.ts.map +0 -1
  39. package/dist/auth/local-ii-probe.js +0 -121
  40. package/dist/auth/local-ii-probe.js.map +0 -1
  41. package/dist/auth/types.d.ts +0 -222
  42. package/dist/auth/types.d.ts.map +0 -1
  43. package/dist/auth/types.js +0 -2
  44. package/dist/auth/types.js.map +0 -1
  45. package/dist/createActorHooks.d.ts +0 -41
  46. package/dist/createActorHooks.d.ts.map +0 -1
  47. package/dist/createActorHooks.js +0 -17
  48. package/dist/createActorHooks.js.map +0 -1
  49. package/dist/createInfiniteQuery.d.ts +0 -185
  50. package/dist/createInfiniteQuery.d.ts.map +0 -1
  51. package/dist/createInfiniteQuery.js +0 -198
  52. package/dist/createInfiniteQuery.js.map +0 -1
  53. package/dist/createMutation.d.ts +0 -33
  54. package/dist/createMutation.d.ts.map +0 -1
  55. package/dist/createMutation.js +0 -199
  56. package/dist/createMutation.js.map +0 -1
  57. package/dist/createQuery.d.ts +0 -63
  58. package/dist/createQuery.d.ts.map +0 -1
  59. package/dist/createQuery.js +0 -204
  60. package/dist/createQuery.js.map +0 -1
  61. package/dist/createReactorProvider.d.ts +0 -158
  62. package/dist/createReactorProvider.d.ts.map +0 -1
  63. package/dist/createReactorProvider.js +0 -256
  64. package/dist/createReactorProvider.js.map +0 -1
  65. package/dist/createSuspenseInfiniteQuery.d.ts +0 -154
  66. package/dist/createSuspenseInfiniteQuery.d.ts.map +0 -1
  67. package/dist/createSuspenseInfiniteQuery.js +0 -209
  68. package/dist/createSuspenseInfiniteQuery.js.map +0 -1
  69. package/dist/createSuspenseQuery.d.ts +0 -46
  70. package/dist/createSuspenseQuery.d.ts.map +0 -1
  71. package/dist/createSuspenseQuery.js +0 -158
  72. package/dist/createSuspenseQuery.js.map +0 -1
  73. package/dist/defineDisplayReactor.d.ts +0 -43
  74. package/dist/defineDisplayReactor.d.ts.map +0 -1
  75. package/dist/defineDisplayReactor.js +0 -42
  76. package/dist/defineDisplayReactor.js.map +0 -1
  77. package/dist/defineReactor.d.ts +0 -99
  78. package/dist/defineReactor.d.ts.map +0 -1
  79. package/dist/defineReactor.js +0 -15
  80. package/dist/defineReactor.js.map +0 -1
  81. package/dist/defineReactorShared.d.ts +0 -84
  82. package/dist/defineReactorShared.d.ts.map +0 -1
  83. package/dist/defineReactorShared.js +0 -139
  84. package/dist/defineReactorShared.js.map +0 -1
  85. package/dist/hooks/createAuthHooks.d.ts +0 -50
  86. package/dist/hooks/createAuthHooks.d.ts.map +0 -1
  87. package/dist/hooks/createAuthHooks.js +0 -291
  88. package/dist/hooks/createAuthHooks.js.map +0 -1
  89. package/dist/hooks/index.d.ts +0 -21
  90. package/dist/hooks/index.d.ts.map +0 -1
  91. package/dist/hooks/index.js +0 -24
  92. package/dist/hooks/index.js.map +0 -1
  93. package/dist/hooks/useActorInfiniteQuery.d.ts +0 -67
  94. package/dist/hooks/useActorInfiniteQuery.d.ts.map +0 -1
  95. package/dist/hooks/useActorInfiniteQuery.js +0 -89
  96. package/dist/hooks/useActorInfiniteQuery.js.map +0 -1
  97. package/dist/hooks/useActorMethod.d.ts +0 -148
  98. package/dist/hooks/useActorMethod.d.ts.map +0 -1
  99. package/dist/hooks/useActorMethod.js +0 -394
  100. package/dist/hooks/useActorMethod.js.map +0 -1
  101. package/dist/hooks/useActorMutation.d.ts +0 -51
  102. package/dist/hooks/useActorMutation.d.ts.map +0 -1
  103. package/dist/hooks/useActorMutation.js +0 -70
  104. package/dist/hooks/useActorMutation.js.map +0 -1
  105. package/dist/hooks/useActorQuery.d.ts +0 -45
  106. package/dist/hooks/useActorQuery.d.ts.map +0 -1
  107. package/dist/hooks/useActorQuery.js +0 -67
  108. package/dist/hooks/useActorQuery.js.map +0 -1
  109. package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts +0 -51
  110. package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts.map +0 -1
  111. package/dist/hooks/useActorSuspenseInfiniteQuery.js +0 -76
  112. package/dist/hooks/useActorSuspenseInfiniteQuery.js.map +0 -1
  113. package/dist/hooks/useActorSuspenseQuery.d.ts +0 -32
  114. package/dist/hooks/useActorSuspenseQuery.d.ts.map +0 -1
  115. package/dist/hooks/useActorSuspenseQuery.js +0 -58
  116. package/dist/hooks/useActorSuspenseQuery.js.map +0 -1
  117. package/dist/ownedAuthentication.d.ts +0 -52
  118. package/dist/ownedAuthentication.d.ts.map +0 -1
  119. package/dist/ownedAuthentication.js +0 -49
  120. package/dist/ownedAuthentication.js.map +0 -1
  121. package/dist/server.d.ts +0 -21
  122. package/dist/server.d.ts.map +0 -1
  123. package/dist/server.js +0 -23
  124. package/dist/server.js.map +0 -1
  125. package/dist/testing.d.ts +0 -19
  126. package/dist/testing.d.ts.map +0 -1
  127. package/dist/testing.js +0 -19
  128. package/dist/testing.js.map +0 -1
  129. package/dist/types.d.ts +0 -671
  130. package/dist/types.d.ts.map +0 -1
  131. package/dist/types.js +0 -5
  132. package/dist/types.js.map +0 -1
  133. package/dist/utils.d.ts +0 -207
  134. package/dist/utils.d.ts.map +0 -1
  135. package/dist/utils.js +0 -405
  136. package/dist/utils.js.map +0 -1
  137. package/dist/validation.d.ts +0 -136
  138. package/dist/validation.d.ts.map +0 -1
  139. package/dist/validation.js +0 -144
  140. package/dist/validation.js.map +0 -1
  141. package/src/auth/auth-client-compat.ts +0 -273
  142. package/src/auth/authentication-manager.ts +0 -1682
  143. package/src/auth/constants.ts +0 -32
  144. package/src/auth/createIdentityAttributeHooks.ts +0 -169
  145. package/src/auth/identity-attributes-manager.ts +0 -226
  146. package/src/auth/identity-attributes.ts +0 -345
  147. package/src/auth/index.ts +0 -7
  148. package/src/auth/local-ii-probe.ts +0 -173
  149. package/src/auth/types.ts +0 -243
  150. package/src/createActorHooks.ts +0 -208
  151. package/src/createInfiniteQuery.ts +0 -670
  152. package/src/createMutation.ts +0 -324
  153. package/src/createQuery.ts +0 -369
  154. package/src/createReactorProvider.ts +0 -365
  155. package/src/createSuspenseInfiniteQuery.ts +0 -651
  156. package/src/createSuspenseQuery.ts +0 -304
  157. package/src/defineDisplayReactor.ts +0 -62
  158. package/src/defineReactor.ts +0 -142
  159. package/src/defineReactorShared.ts +0 -268
  160. package/src/hooks/createAuthHooks.ts +0 -371
  161. package/src/hooks/index.ts +0 -103
  162. package/src/hooks/useActorInfiniteQuery.ts +0 -278
  163. package/src/hooks/useActorMethod.ts +0 -710
  164. package/src/hooks/useActorMutation.ts +0 -205
  165. package/src/hooks/useActorQuery.ts +0 -157
  166. package/src/hooks/useActorSuspenseInfiniteQuery.ts +0 -248
  167. package/src/hooks/useActorSuspenseQuery.ts +0 -147
  168. package/src/index.ts +0 -31
  169. package/src/ownedAuthentication.ts +0 -81
  170. package/src/server.ts +0 -23
  171. package/src/testing.ts +0 -18
  172. package/src/types.ts +0 -948
  173. package/src/utils.ts +0 -505
  174. package/src/validation.ts +0 -226
@@ -1,670 +0,0 @@
1
- /**
2
- * Infinite Query Factory - Generic wrapper for React Query paginated canister data
3
- *
4
- * Creates unified fetch/hook/invalidate functions for any paginated canister method.
5
- * Works with any Reactor instance.
6
- *
7
- * @example
8
- * const postsQuery = createInfiniteQuery(reactor, {
9
- * functionName: "get_posts",
10
- * initialPageParam: 0,
11
- * getArgs: (cursor) => [{ cursor, limit: 10 }] as const,
12
- * getNextPageParam: (lastPage) => lastPage.nextCursor,
13
- * })
14
- *
15
- * // In component
16
- * const { data, fetchNextPage, hasNextPage } = postsQuery.useInfiniteQuery()
17
- *
18
- * // Flatten all pages
19
- * const allPosts = data?.pages.flatMap(page => page.posts)
20
- *
21
- * // Invalidate cache
22
- * postsQuery.invalidate()
23
- */
24
-
25
- import { useMemo } from "react"
26
- import type {
27
- Reactor,
28
- FunctionName,
29
- ReactorArgs,
30
- BaseActor,
31
- TransformKey,
32
- ReactorReturnOk,
33
- ReactorQueryData,
34
- ReactorReturnErr,
35
- } from "@ic-reactor/core"
36
- import {
37
- QueryKey,
38
- useInfiniteQuery,
39
- InfiniteData,
40
- UseInfiniteQueryResult,
41
- UseInfiniteQueryOptions,
42
- QueryFunctionContext,
43
- FetchInfiniteQueryOptions,
44
- InfiniteQueryObserverOptions,
45
- SkipToken,
46
- } from "@tanstack/react-query"
47
- import { CallConfig } from "@icp-sdk/core/agent"
48
- import type {
49
- NoInfer,
50
- QueryCacheControls,
51
- QueryFactoryMethods,
52
- } from "./types.js"
53
- import {
54
- buildChainedSelect,
55
- callConfigForKey,
56
- mergeFactoryQueryKey,
57
- normalizeQueryData,
58
- pickFetchOptions,
59
- queryCacheControls,
60
- retryOption,
61
- useMountQueryClient,
62
- withQueryFactoryMethods,
63
- } from "./utils.js"
64
-
65
- type InfiniteQueryFactoryFn<
66
- Service,
67
- Method extends FunctionName<Service>,
68
- Transform extends TransformKey,
69
- TPageParam,
70
- Selected,
71
- > = QueryFactoryMethods & {
72
- (
73
- getArgs: (pageParam: TPageParam) => ReactorArgs<Service, Method, Transform>
74
- ): InfiniteQueryResult<
75
- InfiniteQueryPageData<Service, Method, Transform>,
76
- TPageParam,
77
- Selected,
78
- InfiniteQueryError<Service, Method, Transform>
79
- >
80
- }
81
-
82
- // ============================================================================
83
- // Type Definitions
84
- // ============================================================================
85
-
86
- /** The raw page data type returned by the query function */
87
- export type InfiniteQueryPageData<
88
- Service = BaseActor,
89
- Method extends FunctionName<Service> = FunctionName<Service>,
90
- Transform extends TransformKey = "candid",
91
- > = ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>
92
-
93
- /** The error type for infinite queries */
94
- export type InfiniteQueryError<
95
- Service = BaseActor,
96
- Method extends FunctionName<Service> = FunctionName<Service>,
97
- Transform extends TransformKey = "candid",
98
- > = ReactorReturnErr<Service, Method, Transform>
99
-
100
- // ============================================================================
101
- // Configuration Types
102
- // ============================================================================
103
-
104
- /**
105
- * Configuration for createInfiniteQuery.
106
- * Extends InfiniteQueryObserverOptions to accept standard TanStack Query
107
- * infinite-query options at the create level (e.g. refetchInterval,
108
- * refetchOnMount, refetchOnWindowFocus, retry, gcTime, networkMode).
109
- *
110
- * @template Service - The actor interface type
111
- * @template Method - The method name on the actor
112
- * @template Transform - The transformation key (identity, display, etc.)
113
- * @template TPageParam - The type of the page parameter
114
- * @template Selected - The type returned after select transformation
115
- */
116
- export interface InfiniteQueryConfig<
117
- Service = BaseActor,
118
- Method extends FunctionName<Service> = FunctionName<Service>,
119
- Transform extends TransformKey = "candid",
120
- TPageParam = unknown,
121
- Selected = InfiniteData<
122
- InfiniteQueryPageData<Service, Method, Transform>,
123
- TPageParam
124
- >,
125
- > extends Omit<
126
- InfiniteQueryObserverOptions<
127
- InfiniteQueryPageData<Service, Method, Transform>,
128
- InfiniteQueryError<Service, Method, Transform>,
129
- Selected,
130
- QueryKey,
131
- TPageParam
132
- >,
133
- "queryKey" | "queryFn"
134
- > {
135
- /** The method to call on the canister */
136
- functionName: Method
137
- /** Call configuration for the actor method */
138
- callConfig?: CallConfig
139
- /** Custom query key (optional, auto-generated if not provided) */
140
- queryKey?: QueryKey
141
- /** Initial page parameter */
142
- initialPageParam: TPageParam
143
- /** Function to get args from page parameter */
144
- getArgs: (pageParam: TPageParam) => ReactorArgs<Service, Method, Transform>
145
- /**
146
- * Narrows what the cache key derives from the call arguments.
147
- *
148
- * By default the key is scoped by `getArgs(initialPageParam)`, so two
149
- * infinite queries on the same method with different arguments stay in
150
- * separate cache entries. Supply this when those args embed the cursor and
151
- * only part of them identifies the query — return the stable, serializable
152
- * portion (typically everything except the pagination field).
153
- */
154
- getKeyArgs?: (args: ReactorArgs<Service, Method, Transform>) => unknown
155
- /** Function to determine next page parameter */
156
- getNextPageParam: (
157
- lastPage: InfiniteQueryPageData<Service, Method, Transform>,
158
- allPages: InfiniteQueryPageData<Service, Method, Transform>[],
159
- lastPageParam: TPageParam,
160
- allPageParams: TPageParam[]
161
- ) => TPageParam | undefined | null
162
- /** Function to determine previous page parameter (for bi-directional) */
163
- getPreviousPageParam?: (
164
- firstPage: InfiniteQueryPageData<Service, Method, Transform>,
165
- allPages: InfiniteQueryPageData<Service, Method, Transform>[],
166
- firstPageParam: TPageParam,
167
- allPageParams: TPageParam[]
168
- ) => TPageParam | undefined | null
169
- }
170
-
171
- /**
172
- * Configuration for the non-suspense infinite query hook of
173
- * `createActorHooks` and `defineReactor` (`useActorInfiniteQuery`): an
174
- * {@link InfiniteQueryConfig} whose `getArgs` may also be TanStack Query's
175
- * `skipToken`, for a list whose arguments are not known yet.
176
- *
177
- * A skipped list does not fetch. It has an entry of its own under its method
178
- * and config `queryKey` (at the canister and agent `callConfig` names), which
179
- * no call's key shares, so it shows no data until the arguments arrive. Once
180
- * `getArgs` is a function, the list is keyed and fetched as usual. Its
181
- * `refetch()` has nothing to run: TanStack Query answers it with a "Missing
182
- * queryFn" error. `useActorSuspenseInfiniteQuery` does not take `skipToken`.
183
- *
184
- * @example
185
- * ```typescript
186
- * import { skipToken } from "@ic-reactor/react"
187
- *
188
- * const { data } = useActorInfiniteQuery({
189
- * functionName: "get_transactions",
190
- * getArgs: account
191
- * ? (start: bigint) => [{ account, start, length: 20n }]
192
- * : skipToken,
193
- * initialPageParam: 0n,
194
- * getNextPageParam: (lastPage) => lastPage.next[0],
195
- * })
196
- * ```
197
- */
198
- export interface SkippableInfiniteQueryConfig<
199
- Service = BaseActor,
200
- Method extends FunctionName<Service> = FunctionName<Service>,
201
- Transform extends TransformKey = "candid",
202
- TPageParam = unknown,
203
- Selected = InfiniteData<
204
- InfiniteQueryPageData<Service, Method, Transform>,
205
- TPageParam
206
- >,
207
- > extends Omit<
208
- InfiniteQueryConfig<Service, Method, Transform, TPageParam, Selected>,
209
- "getArgs"
210
- > {
211
- /**
212
- * Function to get args from page parameter, or `skipToken` while the args
213
- * are not known: the list then waits without fetching.
214
- */
215
- getArgs:
216
- | ((pageParam: TPageParam) => ReactorArgs<Service, Method, Transform>)
217
- | SkipToken
218
- }
219
-
220
- /**
221
- * Configuration for createInfiniteQueryFactory (without getArgs; provided at call time).
222
- */
223
- export type InfiniteQueryFactoryConfig<
224
- Service = BaseActor,
225
- Method extends FunctionName<Service> = FunctionName<Service>,
226
- Transform extends TransformKey = "candid",
227
- TPageParam = unknown,
228
- Selected = InfiniteData<
229
- InfiniteQueryPageData<Service, Method, Transform>,
230
- TPageParam
231
- >,
232
- > = Omit<
233
- // `getArgs` is supplied per factory call. `getKeyArgs` is inherited from
234
- // InfiniteQueryConfig, which now applies it for every infinite query rather
235
- // than only for factory-created ones.
236
- InfiniteQueryConfig<Service, Method, Transform, TPageParam, Selected>,
237
- "getArgs"
238
- >
239
-
240
- // ============================================================================
241
- // Hook Interface
242
- // ============================================================================
243
-
244
- /**
245
- * useInfiniteQuery hook with chained select support.
246
- */
247
- export interface UseInfiniteQueryWithSelect<
248
- TPageData,
249
- TPageParam,
250
- Selected = InfiniteData<TPageData, TPageParam>,
251
- TError = Error,
252
- > {
253
- // Overload 1: Without select - returns Selected
254
- (
255
- options?: Omit<
256
- UseInfiniteQueryOptions<
257
- TPageData,
258
- TError,
259
- Selected,
260
- QueryKey,
261
- TPageParam
262
- >,
263
- | "select"
264
- | "queryKey"
265
- | "queryFn"
266
- | "initialPageParam"
267
- | "getNextPageParam"
268
- | "getPreviousPageParam"
269
- >
270
- ): UseInfiniteQueryResult<Selected, TError>
271
-
272
- // Overload 2: With select - chains on top and returns TFinal
273
- <TFinal = Selected>(
274
- options: Omit<
275
- UseInfiniteQueryOptions<TPageData, TError, TFinal, QueryKey, TPageParam>,
276
- | "queryKey"
277
- | "queryFn"
278
- | "select"
279
- | "initialPageParam"
280
- | "getNextPageParam"
281
- | "getPreviousPageParam"
282
- > & {
283
- select: (data: Selected) => TFinal
284
- }
285
- ): UseInfiniteQueryResult<TFinal, TError>
286
- }
287
-
288
- // ============================================================================
289
- // Result Interface
290
- // ============================================================================
291
-
292
- /**
293
- * Result from createInfiniteQuery
294
- *
295
- * `cancel()`, `reset()` and `optimisticUpdate()` act on the whole page set:
296
- * `optimisticUpdate` gets and returns the raw `InfiniteData`, `{ pages,
297
- * pageParams }`.
298
- *
299
- * @template TPageData - The raw page data type
300
- * @template TPageParam - The page parameter type
301
- * @template Selected - The type after select transformation
302
- * @template TError - The error type
303
- */
304
- export interface InfiniteQueryResult<
305
- TPageData,
306
- TPageParam,
307
- Selected = InfiniteData<TPageData, TPageParam>,
308
- TError = Error,
309
- > extends QueryCacheControls<InfiniteData<TPageData, TPageParam>> {
310
- /** Fetch first page in loader (uses ensureQueryData for cache-first) */
311
- fetch: () => Promise<Selected>
312
-
313
- /** React hook for components - supports pagination */
314
- useInfiniteQuery: UseInfiniteQueryWithSelect<
315
- TPageData,
316
- TPageParam,
317
- Selected,
318
- TError
319
- >
320
-
321
- /** Invalidate the cache (refetches if query is active) */
322
- invalidate: () => Promise<void>
323
-
324
- /** Get query key (for advanced React Query usage) */
325
- getQueryKey: () => QueryKey
326
-
327
- /**
328
- * Read data directly from cache without fetching.
329
- * Returns undefined if data is not in cache.
330
- */
331
- getCacheData: {
332
- (): Selected | undefined
333
- <TFinal>(select: (data: Selected) => TFinal): TFinal | undefined
334
- }
335
- }
336
-
337
- // ============================================================================
338
- // Internal Implementation
339
- // ============================================================================
340
-
341
- const createInfiniteQueryImpl = <
342
- Service,
343
- Method extends FunctionName<Service> = FunctionName<Service>,
344
- Transform extends TransformKey = "candid",
345
- TPageParam = unknown,
346
- Selected = InfiniteData<
347
- InfiniteQueryPageData<Service, Method, Transform>,
348
- TPageParam
349
- >,
350
- >(
351
- reactor: Reactor<Service, Transform>,
352
- config: InfiniteQueryConfig<Service, Method, Transform, TPageParam, Selected>
353
- ): InfiniteQueryResult<
354
- InfiniteQueryPageData<Service, Method, Transform>,
355
- TPageParam,
356
- Selected,
357
- InfiniteQueryError<Service, Method, Transform>
358
- > => {
359
- type TPageData = InfiniteQueryPageData<Service, Method, Transform>
360
- type TError = InfiniteQueryError<Service, Method, Transform>
361
- type TInfiniteData = InfiniteData<TPageData, TPageParam>
362
-
363
- const {
364
- functionName,
365
- callConfig,
366
- queryKey: customQueryKey,
367
- initialPageParam,
368
- getArgs,
369
- getKeyArgs,
370
- getNextPageParam,
371
- getPreviousPageParam,
372
- maxPages,
373
- staleTime = 5 * 60 * 1000,
374
- select,
375
- ...rest
376
- } = config
377
-
378
- // Fold the call arguments into the key. Without them every infinite query on
379
- // a method shares one cache entry, so two lists with different `getArgs` (a
380
- // different page size, a different filter) serve each other's pages — the
381
- // arguments live in a closure, not in the config, so nothing else
382
- // distinguishes them.
383
- //
384
- // The first page's args stand for the query's identity; `getKeyArgs` lets a
385
- // caller drop the cursor field when it is part of those args.
386
- const getQueryKey = (): QueryKey => {
387
- const initialArgs = getArgs(initialPageParam)
388
- const keyArgs = getKeyArgs?.(initialArgs) ?? initialArgs
389
-
390
- return reactor.generateQueryKey(
391
- {
392
- functionName,
393
- queryKey: mergeFactoryQueryKey(customQueryKey, undefined, keyArgs),
394
- },
395
- callConfig
396
- )
397
- }
398
-
399
- // Query function - accepts QueryFunctionContext
400
- const queryFn = async (
401
- context: QueryFunctionContext<QueryKey, TPageParam>
402
- ): Promise<TPageData> => {
403
- // pageParam is typed as unknown in QueryFunctionContext, but we know its type
404
- const pageParam = context.pageParam as TPageParam
405
- const args = getArgs(pageParam)
406
- const result = await reactor.callMethod({
407
- functionName,
408
- args,
409
- callConfig: callConfigForKey(context.queryKey, callConfig),
410
- })
411
- return normalizeQueryData<ReactorReturnOk<Service, Method, Transform>>(
412
- result as ReactorReturnOk<Service, Method, Transform>
413
- )
414
- }
415
-
416
- // Get infinite query options for fetchInfiniteQuery
417
- const getInfiniteQueryOptions = (): FetchInfiniteQueryOptions<
418
- TPageData,
419
- TError,
420
- TPageData,
421
- QueryKey,
422
- TPageParam
423
- > => {
424
- const queryKey = getQueryKey()
425
- return {
426
- // How the query function runs, shared with the hook; see
427
- // pickFetchOptions. An update method's `retry` defaults as
428
- // `Reactor.getQueryRetry` says.
429
- ...pickFetchOptions(rest),
430
- ...retryOption(rest.retry, reactor.getQueryRetry(functionName, queryKey)),
431
- queryKey,
432
- queryFn,
433
- initialPageParam,
434
- getNextPageParam,
435
- }
436
- }
437
-
438
- // Fetch function for loaders (cache-first, fetches first page)
439
- const fetch = async (): Promise<Selected> => {
440
- // Check cache first
441
- const cachedData = reactor.queryClient.getQueryData(getQueryKey()) as
442
- TInfiniteData | undefined
443
-
444
- if (cachedData !== undefined) {
445
- return select ? select(cachedData) : (cachedData as Selected)
446
- }
447
-
448
- // Fetch if not in cache. A sign-in or sign-out while it is in flight
449
- // cancels it; it then runs again for the new identity rather than
450
- // rejecting with TanStack's CancelledError, as `reactor.fetchQuery` does.
451
- const result = await reactor.clientManager.fetchAcrossIdentitySwitch(() =>
452
- reactor.queryClient.fetchInfiniteQuery(getInfiniteQueryOptions())
453
- )
454
-
455
- // Result is already InfiniteData format
456
- return select ? select(result) : (result as unknown as Selected)
457
- }
458
-
459
- // Implementation
460
- const useInfiniteQueryHook: UseInfiniteQueryWithSelect<
461
- TPageData,
462
- TPageParam,
463
- Selected,
464
- TError
465
- > = (options: any): any => {
466
- useMountQueryClient(reactor.queryClient)
467
-
468
- // Memoized and identity-preserving; see buildChainedSelect for why the
469
- // function identity matters to the observer's select-result cache.
470
- const chainedSelect = useMemo(
471
- () => buildChainedSelect(select as never, options?.select),
472
- [options?.select]
473
- )
474
-
475
- const queryKey = getQueryKey()
476
-
477
- return useInfiniteQuery(
478
- {
479
- queryKey,
480
- queryFn,
481
- initialPageParam,
482
- getNextPageParam,
483
- getPreviousPageParam,
484
- maxPages,
485
- staleTime,
486
- ...rest,
487
- ...options,
488
- select: chainedSelect,
489
- // The hook's `retry`, else the config's, else an update method's
490
- // default; see `Reactor.getQueryRetry`.
491
- ...retryOption(
492
- options?.retry ?? rest.retry,
493
- reactor.getQueryRetry(functionName, queryKey)
494
- ),
495
- } as any,
496
- reactor.queryClient
497
- )
498
- }
499
-
500
- // Invalidate function
501
- const invalidate = async (): Promise<void> => {
502
- const queryKey = getQueryKey()
503
- await reactor.queryClient.invalidateQueries({ queryKey })
504
- }
505
-
506
- // Get data from cache without fetching
507
- const getCacheData: any = (selectFn?: (data: Selected) => any) => {
508
- const queryKey = getQueryKey()
509
- const cachedRawData = reactor.queryClient.getQueryData(
510
- queryKey
511
- ) as TInfiniteData
512
-
513
- if (cachedRawData === undefined) {
514
- return undefined
515
- }
516
-
517
- // Apply config.select to raw cache data
518
- const selectedData = (
519
- select ? select(cachedRawData) : cachedRawData
520
- ) as Selected
521
-
522
- // Apply optional select parameter
523
- if (selectFn) {
524
- return selectFn(selectedData)
525
- }
526
-
527
- return selectedData
528
- }
529
-
530
- return {
531
- fetch,
532
- useInfiniteQuery: useInfiniteQueryHook,
533
- invalidate,
534
- getQueryKey,
535
- getCacheData,
536
- ...queryCacheControls<TInfiniteData>(reactor, getQueryKey),
537
- }
538
- }
539
-
540
- // ============================================================================
541
- // Factory Function
542
- // ============================================================================
543
-
544
- export function createInfiniteQuery<
545
- Service,
546
- Transform extends TransformKey,
547
- Method extends FunctionName<Service> = FunctionName<Service>,
548
- TPageParam = unknown,
549
- Selected = InfiniteData<
550
- InfiniteQueryPageData<Service, Method, Transform>,
551
- TPageParam
552
- >,
553
- >(
554
- reactor: Reactor<Service, Transform>,
555
- config: InfiniteQueryConfig<
556
- NoInfer<Service>,
557
- Method,
558
- Transform,
559
- TPageParam,
560
- Selected
561
- >
562
- ): InfiniteQueryResult<
563
- InfiniteQueryPageData<Service, Method, Transform>,
564
- TPageParam,
565
- Selected,
566
- InfiniteQueryError<Service, Method, Transform>
567
- > {
568
- return createInfiniteQueryImpl(
569
- reactor,
570
- config as InfiniteQueryConfig<
571
- Service,
572
- Method,
573
- Transform,
574
- TPageParam,
575
- Selected
576
- >
577
- )
578
- }
579
-
580
- // ============================================================================
581
- // Factory with Dynamic Args
582
- // ============================================================================
583
-
584
- /**
585
- * Create an infinite query factory that accepts getArgs at call time.
586
- * Useful when pagination logic varies by context.
587
- *
588
- * @template Service - The actor interface type
589
- * @template Method - The method name on the actor
590
- * @template Transform - The transformation key (identity, display, etc.)
591
- * @template TPageParam - The page parameter type
592
- * @template Selected - The type returned after select transformation
593
- *
594
- * @param reactor - The Reactor instance
595
- * @param config - Infinite query configuration (without getArgs)
596
- * @returns A function that accepts getArgs and returns an InfiniteQueryResult
597
- *
598
- * @example
599
- * const getPostsQuery = createInfiniteQueryFactory(reactor, {
600
- * functionName: "get_posts",
601
- * initialPageParam: 0,
602
- * getKeyArgs: (args) => {
603
- * const [{ userId }] = args
604
- * return [{ userId }]
605
- * },
606
- * getNextPageParam: (lastPage) => lastPage.nextCursor,
607
- * })
608
- *
609
- * // Create query with specific args builder
610
- * const userPostsQuery = getPostsQuery((cursor) => [{ userId, cursor, limit: 10 }])
611
- * const { data, fetchNextPage } = userPostsQuery.useInfiniteQuery()
612
- *
613
- * // Every list this factory made, whatever its args and pages
614
- * await getPostsQuery.invalidate()
615
- */
616
-
617
- export function createInfiniteQueryFactory<
618
- Service,
619
- Transform extends TransformKey,
620
- Method extends FunctionName<Service> = FunctionName<Service>,
621
- TPageParam = unknown,
622
- Selected = InfiniteData<
623
- InfiniteQueryPageData<Service, Method, Transform>,
624
- TPageParam
625
- >,
626
- >(
627
- reactor: Reactor<Service, Transform>,
628
- config: InfiniteQueryFactoryConfig<
629
- NoInfer<Service>,
630
- Method,
631
- Transform,
632
- TPageParam,
633
- Selected
634
- >
635
- ): InfiniteQueryFactoryFn<Service, Method, Transform, TPageParam, Selected> {
636
- const factory = (
637
- getArgs: (pageParam: TPageParam) => ReactorArgs<Service, Method, Transform>
638
- ) => {
639
- // `getKeyArgs` and the args-derived key segment are applied by the impl,
640
- // which now does it for every infinite query rather than only for factories.
641
- return createInfiniteQueryImpl<
642
- Service,
643
- Method,
644
- Transform,
645
- TPageParam,
646
- Selected
647
- >(reactor, {
648
- ...(config as InfiniteQueryFactoryConfig<
649
- Service,
650
- Method,
651
- Transform,
652
- TPageParam,
653
- Selected
654
- >),
655
- getArgs,
656
- })
657
- }
658
-
659
- // What every instance's key starts with: the method, the `callConfig`
660
- // segments and the config `queryKey`. The args segment comes after them.
661
- return withQueryFactoryMethods(factory, reactor, () =>
662
- reactor.generateQueryKey(
663
- {
664
- functionName: config.functionName as Method,
665
- queryKey: config.queryKey,
666
- },
667
- config.callConfig
668
- )
669
- )
670
- }