@ic-reactor/react 3.12.4 → 3.13.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 (152) hide show
  1. package/README.md +410 -44
  2. package/dist/auth/auth-client-compat.d.ts +122 -0
  3. package/dist/auth/auth-client-compat.d.ts.map +1 -0
  4. package/dist/auth/auth-client-compat.js +162 -0
  5. package/dist/auth/auth-client-compat.js.map +1 -0
  6. package/dist/auth/authentication-manager.d.ts +287 -5
  7. package/dist/auth/authentication-manager.d.ts.map +1 -1
  8. package/dist/auth/authentication-manager.js +920 -150
  9. package/dist/auth/authentication-manager.js.map +1 -1
  10. package/dist/auth/createIdentityAttributeHooks.d.ts.map +1 -1
  11. package/dist/auth/createIdentityAttributeHooks.js +36 -20
  12. package/dist/auth/createIdentityAttributeHooks.js.map +1 -1
  13. package/dist/auth/identity-attributes-manager.d.ts +2 -1
  14. package/dist/auth/identity-attributes-manager.d.ts.map +1 -1
  15. package/dist/auth/identity-attributes-manager.js +90 -6
  16. package/dist/auth/identity-attributes-manager.js.map +1 -1
  17. package/dist/auth/identity-attributes.d.ts.map +1 -1
  18. package/dist/auth/identity-attributes.js +57 -0
  19. package/dist/auth/identity-attributes.js.map +1 -1
  20. package/dist/auth/local-ii-probe.d.ts +12 -1
  21. package/dist/auth/local-ii-probe.d.ts.map +1 -1
  22. package/dist/auth/local-ii-probe.js +22 -3
  23. package/dist/auth/local-ii-probe.js.map +1 -1
  24. package/dist/auth/types.d.ts +48 -5
  25. package/dist/auth/types.d.ts.map +1 -1
  26. package/dist/createActorHooks.d.ts +9 -20
  27. package/dist/createActorHooks.d.ts.map +1 -1
  28. package/dist/createActorHooks.js.map +1 -1
  29. package/dist/createInfiniteQuery.d.ts +51 -10
  30. package/dist/createInfiniteQuery.d.ts.map +1 -1
  31. package/dist/createInfiniteQuery.js +39 -15
  32. package/dist/createInfiniteQuery.js.map +1 -1
  33. package/dist/createMutation.d.ts +4 -1
  34. package/dist/createMutation.d.ts.map +1 -1
  35. package/dist/createMutation.js +121 -84
  36. package/dist/createMutation.js.map +1 -1
  37. package/dist/createQuery.d.ts +35 -2
  38. package/dist/createQuery.d.ts.map +1 -1
  39. package/dist/createQuery.js +104 -17
  40. package/dist/createQuery.js.map +1 -1
  41. package/dist/createReactorProvider.d.ts +158 -0
  42. package/dist/createReactorProvider.d.ts.map +1 -0
  43. package/dist/createReactorProvider.js +256 -0
  44. package/dist/createReactorProvider.js.map +1 -0
  45. package/dist/createSuspenseInfiniteQuery.d.ts +16 -9
  46. package/dist/createSuspenseInfiniteQuery.d.ts.map +1 -1
  47. package/dist/createSuspenseInfiniteQuery.js +59 -27
  48. package/dist/createSuspenseInfiniteQuery.js.map +1 -1
  49. package/dist/createSuspenseQuery.d.ts +23 -2
  50. package/dist/createSuspenseQuery.d.ts.map +1 -1
  51. package/dist/createSuspenseQuery.js +68 -21
  52. package/dist/createSuspenseQuery.js.map +1 -1
  53. package/dist/defineDisplayReactor.d.ts +43 -0
  54. package/dist/defineDisplayReactor.d.ts.map +1 -0
  55. package/dist/defineDisplayReactor.js +42 -0
  56. package/dist/defineDisplayReactor.js.map +1 -0
  57. package/dist/defineReactor.d.ts +46 -72
  58. package/dist/defineReactor.d.ts.map +1 -1
  59. package/dist/defineReactor.js +11 -176
  60. package/dist/defineReactor.js.map +1 -1
  61. package/dist/defineReactorShared.d.ts +84 -0
  62. package/dist/defineReactorShared.d.ts.map +1 -0
  63. package/dist/defineReactorShared.js +139 -0
  64. package/dist/defineReactorShared.js.map +1 -0
  65. package/dist/hooks/createAuthHooks.d.ts +9 -2
  66. package/dist/hooks/createAuthHooks.d.ts.map +1 -1
  67. package/dist/hooks/createAuthHooks.js +184 -24
  68. package/dist/hooks/createAuthHooks.js.map +1 -1
  69. package/dist/hooks/useActorInfiniteQuery.d.ts +36 -8
  70. package/dist/hooks/useActorInfiniteQuery.d.ts.map +1 -1
  71. package/dist/hooks/useActorInfiniteQuery.js +54 -21
  72. package/dist/hooks/useActorInfiniteQuery.js.map +1 -1
  73. package/dist/hooks/useActorMethod.d.ts +37 -4
  74. package/dist/hooks/useActorMethod.d.ts.map +1 -1
  75. package/dist/hooks/useActorMethod.js +201 -57
  76. package/dist/hooks/useActorMethod.js.map +1 -1
  77. package/dist/hooks/useActorMutation.d.ts +15 -12
  78. package/dist/hooks/useActorMutation.d.ts.map +1 -1
  79. package/dist/hooks/useActorMutation.js +14 -13
  80. package/dist/hooks/useActorMutation.js.map +1 -1
  81. package/dist/hooks/useActorQuery.d.ts +17 -4
  82. package/dist/hooks/useActorQuery.d.ts.map +1 -1
  83. package/dist/hooks/useActorQuery.js +30 -9
  84. package/dist/hooks/useActorQuery.js.map +1 -1
  85. package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts +17 -5
  86. package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts.map +1 -1
  87. package/dist/hooks/useActorSuspenseInfiniteQuery.js +37 -17
  88. package/dist/hooks/useActorSuspenseInfiniteQuery.js.map +1 -1
  89. package/dist/hooks/useActorSuspenseQuery.d.ts +2 -2
  90. package/dist/hooks/useActorSuspenseQuery.d.ts.map +1 -1
  91. package/dist/hooks/useActorSuspenseQuery.js +20 -9
  92. package/dist/hooks/useActorSuspenseQuery.js.map +1 -1
  93. package/dist/index.d.ts +4 -0
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +6 -0
  96. package/dist/index.js.map +1 -1
  97. package/dist/ownedAuthentication.d.ts +52 -0
  98. package/dist/ownedAuthentication.d.ts.map +1 -0
  99. package/dist/ownedAuthentication.js +49 -0
  100. package/dist/ownedAuthentication.js.map +1 -0
  101. package/dist/server.d.ts +21 -0
  102. package/dist/server.d.ts.map +1 -0
  103. package/dist/server.js +23 -0
  104. package/dist/server.js.map +1 -0
  105. package/dist/testing.d.ts +19 -0
  106. package/dist/testing.d.ts.map +1 -0
  107. package/dist/testing.js +19 -0
  108. package/dist/testing.js.map +1 -0
  109. package/dist/types.d.ts +428 -21
  110. package/dist/types.d.ts.map +1 -1
  111. package/dist/types.js +1 -1
  112. package/dist/utils.d.ts +159 -3
  113. package/dist/utils.d.ts.map +1 -1
  114. package/dist/utils.js +301 -1
  115. package/dist/utils.js.map +1 -1
  116. package/dist/validation.d.ts +12 -7
  117. package/dist/validation.d.ts.map +1 -1
  118. package/dist/validation.js +34 -15
  119. package/dist/validation.js.map +1 -1
  120. package/llms.txt +259 -33
  121. package/package.json +17 -5
  122. package/src/auth/auth-client-compat.ts +273 -0
  123. package/src/auth/authentication-manager.ts +918 -96
  124. package/src/auth/createIdentityAttributeHooks.ts +47 -21
  125. package/src/auth/identity-attributes-manager.ts +100 -5
  126. package/src/auth/identity-attributes.ts +75 -0
  127. package/src/auth/local-ii-probe.ts +29 -3
  128. package/src/auth/types.ts +49 -6
  129. package/src/createActorHooks.ts +50 -42
  130. package/src/createInfiniteQuery.ts +120 -28
  131. package/src/createMutation.ts +213 -132
  132. package/src/createQuery.ts +164 -32
  133. package/src/createReactorProvider.ts +365 -0
  134. package/src/createSuspenseInfiniteQuery.ts +93 -43
  135. package/src/createSuspenseQuery.ts +102 -32
  136. package/src/defineDisplayReactor.ts +62 -0
  137. package/src/defineReactor.ts +81 -263
  138. package/src/defineReactorShared.ts +268 -0
  139. package/src/hooks/createAuthHooks.ts +210 -28
  140. package/src/hooks/useActorInfiniteQuery.ts +156 -55
  141. package/src/hooks/useActorMethod.ts +295 -92
  142. package/src/hooks/useActorMutation.ts +42 -30
  143. package/src/hooks/useActorQuery.ts +43 -10
  144. package/src/hooks/useActorSuspenseInfiniteQuery.ts +110 -54
  145. package/src/hooks/useActorSuspenseQuery.ts +30 -15
  146. package/src/index.ts +8 -0
  147. package/src/ownedAuthentication.ts +81 -0
  148. package/src/server.ts +23 -0
  149. package/src/testing.ts +18 -0
  150. package/src/types.ts +492 -22
  151. package/src/utils.ts +387 -3
  152. package/src/validation.ts +43 -19
@@ -0,0 +1,273 @@
1
+ /**
2
+ * Bridges IC Reactor's stable authentication options onto whichever
3
+ * `@icp-sdk/auth` major is installed.
4
+ *
5
+ * `@icp-sdk/auth` v9 reshaped the `AuthClient` constructor and v10 moved its
6
+ * `@icp-sdk/core` peer to `^6`. The *method* surface IC Reactor calls --
7
+ * `signIn`, `signOut`, `getIdentity`, `isAuthenticated`, `requestAttributes`,
8
+ * `memoize` -- is byte-identical across v8 and v10, so only the option objects
9
+ * handed to the constructor and to `signIn` have to be translated.
10
+ *
11
+ * The translation lives here rather than in `AuthenticationManager` so that
12
+ * {@link AuthenticationClientOptions} stays IC Reactor's own contract. Callers
13
+ * keep writing `identityProvider: "https://id.ai/authorize"` whichever peer
14
+ * they installed, and the shapes diverge only at the boundary.
15
+ *
16
+ * Why both majors: v8 peers `@icp-sdk/core@^5` while IC Reactor needs `^6`, so
17
+ * a strict `npm install` resolving v8 fails with `ERESOLVE` unless the app adds
18
+ * an `overrides` block. v10 is the first release whose peer is `^6`, which
19
+ * removes that workaround -- but pinning v10 alone would break every app
20
+ * already installed on v8.
21
+ */
22
+ import type {
23
+ AuthClientSignInOptions,
24
+ AuthenticationClientOptions,
25
+ } from "./types.js"
26
+
27
+ /**
28
+ * Which options contract the installed `AuthClient` accepts.
29
+ *
30
+ * - `legacy` -- v8. `identityProvider` is a URL; `storage`, `keyType`,
31
+ * `idleOptions` and `identity` are constructor options; `signIn` takes
32
+ * `targets`.
33
+ * - `session` -- v9/v10. `identityProvider` is an `{ authorizeUrl, canisterId }`
34
+ * pair, credentials moved behind `credentialStorage`, idle moved to the
35
+ * identity provider canister, and `signIn` no longer takes `targets`.
36
+ */
37
+ export type AuthClientFlavor = "legacy" | "session"
38
+
39
+ /** The `{ authorizeUrl, canisterId }` pair a v9+ client names a deployment by. */
40
+ export interface SessionIdentityProvider {
41
+ authorizeUrl: string | URL
42
+ canisterId: string
43
+ }
44
+
45
+ /**
46
+ * Which canister a v9+ client should pair with the configured
47
+ * `identityProvider` URL, as `AuthenticationManager` works it out.
48
+ *
49
+ * - `mainnet`: the URL is mainnet's and nothing overrides the canister, so the
50
+ * option is omitted and the client uses mainnet for both halves.
51
+ * - `pair`: the canister is known, from `internetIdentityId` or because the URL
52
+ * is one IC Reactor derived for a local deployment.
53
+ * - `unknown`: a URL the caller configured with no canister to go with it.
54
+ */
55
+ export type IdentityProviderPairing =
56
+ | { kind: "mainnet" }
57
+ | { kind: "pair"; canisterId: string }
58
+ | { kind: "unknown" }
59
+
60
+ /**
61
+ * Detects the contract from the constructor itself rather than from the
62
+ * module's exports.
63
+ *
64
+ * `getStatus`, `getPrincipal`, `subscribe` and `dispose` were added to
65
+ * `AuthClient` in v9 and have no v8 counterpart. Reading them off the prototype
66
+ * beats sniffing the module namespace: a bundler may drop an unreferenced named
67
+ * export (`IdbStorage`, `IdleManager`) from the namespace object it synthesizes
68
+ * for a dynamic import, but it never drops a class's own methods.
69
+ *
70
+ * Two markers rather than one, because a single name is a coincidence away from
71
+ * matching some future shim. An unrecognised constructor is treated as `legacy`
72
+ * -- the shape IC Reactor's own options already mirror, so a wrong guess there
73
+ * passes the values through untouched instead of rewriting them into a shape
74
+ * nothing understands.
75
+ */
76
+ export function detectAuthClientFlavor(AuthClient: unknown): AuthClientFlavor {
77
+ const prototype = (AuthClient as { prototype?: Record<string, unknown> })
78
+ ?.prototype
79
+
80
+ if (!prototype) {
81
+ return "legacy"
82
+ }
83
+
84
+ return typeof prototype.getStatus === "function" &&
85
+ typeof prototype.getPrincipal === "function"
86
+ ? "session"
87
+ : "legacy"
88
+ }
89
+
90
+ /**
91
+ * Detects the contract of a client the caller built and passed in.
92
+ *
93
+ * Such a client never goes through the module loader, so there is no
94
+ * constructor to hand {@link detectAuthClientFlavor}. The markers are the same
95
+ * two methods, reached through the instance instead of the prototype.
96
+ */
97
+ export function detectAuthClientInstanceFlavor(
98
+ client: unknown
99
+ ): AuthClientFlavor {
100
+ const instance = client as Record<string, unknown> | undefined
101
+
102
+ return typeof instance?.getStatus === "function" &&
103
+ typeof instance?.getPrincipal === "function"
104
+ ? "session"
105
+ : "legacy"
106
+ }
107
+
108
+ /**
109
+ * Options a `session`-era client drops on the floor, and what replaced them.
110
+ *
111
+ * Each is a real capability in v8 with no v9+ constructor equivalent, so the
112
+ * only honest thing to do is say so rather than pass a key that is ignored.
113
+ */
114
+ const DROPPED_CONSTRUCTOR_OPTIONS: Record<string, string> = {
115
+ storage:
116
+ "`storage` (an AuthClientStorage) has no v9+ equivalent: credentials moved behind `credentialStorage`, whose store also generates identities and holds a delegation alongside each key, so an AuthClientStorage cannot be adapted into one. Construct the client yourself and pass it as `authClient` to keep a custom store.",
117
+ keyType:
118
+ "`keyType` was removed in v9+: the credential store decides the key type, because a store that has to serialise needs an extractable key and one that does not should not hold one.",
119
+ idleOptions:
120
+ "`idleOptions` was removed in v9+: the idle timeout belongs to the identity provider canister. Pass `maxTimeToIdle` to `login()` instead, and set `disableBrowserActivity` in the AuthenticationManager options to stop the client watching the browser.",
121
+ identity:
122
+ "`identity` was removed from v9+ constructor options: the agent signs as the session rather than as an identity handed in at construction.",
123
+ }
124
+
125
+ /** Emits each distinct warning once per process, so a render loop cannot spam. */
126
+ const warned = new Set<string>()
127
+
128
+ function warnOnce(key: string, message: string) {
129
+ if (warned.has(key)) return
130
+ warned.add(key)
131
+ console.warn(`[ic-reactor] ${message}`)
132
+ }
133
+
134
+ /** @internal Test seam -- lets a suite assert the first warning every time. */
135
+ export function resetAuthCompatWarnings() {
136
+ warned.clear()
137
+ }
138
+
139
+ /**
140
+ * Translates IC Reactor's constructor options into the installed client's shape.
141
+ *
142
+ * On `legacy` the object is already the right shape and is returned as-is,
143
+ * except for `disableBrowserActivity`. That option exists only on v10, so it is
144
+ * dropped with a one-time warning rather than handed to a v8 client that
145
+ * ignores it.
146
+ *
147
+ * On `session` the identity provider becomes a pair. The canister is not
148
+ * derived from the URL, because v9+ is explicit that the origin serving a
149
+ * ceremony is not a promise about which canister mints there. `pairing` says
150
+ * which canister goes with the URL. When nothing does, this throws rather than
151
+ * guessing: a guessed canister sends the delegation calls to a different
152
+ * deployment than the one the user signs in at, and sign-in fails later with an
153
+ * error that names neither.
154
+ *
155
+ * @param options - IC Reactor's resolved options, in the v8-shaped contract.
156
+ * @param flavor - The contract the installed client accepts.
157
+ * @param pairing - Which canister goes with `options.identityProvider`.
158
+ * @param agentOptions - Options for the agent a v9+ client mints delegations
159
+ * with. v8 has no such agent, so a `legacy` client never receives them.
160
+ */
161
+ export function toAuthClientConstructorOptions(
162
+ options: AuthenticationClientOptions | undefined,
163
+ flavor: AuthClientFlavor,
164
+ pairing: IdentityProviderPairing = { kind: "unknown" },
165
+ agentOptions?: Record<string, unknown>
166
+ ): AuthenticationClientOptions | Record<string, unknown> | undefined {
167
+ if (!options) {
168
+ return options
169
+ }
170
+
171
+ if (flavor === "legacy") {
172
+ if (options.disableBrowserActivity === undefined) {
173
+ return options
174
+ }
175
+ warnOnce(
176
+ "constructor:disableBrowserActivity",
177
+ "`disableBrowserActivity` needs @icp-sdk/auth v10 and is ignored by v8, which has no equivalent. On v8, `idleOptions` controls idle handling."
178
+ )
179
+ const { disableBrowserActivity: _disableBrowserActivity, ...legacy } =
180
+ options
181
+ return legacy
182
+ }
183
+
184
+ // Prefixed with `_` because they are destructured only to keep them out of
185
+ // `carried`: a v9+ constructor has no equivalent for any of them, and the
186
+ // loop below is what actually reports each one that was set.
187
+ const {
188
+ identityProvider,
189
+ storage: _storage,
190
+ keyType: _keyType,
191
+ idleOptions: _idleOptions,
192
+ identity: _identity,
193
+ ...carried
194
+ } = options
195
+
196
+ for (const [name, explanation] of Object.entries(
197
+ DROPPED_CONSTRUCTOR_OPTIONS
198
+ )) {
199
+ if ((options as Record<string, unknown>)[name] !== undefined) {
200
+ warnOnce(`constructor:${name}`, explanation)
201
+ }
202
+ }
203
+ const translated: Record<string, unknown> = { ...carried }
204
+
205
+ if (agentOptions !== undefined) {
206
+ translated.agentOptions = agentOptions
207
+ }
208
+
209
+ if (identityProvider !== undefined) {
210
+ if (pairing.kind === "unknown") {
211
+ throw new Error(
212
+ `[ic-reactor] identityProvider ${String(identityProvider)} needs internetIdentityId with @icp-sdk/auth v10, which names a provider by its authorize URL and the canister that mints its delegations. Set internetIdentityId to the canister that serves that URL.`
213
+ )
214
+ }
215
+ // An absent option is how v9+ says "both values are mainnet's".
216
+ if (pairing.kind === "pair") {
217
+ translated.identityProvider = {
218
+ authorizeUrl: identityProvider,
219
+ canisterId: pairing.canisterId,
220
+ } satisfies SessionIdentityProvider
221
+ }
222
+ }
223
+
224
+ return translated
225
+ }
226
+
227
+ /**
228
+ * Translates `signIn` options into the installed client's shape.
229
+ *
230
+ * `targets` is the one that matters. v8 forwards it to restrict the delegation
231
+ * to named canisters; v9+ removed it, and scoping is decided by the identity
232
+ * provider against the app's own canister. Passing it to a v9+ client does not
233
+ * fail -- it is simply ignored, and the delegation that comes back is broader
234
+ * than the caller asked for. That is a security-relevant difference, so it
235
+ * warns unconditionally rather than only in development.
236
+ *
237
+ * `maxTimeToIdle` goes the other way. It exists only on v10, so a v10 client
238
+ * receives it, and a v8 client, whose sign-in has no idle limit, gets it
239
+ * dropped with a one-time warning.
240
+ */
241
+ export function toAuthClientSignInOptions(
242
+ options: AuthClientSignInOptions | undefined,
243
+ flavor: AuthClientFlavor
244
+ ): AuthClientSignInOptions | undefined {
245
+ if (!options) {
246
+ return options
247
+ }
248
+
249
+ if (flavor === "legacy") {
250
+ if (options.maxTimeToIdle === undefined) {
251
+ return options
252
+ }
253
+ warnOnce(
254
+ "signIn:maxTimeToIdle",
255
+ "`maxTimeToIdle` needs @icp-sdk/auth v10 and is ignored by v8, whose sign-in has no idle limit. On v8, set `idleOptions` instead."
256
+ )
257
+ const { maxTimeToIdle: _maxTimeToIdle, ...legacy } = options
258
+ return legacy
259
+ }
260
+
261
+ const { targets, ...carried } = options
262
+
263
+ if (targets !== undefined) {
264
+ // Every time, not once: each sign-in that passes `targets` receives a
265
+ // delegation broader than it asked for, and a warning spent on an earlier
266
+ // one says nothing about this one.
267
+ console.warn(
268
+ "[ic-reactor] `targets` was removed in @icp-sdk/auth v9+ and is ignored: the delegation you receive is NOT restricted to those canisters. The identity provider scopes a session to the application canister instead. Remove `targets`, or pin @icp-sdk/auth to ^8 if you depend on canister-scoped delegations."
269
+ )
270
+ }
271
+
272
+ return carried
273
+ }