@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.
Files changed (125) hide show
  1. package/README.md +28 -8
  2. package/dist/auth/authentication-manager.d.ts +66 -0
  3. package/dist/auth/authentication-manager.d.ts.map +1 -0
  4. package/dist/auth/authentication-manager.js +458 -0
  5. package/dist/auth/authentication-manager.js.map +1 -0
  6. package/dist/auth/constants.d.ts +18 -0
  7. package/dist/auth/constants.d.ts.map +1 -0
  8. package/dist/auth/constants.js +18 -0
  9. package/dist/auth/constants.js.map +1 -0
  10. package/dist/auth/createIdentityAttributeHooks.d.ts +14 -0
  11. package/dist/auth/createIdentityAttributeHooks.d.ts.map +1 -0
  12. package/dist/auth/createIdentityAttributeHooks.js +54 -0
  13. package/dist/auth/createIdentityAttributeHooks.js.map +1 -0
  14. package/dist/auth/identity-attributes-manager.d.ts +19 -0
  15. package/dist/auth/identity-attributes-manager.d.ts.map +1 -0
  16. package/dist/auth/identity-attributes-manager.js +94 -0
  17. package/dist/auth/identity-attributes-manager.js.map +1 -0
  18. package/dist/auth/identity-attributes.d.ts +19 -0
  19. package/dist/auth/identity-attributes.d.ts.map +1 -0
  20. package/dist/auth/identity-attributes.js +170 -0
  21. package/dist/auth/identity-attributes.js.map +1 -0
  22. package/dist/auth/index.d.ts +8 -0
  23. package/dist/auth/index.d.ts.map +1 -0
  24. package/dist/auth/index.js +8 -0
  25. package/dist/auth/index.js.map +1 -0
  26. package/dist/auth/types.d.ts +75 -0
  27. package/dist/auth/types.d.ts.map +1 -0
  28. package/dist/auth/types.js +2 -0
  29. package/dist/auth/types.js.map +1 -0
  30. package/dist/createActorHooks.d.ts +12 -12
  31. package/dist/createActorHooks.d.ts.map +1 -1
  32. package/dist/createActorHooks.js.map +1 -1
  33. package/dist/createInfiniteQuery.d.ts +32 -32
  34. package/dist/createInfiniteQuery.d.ts.map +1 -1
  35. package/dist/createInfiniteQuery.js +6 -6
  36. package/dist/createInfiniteQuery.js.map +1 -1
  37. package/dist/createMutation.d.ts +12 -1
  38. package/dist/createMutation.d.ts.map +1 -1
  39. package/dist/createMutation.js +11 -0
  40. package/dist/createMutation.js.map +1 -1
  41. package/dist/createQuery.d.ts +12 -2
  42. package/dist/createQuery.d.ts.map +1 -1
  43. package/dist/createQuery.js +15 -5
  44. package/dist/createQuery.js.map +1 -1
  45. package/dist/createSuspenseInfiniteQuery.d.ts +31 -31
  46. package/dist/createSuspenseInfiniteQuery.d.ts.map +1 -1
  47. package/dist/createSuspenseInfiniteQuery.js +6 -6
  48. package/dist/createSuspenseInfiniteQuery.js.map +1 -1
  49. package/dist/createSuspenseQuery.d.ts +2 -2
  50. package/dist/createSuspenseQuery.d.ts.map +1 -1
  51. package/dist/createSuspenseQuery.js.map +1 -1
  52. package/dist/defineReactor.d.ts +74 -0
  53. package/dist/defineReactor.d.ts.map +1 -0
  54. package/dist/defineReactor.js +75 -0
  55. package/dist/defineReactor.js.map +1 -0
  56. package/dist/{createAuthHooks.d.ts → hooks/createAuthHooks.d.ts} +6 -13
  57. package/dist/hooks/createAuthHooks.d.ts.map +1 -0
  58. package/dist/{createAuthHooks.js → hooks/createAuthHooks.js} +12 -57
  59. package/dist/hooks/createAuthHooks.js.map +1 -0
  60. package/dist/hooks/index.d.ts +2 -0
  61. package/dist/hooks/index.d.ts.map +1 -1
  62. package/dist/hooks/index.js +2 -0
  63. package/dist/hooks/index.js.map +1 -1
  64. package/dist/hooks/useActorInfiniteQuery.d.ts +9 -9
  65. package/dist/hooks/useActorInfiniteQuery.d.ts.map +1 -1
  66. package/dist/hooks/useActorInfiniteQuery.js +3 -1
  67. package/dist/hooks/useActorInfiniteQuery.js.map +1 -1
  68. package/dist/hooks/useActorMethod.d.ts +17 -17
  69. package/dist/hooks/useActorMethod.d.ts.map +1 -1
  70. package/dist/hooks/useActorMethod.js.map +1 -1
  71. package/dist/hooks/useActorMutation.d.ts +18 -7
  72. package/dist/hooks/useActorMutation.d.ts.map +1 -1
  73. package/dist/hooks/useActorMutation.js +11 -0
  74. package/dist/hooks/useActorMutation.js.map +1 -1
  75. package/dist/hooks/useActorQuery.d.ts +8 -8
  76. package/dist/hooks/useActorQuery.d.ts.map +1 -1
  77. package/dist/hooks/useActorQuery.js.map +1 -1
  78. package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts +9 -9
  79. package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts.map +1 -1
  80. package/dist/hooks/useActorSuspenseInfiniteQuery.js +3 -1
  81. package/dist/hooks/useActorSuspenseInfiniteQuery.js.map +1 -1
  82. package/dist/hooks/useActorSuspenseQuery.d.ts +8 -8
  83. package/dist/hooks/useActorSuspenseQuery.d.ts.map +1 -1
  84. package/dist/hooks/useActorSuspenseQuery.js.map +1 -1
  85. package/dist/index.d.ts +2 -1
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +2 -1
  88. package/dist/index.js.map +1 -1
  89. package/dist/types.d.ts +24 -24
  90. package/dist/types.d.ts.map +1 -1
  91. package/dist/utils.d.ts +3 -0
  92. package/dist/utils.d.ts.map +1 -1
  93. package/dist/utils.js +10 -2
  94. package/dist/utils.js.map +1 -1
  95. package/llms.txt +48 -0
  96. package/package.json +27 -21
  97. package/src/auth/authentication-manager.ts +519 -0
  98. package/src/auth/constants.ts +25 -0
  99. package/src/auth/createIdentityAttributeHooks.ts +83 -0
  100. package/src/auth/identity-attributes-manager.ts +127 -0
  101. package/src/auth/identity-attributes.ts +270 -0
  102. package/src/auth/index.ts +7 -0
  103. package/src/auth/types.ts +88 -0
  104. package/src/createActorHooks.ts +81 -49
  105. package/src/createInfiniteQuery.ts +153 -97
  106. package/src/createMutation.ts +34 -18
  107. package/src/createQuery.ts +92 -48
  108. package/src/createSuspenseInfiniteQuery.ts +165 -114
  109. package/src/createSuspenseQuery.ts +67 -41
  110. package/src/defineReactor.test.ts +70 -0
  111. package/src/defineReactor.ts +150 -0
  112. package/src/{createAuthHooks.ts → hooks/createAuthHooks.ts} +17 -98
  113. package/src/hooks/index.ts +4 -0
  114. package/src/hooks/useActorInfiniteQuery.ts +44 -30
  115. package/src/hooks/useActorMethod.ts +62 -53
  116. package/src/hooks/useActorMutation.ts +47 -30
  117. package/src/hooks/useActorQuery.ts +36 -32
  118. package/src/hooks/useActorSuspenseInfiniteQuery.ts +56 -30
  119. package/src/hooks/useActorSuspenseQuery.ts +42 -32
  120. package/src/index.ts +3 -1
  121. package/src/types.ts +76 -71
  122. package/src/utils.test.ts +14 -0
  123. package/src/utils.ts +15 -2
  124. package/dist/createAuthHooks.d.ts.map +0 -1
  125. package/dist/createAuthHooks.js.map +0 -1
@@ -42,20 +42,20 @@ import { buildChainedSelect } from "./utils"
42
42
  // ============================================================================
43
43
 
44
44
  const createSuspenseQueryImpl = <
45
- A,
46
- M extends FunctionName<A> = FunctionName<A>,
47
- T extends TransformKey = "candid",
48
- TSelected = QueryFnData<A, M, T>,
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<A, T>,
51
- config: SuspenseQueryConfig<A, M, T, TSelected>
50
+ reactor: Reactor<Service, Transform>,
51
+ config: SuspenseQueryConfig<Service, Method, Transform, Selected>
52
52
  ): SuspenseQueryResult<
53
- QueryFnData<A, M, T>,
54
- TSelected,
55
- QueryError<A, M, T>
53
+ QueryFnData<Service, Method, Transform>,
54
+ Selected,
55
+ QueryError<Service, Method, Transform>
56
56
  > => {
57
- type TData = QueryFnData<A, M, T>
58
- type TError = QueryError<A, M, T>
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): TSelected =>
74
- select ? select(raw) : (raw as unknown as TSelected)
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<TSelected> => {
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
- TSelected,
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
- TSelected,
117
+ Selected,
118
118
  TError
119
- >["getCacheData"] = (selectFn?: (data: TSelected) => unknown): any => {
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, TSelected, TError>["setData"] = (
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
- | TData
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
- A,
151
- T extends TransformKey,
152
- M extends FunctionName<A> = FunctionName<A>,
153
- TSelected = QueryFnData<A, M, T>,
149
+ Service,
150
+ Transform extends TransformKey,
151
+ Method extends FunctionName<Service> = FunctionName<Service>,
152
+ Selected = QueryFnData<Service, Method, Transform>,
154
153
  >(
155
- reactor: Reactor<A, T>,
156
- config: SuspenseQueryConfig<NoInfer<A>, M, T, TSelected>
157
- ): SuspenseQueryResult<QueryFnData<A, M, T>, TSelected, QueryError<A, M, T>> {
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<A, M, T, TSelected>
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
- A,
170
- T extends TransformKey,
171
- M extends FunctionName<A> = FunctionName<A>,
172
- TSelected = QueryFnData<A, M, T>,
172
+ Service,
173
+ Transform extends TransformKey,
174
+ Method extends FunctionName<Service> = FunctionName<Service>,
175
+ Selected = QueryFnData<Service, Method, Transform>,
173
176
  >(
174
- reactor: Reactor<A, T>,
175
- config: SuspenseQueryFactoryConfig<NoInfer<A>, M, T, TSelected>
177
+ reactor: Reactor<Service, Transform>,
178
+ config: SuspenseQueryFactoryConfig<
179
+ NoInfer<Service>,
180
+ Method,
181
+ Transform,
182
+ Selected
183
+ >
176
184
  ): (
177
- args: ReactorArgs<A, M, T>
178
- ) => SuspenseQueryResult<QueryFnData<A, M, T>, TSelected, QueryError<A, M, T>> {
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<QueryFnData<A, M, T>, TSelected, QueryError<A, M, T>>
193
+ SuspenseQueryResult<
194
+ QueryFnData<Service, Method, Transform>,
195
+ Selected,
196
+ QueryError<Service, Method, Transform>
197
+ >
182
198
  >()
183
199
 
184
- return (args: ReactorArgs<A, M, T>) => {
200
+ return (args: ReactorArgs<Service, Method, Transform>) => {
185
201
  const key = reactor.generateQueryKey({
186
- functionName: config.functionName as M,
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<A, M, T, TSelected>(reactor, {
195
- ...(config as SuspenseQueryFactoryConfig<A, M, T, TSelected>),
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
- useSyncExternalStore,
3
- useEffect,
4
- useRef,
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?: ClientManagerSignInOptions) => Promise<void>
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(clientManager)
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
- clientManager: ClientManager
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) => clientManager.subscribeAuthState(callback),
88
- () => clientManager.authState,
61
+ (callback) => authentication.subscribeAuthState(callback),
62
+ () => authentication.authState,
89
63
  // Server snapshot - provide initial state for SSR
90
- () => clientManager.authState
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 } = clientManager
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
- clientManager.initialize()
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
  }
@@ -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
  // ============================================================================