@ic-reactor/react 3.13.0 → 4.0.0-beta.2

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