@ic-reactor/react 3.6.0 → 3.7.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 +28 -8
- package/dist/auth/authentication-manager.d.ts +66 -0
- package/dist/auth/authentication-manager.d.ts.map +1 -0
- package/dist/auth/authentication-manager.js +458 -0
- package/dist/auth/authentication-manager.js.map +1 -0
- package/dist/auth/constants.d.ts +18 -0
- package/dist/auth/constants.d.ts.map +1 -0
- package/dist/auth/constants.js +18 -0
- package/dist/auth/constants.js.map +1 -0
- package/dist/auth/createIdentityAttributeHooks.d.ts +14 -0
- package/dist/auth/createIdentityAttributeHooks.d.ts.map +1 -0
- package/dist/auth/createIdentityAttributeHooks.js +54 -0
- package/dist/auth/createIdentityAttributeHooks.js.map +1 -0
- package/dist/auth/identity-attributes-manager.d.ts +19 -0
- package/dist/auth/identity-attributes-manager.d.ts.map +1 -0
- package/dist/auth/identity-attributes-manager.js +94 -0
- package/dist/auth/identity-attributes-manager.js.map +1 -0
- package/dist/auth/identity-attributes.d.ts +19 -0
- package/dist/auth/identity-attributes.d.ts.map +1 -0
- package/dist/auth/identity-attributes.js +170 -0
- package/dist/auth/identity-attributes.js.map +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/types.d.ts +75 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +2 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/createActorHooks.d.ts +12 -12
- package/dist/createActorHooks.d.ts.map +1 -1
- package/dist/createActorHooks.js.map +1 -1
- package/dist/createInfiniteQuery.d.ts +32 -32
- package/dist/createInfiniteQuery.d.ts.map +1 -1
- package/dist/createInfiniteQuery.js +6 -6
- package/dist/createInfiniteQuery.js.map +1 -1
- package/dist/createMutation.d.ts +12 -1
- package/dist/createMutation.d.ts.map +1 -1
- package/dist/createMutation.js +11 -0
- package/dist/createMutation.js.map +1 -1
- package/dist/createQuery.d.ts +12 -2
- package/dist/createQuery.d.ts.map +1 -1
- package/dist/createQuery.js +15 -5
- package/dist/createQuery.js.map +1 -1
- package/dist/createSuspenseInfiniteQuery.d.ts +31 -31
- package/dist/createSuspenseInfiniteQuery.d.ts.map +1 -1
- package/dist/createSuspenseInfiniteQuery.js +6 -6
- package/dist/createSuspenseInfiniteQuery.js.map +1 -1
- package/dist/createSuspenseQuery.d.ts +2 -2
- package/dist/createSuspenseQuery.d.ts.map +1 -1
- package/dist/createSuspenseQuery.js.map +1 -1
- package/dist/defineReactor.d.ts +74 -0
- package/dist/defineReactor.d.ts.map +1 -0
- package/dist/defineReactor.js +75 -0
- package/dist/defineReactor.js.map +1 -0
- package/dist/{createAuthHooks.d.ts → hooks/createAuthHooks.d.ts} +6 -13
- package/dist/hooks/createAuthHooks.d.ts.map +1 -0
- package/dist/{createAuthHooks.js → hooks/createAuthHooks.js} +12 -57
- package/dist/hooks/createAuthHooks.js.map +1 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useActorInfiniteQuery.d.ts +9 -9
- package/dist/hooks/useActorInfiniteQuery.d.ts.map +1 -1
- package/dist/hooks/useActorInfiniteQuery.js +3 -1
- package/dist/hooks/useActorInfiniteQuery.js.map +1 -1
- package/dist/hooks/useActorMethod.d.ts +17 -17
- package/dist/hooks/useActorMethod.d.ts.map +1 -1
- package/dist/hooks/useActorMethod.js.map +1 -1
- package/dist/hooks/useActorMutation.d.ts +18 -7
- package/dist/hooks/useActorMutation.d.ts.map +1 -1
- package/dist/hooks/useActorMutation.js +11 -0
- package/dist/hooks/useActorMutation.js.map +1 -1
- package/dist/hooks/useActorQuery.d.ts +8 -8
- package/dist/hooks/useActorQuery.d.ts.map +1 -1
- package/dist/hooks/useActorQuery.js.map +1 -1
- package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts +9 -9
- package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts.map +1 -1
- package/dist/hooks/useActorSuspenseInfiniteQuery.js +3 -1
- package/dist/hooks/useActorSuspenseInfiniteQuery.js.map +1 -1
- package/dist/hooks/useActorSuspenseQuery.d.ts +8 -8
- package/dist/hooks/useActorSuspenseQuery.d.ts.map +1 -1
- package/dist/hooks/useActorSuspenseQuery.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +24 -24
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +10 -2
- package/dist/utils.js.map +1 -1
- package/llms.txt +48 -0
- package/package.json +27 -21
- package/src/auth/authentication-manager.ts +519 -0
- package/src/auth/constants.ts +25 -0
- package/src/auth/createIdentityAttributeHooks.ts +83 -0
- package/src/auth/identity-attributes-manager.ts +127 -0
- package/src/auth/identity-attributes.ts +270 -0
- package/src/auth/index.ts +7 -0
- package/src/auth/types.ts +88 -0
- package/src/createActorHooks.ts +81 -49
- package/src/createInfiniteQuery.ts +153 -97
- package/src/createMutation.ts +34 -18
- package/src/createQuery.ts +92 -48
- package/src/createSuspenseInfiniteQuery.ts +165 -114
- package/src/createSuspenseQuery.ts +67 -41
- package/src/defineReactor.test.ts +70 -0
- package/src/defineReactor.ts +150 -0
- package/src/{createAuthHooks.ts → hooks/createAuthHooks.ts} +17 -98
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useActorInfiniteQuery.ts +44 -30
- package/src/hooks/useActorMethod.ts +62 -53
- package/src/hooks/useActorMutation.ts +47 -30
- package/src/hooks/useActorQuery.ts +36 -32
- package/src/hooks/useActorSuspenseInfiniteQuery.ts +56 -30
- package/src/hooks/useActorSuspenseQuery.ts +42 -32
- package/src/index.ts +3 -1
- package/src/types.ts +76 -71
- package/src/utils.test.ts +14 -0
- package/src/utils.ts +15 -2
- package/dist/createAuthHooks.d.ts.map +0 -1
- package/dist/createAuthHooks.js.map +0 -1
|
@@ -42,20 +42,20 @@ import { buildChainedSelect } from "./utils"
|
|
|
42
42
|
// ============================================================================
|
|
43
43
|
|
|
44
44
|
const createSuspenseQueryImpl = <
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
Service,
|
|
46
|
+
Method extends FunctionName<Service> = FunctionName<Service>,
|
|
47
|
+
Transform extends TransformKey = "candid",
|
|
48
|
+
Selected = QueryFnData<Service, Method, Transform>,
|
|
49
49
|
>(
|
|
50
|
-
reactor: Reactor<
|
|
51
|
-
config: SuspenseQueryConfig<
|
|
50
|
+
reactor: Reactor<Service, Transform>,
|
|
51
|
+
config: SuspenseQueryConfig<Service, Method, Transform, Selected>
|
|
52
52
|
): SuspenseQueryResult<
|
|
53
|
-
QueryFnData<
|
|
54
|
-
|
|
55
|
-
QueryError<
|
|
53
|
+
QueryFnData<Service, Method, Transform>,
|
|
54
|
+
Selected,
|
|
55
|
+
QueryError<Service, Method, Transform>
|
|
56
56
|
> => {
|
|
57
|
-
type TData = QueryFnData<
|
|
58
|
-
type TError = QueryError<
|
|
57
|
+
type TData = QueryFnData<Service, Method, Transform>
|
|
58
|
+
type TError = QueryError<Service, Method, Transform>
|
|
59
59
|
|
|
60
60
|
const {
|
|
61
61
|
functionName,
|
|
@@ -70,11 +70,11 @@ const createSuspenseQueryImpl = <
|
|
|
70
70
|
|
|
71
71
|
const getQueryKey = () => reactor.generateQueryKey(params)
|
|
72
72
|
|
|
73
|
-
const applySelect = (raw: TData):
|
|
74
|
-
select ? select(raw) : (raw as unknown as
|
|
73
|
+
const applySelect = (raw: TData): Selected =>
|
|
74
|
+
select ? select(raw) : (raw as unknown as Selected)
|
|
75
75
|
|
|
76
76
|
/** Cache-first fetch for use in loaders / route preloading. */
|
|
77
|
-
const fetch = async (): Promise<
|
|
77
|
+
const fetch = async (): Promise<Selected> => {
|
|
78
78
|
const result = await reactor.fetchQuery(params)
|
|
79
79
|
return applySelect(result)
|
|
80
80
|
}
|
|
@@ -91,7 +91,7 @@ const createSuspenseQueryImpl = <
|
|
|
91
91
|
|
|
92
92
|
const useSuspenseQueryHook: UseSuspenseQueryWithSelect<
|
|
93
93
|
TData,
|
|
94
|
-
|
|
94
|
+
Selected,
|
|
95
95
|
TError
|
|
96
96
|
> = (options: any): any => {
|
|
97
97
|
const baseOptions = reactor.getQueryOptions(params)
|
|
@@ -114,21 +114,20 @@ const createSuspenseQueryImpl = <
|
|
|
114
114
|
|
|
115
115
|
const getCacheData: SuspenseQueryResult<
|
|
116
116
|
TData,
|
|
117
|
-
|
|
117
|
+
Selected,
|
|
118
118
|
TError
|
|
119
|
-
>["getCacheData"] = (selectFn?: (data:
|
|
119
|
+
>["getCacheData"] = (selectFn?: (data: Selected) => unknown): any => {
|
|
120
120
|
const raw = reactor.getQueryData(params)
|
|
121
121
|
if (raw === undefined) return undefined
|
|
122
122
|
const selected = applySelect(raw)
|
|
123
123
|
return selectFn ? selectFn(selected) : selected
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
const setData: SuspenseQueryResult<TData,
|
|
126
|
+
const setData: SuspenseQueryResult<TData, Selected, TError>["setData"] = (
|
|
127
127
|
updater
|
|
128
128
|
) => {
|
|
129
129
|
return reactor.queryClient.setQueryData(getQueryKey(), updater as any) as
|
|
130
|
-
|
|
|
131
|
-
| undefined
|
|
130
|
+
TData | undefined
|
|
132
131
|
}
|
|
133
132
|
|
|
134
133
|
return {
|
|
@@ -147,17 +146,21 @@ const createSuspenseQueryImpl = <
|
|
|
147
146
|
// ============================================================================
|
|
148
147
|
|
|
149
148
|
export function createSuspenseQuery<
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
149
|
+
Service,
|
|
150
|
+
Transform extends TransformKey,
|
|
151
|
+
Method extends FunctionName<Service> = FunctionName<Service>,
|
|
152
|
+
Selected = QueryFnData<Service, Method, Transform>,
|
|
154
153
|
>(
|
|
155
|
-
reactor: Reactor<
|
|
156
|
-
config: SuspenseQueryConfig<NoInfer<
|
|
157
|
-
): SuspenseQueryResult<
|
|
154
|
+
reactor: Reactor<Service, Transform>,
|
|
155
|
+
config: SuspenseQueryConfig<NoInfer<Service>, Method, Transform, Selected>
|
|
156
|
+
): SuspenseQueryResult<
|
|
157
|
+
QueryFnData<Service, Method, Transform>,
|
|
158
|
+
Selected,
|
|
159
|
+
QueryError<Service, Method, Transform>
|
|
160
|
+
> {
|
|
158
161
|
return createSuspenseQueryImpl(
|
|
159
162
|
reactor,
|
|
160
|
-
config as SuspenseQueryConfig<
|
|
163
|
+
config as SuspenseQueryConfig<Service, Method, Transform, Selected>
|
|
161
164
|
)
|
|
162
165
|
}
|
|
163
166
|
|
|
@@ -166,24 +169,37 @@ export function createSuspenseQuery<
|
|
|
166
169
|
// ============================================================================
|
|
167
170
|
|
|
168
171
|
export function createSuspenseQueryFactory<
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
172
|
+
Service,
|
|
173
|
+
Transform extends TransformKey,
|
|
174
|
+
Method extends FunctionName<Service> = FunctionName<Service>,
|
|
175
|
+
Selected = QueryFnData<Service, Method, Transform>,
|
|
173
176
|
>(
|
|
174
|
-
reactor: Reactor<
|
|
175
|
-
config: SuspenseQueryFactoryConfig<
|
|
177
|
+
reactor: Reactor<Service, Transform>,
|
|
178
|
+
config: SuspenseQueryFactoryConfig<
|
|
179
|
+
NoInfer<Service>,
|
|
180
|
+
Method,
|
|
181
|
+
Transform,
|
|
182
|
+
Selected
|
|
183
|
+
>
|
|
176
184
|
): (
|
|
177
|
-
args: ReactorArgs<
|
|
178
|
-
) => SuspenseQueryResult<
|
|
185
|
+
args: ReactorArgs<Service, Method, Transform>
|
|
186
|
+
) => SuspenseQueryResult<
|
|
187
|
+
QueryFnData<Service, Method, Transform>,
|
|
188
|
+
Selected,
|
|
189
|
+
QueryError<Service, Method, Transform>
|
|
190
|
+
> {
|
|
179
191
|
const cache = new Map<
|
|
180
192
|
string,
|
|
181
|
-
SuspenseQueryResult<
|
|
193
|
+
SuspenseQueryResult<
|
|
194
|
+
QueryFnData<Service, Method, Transform>,
|
|
195
|
+
Selected,
|
|
196
|
+
QueryError<Service, Method, Transform>
|
|
197
|
+
>
|
|
182
198
|
>()
|
|
183
199
|
|
|
184
|
-
return (args: ReactorArgs<
|
|
200
|
+
return (args: ReactorArgs<Service, Method, Transform>) => {
|
|
185
201
|
const key = reactor.generateQueryKey({
|
|
186
|
-
functionName: config.functionName as
|
|
202
|
+
functionName: config.functionName as Method,
|
|
187
203
|
args,
|
|
188
204
|
})
|
|
189
205
|
const cacheKey = JSON.stringify(key)
|
|
@@ -191,8 +207,18 @@ export function createSuspenseQueryFactory<
|
|
|
191
207
|
const existing = cache.get(cacheKey)
|
|
192
208
|
if (existing) return existing
|
|
193
209
|
|
|
194
|
-
const result = createSuspenseQueryImpl<
|
|
195
|
-
|
|
210
|
+
const result = createSuspenseQueryImpl<
|
|
211
|
+
Service,
|
|
212
|
+
Method,
|
|
213
|
+
Transform,
|
|
214
|
+
Selected
|
|
215
|
+
>(reactor, {
|
|
216
|
+
...(config as SuspenseQueryFactoryConfig<
|
|
217
|
+
Service,
|
|
218
|
+
Method,
|
|
219
|
+
Transform,
|
|
220
|
+
Selected
|
|
221
|
+
>),
|
|
196
222
|
args,
|
|
197
223
|
})
|
|
198
224
|
cache.set(cacheKey, result)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest"
|
|
2
|
+
import { ClientManager, Reactor, DisplayReactor } from "@ic-reactor/core"
|
|
3
|
+
import { QueryClient } from "@tanstack/react-query"
|
|
4
|
+
import { defineReactor } from "./defineReactor"
|
|
5
|
+
import { ActorMethod } from "@icp-sdk/core/agent"
|
|
6
|
+
|
|
7
|
+
const idlFactory = ({ IDL }: any) =>
|
|
8
|
+
IDL.Service({
|
|
9
|
+
greet: IDL.Func([IDL.Text], [IDL.Text], ["query"]),
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
interface TestActor {
|
|
13
|
+
greet: ActorMethod<[string], string>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const baseConfig = {
|
|
17
|
+
name: "test",
|
|
18
|
+
idlFactory,
|
|
19
|
+
canisterId: "rrkah-fqaaa-aaaaa-aaaaq-cai",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe("defineReactor", () => {
|
|
23
|
+
it("bootstraps a standard Reactor with hooks and infrastructure", () => {
|
|
24
|
+
const result = defineReactor<TestActor>(baseConfig)
|
|
25
|
+
|
|
26
|
+
expect(result.reactor).toBeInstanceOf(Reactor)
|
|
27
|
+
expect(result.reactor).not.toBeInstanceOf(DisplayReactor)
|
|
28
|
+
expect(result.clientManager).toBeInstanceOf(ClientManager)
|
|
29
|
+
expect(result.queryClient).toBeInstanceOf(QueryClient)
|
|
30
|
+
expect(typeof result.useActorQuery).toBe("function")
|
|
31
|
+
expect(typeof result.useActorMutation).toBe("function")
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it("creates a DisplayReactor when display is true", () => {
|
|
35
|
+
const result = defineReactor<TestActor>({ ...baseConfig, display: true })
|
|
36
|
+
|
|
37
|
+
expect(result.reactor).toBeInstanceOf(DisplayReactor)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it("wires the reactor to the created ClientManager and QueryClient", () => {
|
|
41
|
+
const { reactor, clientManager, queryClient } =
|
|
42
|
+
defineReactor<TestActor>(baseConfig)
|
|
43
|
+
|
|
44
|
+
expect(reactor.clientManager).toBe(clientManager)
|
|
45
|
+
expect(clientManager.queryClient).toBe(queryClient)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it("reuses an existing ClientManager and its QueryClient", () => {
|
|
49
|
+
const queryClient = new QueryClient()
|
|
50
|
+
const clientManager = new ClientManager({ queryClient })
|
|
51
|
+
|
|
52
|
+
const result = defineReactor<TestActor>({ ...baseConfig, clientManager })
|
|
53
|
+
|
|
54
|
+
expect(result.clientManager).toBe(clientManager)
|
|
55
|
+
expect(result.queryClient).toBe(queryClient)
|
|
56
|
+
expect(result.reactor.clientManager).toBe(clientManager)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it("lets multiple reactors share one ClientManager", () => {
|
|
60
|
+
const ledger = defineReactor<TestActor>({ ...baseConfig, name: "ledger" })
|
|
61
|
+
const index = defineReactor<TestActor>({
|
|
62
|
+
...baseConfig,
|
|
63
|
+
name: "index",
|
|
64
|
+
clientManager: ledger.clientManager,
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
expect(index.clientManager).toBe(ledger.clientManager)
|
|
68
|
+
expect(index.reactor).not.toBe(ledger.reactor)
|
|
69
|
+
})
|
|
70
|
+
})
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* defineReactor - One-call bootstrap for a canister reactor + its React hooks.
|
|
3
|
+
*
|
|
4
|
+
* Collapses the four manual steps (QueryClient → ClientManager → Reactor →
|
|
5
|
+
* createActorHooks) into a single call, and turns the Reactor / DisplayReactor
|
|
6
|
+
* choice into a `display` flag.
|
|
7
|
+
* Use this when one-call bootstrap is enough. If you need reusable
|
|
8
|
+
* method-specific operations outside React, compose with query/mutation
|
|
9
|
+
* factories after setup.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { defineReactor } from "@ic-reactor/react"
|
|
14
|
+
* import { idlFactory, type _SERVICE } from "./declarations/backend"
|
|
15
|
+
*
|
|
16
|
+
* const { reactor, useActorQuery, useActorMutation } = defineReactor<_SERVICE>({
|
|
17
|
+
* name: "backend",
|
|
18
|
+
* idlFactory,
|
|
19
|
+
* canisterId: "rrkah-fqaaa-aaaaa-aaaaq-cai",
|
|
20
|
+
* display: true, // ⇒ DisplayReactor (string principals/bigints)
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* function Profile() {
|
|
24
|
+
* const { data } = useActorQuery({ functionName: "get_profile" })
|
|
25
|
+
* return <div>{data?.name}</div>
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example Reuse an existing ClientManager (multiple canisters share one agent)
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const ledger = defineReactor<_LEDGER>({ name: "ledger", idlFactory: ledgerIdl })
|
|
32
|
+
* const index = defineReactor<_INDEX>({
|
|
33
|
+
* name: "index",
|
|
34
|
+
* idlFactory: indexIdl,
|
|
35
|
+
* clientManager: ledger.clientManager,
|
|
36
|
+
* })
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
import { ClientManager, Reactor, DisplayReactor } from "@ic-reactor/core"
|
|
40
|
+
import type {
|
|
41
|
+
BaseActor,
|
|
42
|
+
TransformKey,
|
|
43
|
+
ReactorParameters,
|
|
44
|
+
ClientManagerParameters,
|
|
45
|
+
DisplayReactorParameters,
|
|
46
|
+
} from "@ic-reactor/core"
|
|
47
|
+
import { QueryClient } from "@tanstack/react-query"
|
|
48
|
+
import { createActorHooks, ActorHooks } from "./createActorHooks"
|
|
49
|
+
|
|
50
|
+
/** Options shared by both the standard and display variants of defineReactor. */
|
|
51
|
+
export interface DefineReactorSharedParameters
|
|
52
|
+
extends
|
|
53
|
+
Omit<ReactorParameters, "clientManager">,
|
|
54
|
+
Omit<ClientManagerParameters, "queryClient"> {
|
|
55
|
+
/**
|
|
56
|
+
* Reuse an existing ClientManager (e.g. to share one agent across canisters).
|
|
57
|
+
* When omitted, a ClientManager is created from the agent options below.
|
|
58
|
+
*/
|
|
59
|
+
clientManager?: ClientManager
|
|
60
|
+
/**
|
|
61
|
+
* Reuse an existing QueryClient. When omitted, the provided ClientManager's
|
|
62
|
+
* QueryClient is reused, or a new one is created.
|
|
63
|
+
*/
|
|
64
|
+
queryClient?: QueryClient
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Parameters for a standard (raw Candid types) reactor. */
|
|
68
|
+
export interface DefineReactorParameters extends DefineReactorSharedParameters {
|
|
69
|
+
display?: false
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Parameters for a DisplayReactor (UI-friendly string principals/bigints). */
|
|
73
|
+
export interface DefineDisplayReactorParameters<
|
|
74
|
+
Service,
|
|
75
|
+
> extends DefineReactorSharedParameters {
|
|
76
|
+
display: true
|
|
77
|
+
/** Optional initial argument validators (receive display types). */
|
|
78
|
+
validators?: DisplayReactorParameters<Service>["validators"]
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** The reactor instance plus its bound hooks and shared infrastructure. */
|
|
82
|
+
export type DefineReactorResult<
|
|
83
|
+
Service,
|
|
84
|
+
Transform extends TransformKey,
|
|
85
|
+
R extends Reactor<Service, Transform>,
|
|
86
|
+
> = ActorHooks<Service, Transform> & {
|
|
87
|
+
reactor: R
|
|
88
|
+
clientManager: ClientManager
|
|
89
|
+
queryClient: QueryClient
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function defineReactor<Service = BaseActor>(
|
|
93
|
+
params: DefineDisplayReactorParameters<Service>
|
|
94
|
+
): DefineReactorResult<Service, "display", DisplayReactor<Service>>
|
|
95
|
+
|
|
96
|
+
export function defineReactor<Service = BaseActor>(
|
|
97
|
+
params: DefineReactorParameters
|
|
98
|
+
): DefineReactorResult<Service, "candid", Reactor<Service, "candid">>
|
|
99
|
+
|
|
100
|
+
export function defineReactor<Service = BaseActor>(
|
|
101
|
+
params: DefineReactorParameters | DefineDisplayReactorParameters<Service>
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
103
|
+
): DefineReactorResult<Service, any, any> {
|
|
104
|
+
const {
|
|
105
|
+
clientManager: providedClientManager,
|
|
106
|
+
queryClient: providedQueryClient,
|
|
107
|
+
display,
|
|
108
|
+
agentOptions,
|
|
109
|
+
name,
|
|
110
|
+
idlFactory,
|
|
111
|
+
canisterId,
|
|
112
|
+
pollingOptions,
|
|
113
|
+
} = params as DefineDisplayReactorParameters<Service>
|
|
114
|
+
|
|
115
|
+
const queryClient =
|
|
116
|
+
providedQueryClient ??
|
|
117
|
+
providedClientManager?.queryClient ??
|
|
118
|
+
new QueryClient()
|
|
119
|
+
|
|
120
|
+
const clientManager =
|
|
121
|
+
providedClientManager ??
|
|
122
|
+
new ClientManager({
|
|
123
|
+
queryClient,
|
|
124
|
+
agentOptions,
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
const reactorConfig = {
|
|
128
|
+
clientManager,
|
|
129
|
+
name,
|
|
130
|
+
idlFactory,
|
|
131
|
+
canisterId,
|
|
132
|
+
pollingOptions,
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// The Reactor / DisplayReactor union cannot be expressed through the shared
|
|
136
|
+
// implementation signature, so the body is intentionally untyped here; the
|
|
137
|
+
// public overloads above carry the precise types for callers.
|
|
138
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
139
|
+
const reactor: any = display
|
|
140
|
+
? new DisplayReactor<Service>({
|
|
141
|
+
...reactorConfig,
|
|
142
|
+
validators: (params as DefineDisplayReactorParameters<Service>)
|
|
143
|
+
.validators,
|
|
144
|
+
})
|
|
145
|
+
: new Reactor<Service>(reactorConfig)
|
|
146
|
+
|
|
147
|
+
const hooks = createActorHooks(reactor)
|
|
148
|
+
|
|
149
|
+
return { ...hooks, reactor, clientManager, queryClient }
|
|
150
|
+
}
|
|
@@ -1,26 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
useMemo,
|
|
6
|
-
useState,
|
|
7
|
-
useCallback,
|
|
8
|
-
} from "react"
|
|
9
|
-
import {
|
|
10
|
-
ClientManager,
|
|
11
|
-
AgentState,
|
|
12
|
-
AuthState,
|
|
13
|
-
ClientManagerSignInOptions,
|
|
14
|
-
IdentityAttributeResult,
|
|
15
|
-
RequestIdentityAttributesParameters,
|
|
16
|
-
RequestOpenIdIdentityAttributesParameters,
|
|
17
|
-
} from "@ic-reactor/core"
|
|
1
|
+
import { useSyncExternalStore, useEffect, useRef, useMemo } from "react"
|
|
2
|
+
import type { AuthenticationManager } from "../auth/authentication-manager"
|
|
3
|
+
import type { AuthState, AuthenticationSignInOptions } from "../auth/types"
|
|
4
|
+
import type { AgentState } from "@ic-reactor/core"
|
|
18
5
|
import type { Principal } from "@icp-sdk/core/principal"
|
|
19
6
|
import type { Identity } from "@icp-sdk/core/agent"
|
|
20
7
|
|
|
21
8
|
export interface UseAuthReturn {
|
|
22
9
|
authenticate: () => Promise<Identity | undefined>
|
|
23
|
-
login: (options?:
|
|
10
|
+
login: (options?: AuthenticationSignInOptions) => Promise<void>
|
|
24
11
|
logout: (options?: { returnTo?: string }) => Promise<void>
|
|
25
12
|
isAuthenticated: boolean
|
|
26
13
|
isAuthenticating: boolean
|
|
@@ -33,27 +20,13 @@ export interface CreateAuthHooksReturn {
|
|
|
33
20
|
useAgentState: () => AgentState
|
|
34
21
|
useUserPrincipal: () => Principal | null
|
|
35
22
|
useAuth: () => UseAuthReturn
|
|
36
|
-
useIdentityAttributes: () => UseIdentityAttributesReturn
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface UseIdentityAttributesReturn {
|
|
40
|
-
requestAttributes: (
|
|
41
|
-
params: RequestIdentityAttributesParameters
|
|
42
|
-
) => Promise<IdentityAttributeResult>
|
|
43
|
-
requestOpenIdAttributes: (
|
|
44
|
-
params: RequestOpenIdIdentityAttributesParameters
|
|
45
|
-
) => Promise<IdentityAttributeResult>
|
|
46
|
-
attributes: IdentityAttributeResult | null
|
|
47
|
-
isRequestingAttributes: boolean
|
|
48
|
-
attributeError: Error | null
|
|
49
|
-
clearAttributes: () => void
|
|
50
23
|
}
|
|
51
24
|
|
|
52
25
|
/**
|
|
53
26
|
* Create authentication hooks for managing user sessions with Internet Identity.
|
|
54
27
|
*
|
|
55
28
|
* @example
|
|
56
|
-
* const { useAuth, useUserPrincipal, useAgentState } = createAuthHooks(
|
|
29
|
+
* const { useAuth, useUserPrincipal, useAgentState } = createAuthHooks(authentication)
|
|
57
30
|
*
|
|
58
31
|
* function App() {
|
|
59
32
|
* const { login, logout, principal, isAuthenticated } = useAuth()
|
|
@@ -64,8 +37,9 @@ export interface UseIdentityAttributesReturn {
|
|
|
64
37
|
* }
|
|
65
38
|
*/
|
|
66
39
|
export const createAuthHooks = (
|
|
67
|
-
|
|
40
|
+
authentication: AuthenticationManager
|
|
68
41
|
): CreateAuthHooksReturn => {
|
|
42
|
+
const { clientManager } = authentication
|
|
69
43
|
/**
|
|
70
44
|
* Subscribe to agent state changes.
|
|
71
45
|
* Returns the current agent state (agent, isInitialized, etc.)
|
|
@@ -84,10 +58,10 @@ export const createAuthHooks = (
|
|
|
84
58
|
*/
|
|
85
59
|
const useAuthState = (): AuthState =>
|
|
86
60
|
useSyncExternalStore(
|
|
87
|
-
(callback) =>
|
|
88
|
-
() =>
|
|
61
|
+
(callback) => authentication.subscribeAuthState(callback),
|
|
62
|
+
() => authentication.authState,
|
|
89
63
|
// Server snapshot - provide initial state for SSR
|
|
90
|
-
() =>
|
|
64
|
+
() => authentication.authState
|
|
91
65
|
)
|
|
92
66
|
|
|
93
67
|
/**
|
|
@@ -109,7 +83,7 @@ export const createAuthHooks = (
|
|
|
109
83
|
* }
|
|
110
84
|
*/
|
|
111
85
|
const useAuth = (): UseAuthReturn => {
|
|
112
|
-
const { login, logout, authenticate } =
|
|
86
|
+
const { login, logout, authenticate } = authentication
|
|
113
87
|
const { isAuthenticated, isAuthenticating, identity, error } =
|
|
114
88
|
useAuthState()
|
|
115
89
|
|
|
@@ -120,7 +94,11 @@ export const createAuthHooks = (
|
|
|
120
94
|
useEffect(() => {
|
|
121
95
|
if (!initializedRef.current) {
|
|
122
96
|
initializedRef.current = true
|
|
123
|
-
|
|
97
|
+
authentication
|
|
98
|
+
.prepareClient()
|
|
99
|
+
.catch(() => undefined)
|
|
100
|
+
.then(() => clientManager.initialize())
|
|
101
|
+
.then(() => authentication.authenticate())
|
|
124
102
|
}
|
|
125
103
|
}, [])
|
|
126
104
|
|
|
@@ -157,68 +135,9 @@ export const createAuthHooks = (
|
|
|
157
135
|
return identity ? identity.getPrincipal() : null
|
|
158
136
|
}
|
|
159
137
|
|
|
160
|
-
const useIdentityAttributes = (): UseIdentityAttributesReturn => {
|
|
161
|
-
const [attributes, setAttributes] =
|
|
162
|
-
useState<IdentityAttributeResult | null>(null)
|
|
163
|
-
const [isRequestingAttributes, setIsRequestingAttributes] = useState(false)
|
|
164
|
-
const [attributeError, setAttributeError] = useState<Error | null>(null)
|
|
165
|
-
|
|
166
|
-
const requestAttributes = useCallback(
|
|
167
|
-
async (params: RequestIdentityAttributesParameters) => {
|
|
168
|
-
setIsRequestingAttributes(true)
|
|
169
|
-
setAttributeError(null)
|
|
170
|
-
try {
|
|
171
|
-
const result = await clientManager.requestIdentityAttributes(params)
|
|
172
|
-
setAttributes(result)
|
|
173
|
-
return result
|
|
174
|
-
} catch (error) {
|
|
175
|
-
setAttributeError(error as Error)
|
|
176
|
-
throw error
|
|
177
|
-
} finally {
|
|
178
|
-
setIsRequestingAttributes(false)
|
|
179
|
-
}
|
|
180
|
-
},
|
|
181
|
-
[]
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
const requestOpenIdAttributes = useCallback(
|
|
185
|
-
async (params: RequestOpenIdIdentityAttributesParameters) => {
|
|
186
|
-
setIsRequestingAttributes(true)
|
|
187
|
-
setAttributeError(null)
|
|
188
|
-
try {
|
|
189
|
-
const result =
|
|
190
|
-
await clientManager.requestOpenIdIdentityAttributes(params)
|
|
191
|
-
setAttributes(result)
|
|
192
|
-
return result
|
|
193
|
-
} catch (error) {
|
|
194
|
-
setAttributeError(error as Error)
|
|
195
|
-
throw error
|
|
196
|
-
} finally {
|
|
197
|
-
setIsRequestingAttributes(false)
|
|
198
|
-
}
|
|
199
|
-
},
|
|
200
|
-
[]
|
|
201
|
-
)
|
|
202
|
-
|
|
203
|
-
const clearAttributes = useCallback(() => {
|
|
204
|
-
setAttributes(null)
|
|
205
|
-
setAttributeError(null)
|
|
206
|
-
}, [])
|
|
207
|
-
|
|
208
|
-
return {
|
|
209
|
-
requestAttributes,
|
|
210
|
-
requestOpenIdAttributes,
|
|
211
|
-
attributes,
|
|
212
|
-
isRequestingAttributes,
|
|
213
|
-
attributeError,
|
|
214
|
-
clearAttributes,
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
138
|
return {
|
|
219
139
|
useAuth,
|
|
220
140
|
useAgentState,
|
|
221
141
|
useUserPrincipal,
|
|
222
|
-
useIdentityAttributes,
|
|
223
142
|
}
|
|
224
143
|
}
|
package/src/hooks/index.ts
CHANGED
|
@@ -24,6 +24,10 @@ export {
|
|
|
24
24
|
createActorMethodHooks,
|
|
25
25
|
} from "./useActorMethod.js"
|
|
26
26
|
|
|
27
|
+
// createAuthHooks
|
|
28
|
+
export { createAuthHooks } from "./createAuthHooks.js"
|
|
29
|
+
export type { CreateAuthHooksReturn, UseAuthReturn } from "./createAuthHooks.js"
|
|
30
|
+
|
|
27
31
|
// ============================================================================
|
|
28
32
|
// Types - UseReactor* (with reactor parameter)
|
|
29
33
|
// ============================================================================
|