@ic-reactor/react 3.12.5 → 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 +7 -18
  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 +3 -0
  34. package/dist/createMutation.d.ts.map +1 -1
  35. package/dist/createMutation.js +87 -80
  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 +7 -0
  66. package/dist/hooks/createAuthHooks.d.ts.map +1 -1
  67. package/dist/hooks/createAuthHooks.js +180 -20
  68. package/dist/hooks/createAuthHooks.js.map +1 -1
  69. package/dist/hooks/useActorInfiniteQuery.d.ts +34 -6
  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 +10 -7
  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 +15 -3
  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 +416 -15
  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 +20 -32
  130. package/src/createInfiniteQuery.ts +120 -28
  131. package/src/createMutation.ts +161 -178
  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 +206 -24
  140. package/src/hooks/useActorInfiniteQuery.ts +122 -49
  141. package/src/hooks/useActorMethod.ts +295 -92
  142. package/src/hooks/useActorMutation.ts +23 -23
  143. package/src/hooks/useActorQuery.ts +43 -10
  144. package/src/hooks/useActorSuspenseInfiniteQuery.ts +93 -50
  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 +463 -14
  151. package/src/utils.ts +387 -3
  152. package/src/validation.ts +43 -19
@@ -7,30 +7,48 @@
7
7
  import { ValidationError, isValidationError, } from "@ic-reactor/core";
8
8
  // Re-export for convenience
9
9
  export { isValidationError, ValidationError };
10
+ /**
11
+ * The field an issue belongs to: the first segment of its path, as a string.
12
+ * An issue with an empty path is about the whole argument (a zod object-level
13
+ * `.refine()`, or any issue of a primitive argument) and belongs to `""`.
14
+ */
15
+ function fieldNameOf(issue) {
16
+ return String(issue.path[0] ?? "");
17
+ }
10
18
  export function mapValidationErrors(error, options) {
19
+ // Collected in a Map, not a plain object: a field named like an
20
+ // Object.prototype member (`constructor`, `toString`, `__proto__`) read that
21
+ // member back as if the field were already filled, which dropped its issue,
22
+ // and threw on `.push` with `multiple`. `Object.fromEntries` then creates
23
+ // every field as an own property, `__proto__` included.
11
24
  if (options?.multiple) {
12
- const result = {};
25
+ const messages = new Map();
13
26
  for (const issue of error.issues) {
14
- const fieldName = String(issue.path[0] ?? "");
15
- if (!result[fieldName]) {
16
- result[fieldName] = [];
27
+ const fieldName = fieldNameOf(issue);
28
+ const fieldMessages = messages.get(fieldName);
29
+ if (fieldMessages) {
30
+ fieldMessages.push(issue.message);
31
+ }
32
+ else {
33
+ messages.set(fieldName, [issue.message]);
17
34
  }
18
- result[fieldName].push(issue.message);
19
35
  }
20
- return result;
36
+ return Object.fromEntries(messages);
21
37
  }
22
- const result = {};
38
+ const messages = new Map();
23
39
  for (const issue of error.issues) {
24
- const fieldName = String(issue.path[0] ?? "");
25
- if (!result[fieldName]) {
26
- result[fieldName] = issue.message;
40
+ const fieldName = fieldNameOf(issue);
41
+ if (!messages.get(fieldName)) {
42
+ messages.set(fieldName, issue.message);
27
43
  }
28
44
  }
29
- return result;
45
+ return Object.fromEntries(messages);
30
46
  }
31
47
  /**
32
48
  * Gets error message for a specific field from a ValidationError.
33
- * Returns undefined if no error exists for that field.
49
+ * Returns undefined if no error exists for that field. Pass `""` for issues
50
+ * about the whole argument (an empty path), the key `mapValidationErrors`
51
+ * files them under.
34
52
  *
35
53
  * @example
36
54
  * ```tsx
@@ -41,12 +59,13 @@ export function mapValidationErrors(error, options) {
41
59
  * ```
42
60
  */
43
61
  export function getFieldError(error, fieldName) {
44
- const issue = error.issues.find((i) => String(i.path[0]) === fieldName);
62
+ const issue = error.issues.find((i) => fieldNameOf(i) === fieldName);
45
63
  return issue?.message;
46
64
  }
47
65
  /**
48
66
  * Gets all error messages for a specific field from a ValidationError.
49
- * Returns empty array if no errors exist for that field.
67
+ * Returns empty array if no errors exist for that field. Pass `""` for issues
68
+ * about the whole argument (an empty path).
50
69
  *
51
70
  * @example
52
71
  * ```tsx
@@ -58,7 +77,7 @@ export function getFieldError(error, fieldName) {
58
77
  */
59
78
  export function getFieldErrors(error, fieldName) {
60
79
  return error.issues
61
- .filter((i) => String(i.path[0]) === fieldName)
80
+ .filter((i) => fieldNameOf(i) === fieldName)
62
81
  .map((i) => i.message);
63
82
  }
64
83
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,eAAe,EACf,iBAAiB,GAElB,MAAM,kBAAkB,CAAA;AAEzB,4BAA4B;AAC5B,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,CAAA;AAyD7C,MAAM,UAAU,mBAAmB,CACjC,KAAsB,EACtB,OAAoC;IAEpC,IAAI,OAAO,EAAE,QAAQ,EAAE,CAAC;QACtB,MAAM,MAAM,GAAwB,EAAE,CAAA;QACtC,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;YAC7C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;gBACvB,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,CAAA;YACxB,CAAC;YACD,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACvC,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED,MAAM,MAAM,GAAgB,EAAE,CAAA;IAC9B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QAC7C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,OAAO,CAAA;QACnC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAsB,EACtB,SAAiB;IAEjB,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAA;IACvE,OAAO,KAAK,EAAE,OAAO,CAAA;AACvB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAsB,EACtB,SAAiB;IAEjB,OAAO,KAAK,CAAC,MAAM;SAChB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;SAC9C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;AAC1B,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAA;IACnC,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,qBAAqB,CACnC,cAA6C,EAC7C,YAAqC;IAErC,OAAO,CAAC,KAAY,EAAE,EAAE;QACtB,MAAM,WAAW,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAA;QAClD,IAAI,WAAW,EAAE,CAAC;YAChB,cAAc,CAAC,WAAW,CAAC,CAAA;QAC7B,CAAC;aAAM,IAAI,YAAY,EAAE,CAAC;YACxB,YAAY,CAAC,KAAK,CAAC,CAAA;QACrB,CAAC;IACH,CAAC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
package/llms.txt CHANGED
@@ -1,54 +1,280 @@
1
- # @ic-reactor/react — AI Quick Guide
1
+ # @ic-reactor/react
2
2
 
3
- Use this file when your app installs `@ic-reactor/react` and you need fast,
4
- accurate integration guidance.
3
+ > React hooks, reusable query/mutation objects and Internet Identity sign-in
4
+ > for Internet Computer canisters, on TanStack Query. Re-exports all of
5
+ > `@ic-reactor/core`.
6
+
7
+ Applies to `@ic-reactor/react` 3.13.0.
8
+
9
+ Read this file from `node_modules/@ic-reactor/react/llms.txt` when writing
10
+ code against the installed version. The complete guide for every package is
11
+ https://ic-reactor.b3pay.net/llms-full.txt, and behaviour changes are in
12
+ https://github.com/B3Pay/ic-reactor/blob/main/CHANGELOG.md.
5
13
 
6
14
  ## Install
7
15
 
8
16
  ```bash
9
17
  pnpm add @ic-reactor/react @icp-sdk/core @tanstack/react-query
10
- pnpm add @icp-sdk/auth@^8 # optional auth helpers; v8 only, v7 is not supported
18
+ pnpm add @icp-sdk/auth@^10 # optional: Internet Identity sign-in
19
+ ```
20
+
21
+ Needs `@tanstack/react-query` 5.90.2 or later, React 18 or later and
22
+ TypeScript 5.7 or later. Import the runtime (`ClientManager`, `Reactor`,
23
+ `DisplayReactor`, errors, token helpers) from `@ic-reactor/react` as well; do
24
+ not add `@ic-reactor/core` beside it. `@icp-sdk/auth` v10 is recommended and
25
+ v8 still works; on npm, v8 needs
26
+ `{"overrides":{"@icp-sdk/auth":{"@icp-sdk/core":"$@icp-sdk/core"}}}` in
27
+ `package.json`. v7 and v9 are not supported.
28
+
29
+ ## Setup and Usage
30
+
31
+ ```tsx
32
+ // src/reactor.tsx
33
+ import { defineReactor, isCanisterError, skipToken } from "@ic-reactor/react"
34
+ import { canisterId, idlFactory, type _SERVICE } from "./declarations/backend"
35
+
36
+ export const {
37
+ reactor: backend,
38
+ useActorQuery,
39
+ useActorMutation,
40
+ useAuth,
41
+ } = defineReactor<_SERVICE>({ name: "backend", idlFactory, canisterId })
42
+
43
+ export function Profile({ userId }: { userId?: string }) {
44
+ const profile = useActorQuery({
45
+ functionName: "get_profile",
46
+ args: userId ? [userId] : skipToken, // no call until the id exists
47
+ })
48
+ const rename = useActorMutation({
49
+ functionName: "update_profile",
50
+ invalidateQueries: [{ functionName: "get_profile" }], // refetched first
51
+ onCanisterError: (err) => console.warn("Refused:", err.code), // Err variant
52
+ })
53
+
54
+ if (!userId) return <p>Sign in first</p>
55
+ if (profile.isPending) return <p>Loading…</p>
56
+ if (profile.error) {
57
+ const { error } = profile
58
+ return <p>{isCanisterError(error) ? error.code : error.message}</p>
59
+ }
60
+ return (
61
+ <button
62
+ disabled={rename.isPending}
63
+ onClick={() => rename.mutate([{ name: "Ada" }])}
64
+ >
65
+ {profile.data.name}: {profile.data.likes.toString()} likes
66
+ </button>
67
+ )
68
+ }
69
+ ```
70
+
71
+ `defineReactor` builds the `QueryClient` (query retry `reactorRetry`), the
72
+ `ClientManager`, a `Reactor` with raw Candid values (`bigint`, `Principal`),
73
+ the six hooks of `createActorHooks`, and `useAuth`, `useAgentState`,
74
+ `useUserPrincipal`, `useIdentityAttributes`, `authentication`,
75
+ `identityAttributes`. `defineDisplayReactor` takes the same options and gives
76
+ display values instead (strings for `bigint` and `Principal`, hex for blobs,
77
+ `T | undefined` for `opt`, `{ _type: "A", A: value }` for a variant, and just
78
+ `{ _type: "A" }` for a case without a value). `canisterId` is required except
79
+ on a local replica whose `ic_env` cookie names it. `./declarations/backend`
80
+ stands for your canister's declarations: `idlFactory` from the generated
81
+ `.js`, `_SERVICE` from the `.d.ts` (with the CLI or the Vite plugin,
82
+ `src/declarations/<name>/declarations/<did>.js` and `.d.ts`, named after the
83
+ `.did` file), and `canisterId` your canister's id as text.
84
+
85
+ ## When to Use What
86
+
87
+ | Need | Use |
88
+ | --------------------------------------------- | --------------------------------------------------------------------------------- |
89
+ | Client-only app, raw Candid values | `defineReactor(...)` at module scope |
90
+ | Client-only app, values for forms and display | `defineDisplayReactor(...)` at module scope |
91
+ | A reactor you built yourself | `createActorHooks(reactor)` |
92
+ | Server-rendered app (Next.js, any SSR) | `createReactorProvider(() => defineReactor(...))` in a `"use client"` module |
93
+ | React Server Component, server action, route | `ClientManager` + `Reactor` from this package, built in the request; `fetchQuery` |
94
+ | One call used in components and loaders | `createQuery`, `createQueryFactory` (args later), `createMutation` |
95
+ | Suspense | `useActorSuspenseQuery`, `createSuspenseQuery`, `createSuspenseQueryFactory` |
96
+ | Paginated reads | `useActorInfiniteQuery`, `createInfiniteQuery`, `createInfiniteQueryFactory` |
97
+ | One hook for a query or update with `call()` | `useActorMethod` |
98
+ | Another canister with the same interface | `reactor.forCanister(canisterId)`, or `callConfig: { canisterId }` for one query |
99
+ | A second canister on the same sign-in | `defineReactor({ ..., authentication: firstApp.authentication })` |
100
+ | Sign-in with a manual setup | `createAuthHooks(new AuthenticationManager({ clientManager }))` |
101
+ | Tests | `installFakeReplica` + `createTestCanister` from `@ic-reactor/react/testing` |
102
+
103
+ ## Inside React vs Outside React
104
+
105
+ - In components and custom hooks: `useActorQuery`, `useActorMutation`,
106
+ `useActorMethod`, `useAuth`, `.useQuery()`, `.useMutation()`,
107
+ `.useSuspenseQuery()`, `.useInfiniteQuery()`.
108
+ - In loaders, actions, services, scripts and non-hook tests: query objects'
109
+ `.fetch()`, `.prefetch()`, `.invalidate()`, `.getCacheData()`,
110
+ `.setData()`, `.cancel()`, `.reset()`, `.optimisticUpdate()`; mutation
111
+ objects' `.execute(args)`; and the reactor's `.fetchQuery()`,
112
+ `.getQueryData()`, `.invalidateQueries()`, `.callMethod()`.
113
+ - `.fetch()` and `reactor.fetchQuery()` fetch again as the new principal when a
114
+ sign-in or sign-out lands mid-fetch; they never reject with TanStack's
115
+ `CancelledError`. `.prefetch()` fetches again the same way and never
116
+ rejects, and a query method's `call()` / `refetch()` from `useActorMethod`
117
+ resolve with the new principal's answer (`undefined` if that fetch fails).
118
+ Wrap your own `queryClient.fetchQuery` or
119
+ `fetchInfiniteQuery` of a canister query in
120
+ `clientManager.fetchAcrossIdentitySwitch(() => ...)`.
121
+
122
+ ```ts
123
+ import { createMutation, createQueryFactory } from "@ic-reactor/react"
124
+ import { backend } from "./reactor"
125
+
126
+ export const getPost = createQueryFactory(backend, { functionName: "get_post" })
127
+ export const likePost = createMutation(backend, {
128
+ functionName: "like_post",
129
+ invalidateQueries: [getPost], // every cached post, whatever its args
130
+ })
131
+
132
+ // In a component: getPost([id]).useQuery(), likePost.useMutation()
133
+ // In a loader: await getPost([id]).fetch()
134
+ // In an action: await likePost.execute([id])
11
135
  ```
12
136
 
13
- npm cannot resolve this set on its own: every published `@icp-sdk/auth` still
14
- peers `@icp-sdk/core@^5` while this package needs `^6`, so a strict
15
- `npm install` fails with `ERESOLVE`. Add
16
- `{"overrides":{"@icp-sdk/auth":{"@icp-sdk/core":"$@icp-sdk/core"}}}` to
17
- `package.json`. pnpm and yarn do not need it.
137
+ ## Server Rendering
138
+
139
+ A reactor owns its `QueryClient` and query keys carry no caller principal, so
140
+ a module-scope reactor on a server is one cache shared by every request. In a
141
+ server-rendered app, build reactors per mounted provider:
142
+
143
+ ```tsx
144
+ "use client"
145
+ import { createReactorProvider, defineReactor } from "@ic-reactor/react"
146
+ import { canisterId, idlFactory, type _SERVICE } from "./declarations/backend"
147
+
148
+ export const { ReactorProvider, useReactor } = createReactorProvider(() =>
149
+ defineReactor<_SERVICE>({ name: "backend", idlFactory, canisterId })
150
+ )
151
+ // layout: <ReactorProvider>{children}</ReactorProvider>
152
+ // component: const { useActorQuery, useAuth } = useReactor()
153
+ ```
18
154
 
19
- ## Start Here
155
+ - The factory runs once per mounted provider (once per request on a server).
156
+ It may return a record (`useReactor("ledger")`) and query/mutation objects
157
+ built inside it. `useReactor()` is typed as the factory's return: never write
158
+ `as any` hook forwarders or a hand-rolled context provider.
159
+ - On unmount it disposes the `AuthenticationManager`s built for its value.
160
+ When the value holds exactly one `QueryClient` (its reactors share one
161
+ `ClientManager`), it renders a `QueryClientProvider` for it
162
+ (`{ queryClientProvider: false }` to keep your own).
163
+ - Props other than `children` go to the factory, read once per mount; change
164
+ the provider's `key` to rebuild. A provider mounted by a transition needs a
165
+ `<Suspense>` boundary inside it around suspending components.
166
+ - A React Server Component, server action or route handler may import
167
+ `Reactor`, `DisplayReactor`, `ClientManager` and the rest of the core runtime
168
+ from `@ic-reactor/react`: its `react-server` export condition resolves to an
169
+ entry without React. Hooks, `defineReactor`, `defineDisplayReactor`,
170
+ `createActorHooks`, `createReactorProvider`, the query/mutation factories,
171
+ `skipToken` and the auth classes are missing exports there.
20
172
 
21
- - Fastest setup: `defineReactor(...)`
22
- - Existing reactor instance: `createActorHooks(reactor)`
23
- - Reusable shared operations: `createQuery(...)`, `createMutation(...)`
173
+ ## Queries
24
174
 
25
- ## Inside React vs Outside React (critical)
175
+ - `skipToken` in place of args waits without calling the canister:
176
+ `args: owner ? [account] : skipToken` in `useActorQuery`,
177
+ `getArgs: owner ? (page) => [...] : skipToken` in `useActorInfiniteQuery`,
178
+ `getBalance(owner ? [account] : skipToken).useQuery()` with
179
+ `createQueryFactory` (that skipped object has only `useQuery()`). The
180
+ suspense hooks, `createQuery` and `createSuspenseQuery` do not take it.
181
+ - Paginated reads: `createInfiniteQuery` (or `useActorInfiniteQuery`) takes
182
+ `functionName`, `initialPageParam`, `getNextPageParam` and
183
+ `getArgs: (page) => [...] as const`. Keep `as const`: without it
184
+ `createInfiniteQuery` infers an array rather than the argument tuple and
185
+ rejects it.
186
+ - A `Result` is unwrapped: `data` is the `Ok` payload and an `Err` arrives as a
187
+ `CanisterError` in `error`.
188
+ - Query hooks and objects take TanStack's options (`select`, `staleTime`,
189
+ `enabled`, ...) and `callConfig` (`canisterId`, `agent`,
190
+ `effectiveCanisterId`).
191
+ - Several tokens of one interface: `reactor.forCanister(canisterId)` returns a
192
+ memoized sibling reactor on the same `ClientManager`. Build hooks on it with
193
+ `useMemo(() => createActorHooks(ledger.forCanister(id)), [id])`.
194
+ - Types: `ReactorArgsOf<typeof reactor, "method">[0]`,
195
+ `ReactorDataOf<typeof reactor, "method">`,
196
+ `ReactorErrorOf<typeof reactor, "method">`.
26
197
 
27
- - Inside React components/custom hooks: `useActorQuery`, `useActorMutation`,
28
- `useActorMethod`, `.useQuery()`, `.useMutation()`
29
- - Outside React (loaders/actions/services/tests): `.fetch()`, `.prefetch()`,
30
- `.invalidate()`, `.getCacheData()`, `.execute(args)`
198
+ ## Mutations, Invalidation and Retries
31
199
 
32
- Never call React hooks in loaders, actions, route modules, scripts, or tests.
200
+ - Call state-changing update methods only through `useActorMutation`,
201
+ `useActorMethod` or `createMutation`. A query runs its method again on every
202
+ refetch, and each run of an update executes on the canister.
203
+ - `invalidateQueries` takes query objects, query factories (every args
204
+ instance) and `{ functionName, args? }` methods of the mutation's reactor,
205
+ keyed at the canister the mutation was sent to. It is awaited before
206
+ `onSuccess`. Every key starts with the canister id, so a hand-written
207
+ `["get_posts"]` matches nothing.
208
+ - `onCanisterError` receives the `CanisterError` of an `Err` result
209
+ (`err.code`, `err.err`); `onError` receives every error.
210
+ - Mutations retry nothing unless `retry` is set, on them or as the
211
+ `QueryClient`'s `mutations.retry` default (which reaches `execute()` and
212
+ `useActorMethod` update calls too). Use `retry: reactorUpdateRetry`, which
213
+ retries only a `SysTransient` rejection, never a number.
214
+ - Optimistic UI: return `query.optimisticUpdate(updater)` from `onMutate`,
215
+ call `update?.rollback()` in `onError`, and `invalidate()` in `onSettled`.
216
+ When you need the `QueryClient`, use `reactor.queryClient`:
217
+ `useQueryClient()` throws without a `QueryClientProvider`.
33
218
 
34
- ## Display vs Raw Values
219
+ ## Sign-In
35
220
 
36
- - Prefer `display: true` in `defineReactor(...)` (or `DisplayReactor`) for
37
- UI/form code.
38
- - Use raw `Reactor` when you intentionally need native `bigint`/`Principal`.
221
+ - `useAuth()` gives `login`, `logout`, `isAuthenticated`,
222
+ `isAuthenticating`, `principal`, `identity` and `error`. It reports
223
+ `isAuthenticating: true` until the first session restore settles, and in
224
+ every server render: check it before redirecting on `!isAuthenticated`.
225
+ - `createAuthHooks` takes an `AuthenticationManager`, never a `ClientManager`,
226
+ and returns `useAuth`, `useAgentState` and `useUserPrincipal`.
227
+ `useIdentityAttributes` comes from `createIdentityAttributeHooks`.
228
+ - Pass an identity-attribute nonce as a callback (`nonce: async () => ...`),
229
+ not an awaited value, so the popup opens within the click.
230
+ - `authentication.dispose()` releases the auth client the manager built,
231
+ without signing out.
39
232
 
40
- ## Mutation Error Handling
233
+ ## Testing
41
234
 
42
- For canister `Result.Err` variants, use `onCanisterError`. Keep `onError` for
43
- network/agent and unexpected errors.
235
+ Run the real reactor and hooks against `installFakeReplica` and
236
+ `createTestCanister` from `@ic-reactor/react/testing`. Install the fake before
237
+ any `ClientManager` is built: for a module-scope `defineReactor`, at the top of
238
+ the test file, then `await import(...)` the components. Generated code is
239
+ module scope too: import `idlFactory` and `_SERVICE` from the canister's
240
+ `declarations/` folder, key the fake by the `canisterId` the generator wrote,
241
+ and `await import(...)` the entry after the fake. A handler returns
242
+ `{ Err: ... }` for a `CanisterError` and throws for a `CallError`. Reset a
243
+ shared reactor with `queryClient.clear()`, and test a signed-in user with
244
+ `clientManager.updateAgent(identity)`.
44
245
 
45
- ## Generated Files
246
+ ## Do Not
46
247
 
47
- Do not hand-edit generated `index.generated.ts` files. Put app-specific code in
48
- `index.ts` wrappers or separate factory modules.
248
+ - Call hooks outside components and custom hooks, or create hooks with
249
+ `createActorHooks` / `createAuthHooks` on every render.
250
+ - Put a state-changing update method in `useActorQuery`, `createQuery` or
251
+ `createQueryFactory`.
252
+ - Give an update mutation a numeric `retry`; use `reactorUpdateRetry`.
253
+ - Hand-write query keys, or add the canister id to a `queryKey`.
254
+ - Write `args: [userId!]`, a placeholder account, or `as any` plus `enabled`;
255
+ pass `skipToken`.
256
+ - Check `"Ok" in data`; the `Result` is already unwrapped.
257
+ - Use `Number(x) / 10 ** decimals`; use `formatTokenAmount` and
258
+ `parseTokenAmount`.
259
+ - Retarget a shared reactor with `setCanisterId`; use `forCanister`.
260
+ - Write `defineReactor({ display: true })`; use `defineDisplayReactor`.
261
+ - Build reactors or managers at module scope in a server-rendered app, or
262
+ import hooks into a server component.
263
+ - Stub a reactor with `as unknown as Reactor` in tests.
264
+ - Edit `index.generated.ts` or `index.factories.generated.ts`.
49
265
 
50
- ## Full References
266
+ ## Docs
51
267
 
52
- - Full AI guide: https://ic-reactor.b3pay.net/llms-full.txt
53
- - React package docs: https://ic-reactor.b3pay.net/v3/packages/react
54
- - Skill install: `npx skills add B3Pay/ic-reactor-skills --full-depth --skill ic-reactor-hooks`
268
+ - React package: https://ic-reactor.b3pay.net/v3/packages/react.md
269
+ - React setup: https://ic-reactor.b3pay.net/v3/framework/react-setup.md
270
+ - Queries: https://ic-reactor.b3pay.net/v3/framework/queries.md
271
+ - Mutations: https://ic-reactor.b3pay.net/v3/framework/mutations.md
272
+ - Query caching: https://ic-reactor.b3pay.net/v3/framework/query-caching.md
273
+ - Query and mutation factories: https://ic-reactor.b3pay.net/v3/reference/factories/overview.md
274
+ - createReactorProvider: https://ic-reactor.b3pay.net/v3/reference/createReactorProvider.md
275
+ - Authentication: https://ic-reactor.b3pay.net/v3/guides/authentication.md
276
+ - Error handling: https://ic-reactor.b3pay.net/v3/guides/error-handling.md
277
+ - Testing: https://ic-reactor.b3pay.net/v3/guides/testing.md
278
+ - Index of all docs: https://ic-reactor.b3pay.net/llms.txt
279
+ - Full guide: https://ic-reactor.b3pay.net/llms-full.txt
280
+ - Agent skill for Claude Code and other agents: https://github.com/B3Pay/ic-reactor/tree/main/skill-packages/ic-reactor
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ic-reactor/react",
3
- "version": "3.12.5",
3
+ "version": "3.13.0",
4
4
  "description": "IC Reactor React library for building Internet Computer apps",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -13,9 +13,15 @@
13
13
  "exports": {
14
14
  ".": {
15
15
  "types": "./dist/index.d.ts",
16
+ "react-server": "./dist/server.js",
16
17
  "import": "./dist/index.js",
17
18
  "default": "./dist/index.js"
18
19
  },
20
+ "./testing": {
21
+ "types": "./dist/testing.d.ts",
22
+ "import": "./dist/testing.js",
23
+ "default": "./dist/testing.js"
24
+ },
19
25
  "./package.json": "./package.json"
20
26
  },
21
27
  "files": [
@@ -53,18 +59,21 @@
53
59
  "author": "Behrad Deylami",
54
60
  "license": "MIT",
55
61
  "dependencies": {
56
- "@ic-reactor/core": "^3.12.5"
62
+ "@ic-reactor/core": "^3.13.0"
57
63
  },
58
64
  "peerDependencies": {
59
- "@icp-sdk/auth": "^8.0.0",
65
+ "@icp-sdk/auth": "^8.0.0 || ^10.0.0",
60
66
  "@icp-sdk/core": "^6.1.0",
61
- "@tanstack/react-query": "^5.0.0",
67
+ "@noble/curves": "^2.2.0",
68
+ "@tanstack/react-query": "^5.90.2",
62
69
  "react": ">=18.0.0",
63
70
  "react-dom": ">=18.0.0"
64
71
  },
65
72
  "devDependencies": {
66
- "@icp-sdk/auth": "^8.0.3",
73
+ "@icp-sdk/auth": "^10.0.0",
74
+ "@icp-sdk/auth-v8": "npm:@icp-sdk/auth@^8.0.3",
67
75
  "@icp-sdk/core": "^6.1.0",
76
+ "@noble/curves": "^2.2.0",
68
77
  "@size-limit/preset-small-lib": "^13.0.3",
69
78
  "@tanstack/react-query": "^5.102.8",
70
79
  "@testing-library/dom": "^10.4.1",
@@ -98,6 +107,9 @@
98
107
  "@icp-sdk/auth": {
99
108
  "optional": true
100
109
  },
110
+ "@noble/curves": {
111
+ "optional": true
112
+ },
101
113
  "react-dom": {
102
114
  "optional": true
103
115
  }