@ic-reactor/react 3.13.0 → 4.0.0-beta.2

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 (174) hide show
  1. package/README.md +237 -787
  2. package/dist/index.d.ts +260 -16
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +471 -23
  5. package/dist/index.js.map +1 -1
  6. package/llms.txt +82 -278
  7. package/package.json +11 -39
  8. package/src/index.tsx +612 -0
  9. package/dist/auth/auth-client-compat.d.ts +0 -122
  10. package/dist/auth/auth-client-compat.d.ts.map +0 -1
  11. package/dist/auth/auth-client-compat.js +0 -162
  12. package/dist/auth/auth-client-compat.js.map +0 -1
  13. package/dist/auth/authentication-manager.d.ts +0 -405
  14. package/dist/auth/authentication-manager.d.ts.map +0 -1
  15. package/dist/auth/authentication-manager.js +0 -1537
  16. package/dist/auth/authentication-manager.js.map +0 -1
  17. package/dist/auth/constants.d.ts +0 -24
  18. package/dist/auth/constants.d.ts.map +0 -1
  19. package/dist/auth/constants.js +0 -24
  20. package/dist/auth/constants.js.map +0 -1
  21. package/dist/auth/createIdentityAttributeHooks.d.ts +0 -14
  22. package/dist/auth/createIdentityAttributeHooks.d.ts.map +0 -1
  23. package/dist/auth/createIdentityAttributeHooks.js +0 -122
  24. package/dist/auth/createIdentityAttributeHooks.js.map +0 -1
  25. package/dist/auth/identity-attributes-manager.d.ts +0 -27
  26. package/dist/auth/identity-attributes-manager.d.ts.map +0 -1
  27. package/dist/auth/identity-attributes-manager.js +0 -191
  28. package/dist/auth/identity-attributes-manager.js.map +0 -1
  29. package/dist/auth/identity-attributes.d.ts +0 -19
  30. package/dist/auth/identity-attributes.d.ts.map +0 -1
  31. package/dist/auth/identity-attributes.js +0 -227
  32. package/dist/auth/identity-attributes.js.map +0 -1
  33. package/dist/auth/index.d.ts +0 -8
  34. package/dist/auth/index.d.ts.map +0 -1
  35. package/dist/auth/index.js +0 -8
  36. package/dist/auth/index.js.map +0 -1
  37. package/dist/auth/local-ii-probe.d.ts +0 -57
  38. package/dist/auth/local-ii-probe.d.ts.map +0 -1
  39. package/dist/auth/local-ii-probe.js +0 -121
  40. package/dist/auth/local-ii-probe.js.map +0 -1
  41. package/dist/auth/types.d.ts +0 -222
  42. package/dist/auth/types.d.ts.map +0 -1
  43. package/dist/auth/types.js +0 -2
  44. package/dist/auth/types.js.map +0 -1
  45. package/dist/createActorHooks.d.ts +0 -41
  46. package/dist/createActorHooks.d.ts.map +0 -1
  47. package/dist/createActorHooks.js +0 -17
  48. package/dist/createActorHooks.js.map +0 -1
  49. package/dist/createInfiniteQuery.d.ts +0 -185
  50. package/dist/createInfiniteQuery.d.ts.map +0 -1
  51. package/dist/createInfiniteQuery.js +0 -198
  52. package/dist/createInfiniteQuery.js.map +0 -1
  53. package/dist/createMutation.d.ts +0 -33
  54. package/dist/createMutation.d.ts.map +0 -1
  55. package/dist/createMutation.js +0 -199
  56. package/dist/createMutation.js.map +0 -1
  57. package/dist/createQuery.d.ts +0 -63
  58. package/dist/createQuery.d.ts.map +0 -1
  59. package/dist/createQuery.js +0 -204
  60. package/dist/createQuery.js.map +0 -1
  61. package/dist/createReactorProvider.d.ts +0 -158
  62. package/dist/createReactorProvider.d.ts.map +0 -1
  63. package/dist/createReactorProvider.js +0 -256
  64. package/dist/createReactorProvider.js.map +0 -1
  65. package/dist/createSuspenseInfiniteQuery.d.ts +0 -154
  66. package/dist/createSuspenseInfiniteQuery.d.ts.map +0 -1
  67. package/dist/createSuspenseInfiniteQuery.js +0 -209
  68. package/dist/createSuspenseInfiniteQuery.js.map +0 -1
  69. package/dist/createSuspenseQuery.d.ts +0 -46
  70. package/dist/createSuspenseQuery.d.ts.map +0 -1
  71. package/dist/createSuspenseQuery.js +0 -158
  72. package/dist/createSuspenseQuery.js.map +0 -1
  73. package/dist/defineDisplayReactor.d.ts +0 -43
  74. package/dist/defineDisplayReactor.d.ts.map +0 -1
  75. package/dist/defineDisplayReactor.js +0 -42
  76. package/dist/defineDisplayReactor.js.map +0 -1
  77. package/dist/defineReactor.d.ts +0 -99
  78. package/dist/defineReactor.d.ts.map +0 -1
  79. package/dist/defineReactor.js +0 -15
  80. package/dist/defineReactor.js.map +0 -1
  81. package/dist/defineReactorShared.d.ts +0 -84
  82. package/dist/defineReactorShared.d.ts.map +0 -1
  83. package/dist/defineReactorShared.js +0 -139
  84. package/dist/defineReactorShared.js.map +0 -1
  85. package/dist/hooks/createAuthHooks.d.ts +0 -50
  86. package/dist/hooks/createAuthHooks.d.ts.map +0 -1
  87. package/dist/hooks/createAuthHooks.js +0 -291
  88. package/dist/hooks/createAuthHooks.js.map +0 -1
  89. package/dist/hooks/index.d.ts +0 -21
  90. package/dist/hooks/index.d.ts.map +0 -1
  91. package/dist/hooks/index.js +0 -24
  92. package/dist/hooks/index.js.map +0 -1
  93. package/dist/hooks/useActorInfiniteQuery.d.ts +0 -67
  94. package/dist/hooks/useActorInfiniteQuery.d.ts.map +0 -1
  95. package/dist/hooks/useActorInfiniteQuery.js +0 -89
  96. package/dist/hooks/useActorInfiniteQuery.js.map +0 -1
  97. package/dist/hooks/useActorMethod.d.ts +0 -148
  98. package/dist/hooks/useActorMethod.d.ts.map +0 -1
  99. package/dist/hooks/useActorMethod.js +0 -394
  100. package/dist/hooks/useActorMethod.js.map +0 -1
  101. package/dist/hooks/useActorMutation.d.ts +0 -51
  102. package/dist/hooks/useActorMutation.d.ts.map +0 -1
  103. package/dist/hooks/useActorMutation.js +0 -70
  104. package/dist/hooks/useActorMutation.js.map +0 -1
  105. package/dist/hooks/useActorQuery.d.ts +0 -45
  106. package/dist/hooks/useActorQuery.d.ts.map +0 -1
  107. package/dist/hooks/useActorQuery.js +0 -67
  108. package/dist/hooks/useActorQuery.js.map +0 -1
  109. package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts +0 -51
  110. package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts.map +0 -1
  111. package/dist/hooks/useActorSuspenseInfiniteQuery.js +0 -76
  112. package/dist/hooks/useActorSuspenseInfiniteQuery.js.map +0 -1
  113. package/dist/hooks/useActorSuspenseQuery.d.ts +0 -32
  114. package/dist/hooks/useActorSuspenseQuery.d.ts.map +0 -1
  115. package/dist/hooks/useActorSuspenseQuery.js +0 -58
  116. package/dist/hooks/useActorSuspenseQuery.js.map +0 -1
  117. package/dist/ownedAuthentication.d.ts +0 -52
  118. package/dist/ownedAuthentication.d.ts.map +0 -1
  119. package/dist/ownedAuthentication.js +0 -49
  120. package/dist/ownedAuthentication.js.map +0 -1
  121. package/dist/server.d.ts +0 -21
  122. package/dist/server.d.ts.map +0 -1
  123. package/dist/server.js +0 -23
  124. package/dist/server.js.map +0 -1
  125. package/dist/testing.d.ts +0 -19
  126. package/dist/testing.d.ts.map +0 -1
  127. package/dist/testing.js +0 -19
  128. package/dist/testing.js.map +0 -1
  129. package/dist/types.d.ts +0 -671
  130. package/dist/types.d.ts.map +0 -1
  131. package/dist/types.js +0 -5
  132. package/dist/types.js.map +0 -1
  133. package/dist/utils.d.ts +0 -207
  134. package/dist/utils.d.ts.map +0 -1
  135. package/dist/utils.js +0 -405
  136. package/dist/utils.js.map +0 -1
  137. package/dist/validation.d.ts +0 -136
  138. package/dist/validation.d.ts.map +0 -1
  139. package/dist/validation.js +0 -144
  140. package/dist/validation.js.map +0 -1
  141. package/src/auth/auth-client-compat.ts +0 -273
  142. package/src/auth/authentication-manager.ts +0 -1682
  143. package/src/auth/constants.ts +0 -32
  144. package/src/auth/createIdentityAttributeHooks.ts +0 -169
  145. package/src/auth/identity-attributes-manager.ts +0 -226
  146. package/src/auth/identity-attributes.ts +0 -345
  147. package/src/auth/index.ts +0 -7
  148. package/src/auth/local-ii-probe.ts +0 -173
  149. package/src/auth/types.ts +0 -243
  150. package/src/createActorHooks.ts +0 -208
  151. package/src/createInfiniteQuery.ts +0 -670
  152. package/src/createMutation.ts +0 -324
  153. package/src/createQuery.ts +0 -369
  154. package/src/createReactorProvider.ts +0 -365
  155. package/src/createSuspenseInfiniteQuery.ts +0 -651
  156. package/src/createSuspenseQuery.ts +0 -304
  157. package/src/defineDisplayReactor.ts +0 -62
  158. package/src/defineReactor.ts +0 -142
  159. package/src/defineReactorShared.ts +0 -268
  160. package/src/hooks/createAuthHooks.ts +0 -371
  161. package/src/hooks/index.ts +0 -103
  162. package/src/hooks/useActorInfiniteQuery.ts +0 -278
  163. package/src/hooks/useActorMethod.ts +0 -710
  164. package/src/hooks/useActorMutation.ts +0 -205
  165. package/src/hooks/useActorQuery.ts +0 -157
  166. package/src/hooks/useActorSuspenseInfiniteQuery.ts +0 -248
  167. package/src/hooks/useActorSuspenseQuery.ts +0 -147
  168. package/src/index.ts +0 -31
  169. package/src/ownedAuthentication.ts +0 -81
  170. package/src/server.ts +0 -23
  171. package/src/testing.ts +0 -18
  172. package/src/types.ts +0 -948
  173. package/src/utils.ts +0 -505
  174. package/src/validation.ts +0 -226
package/dist/index.js CHANGED
@@ -1,24 +1,472 @@
1
- // Re-export core (following TanStack Query's pattern)
2
- // Users can import everything from @ic-reactor/react without needing @ic-reactor/core
3
- export * from "@ic-reactor/core";
4
- // Re-export hooks
5
- export * from "./hooks/index.js";
6
- // Validation utilities for React
7
- export * from "./validation.js";
8
- // React-specific exports
9
- export * from "./createActorHooks.js";
10
- export * from "./defineReactor.js";
11
- export * from "./defineDisplayReactor.js";
12
- export * from "./createReactorProvider.js";
13
- export * from "./createQuery.js";
14
- export * from "./createSuspenseQuery.js";
15
- export * from "./createInfiniteQuery.js";
16
- export * from "./createSuspenseInfiniteQuery.js";
17
- export * from "./createMutation.js";
18
- export * from "./auth/index.js";
19
- export * from "./types.js";
20
- // TanStack Query's marker for a query whose args are not known yet, which the
21
- // non-suspense query hooks and createQueryFactory take in place of args. It is
22
- // the same symbol as @tanstack/react-query's, so either import works.
23
- export { skipToken } from "@tanstack/react-query";
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { QueryClientProvider } from "@tanstack/react-query";
4
+ import { createContext, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore, } from "react";
5
+ /** The client of the nearest {@link ReactorProvider}, or none outside one. */
6
+ const ClientContext = createContext(undefined);
7
+ /**
8
+ * The clients whose disposal this package has run, so that a provider can tell
9
+ * when React hands it a client it already disposed (see {@link ReactorProvider}).
10
+ */
11
+ const disposedClients = new WeakSet();
12
+ /*
13
+ * An internal contract with `@ic-reactor/core`'s `createClient`, not public
14
+ * API (core's `src/client.ts` documents the other side): `globalThis` holds
15
+ * how many clients have been made in this realm, each client carries that
16
+ * count once it was made as its serial, and a getter that says whether it
17
+ * was disposed. Each client also carries a method that, called with the
18
+ * client as `this` and a principal's text, returns a frozen view of the
19
+ * client whose keys, read options, `caller()` and `authState()` are that
20
+ * principal's (the client itself for one built with `identity`): what
21
+ * {@link useClient} returns while it renders with a caller that is not the
22
+ * live one. Each such view carries the client it was made over, which
23
+ * {@link hold} keeps in its place. `Symbol.for` keys and a count on `globalThis`, so that this
24
+ * module reads them from whichever copy of core made the client, and imports
25
+ * nothing of core at run time.
26
+ */
27
+ const CLIENTS_CREATED = Symbol.for("ic-reactor.clients.created");
28
+ const CLIENT_SERIAL = Symbol.for("ic-reactor.client.serial");
29
+ const CLIENT_DISPOSED = Symbol.for("ic-reactor.client.disposed");
30
+ const CLIENT_AS = Symbol.for("ic-reactor.client.as");
31
+ const CLIENT_OF = Symbol.for("ic-reactor.client.of");
32
+ /** How many clients `createClient` has made in this realm so far. */
33
+ const clientsCreated = () => Number(globalThis[CLIENTS_CREATED]) || 0;
34
+ /*
35
+ * Disposes an owned client whose render React threw away before committing it.
36
+ *
37
+ * React gives a discarded render no cleanup. When a Suspense boundary above
38
+ * the provider suspends during the provider's first render, or `StrictMode`
39
+ * calls the `useState` initializer twice in development and keeps one result,
40
+ * the client built for the render React drops never reaches the effect that
41
+ * disposes it. By then a child's `useAuth()` may have built its auth (an
42
+ * `AuthClient`) and subscribed to it, so every abandoned render leaked an auth
43
+ * and its listeners.
44
+ *
45
+ * So an owned client is registered here against its `Held`, the provider's
46
+ * state, which nothing outside the provider references. If React drops that
47
+ * state, the registry disposes the client after a garbage collection finds the
48
+ * state unreachable. That is a backstop, not a lifecycle: no code chooses the
49
+ * moment, and the language does not even promise it comes, but engines run it
50
+ * after the next collections, and `dispose()` is idempotent.
51
+ *
52
+ * The client is the unregister token, so one `unregister` removes what every
53
+ * dropped render registered for it. Two moments do: a factory call that hands
54
+ * the client back as borrowed (see {@link hold}), and the commit of any
55
+ * provider that renders it. A client that a factory returns again, or that a
56
+ * tree runs on, is not one React threw away, and only an unmount, or its
57
+ * owner, may end it.
58
+ *
59
+ * Not on a server: a server keeps no state after a component renders, while
60
+ * the rest of the request still uses the client, so a collection there would
61
+ * end a client in use. A server's client builds no auth and mounts no
62
+ * `QueryClient`, so it holds nothing to release anyway.
63
+ */
64
+ const unclaimed = typeof FinalizationRegistry === "function" &&
65
+ typeof window !== "undefined" &&
66
+ !("Deno" in globalThis)
67
+ ? new FinalizationRegistry((client) => client.dispose())
68
+ : undefined;
69
+ /**
70
+ * Calls a provider's factory and decides whether the provider owns what it
71
+ * returns.
72
+ *
73
+ * It owns a client its factory call created, and only that one: the count of
74
+ * clients is read before the call, and a client whose serial is above it was
75
+ * made during the call. A client made before (at module scope, one per tab,
76
+ * and used outside React too) is borrowed. Disposing a borrowed client on
77
+ * unmount killed it for good: the next provider to mount, the next test's
78
+ * render or a remounted route got the same client back from its factory,
79
+ * already disposed, and every call through it was cancelled with no error
80
+ * anywhere (#780). Its owner, not a provider, decides when it ends.
81
+ *
82
+ * A client without a serial, such as a test's spread copy of one, is owned
83
+ * when some client was made during the call: the one it copies, then.
84
+ *
85
+ * An owned client is registered with {@link unclaimed} against this call's
86
+ * `Held`, until a provider commits it. A borrowed one is never registered,
87
+ * and a registration that an earlier, dropped render made for it is removed
88
+ * here: a factory that returns a client again keeps it outside the render. A
89
+ * lazily shared factory (`() => (client ??= createClient(...))`) is the case:
90
+ * the render that created the client owns it, and when React throws that
91
+ * render away the retry gets the same client back as borrowed, then commits
92
+ * and uses it. Left registered, the client would be disposed under the
93
+ * mounted tree at the next collection.
94
+ *
95
+ * That removal is also how the pattern shows itself, so it is reported in
96
+ * development (see {@link reportLazilyShared}). Only the call that created a
97
+ * client registers it, and the first removal ends the registration, so the
98
+ * report comes once per client.
99
+ */
100
+ function hold(build) {
101
+ const before = clientsCreated();
102
+ const built = build();
103
+ // A view that a component's useClient() returned keeps its caller for good:
104
+ // hold the client it was made over, whose caller the tree then follows.
105
+ const client = built[CLIENT_OF] ?? built;
106
+ const serial = client[CLIENT_SERIAL];
107
+ const owned = typeof serial === "number" ? serial > before : clientsCreated() > before;
108
+ const held = { client, owned };
109
+ if (owned)
110
+ unclaimed?.register(held, client, client);
111
+ else if (unclaimed?.unregister(client))
112
+ reportLazilyShared();
113
+ return held;
114
+ }
115
+ /**
116
+ * Whether to report how a provider's client was handed to it (see
117
+ * {@link reportDisposed} and {@link reportLazilyShared}).
118
+ */
119
+ const isDevelopment = () => {
120
+ try {
121
+ // Written as is, so that a bundler replaces `process.env.NODE_ENV` with
122
+ // its value. Without a bundler and without Node, `process` throws, and
123
+ // the message is shown.
124
+ return process.env.NODE_ENV !== "production";
125
+ }
126
+ catch {
127
+ return true;
128
+ }
129
+ };
130
+ /** The disposed clients a provider was handed and that were reported. */
131
+ const reported = new WeakSet();
132
+ /**
133
+ * Reports, once per client and in development, a borrowed client that its
134
+ * owner already disposed: a provider cannot replace it (the factory returns
135
+ * the same one), and nothing else would say why every call is cancelled.
136
+ */
137
+ function reportDisposed(client) {
138
+ if (client[CLIENT_DISPOSED] !== true ||
139
+ reported.has(client) ||
140
+ !isDevelopment()) {
141
+ return;
142
+ }
143
+ reported.add(client);
144
+ console.error("[ic-reactor] <ReactorProvider> got a disposed client, so every call is cancelled (client_disposed). " +
145
+ "A provider disposes only a client its own factory created: create a shared client eagerly and keep it " +
146
+ "alive, or use client={() => createClient({ ... })}.");
147
+ }
148
+ /**
149
+ * Reports, in development, a factory that handed back a client which an
150
+ * earlier factory call created and no provider has committed yet. A lazily
151
+ * shared factory (`() => (client ??= createClient(...))`) does that, and so
152
+ * does one that returns a client another provider's factory call created.
153
+ *
154
+ * The provider of the call that created such a client owns it, so it disposes
155
+ * it on unmount under every other tree that uses it; and from the moment React
156
+ * throws the creating render away until a later render gets the client back, a
157
+ * garbage collection can dispose it. Both show up late, as calls that are
158
+ * cancelled, and on React 18 the second window can last a whole fetch of a
159
+ * suspending child. The pattern shows here first, and `StrictMode`, which
160
+ * calls the factory twice on every mount, shows it on the first render of a
161
+ * development build.
162
+ */
163
+ function reportLazilyShared() {
164
+ if (!isDevelopment())
165
+ return;
166
+ console.warn("[ic-reactor] <ReactorProvider> got a client that an earlier factory call created (client ??= createClient(...)). " +
167
+ "That call's provider disposes it on unmount, or at a garbage collection if React threw its render away. " +
168
+ "A provider disposes only a client its own factory created: create a shared client eagerly and keep it " +
169
+ "alive, or use client={() => createClient({ ... })}.");
170
+ }
171
+ /**
172
+ * Gives a tree one client: it gets it from `client` once, on the first
173
+ * render, makes it available to {@link useClient} and {@link useAuth}, renders
174
+ * TanStack Query's `QueryClientProvider` around the children with the
175
+ * client's `QueryClient`, and, if its factory created the client, disposes it
176
+ * when it unmounts.
177
+ *
178
+ * Put it at the root of the part of the app that calls canisters, in a
179
+ * client module (the examples below). On a server it renders inside the
180
+ * request, so a factory that creates the client runs once per request and no
181
+ * cache or caller is shared between two users, which a client at module scope
182
+ * would be.
183
+ *
184
+ * Who disposes the client depends on when it was created, not on where the
185
+ * factory is written. A client the factory call creates belongs to the
186
+ * provider. A client created before the call, such as one at module scope that
187
+ * code outside React uses too, is borrowed: the provider never disposes it,
188
+ * however many times it mounts and unmounts, and the app ends it with
189
+ * `client.dispose()` if it ever needs to. A factory that creates the shared
190
+ * client lazily on its first call (`() => (client ??= createClient(...))`)
191
+ * hands that first provider ownership, and the provider disposes it on
192
+ * unmount. It can also lose the client before any unmount: when React throws
193
+ * away the render that created it (see below), the client stays registered
194
+ * for disposal at collection until the next render gets it back from the
195
+ * factory, so a garbage collection while the fallback shows disposes the
196
+ * client the retry then mounts. Create a shared client eagerly instead. In
197
+ * development, a provider whose factory hands back a client that an earlier
198
+ * factory call created and no provider has committed yet, as a lazily shared
199
+ * factory does, logs a warning (under `StrictMode`, on its first render), and
200
+ * a provider that is given a borrowed client which is already disposed logs an
201
+ * error.
202
+ *
203
+ * Disposal is safe in React's development double-mount (`StrictMode` mounts,
204
+ * unmounts and mounts every component again at once): the cleanup only
205
+ * schedules the disposal for the next macrotask, and the second mount cancels
206
+ * it, so a client in use is never disposed. An unmount that is not followed
207
+ * by a mount disposes an owned client exactly once.
208
+ *
209
+ * React runs no cleanup for a render it throws away before committing it: the
210
+ * first render of a provider below a Suspense boundary that suspends, or the
211
+ * `useState` initializer call that `StrictMode` drops in development. An owned
212
+ * client built for such a render, whose auth a child's {@link useAuth} may
213
+ * already have built, is disposed once that render's state is garbage
214
+ * collected, through a `FinalizationRegistry`. That is later than an unmount
215
+ * would dispose it, at a moment no code chooses, but it is disposed, auth and
216
+ * listeners with it. A client that the factory returns again, or that a
217
+ * provider commits, is taken off the registry, whoever owns it. A runtime
218
+ * without `FinalizationRegistry` never disposes such a client, and a server
219
+ * never registers one: it builds no auth there, and the rest of the request
220
+ * still uses it.
221
+ *
222
+ * React also runs the effects of a subtree again when it shows a hidden
223
+ * `Activity` once more, and that can be long after they were cleaned up. If an
224
+ * owned client was disposed meanwhile, the provider builds another from the
225
+ * same factory, because a disposed client cannot call, sign in or cache any
226
+ * more. The cost is that hiding a provider inside an `Activity` drops its
227
+ * cache: disposing clears the `QueryClient`, and the client built on the next
228
+ * show starts empty. React cannot tell a hidden subtree from an unmounted one
229
+ * in the cleanup, so there is no way to keep it. To keep a cache across
230
+ * hiding, render the provider above the `Activity`, not inside it, or give it
231
+ * a borrowed client, which is never disposed.
232
+ *
233
+ * @example
234
+ * A client per provider, owned and disposed by it (on a server, one per
235
+ * request):
236
+ * ```tsx
237
+ * "use client"
238
+ *
239
+ * import { createClient } from "@ic-reactor/core"
240
+ * import { ReactorProvider } from "@ic-reactor/react"
241
+ * import { AuthClient } from "@icp-sdk/auth/client"
242
+ * import type { ReactNode } from "react"
243
+ *
244
+ * export function Providers({ children }: { children: ReactNode }) {
245
+ * return (
246
+ * <ReactorProvider
247
+ * client={() =>
248
+ * createClient({ network: "ic", auth: () => new AuthClient() })
249
+ * }
250
+ * >
251
+ * {children}
252
+ * </ReactorProvider>
253
+ * )
254
+ * }
255
+ * ```
256
+ *
257
+ * @example
258
+ * One client per tab, created at module scope and used outside React too.
259
+ * The provider borrows it and never disposes it (browser-only: on a server a
260
+ * module-scope client is shared by every request):
261
+ * ```tsx
262
+ * "use client"
263
+ *
264
+ * import { createClient } from "@ic-reactor/core"
265
+ * import { ReactorProvider } from "@ic-reactor/react"
266
+ * import { AuthClient } from "@icp-sdk/auth/client"
267
+ * import type { ReactNode } from "react"
268
+ *
269
+ * export const client = createClient({
270
+ * network: "ic",
271
+ * auth: () => new AuthClient(),
272
+ * })
273
+ *
274
+ * export function Providers({ children }: { children: ReactNode }) {
275
+ * return <ReactorProvider client={() => client}>{children}</ReactorProvider>
276
+ * }
277
+ * ```
278
+ */
279
+ export function ReactorProvider({ client: build, children, }) {
280
+ const [held, setHeld] = useState(() => hold(build));
281
+ const { client, owned } = held;
282
+ const firstBuild = useRef(build);
283
+ const replacement = useRef(undefined);
284
+ const pendingDispose = useRef(undefined);
285
+ useEffect(() => {
286
+ // A client a tree runs on is never left to the registry, whoever owns it:
287
+ // a dropped render may have registered this same client, as the one that
288
+ // created a lazily shared client does before a retry borrows it.
289
+ unclaimed?.unregister(client);
290
+ if (!owned) {
291
+ // Borrowed: never disposed here, so there is nothing to schedule, to
292
+ // cancel or to replace.
293
+ reportDisposed(client);
294
+ return undefined;
295
+ }
296
+ if (disposedClients.has(client)) {
297
+ // A hidden subtree was shown again after its client was disposed. React
298
+ // runs this effect twice in development before the state below commits;
299
+ // both runs must hand it the same client, not build one to drop.
300
+ if (replacement.current?.of !== client) {
301
+ replacement.current = { of: client, held: hold(firstBuild.current) };
302
+ }
303
+ setHeld(replacement.current.held);
304
+ return undefined;
305
+ }
306
+ // The mount that follows a development unmount: the client is still alive.
307
+ clearTimeout(pendingDispose.current);
308
+ pendingDispose.current = undefined;
309
+ return () => {
310
+ pendingDispose.current = setTimeout(() => {
311
+ pendingDispose.current = undefined;
312
+ disposedClients.add(client);
313
+ client.dispose();
314
+ }, 0);
315
+ };
316
+ }, [client, owned]);
317
+ return (_jsx(ClientContext.Provider, { value: client, children: _jsx(QueryClientProvider, { client: client.queryClient, children: children }) }));
318
+ }
319
+ /** The provider's client, or the error that names the provider. */
320
+ function useProvided() {
321
+ const client = useContext(ClientContext);
322
+ if (client === undefined) {
323
+ throw new Error("[ic-reactor] useClient() and useAuth() need a <ReactorProvider> above them: " +
324
+ "render <ReactorProvider client={() => createClient({ ... })}> around the tree.");
325
+ }
326
+ return client;
327
+ }
328
+ /** The principal a server render, and a hydrating render, call as: nobody. */
329
+ const ANONYMOUS = "2vxsx-fae";
330
+ const anonymous = () => ANONYMOUS;
331
+ /**
332
+ * The client of the nearest {@link ReactorProvider}: the one object that
333
+ * builds canister handles and query options, and that signs users in and out.
334
+ *
335
+ * Call it in the body of each component that builds keys or options, on
336
+ * every render, and build them from what it returns there, never from a
337
+ * client held at module scope: they are built for the caller this render
338
+ * shows. Do not keep what it returns past the render: while a page hydrates
339
+ * it is a view for the anonymous caller, and a view never moves on. An effect
340
+ * or a callback that uses it closes over its render's value and lists it in
341
+ * its dependencies (`react-hooks/exhaustive-deps`), so that it runs again with
342
+ * the client after hydrating. Kept from the hydrating render anywhere else
343
+ * (`useState(client)`, `useRef(client)`, a `useMemo` or `useCallback` with
344
+ * `[]`, a module variable), it stays that view: the component shows the
345
+ * anonymous caller's data, a read it starts while the user is signed in is
346
+ * cancelled, and a write through it still signs as the live caller. Nothing
347
+ * warns about it. A nested {@link ReactorProvider} given it
348
+ * (`client={() => client}`) holds the client the view was made over.
349
+ * It follows the client's caller with `useSyncExternalStore`, so a
350
+ * component that calls it renders again when the caller changes (a sign-in, a
351
+ * switch of account, a sign-out) and never otherwise: a change of status that
352
+ * leaves the caller as it is (a session that expired, or one signed in
353
+ * elsewhere, both call as the anonymous principal) renders nothing. In the
354
+ * steady state it returns the provider's client object itself.
355
+ *
356
+ * On a server, and while a page hydrates, the caller is the anonymous one, as
357
+ * for {@link useAuth}. In a browser that holds a session, the hydrating render
358
+ * gets a view of the client for the anonymous caller: its `queryKey`,
359
+ * `queryOptions`, `caller()` and `authState()` are the anonymous caller's, so
360
+ * the page finds what the server prefetched and dehydrated and matches its
361
+ * HTML; everything else (canisters, `mutationOptions`, `signIn`, `signOut`,
362
+ * the `QueryClient`) is the client's own, and a write signs as the caller
363
+ * current when it runs. Right after hydrating, React renders the component
364
+ * again with the client itself, for the user: a read with none of the user's
365
+ * data yet shows its loading state, and a `useSuspenseQuery` read its
366
+ * boundary's fallback, until that data arrives. A client built with
367
+ * `identity` keeps its caller for good and is always returned as it is.
368
+ *
369
+ * Three consequences of that move on a signed-in reload:
370
+ *
371
+ * - A Suspense boundary that is still dehydrated below a component that
372
+ * renders with the caller (this hook or {@link useAuth}), because its lazy
373
+ * code is still loading or its streamed HTML has not arrived, is rendered
374
+ * on the client when that component moves on: it shows its fallback
375
+ * instead of the server's HTML, and React 18 reports a recoverable error.
376
+ * Its data is still the user's. A `useAuth()` component also moves on in a
377
+ * tab whose session expired or is signed in elsewhere. Render such a boundary where no component
378
+ * that renders with the caller sits above it, or pass it in as `children`,
379
+ * which a component's own update does not render again.
380
+ * - A read the hydrating render built may still run once (TanStack Query
381
+ * refetches stale data on mount, and an effect may fetch with the view's
382
+ * options). It is cancelled before anything is sent. A key that holds data
383
+ * keeps it as it was, and a fetch of it resolves with that data. A key with
384
+ * none fails (`kind` `"cancelled"`, `code` `"caller_changed"`) until the
385
+ * anonymous caller is current again: the hydrating render's own reads never
386
+ * show that, but a listener of
387
+ * `client.queryClient.getQueryCache().subscribe()` (the client takes no
388
+ * `QueryCache` of yours), an effect that awaits the fetch and, for a
389
+ * `useSuspenseQuery` read the server rendered without dehydrating its
390
+ * data, React's `onRecoverableError` (as the reported error's `cause` on
391
+ * React 19) see it, so ignore `kind` `"cancelled"` there.
392
+ * - Put a Suspense boundary above every component that reads with
393
+ * `useSuspenseQuery`, on React 18 and 19 alike. The move is a synchronous
394
+ * update, which such a read suspends until the user's data arrives. With a
395
+ * boundary above, the boundary shows its fallback, then the user's data,
396
+ * and the rest of the page responds meanwhile. With none, React 18 refuses
397
+ * the update ("A component suspended while responding to synchronous
398
+ * input") and unmounts the root, so a signed-in reload renders nothing.
399
+ * React 19 keeps the server's HTML on screen, but until the user's data
400
+ * arrives, however long the read and its retries take, a click or any other
401
+ * update outside a transition commits nothing, and neither does a
402
+ * transition that renders the reading component again.
403
+ *
404
+ * @throws Error outside a `ReactorProvider`, naming it.
405
+ */
406
+ export function useClient() {
407
+ const client = useProvided();
408
+ // The view for the server's caller. A client with one caller for good is
409
+ // its own view and its own server snapshot: it has nothing to move on to
410
+ // after hydrating.
411
+ const view = client[CLIENT_AS]?.call(client, ANONYMOUS) ?? client;
412
+ const principal = useSyncExternalStore(client.subscribe, client.caller, view === client ? client.caller : anonymous);
413
+ // Only the server snapshot differs from the live caller, and only while a
414
+ // component hydrates.
415
+ return principal === client.caller() ? client : view;
416
+ }
417
+ /**
418
+ * Who a server render, and the first render of a hydrating page, call as:
419
+ * nobody. It is what `createClient` reports for an anonymous client, one
420
+ * constant for every render, so that the HTML a server wrote and the markup
421
+ * the browser's first render produces agree even when the browser holds a
422
+ * session.
423
+ */
424
+ const SERVER_STATE = Object.freeze({
425
+ status: "anonymous",
426
+ principal: ANONYMOUS,
427
+ });
428
+ const serverState = () => SERVER_STATE;
429
+ /**
430
+ * Who calls, and how to change it: the client's {@link AuthState} (`status`
431
+ * and `principal`) with `signIn` and `signOut` forwarded to the client.
432
+ *
433
+ * It follows the client with `useSyncExternalStore`, so a component renders
434
+ * again once per change of status or principal and never otherwise (a renewed
435
+ * delegation, or a parent that renders, does not). The object it returns is
436
+ * the same until the state changes, so it is safe in a dependency array or
437
+ * as a prop of a memoized child.
438
+ *
439
+ * On a server, and while a page hydrates, the state is `anonymous`: the
440
+ * server has no session, and rendering the browser's would not match the
441
+ * server's HTML. A browser whose state is another one (signed in, or a session
442
+ * that expired or is signed in elsewhere) renders the component again with its
443
+ * own state right after hydration; an anonymous one does not, and keeps the
444
+ * object. A component that reads `status` before then should show the same
445
+ * thing signed out and while the session is read. Whenever it moves on after
446
+ * hydrating (a signed-in reload, or a session that expired or is signed in
447
+ * elsewhere), it renders a Suspense boundary still dehydrated below it on the
448
+ * client, as for {@link useClient}.
449
+ *
450
+ * `signIn` and `signOut` reject like {@link Client.signIn} and
451
+ * {@link Client.signOut}: on a client built with `identity`, which has no
452
+ * sign-in, and on a server.
453
+ *
454
+ * @throws Error outside a {@link ReactorProvider}.
455
+ */
456
+ export function useAuth() {
457
+ const client = useProvided();
458
+ const state = useSyncExternalStore(client.subscribe, () => {
459
+ const live = client.authState();
460
+ // The anonymous state (whose principal is always the anonymous one) is
461
+ // the server's own object, so an anonymous tab has nothing to move on
462
+ // to after hydrating.
463
+ return live.status === "anonymous" ? SERVER_STATE : live;
464
+ }, serverState);
465
+ return useMemo(() => ({
466
+ status: state.status,
467
+ principal: state.principal,
468
+ signIn: (options) => client.signIn(options),
469
+ signOut: (options) => client.signOut(options),
470
+ }), [client, state]);
471
+ }
24
472
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,sFAAsF;AACtF,cAAc,kBAAkB,CAAA;AAEhC,kBAAkB;AAClB,cAAc,kBAAkB,CAAA;AAEhC,iCAAiC;AACjC,cAAc,iBAAiB,CAAA;AAE/B,yBAAyB;AACzB,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,2BAA2B,CAAA;AACzC,cAAc,4BAA4B,CAAA;AAE1C,cAAc,kBAAkB,CAAA;AAChC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,kCAAkC,CAAA;AAChD,cAAc,qBAAqB,CAAA;AAEnC,cAAc,iBAAiB,CAAA;AAE/B,cAAc,YAAY,CAAA;AAE1B,8EAA8E;AAC9E,+EAA+E;AAC/E,sEAAsE;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}