@ic-reactor/react 3.12.5 → 3.13.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.
- package/README.md +410 -44
- package/dist/auth/auth-client-compat.d.ts +122 -0
- package/dist/auth/auth-client-compat.d.ts.map +1 -0
- package/dist/auth/auth-client-compat.js +162 -0
- package/dist/auth/auth-client-compat.js.map +1 -0
- package/dist/auth/authentication-manager.d.ts +287 -5
- package/dist/auth/authentication-manager.d.ts.map +1 -1
- package/dist/auth/authentication-manager.js +920 -150
- package/dist/auth/authentication-manager.js.map +1 -1
- package/dist/auth/createIdentityAttributeHooks.d.ts.map +1 -1
- package/dist/auth/createIdentityAttributeHooks.js +36 -20
- package/dist/auth/createIdentityAttributeHooks.js.map +1 -1
- package/dist/auth/identity-attributes-manager.d.ts +2 -1
- package/dist/auth/identity-attributes-manager.d.ts.map +1 -1
- package/dist/auth/identity-attributes-manager.js +90 -6
- package/dist/auth/identity-attributes-manager.js.map +1 -1
- package/dist/auth/identity-attributes.d.ts.map +1 -1
- package/dist/auth/identity-attributes.js +57 -0
- package/dist/auth/identity-attributes.js.map +1 -1
- package/dist/auth/local-ii-probe.d.ts +12 -1
- package/dist/auth/local-ii-probe.d.ts.map +1 -1
- package/dist/auth/local-ii-probe.js +22 -3
- package/dist/auth/local-ii-probe.js.map +1 -1
- package/dist/auth/types.d.ts +48 -5
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/createActorHooks.d.ts +7 -18
- package/dist/createActorHooks.d.ts.map +1 -1
- package/dist/createActorHooks.js.map +1 -1
- package/dist/createInfiniteQuery.d.ts +51 -10
- package/dist/createInfiniteQuery.d.ts.map +1 -1
- package/dist/createInfiniteQuery.js +39 -15
- package/dist/createInfiniteQuery.js.map +1 -1
- package/dist/createMutation.d.ts +3 -0
- package/dist/createMutation.d.ts.map +1 -1
- package/dist/createMutation.js +87 -80
- package/dist/createMutation.js.map +1 -1
- package/dist/createQuery.d.ts +35 -2
- package/dist/createQuery.d.ts.map +1 -1
- package/dist/createQuery.js +104 -17
- package/dist/createQuery.js.map +1 -1
- package/dist/createReactorProvider.d.ts +158 -0
- package/dist/createReactorProvider.d.ts.map +1 -0
- package/dist/createReactorProvider.js +256 -0
- package/dist/createReactorProvider.js.map +1 -0
- package/dist/createSuspenseInfiniteQuery.d.ts +16 -9
- package/dist/createSuspenseInfiniteQuery.d.ts.map +1 -1
- package/dist/createSuspenseInfiniteQuery.js +59 -27
- package/dist/createSuspenseInfiniteQuery.js.map +1 -1
- package/dist/createSuspenseQuery.d.ts +23 -2
- package/dist/createSuspenseQuery.d.ts.map +1 -1
- package/dist/createSuspenseQuery.js +68 -21
- package/dist/createSuspenseQuery.js.map +1 -1
- package/dist/defineDisplayReactor.d.ts +43 -0
- package/dist/defineDisplayReactor.d.ts.map +1 -0
- package/dist/defineDisplayReactor.js +42 -0
- package/dist/defineDisplayReactor.js.map +1 -0
- package/dist/defineReactor.d.ts +46 -72
- package/dist/defineReactor.d.ts.map +1 -1
- package/dist/defineReactor.js +11 -176
- package/dist/defineReactor.js.map +1 -1
- package/dist/defineReactorShared.d.ts +84 -0
- package/dist/defineReactorShared.d.ts.map +1 -0
- package/dist/defineReactorShared.js +139 -0
- package/dist/defineReactorShared.js.map +1 -0
- package/dist/hooks/createAuthHooks.d.ts +7 -0
- package/dist/hooks/createAuthHooks.d.ts.map +1 -1
- package/dist/hooks/createAuthHooks.js +180 -20
- package/dist/hooks/createAuthHooks.js.map +1 -1
- package/dist/hooks/useActorInfiniteQuery.d.ts +34 -6
- package/dist/hooks/useActorInfiniteQuery.d.ts.map +1 -1
- package/dist/hooks/useActorInfiniteQuery.js +54 -21
- package/dist/hooks/useActorInfiniteQuery.js.map +1 -1
- package/dist/hooks/useActorMethod.d.ts +37 -4
- package/dist/hooks/useActorMethod.d.ts.map +1 -1
- package/dist/hooks/useActorMethod.js +201 -57
- package/dist/hooks/useActorMethod.js.map +1 -1
- package/dist/hooks/useActorMutation.d.ts +10 -7
- package/dist/hooks/useActorMutation.d.ts.map +1 -1
- package/dist/hooks/useActorMutation.js +14 -13
- package/dist/hooks/useActorMutation.js.map +1 -1
- package/dist/hooks/useActorQuery.d.ts +17 -4
- package/dist/hooks/useActorQuery.d.ts.map +1 -1
- package/dist/hooks/useActorQuery.js +30 -9
- package/dist/hooks/useActorQuery.js.map +1 -1
- package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts +15 -3
- package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts.map +1 -1
- package/dist/hooks/useActorSuspenseInfiniteQuery.js +37 -17
- package/dist/hooks/useActorSuspenseInfiniteQuery.js.map +1 -1
- package/dist/hooks/useActorSuspenseQuery.d.ts +2 -2
- package/dist/hooks/useActorSuspenseQuery.d.ts.map +1 -1
- package/dist/hooks/useActorSuspenseQuery.js +20 -9
- package/dist/hooks/useActorSuspenseQuery.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/ownedAuthentication.d.ts +52 -0
- package/dist/ownedAuthentication.d.ts.map +1 -0
- package/dist/ownedAuthentication.js +49 -0
- package/dist/ownedAuthentication.js.map +1 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +23 -0
- package/dist/server.js.map +1 -0
- package/dist/testing.d.ts +19 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +19 -0
- package/dist/testing.js.map +1 -0
- package/dist/types.d.ts +416 -15
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/utils.d.ts +159 -3
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +301 -1
- package/dist/utils.js.map +1 -1
- package/dist/validation.d.ts +12 -7
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +34 -15
- package/dist/validation.js.map +1 -1
- package/llms.txt +259 -33
- package/package.json +17 -5
- package/src/auth/auth-client-compat.ts +273 -0
- package/src/auth/authentication-manager.ts +918 -96
- package/src/auth/createIdentityAttributeHooks.ts +47 -21
- package/src/auth/identity-attributes-manager.ts +100 -5
- package/src/auth/identity-attributes.ts +75 -0
- package/src/auth/local-ii-probe.ts +29 -3
- package/src/auth/types.ts +49 -6
- package/src/createActorHooks.ts +20 -32
- package/src/createInfiniteQuery.ts +120 -28
- package/src/createMutation.ts +161 -178
- package/src/createQuery.ts +164 -32
- package/src/createReactorProvider.ts +365 -0
- package/src/createSuspenseInfiniteQuery.ts +93 -43
- package/src/createSuspenseQuery.ts +102 -32
- package/src/defineDisplayReactor.ts +62 -0
- package/src/defineReactor.ts +81 -263
- package/src/defineReactorShared.ts +268 -0
- package/src/hooks/createAuthHooks.ts +206 -24
- package/src/hooks/useActorInfiniteQuery.ts +122 -49
- package/src/hooks/useActorMethod.ts +295 -92
- package/src/hooks/useActorMutation.ts +23 -23
- package/src/hooks/useActorQuery.ts +43 -10
- package/src/hooks/useActorSuspenseInfiniteQuery.ts +93 -50
- package/src/hooks/useActorSuspenseQuery.ts +30 -15
- package/src/index.ts +8 -0
- package/src/ownedAuthentication.ts +81 -0
- package/src/server.ts +23 -0
- package/src/testing.ts +18 -0
- package/src/types.ts +463 -14
- package/src/utils.ts +387 -3
- package/src/validation.ts +43 -19
package/src/createMutation.ts
CHANGED
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
* @example
|
|
10
10
|
* const transferMutation = createMutation(reactor, {
|
|
11
11
|
* functionName: "transfer",
|
|
12
|
+
* // Refetched before onSuccess runs: a query factory covers every args
|
|
13
|
+
* // instance, a `{ functionName }` every query of that method
|
|
14
|
+
* invalidateQueries: [getBalance, { functionName: "get_history" }],
|
|
12
15
|
* onSuccess: () => console.log("Success!"),
|
|
13
16
|
* })
|
|
14
17
|
*
|
|
@@ -28,6 +31,7 @@
|
|
|
28
31
|
import {
|
|
29
32
|
useMutation,
|
|
30
33
|
type MutationFunctionContext,
|
|
34
|
+
type UseMutationOptions,
|
|
31
35
|
} from "@tanstack/react-query"
|
|
32
36
|
import type {
|
|
33
37
|
Reactor,
|
|
@@ -44,22 +48,7 @@ import type {
|
|
|
44
48
|
MutationHookOptions,
|
|
45
49
|
NoInfer,
|
|
46
50
|
} from "./types.js"
|
|
47
|
-
|
|
48
|
-
// ============================================================================
|
|
49
|
-
// Internal helpers
|
|
50
|
-
// ============================================================================
|
|
51
|
-
|
|
52
|
-
/** Invalidate a list of query keys in parallel, filtering out undefineds. */
|
|
53
|
-
async function invalidateAll(
|
|
54
|
-
queryClient: Reactor<any, any>["queryClient"],
|
|
55
|
-
keys: (import("@tanstack/react-query").QueryKey | undefined)[]
|
|
56
|
-
): Promise<void> {
|
|
57
|
-
await Promise.all(
|
|
58
|
-
keys.map((queryKey) =>
|
|
59
|
-
queryKey ? queryClient.invalidateQueries({ queryKey }) : Promise.resolve()
|
|
60
|
-
)
|
|
61
|
-
)
|
|
62
|
-
}
|
|
51
|
+
import { invalidateTargets, useMountQueryClient } from "./utils.js"
|
|
63
52
|
|
|
64
53
|
// ============================================================================
|
|
65
54
|
// Internal Implementation
|
|
@@ -79,6 +68,10 @@ const createMutationImpl = <
|
|
|
79
68
|
TOnMutateResult | undefined
|
|
80
69
|
>
|
|
81
70
|
): MutationResult<Service, Method, Transform> => {
|
|
71
|
+
type TData = ReactorReturnOk<Service, Method, Transform>
|
|
72
|
+
type TError = ReactorReturnErr<Service, Method, Transform>
|
|
73
|
+
type TVariables = ReactorArgs<Service, Method, Transform>
|
|
74
|
+
|
|
82
75
|
const {
|
|
83
76
|
functionName,
|
|
84
77
|
callConfig,
|
|
@@ -96,13 +89,11 @@ const createMutationImpl = <
|
|
|
96
89
|
* Used as mutationFn so that onSuccess handles all post-mutation work
|
|
97
90
|
* and there is no double-invalidation.
|
|
98
91
|
*/
|
|
99
|
-
const callFn = (
|
|
100
|
-
args: ReactorArgs<Service, Method, Transform>
|
|
101
|
-
): Promise<ReactorReturnOk<Service, Method, Transform>> =>
|
|
92
|
+
const callFn = (args: TVariables): Promise<TData> =>
|
|
102
93
|
reactor.callMethod({ functionName, args, callConfig })
|
|
103
94
|
|
|
104
95
|
/**
|
|
105
|
-
* The factory's own `onMutate` result for each call
|
|
96
|
+
* The factory's own `onMutate` result for each call.
|
|
106
97
|
*
|
|
107
98
|
* TanStack Query stores one `onMutate` result per mutation and hands it to
|
|
108
99
|
* every callback. That slot holds the hook's result, which the mutation also
|
|
@@ -117,9 +108,7 @@ const createMutationImpl = <
|
|
|
117
108
|
|
|
118
109
|
/**
|
|
119
110
|
* The `onMutate` result a factory callback receives. A factory without its
|
|
120
|
-
* own `onMutate` gets the hook's, as it always has.
|
|
121
|
-
* 5.89 passes no context, so there a factory callback gets the hook's result
|
|
122
|
-
* too.
|
|
111
|
+
* own `onMutate` gets the hook's, as it always has.
|
|
123
112
|
*/
|
|
124
113
|
const factoryOnMutateResult = (
|
|
125
114
|
onMutateResult: unknown,
|
|
@@ -129,73 +118,160 @@ const createMutationImpl = <
|
|
|
129
118
|
? factoryOnMutateResults.get(context)
|
|
130
119
|
: onMutateResult) as TOnMutateResult | undefined
|
|
131
120
|
|
|
121
|
+
/**
|
|
122
|
+
* The options a mutation of this factory runs with, on both call paths: the
|
|
123
|
+
* factory's config, the hook's options on top when there is a hook, and the
|
|
124
|
+
* callbacks of both levels chained, factory first. `useMutation()` hands
|
|
125
|
+
* them to TanStack Query's `useMutation`, and `execute()` builds a mutation
|
|
126
|
+
* from them in the QueryClient's MutationCache.
|
|
127
|
+
*/
|
|
128
|
+
const mutationOptions = <THookOnMutateResult = unknown>(
|
|
129
|
+
options?: MutationHookOptions<
|
|
130
|
+
Service,
|
|
131
|
+
Method,
|
|
132
|
+
Transform,
|
|
133
|
+
THookOnMutateResult
|
|
134
|
+
>
|
|
135
|
+
): UseMutationOptions<TData, TError, TVariables, THookOnMutateResult> => {
|
|
136
|
+
const {
|
|
137
|
+
invalidateQueries: hookInvalidateQueries,
|
|
138
|
+
onCanisterError: hookOnCanisterError,
|
|
139
|
+
...restOptions
|
|
140
|
+
} = options ?? {}
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
mutationKey: reactor.getQueryOptions({ functionName }).queryKey,
|
|
144
|
+
...factoryOptions,
|
|
145
|
+
...restOptions,
|
|
146
|
+
// Use callFn (not execute) to avoid double-invalidation:
|
|
147
|
+
// factoryInvalidateQueries are handled in onSuccess below.
|
|
148
|
+
mutationFn: callFn,
|
|
149
|
+
onSuccess: async (data, variables, onMutateResult, context) => {
|
|
150
|
+
// 1. Factory-level invalidation
|
|
151
|
+
await invalidateTargets(reactor, factoryInvalidateQueries, callConfig)
|
|
152
|
+
// 2. Hook-level invalidation
|
|
153
|
+
await invalidateTargets(reactor, hookInvalidateQueries, callConfig)
|
|
154
|
+
// 3. Factory onSuccess
|
|
155
|
+
await factoryOnSuccess?.(
|
|
156
|
+
data,
|
|
157
|
+
variables,
|
|
158
|
+
factoryOnMutateResult(onMutateResult, context),
|
|
159
|
+
context
|
|
160
|
+
)
|
|
161
|
+
// 4. Hook onSuccess
|
|
162
|
+
await restOptions.onSuccess?.(data, variables, onMutateResult, context)
|
|
163
|
+
},
|
|
164
|
+
onError: async (error, variables, onMutateResult, context) => {
|
|
165
|
+
if (isCanisterError(error)) {
|
|
166
|
+
factoryOnCanisterError?.(error, variables)
|
|
167
|
+
hookOnCanisterError?.(error, variables)
|
|
168
|
+
}
|
|
169
|
+
// Awaited in order, like `onSuccess`. TanStack Query holds
|
|
170
|
+
// `onSettled` and the settled state until this promise resolves, so
|
|
171
|
+
// an async `onError` must be part of it.
|
|
172
|
+
await factoryOnError?.(
|
|
173
|
+
error,
|
|
174
|
+
variables,
|
|
175
|
+
factoryOnMutateResult(onMutateResult, context),
|
|
176
|
+
context
|
|
177
|
+
)
|
|
178
|
+
await restOptions.onError?.(error, variables, onMutateResult, context)
|
|
179
|
+
},
|
|
180
|
+
// `onMutate` and `onSettled` are composed like `onSuccess`/`onError`
|
|
181
|
+
// above. They used to arrive through the `...restOptions` spread, so a
|
|
182
|
+
// hook-level one silently replaced the factory's — factory teardown,
|
|
183
|
+
// telemetry or logging simply vanished the moment any call site passed
|
|
184
|
+
// its own, with no warning and no type error. Chaining is what a
|
|
185
|
+
// reader who has seen `onSuccess` chain already expects.
|
|
186
|
+
onMutate: async (variables, context) => {
|
|
187
|
+
if (factoryOnMutate) {
|
|
188
|
+
const result = await factoryOnMutate(variables, context)
|
|
189
|
+
if (context) factoryOnMutateResults.set(context, result)
|
|
190
|
+
}
|
|
191
|
+
// Without a hook-level `onMutate` this is `undefined`, and
|
|
192
|
+
// THookOnMutateResult is then `unknown`.
|
|
193
|
+
return (await restOptions.onMutate?.(
|
|
194
|
+
variables,
|
|
195
|
+
context
|
|
196
|
+
)) as THookOnMutateResult
|
|
197
|
+
},
|
|
198
|
+
onSettled: async (data, error, variables, onMutateResult, context) => {
|
|
199
|
+
await factoryOnSettled?.(
|
|
200
|
+
data,
|
|
201
|
+
error,
|
|
202
|
+
variables,
|
|
203
|
+
factoryOnMutateResult(onMutateResult, context),
|
|
204
|
+
context
|
|
205
|
+
)
|
|
206
|
+
await restOptions.onSettled?.(
|
|
207
|
+
data,
|
|
208
|
+
error,
|
|
209
|
+
variables,
|
|
210
|
+
onMutateResult,
|
|
211
|
+
context
|
|
212
|
+
)
|
|
213
|
+
},
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
132
217
|
/**
|
|
133
218
|
* Imperative execution for non-React usage.
|
|
134
219
|
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
220
|
+
* Builds the mutation in the QueryClient's MutationCache and runs it, as
|
|
221
|
+
* TanStack Query's `useMutation` does, with the options the hook path uses
|
|
222
|
+
* minus the hook's own. It used to call the canister and the factory's
|
|
223
|
+
* callbacks itself, so the MutationCache never saw it: its global
|
|
224
|
+
* `onError`, `onSuccess` and `onSettled` did not run, `useIsMutating` did
|
|
225
|
+
* not count it, and neither the factory's `retry` or `networkMode` nor the
|
|
226
|
+
* same options in the QueryClient's mutation defaults applied to the call.
|
|
227
|
+
* The factory's `onMutate` and `onSettled` did not run either.
|
|
228
|
+
*
|
|
229
|
+
* Now the factory's chain runs as it does through `useMutation()`:
|
|
230
|
+
* `onMutate`, then the factory's invalidation and `onSuccess`, or
|
|
231
|
+
* `onCanisterError` and `onError` on failure, then `onSettled`. Each factory
|
|
232
|
+
* callback gets the result of the factory's `onMutate` for this call. Only
|
|
233
|
+
* hook-level callbacks are absent, because there is no hook here to supply
|
|
234
|
+
* them.
|
|
139
235
|
*
|
|
140
|
-
* The
|
|
141
|
-
*
|
|
236
|
+
* The QueryClient's mutation defaults apply as well, so a `mutations.retry`
|
|
237
|
+
* there re-sends a failed call here too. Each retry of an update method is
|
|
238
|
+
* a new call the canister runs; set `retry` on the factory (`false`, or
|
|
239
|
+
* `reactorUpdateRetry` to retry only a SysTransient rejection) to decide it
|
|
240
|
+
* per method.
|
|
142
241
|
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
242
|
+
* It resolves with the method's result. On failure it rejects with the
|
|
243
|
+
* call's error once the callbacks have run, so `await execute(...)` still
|
|
244
|
+
* rejects for the caller.
|
|
145
245
|
*
|
|
146
246
|
* Use this in route loaders, scripts, or server-side code.
|
|
147
247
|
*/
|
|
148
|
-
const execute = async (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
//
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
let result: ReactorReturnOk<Service, Method, Transform>
|
|
248
|
+
const execute = async (args: TVariables): Promise<TData> => {
|
|
249
|
+
const { queryClient } = reactor
|
|
250
|
+
const options = mutationOptions()
|
|
251
|
+
const { onError } = options
|
|
252
|
+
// What the factory's `onError` or `onCanisterError` throws, if either
|
|
253
|
+
// does. execute() has always rejected with it, and a TanStack Query
|
|
254
|
+
// mutation at the 5.90.2 peer floor does too. Later releases reject with
|
|
255
|
+
// the call's error and report the thrown one as an unhandled rejection,
|
|
256
|
+
// which ends a Node script, so it is caught here and rethrown below.
|
|
257
|
+
let thrownByOnError: { error: unknown } | undefined
|
|
258
|
+
const mutation = queryClient
|
|
259
|
+
.getMutationCache()
|
|
260
|
+
.build<TData, TError, TVariables, unknown>(queryClient, {
|
|
261
|
+
...options,
|
|
262
|
+
onError: async (error, variables, onMutateResult, context) => {
|
|
263
|
+
try {
|
|
264
|
+
await onError?.(error, variables, onMutateResult, context)
|
|
265
|
+
} catch (thrown) {
|
|
266
|
+
thrownByOnError = { error: thrown }
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
})
|
|
171
270
|
try {
|
|
172
|
-
|
|
271
|
+
return await mutation.execute(args)
|
|
173
272
|
} catch (error) {
|
|
174
|
-
|
|
175
|
-
// `catch` drops the type. `callMethod` rejects with this method's
|
|
176
|
-
// CanisterError, the one the hook path narrows to.
|
|
177
|
-
factoryOnCanisterError?.(
|
|
178
|
-
error as Parameters<NonNullable<typeof factoryOnCanisterError>>[0],
|
|
179
|
-
args
|
|
180
|
-
)
|
|
181
|
-
}
|
|
182
|
-
// `onMutate` does not run on this path, so there is no result to pass.
|
|
183
|
-
// Awaited like `onSuccess` below and like the hook path, so an async
|
|
184
|
-
// rollback or report finishes before `execute()` rejects.
|
|
185
|
-
await factoryOnError?.(
|
|
186
|
-
error as Parameters<NonNullable<typeof factoryOnError>>[0],
|
|
187
|
-
args,
|
|
188
|
-
undefined,
|
|
189
|
-
context
|
|
190
|
-
)
|
|
191
|
-
throw error
|
|
273
|
+
throw thrownByOnError ? thrownByOnError.error : error
|
|
192
274
|
}
|
|
193
|
-
|
|
194
|
-
if (factoryInvalidateQueries) {
|
|
195
|
-
await invalidateAll(reactor.queryClient, factoryInvalidateQueries)
|
|
196
|
-
}
|
|
197
|
-
await factoryOnSuccess?.(result, args, undefined, context)
|
|
198
|
-
return result
|
|
199
275
|
}
|
|
200
276
|
|
|
201
277
|
// Hook implementation
|
|
@@ -207,103 +283,8 @@ const createMutationImpl = <
|
|
|
207
283
|
THookOnMutateResult
|
|
208
284
|
>
|
|
209
285
|
) => {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
invalidateQueries: hookInvalidateQueries,
|
|
213
|
-
onCanisterError: hookOnCanisterError,
|
|
214
|
-
...restOptions
|
|
215
|
-
} = options ?? {}
|
|
216
|
-
|
|
217
|
-
return useMutation<
|
|
218
|
-
ReactorReturnOk<Service, Method, Transform>,
|
|
219
|
-
ReactorReturnErr<Service, Method, Transform>,
|
|
220
|
-
ReactorArgs<Service, Method, Transform>,
|
|
221
|
-
THookOnMutateResult
|
|
222
|
-
>(
|
|
223
|
-
{
|
|
224
|
-
mutationKey: baseOptions.queryKey,
|
|
225
|
-
...factoryOptions,
|
|
226
|
-
...restOptions,
|
|
227
|
-
// Use callFn (not execute) to avoid double-invalidation:
|
|
228
|
-
// factoryInvalidateQueries are handled in onSuccess below.
|
|
229
|
-
mutationFn: callFn,
|
|
230
|
-
onSuccess: async (data, variables, onMutateResult, context) => {
|
|
231
|
-
// 1. Factory-level invalidation
|
|
232
|
-
if (factoryInvalidateQueries) {
|
|
233
|
-
await invalidateAll(reactor.queryClient, factoryInvalidateQueries)
|
|
234
|
-
}
|
|
235
|
-
// 2. Hook-level invalidation
|
|
236
|
-
if (hookInvalidateQueries) {
|
|
237
|
-
await invalidateAll(reactor.queryClient, hookInvalidateQueries)
|
|
238
|
-
}
|
|
239
|
-
// 3. Factory onSuccess
|
|
240
|
-
await factoryOnSuccess?.(
|
|
241
|
-
data,
|
|
242
|
-
variables,
|
|
243
|
-
factoryOnMutateResult(onMutateResult, context),
|
|
244
|
-
context
|
|
245
|
-
)
|
|
246
|
-
// 4. Hook onSuccess
|
|
247
|
-
await restOptions.onSuccess?.(
|
|
248
|
-
data,
|
|
249
|
-
variables,
|
|
250
|
-
onMutateResult,
|
|
251
|
-
context
|
|
252
|
-
)
|
|
253
|
-
},
|
|
254
|
-
onError: async (error, variables, onMutateResult, context) => {
|
|
255
|
-
if (isCanisterError(error)) {
|
|
256
|
-
factoryOnCanisterError?.(error, variables)
|
|
257
|
-
hookOnCanisterError?.(error, variables)
|
|
258
|
-
}
|
|
259
|
-
// Awaited in order, like `onSuccess`. TanStack Query holds
|
|
260
|
-
// `onSettled` and the settled state until this promise resolves, so
|
|
261
|
-
// an async `onError` must be part of it.
|
|
262
|
-
await factoryOnError?.(
|
|
263
|
-
error,
|
|
264
|
-
variables,
|
|
265
|
-
factoryOnMutateResult(onMutateResult, context),
|
|
266
|
-
context
|
|
267
|
-
)
|
|
268
|
-
await restOptions.onError?.(error, variables, onMutateResult, context)
|
|
269
|
-
},
|
|
270
|
-
// `onMutate` and `onSettled` are composed like `onSuccess`/`onError`
|
|
271
|
-
// above. They used to arrive through the `...restOptions` spread, so a
|
|
272
|
-
// hook-level one silently replaced the factory's — factory teardown,
|
|
273
|
-
// telemetry or logging simply vanished the moment any call site passed
|
|
274
|
-
// its own, with no warning and no type error. Chaining is what a
|
|
275
|
-
// reader who has seen `onSuccess` chain already expects.
|
|
276
|
-
onMutate: async (variables, context) => {
|
|
277
|
-
if (factoryOnMutate) {
|
|
278
|
-
const result = await factoryOnMutate(variables, context)
|
|
279
|
-
if (context) factoryOnMutateResults.set(context, result)
|
|
280
|
-
}
|
|
281
|
-
// Without a hook-level `onMutate` this is `undefined`, and
|
|
282
|
-
// THookOnMutateResult is then `unknown`.
|
|
283
|
-
return (await restOptions.onMutate?.(
|
|
284
|
-
variables,
|
|
285
|
-
context
|
|
286
|
-
)) as THookOnMutateResult
|
|
287
|
-
},
|
|
288
|
-
onSettled: async (data, error, variables, onMutateResult, context) => {
|
|
289
|
-
await factoryOnSettled?.(
|
|
290
|
-
data,
|
|
291
|
-
error,
|
|
292
|
-
variables,
|
|
293
|
-
factoryOnMutateResult(onMutateResult, context),
|
|
294
|
-
context
|
|
295
|
-
)
|
|
296
|
-
await restOptions.onSettled?.(
|
|
297
|
-
data,
|
|
298
|
-
error,
|
|
299
|
-
variables,
|
|
300
|
-
onMutateResult,
|
|
301
|
-
context
|
|
302
|
-
)
|
|
303
|
-
},
|
|
304
|
-
},
|
|
305
|
-
reactor.queryClient
|
|
306
|
-
)
|
|
286
|
+
useMountQueryClient(reactor.queryClient)
|
|
287
|
+
return useMutation(mutationOptions(options), reactor.queryClient)
|
|
307
288
|
}
|
|
308
289
|
|
|
309
290
|
return { useMutation: useMutationHook, execute }
|
|
@@ -320,8 +301,10 @@ export function createMutation<
|
|
|
320
301
|
TOnMutateResult = unknown,
|
|
321
302
|
>(
|
|
322
303
|
reactor: Reactor<Service, Transform>,
|
|
323
|
-
// `
|
|
324
|
-
//
|
|
304
|
+
// A factory `onError` or `onSettled` gets no `onMutate` result when
|
|
305
|
+
// `onMutate` throws, so the result can also be `undefined`. `onSuccess`
|
|
306
|
+
// shares the type argument. It kept the `undefined` from when `execute()`
|
|
307
|
+
// ran no `onMutate`, although it now always gets a result.
|
|
325
308
|
config: MutationConfig<
|
|
326
309
|
NoInfer<Service>,
|
|
327
310
|
Method,
|