@ic-reactor/react 3.9.0 → 3.10.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 +16 -7
- package/dist/auth/authentication-manager.d.ts.map +1 -1
- package/dist/auth/authentication-manager.js +9 -0
- package/dist/auth/authentication-manager.js.map +1 -1
- package/dist/auth/createIdentityAttributeHooks.d.ts.map +1 -1
- package/dist/auth/createIdentityAttributeHooks.js +47 -5
- package/dist/auth/createIdentityAttributeHooks.js.map +1 -1
- package/dist/createMutation.d.ts.map +1 -1
- package/dist/createMutation.js +15 -1
- package/dist/createMutation.js.map +1 -1
- package/dist/createQuery.js +2 -2
- package/dist/createQuery.js.map +1 -1
- package/dist/createSuspenseQuery.js +2 -2
- package/dist/createSuspenseQuery.js.map +1 -1
- package/dist/defineReactor.d.ts.map +1 -1
- package/dist/defineReactor.js +17 -2
- package/dist/defineReactor.js.map +1 -1
- package/dist/hooks/createAuthHooks.d.ts.map +1 -1
- package/dist/hooks/createAuthHooks.js +13 -0
- package/dist/hooks/createAuthHooks.js.map +1 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useActorInfiniteQuery.d.ts.map +1 -1
- package/dist/hooks/useActorInfiniteQuery.js +5 -0
- package/dist/hooks/useActorInfiniteQuery.js.map +1 -1
- package/dist/hooks/useActorMethod.d.ts.map +1 -1
- package/dist/hooks/useActorMethod.js +11 -1
- package/dist/hooks/useActorMethod.js.map +1 -1
- package/dist/hooks/useActorMutation.d.ts.map +1 -1
- package/dist/hooks/useActorMutation.js +14 -6
- package/dist/hooks/useActorMutation.js.map +1 -1
- package/dist/hooks/useActorQuery.d.ts.map +1 -1
- package/dist/hooks/useActorQuery.js +12 -1
- package/dist/hooks/useActorQuery.js.map +1 -1
- package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts.map +1 -1
- package/dist/hooks/useActorSuspenseInfiniteQuery.js +5 -0
- package/dist/hooks/useActorSuspenseInfiniteQuery.js.map +1 -1
- package/dist/hooks/useActorSuspenseQuery.d.ts.map +1 -1
- package/dist/hooks/useActorSuspenseQuery.js +12 -1
- package/dist/hooks/useActorSuspenseQuery.js.map +1 -1
- package/dist/utils.d.ts +13 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +45 -0
- package/dist/utils.js.map +1 -1
- package/package.json +8 -2
- package/src/auth/authentication-manager.ts +10 -0
- package/src/auth/createIdentityAttributeHooks.ts +54 -5
- package/src/createMutation.ts +16 -0
- package/src/createQuery.ts +9 -9
- package/src/createSuspenseQuery.ts +9 -9
- package/src/defineReactor.ts +24 -2
- package/src/hooks/createAuthHooks.ts +18 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/useActorInfiniteQuery.ts +5 -0
- package/src/hooks/useActorMethod.ts +10 -1
- package/src/hooks/useActorMutation.ts +16 -8
- package/src/hooks/useActorQuery.ts +11 -1
- package/src/hooks/useActorSuspenseInfiniteQuery.ts +5 -0
- package/src/hooks/useActorSuspenseQuery.ts +11 -1
- package/src/utils.ts +45 -0
package/src/hooks/index.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
// ============================================================================
|
|
2
2
|
// Hooks
|
|
3
|
+
//
|
|
4
|
+
// These are the RAW hooks: they take the reactor as a property. They are
|
|
5
|
+
// therefore exported as `useReactor*` only — the `useActor*` names belong to
|
|
6
|
+
// the bound hooks `createActorHooks` returns, which take no reactor. Aliasing
|
|
7
|
+
// the raw implementations under the bound names would hand a caller following
|
|
8
|
+
// the documented `useActorQuery({ functionName })` shape an undefined reactor.
|
|
3
9
|
// ============================================================================
|
|
4
10
|
|
|
5
11
|
// useActorQuery / useReactorQuery
|
|
@@ -138,6 +138,11 @@ export const useActorInfiniteQuery = <
|
|
|
138
138
|
[
|
|
139
139
|
queryKey,
|
|
140
140
|
reactor,
|
|
141
|
+
// `canisterId` is mutable reactor state that `setCanisterId` can change,
|
|
142
|
+
// while `reactor` itself stays the same object — so it has to be a
|
|
143
|
+
// dependency in its own right or the key stays pinned to the old canister
|
|
144
|
+
// while the queryFn already calls the new one.
|
|
145
|
+
reactor.canisterId?.toString(),
|
|
141
146
|
functionName,
|
|
142
147
|
callConfig,
|
|
143
148
|
getArgs,
|
|
@@ -208,7 +208,16 @@ export function useActorMethod<
|
|
|
208
208
|
{ functionName, args: keyArgs, queryKey: customQueryKey },
|
|
209
209
|
callConfig
|
|
210
210
|
),
|
|
211
|
-
|
|
211
|
+
// `canisterId` is mutable reactor state that `setCanisterId` can change,
|
|
212
|
+
// while `reactor` itself stays the same object — so it has to be a
|
|
213
|
+
// dependency in its own right or the key stays pinned to the old canister.
|
|
214
|
+
[
|
|
215
|
+
reactor,
|
|
216
|
+
reactor.canisterId?.toString(),
|
|
217
|
+
functionName,
|
|
218
|
+
callConfig,
|
|
219
|
+
customQueryKey,
|
|
220
|
+
]
|
|
212
221
|
)
|
|
213
222
|
|
|
214
223
|
const queryKey = useMemo(() => buildQueryKey(args), [buildQueryKey, args])
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCallback } from "react"
|
|
2
2
|
import {
|
|
3
3
|
useMutation,
|
|
4
4
|
UseMutationOptions,
|
|
@@ -167,16 +167,24 @@ export const useActorMutation = <
|
|
|
167
167
|
[onCanisterError, onError]
|
|
168
168
|
)
|
|
169
169
|
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
// Not memoized. The deps could only ever list the values destructured above,
|
|
171
|
+
// never the `options` rest bucket, so everything passed straight through —
|
|
172
|
+
// `onMutate`, `onSettled`, `retry`, `meta`, `gcTime` — was frozen at the first
|
|
173
|
+
// render: `useMutation` calls `observer.setOptions` from an effect keyed on
|
|
174
|
+
// the options identity, so a later render's closures never reached it. A
|
|
175
|
+
// component passing only `onSettled` would report the recipient selected at
|
|
176
|
+
// mount rather than at submit.
|
|
177
|
+
//
|
|
178
|
+
// `createMutation`'s own hook builds its options inline for the same reason.
|
|
179
|
+
// A fresh object per render costs nothing here: `setOptions` diffs the values
|
|
180
|
+
// rather than the reference.
|
|
181
|
+
return useMutation(
|
|
182
|
+
{
|
|
172
183
|
...options,
|
|
173
184
|
mutationFn,
|
|
174
185
|
onSuccess: handleSuccess,
|
|
175
186
|
onError: handleError,
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
[mutationFn, handleSuccess, handleError]
|
|
187
|
+
},
|
|
188
|
+
reactor.queryClient
|
|
179
189
|
)
|
|
180
|
-
|
|
181
|
-
return useMutation(mutationOptions, reactor.queryClient)
|
|
182
190
|
}
|
|
@@ -100,7 +100,17 @@ export const useActorQuery = <
|
|
|
100
100
|
args,
|
|
101
101
|
queryKey: defaultQueryKey,
|
|
102
102
|
}),
|
|
103
|
-
|
|
103
|
+
// `canisterId` is mutable reactor state that `setCanisterId` can change,
|
|
104
|
+
// while `reactor` itself stays the same object — so it has to be a
|
|
105
|
+
// dependency in its own right or the key stays pinned to the old canister.
|
|
106
|
+
[
|
|
107
|
+
reactor,
|
|
108
|
+
reactor.canisterId?.toString(),
|
|
109
|
+
callConfig,
|
|
110
|
+
functionName,
|
|
111
|
+
args,
|
|
112
|
+
defaultQueryKey,
|
|
113
|
+
]
|
|
104
114
|
)
|
|
105
115
|
|
|
106
116
|
return useQuery(
|
|
@@ -148,6 +148,11 @@ export const useActorSuspenseInfiniteQuery = <
|
|
|
148
148
|
[
|
|
149
149
|
queryKey,
|
|
150
150
|
reactor,
|
|
151
|
+
// `canisterId` is mutable reactor state that `setCanisterId` can change,
|
|
152
|
+
// while `reactor` itself stays the same object — so it has to be a
|
|
153
|
+
// dependency in its own right or the key stays pinned to the old canister
|
|
154
|
+
// while the queryFn already calls the new one.
|
|
155
|
+
reactor.canisterId?.toString(),
|
|
151
156
|
functionName,
|
|
152
157
|
callConfig,
|
|
153
158
|
getArgs,
|
|
@@ -104,7 +104,17 @@ export const useActorSuspenseQuery = <
|
|
|
104
104
|
args,
|
|
105
105
|
queryKey: defaultQueryKey,
|
|
106
106
|
}),
|
|
107
|
-
|
|
107
|
+
// `canisterId` is mutable reactor state that `setCanisterId` can change,
|
|
108
|
+
// while `reactor` itself stays the same object — so it has to be a
|
|
109
|
+
// dependency in its own right or the key stays pinned to the old canister.
|
|
110
|
+
[
|
|
111
|
+
reactor,
|
|
112
|
+
reactor.canisterId?.toString(),
|
|
113
|
+
callConfig,
|
|
114
|
+
functionName,
|
|
115
|
+
args,
|
|
116
|
+
defaultQueryKey,
|
|
117
|
+
]
|
|
108
118
|
)
|
|
109
119
|
|
|
110
120
|
return useSuspenseQuery(
|
package/src/utils.ts
CHANGED
|
@@ -74,3 +74,48 @@ export function buildChainedSelect<TData, TSelected, TFinal = TSelected>(
|
|
|
74
74
|
if (!hookSelect) return configSelect
|
|
75
75
|
return (rawData: TData) => hookSelect(configSelect(rawData))
|
|
76
76
|
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* How many memoized query objects an args-late factory keeps.
|
|
80
|
+
*
|
|
81
|
+
* The memo exists so `getBalance(sameArgs)` returns the same object twice; it
|
|
82
|
+
* was unbounded, so an open-ended argument space — a per-principal balance in a
|
|
83
|
+
* long-lived SPA, a search-as-you-type filter, a cursor-keyed list — grew it
|
|
84
|
+
* forever (measured at ~2.9 kB per entry, 55.8 MB for 20k). A few hundred
|
|
85
|
+
* covers any realistic working set while capping the worst case.
|
|
86
|
+
*/
|
|
87
|
+
const FACTORY_CACHE_LIMIT = 256
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Smallest useful LRU: a `Map` already iterates in insertion order, so
|
|
91
|
+
* re-inserting on read is enough to track recency.
|
|
92
|
+
*
|
|
93
|
+
* Eviction is safe — it costs memoization, never correctness. A query object is
|
|
94
|
+
* a closure over the reactor and config, so one rebuilt after eviction behaves
|
|
95
|
+
* identically; only its reference identity differs.
|
|
96
|
+
*/
|
|
97
|
+
export function createBoundedCache<V>(limit: number = FACTORY_CACHE_LIMIT) {
|
|
98
|
+
const entries = new Map<string, V>()
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
get(key: string): V | undefined {
|
|
102
|
+
const value = entries.get(key)
|
|
103
|
+
if (value === undefined) return undefined
|
|
104
|
+
// Touch: move to the most-recent end.
|
|
105
|
+
entries.delete(key)
|
|
106
|
+
entries.set(key, value)
|
|
107
|
+
return value
|
|
108
|
+
},
|
|
109
|
+
set(key: string, value: V): void {
|
|
110
|
+
if (entries.has(key)) entries.delete(key)
|
|
111
|
+
else if (entries.size >= limit) {
|
|
112
|
+
const oldest = entries.keys().next().value
|
|
113
|
+
if (oldest !== undefined) entries.delete(oldest)
|
|
114
|
+
}
|
|
115
|
+
entries.set(key, value)
|
|
116
|
+
},
|
|
117
|
+
get size(): number {
|
|
118
|
+
return entries.size
|
|
119
|
+
},
|
|
120
|
+
}
|
|
121
|
+
}
|