@ic-reactor/react 3.0.0-beta.7 → 3.0.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 +11 -10
- package/dist/createActorHooks.d.ts +2 -0
- package/dist/createActorHooks.d.ts.map +1 -1
- package/dist/createActorHooks.js +2 -0
- package/dist/createActorHooks.js.map +1 -1
- package/dist/createMutation.d.ts.map +1 -1
- package/dist/createMutation.js +4 -0
- package/dist/createMutation.js.map +1 -1
- package/dist/hooks/index.d.ts +18 -5
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +15 -5
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useActorInfiniteQuery.d.ts +13 -11
- package/dist/hooks/useActorInfiniteQuery.d.ts.map +1 -1
- package/dist/hooks/useActorInfiniteQuery.js.map +1 -1
- package/dist/hooks/useActorMethod.d.ts +105 -0
- package/dist/hooks/useActorMethod.d.ts.map +1 -0
- package/dist/hooks/useActorMethod.js +192 -0
- package/dist/hooks/useActorMethod.js.map +1 -0
- package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts +13 -10
- package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts.map +1 -1
- package/dist/hooks/useActorSuspenseInfiniteQuery.js.map +1 -1
- package/package.json +9 -8
- package/src/createActorHooks.ts +146 -0
- package/src/createAuthHooks.ts +137 -0
- package/src/createInfiniteQuery.ts +471 -0
- package/src/createMutation.ts +163 -0
- package/src/createQuery.ts +197 -0
- package/src/createSuspenseInfiniteQuery.ts +478 -0
- package/src/createSuspenseQuery.ts +215 -0
- package/src/hooks/index.ts +93 -0
- package/src/hooks/useActorInfiniteQuery.test.tsx +457 -0
- package/src/hooks/useActorInfiniteQuery.ts +134 -0
- package/src/hooks/useActorMethod.test.tsx +798 -0
- package/src/hooks/useActorMethod.ts +397 -0
- package/src/hooks/useActorMutation.test.tsx +220 -0
- package/src/hooks/useActorMutation.ts +124 -0
- package/src/hooks/useActorQuery.test.tsx +287 -0
- package/src/hooks/useActorQuery.ts +110 -0
- package/src/hooks/useActorSuspenseInfiniteQuery.test.tsx +472 -0
- package/src/hooks/useActorSuspenseInfiniteQuery.ts +137 -0
- package/src/hooks/useActorSuspenseQuery.test.tsx +254 -0
- package/src/hooks/useActorSuspenseQuery.ts +112 -0
- package/src/index.ts +21 -0
- package/src/types.ts +435 -0
- package/src/validation.ts +202 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Suspense Query Factory - Generic wrapper for React Suspense-based canister data
|
|
3
|
+
*
|
|
4
|
+
* Creates unified fetch/hook/invalidate functions for any canister method.
|
|
5
|
+
* Works with any Reactor instance.
|
|
6
|
+
*
|
|
7
|
+
* Uses `useSuspenseQuery` which:
|
|
8
|
+
* - Requires wrapping in <Suspense> boundary
|
|
9
|
+
* - Data is always defined (no undefined checks)
|
|
10
|
+
* - Does NOT support `enabled` option
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const userQuery = createSuspenseQuery(todoManager, {
|
|
14
|
+
* functionName: "get_user",
|
|
15
|
+
* select: (result) => result.user,
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* // In component (wrap in Suspense)
|
|
19
|
+
* const { data: user } = userQuery.useSuspenseQuery() // data is never undefined!
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type {
|
|
23
|
+
Reactor,
|
|
24
|
+
FunctionName,
|
|
25
|
+
ReactorArgs,
|
|
26
|
+
TransformKey,
|
|
27
|
+
} from "@ic-reactor/core"
|
|
28
|
+
import { useSuspenseQuery } from "@tanstack/react-query"
|
|
29
|
+
import type {
|
|
30
|
+
QueryFnData,
|
|
31
|
+
QueryError,
|
|
32
|
+
SuspenseQueryConfig,
|
|
33
|
+
UseSuspenseQueryWithSelect,
|
|
34
|
+
SuspenseQueryResult,
|
|
35
|
+
SuspenseQueryFactoryConfig,
|
|
36
|
+
NoInfer,
|
|
37
|
+
} from "./types"
|
|
38
|
+
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// Internal Implementation
|
|
41
|
+
// ============================================================================
|
|
42
|
+
|
|
43
|
+
const createSuspenseQueryImpl = <
|
|
44
|
+
A,
|
|
45
|
+
M extends FunctionName<A> = FunctionName<A>,
|
|
46
|
+
T extends TransformKey = "candid",
|
|
47
|
+
TSelected = QueryFnData<A, M, T>,
|
|
48
|
+
>(
|
|
49
|
+
reactor: Reactor<A, T>,
|
|
50
|
+
config: SuspenseQueryConfig<A, M, T, TSelected>
|
|
51
|
+
): SuspenseQueryResult<
|
|
52
|
+
QueryFnData<A, M, T>,
|
|
53
|
+
TSelected,
|
|
54
|
+
QueryError<A, M, T>
|
|
55
|
+
> => {
|
|
56
|
+
type TData = QueryFnData<A, M, T>
|
|
57
|
+
type TError = QueryError<A, M, T>
|
|
58
|
+
|
|
59
|
+
const {
|
|
60
|
+
functionName,
|
|
61
|
+
args,
|
|
62
|
+
staleTime = 5 * 60 * 1000,
|
|
63
|
+
select,
|
|
64
|
+
queryKey: customQueryKey,
|
|
65
|
+
...rest
|
|
66
|
+
} = config
|
|
67
|
+
|
|
68
|
+
const params = {
|
|
69
|
+
functionName,
|
|
70
|
+
args,
|
|
71
|
+
queryKey: customQueryKey,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Get query key from actor manager
|
|
75
|
+
const getQueryKey = () => {
|
|
76
|
+
return reactor.generateQueryKey(params)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Fetch function for loaders (cache-first)
|
|
80
|
+
const fetch = async (): Promise<TSelected> => {
|
|
81
|
+
const result = await reactor.fetchQuery(params)
|
|
82
|
+
return select ? select(result) : (result as TSelected)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Implementation
|
|
86
|
+
const useSuspenseQueryHook: UseSuspenseQueryWithSelect<
|
|
87
|
+
TData,
|
|
88
|
+
TSelected,
|
|
89
|
+
TError
|
|
90
|
+
> = (options: any): any => {
|
|
91
|
+
const baseOptions = reactor.getQueryOptions(params)
|
|
92
|
+
|
|
93
|
+
// Chain the selects: raw -> config.select -> options.select
|
|
94
|
+
const chainedSelect = (rawData: TData) => {
|
|
95
|
+
const firstPass = config.select ? config.select(rawData) : rawData
|
|
96
|
+
if (options?.select) {
|
|
97
|
+
return options.select(firstPass)
|
|
98
|
+
}
|
|
99
|
+
return firstPass
|
|
100
|
+
}
|
|
101
|
+
return useSuspenseQuery(
|
|
102
|
+
{
|
|
103
|
+
queryKey: baseOptions.queryKey,
|
|
104
|
+
staleTime,
|
|
105
|
+
...rest,
|
|
106
|
+
...options,
|
|
107
|
+
queryFn: baseOptions.queryFn,
|
|
108
|
+
select: chainedSelect,
|
|
109
|
+
},
|
|
110
|
+
reactor.queryClient
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Invalidate function
|
|
115
|
+
const invalidate = async (): Promise<void> => {
|
|
116
|
+
const queryKey = getQueryKey()
|
|
117
|
+
await reactor.queryClient.invalidateQueries({ queryKey })
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Get data from cache without fetching
|
|
121
|
+
const getCacheData: any = (selectFn?: (data: TData) => any) => {
|
|
122
|
+
const cachedRawData = reactor.getQueryData(params)
|
|
123
|
+
|
|
124
|
+
if (cachedRawData === undefined) {
|
|
125
|
+
return undefined
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Apply config.select to raw cache data
|
|
129
|
+
const selectedData = (
|
|
130
|
+
config.select ? config.select(cachedRawData) : cachedRawData
|
|
131
|
+
) as TData
|
|
132
|
+
|
|
133
|
+
// Apply optional select parameter
|
|
134
|
+
if (selectFn) {
|
|
135
|
+
return selectFn(selectedData)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return selectedData
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
fetch,
|
|
143
|
+
useSuspenseQuery: useSuspenseQueryHook,
|
|
144
|
+
invalidate,
|
|
145
|
+
getQueryKey,
|
|
146
|
+
getCacheData,
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ============================================================================
|
|
151
|
+
// Factory Function
|
|
152
|
+
// ============================================================================
|
|
153
|
+
|
|
154
|
+
export function createSuspenseQuery<
|
|
155
|
+
A,
|
|
156
|
+
T extends TransformKey,
|
|
157
|
+
M extends FunctionName<A> = FunctionName<A>,
|
|
158
|
+
TSelected = QueryFnData<A, M, T>,
|
|
159
|
+
>(
|
|
160
|
+
reactor: Reactor<A, T>,
|
|
161
|
+
config: SuspenseQueryConfig<NoInfer<A>, M, T, TSelected>
|
|
162
|
+
): SuspenseQueryResult<QueryFnData<A, M, T>, TSelected, QueryError<A, M, T>> {
|
|
163
|
+
return createSuspenseQueryImpl(
|
|
164
|
+
reactor,
|
|
165
|
+
config as SuspenseQueryConfig<A, M, T, TSelected>
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ============================================================================
|
|
170
|
+
// Convenience: Create suspense query with dynamic args
|
|
171
|
+
// ============================================================================
|
|
172
|
+
|
|
173
|
+
export function createSuspenseQueryFactory<
|
|
174
|
+
A,
|
|
175
|
+
T extends TransformKey,
|
|
176
|
+
M extends FunctionName<A> = FunctionName<A>,
|
|
177
|
+
TSelected = QueryFnData<A, M, T>,
|
|
178
|
+
>(
|
|
179
|
+
reactor: Reactor<A, T>,
|
|
180
|
+
config: SuspenseQueryFactoryConfig<NoInfer<A>, M, T, TSelected>
|
|
181
|
+
): (
|
|
182
|
+
args: ReactorArgs<A, M, T>
|
|
183
|
+
) => SuspenseQueryResult<QueryFnData<A, M, T>, TSelected, QueryError<A, M, T>> {
|
|
184
|
+
const cache = new Map<
|
|
185
|
+
string,
|
|
186
|
+
SuspenseQueryResult<QueryFnData<A, M, T>, TSelected, QueryError<A, M, T>>
|
|
187
|
+
>()
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
args: ReactorArgs<A, M, T>
|
|
191
|
+
): SuspenseQueryResult<
|
|
192
|
+
QueryFnData<A, M, T>,
|
|
193
|
+
TSelected,
|
|
194
|
+
QueryError<A, M, T>
|
|
195
|
+
> => {
|
|
196
|
+
const key = reactor.generateQueryKey({
|
|
197
|
+
functionName: config.functionName as M,
|
|
198
|
+
args,
|
|
199
|
+
})
|
|
200
|
+
const cacheKey = JSON.stringify(key)
|
|
201
|
+
|
|
202
|
+
if (cache.has(cacheKey)) {
|
|
203
|
+
return cache.get(cacheKey)!
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const result = createSuspenseQueryImpl<A, M, T, TSelected>(reactor, {
|
|
207
|
+
...(config as SuspenseQueryFactoryConfig<A, M, T, TSelected>),
|
|
208
|
+
args,
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
cache.set(cacheKey, result)
|
|
212
|
+
|
|
213
|
+
return result
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Hooks
|
|
3
|
+
// ============================================================================
|
|
4
|
+
|
|
5
|
+
// useActorQuery / useReactorQuery
|
|
6
|
+
export { useActorQuery as useReactorQuery } from "./useActorQuery.js"
|
|
7
|
+
|
|
8
|
+
// useActorMutation / useReactorMutation
|
|
9
|
+
export { useActorMutation as useReactorMutation } from "./useActorMutation.js"
|
|
10
|
+
|
|
11
|
+
// useActorSuspenseQuery / useReactorSuspenseQuery
|
|
12
|
+
export { useActorSuspenseQuery as useReactorSuspenseQuery } from "./useActorSuspenseQuery.js"
|
|
13
|
+
|
|
14
|
+
// useActorInfiniteQuery / useReactorInfiniteQuery
|
|
15
|
+
export { useActorInfiniteQuery as useReactorInfiniteQuery } from "./useActorInfiniteQuery.js"
|
|
16
|
+
|
|
17
|
+
// useActorSuspenseInfiniteQuery / useReactorSuspenseInfiniteQuery
|
|
18
|
+
export { useActorSuspenseInfiniteQuery as useReactorSuspenseInfiniteQuery } from "./useActorSuspenseInfiniteQuery.js"
|
|
19
|
+
|
|
20
|
+
// useActorMethod / useReactorMethod
|
|
21
|
+
export {
|
|
22
|
+
useActorMethod,
|
|
23
|
+
useActorMethod as useReactorMethod,
|
|
24
|
+
createActorMethodHooks,
|
|
25
|
+
} from "./useActorMethod.js"
|
|
26
|
+
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Types - UseReactor* (with reactor parameter)
|
|
29
|
+
// ============================================================================
|
|
30
|
+
|
|
31
|
+
export type {
|
|
32
|
+
UseActorQueryParameters as UseReactorQueryParameters,
|
|
33
|
+
UseActorQueryResult as UseReactorQueryResult,
|
|
34
|
+
} from "./useActorQuery.js"
|
|
35
|
+
|
|
36
|
+
export type {
|
|
37
|
+
UseActorMutationParameters as UseReactorMutationParameters,
|
|
38
|
+
UseActorMutationResult as UseReactorMutationResult,
|
|
39
|
+
} from "./useActorMutation.js"
|
|
40
|
+
|
|
41
|
+
export type {
|
|
42
|
+
UseActorSuspenseQueryParameters as UseReactorSuspenseQueryParameters,
|
|
43
|
+
UseActorSuspenseQueryResult as UseReactorSuspenseQueryResult,
|
|
44
|
+
} from "./useActorSuspenseQuery.js"
|
|
45
|
+
|
|
46
|
+
export type {
|
|
47
|
+
UseActorInfiniteQueryParameters as UseReactorInfiniteQueryParameters,
|
|
48
|
+
UseActorInfiniteQueryResult as UseReactorInfiniteQueryResult,
|
|
49
|
+
} from "./useActorInfiniteQuery.js"
|
|
50
|
+
|
|
51
|
+
export type {
|
|
52
|
+
UseActorSuspenseInfiniteQueryParameters as UseReactorSuspenseInfiniteQueryParameters,
|
|
53
|
+
UseActorSuspenseInfiniteQueryResult as UseReactorSuspenseInfiniteQueryResult,
|
|
54
|
+
} from "./useActorSuspenseInfiniteQuery.js"
|
|
55
|
+
|
|
56
|
+
export type {
|
|
57
|
+
UseActorMethodParameters as UseReactorMethodParameters,
|
|
58
|
+
UseActorMethodResult as UseReactorMethodResult,
|
|
59
|
+
} from "./useActorMethod.js"
|
|
60
|
+
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// Types - UseActor* (without reactor parameter, for use with createActorHooks)
|
|
63
|
+
// ============================================================================
|
|
64
|
+
|
|
65
|
+
export type {
|
|
66
|
+
UseActorQueryConfig as UseActorQueryParameters,
|
|
67
|
+
UseActorQueryResult,
|
|
68
|
+
} from "./useActorQuery.js"
|
|
69
|
+
|
|
70
|
+
export type {
|
|
71
|
+
UseActorMutationConfig as UseActorMutationParameters,
|
|
72
|
+
UseActorMutationResult,
|
|
73
|
+
} from "./useActorMutation.js"
|
|
74
|
+
|
|
75
|
+
export type {
|
|
76
|
+
UseActorSuspenseQueryConfig as UseActorSuspenseQueryParameters,
|
|
77
|
+
UseActorSuspenseQueryResult,
|
|
78
|
+
} from "./useActorSuspenseQuery.js"
|
|
79
|
+
|
|
80
|
+
export type {
|
|
81
|
+
UseActorInfiniteQueryConfig as UseActorInfiniteQueryParameters,
|
|
82
|
+
UseActorInfiniteQueryResult,
|
|
83
|
+
} from "./useActorInfiniteQuery.js"
|
|
84
|
+
|
|
85
|
+
export type {
|
|
86
|
+
UseActorSuspenseInfiniteQueryConfig as UseActorSuspenseInfiniteQueryParameters,
|
|
87
|
+
UseActorSuspenseInfiniteQueryResult,
|
|
88
|
+
} from "./useActorSuspenseInfiniteQuery.js"
|
|
89
|
+
|
|
90
|
+
export type {
|
|
91
|
+
UseActorMethodConfig as UseActorMethodParameters,
|
|
92
|
+
UseActorMethodResult,
|
|
93
|
+
} from "./useActorMethod.js"
|