@ic-reactor/react 3.0.0-beta.8 → 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.
Files changed (46) hide show
  1. package/README.md +11 -10
  2. package/dist/createActorHooks.d.ts +2 -0
  3. package/dist/createActorHooks.d.ts.map +1 -1
  4. package/dist/createActorHooks.js +2 -0
  5. package/dist/createActorHooks.js.map +1 -1
  6. package/dist/createMutation.d.ts.map +1 -1
  7. package/dist/createMutation.js +4 -0
  8. package/dist/createMutation.js.map +1 -1
  9. package/dist/hooks/index.d.ts +18 -5
  10. package/dist/hooks/index.d.ts.map +1 -1
  11. package/dist/hooks/index.js +15 -5
  12. package/dist/hooks/index.js.map +1 -1
  13. package/dist/hooks/useActorInfiniteQuery.d.ts +13 -11
  14. package/dist/hooks/useActorInfiniteQuery.d.ts.map +1 -1
  15. package/dist/hooks/useActorInfiniteQuery.js.map +1 -1
  16. package/dist/hooks/useActorMethod.d.ts +105 -0
  17. package/dist/hooks/useActorMethod.d.ts.map +1 -0
  18. package/dist/hooks/useActorMethod.js +192 -0
  19. package/dist/hooks/useActorMethod.js.map +1 -0
  20. package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts +13 -10
  21. package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts.map +1 -1
  22. package/dist/hooks/useActorSuspenseInfiniteQuery.js.map +1 -1
  23. package/package.json +7 -6
  24. package/src/createActorHooks.ts +146 -0
  25. package/src/createAuthHooks.ts +137 -0
  26. package/src/createInfiniteQuery.ts +471 -0
  27. package/src/createMutation.ts +163 -0
  28. package/src/createQuery.ts +197 -0
  29. package/src/createSuspenseInfiniteQuery.ts +478 -0
  30. package/src/createSuspenseQuery.ts +215 -0
  31. package/src/hooks/index.ts +93 -0
  32. package/src/hooks/useActorInfiniteQuery.test.tsx +457 -0
  33. package/src/hooks/useActorInfiniteQuery.ts +134 -0
  34. package/src/hooks/useActorMethod.test.tsx +798 -0
  35. package/src/hooks/useActorMethod.ts +397 -0
  36. package/src/hooks/useActorMutation.test.tsx +220 -0
  37. package/src/hooks/useActorMutation.ts +124 -0
  38. package/src/hooks/useActorQuery.test.tsx +287 -0
  39. package/src/hooks/useActorQuery.ts +110 -0
  40. package/src/hooks/useActorSuspenseInfiniteQuery.test.tsx +472 -0
  41. package/src/hooks/useActorSuspenseInfiniteQuery.ts +137 -0
  42. package/src/hooks/useActorSuspenseQuery.test.tsx +254 -0
  43. package/src/hooks/useActorSuspenseQuery.ts +112 -0
  44. package/src/index.ts +21 -0
  45. package/src/types.ts +435 -0
  46. 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"