@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,205 +0,0 @@
1
- import { useCallback } from "react"
2
- import {
3
- useMutation,
4
- UseMutationOptions,
5
- UseMutationResult,
6
- } from "@tanstack/react-query"
7
- import {
8
- Reactor,
9
- ReactorArgs,
10
- ReactorReturnOk,
11
- FunctionName,
12
- TransformKey,
13
- ReactorReturnErr,
14
- isCanisterError,
15
- CanisterError,
16
- ErrResult,
17
- ActorMethodReturnType,
18
- TransformReturnRegistry,
19
- } from "@ic-reactor/core"
20
- import { CallConfig } from "@icp-sdk/core/agent"
21
- import { invalidateTargets, useMountQueryClient } from "../utils.js"
22
- import type { InvalidationTarget } from "../types.js"
23
-
24
- export interface UseActorMutationParameters<
25
- Service,
26
- Method extends FunctionName<Service>,
27
- Transform extends TransformKey = "candid",
28
- TOnMutateResult = unknown,
29
- > extends Omit<
30
- UseMutationOptions<
31
- ReactorReturnOk<Service, Method, Transform>,
32
- ReactorReturnErr<Service, Method, Transform>,
33
- ReactorArgs<Service, Method, Transform>,
34
- TOnMutateResult
35
- >,
36
- "mutationFn"
37
- > {
38
- reactor: Reactor<Service, Transform>
39
- functionName: Method
40
- callConfig?: CallConfig
41
- /**
42
- * Queries to invalidate upon successful mutation, awaited before
43
- * `onSuccess` runs.
44
- *
45
- * Each entry is a query key, a query object or query factory, or a
46
- * `{ functionName, args? }` method of `reactor`; see
47
- * {@link InvalidationTarget}. `undefined` entries are skipped, so
48
- * `[maybeQuery]` is safe when the optional query object is absent.
49
- */
50
- invalidateQueries?: InvalidationTarget<Service, Transform>[]
51
- /**
52
- * Callback for canister-level business logic errors.
53
- * Called when the canister returns a Result { Err: E } variant.
54
- * Separate from `onError`, which fires for all errors including network failures.
55
- */
56
- onCanisterError?: (
57
- error: CanisterError<
58
- TransformReturnRegistry<
59
- ErrResult<ActorMethodReturnType<Service[Method]>>,
60
- Service
61
- >[Transform]
62
- >,
63
- variables: ReactorArgs<Service, Method, Transform>
64
- ) => void
65
- }
66
-
67
- export type UseActorMutationConfig<
68
- Service,
69
- Method extends FunctionName<Service>,
70
- Transform extends TransformKey = "candid",
71
- TOnMutateResult = unknown,
72
- > = Omit<
73
- UseActorMutationParameters<Service, Method, Transform, TOnMutateResult>,
74
- "reactor"
75
- >
76
-
77
- export type UseActorMutationResult<
78
- Service,
79
- Method extends FunctionName<Service>,
80
- Transform extends TransformKey = "candid",
81
- TOnMutateResult = unknown,
82
- > = UseMutationResult<
83
- ReactorReturnOk<Service, Method, Transform>,
84
- ReactorReturnErr<Service, Method, Transform>,
85
- ReactorArgs<Service, Method, Transform>,
86
- TOnMutateResult
87
- >
88
-
89
- /**
90
- * Hook for executing mutation calls on a canister.
91
- * Use this for component-level mutation flows.
92
- * For non-React usage, prefer `createMutation(...).execute(args)`.
93
- *
94
- * @example
95
- * const { mutate, isPending } = useReactorMutation({
96
- * reactor,
97
- * functionName: "transfer",
98
- * onSuccess: () => console.log("Success!"),
99
- * onCanisterError: (err) => console.error("Canister Err:", err.code),
100
- * })
101
- *
102
- * @example
103
- * const transferMutation = createMutation(reactor, {
104
- * functionName: "transfer",
105
- * onCanisterError: (err) => console.error(err.code),
106
- * })
107
- *
108
- * // Non-React execution path
109
- * await transferMutation.execute([{ to: "aaaaa-aa", amount: "100" }])
110
- */
111
- export const useActorMutation = <
112
- Service,
113
- Method extends FunctionName<Service>,
114
- Transform extends TransformKey = "candid",
115
- TOnMutateResult = unknown,
116
- >({
117
- reactor,
118
- functionName,
119
- invalidateQueries,
120
- onSuccess,
121
- onError,
122
- onCanisterError,
123
- callConfig,
124
- ...options
125
- }: UseActorMutationParameters<
126
- Service,
127
- Method,
128
- Transform,
129
- TOnMutateResult
130
- >): UseActorMutationResult<Service, Method, Transform, TOnMutateResult> => {
131
- useMountQueryClient(reactor.queryClient)
132
-
133
- const mutationFn = useCallback(
134
- async (args: ReactorArgs<Service, Method, Transform>) =>
135
- reactor.callMethod({ functionName, callConfig, args }),
136
- [reactor, functionName, callConfig]
137
- )
138
-
139
- const handleSuccess = useCallback(
140
- async (
141
- ...params: Parameters<
142
- NonNullable<
143
- UseMutationOptions<
144
- ReactorReturnOk<Service, Method, Transform>,
145
- ReactorReturnErr<Service, Method, Transform>,
146
- ReactorArgs<Service, Method, Transform>,
147
- TOnMutateResult
148
- >["onSuccess"]
149
- >
150
- >
151
- ) => {
152
- // Undefined entries are skipped: React Query reads
153
- // `{ queryKey: undefined }` as "match everything", and the natural
154
- // `[maybeQuery]` idiom produces one whenever the query is absent.
155
- await invalidateTargets(reactor, invalidateQueries, callConfig)
156
- await onSuccess?.(...params)
157
- },
158
- [reactor, invalidateQueries, onSuccess, callConfig]
159
- )
160
-
161
- const handleError = useCallback(
162
- async (
163
- error: ReactorReturnErr<Service, Method, Transform>,
164
- variables: ReactorArgs<Service, Method, Transform>,
165
- context: unknown,
166
- mutation: unknown
167
- ) => {
168
- if (isCanisterError(error)) {
169
- onCanisterError?.(error as any, variables)
170
- }
171
- // Awaited like `onSuccess` above. TanStack Query waits for the promise
172
- // `onError` returns before it runs `onSettled` and settles the mutation,
173
- // and it can only wait for a promise this wrapper passes back.
174
- await onError?.(error, variables, context as any, mutation as any)
175
- },
176
- [onCanisterError, onError]
177
- )
178
-
179
- // Not memoized. The deps could only ever list the values destructured above,
180
- // never the `options` rest bucket, so everything passed straight through —
181
- // `onMutate`, `onSettled`, `retry`, `meta`, `gcTime` — was frozen at the first
182
- // render: `useMutation` calls `observer.setOptions` from an effect keyed on
183
- // the options identity, so a later render's closures never reached it. A
184
- // component passing only `onSettled` would report the recipient selected at
185
- // mount rather than at submit.
186
- //
187
- // `createMutation`'s own hook builds its options inline for the same reason.
188
- // A fresh object per render costs nothing here: `setOptions` diffs the values
189
- // rather than the reference.
190
- return useMutation(
191
- {
192
- // Keyed like `createMutation`'s hook and `useActorMethod`'s mutations,
193
- // so `useIsMutating({ mutationKey })`, `useMutationState` and defaults
194
- // registered with `setMutationDefaults` can find this one too. An
195
- // explicit `mutationKey` in the options still wins.
196
- mutationKey: reactor.getQueryOptions({ functionName, callConfig })
197
- .queryKey,
198
- ...options,
199
- mutationFn,
200
- onSuccess: handleSuccess,
201
- onError: handleError,
202
- },
203
- reactor.queryClient
204
- )
205
- }
@@ -1,157 +0,0 @@
1
- import { useMemo } from "react"
2
- import {
3
- QueryKey,
4
- useQuery,
5
- skipToken,
6
- QueryObserverOptions,
7
- UseQueryResult,
8
- type SkipToken,
9
- } from "@tanstack/react-query"
10
- import {
11
- FunctionName,
12
- Reactor,
13
- TransformKey,
14
- ReactorArgs,
15
- ReactorReturnOk,
16
- ReactorQueryData,
17
- ReactorReturnErr,
18
- } from "@ic-reactor/core"
19
- import { CallConfig } from "@icp-sdk/core/agent"
20
- import { retryOption, skippedQueryKey, useMountQueryClient } from "../utils.js"
21
-
22
- export interface UseActorQueryParameters<
23
- Service,
24
- Method extends FunctionName<Service>,
25
- Transform extends TransformKey = "candid",
26
- Selected = ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
27
- > extends Omit<
28
- QueryObserverOptions<
29
- ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
30
- ReactorReturnErr<Service, Method, Transform>,
31
- Selected,
32
- ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
33
- QueryKey
34
- >,
35
- "queryKey" | "queryFn"
36
- > {
37
- reactor: Reactor<Service, Transform>
38
- functionName: Method
39
- /**
40
- * The method's arguments, or TanStack Query's `skipToken` while they are
41
- * not known: the query then waits without fetching, in an entry of its own
42
- * under its method's key, which no call's key shares, so it shows no data
43
- * until the arguments arrive.
44
- */
45
- args?: ReactorArgs<Service, Method, Transform> | SkipToken
46
- callConfig?: CallConfig
47
- queryKey?: QueryKey
48
- }
49
-
50
- export type UseActorQueryConfig<
51
- Service,
52
- Method extends FunctionName<Service>,
53
- Transform extends TransformKey = "candid",
54
- Selected = ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
55
- > = Omit<
56
- UseActorQueryParameters<Service, Method, Transform, Selected>,
57
- "reactor"
58
- >
59
-
60
- export type UseActorQueryResult<
61
- Service,
62
- Method extends FunctionName<Service>,
63
- Transform extends TransformKey = "candid",
64
- Selected = ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
65
- > = UseQueryResult<Selected, ReactorReturnErr<Service, Method, Transform>>
66
-
67
- /**
68
- * Hook for executing query calls on a canister.
69
- *
70
- * @example
71
- * const { data, isLoading } = useReactorQuery({
72
- * reactor,
73
- * functionName: "getUser",
74
- * args: ["user-123"],
75
- * })
76
- *
77
- * // With select transformation
78
- * const { data } = useReactorQuery({
79
- * reactor,
80
- * functionName: "getUser",
81
- * args: ["user-123"],
82
- * select: (user) => user.name,
83
- * })
84
- *
85
- * // Wait for the args: no fetch until userId is known
86
- * const { data } = useReactorQuery({
87
- * reactor,
88
- * functionName: "getUser",
89
- * args: userId ? [userId] : skipToken,
90
- * })
91
- */
92
- export const useActorQuery = <
93
- Service,
94
- Method extends FunctionName<Service>,
95
- Transform extends TransformKey = "candid",
96
- Selected = ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
97
- >({
98
- reactor,
99
- functionName,
100
- args,
101
- callConfig,
102
- queryKey: defaultQueryKey,
103
- ...options
104
- }: UseActorQueryParameters<
105
- Service,
106
- Method,
107
- Transform,
108
- Selected
109
- >): UseActorQueryResult<Service, Method, Transform, Selected> => {
110
- useMountQueryClient(reactor.queryClient)
111
-
112
- // Memoize query options to prevent unnecessary re-computations
113
- // For an update method, the options also carry its default `retry`; see
114
- // `Reactor.getQueryRetry`.
115
- const { queryKey, queryFn, retry } = useMemo(
116
- () =>
117
- args === skipToken
118
- ? // Waiting for its args: an entry of its own under the method's key,
119
- // with nothing to run until then; see skippedQueryKey.
120
- {
121
- queryKey: skippedQueryKey(
122
- reactor.generateQueryKey({ functionName }, callConfig),
123
- "query"
124
- ),
125
- // Kept as the unique symbol, which an object literal widens.
126
- queryFn: skipToken as SkipToken,
127
- retry: undefined,
128
- }
129
- : reactor.getQueryOptions<Method>({
130
- callConfig,
131
- functionName,
132
- args,
133
- queryKey: defaultQueryKey,
134
- }),
135
- // `canisterId` is mutable reactor state that `setCanisterId` can change,
136
- // while `reactor` itself stays the same object — so it has to be a
137
- // dependency in its own right or the key stays pinned to the old canister.
138
- [
139
- reactor,
140
- reactor.canisterId?.toString(),
141
- callConfig,
142
- functionName,
143
- args,
144
- defaultQueryKey,
145
- ]
146
- )
147
-
148
- return useQuery(
149
- {
150
- queryFn,
151
- ...options,
152
- queryKey,
153
- ...retryOption(options.retry, retry),
154
- },
155
- reactor.queryClient
156
- )
157
- }
@@ -1,248 +0,0 @@
1
- import { useMemo, useCallback } from "react"
2
- import {
3
- QueryKey,
4
- useSuspenseInfiniteQuery,
5
- UseSuspenseInfiniteQueryResult,
6
- UseSuspenseInfiniteQueryOptions,
7
- InfiniteData,
8
- } from "@tanstack/react-query"
9
- import {
10
- FunctionName,
11
- Reactor,
12
- TransformKey,
13
- ReactorArgs,
14
- ReactorReturnOk,
15
- ReactorQueryData,
16
- ReactorReturnErr,
17
- } from "@ic-reactor/core"
18
- import { CallConfig } from "@icp-sdk/core/agent"
19
- import {
20
- callConfigForKey,
21
- mergeFactoryQueryKey,
22
- mountWhileSuspended,
23
- normalizeQueryData,
24
- retryOption,
25
- useMountQueryClient,
26
- } from "../utils.js"
27
-
28
- /**
29
- * Parameters for useActorSuspenseInfiniteQuery hook.
30
- * Extends react-query's UseSuspenseInfiniteQueryOptions with custom reactor params.
31
- */
32
- export interface UseActorSuspenseInfiniteQueryParameters<
33
- Service,
34
- Method extends FunctionName<Service>,
35
- Transform extends TransformKey = "candid",
36
- TPageParam = unknown,
37
- Selected = InfiniteData<
38
- ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
39
- TPageParam
40
- >,
41
- > extends Omit<
42
- UseSuspenseInfiniteQueryOptions<
43
- ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
44
- ReactorReturnErr<Service, Method, Transform>,
45
- Selected,
46
- QueryKey,
47
- TPageParam
48
- >,
49
- "queryKey" | "queryFn" | "getNextPageParam" | "initialPageParam"
50
- > {
51
- /** The reactor instance to use for method calls */
52
- reactor: Reactor<Service, Transform>
53
- /** The method name to call on the canister */
54
- functionName: Method
55
- /** Function to get args from page parameter */
56
- getArgs: (pageParam: TPageParam) => ReactorArgs<Service, Method, Transform>
57
- /**
58
- * Narrows what the cache key derives from the call arguments.
59
- *
60
- * By default the key is scoped by `getArgs(initialPageParam)`, so two
61
- * infinite queries on the same method with different arguments stay in
62
- * separate cache entries. Supply this when those args embed the cursor and
63
- * only part of them identifies the query — return the stable, serializable
64
- * portion (typically everything except the pagination field). It is required
65
- * when `initialPageParam` changes between renders, as `Date.now()` does:
66
- * without it every render keys a new query.
67
- */
68
- getKeyArgs?: (args: ReactorArgs<Service, Method, Transform>) => unknown
69
- /** Agent call configuration (effectiveCanisterId, etc.) */
70
- callConfig?: CallConfig
71
- /** Custom query key (auto-generated if not provided) */
72
- queryKey?: QueryKey
73
- /** Initial page parameter */
74
- initialPageParam: TPageParam
75
- /** Function to determine next page parameter */
76
- getNextPageParam: (
77
- lastPage: ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
78
- allPages: ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>[],
79
- lastPageParam: TPageParam,
80
- allPageParams: TPageParam[]
81
- ) => TPageParam | undefined | null
82
- }
83
-
84
- export type UseActorSuspenseInfiniteQueryConfig<
85
- Service,
86
- Method extends FunctionName<Service>,
87
- Transform extends TransformKey = "candid",
88
- TPageParam = unknown,
89
- Selected = InfiniteData<
90
- ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
91
- TPageParam
92
- >,
93
- > = Omit<
94
- UseActorSuspenseInfiniteQueryParameters<
95
- Service,
96
- Method,
97
- Transform,
98
- TPageParam,
99
- Selected
100
- >,
101
- "reactor"
102
- >
103
-
104
- export type UseActorSuspenseInfiniteQueryResult<
105
- Service,
106
- Method extends FunctionName<Service>,
107
- Transform extends TransformKey = "candid",
108
- TPageParam = unknown,
109
- Selected = InfiniteData<
110
- ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
111
- TPageParam
112
- >,
113
- > = UseSuspenseInfiniteQueryResult<
114
- Selected,
115
- ReactorReturnErr<Service, Method, Transform>
116
- >
117
-
118
- /**
119
- * Hook for executing suspense-enabled infinite/paginated query calls on a canister.
120
- *
121
- * @example
122
- * const { data, fetchNextPage, hasNextPage } = useReactorSuspenseInfiniteQuery({
123
- * reactor,
124
- * functionName: "getItems",
125
- * getArgs: (pageParam) => [{ offset: pageParam, limit: 10 }] as const,
126
- * initialPageParam: 0,
127
- * getNextPageParam: (lastPage) => lastPage.nextOffset,
128
- * })
129
- */
130
- export const useActorSuspenseInfiniteQuery = <
131
- Service,
132
- Method extends FunctionName<Service>,
133
- Transform extends TransformKey = "candid",
134
- TPageParam = unknown,
135
- Selected = InfiniteData<
136
- ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
137
- TPageParam
138
- >,
139
- >({
140
- reactor,
141
- functionName,
142
- getArgs,
143
- getKeyArgs,
144
- callConfig,
145
- queryKey,
146
- ...options
147
- }: UseActorSuspenseInfiniteQueryParameters<
148
- Service,
149
- Method,
150
- Transform,
151
- TPageParam,
152
- Selected
153
- >): UseActorSuspenseInfiniteQueryResult<
154
- Service,
155
- Method,
156
- Transform,
157
- TPageParam,
158
- Selected
159
- > => {
160
- useMountQueryClient(reactor.queryClient)
161
-
162
- // Always pass queryKey through generateQueryKey so it is merged with the
163
- // reactor/function identity. Using the custom key verbatim would cause cache
164
- // collisions if two different actors or methods share the same key string.
165
- const baseQueryKey = useMemo(() => {
166
- // Fold the call arguments into the key. They live in the `getArgs`
167
- // closure rather than in the config, so without this two hooks on the
168
- // same method with different arguments share one cache entry and serve
169
- // each other's pages. `getKeyArgs` narrows them exactly as it does for the
170
- // factories, which the bound hook's config type always accepted: it used
171
- // to be ignored here, so the cursor stayed in the key, and an
172
- // `initialPageParam` that changes every render (`Date.now()`) keyed a new
173
- // query on every render — an endless loop of first-page fetches.
174
- const initialArgs = getArgs(options.initialPageParam)
175
- const keyArgs = getKeyArgs?.(initialArgs) ?? initialArgs
176
-
177
- return reactor.generateQueryKey(
178
- {
179
- functionName,
180
- queryKey: mergeFactoryQueryKey(queryKey, undefined, keyArgs),
181
- },
182
- callConfig
183
- )
184
- }, [
185
- queryKey,
186
- reactor,
187
- // `canisterId` is mutable reactor state that `setCanisterId` can change,
188
- // while `reactor` itself stays the same object — so it has to be a
189
- // dependency in its own right or the key stays pinned to the old canister
190
- // while the queryFn already calls the new one.
191
- reactor.canisterId?.toString(),
192
- functionName,
193
- callConfig,
194
- getArgs,
195
- getKeyArgs,
196
- options.initialPageParam,
197
- ])
198
-
199
- // Memoize queryFn to prevent recreation on every render
200
- const queryFn = useCallback(
201
- async ({
202
- pageParam,
203
- queryKey: fetchedKey,
204
- }: {
205
- pageParam: TPageParam
206
- queryKey: QueryKey
207
- }) => {
208
- const args = getArgs(pageParam)
209
- const result = await reactor.callMethod({
210
- functionName,
211
- args,
212
- callConfig: callConfigForKey(fetchedKey, callConfig),
213
- })
214
- return normalizeQueryData<ReactorReturnOk<Service, Method, Transform>>(
215
- result as ReactorReturnOk<Service, Method, Transform>
216
- )
217
- },
218
- [reactor, functionName, getArgs, callConfig]
219
- )
220
-
221
- // The method's default `retry`: for an update method, only failures that
222
- // prove the canister never ran the call; see `Reactor.getQueryRetry`.
223
- const defaultRetry = useMemo(
224
- () => reactor.getQueryRetry(functionName, baseQueryKey),
225
- [reactor, functionName, baseQueryKey]
226
- )
227
-
228
- try {
229
- return useSuspenseInfiniteQuery(
230
- {
231
- queryKey: baseQueryKey,
232
- queryFn,
233
- ...options,
234
- ...retryOption(options.retry, defaultRetry),
235
- } as any,
236
- reactor.queryClient
237
- ) as UseActorSuspenseInfiniteQueryResult<
238
- Service,
239
- Method,
240
- Transform,
241
- TPageParam,
242
- Selected
243
- >
244
- } catch (thrown) {
245
- mountWhileSuspended(reactor.queryClient, thrown)
246
- throw thrown
247
- }
248
- }