@ic-reactor/mcp 0.0.0-stage → 0.0.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 (1041) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.yml +108 -0
  2. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.yml +77 -0
  4. package/.github/actions/setup-rust-wasm/action.yml +25 -0
  5. package/.github/dependabot.yml +107 -0
  6. package/.github/workflows/auth-latest.yml +67 -0
  7. package/.github/workflows/b3pay-site.yml +49 -0
  8. package/.github/workflows/ci.yml +430 -0
  9. package/.github/workflows/codeql.yml +41 -0
  10. package/.github/workflows/dependency-review.yml +68 -0
  11. package/.github/workflows/docs-check.yml +98 -0
  12. package/.github/workflows/docs.yml +265 -0
  13. package/.github/workflows/e2e.yml +90 -0
  14. package/.github/workflows/examples-published.yml +97 -0
  15. package/.github/workflows/release.yml +326 -0
  16. package/.husky/pre-commit +12 -0
  17. package/.prettierignore +109 -0
  18. package/.prettierrc +6 -0
  19. package/AGENTS.md +103 -0
  20. package/CHANGELOG.md +3268 -0
  21. package/CLAUDE.md +93 -0
  22. package/CNAME +1 -0
  23. package/CODE_OF_CONDUCT.md +7 -0
  24. package/CONTRIBUTING.md +433 -0
  25. package/LICENSE +21 -0
  26. package/README.md +2 -2
  27. package/SECURITY.md +74 -0
  28. package/b3pay-module.json +194 -0
  29. package/docs/.remarkrc.json +10 -0
  30. package/docs/README.md +64 -0
  31. package/docs/astro.config.mjs +205 -0
  32. package/docs/favicon.svg +15 -0
  33. package/docs/package.json +39 -0
  34. package/docs/public/favicon.svg +15 -0
  35. package/docs/public/ic-reactor-social-card.png +0 -0
  36. package/docs/scripts/b3pay-static.mjs +22 -0
  37. package/docs/scripts/check-example-docs.mjs +214 -0
  38. package/docs/scripts/check-links.mjs +212 -0
  39. package/docs/scripts/fix-dist-links.js +125 -0
  40. package/docs/scripts/fix-frontmatter.js +71 -0
  41. package/docs/scripts/remove-redundant-h1.cjs +48 -0
  42. package/docs/scripts/rewrite-typedoc-links.js +110 -0
  43. package/docs/scripts/split-index.js +69 -0
  44. package/docs/src/assets/ic-reactor-hero-dark.svg +23 -0
  45. package/docs/src/assets/ic-reactor-hero-light.svg +23 -0
  46. package/docs/src/assets/ic-reactor-lockup-dark.svg +15 -0
  47. package/docs/src/assets/ic-reactor-lockup-light.svg +15 -0
  48. package/docs/src/assets/ic-reactor-mark-dark.svg +14 -0
  49. package/docs/src/assets/ic-reactor-mark-light.svg +14 -0
  50. package/docs/src/assets/layers/candid-core-layer-icon-dark.svg +4 -0
  51. package/docs/src/assets/layers/candid-core-layer-icon-light.svg +4 -0
  52. package/docs/src/assets/layers/candid-profile-layer-icon-dark.svg +4 -0
  53. package/docs/src/assets/layers/candid-profile-layer-icon-light.svg +4 -0
  54. package/docs/src/assets/layers/ic-reactor-layer-icon-dark.svg +4 -0
  55. package/docs/src/assets/layers/ic-reactor-layer-icon-light.svg +4 -0
  56. package/docs/src/components/LibraryCards.astro +172 -0
  57. package/docs/src/components/LibraryIcon.astro +28 -0
  58. package/docs/src/components/SiteTitle.astro +241 -0
  59. package/docs/src/content/docs/404.mdx +19 -0
  60. package/docs/src/content/docs/build/agent-tools.mdx +593 -0
  61. package/docs/src/content/docs/build/icrc1-wallet.mdx +619 -0
  62. package/docs/src/content/docs/build/ssr-per-user.mdx +552 -0
  63. package/docs/src/content/docs/examples/canister-studio.mdx +95 -0
  64. package/docs/src/content/docs/examples/icrc-ledger.mdx +45 -0
  65. package/docs/src/content/docs/examples/index.mdx +38 -0
  66. package/docs/src/content/docs/examples/next-ssr.mdx +73 -0
  67. package/docs/src/content/docs/examples/node-agent-tool.mdx +80 -0
  68. package/docs/src/content/docs/examples/vite-wallet.mdx +71 -0
  69. package/docs/src/content/docs/guides/auth.mdx +1181 -0
  70. package/docs/src/content/docs/guides/client.mdx +551 -0
  71. package/docs/src/content/docs/guides/deploy.mdx +180 -0
  72. package/docs/src/content/docs/guides/errors.mdx +475 -0
  73. package/docs/src/content/docs/guides/getting-started.mdx +620 -0
  74. package/docs/src/content/docs/guides/reads.mdx +586 -0
  75. package/docs/src/content/docs/guides/ssr.mdx +529 -0
  76. package/docs/src/content/docs/guides/testing.mdx +401 -0
  77. package/docs/src/content/docs/guides/values.mdx +261 -0
  78. package/docs/src/content/docs/guides/vite-plugin.mdx +690 -0
  79. package/docs/src/content/docs/guides/writes.mdx +572 -0
  80. package/docs/src/content/docs/ic-reactor/index.mdx +167 -0
  81. package/docs/src/content/docs/index.mdx +65 -0
  82. package/docs/src/content/docs/migrating-from-3.mdx +535 -0
  83. package/docs/src/content/docs/packages/core.mdx +186 -0
  84. package/docs/src/content/docs/packages/mcp.mdx +163 -0
  85. package/docs/src/content/docs/packages/react.mdx +207 -0
  86. package/docs/src/content/docs/packages/vite-plugin.mdx +73 -0
  87. package/docs/src/content/docs/versioning.mdx +104 -0
  88. package/docs/src/content.config.ts +7 -0
  89. package/docs/src/styles/custom.css +189 -0
  90. package/docs/tsconfig.typedoc.json +26 -0
  91. package/docs/typedoc-entry.ts +17 -0
  92. package/docs/typedoc.json +37 -0
  93. package/e2e/Cargo.lock +646 -0
  94. package/e2e/Cargo.toml +3 -0
  95. package/e2e/README.md +101 -0
  96. package/e2e/frontends/build.mjs +94 -0
  97. package/e2e/frontends/index.html +10 -0
  98. package/e2e/global-setup.ts +65 -0
  99. package/e2e/icp.yaml +38 -0
  100. package/e2e/package.json +40 -0
  101. package/e2e/setup.ts +6 -0
  102. package/e2e/src/actor/Cargo.toml +14 -0
  103. package/e2e/src/actor/hello_actor.did +10 -0
  104. package/e2e/src/actor/src/lib.rs +73 -0
  105. package/e2e/src/calls.test.ts +132 -0
  106. package/e2e/src/declarations/hello_actor.envelope.json +175 -0
  107. package/e2e/src/declarations/hello_actor.ts +15 -0
  108. package/e2e/src/errors.test.ts +107 -0
  109. package/e2e/src/frontend-headers.test.ts +253 -0
  110. package/e2e/src/identity.test.ts +61 -0
  111. package/e2e/src/react.test.tsx +59 -0
  112. package/e2e/src/replica.ts +70 -0
  113. package/e2e/src/vite-env.test.ts +108 -0
  114. package/e2e/test.sh +47 -0
  115. package/e2e/tsconfig.json +20 -0
  116. package/e2e/tsconfig.typecheck.json +9 -0
  117. package/e2e/vitest.config.ts +22 -0
  118. package/eslint.config.mjs +100 -0
  119. package/evals/PREREGISTRATION.md +1346 -0
  120. package/evals/README.md +756 -0
  121. package/evals/conditions/thin/condition.json +8 -0
  122. package/evals/conditions/thin/docs/candid-core-cli.README.md +90 -0
  123. package/evals/conditions/thin/docs/candid-core-schema.README.md +339 -0
  124. package/evals/conditions/thin/package.json +25 -0
  125. package/evals/conditions/thin/starter/src/generated/icrc1.ts +57 -0
  126. package/evals/conditions/thin-guide/condition.json +10 -0
  127. package/evals/conditions/thin-guide/docs/llms.txt +292 -0
  128. package/evals/conditions/v3/condition.json +9 -0
  129. package/evals/conditions/v3/docs/ic-reactor-core.llms.txt +232 -0
  130. package/evals/conditions/v3/docs/ic-reactor-react.llms.txt +280 -0
  131. package/evals/conditions/v3/docs/llms-full.txt +1053 -0
  132. package/evals/conditions/v3/package.json +26 -0
  133. package/evals/conditions/v3/starter/src/declarations/icrc1.did.d.ts +95 -0
  134. package/evals/conditions/v3/starter/src/declarations/icrc1.did.js +140 -0
  135. package/evals/conditions/v4/PORTING.md +384 -0
  136. package/evals/conditions/v4/README.md +106 -0
  137. package/evals/conditions/v4/condition.json +5 -0
  138. package/evals/conditions/v4/docs/llms.txt +323 -0
  139. package/evals/conditions/v4/package.json +27 -0
  140. package/evals/conditions/v4/starter/src/generated/icrc1.ts +78 -0
  141. package/evals/conditions/v4-proto/condition.json +6 -0
  142. package/evals/conditions/v4-proto/docs/llms.txt +291 -0
  143. package/evals/conditions/v4-proto/lib/SHIM-NOTES.md +20 -0
  144. package/evals/conditions/v4-proto/lib/package.json +27 -0
  145. package/evals/conditions/v4-proto/lib/src/client.ts +471 -0
  146. package/evals/conditions/v4-proto/lib/src/errors.ts +214 -0
  147. package/evals/conditions/v4-proto/lib/src/index.ts +36 -0
  148. package/evals/conditions/v4-proto/lib/src/principal.ts +175 -0
  149. package/evals/conditions/v4-proto/lib/src/service.ts +69 -0
  150. package/evals/conditions/v4-proto/lib/src/types.ts +174 -0
  151. package/evals/conditions/v4-proto/lib/test/runtime.test.ts +170 -0
  152. package/evals/conditions/v4-proto/lib/test/tsconfig.json +10 -0
  153. package/evals/conditions/v4-proto/lib/test/types.test-d.ts +145 -0
  154. package/evals/conditions/v4-proto/lib/test/vitest.config.mjs +8 -0
  155. package/evals/conditions/v4-proto/lib/tsconfig.json +17 -0
  156. package/evals/conditions/v4-proto/package.json +26 -0
  157. package/evals/conditions/v4-proto/starter/src/generated/icrc1.service.ts +19 -0
  158. package/evals/conditions/v4-proto/starter/src/generated/icrc1.ts +57 -0
  159. package/evals/drive.mjs +1221 -0
  160. package/evals/gate.mjs +161 -0
  161. package/evals/harness/aggregate.mjs +534 -0
  162. package/evals/harness/aggregate.test.mjs +344 -0
  163. package/evals/harness/assemble.mjs +216 -0
  164. package/evals/harness/assemble.test.mjs +143 -0
  165. package/evals/harness/auth.mjs +91 -0
  166. package/evals/harness/check-docs.mjs +157 -0
  167. package/evals/harness/declarations/icrc1.did.d.ts +95 -0
  168. package/evals/harness/declarations/icrc1.did.js +140 -0
  169. package/evals/harness/drive-auth.test.mjs +584 -0
  170. package/evals/harness/drive.test.mjs +509 -0
  171. package/evals/harness/fake-auth.ts +67 -0
  172. package/evals/harness/fake-ledger.ts +178 -0
  173. package/evals/harness/gate-plan.mjs +104 -0
  174. package/evals/harness/gate-plan.test.mjs +243 -0
  175. package/evals/harness/icrc1.did +88 -0
  176. package/evals/harness/judge.mjs +63 -0
  177. package/evals/harness/judge.test.mjs +81 -0
  178. package/evals/harness/leak-scan.mjs +1373 -0
  179. package/evals/harness/leak-scan.test.mjs +1300 -0
  180. package/evals/harness/probes/amounts.ts +14 -0
  181. package/evals/harness/probes/node-tool.probe.ts +48 -0
  182. package/evals/harness/probes/probe.mjs +149 -0
  183. package/evals/harness/probes/react-wallet.probe.ts +96 -0
  184. package/evals/harness/public/support/auth.ts +38 -0
  185. package/evals/harness/public/support/fake-replica.d.ts +28 -0
  186. package/evals/harness/public/support/fake-replica.js +434 -0
  187. package/evals/harness/public/support/ledger.idl.d.ts +95 -0
  188. package/evals/harness/public/support/ledger.idl.js +140 -0
  189. package/evals/harness/public/support/world.ts +179 -0
  190. package/evals/harness/runs.mjs +139 -0
  191. package/evals/harness/sandbox.mjs +88 -0
  192. package/evals/harness/sandbox.test.mjs +134 -0
  193. package/evals/harness/ship.mjs +264 -0
  194. package/evals/harness/ship.test.mjs +552 -0
  195. package/evals/harness/world.ts +291 -0
  196. package/evals/package.json +26 -0
  197. package/evals/pnpm-lock.yaml +1537 -0
  198. package/evals/pnpm-workspace.yaml +12 -0
  199. package/evals/results/2026-09-30T14-22-05-924Z/pilot.json +384 -0
  200. package/evals/results/2026-09-30T14-22-05-924Z/pilot.rescanned.json +404 -0
  201. package/evals/results/2026-09-30T14-22-05-924Z/pilot.rescanned.rescored.json +404 -0
  202. package/evals/results/2026-09-30T14-22-05-924Z/plan.json +240 -0
  203. package/evals/results/2026-09-30T14-22-05-924Z/summary.json +1800 -0
  204. package/evals/results/2026-09-30T14-22-05-924Z/summary.rescanned.json +1843 -0
  205. package/evals/results/2026-09-30T14-22-05-924Z/summary.rescanned.rescored.json +2100 -0
  206. package/evals/results/2026-09-30T15-48-23-343Z/pilot.json +404 -0
  207. package/evals/results/2026-09-30T15-48-23-343Z/pilot.rescored.json +404 -0
  208. package/evals/results/2026-09-30T15-48-23-343Z/plan.json +242 -0
  209. package/evals/results/2026-09-30T15-48-23-343Z/summary.json +1843 -0
  210. package/evals/results/2026-09-30T15-48-23-343Z/summary.rescored.json +2195 -0
  211. package/evals/results/2026-10-03-beta1-gate/pilot.json +162 -0
  212. package/evals/results/2026-10-03-beta1-gate/plan.json +141 -0
  213. package/evals/results/2026-10-03-beta1-gate/summary.json +983 -0
  214. package/evals/results/2026-10-05-ga-gate/contaminated-run.json +55 -0
  215. package/evals/results/2026-10-05-ga-gate/pilot.json +162 -0
  216. package/evals/results/2026-10-05-ga-gate/plan.json +457 -0
  217. package/evals/results/2026-10-05-ga-gate/summary.json +1037 -0
  218. package/evals/results/2026-10-05-ga-gate/summary.rescanned.json +1037 -0
  219. package/evals/results/README.md +31 -0
  220. package/evals/runs-pilot.log +150 -0
  221. package/evals/runs-pilot2.log +150 -0
  222. package/evals/score.mjs +256 -0
  223. package/evals/setup.mjs +547 -0
  224. package/evals/tasks/node-tool/faulty/thin-accepts-exponent/meta.json +5 -0
  225. package/evals/tasks/node-tool/faulty/thin-accepts-exponent/src/index.ts +121 -0
  226. package/evals/tasks/node-tool/faulty/thin-anonymous-transfer/meta.json +5 -0
  227. package/evals/tasks/node-tool/faulty/thin-anonymous-transfer/src/index.ts +116 -0
  228. package/evals/tasks/node-tool/faulty/thin-every-reject-may-have-executed/meta.json +9 -0
  229. package/evals/tasks/node-tool/faulty/thin-every-reject-may-have-executed/src/index.ts +118 -0
  230. package/evals/tasks/node-tool/faulty/thin-fetches-root-key-off-local/meta.json +5 -0
  231. package/evals/tasks/node-tool/faulty/thin-fetches-root-key-off-local/src/index.ts +118 -0
  232. package/evals/tasks/node-tool/faulty/thin-ignores-root-key/meta.json +5 -0
  233. package/evals/tasks/node-tool/faulty/thin-ignores-root-key/src/index.ts +117 -0
  234. package/evals/tasks/node-tool/faulty/thin-misclassifies-reject-codes/meta.json +9 -0
  235. package/evals/tasks/node-tool/faulty/thin-misclassifies-reject-codes/src/index.ts +119 -0
  236. package/evals/tasks/node-tool/faulty/thin-no-nat64-cap/meta.json +9 -0
  237. package/evals/tasks/node-tool/faulty/thin-no-nat64-cap/src/index.ts +118 -0
  238. package/evals/tasks/node-tool/faulty/thin-number-amount/meta.json +10 -0
  239. package/evals/tasks/node-tool/faulty/thin-number-amount/src/index.ts +117 -0
  240. package/evals/tasks/node-tool/faulty/thin-truncates-fraction-digits/meta.json +5 -0
  241. package/evals/tasks/node-tool/faulty/thin-truncates-fraction-digits/src/index.ts +120 -0
  242. package/evals/tasks/node-tool/faulty/thin-unvalidated-recipient/meta.json +5 -0
  243. package/evals/tasks/node-tool/faulty/thin-unvalidated-recipient/src/index.ts +118 -0
  244. package/evals/tasks/node-tool/faulty/v3-retry-call-errors/meta.json +11 -0
  245. package/evals/tasks/node-tool/faulty/v3-retry-call-errors/src/index.ts +149 -0
  246. package/evals/tasks/node-tool/faulty/v4-anonymous-identity-sent/meta.json +5 -0
  247. package/evals/tasks/node-tool/faulty/v4-anonymous-identity-sent/src/index.ts +71 -0
  248. package/evals/tasks/node-tool/faulty/v4-never-may-have-executed/meta.json +9 -0
  249. package/evals/tasks/node-tool/faulty/v4-never-may-have-executed/src/index.ts +84 -0
  250. package/evals/tasks/node-tool/faulty/v4-proto-never-may-have-executed/meta.json +9 -0
  251. package/evals/tasks/node-tool/faulty/v4-proto-never-may-have-executed/src/index.ts +72 -0
  252. package/evals/tasks/node-tool/faulty/v4-proto-refuses-nat64-max/meta.json +5 -0
  253. package/evals/tasks/node-tool/faulty/v4-proto-refuses-nat64-max/src/index.ts +72 -0
  254. package/evals/tasks/node-tool/faulty/v4-refuses-nat64-max/meta.json +5 -0
  255. package/evals/tasks/node-tool/faulty/v4-refuses-nat64-max/src/index.ts +84 -0
  256. package/evals/tasks/node-tool/hidden/node-tool.test.ts +312 -0
  257. package/evals/tasks/node-tool/prompt.md +55 -0
  258. package/evals/tasks/node-tool/prompt.minimal.md +30 -0
  259. package/evals/tasks/node-tool/solutions/thin/reference/src/index.ts +118 -0
  260. package/evals/tasks/node-tool/solutions/thin/reference-module-scope/src/index.ts +145 -0
  261. package/evals/tasks/node-tool/solutions/thin-guide/reference/src/index.ts +118 -0
  262. package/evals/tasks/node-tool/solutions/thin-guide/reference-module-scope/src/index.ts +145 -0
  263. package/evals/tasks/node-tool/solutions/v3/reference/src/index.ts +140 -0
  264. package/evals/tasks/node-tool/solutions/v3/reference-module-scope/src/index.ts +153 -0
  265. package/evals/tasks/node-tool/solutions/v4/reference/src/index.ts +84 -0
  266. package/evals/tasks/node-tool/solutions/v4/reference-module-scope/src/index.ts +105 -0
  267. package/evals/tasks/node-tool/solutions/v4-proto/reference/src/index.ts +72 -0
  268. package/evals/tasks/node-tool/solutions/v4-proto/reference-module-scope/src/index.ts +87 -0
  269. package/evals/tasks/node-tool/starter/src/contract.ts +31 -0
  270. package/evals/tasks/node-tool/starter/src/index.ts +7 -0
  271. package/evals/tasks/node-tool/starter/test/smoke.test.ts +22 -0
  272. package/evals/tasks/node-tool/starter/tsconfig.json +17 -0
  273. package/evals/tasks/node-tool/task.json +63 -0
  274. package/evals/tasks/react-wallet/faulty/thin-accepts-exponent/meta.json +5 -0
  275. package/evals/tasks/react-wallet/faulty/thin-accepts-exponent/src/Wallet.tsx +216 -0
  276. package/evals/tasks/react-wallet/faulty/thin-anonymous-transfer/meta.json +5 -0
  277. package/evals/tasks/react-wallet/faulty/thin-anonymous-transfer/src/Wallet.tsx +212 -0
  278. package/evals/tasks/react-wallet/faulty/thin-both-auth-buttons/meta.json +5 -0
  279. package/evals/tasks/react-wallet/faulty/thin-both-auth-buttons/src/Wallet.tsx +210 -0
  280. package/evals/tasks/react-wallet/faulty/thin-constant-balance-key/meta.json +8 -0
  281. package/evals/tasks/react-wallet/faulty/thin-constant-balance-key/src/Wallet.tsx +213 -0
  282. package/evals/tasks/react-wallet/faulty/thin-no-nat64-cap/meta.json +9 -0
  283. package/evals/tasks/react-wallet/faulty/thin-no-nat64-cap/src/Wallet.tsx +213 -0
  284. package/evals/tasks/react-wallet/faulty/thin-number-balance/meta.json +5 -0
  285. package/evals/tasks/react-wallet/faulty/thin-number-balance/src/Wallet.tsx +213 -0
  286. package/evals/tasks/react-wallet/faulty/thin-transfer-as-query/meta.json +5 -0
  287. package/evals/tasks/react-wallet/faulty/thin-transfer-as-query/src/Wallet.tsx +254 -0
  288. package/evals/tasks/react-wallet/faulty/thin-truncates-fraction-digits/meta.json +5 -0
  289. package/evals/tasks/react-wallet/faulty/thin-truncates-fraction-digits/src/Wallet.tsx +215 -0
  290. package/evals/tasks/react-wallet/faulty/thin-unguarded-balance-effect/meta.json +5 -0
  291. package/evals/tasks/react-wallet/faulty/thin-unguarded-balance-effect/src/Wallet.tsx +214 -0
  292. package/evals/tasks/react-wallet/faulty/v3-http-4xx-unknown/meta.json +5 -0
  293. package/evals/tasks/react-wallet/faulty/v3-http-4xx-unknown/src/Wallet.tsx +224 -0
  294. package/evals/tasks/react-wallet/faulty/v3-mutation-retry-3/meta.json +12 -0
  295. package/evals/tasks/react-wallet/faulty/v3-mutation-retry-3/src/Wallet.tsx +225 -0
  296. package/evals/tasks/react-wallet/faulty/v3-unknown-as-error/meta.json +11 -0
  297. package/evals/tasks/react-wallet/faulty/v3-unknown-as-error/src/Wallet.tsx +182 -0
  298. package/evals/tasks/react-wallet/faulty/v4-every-reject-unknown/meta.json +5 -0
  299. package/evals/tasks/react-wallet/faulty/v4-every-reject-unknown/src/Wallet.tsx +160 -0
  300. package/evals/tasks/react-wallet/faulty/v4-keep-previous-data/meta.json +5 -0
  301. package/evals/tasks/react-wallet/faulty/v4-keep-previous-data/src/Wallet.tsx +166 -0
  302. package/evals/tasks/react-wallet/faulty/v4-proto-every-reject-unknown/meta.json +5 -0
  303. package/evals/tasks/react-wallet/faulty/v4-proto-every-reject-unknown/src/Wallet.tsx +161 -0
  304. package/evals/tasks/react-wallet/faulty/v4-proto-keep-previous-data/meta.json +5 -0
  305. package/evals/tasks/react-wallet/faulty/v4-proto-keep-previous-data/src/Wallet.tsx +163 -0
  306. package/evals/tasks/react-wallet/faulty/v4-proto-retry-spread/meta.json +12 -0
  307. package/evals/tasks/react-wallet/faulty/v4-proto-retry-spread/src/Wallet.tsx +162 -0
  308. package/evals/tasks/react-wallet/faulty/v4-proto-status-not-idle/meta.json +5 -0
  309. package/evals/tasks/react-wallet/faulty/v4-proto-status-not-idle/src/Wallet.tsx +163 -0
  310. package/evals/tasks/react-wallet/faulty/v4-retry-spread/meta.json +12 -0
  311. package/evals/tasks/react-wallet/faulty/v4-retry-spread/src/Wallet.tsx +163 -0
  312. package/evals/tasks/react-wallet/faulty/v4-status-not-idle/meta.json +5 -0
  313. package/evals/tasks/react-wallet/faulty/v4-status-not-idle/src/Wallet.tsx +162 -0
  314. package/evals/tasks/react-wallet/hidden/react-wallet.test.ts +536 -0
  315. package/evals/tasks/react-wallet/prompt.md +88 -0
  316. package/evals/tasks/react-wallet/prompt.minimal.md +51 -0
  317. package/evals/tasks/react-wallet/solutions/thin/reference/src/Wallet.tsx +213 -0
  318. package/evals/tasks/react-wallet/solutions/thin/reference-module-scope/src/Wallet.tsx +227 -0
  319. package/evals/tasks/react-wallet/solutions/thin-guide/reference/src/Wallet.tsx +213 -0
  320. package/evals/tasks/react-wallet/solutions/thin-guide/reference-module-scope/src/Wallet.tsx +227 -0
  321. package/evals/tasks/react-wallet/solutions/v3/reference/src/Wallet.tsx +224 -0
  322. package/evals/tasks/react-wallet/solutions/v3/reference-module-scope/src/Wallet.tsx +230 -0
  323. package/evals/tasks/react-wallet/solutions/v4/reference/src/Wallet.tsx +160 -0
  324. package/evals/tasks/react-wallet/solutions/v4/reference-module-scope/src/Wallet.tsx +178 -0
  325. package/evals/tasks/react-wallet/solutions/v4-proto/reference/src/Wallet.tsx +161 -0
  326. package/evals/tasks/react-wallet/solutions/v4-proto/reference-module-scope/src/Wallet.tsx +161 -0
  327. package/evals/tasks/react-wallet/starter/src/Wallet.tsx +12 -0
  328. package/evals/tasks/react-wallet/starter/src/auth.ts +16 -0
  329. package/evals/tasks/react-wallet/starter/src/config.ts +14 -0
  330. package/evals/tasks/react-wallet/starter/src/ii-auth.ts +43 -0
  331. package/evals/tasks/react-wallet/starter/src/main.tsx +15 -0
  332. package/evals/tasks/react-wallet/starter/test/smoke.test.ts +34 -0
  333. package/evals/tasks/react-wallet/starter/tsconfig.json +18 -0
  334. package/evals/tasks/react-wallet/task.json +84 -0
  335. package/examples/canister-studio/.stackblitzrc +4 -0
  336. package/examples/canister-studio/README.md +183 -0
  337. package/examples/canister-studio/did/ckbtc_minter.did +806 -0
  338. package/examples/canister-studio/did/icp_ledger.did +586 -0
  339. package/examples/canister-studio/did/icrc1.did +88 -0
  340. package/examples/canister-studio/package.json +45 -0
  341. package/examples/canister-studio/scripts/smoke.ts +188 -0
  342. package/examples/canister-studio/src/calls/CacheKeyPanel.tsx +104 -0
  343. package/examples/canister-studio/src/calls/ConfirmWrite.tsx +265 -0
  344. package/examples/canister-studio/src/calls/ErrorPanel.test.tsx +113 -0
  345. package/examples/canister-studio/src/calls/ErrorPanel.tsx +214 -0
  346. package/examples/canister-studio/src/calls/MethodRunner.test.tsx +354 -0
  347. package/examples/canister-studio/src/calls/MethodRunner.tsx +57 -0
  348. package/examples/canister-studio/src/calls/ReadRunner.tsx +244 -0
  349. package/examples/canister-studio/src/calls/ResendPanel.tsx +165 -0
  350. package/examples/canister-studio/src/calls/ShareLink.tsx +59 -0
  351. package/examples/canister-studio/src/calls/WriteRunner.test.tsx +678 -0
  352. package/examples/canister-studio/src/calls/WriteRunner.tsx +670 -0
  353. package/examples/canister-studio/src/calls/dedupe.ts +189 -0
  354. package/examples/canister-studio/src/calls/error-info.ts +168 -0
  355. package/examples/canister-studio/src/calls/history.test.ts +284 -0
  356. package/examples/canister-studio/src/calls/history.ts +287 -0
  357. package/examples/canister-studio/src/calls/kinds.ts +68 -0
  358. package/examples/canister-studio/src/calls/prepare.ts +32 -0
  359. package/examples/canister-studio/src/calls/query-options.ts +30 -0
  360. package/examples/canister-studio/src/calls/read.ts +47 -0
  361. package/examples/canister-studio/src/calls/readback.ts +100 -0
  362. package/examples/canister-studio/src/calls/record.ts +123 -0
  363. package/examples/canister-studio/src/calls/safe-calls.test.ts +299 -0
  364. package/examples/canister-studio/src/calls/share.ts +46 -0
  365. package/examples/canister-studio/src/calls/testing/doubles.tsx +108 -0
  366. package/examples/canister-studio/src/calls/testing/fixtures.ts +185 -0
  367. package/examples/canister-studio/src/calls/useCanisterHandle.ts +35 -0
  368. package/examples/canister-studio/src/canisters/ckbtc_minter.envelope.json +4228 -0
  369. package/examples/canister-studio/src/canisters/ckbtc_minter.ts +868 -0
  370. package/examples/canister-studio/src/canisters/icp_ledger.envelope.json +3454 -0
  371. package/examples/canister-studio/src/canisters/icp_ledger.ts +584 -0
  372. package/examples/canister-studio/src/canisters/icrc1.envelope.json +840 -0
  373. package/examples/canister-studio/src/canisters/icrc1.ts +78 -0
  374. package/examples/canister-studio/src/components/ActionButton.tsx +32 -0
  375. package/examples/canister-studio/src/components/AppHeader.tsx +83 -0
  376. package/examples/canister-studio/src/components/AppShell.tsx +29 -0
  377. package/examples/canister-studio/src/components/AuthButton.tsx +79 -0
  378. package/examples/canister-studio/src/components/Badge.tsx +79 -0
  379. package/examples/canister-studio/src/components/CanisterHeader.tsx +200 -0
  380. package/examples/canister-studio/src/components/CanisterJump.tsx +130 -0
  381. package/examples/canister-studio/src/components/Card.tsx +64 -0
  382. package/examples/canister-studio/src/components/Code.tsx +101 -0
  383. package/examples/canister-studio/src/components/CopyButton.tsx +126 -0
  384. package/examples/canister-studio/src/components/Disclosure.tsx +34 -0
  385. package/examples/canister-studio/src/components/EmptyState.tsx +34 -0
  386. package/examples/canister-studio/src/components/MethodList.test.tsx +137 -0
  387. package/examples/canister-studio/src/components/MethodList.tsx +244 -0
  388. package/examples/canister-studio/src/components/Notice.tsx +36 -0
  389. package/examples/canister-studio/src/components/ProvenanceBadge.tsx +44 -0
  390. package/examples/canister-studio/src/components/RouteError.tsx +42 -0
  391. package/examples/canister-studio/src/components/SectionBoundary.tsx +76 -0
  392. package/examples/canister-studio/src/components/Spinner.tsx +33 -0
  393. package/examples/canister-studio/src/components/Tabs.tsx +96 -0
  394. package/examples/canister-studio/src/components/canister/CanisterLoadFailure.test.tsx +56 -0
  395. package/examples/canister-studio/src/components/canister/CanisterLoadFailure.tsx +165 -0
  396. package/examples/canister-studio/src/components/canister/CanisterNotFound.tsx +59 -0
  397. package/examples/canister-studio/src/components/canister/CanisterPending.tsx +33 -0
  398. package/examples/canister-studio/src/components/canister/MethodOverview.tsx +93 -0
  399. package/examples/canister-studio/src/components/canister/MethodWorkspace.test.tsx +201 -0
  400. package/examples/canister-studio/src/components/canister/MethodWorkspace.tsx +187 -0
  401. package/examples/canister-studio/src/components/canister/shared-call.test.ts +186 -0
  402. package/examples/canister-studio/src/components/canister/shared-call.ts +133 -0
  403. package/examples/canister-studio/src/components/canister/shared-link-loader.test.ts +116 -0
  404. package/examples/canister-studio/src/components/canister/use-canister-page.ts +44 -0
  405. package/examples/canister-studio/src/components/canister/workspace-key.test.ts +27 -0
  406. package/examples/canister-studio/src/components/canister/workspace-key.ts +36 -0
  407. package/examples/canister-studio/src/components/canister-id-input.ts +69 -0
  408. package/examples/canister-studio/src/components/canister-names.ts +11 -0
  409. package/examples/canister-studio/src/components/download.ts +34 -0
  410. package/examples/canister-studio/src/components/fallbacks.tsx +33 -0
  411. package/examples/canister-studio/src/components/helpers.test.ts +107 -0
  412. package/examples/canister-studio/src/components/history/HistoryList.tsx +284 -0
  413. package/examples/canister-studio/src/components/home/FeaturedLedger.tsx +149 -0
  414. package/examples/canister-studio/src/components/home/OpenCanister.tsx +99 -0
  415. package/examples/canister-studio/src/components/home/featured.test.tsx +92 -0
  416. package/examples/canister-studio/src/components/home/featured.ts +64 -0
  417. package/examples/canister-studio/src/components/interface/CandidTab.tsx +38 -0
  418. package/examples/canister-studio/src/components/interface/CompatReport.tsx +92 -0
  419. package/examples/canister-studio/src/components/interface/CompatibilityTab.tsx +190 -0
  420. package/examples/canister-studio/src/components/interface/ProjectTab.tsx +196 -0
  421. package/examples/canister-studio/src/components/interface/TypeScriptTab.tsx +114 -0
  422. package/examples/canister-studio/src/components/interface/tools.test.tsx +169 -0
  423. package/examples/canister-studio/src/components/modes.ts +31 -0
  424. package/examples/canister-studio/src/components/playground/MethodPicker.tsx +67 -0
  425. package/examples/canister-studio/src/components/playground/PlaygroundForms.tsx +112 -0
  426. package/examples/canister-studio/src/components/playground/PlaygroundTools.tsx +219 -0
  427. package/examples/canister-studio/src/components/playground/sample.ts +43 -0
  428. package/examples/canister-studio/src/components/playground/target.test.tsx +86 -0
  429. package/examples/canister-studio/src/components/primitives.test.tsx +121 -0
  430. package/examples/canister-studio/src/components/provenance.ts +38 -0
  431. package/examples/canister-studio/src/components/route-render.test.tsx +71 -0
  432. package/examples/canister-studio/src/components/use-task.ts +56 -0
  433. package/examples/canister-studio/src/components/wallet/BalancePanel.tsx +110 -0
  434. package/examples/canister-studio/src/components/wallet/LedgerSummary.tsx +63 -0
  435. package/examples/canister-studio/src/components/wallet/MinterPanel.tsx +255 -0
  436. package/examples/canister-studio/src/components/wallet/SendPanel.test.tsx +297 -0
  437. package/examples/canister-studio/src/components/wallet/SendPanel.tsx +446 -0
  438. package/examples/canister-studio/src/components/wallet/ledgers.test.ts +36 -0
  439. package/examples/canister-studio/src/components/wallet/ledgers.ts +111 -0
  440. package/examples/canister-studio/src/forms/JsonPanel.tsx +157 -0
  441. package/examples/canister-studio/src/forms/MethodForm.test.tsx +369 -0
  442. package/examples/canister-studio/src/forms/MethodForm.tsx +368 -0
  443. package/examples/canister-studio/src/forms/TypedForm.tsx +55 -0
  444. package/examples/canister-studio/src/forms/context.ts +62 -0
  445. package/examples/canister-studio/src/forms/convert.ts +131 -0
  446. package/examples/canister-studio/src/forms/edge.test.ts +252 -0
  447. package/examples/canister-studio/src/forms/engine.test.ts +358 -0
  448. package/examples/canister-studio/src/forms/engine.ts +1492 -0
  449. package/examples/canister-studio/src/forms/fields/BytesField.tsx +210 -0
  450. package/examples/canister-studio/src/forms/fields/Field.tsx +106 -0
  451. package/examples/canister-studio/src/forms/fields/FieldShell.tsx +101 -0
  452. package/examples/canister-studio/src/forms/fields/Group.tsx +74 -0
  453. package/examples/canister-studio/src/forms/fields/ListField.tsx +256 -0
  454. package/examples/canister-studio/src/forms/fields/Segmented.tsx +78 -0
  455. package/examples/canister-studio/src/forms/fields/TimestampField.tsx +108 -0
  456. package/examples/canister-studio/src/forms/fields/UnitsField.tsx +119 -0
  457. package/examples/canister-studio/src/forms/fields/composites.tsx +389 -0
  458. package/examples/canister-studio/src/forms/fields/leaves.tsx +350 -0
  459. package/examples/canister-studio/src/forms/fields.test.tsx +396 -0
  460. package/examples/canister-studio/src/forms/helpers.test.ts +225 -0
  461. package/examples/canister-studio/src/forms/hints.ts +128 -0
  462. package/examples/canister-studio/src/forms/json.ts +119 -0
  463. package/examples/canister-studio/src/forms/parsing.test.ts +217 -0
  464. package/examples/canister-studio/src/forms/useMethodForm.ts +251 -0
  465. package/examples/canister-studio/src/interface/browser.test.ts +23 -0
  466. package/examples/canister-studio/src/interface/browser.ts +153 -0
  467. package/examples/canister-studio/src/interface/cache.ts +68 -0
  468. package/examples/canister-studio/src/interface/cli-cache.test.ts +155 -0
  469. package/examples/canister-studio/src/interface/cli-cache.ts +125 -0
  470. package/examples/canister-studio/src/interface/compile.server.test.ts +198 -0
  471. package/examples/canister-studio/src/interface/compile.server.ts +262 -0
  472. package/examples/canister-studio/src/interface/compile.test.ts +108 -0
  473. package/examples/canister-studio/src/interface/compile.ts +305 -0
  474. package/examples/canister-studio/src/interface/docs.test.ts +75 -0
  475. package/examples/canister-studio/src/interface/docs.ts +100 -0
  476. package/examples/canister-studio/src/interface/functions.test.ts +42 -0
  477. package/examples/canister-studio/src/interface/functions.ts +200 -0
  478. package/examples/canister-studio/src/interface/live-candid.server.ts +91 -0
  479. package/examples/canister-studio/src/interface/live-loader.test.ts +515 -0
  480. package/examples/canister-studio/src/interface/live-loader.ts +364 -0
  481. package/examples/canister-studio/src/interface/load.test.ts +328 -0
  482. package/examples/canister-studio/src/interface/load.ts +249 -0
  483. package/examples/canister-studio/src/interface/read-candid.test.ts +185 -0
  484. package/examples/canister-studio/src/interface/read-candid.ts +233 -0
  485. package/examples/canister-studio/src/interface/server-result.ts +42 -0
  486. package/examples/canister-studio/src/interface/typed.ts +68 -0
  487. package/examples/canister-studio/src/interface/types.ts +121 -0
  488. package/examples/canister-studio/src/lib/format.test.ts +107 -0
  489. package/examples/canister-studio/src/lib/format.ts +139 -0
  490. package/examples/canister-studio/src/lib/hex.test.ts +43 -0
  491. package/examples/canister-studio/src/lib/hex.ts +33 -0
  492. package/examples/canister-studio/src/lib/ids.test.ts +70 -0
  493. package/examples/canister-studio/src/lib/ids.ts +93 -0
  494. package/examples/canister-studio/src/lib/reactor.test.ts +55 -0
  495. package/examples/canister-studio/src/lib/reactor.ts +55 -0
  496. package/examples/canister-studio/src/lib/registry.test.ts +74 -0
  497. package/examples/canister-studio/src/lib/registry.ts +238 -0
  498. package/examples/canister-studio/src/lib/schema.ts +148 -0
  499. package/examples/canister-studio/src/routeTree.gen.ts +227 -0
  500. package/examples/canister-studio/src/router.test.ts +290 -0
  501. package/examples/canister-studio/src/router.tsx +127 -0
  502. package/examples/canister-studio/src/routes/__root.tsx +58 -0
  503. package/examples/canister-studio/src/routes/canister.$canisterId.index.tsx +172 -0
  504. package/examples/canister-studio/src/routes/canister.$canisterId.interface.tsx +98 -0
  505. package/examples/canister-studio/src/routes/canister.$canisterId.tsx +91 -0
  506. package/examples/canister-studio/src/routes/history.tsx +55 -0
  507. package/examples/canister-studio/src/routes/index.tsx +169 -0
  508. package/examples/canister-studio/src/routes/playground.tsx +286 -0
  509. package/examples/canister-studio/src/routes/safety.tsx +57 -0
  510. package/examples/canister-studio/src/routes/wallet.tsx +213 -0
  511. package/examples/canister-studio/src/safety/LabTransferForm.tsx +84 -0
  512. package/examples/canister-studio/src/safety/RequestLog.tsx +79 -0
  513. package/examples/canister-studio/src/safety/SafetyLab.test.tsx +89 -0
  514. package/examples/canister-studio/src/safety/SafetyLab.tsx +140 -0
  515. package/examples/canister-studio/src/safety/ScenarioCard.tsx +262 -0
  516. package/examples/canister-studio/src/safety/lab-run.ts +283 -0
  517. package/examples/canister-studio/src/safety/mock-ledger.test.ts +99 -0
  518. package/examples/canister-studio/src/safety/mock-ledger.ts +263 -0
  519. package/examples/canister-studio/src/safety/scenarios.test.ts +157 -0
  520. package/examples/canister-studio/src/safety/scenarios.ts +924 -0
  521. package/examples/canister-studio/src/styles.css +3453 -0
  522. package/examples/canister-studio/src/styles.test.ts +46 -0
  523. package/examples/canister-studio/src/values/CallPreview.test.tsx +86 -0
  524. package/examples/canister-studio/src/values/CallPreview.tsx +148 -0
  525. package/examples/canister-studio/src/values/ErrValueView.tsx +66 -0
  526. package/examples/canister-studio/src/values/Inspector.tsx +133 -0
  527. package/examples/canister-studio/src/values/ReplyView.test.tsx +341 -0
  528. package/examples/canister-studio/src/values/ReplyView.tsx +164 -0
  529. package/examples/canister-studio/src/values/candid-text.test.ts +516 -0
  530. package/examples/canister-studio/src/values/candid-text.ts +479 -0
  531. package/examples/canister-studio/src/values/hints.ts +58 -0
  532. package/examples/canister-studio/src/values/json.test.ts +66 -0
  533. package/examples/canister-studio/src/values/json.ts +31 -0
  534. package/examples/canister-studio/src/values/leaves.tsx +309 -0
  535. package/examples/canister-studio/src/values/schema.test.ts +123 -0
  536. package/examples/canister-studio/src/values/schema.ts +78 -0
  537. package/examples/canister-studio/src/values/test-router.tsx +21 -0
  538. package/examples/canister-studio/src/values/tree.tsx +670 -0
  539. package/examples/canister-studio/src/values/use-sha256.ts +29 -0
  540. package/examples/canister-studio/tsconfig.json +20 -0
  541. package/examples/canister-studio/vite.config.ts +50 -0
  542. package/examples/canister-studio/vitest.config.ts +20 -0
  543. package/examples/icrc-ledger/.stackblitzrc +4 -0
  544. package/examples/icrc-ledger/README.md +100 -0
  545. package/examples/icrc-ledger/ckbtc_minter.did +12 -0
  546. package/examples/icrc-ledger/icp_ledger.did +147 -0
  547. package/examples/icrc-ledger/icrc1.did +88 -0
  548. package/examples/icrc-ledger/index.html +13 -0
  549. package/examples/icrc-ledger/package.json +40 -0
  550. package/examples/icrc-ledger/scripts/smoke.ts +151 -0
  551. package/examples/icrc-ledger/src/App.tsx +71 -0
  552. package/examples/icrc-ledger/src/ErrorPanel.tsx +105 -0
  553. package/examples/icrc-ledger/src/MainnetTab.tsx +450 -0
  554. package/examples/icrc-ledger/src/SandboxTab.test.tsx +379 -0
  555. package/examples/icrc-ledger/src/SandboxTab.tsx +761 -0
  556. package/examples/icrc-ledger/src/blocks.test.ts +247 -0
  557. package/examples/icrc-ledger/src/blocks.ts +140 -0
  558. package/examples/icrc-ledger/src/canisters/ckbtc_minter.envelope.json +96 -0
  559. package/examples/icrc-ledger/src/canisters/ckbtc_minter.ts +16 -0
  560. package/examples/icrc-ledger/src/canisters/icp_ledger.envelope.json +690 -0
  561. package/examples/icrc-ledger/src/canisters/icp_ledger.ts +223 -0
  562. package/examples/icrc-ledger/src/canisters/icrc1.envelope.json +840 -0
  563. package/examples/icrc-ledger/src/canisters/icrc1.ts +78 -0
  564. package/examples/icrc-ledger/src/format.test.ts +41 -0
  565. package/examples/icrc-ledger/src/format.ts +68 -0
  566. package/examples/icrc-ledger/src/ledger.ts +15 -0
  567. package/examples/icrc-ledger/src/main.tsx +10 -0
  568. package/examples/icrc-ledger/src/minter.ts +16 -0
  569. package/examples/icrc-ledger/src/sandbox.test.ts +464 -0
  570. package/examples/icrc-ledger/src/sandbox.ts +281 -0
  571. package/examples/icrc-ledger/src/styles.css +391 -0
  572. package/examples/icrc-ledger/src/transfer-form.test.ts +62 -0
  573. package/examples/icrc-ledger/src/transfer-form.ts +97 -0
  574. package/examples/icrc-ledger/tsconfig.json +19 -0
  575. package/examples/icrc-ledger/vite.config.ts +44 -0
  576. package/examples/icrc-ledger/vitest.config.ts +12 -0
  577. package/examples/next-ssr/.stackblitzrc +4 -0
  578. package/examples/next-ssr/README.md +112 -0
  579. package/examples/next-ssr/icrc1.did +88 -0
  580. package/examples/next-ssr/next.config.ts +10 -0
  581. package/examples/next-ssr/package.json +41 -0
  582. package/examples/next-ssr/scripts/smoke.ts +169 -0
  583. package/examples/next-ssr/src/app/account/CertifiedBalances.tsx +58 -0
  584. package/examples/next-ssr/src/app/account/account.test.tsx +165 -0
  585. package/examples/next-ssr/src/app/account/page.tsx +82 -0
  586. package/examples/next-ssr/src/app/api/balance/[ledger]/[principal]/route.ts +10 -0
  587. package/examples/next-ssr/src/app/globals.css +278 -0
  588. package/examples/next-ssr/src/app/layout.tsx +34 -0
  589. package/examples/next-ssr/src/app/page.tsx +46 -0
  590. package/examples/next-ssr/src/app/providers.browser.test.tsx +127 -0
  591. package/examples/next-ssr/src/app/providers.test.tsx +73 -0
  592. package/examples/next-ssr/src/app/providers.tsx +60 -0
  593. package/examples/next-ssr/src/canisters/icrc1.envelope.json +840 -0
  594. package/examples/next-ssr/src/canisters/icrc1.ts +78 -0
  595. package/examples/next-ssr/src/components/BalanceTable.tsx +43 -0
  596. package/examples/next-ssr/src/components/LedgerCard.test.tsx +96 -0
  597. package/examples/next-ssr/src/components/LedgerCard.tsx +230 -0
  598. package/examples/next-ssr/src/components/LedgerError.tsx +32 -0
  599. package/examples/next-ssr/src/components/LedgerSections.tsx +22 -0
  600. package/examples/next-ssr/src/components/MyBalances.test.tsx +253 -0
  601. package/examples/next-ssr/src/components/MyBalances.tsx +129 -0
  602. package/examples/next-ssr/src/components/SessionBadge.tsx +18 -0
  603. package/examples/next-ssr/src/components/hydration.test.tsx +259 -0
  604. package/examples/next-ssr/src/components/server-data.ts +10 -0
  605. package/examples/next-ssr/src/format.ts +46 -0
  606. package/examples/next-ssr/src/ledgers.ts +38 -0
  607. package/examples/next-ssr/src/server/balance-route.test.ts +151 -0
  608. package/examples/next-ssr/src/server/balance-route.ts +157 -0
  609. package/examples/next-ssr/src/server/error-summary.test.ts +34 -0
  610. package/examples/next-ssr/src/server/error-summary.ts +37 -0
  611. package/examples/next-ssr/src/server/parse-owner.test.ts +39 -0
  612. package/examples/next-ssr/src/server/parse-owner.ts +34 -0
  613. package/examples/next-ssr/src/server/prefetch-ledgers.test.ts +137 -0
  614. package/examples/next-ssr/src/server/prefetch-ledgers.ts +70 -0
  615. package/examples/next-ssr/src/server/read-balances.test.ts +103 -0
  616. package/examples/next-ssr/src/server/read-balances.ts +78 -0
  617. package/examples/next-ssr/src/server/request-client.rsc.test.tsx +110 -0
  618. package/examples/next-ssr/src/server/request-client.ts +24 -0
  619. package/examples/next-ssr/src/testing/mock-ledgers.ts +115 -0
  620. package/examples/next-ssr/src/testing/react-server-dom-turbopack.d.ts +15 -0
  621. package/examples/next-ssr/src/testing/setup.ts +10 -0
  622. package/examples/next-ssr/tsconfig.json +31 -0
  623. package/examples/next-ssr/vitest.config.ts +59 -0
  624. package/examples/node-agent-tool/.stackblitzrc +4 -0
  625. package/examples/node-agent-tool/README.md +165 -0
  626. package/examples/node-agent-tool/icp.yaml +11 -0
  627. package/examples/node-agent-tool/icrc1.did +88 -0
  628. package/examples/node-agent-tool/package.json +32 -0
  629. package/examples/node-agent-tool/src/canisters/icrc1.envelope.json +840 -0
  630. package/examples/node-agent-tool/src/canisters/icrc1.ts +78 -0
  631. package/examples/node-agent-tool/src/cli.test.ts +64 -0
  632. package/examples/node-agent-tool/src/cli.ts +23 -0
  633. package/examples/node-agent-tool/src/command-line.ts +159 -0
  634. package/examples/node-agent-tool/src/commands/balance.ts +73 -0
  635. package/examples/node-agent-tool/src/commands/demo.test.ts +51 -0
  636. package/examples/node-agent-tool/src/commands/demo.ts +359 -0
  637. package/examples/node-agent-tool/src/commands/info.ts +69 -0
  638. package/examples/node-agent-tool/src/commands/reads.test.ts +133 -0
  639. package/examples/node-agent-tool/src/commands/resend.test.ts +363 -0
  640. package/examples/node-agent-tool/src/commands/transfer.test.ts +313 -0
  641. package/examples/node-agent-tool/src/commands/transfer.ts +415 -0
  642. package/examples/node-agent-tool/src/commands/watch.test.ts +159 -0
  643. package/examples/node-agent-tool/src/commands/watch.ts +135 -0
  644. package/examples/node-agent-tool/src/commands/whoami.ts +36 -0
  645. package/examples/node-agent-tool/src/context.ts +20 -0
  646. package/examples/node-agent-tool/src/dispatch.ts +70 -0
  647. package/examples/node-agent-tool/src/failure.test.ts +59 -0
  648. package/examples/node-agent-tool/src/failure.ts +176 -0
  649. package/examples/node-agent-tool/src/identity.test.ts +242 -0
  650. package/examples/node-agent-tool/src/identity.ts +228 -0
  651. package/examples/node-agent-tool/src/input.ts +110 -0
  652. package/examples/node-agent-tool/src/ledgers.test.ts +74 -0
  653. package/examples/node-agent-tool/src/ledgers.ts +62 -0
  654. package/examples/node-agent-tool/src/mock-ledger.ts +211 -0
  655. package/examples/node-agent-tool/src/network.test.ts +128 -0
  656. package/examples/node-agent-tool/src/network.ts +101 -0
  657. package/examples/node-agent-tool/src/output.test.ts +208 -0
  658. package/examples/node-agent-tool/src/output.ts +163 -0
  659. package/examples/node-agent-tool/src/run.ts +73 -0
  660. package/examples/node-agent-tool/src/test-kit.ts +167 -0
  661. package/examples/node-agent-tool/tsconfig.json +18 -0
  662. package/examples/node-agent-tool/vitest.config.ts +8 -0
  663. package/examples/vite-wallet/.stackblitzrc +4 -0
  664. package/examples/vite-wallet/Cargo.lock +646 -0
  665. package/examples/vite-wallet/Cargo.toml +5 -0
  666. package/examples/vite-wallet/README.md +107 -0
  667. package/examples/vite-wallet/backend/Cargo.toml +12 -0
  668. package/examples/vite-wallet/backend/backend.did +37 -0
  669. package/examples/vite-wallet/backend/src/lib.rs +133 -0
  670. package/examples/vite-wallet/icp.yaml +44 -0
  671. package/examples/vite-wallet/index.html +13 -0
  672. package/examples/vite-wallet/ledger.did +54 -0
  673. package/examples/vite-wallet/package.json +46 -0
  674. package/examples/vite-wallet/public/.ic-assets.json5 +26 -0
  675. package/examples/vite-wallet/scripts/faucet-args.test.ts +30 -0
  676. package/examples/vite-wallet/scripts/faucet-args.ts +41 -0
  677. package/examples/vite-wallet/scripts/faucet.ts +41 -0
  678. package/examples/vite-wallet/src/AddressBook.test.tsx +191 -0
  679. package/examples/vite-wallet/src/AddressBook.tsx +147 -0
  680. package/examples/vite-wallet/src/App.tsx +53 -0
  681. package/examples/vite-wallet/src/Balance.test.tsx +57 -0
  682. package/examples/vite-wallet/src/Balance.tsx +58 -0
  683. package/examples/vite-wallet/src/EnvironmentPanel.test.tsx +83 -0
  684. package/examples/vite-wallet/src/EnvironmentPanel.tsx +103 -0
  685. package/examples/vite-wallet/src/ErrorNote.tsx +70 -0
  686. package/examples/vite-wallet/src/Profile.test.tsx +145 -0
  687. package/examples/vite-wallet/src/Profile.tsx +92 -0
  688. package/examples/vite-wallet/src/SendIcp.test.tsx +231 -0
  689. package/examples/vite-wallet/src/SendIcp.tsx +244 -0
  690. package/examples/vite-wallet/src/SendToContact.test.tsx +113 -0
  691. package/examples/vite-wallet/src/SendToContact.tsx +102 -0
  692. package/examples/vite-wallet/src/SignIn.test.tsx +106 -0
  693. package/examples/vite-wallet/src/SignIn.tsx +120 -0
  694. package/examples/vite-wallet/src/Wallet.test.tsx +89 -0
  695. package/examples/vite-wallet/src/account-switch.test.tsx +108 -0
  696. package/examples/vite-wallet/src/auth/dev-accounts.test.ts +113 -0
  697. package/examples/vite-wallet/src/auth/dev-accounts.ts +216 -0
  698. package/examples/vite-wallet/src/auth/local-page.test.ts +28 -0
  699. package/examples/vite-wallet/src/auth/local-page.ts +20 -0
  700. package/examples/vite-wallet/src/auth/wallet-auth.test.ts +159 -0
  701. package/examples/vite-wallet/src/auth/wallet-auth.ts +131 -0
  702. package/examples/vite-wallet/src/canisters/backend.envelope.json +275 -0
  703. package/examples/vite-wallet/src/canisters/backend.ts +58 -0
  704. package/examples/vite-wallet/src/canisters/ledger.envelope.json +451 -0
  705. package/examples/vite-wallet/src/canisters/ledger.ts +56 -0
  706. package/examples/vite-wallet/src/client.ts +45 -0
  707. package/examples/vite-wallet/src/main.tsx +18 -0
  708. package/examples/vite-wallet/src/optimistic-contacts.ts +113 -0
  709. package/examples/vite-wallet/src/refusal.ts +17 -0
  710. package/examples/vite-wallet/src/styles.css +282 -0
  711. package/examples/vite-wallet/src/test/test-wallet.tsx +322 -0
  712. package/examples/vite-wallet/src/token.ts +50 -0
  713. package/examples/vite-wallet/src/transfer.test.ts +178 -0
  714. package/examples/vite-wallet/src/transfer.ts +110 -0
  715. package/examples/vite-wallet/src/use-canisters.ts +49 -0
  716. package/examples/vite-wallet/tsconfig.json +19 -0
  717. package/examples/vite-wallet/vite.config.ts +47 -0
  718. package/examples/vite-wallet/vitest.config.ts +17 -0
  719. package/package.json +9 -4
  720. package/packages/core/.size-limit.js +47 -0
  721. package/packages/core/LICENSE +21 -0
  722. package/packages/core/README.md +84 -0
  723. package/packages/core/llms.txt +610 -0
  724. package/packages/core/package.json +89 -0
  725. package/packages/core/src/call.ts +961 -0
  726. package/packages/core/src/canister.ts +259 -0
  727. package/packages/core/src/client.ts +2061 -0
  728. package/packages/core/src/errors.ts +1079 -0
  729. package/packages/core/src/hydration.ts +239 -0
  730. package/packages/core/src/index.ts +23 -0
  731. package/packages/core/src/keys.ts +108 -0
  732. package/packages/core/src/management.ts +138 -0
  733. package/packages/core/src/network.ts +1020 -0
  734. package/packages/core/src/options.ts +1000 -0
  735. package/packages/core/src/runtime.ts +50 -0
  736. package/packages/core/src/testing/fake-replica.ts +1166 -0
  737. package/packages/core/src/testing/index.ts +16 -0
  738. package/packages/core/src/testing/test-auth.ts +340 -0
  739. package/packages/core/src/testing/test-client.ts +559 -0
  740. package/packages/core/src/types.ts +541 -0
  741. package/packages/core/src/units.ts +299 -0
  742. package/packages/core/src/version.ts +4 -0
  743. package/packages/core/tests/canister-helpers.ts +187 -0
  744. package/packages/core/tests/canister-id.test.ts +158 -0
  745. package/packages/core/tests/canister-unwrap.test.ts +94 -0
  746. package/packages/core/tests/canister.test-d.ts +406 -0
  747. package/packages/core/tests/canister.test.ts +1921 -0
  748. package/packages/core/tests/client-account-change.test.ts +131 -0
  749. package/packages/core/tests/client-agents.test.ts +402 -0
  750. package/packages/core/tests/client-auth-network.test.ts +719 -0
  751. package/packages/core/tests/client-disposed.test.ts +403 -0
  752. package/packages/core/tests/client-helpers.ts +136 -0
  753. package/packages/core/tests/client-hydration.test.ts +166 -0
  754. package/packages/core/tests/client-pinned.test.ts +626 -0
  755. package/packages/core/tests/client-session.test.ts +348 -0
  756. package/packages/core/tests/client.test-d.ts +181 -0
  757. package/packages/core/tests/client.test.ts +1162 -0
  758. package/packages/core/tests/encode.test.ts +171 -0
  759. package/packages/core/tests/env-canister-id.test.ts +666 -0
  760. package/packages/core/tests/env-cookie-copies.test.ts +182 -0
  761. package/packages/core/tests/error-guard.test.ts +222 -0
  762. package/packages/core/tests/errors.test-d.ts +280 -0
  763. package/packages/core/tests/errors.test.ts +1359 -0
  764. package/packages/core/tests/fixtures/README.md +28 -0
  765. package/packages/core/tests/fixtures/accounts.did +21 -0
  766. package/packages/core/tests/fixtures/accounts.envelope.json +367 -0
  767. package/packages/core/tests/fixtures/accounts.ts +26 -0
  768. package/packages/core/tests/fixtures/archive.did +31 -0
  769. package/packages/core/tests/fixtures/archive.envelope.json +259 -0
  770. package/packages/core/tests/fixtures/archive.ts +55 -0
  771. package/packages/core/tests/fixtures/icrc1.did +88 -0
  772. package/packages/core/tests/fixtures/icrc1.envelope.json +840 -0
  773. package/packages/core/tests/fixtures/icrc1.ts +78 -0
  774. package/packages/core/tests/fixtures/management.did +724 -0
  775. package/packages/core/tests/fixtures/management.envelope.json +4455 -0
  776. package/packages/core/tests/fixtures/management.ts +486 -0
  777. package/packages/core/tests/fixtures/shapes.did +33 -0
  778. package/packages/core/tests/fixtures/shapes.envelope.json +440 -0
  779. package/packages/core/tests/fixtures/shapes.ts +56 -0
  780. package/packages/core/tests/fixtures/skippable.did +15 -0
  781. package/packages/core/tests/fixtures/skippable.envelope.json +182 -0
  782. package/packages/core/tests/fixtures/skippable.ts +33 -0
  783. package/packages/core/tests/func.test.ts +154 -0
  784. package/packages/core/tests/identity-attributes.test.ts +214 -0
  785. package/packages/core/tests/keys.test.ts +289 -0
  786. package/packages/core/tests/management.test.ts +206 -0
  787. package/packages/core/tests/network-helpers.ts +121 -0
  788. package/packages/core/tests/network.test-d.ts +78 -0
  789. package/packages/core/tests/network.test.ts +1051 -0
  790. package/packages/core/tests/options.test.ts +1594 -0
  791. package/packages/core/tests/redirect-sign-in.test.ts +393 -0
  792. package/packages/core/tests/resend.test-d.ts +81 -0
  793. package/packages/core/tests/resend.test.ts +723 -0
  794. package/packages/core/tests/skip.test-d.ts +125 -0
  795. package/packages/core/tests/testing-entry.test.ts +73 -0
  796. package/packages/core/tests/testing-fake-replica.test.ts +1242 -0
  797. package/packages/core/tests/testing-test-auth.test-d.ts +84 -0
  798. package/packages/core/tests/testing-test-auth.test.ts +483 -0
  799. package/packages/core/tests/testing-test-client.test-d.ts +184 -0
  800. package/packages/core/tests/testing-test-client.test.ts +1272 -0
  801. package/packages/core/tests/time-realm.test.ts +63 -0
  802. package/packages/core/tests/time.test.ts +238 -0
  803. package/packages/core/tests/traps/README.md +39 -0
  804. package/packages/core/tests/traps/anonymous-write.test.ts +145 -0
  805. package/packages/core/tests/traps/classification-table.test.ts +256 -0
  806. package/packages/core/tests/traps/err-arm.test.ts +144 -0
  807. package/packages/core/tests/traps/fetch-spy.ts +39 -0
  808. package/packages/core/tests/traps/invalidation-after-write.test.ts +178 -0
  809. package/packages/core/tests/traps/ledger.ts +248 -0
  810. package/packages/core/tests/traps/root-key-off-local.test.ts +130 -0
  811. package/packages/core/tests/traps/stale-data-across-users.test.ts +173 -0
  812. package/packages/core/tests/traps/unresolved-name.test.ts +155 -0
  813. package/packages/core/tests/traps/update-as-query.test.ts +244 -0
  814. package/packages/core/tests/traps/update-not-resent.test.ts +126 -0
  815. package/packages/core/tests/traps/update-resent-when-never-delivered.test.ts +159 -0
  816. package/packages/core/tests/traps.test-d.ts +476 -0
  817. package/packages/core/tests/units.test-d.ts +118 -0
  818. package/packages/core/tests/units.test.ts +634 -0
  819. package/packages/core/tsconfig.json +19 -0
  820. package/packages/core/tsconfig.typecheck.json +16 -0
  821. package/packages/core/vitest.config.ts +13 -0
  822. package/packages/mcp/LICENSE +21 -0
  823. package/packages/mcp/README.md +189 -0
  824. package/packages/mcp/package.json +62 -0
  825. package/packages/mcp/src/candid/candid-text.test.ts +455 -0
  826. package/packages/mcp/src/candid/candid-text.ts +501 -0
  827. package/packages/mcp/src/candid/contract.test.ts +398 -0
  828. package/packages/mcp/src/candid/formats.ts +155 -0
  829. package/packages/mcp/src/candid/hex.ts +29 -0
  830. package/packages/mcp/src/candid/json-schema.test.ts +758 -0
  831. package/packages/mcp/src/candid/json-schema.ts +454 -0
  832. package/packages/mcp/src/candid/json.test.ts +1207 -0
  833. package/packages/mcp/src/candid/json.ts +1053 -0
  834. package/packages/mcp/src/candid/schema-walk.ts +189 -0
  835. package/packages/mcp/src/candid/type-text.test.ts +179 -0
  836. package/packages/mcp/src/candid/type-text.ts +238 -0
  837. package/packages/mcp/src/cli.ts +134 -0
  838. package/packages/mcp/src/identity.ts +188 -0
  839. package/packages/mcp/src/interface/cache.test.ts +48 -0
  840. package/packages/mcp/src/interface/cache.ts +68 -0
  841. package/packages/mcp/src/interface/cli-cache.test.ts +150 -0
  842. package/packages/mcp/src/interface/cli-cache.ts +122 -0
  843. package/packages/mcp/src/interface/compile-worker.test.ts +246 -0
  844. package/packages/mcp/src/interface/compile-worker.ts +290 -0
  845. package/packages/mcp/src/interface/compile.test.ts +155 -0
  846. package/packages/mcp/src/interface/compile.ts +281 -0
  847. package/packages/mcp/src/interface/docs.test.ts +105 -0
  848. package/packages/mcp/src/interface/docs.ts +86 -0
  849. package/packages/mcp/src/interface/fixtures/icrc1.did +88 -0
  850. package/packages/mcp/src/interface/hex.ts +8 -0
  851. package/packages/mcp/src/interface/ids.test.ts +71 -0
  852. package/packages/mcp/src/interface/ids.ts +87 -0
  853. package/packages/mcp/src/interface/loader.test.ts +804 -0
  854. package/packages/mcp/src/interface/loader.ts +519 -0
  855. package/packages/mcp/src/interface/read-candid.test.ts +300 -0
  856. package/packages/mcp/src/interface/read-candid.ts +259 -0
  857. package/packages/mcp/src/interface/types.ts +113 -0
  858. package/packages/mcp/src/network.ts +122 -0
  859. package/packages/mcp/src/options.ts +149 -0
  860. package/packages/mcp/src/server/approval.ts +159 -0
  861. package/packages/mcp/src/server/naming.ts +43 -0
  862. package/packages/mcp/src/server/results.ts +102 -0
  863. package/packages/mcp/src/server/server.ts +797 -0
  864. package/packages/mcp/src/server/tools.ts +116 -0
  865. package/packages/mcp/src/usage.ts +40 -0
  866. package/packages/mcp/tests/approval.test.ts +60 -0
  867. package/packages/mcp/tests/identity.test.ts +234 -0
  868. package/packages/mcp/tests/naming.test.ts +62 -0
  869. package/packages/mcp/tests/options.test.ts +140 -0
  870. package/packages/mcp/tests/server.test.ts +997 -0
  871. package/packages/mcp/tsconfig.json +19 -0
  872. package/packages/mcp/tsconfig.typecheck.json +10 -0
  873. package/packages/mcp/vitest.config.ts +10 -0
  874. package/packages/react/LICENSE +21 -0
  875. package/packages/react/README.md +328 -0
  876. package/packages/react/llms.txt +95 -0
  877. package/packages/react/package.json +95 -0
  878. package/packages/react/src/index.tsx +678 -0
  879. package/packages/react/tests/abandoned-render.test.tsx +816 -0
  880. package/packages/react/tests/auth.test.tsx +315 -0
  881. package/packages/react/tests/caller-keys.test.tsx +2334 -0
  882. package/packages/react/tests/client-time.test.ts +40 -0
  883. package/packages/react/tests/entry.test.ts +52 -0
  884. package/packages/react/tests/helpers.tsx +291 -0
  885. package/packages/react/tests/hydration.test.tsx +262 -0
  886. package/packages/react/tests/ownership.test.tsx +260 -0
  887. package/packages/react/tests/provider.server.test.tsx +169 -0
  888. package/packages/react/tests/query-client.test.tsx +107 -0
  889. package/packages/react/tests/strict-mode.test.tsx +288 -0
  890. package/packages/react/tests/suspense.test-d.tsx +357 -0
  891. package/packages/react/tests/two-query-cores.test.tsx +135 -0
  892. package/packages/react/tests/types.test-d.tsx +63 -0
  893. package/packages/react/tsconfig.json +23 -0
  894. package/packages/react/tsconfig.test.json +8 -0
  895. package/packages/react/tsconfig.typecheck.json +16 -0
  896. package/packages/react/vitest.config.ts +39 -0
  897. package/packages/vite-plugin/LICENSE +21 -0
  898. package/packages/vite-plugin/README.md +532 -0
  899. package/packages/vite-plugin/package.json +76 -0
  900. package/packages/vite-plugin/src/describe-value.test.ts +43 -0
  901. package/packages/vite-plugin/src/describe-value.ts +167 -0
  902. package/packages/vite-plugin/src/dev-environment.test.ts +747 -0
  903. package/packages/vite-plugin/src/dev-environment.ts +510 -0
  904. package/packages/vite-plugin/src/env.ts +431 -0
  905. package/packages/vite-plugin/src/fetch.ts +348 -0
  906. package/packages/vite-plugin/src/file-identity.ts +106 -0
  907. package/packages/vite-plugin/src/generate.ts +691 -0
  908. package/packages/vite-plugin/src/index.test.ts +1243 -0
  909. package/packages/vite-plugin/src/index.ts +2565 -0
  910. package/packages/vite-plugin/src/interface.ts +339 -0
  911. package/packages/vite-plugin/src/local-host.ts +34 -0
  912. package/packages/vite-plugin/src/options.ts +641 -0
  913. package/packages/vite-plugin/src/principal-text.test.ts +87 -0
  914. package/packages/vite-plugin/src/principal-text.ts +98 -0
  915. package/packages/vite-plugin/tests/close.test.ts +141 -0
  916. package/packages/vite-plugin/tests/environment-mode.test.ts +136 -0
  917. package/packages/vite-plugin/tests/fake-ic.ts +214 -0
  918. package/packages/vite-plugin/tests/fetch-sdk.test.ts +27 -0
  919. package/packages/vite-plugin/tests/fetch.test.ts +1196 -0
  920. package/packages/vite-plugin/tests/fixtures/fake-cli/bin.js +90 -0
  921. package/packages/vite-plugin/tests/fixtures/fake-cli/package.json +8 -0
  922. package/packages/vite-plugin/tests/fixtures/icrc1.did +88 -0
  923. package/packages/vite-plugin/tests/generation.test.ts +1036 -0
  924. package/packages/vite-plugin/tests/icp-command.test.ts +194 -0
  925. package/packages/vite-plugin/tests/icp-timeout.test.ts +83 -0
  926. package/packages/vite-plugin/tests/no-process-exit.test.ts +83 -0
  927. package/packages/vite-plugin/tests/on-generated.test.ts +323 -0
  928. package/packages/vite-plugin/tests/output-collision.test.ts +329 -0
  929. package/packages/vite-plugin/tests/package.test.ts +62 -0
  930. package/packages/vite-plugin/tests/project.test.ts +2993 -0
  931. package/packages/vite-plugin/tests/support.ts +339 -0
  932. package/packages/vite-plugin/tests/timeout.test.ts +107 -0
  933. package/packages/vite-plugin/tsconfig.json +23 -0
  934. package/packages/vite-plugin/tsconfig.typecheck.json +16 -0
  935. package/packages/vite-plugin/vitest.config.ts +9 -0
  936. package/pnpm-workspace.yaml +23 -0
  937. package/scripts/ai-context-files.js +72 -0
  938. package/scripts/assemble-docs-site.mjs +485 -0
  939. package/scripts/assemble-docs-site.test.mjs +568 -0
  940. package/scripts/build-examples.js +58 -0
  941. package/scripts/check-ai-context.js +963 -0
  942. package/scripts/check-ai-context.test.mjs +811 -0
  943. package/scripts/check-exports.mjs +767 -0
  944. package/scripts/check-exports.test.mjs +1136 -0
  945. package/scripts/check-snippets/ambient.d.ts +428 -0
  946. package/scripts/check-snippets/app/generated/backend.did +7 -0
  947. package/scripts/check-snippets/app/generated/backend.ts +15 -0
  948. package/scripts/check-snippets/app/generated/icrc1.did +88 -0
  949. package/scripts/check-snippets/app/generated/icrc1.ts +78 -0
  950. package/scripts/check-snippets/app/globals.ts +26 -0
  951. package/scripts/check-snippets/docs/guides/App.tsx +21 -0
  952. package/scripts/check-snippets/docs/guides/app/providers.tsx +23 -0
  953. package/scripts/check-snippets/docs/guides/auth-client.ts +47 -0
  954. package/scripts/check-snippets/docs/guides/canisters/backend.ts +3 -0
  955. package/scripts/check-snippets/docs/guides/canisters/icrc1.ts +3 -0
  956. package/scripts/check-snippets/docs/guides/components/LedgerCard.tsx +26 -0
  957. package/scripts/check-snippets/docs/guides/components/shell.tsx +11 -0
  958. package/scripts/check-snippets/docs/guides/components/sign-in-page.tsx +29 -0
  959. package/scripts/check-snippets/docs/guides/components/slow-section.tsx +5 -0
  960. package/scripts/check-snippets/docs/guides/generated/accounts.ts +95 -0
  961. package/scripts/check-snippets/docs/guides/generated/ckbtc_minter.ts +40 -0
  962. package/scripts/check-snippets/docs/guides/generated/icp_ledger.ts +267 -0
  963. package/scripts/check-snippets/docs/guides/ledger.ts +10 -0
  964. package/scripts/check-snippets/docs/guides/server/request-client.ts +8 -0
  965. package/scripts/check-snippets.mjs +993 -0
  966. package/scripts/check-snippets.test.mjs +338 -0
  967. package/scripts/check-stack.mjs +501 -0
  968. package/scripts/check-stack.test.mjs +800 -0
  969. package/scripts/clean-node-modules.js +67 -0
  970. package/scripts/example-projects.js +58 -0
  971. package/scripts/export-budget.mjs +145 -0
  972. package/scripts/faults.json +6749 -0
  973. package/scripts/lib/fault-workspace.mjs +210 -0
  974. package/scripts/lib/io.mjs +29 -0
  975. package/scripts/lib/io.test.mjs +38 -0
  976. package/scripts/lib/markdown-fences.mjs +56 -0
  977. package/scripts/lib/markdown-fences.test.mjs +84 -0
  978. package/scripts/lib/package-exports.mjs +54 -0
  979. package/scripts/lib/package-exports.test.mjs +66 -0
  980. package/scripts/lib/release-pr-steps.mjs +47 -0
  981. package/scripts/release-tag.mjs +95 -0
  982. package/scripts/release-tag.test.mjs +278 -0
  983. package/scripts/release-workflow.test.mjs +98 -0
  984. package/scripts/release.js +167 -0
  985. package/scripts/release.test.mjs +347 -0
  986. package/scripts/removed-v3-names.js +125 -0
  987. package/scripts/size-app/.size-limit.js +90 -0
  988. package/scripts/size-app/core.js +3 -0
  989. package/scripts/size-app/package.json +24 -0
  990. package/scripts/size-app/react.js +4 -0
  991. package/scripts/size-app.test.mjs +73 -0
  992. package/scripts/sync-ai-context-versions.js +102 -0
  993. package/scripts/sync-example-versions.js +151 -0
  994. package/scripts/test-examples-published.mjs +1585 -0
  995. package/scripts/test-examples-published.test.mjs +1586 -0
  996. package/scripts/traps/any-method-vars-not-a-list.json +5 -0
  997. package/scripts/traps/canister-method-unknown.json +5 -0
  998. package/scripts/traps/client-says-who-calls-once.json +5 -0
  999. package/scripts/traps/client-says-who-calls.json +5 -0
  1000. package/scripts/traps/err-only-on-canister-err.json +14 -0
  1001. package/scripts/traps/format-units-refuses-missing-value.json +5 -0
  1002. package/scripts/traps/format-units-refuses-number.json +5 -0
  1003. package/scripts/traps/format-units-unknown-option.json +5 -0
  1004. package/scripts/traps/guard-err-is-the-methods.json +5 -0
  1005. package/scripts/traps/guard-false-keeps-every-kind.json +5 -0
  1006. package/scripts/traps/internals-not-exported.json +9 -0
  1007. package/scripts/traps/network-refuses-unknown-name.json +5 -0
  1008. package/scripts/traps/never-err-has-no-type.json +5 -0
  1009. package/scripts/traps/options-method-unknown.json +5 -0
  1010. package/scripts/traps/options-vars-wrong-type.json +5 -0
  1011. package/scripts/traps/parse-units-refuses-number.json +5 -0
  1012. package/scripts/traps/parse-units-unknown-option.json +5 -0
  1013. package/scripts/traps/principal-is-not-plain-text.json +14 -0
  1014. package/scripts/traps/query-options-refuses-oneway.json +5 -0
  1015. package/scripts/traps/query-options-refuses-update.json +5 -0
  1016. package/scripts/traps/refuse-next-unknown-option.json +5 -0
  1017. package/scripts/traps/resend-key-reads-the-methods-arg.json +5 -0
  1018. package/scripts/traps/resend-states-its-dedupe-key.json +5 -0
  1019. package/scripts/traps/suspense-refuses-argument-skip.json +5 -0
  1020. package/scripts/traps/suspense-refuses-skippable-read.json +5 -0
  1021. package/scripts/traps/suspense-refuses-vars-skip-fits.json +5 -0
  1022. package/scripts/traps/test-handler-method-unknown.json +5 -0
  1023. package/scripts/traps/test-handler-nat-is-bigint.json +5 -0
  1024. package/scripts/traps/test-handler-takes-the-domain-value.json +5 -0
  1025. package/scripts/traps/vars-of-two-arguments-are-the-tuple.json +5 -0
  1026. package/scripts/typecheck-examples.js +122 -0
  1027. package/scripts/verify-faults.mjs +375 -0
  1028. package/scripts/verify-faults.test.mjs +402 -0
  1029. package/scripts/verify-package-artifacts.mjs +590 -0
  1030. package/scripts/verify-peer-floors.js +399 -0
  1031. package/scripts/verify-peer-floors.test.mjs +422 -0
  1032. package/scripts/verify-test-fails-rules.mjs +104 -0
  1033. package/scripts/verify-test-fails-rules.test.mjs +215 -0
  1034. package/scripts/verify-test-fails.js +371 -0
  1035. package/scripts/verify-traps.mjs +505 -0
  1036. package/scripts/verify-traps.test.mjs +521 -0
  1037. package/scripts/verify-typescript-floor.js +239 -0
  1038. package/skill-packages/ic-reactor/SKILL.md +103 -0
  1039. package/stack.json +8 -0
  1040. package/tsconfig.base.json +23 -0
  1041. package/tsconfig.json +8 -0
@@ -0,0 +1,1181 @@
1
+ ---
2
+ title: "Auth"
3
+ description: "Signing users in with @icp-sdk/auth 10 or any AuthLike, useAuth, caller changes, and identity attributes"
4
+ ---
5
+
6
+ import { Aside } from "@astrojs/starlight/components"
7
+
8
+ A client is built with exactly one way to say who calls (see
9
+ [The client](/v4/guides/client/)).
10
+
11
+ - `identity` is a caller that never changes: `"anonymous"` for a read-only
12
+ client, or an `Identity` for a script, a server or a test. It has no sign-in.
13
+ - `auth` is a factory for a sign-in, and gives you users who sign in and out.
14
+ This page is about `auth`.
15
+
16
+ Query keys carry the caller. When the user signs in or out, the client moves
17
+ every read to the new caller's keys, and nothing read for one principal shows
18
+ under another.
19
+
20
+ ## Internet Identity with @icp-sdk/auth 10
21
+
22
+ The `AuthClient` of `@icp-sdk/auth` 10 is an `AuthLike` as it is. The
23
+ supported range is `^10.0.1`, and a weekly CI job checks the newest release
24
+ against `AuthLike`. A later release whose session has a state the client does
25
+ not know still compiles: the client calls anonymously in that state, and
26
+ `useAuth()` reads it as `"anonymous"`. npm's newest release is 11, which is
27
+ outside that range, so name the major version when you install it, and pass a
28
+ factory that builds one:
29
+
30
+ ```sh
31
+ npm install @icp-sdk/auth@^10
32
+ ```
33
+
34
+ ```ts
35
+ import { createClient } from "@ic-reactor/core"
36
+ import { AuthClient } from "@icp-sdk/auth/client"
37
+
38
+ export const client = createClient({
39
+ network: "ic",
40
+ auth: (network) => new AuthClient(network),
41
+ })
42
+ ```
43
+
44
+ You write no adapter. The client does the rest:
45
+
46
+ - It calls the factory once, on first use, and only in a browser. On a server
47
+ the factory never runs and the client is anonymous.
48
+ - It owns what the factory returns. `client.dispose()` stops listening to it
49
+ and calls its `dispose()`.
50
+ - It reads `getStatus()` and `getPrincipal()` to decide who calls, and asks
51
+ `getIdentity()` for the identity to sign with.
52
+ - It sets a timer for the session's end, `getStatus().expiresAtMs`.
53
+ `AuthClient`'s status turns `"expired"` by the clock and tells nobody, so
54
+ the client tells its listeners itself: `useAuth()` renders `"expired"` when
55
+ the session ends, with no user activity needed.
56
+ - It forwards `signIn(options)` and `signOut(options)` to it. Two `signIn()`
57
+ calls with the same options in one synchronous run reach it once (see
58
+ [Sign-in options](#sign-in-options)).
59
+ - If the factory throws, it is not called again. `new AuthClient()` reads
60
+ `localStorage`, which throws where site data is blocked or in a sandboxed
61
+ frame. The client then calls anonymously, so public reads still work, logs
62
+ the error once in development, and rejects `signIn()` and `signOut()` with
63
+ what the factory threw. A factory that returns something other than an
64
+ auth, such as a Promise from an `async` factory, is treated the same way,
65
+ with a `TypeError` that names what the result lacks. Build a new client to
66
+ try again.
67
+
68
+ `AuthClient` is not a peer dependency of core: you install `@icp-sdk/auth`
69
+ yourself when you want Internet Identity.
70
+
71
+ The factory returns the auth synchronously, so the module that builds the
72
+ client imports `AuthClient` statically, and, when the entry module imports
73
+ that module statically, a bundler puts it in the page's first chunk. To keep
74
+ the client, the sign-in code and the generated module out of that chunk
75
+ instead, lazy-load the component that holds the `ReactorProvider`: see
76
+ [Keep the IC stack out of the first load](/v4/guides/getting-started/#keep-the-ic-stack-out-of-the-first-load),
77
+ which also says what a route guard sees while it loads.
78
+
79
+ ### The network the factory is handed
80
+
81
+ The client calls the factory with one argument, `network`, under
82
+ `AuthClient`'s own option names, so passing it through signs users in on the
83
+ network the client calls:
84
+
85
+ - `agentOptions` is the host, root key and `shouldFetchRootKey` of the
86
+ client's own agents, and its `fetch`, when you gave one. `AuthClient` makes
87
+ its mint and revoke calls with them.
88
+ - `identityProvider` is the Internet Identity to sign in with, as the two
89
+ values `AuthClient` 10 takes (the page a person signs in on and the canister
90
+ that mints their delegations), or absent, which `AuthClient` reads as
91
+ mainnet's.
92
+
93
+ The client picks the identity provider by these rules, in order:
94
+
95
+ 1. The `ic_env` cookie is believed in full, on a local page or with
96
+ `allowEnvConfig: true` (see [The client](/v4/guides/client/)), and names
97
+ `INTERNET_IDENTITY_PROVIDER`: that URL, with the cookie's
98
+ `PUBLIC_CANISTER_ID:internet_identity`, or Internet Identity's own id,
99
+ `rdmx6-jaaaa-aaaaa-aaadq-cai`, when it names none. The
100
+ [Vite plugin](/v4/guides/vite-plugin/) writes this cookie in dev and
101
+ preview. On a canister's own `<id>.icp0.io` page the cookie is believed
102
+ for canister ids only, so neither this rule nor the next applies there.
103
+ 2. That cookie names an `internet_identity` canister but no URL: the
104
+ project deploys its own Internet Identity, whose sign-in page cannot be
105
+ derived from its id. No provider.
106
+ 3. The network is `"local"`, or an object whose host is local: icp-cli's
107
+ built-in Internet Identity, `http://id.ai.localhost:<port>/authorize` on
108
+ the replica's port, with `rdmx6-jaaaa-aaaaa-aaadq-cai`. For `"local"` that
109
+ is `http://id.ai.localhost:8000/authorize`, the Vite plugin's default too.
110
+ 4. `"env"` on a local page whose cookie names no provider: the agent's host is
111
+ the page's (a dev server, or a gateway serving an asset canister), which
112
+ does not say where icp-cli's built-in Internet Identity is. No provider.
113
+ 5. Any other network whose root key is not mainnet's (one given, from the
114
+ cookie, or fetched): no provider.
115
+ 6. Mainnet: no provider, and `AuthClient`'s defaults are right.
116
+
117
+ So in the [Vite wallet](/v4/examples/vite-wallet/), with `network: "env"` and
118
+ the plugin's cookie, the one line above signs in with the local Internet
119
+ Identity in dev and with mainnet's on a deployed page.
120
+
121
+ A local replica rejects every delegation mainnet's Internet Identity mints.
122
+ So in cases 2, 4 and 5, on a network that is not mainnet's, the client warns
123
+ when the factory reads `network.identityProvider`, as `new AuthClient(network)`
124
+ does. The warning comes once, in development: sign-in cannot work on this
125
+ network without an identity provider, and the line that names one is
126
+ `(network) => new AuthClient({ ...network, identityProvider: { authorizeUrl, canisterId } })`.
127
+ A factory that names its own provider, as that line does, or builds an auth
128
+ that is not Internet Identity, never sees the warning. Nor does a spread that
129
+ adds other options and names no provider, such as
130
+ `new AuthClient({ ...network, derivationOrigin })`: it does not read
131
+ `identityProvider`, so on these networks it must name one.
132
+
133
+ For the `internet_identity` your project deploys, `authorizeUrl` is the
134
+ sign-in page it serves and `canisterId` the id `icp deploy` gave its backend:
135
+
136
+ ```ts
137
+ import { createClient } from "@ic-reactor/core"
138
+ import { AuthClient } from "@icp-sdk/auth/client"
139
+
140
+ // Your own Internet Identity: its sign-in page, and its backend canister.
141
+ const authorizeUrl = "http://my-ii.localhost:8000/authorize"
142
+ const canisterId = "bkyz2-fmaaa-aaaaa-qaaaq-cai"
143
+
144
+ export const client = createClient({
145
+ network: "env",
146
+ auth: (network) =>
147
+ new AuthClient({
148
+ ...network,
149
+ identityProvider: { authorizeUrl, canisterId },
150
+ }),
151
+ })
152
+ ```
153
+
154
+ `identityProvider` takes both values or neither. A factory that takes no
155
+ argument, `() => new AuthClient()`, still works on mainnet. It ignores the
156
+ network the client hands it, so on any other network it signs in with
157
+ mainnet's Internet Identity, whose delegations the replica rejects, and the
158
+ client cannot tell that it did. On any network but mainnet, pass `network`
159
+ through.
160
+
161
+ **On dfx.** Rule 3 names icp-cli's built-in Internet Identity, which dfx does
162
+ not serve. A client of dfx's replica, `{ host: "http://127.0.0.1:4943" }`, is
163
+ handed `http://id.ai.localhost:4943/authorize`, a page that does not load,
164
+ and nothing warns. Name the Internet Identity your dfx project deploys, as
165
+ above: `authorizeUrl` is its sign-in page on dfx's gateway,
166
+ `http://<the id of the canister that serves it>.localhost:4943/authorize`,
167
+ and `canisterId` the canister that mints its delegations. It must be a release
168
+ of Internet Identity that answers the `ii_session_delegation` request
169
+ `@icp-sdk/auth` 10 signs in with.
170
+
171
+ ### Sign-in options
172
+
173
+ `signIn` and `signOut` of the client and of `useAuth()` pass their argument to
174
+ the auth unchanged. For an `AuthClient` that is `maxTimeToLive` and
175
+ `maxTimeToIdle` (nanoseconds, as `bigint`) and `returnTo` for `signIn`, and
176
+ `returnTo` for `signOut`:
177
+
178
+ ```tsx
179
+ import { useAuth } from "@ic-reactor/react"
180
+
181
+ const HOUR_NS = 3_600_000_000_000n
182
+
183
+ export function EightHourSession() {
184
+ const { status, signIn, signOut } = useAuth()
185
+ return status === "signed-in" ? (
186
+ <button onClick={() => signOut({ returnTo: "/" }).catch(console.error)}>
187
+ Sign out
188
+ </button>
189
+ ) : (
190
+ <button
191
+ onClick={() =>
192
+ signIn({ maxTimeToLive: 8n * HOUR_NS, returnTo: "/account" }).catch(
193
+ console.error
194
+ )
195
+ }
196
+ >
197
+ Sign in for 8 hours
198
+ </button>
199
+ )
200
+ }
201
+ ```
202
+
203
+ The client types `options` as `unknown`, so a wrong option is not a type error.
204
+ Check it against `AuthClientSignInOptions` in `@icp-sdk/auth`.
205
+
206
+ Two `signIn()` calls with the same options in one synchronous run are one
207
+ sign-in: the later one returns the earlier one's promise, and the auth is
208
+ asked once. Options are the same when they are the same value (none at all
209
+ included), or objects with the same keys and the same values (compared with
210
+ `Object.is`, one level deep), so `{ returnTo: "/account" }` built twice is the
211
+ same. `StrictMode` makes such a pair in development, when it runs an effect
212
+ twice in a row. A call in a later run, such as a second click, signs in
213
+ again, as does a call with other options.
214
+
215
+ `AuthClient` has more options, such as `openIdProvider: "google"` for a
216
+ one-click sign-in and `transport: "redirect"`. They belong to
217
+ `@icp-sdk/auth`, not to this library: [Internet Identity 2.0](#internet-identity-20)
218
+ lists them. One of them, `transport: "redirect"`, changes how the page that
219
+ signs in is written: see [Redirect sign-in](#redirect-sign-in).
220
+
221
+ ### Redirect sign-in
222
+
223
+ With `transport: "redirect"`, `AuthClient` signs in over the ICRC-167 URL
224
+ transport instead of a window: the page itself goes to Internet Identity,
225
+ which sends the user back to the same page with its answer in the URL
226
+ fragment. `@icp-sdk/auth` suggests it for a full-page sign-in that needs no
227
+ click to open a window, and for a native app that hands off through a
228
+ universal link.
229
+
230
+ The page unloads on the way out, so the `signIn()` that left never settles.
231
+ On the load Internet Identity returns to, the same `signIn()` runs again, and
232
+ `AuthClient` finishes the sign-in from the URL. So the sign-in is a route of
233
+ its own that calls `signIn()` each time it loads, not from a click. Build the
234
+ `AuthClient` with the option in the client's factory:
235
+ `auth: (network) => new AuthClient({ ...network, transport: "redirect" })`.
236
+ A spread like this one reads no provider, so on a network the client names
237
+ none for (see [The network the factory is handed](#the-network-the-factory-is-handed)),
238
+ name `identityProvider` in it too.
239
+
240
+ `AuthClient` takes its callback, the URL Internet Identity returns to, from
241
+ the page it is built on: `location.origin` plus `location.pathname`. The
242
+ client builds it once, on first use, and keeps it while the app moves between
243
+ routes without a page load. So enter the sign-in route with a full page load,
244
+ a plain `<a href="/sign-in">` or `location.assign("/sign-in")`, not a
245
+ router's link, and start every sign-in there.
246
+
247
+ The route renders a component like this one:
248
+
249
+ ```tsx
250
+ // src/components/sign-in-page.tsx
251
+ import { useAuth } from "@ic-reactor/react"
252
+ import { useEffect, useState } from "react"
253
+
254
+ /** Signs in each time it loads; Internet Identity's return goes to /account. */
255
+ export function SignInPage() {
256
+ const { status, signIn } = useAuth()
257
+ const [failed, setFailed] = useState(false)
258
+ useEffect(() => {
259
+ if (status === "signed-in") return
260
+ const start = setTimeout(() => {
261
+ signIn({ returnTo: "/account" }).catch((error: unknown) => {
262
+ console.error(error)
263
+ setFailed(true)
264
+ })
265
+ })
266
+ return () => clearTimeout(start)
267
+ }, [status, signIn])
268
+ if (status === "signed-in") return <a href="/account">Continue</a>
269
+ if (failed) {
270
+ return (
271
+ <p>
272
+ The sign-in did not finish. <a href="/sign-in">Try again</a>
273
+ </p>
274
+ )
275
+ }
276
+ return <p>Signing you in…</p>
277
+ }
278
+ ```
279
+
280
+ - The first load leaves for Internet Identity. The load it returns to
281
+ finishes the sign-in, and `AuthClient` goes to `returnTo` in place of the
282
+ sign-in page's history entry.
283
+ - Pass the same options on every load. The return load replays the first
284
+ load's request, and a different one (another `maxTimeToLive`, say) fails.
285
+ `AuthClient` keeps the first load's `returnTo`, so it may come from a query
286
+ such as `?next=`, which the callback drops; pass one on every load or on
287
+ none.
288
+ - A user who cancels at Internet Identity comes back with an error, and
289
+ `signIn()` rejects. A new visit to the route starts a new sign-in. So does a
290
+ return more than 10 minutes later: `AuthClient` keeps the flow in the tab's
291
+ `sessionStorage` for that long.
292
+ - Once the user is signed in, `status` changes, the effect runs again, and
293
+ returns. A user who is already signed in gets the link on.
294
+ - The timer is for a page rendered on a server. There, the render that
295
+ hydrates shows `"anonymous"` whatever session the browser holds (see
296
+ [The hydrating render](/v4/guides/ssr/#the-hydrating-render)), and React
297
+ renders again with the session right after. The cleanup then clears the
298
+ timer, so a user who is already signed in is not sent to Internet Identity.
299
+ It also clears the first of the two runs `StrictMode` makes in development.
300
+ In an app with no server render, calling `signIn()` straight from the effect
301
+ works as well: `StrictMode`'s second call joins the first.
302
+
303
+ The route, by framework:
304
+
305
+ - **Vite.** With a router, give `/sign-in` a route that renders
306
+ `SignInPage`, below the `ReactorProvider`. Without one, choose by the path:
307
+
308
+ ```tsx
309
+ // src/App.tsx, with a redirect sign-in
310
+ import { createClient } from "@ic-reactor/core"
311
+ import { ReactorProvider, useAuth } from "@ic-reactor/react"
312
+ import { AuthClient } from "@icp-sdk/auth/client"
313
+ import { SignInPage } from "./components/sign-in-page"
314
+
315
+ export function App() {
316
+ return (
317
+ <ReactorProvider
318
+ client={() =>
319
+ createClient({
320
+ network: "ic",
321
+ auth: (network) =>
322
+ new AuthClient({ ...network, transport: "redirect" }),
323
+ })
324
+ }
325
+ >
326
+ {location.pathname === "/sign-in" ? <SignInPage /> : <Home />}
327
+ </ReactorProvider>
328
+ )
329
+ }
330
+
331
+ function Home() {
332
+ const { status, signOut } = useAuth()
333
+ return status === "signed-in" ? (
334
+ <button onClick={() => signOut({ returnTo: "/" }).catch(console.error)}>
335
+ Sign out
336
+ </button>
337
+ ) : (
338
+ <a href="/sign-in">Sign in</a>
339
+ )
340
+ }
341
+ ```
342
+
343
+ - **Next.js** (App Router). The provider in the root layout (see
344
+ [SSR and hydration](/v4/guides/ssr/#the-provider)) builds the `AuthClient`
345
+ with `transport: "redirect"`, and the page is a client module. Link to it
346
+ with `<a href="/sign-in">`, not `<Link>`:
347
+
348
+ ```tsx
349
+ "use client"
350
+ // src/app/sign-in/page.tsx
351
+
352
+ import { SignInPage } from "@/components/sign-in-page"
353
+
354
+ export default SignInPage
355
+ ```
356
+
357
+ - **TanStack Start.** A file route, below the root route that renders the
358
+ provider. Link to it with `<a href="/sign-in">`, or a `<Link>` with
359
+ `reloadDocument`:
360
+
361
+ ```tsx nocheck
362
+ // src/routes/sign-in.tsx
363
+ import { createFileRoute } from "@tanstack/react-router"
364
+ import { SignInPage } from "../components/sign-in-page"
365
+
366
+ export const Route = createFileRoute("/sign-in")({ component: SignInPage })
367
+ ```
368
+
369
+ `signOut({ returnTo })` works as with a window: it ends the session and goes
370
+ to `returnTo`, from any page.
371
+
372
+ #### The callbacks file
373
+
374
+ Internet Identity sends its answer only to a URL that the page's origin
375
+ lists. The callback is the sign-in page's `location.origin` plus
376
+ `location.pathname`, so list exactly that:
377
+
378
+ ```json
379
+ { "callbacks": ["https://app.example/sign-in"] }
380
+ ```
381
+
382
+ Serve it at `/.well-known/ii-auth-callbacks` on that origin:
383
+
384
+ - as JSON, with `Content-Type: application/json`;
385
+ - with an `Access-Control-Allow-Origin` header, so that Internet Identity's
386
+ page can read it;
387
+ - at that URL itself: Internet Identity does not follow a redirect.
388
+
389
+ An entry matches the callback byte for byte, with nothing normalized: an
390
+ absolute URL on the same origin, with no fragment.
391
+ `https://app.example/sign-in/` does not match `https://app.example/sign-in`.
392
+ Each origin the app signs in from lists its own callback in its own file.
393
+ Check the two headers there, for example with `curl -i`, a dev server
394
+ included: Vite's serves `public/.well-known/ii-auth-callbacks` with an empty
395
+ `Content-Type`, since the name has no extension, so set the header in a
396
+ middleware ahead of Vite's own (a plugin's `configureServer`).
397
+
398
+ On the IC, the asset canister's upload skips a name that starts with a dot
399
+ unless `.ic-assets.json5` in the assets folder (in a Vite app, `public/`)
400
+ says otherwise, as for Internet Identity's alternative-origins file:
401
+
402
+ ```json5
403
+ [
404
+ { match: ".well-known", ignore: false },
405
+ {
406
+ match: ".well-known/ii-auth-callbacks",
407
+ headers: {
408
+ "Access-Control-Allow-Origin": "*",
409
+ "Content-Type": "application/json",
410
+ },
411
+ ignore: false,
412
+ },
413
+ ]
414
+ ```
415
+
416
+ #### Values the return load needs
417
+
418
+ The return load runs the page's code from the start. A value of your own
419
+ that the first load computed and the code after the sign-in reads, such as
420
+ an id it generated or something it fetched, goes through
421
+ `authClient.memoize(produce)`: it runs `produce` on the first load, keeps the
422
+ result, and returns it on the return load. Call it in the same order relative
423
+ to `signIn()` on every load, and keep the value JSON. It is a method of
424
+ `AuthClient`, not of the client, so keep your own reference to it, as in
425
+ [Identity attributes](#identity-attributes).
426
+
427
+ `requestAttributes` keeps the nonce its callback returns by itself, so the
428
+ canister that issues it is asked once. `@icp-sdk/auth` advises giving each
429
+ flow its own route, so this guide's `SignInPage` calls `signIn()` only, and
430
+ `requestAttributes()` goes on a route of its own.
431
+
432
+ ### Internet Identity 2.0
433
+
434
+ What Internet Identity offers an app beyond a plain sign-in, its 2.0 features
435
+ among them, is an option of `AuthClient`, so it works through the factory, with
436
+ nothing from this library. An option of `new AuthClient()` goes in the factory,
437
+ beside `...network`, and is fixed for the client's life, since the client calls
438
+ its factory once. An option of `signIn()` goes in the call.
439
+
440
+ | To get | Pass | In |
441
+ | ------------------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------- |
442
+ | One-click sign-in with Google, Apple or Microsoft | `openIdProvider: "google"`, `"apple"` or `"microsoft"` | the factory |
443
+ | Sign-in with an organization's own SSO | `ssoDomain: "example.com"` | the factory |
444
+ | A verified email and the user's name | `requestAttributes()` with `verified_email` and `name` | [Identity attributes](#identity-attributes) |
445
+ | A shorter session, or a shorter idle time | `maxTimeToLive`, `maxTimeToIdle` (nanoseconds) | `signIn()` |
446
+ | Sessions that only calls keep alive | `disableBrowserActivity: true` | the factory |
447
+ | Two clients on one origin, each with its sign-in | `namespace: "admin"` on one of them | the factory |
448
+ | One principal on several origins | `derivationOrigin` | the factory |
449
+ | One sign-in for sibling subdomains | `stateStorage: new CookieStateStorage({ domain })` and a `derivationOrigin` | the factory |
450
+ | A full-page sign-in instead of a window | `transport: "redirect"` | the factory |
451
+
452
+ ```ts
453
+ import { createClient } from "@ic-reactor/core"
454
+ import { AuthClient } from "@icp-sdk/auth/client"
455
+
456
+ // An admin console beside the main app on the same origin, signed in with
457
+ // the organization's SSO.
458
+ export const adminClient = createClient({
459
+ network: "ic",
460
+ auth: (network) =>
461
+ new AuthClient({
462
+ ...network,
463
+ ssoDomain: "example.com",
464
+ namespace: "admin",
465
+ }),
466
+ })
467
+ ```
468
+
469
+ - `openIdProvider` and `ssoDomain` exclude each other.
470
+ - `disableBrowserActivity` stops `AuthClient` from reading page visits, focus,
471
+ pointer and keys as signs that the user is there. Calls are then the only
472
+ sign, so a session in which the user only reads can reach its idle time.
473
+ - Sibling subdomains share one sign-in only when they share a principal, so
474
+ every app passes the same `derivationOrigin`. A sibling whose browser holds
475
+ the shared record but no credential of its own reads as
476
+ `"signed-in-elsewhere"` (see [AuthState](#authstate)) and calls
477
+ anonymously. Taking that sign-in over without asking the user again needs
478
+ `prompt: "none"` and `hint`, which are options of the constructor, on a
479
+ redirect route: see `@icp-sdk/auth`'s documentation.
480
+ - With `transport: "redirect"` the page itself goes to Internet Identity and
481
+ comes back, so `AuthClient` asks for `signIn()` to be called on the page's
482
+ load, not from a click, on a route of its own for each flow: see
483
+ [Redirect sign-in](#redirect-sign-in).
484
+
485
+ ## Any other sign-in: AuthLike
486
+
487
+ An `AuthLike` is six methods and an optional `dispose`:
488
+
489
+ ```ts nocheck
490
+ interface AuthLike {
491
+ getPrincipal(): { toText(): string } | undefined
492
+ getStatus(): {
493
+ readonly state:
494
+ | "signed-in"
495
+ | "signed-in-elsewhere"
496
+ | "expired"
497
+ | "signed-out"
498
+ // A state a later @icp-sdk/auth adds: the client calls anonymously.
499
+ | (string & {})
500
+ readonly expiresAtMs?: number // when the session ends, as Date.now() counts
501
+ }
502
+ getIdentity(): Promise<Identity>
503
+ subscribe(listener: () => void): () => void
504
+ signIn(options?: unknown): Promise<unknown>
505
+ signOut(options?: unknown): Promise<unknown>
506
+ dispose?(): void
507
+ }
508
+ ```
509
+
510
+ The client reads `getStatus()` and `getPrincipal()` synchronously. It calls
511
+ `getIdentity()` only when it builds or checks an agent for a signed-in
512
+ principal, and it reads both again after every `subscribe()` notification.
513
+ Only the state `"signed-in"` makes the client call as `getPrincipal()`. Every
514
+ other state calls as the anonymous principal.
515
+
516
+ `expiresAtMs` is optional. When the status carries it while `"signed-in"` or
517
+ `"signed-in-elsewhere"`, the client sets a timer for it and reads the status
518
+ again then, so an `AuthLike` whose status turns `"expired"` by the clock need
519
+ not notify for it. A deadline that has passed while the status still says
520
+ `"signed-in"` sets no timer. And whenever `client.caller()` or
521
+ `client.authState()` reads a change no notification announced, the client
522
+ tells its listeners in a microtask.
523
+
524
+ `getIdentity()` should return the same object until the identity really
525
+ changes. The client builds a new agent for every new identity object it is
526
+ handed, and reads a new object for the same principal as a renewal.
527
+
528
+ Any other sign-in that hands over an `Identity` fits with a small adapter:
529
+ one that gives a delegation (a hand-rolled session, or Internet Identity
530
+ through a client other than `AuthClient`) or a key (a local dev account).
531
+ This is the one in the guide, `packages/core/llms.txt`:
532
+
533
+ ```ts
534
+ import type { AuthLike } from "@ic-reactor/core"
535
+ import type { Identity } from "@icp-sdk/core/agent"
536
+
537
+ export interface SignInSource {
538
+ getIdentity(): Identity // anonymous while signed out
539
+ isAuthenticated(): boolean
540
+ login(): Promise<void>
541
+ logout(): Promise<void>
542
+ subscribe(listener: () => void): () => void
543
+ }
544
+
545
+ export function toAuthLike(source: SignInSource): AuthLike {
546
+ const signedIn = () =>
547
+ source.isAuthenticated() &&
548
+ !source.getIdentity().getPrincipal().isAnonymous()
549
+ return {
550
+ getPrincipal: () =>
551
+ signedIn() ? source.getIdentity().getPrincipal() : undefined,
552
+ getStatus: () => ({ state: signedIn() ? "signed-in" : "signed-out" }),
553
+ getIdentity: async () => source.getIdentity(),
554
+ subscribe: (listener) => source.subscribe(listener),
555
+ signIn: () => source.login(),
556
+ signOut: () => source.logout(),
557
+ }
558
+ }
559
+ ```
560
+
561
+ One client has one `auth`. To offer two sign-in sources, write one `AuthLike`
562
+ that holds both and picks one from the options of `signIn`. The Vite wallet's
563
+ `src/auth/wallet-auth.ts` does this for Internet Identity and a local dev
564
+ account.
565
+
566
+ ### Wallets that sign each call
567
+
568
+ A wallet used through ICRC-25, ICRC-27 and ICRC-49 (OISY, Plug, an NFID
569
+ account) signs each call: the user approves it in the wallet, which signs and
570
+ sends it, and the app never holds an `Identity`. Used this way, the wallet is
571
+ not an `AuthLike`, and the client cannot send as it. (A wallet that also
572
+ speaks ICRC-34 can hand the app a delegation instead, from
573
+ `signer.requestDelegation()`; a `DelegationIdentity` made from it is an
574
+ `Identity`, and an `AuthLike` can hold it as for Internet Identity above.) Keep the client for reads, anonymous (a ledger's balances are
575
+ public; `SignerAgent` would send each read to the wallet for approval too),
576
+ and send the wallet's writes through `SignerAgent` from `@icp-sdk/signer`,
577
+ then invalidate the reads yourself:
578
+
579
+ ```ts
580
+ // src/wallet.ts: needs @icp-sdk/signer, @icp-sdk/canisters and @dfinity/utils
581
+ import { createClient } from "@ic-reactor/core"
582
+ import { IcrcLedgerCanister } from "@icp-sdk/canisters/ledger/icrc"
583
+ import { Principal } from "@icp-sdk/core/principal"
584
+ import { Signer } from "@icp-sdk/signer"
585
+ import { SignerAgent } from "@icp-sdk/signer/agent"
586
+ import { PostMessageTransport } from "@icp-sdk/signer/web"
587
+ import { actor, type Actor } from "./generated/icrc1"
588
+
589
+ const LEDGER = "ryjl3-tyaaa-aaaaa-aaaba-cai"
590
+
591
+ // Reads: the client, anonymous.
592
+ export const client = createClient({ network: "ic", identity: "anonymous" })
593
+ export const ledger = client.canister<Actor>(actor, { id: LEDGER })
594
+
595
+ type Account = Awaited<ReturnType<Signer["getAccounts"]>>[number]
596
+
597
+ // The wallet's window may open only in a click handler: call connect()
598
+ // straight from a "Connect" button's onClick, before any await.
599
+ export async function connect(
600
+ // A wallet may share several accounts (NFID does): let the user pick one.
601
+ choose: (
602
+ accounts: Account[]
603
+ ) => Account | undefined | Promise<Account | undefined> = (accounts) =>
604
+ accounts[0]
605
+ ) {
606
+ const signer = new Signer({
607
+ transport: new PostMessageTransport({ url: "https://oisy.com/sign" }),
608
+ // Keep the channel open between the requests of one session.
609
+ autoCloseTransportChannel: false,
610
+ })
611
+ try {
612
+ // ICRC-27: the accounts the user shares. A wallet that lacks it cannot
613
+ // be used this way; signer.getSupportedStandards() says which it has.
614
+ const account = await choose(await signer.getAccounts())
615
+ if (!account) throw new Error("the wallet shared no account")
616
+ const agent = await SignerAgent.create({ signer, account: account.owner })
617
+ const wallet = IcrcLedgerCanister.create({
618
+ agent,
619
+ canisterId: Principal.fromText(LEDGER),
620
+ })
621
+ // The whole account: its subaccount, if any, is the one to debit. Call
622
+ // disconnect() when the session ends, or before connecting again: it
623
+ // closes the wallet's window, which stays open otherwise.
624
+ return { account, wallet, disconnect: () => signer.closeChannel() }
625
+ } catch (error) {
626
+ // Cancelled or failed: close the window the request opened.
627
+ await signer.closeChannel()
628
+ throw error
629
+ }
630
+ }
631
+
632
+ // Writes: through the wallet, which shows each call to the user.
633
+ export async function send(
634
+ { account, wallet }: Awaited<ReturnType<typeof connect>>,
635
+ to: Principal,
636
+ amount: bigint,
637
+ // Nanoseconds since the epoch, BigInt(Date.now()) * 1_000_000n, fixed
638
+ // per transfer so a re-send is deduplicated.
639
+ createdAt: bigint
640
+ ) {
641
+ try {
642
+ return await wallet.transfer({
643
+ // Without it the ledger debits the owner's default subaccount.
644
+ from_subaccount: account.subaccount,
645
+ to: { owner: to, subaccount: [] },
646
+ amount,
647
+ created_at_time: createdAt,
648
+ })
649
+ } finally {
650
+ // The client did not send this write, so it cannot invalidate for it.
651
+ await client.queryClient.invalidateQueries({
652
+ queryKey: client.queryKey(ledger),
653
+ })
654
+ }
655
+ }
656
+ ```
657
+
658
+ What the client gives a write does not reach this one: no `ReactorError`, no
659
+ `mayHaveExecuted`, no invalidation of its own. Read the failure yourself:
660
+
661
+ - A `SignerError` (from `@icp-sdk/signer`) with ICRC-25's code `3001`, action
662
+ aborted, is the user's refusal: nothing was sent.
663
+ - A ledger `Err` (`IcrcTransferError` from `@icp-sdk/canisters`) means the
664
+ ledger answered and did not move the funds.
665
+ - Anything else after the user approved, a closed wallet window included, can
666
+ mean the transfer ran. Read the balance, or send the same transfer again
667
+ with the same `created_at_time`, which the ledger answers `Duplicate` if
668
+ the first went through.
669
+
670
+ Show the wallet's account (`account.owner`, and its subaccount when it has
671
+ one) as the user's, not `useAuth()`'s principal, which stays anonymous. A wallet that is a browser extension (Plug) connects with
672
+ `BrowserExtensionTransport` from `@icp-sdk/signer/extension` instead.
673
+ `@icp-sdk/signer` peers only `@icp-sdk/core` 6, so it installs beside the
674
+ client. NFID IdentityKit 2.0 does not: it peers `@icp-sdk/auth` 5, and npm
675
+ refuses it beside the `@icp-sdk/auth` 10 the client uses.
676
+
677
+ ## AuthState
678
+
679
+ `client.authState()` and `useAuth()` give an `AuthState`: a `status`, a
680
+ `principal` and, while signed in, `expiresAt`.
681
+
682
+ | The auth says | `status` | `principal` |
683
+ | --------------------- | ----------------------- | -------------------- |
684
+ | `signed-in` | `"signed-in"` | the signed-in user's |
685
+ | `signed-out` | `"anonymous"` | `2vxsx-fae` |
686
+ | `expired` | `"expired"` | `2vxsx-fae` |
687
+ | `signed-in-elsewhere` | `"signed-in-elsewhere"` | `2vxsx-fae` |
688
+
689
+ `principal` is the principal calls go out as, so in every state but
690
+ `"signed-in"` it is the anonymous principal, and a check such as
691
+ `principal !== "2vxsx-fae"` means what it looks like. An expired session
692
+ and one signed in on a sibling origin cannot sign a call, so they do not name
693
+ their principal. To say whose session ended, read the auth's own
694
+ `getStatus()`, which keeps it. For that you need your own reference to the
695
+ `AuthClient` (see
696
+ [Your own reference to the AuthClient](#your-own-reference-to-the-authclient)),
697
+ because the client does not expose its auth.
698
+
699
+ `expiresAt` is when the session ends, in milliseconds since the epoch (as
700
+ `Date.now()` counts; `new Date(expiresAt)` for a date), so you can show
701
+ "signed in until". It is there only while `status` is `"signed-in"` through an
702
+ auth whose `getStatus()` carries `expiresAtMs`, as `AuthClient` 10's does.
703
+ When that time passes, the status turns `"expired"` and listeners are told.
704
+
705
+ A client built with `identity` reports `"signed-in"` with that identity's
706
+ principal, or `"anonymous"` for `"anonymous"` and for an explicit
707
+ `AnonymousIdentity`, with no `expiresAt`. A client on a server reports
708
+ `"anonymous"`.
709
+
710
+ <Aside type="caution" title="Signed in may be read-only">
711
+ Since `@icp-sdk/auth` 10.0.0, `AuthClient` acts for sessions that Internet
712
+ Identity scoped to queries only. Such a session reports `"signed-in"`, and the
713
+ network refuses its updates. `@icp-sdk/auth` does not expose the scope yet, so
714
+ `AuthState` cannot tell the two apart: `"signed-in"` means calls are signed by
715
+ `principal`, not that a write will be accepted. Handle an update's rejection
716
+ as you would any other.
717
+ </Aside>
718
+
719
+ ## useAuth
720
+
721
+ `useAuth()` returns the `AuthState` plus `signIn` and `signOut`:
722
+
723
+ ```tsx
724
+ import { useAuth } from "@ic-reactor/react"
725
+
726
+ export function SessionButton() {
727
+ const { status, principal, signIn, signOut } = useAuth()
728
+ if (status === "signed-in") {
729
+ return (
730
+ <button onClick={() => signOut().catch(console.error)}>
731
+ Sign out {principal}
732
+ </button>
733
+ )
734
+ }
735
+ return (
736
+ <>
737
+ {status === "expired" && <p>Your session expired.</p>}
738
+ <button onClick={() => signIn().catch(console.error)}>Sign in</button>
739
+ </>
740
+ )
741
+ }
742
+ ```
743
+
744
+ - A component that calls it renders once for each change of `status`,
745
+ `principal` or `expiresAt`, and never otherwise. A renewed delegation does
746
+ not render it. A session that ends by the clock renders it with
747
+ `"expired"` when it ends.
748
+ - The object it returns is the same until one of them changes, so it is safe
749
+ in a dependency array or as a prop of a memoized child.
750
+ - It is `"anonymous"` on a server and during a hydrating render, even when the
751
+ browser holds a session, so the HTML matches the server's. The component
752
+ renders again with the real state right after hydration. Show the same thing
753
+ signed out and while the session is read. See
754
+ [SSR and hydration](/v4/guides/ssr/).
755
+ - It throws outside a `ReactorProvider`.
756
+
757
+ `signIn` and `signOut` return a promise, and the promise can reject:
758
+
759
+ - on a client built with `identity`, with a `TypeError`: there is no sign-in;
760
+ - on a server, and after `client.dispose()`, with an `Error`;
761
+ - with what the auth factory threw, when it threw, or a `TypeError` when it
762
+ returned something other than an auth;
763
+ - with whatever the auth rejects with, never a `ReactorError`. `AuthClient`
764
+ rejects when the user closes Internet Identity's window or the browser
765
+ blocks it, and rejects a sign-in that a later sign-in or sign-out took over
766
+ from with a `SupersededError`, which you can usually ignore.
767
+
768
+ Always catch them, as the examples do.
769
+
770
+ ```tsx
771
+ import { useAuth } from "@ic-reactor/react"
772
+ import { SupersededError } from "@icp-sdk/auth/client"
773
+ import { useState } from "react"
774
+
775
+ export function SignInButton() {
776
+ const { signIn } = useAuth()
777
+ const [failure, setFailure] = useState<string>()
778
+ return (
779
+ <>
780
+ <button
781
+ onClick={() =>
782
+ signIn().catch((error: unknown) => {
783
+ if (error instanceof SupersededError) return
784
+ setFailure(error instanceof Error ? error.message : String(error))
785
+ })
786
+ }
787
+ >
788
+ Sign in
789
+ </button>
790
+ {failure !== undefined && <p role="alert">{failure}</p>}
791
+ </>
792
+ )
793
+ }
794
+ ```
795
+
796
+ Outside React, `client.authState()` is the same state, and
797
+ `client.subscribe(listener)` calls `listener` once after each change of it.
798
+ It returns a function that stops listening.
799
+
800
+ ```ts
801
+ import { client } from "./ledger"
802
+
803
+ const stop = client.subscribe(() => {
804
+ const { status, principal } = client.authState()
805
+ console.log(`caller is now ${principal} (${status})`)
806
+ })
807
+
808
+ // later
809
+ stop()
810
+ ```
811
+
812
+ ## When the caller changes
813
+
814
+ | Question | Answer |
815
+ | ---------------------- | ----------------------------------------------------------------------- |
816
+ | the caller's principal | `useAuth().principal`, `client.caller()` (`2vxsx-fae` unless signed in) |
817
+ | may a write be sent | `useAuth().status === "signed-in"`; the client refuses the rest itself |
818
+ | when did it change | `useAuth()` re-renders; `client.subscribe(fn)` |
819
+
820
+ A `"signed-in"` session may still be read-only (see [AuthState](#authstate)).
821
+
822
+ A call goes out as the principal that was current when it was made, or not at
823
+ all. The client keeps one agent per principal and never points an agent at
824
+ another identity. What that means in practice:
825
+
826
+ - **Components.** `useClient()` re-renders its component on a sign-in, a switch
827
+ of account and a sign-out, and returns a new object for the new caller, so
828
+ the options it builds in that render use the new caller's keys, and a
829
+ `useMemo` or effect that lists it in its dependencies (or React Compiler's
830
+ cache) builds them again. A change of status that keeps the caller (a
831
+ session that expired, one signed in elsewhere) renders nothing, because
832
+ both already called anonymously. Call `useClient()` in the body of each
833
+ component that builds options, on every render.
834
+ - **Reads in flight.** A read started for the old caller is cancelled when
835
+ someone else is current, before anything is sent. It fails with
836
+ `kind: "cancelled"` and `code: "caller_changed"`, and it never lands in the
837
+ new caller's key. Treat this error as "ignore" (see
838
+ [Errors](/v4/guides/errors/)).
839
+ - **Writes.** A write goes out as the caller current when `mutate()` was
840
+ called, or not at all. When TanStack Query holds it back (offline, or
841
+ queued behind another mutation of its `scope`) and the account changes in
842
+ between, it fails with `kind: "cancelled"`, `code: "caller_changed"` and
843
+ `mayHaveExecuted: false`, and nothing is sent. Built from a render's
844
+ `useClient()`, its options also send only as that render's caller: a press
845
+ handled before a switch reached the render is refused the same way. A
846
+ re-send `client.resendOf()` offered is refused as `outcome_unknown` with
847
+ `mayHaveExecuted: true` instead, since the write it re-sends may have run. If
848
+ nobody is signed in, the client refuses it before sending:
849
+ `kind: "unauthenticated"`, code `anonymous_write`.
850
+ - **Data.** After a sign-in, a sign-out or a switch, the new keys are empty
851
+ until they load. A sign-out, an expired session or a switch also removes
852
+ the previous principal's reads from the client's cache before your
853
+ components re-render, so the next person in the same browser cannot read
854
+ them back. The anonymous reads stay. Do not use
855
+ `placeholderData: keepPreviousData` or an `initialData` taken from another
856
+ key: it would show one principal's data to another. A persister restores
857
+ what it saved, whoever is signed in by then: on a page people share,
858
+ persist only the anonymous reads, with a
859
+ `dehydrateOptions.shouldDehydrateQuery` that checks that the key's caller
860
+ (its third segment) is `2vxsx-fae`.
861
+
862
+ A read that waits for a user uses `skipToken` (see
863
+ [Reads](/v4/guides/reads/)):
864
+
865
+ ```tsx
866
+ import { principal } from "@meantjs/schema"
867
+ import { useClient, useAuth } from "@ic-reactor/react"
868
+ import { skipToken, useQuery } from "@tanstack/react-query"
869
+ import { actor, type Actor } from "./generated/icrc1"
870
+
871
+ export function MyBalance() {
872
+ const client = useClient()
873
+ const { status, principal: caller } = useAuth()
874
+ const ledger = client.canister<Actor>(actor, {
875
+ id: "ryjl3-tyaaa-aaaaa-aaaba-cai",
876
+ })
877
+ const balance = useQuery(
878
+ client.queryOptions(
879
+ ledger,
880
+ "icrc1_balance_of",
881
+ status === "signed-in"
882
+ ? { owner: principal(caller), subaccount: null }
883
+ : skipToken
884
+ )
885
+ )
886
+ if (status !== "signed-in") return <p>Sign in to see your balance.</p>
887
+ return <p>{balance.data?.toString() ?? "…"}</p>
888
+ }
889
+ ```
890
+
891
+ ## Identity attributes
892
+
893
+ Internet Identity can sign attributes about the user for your canister, such
894
+ as their name and an email address. The canister reads them from a call that
895
+ carries them, and they reach it in three steps:
896
+
897
+ 1. Your canister issues a nonce: an update call to
898
+ `_internet_identity_sign_in_start`, made as the anonymous principal, which
899
+ returns a `blob`.
900
+ 2. The app signs in and asks for the attributes with that nonce. Started
901
+ together, they are one Internet Identity interaction for the user. The
902
+ answer is the attributes, Candid-encoded, as `data`, and Internet
903
+ Identity's `signature` over them.
904
+ 3. The app calls `_internet_identity_sign_in_finish` as the signed-in user,
905
+ with `data` and `signature` attached to the call as its `sender_info`. The
906
+ canister checks them and keeps what it needs.
907
+
908
+ DFINITY's `identity-attributes` library adds both methods to a canister and
909
+ makes the checks: [`mo:identity-attributes`](https://github.com/dfinity/identity-attributes/tree/main/motoko)
910
+ for Motoko, a mixin you `include`, and the
911
+ [`identity-attributes`](https://github.com/dfinity/identity-attributes/tree/main/rust)
912
+ crate for Rust, `#[identity_attributes]`. Both answer with the same Candid, so
913
+ the app's side below works with either. Their READMEs say how to set the
914
+ canister up. They pair the library with `@icp-sdk/auth` 7, whose
915
+ `requestAttributes` takes the nonce as a promise; in 10 it takes a function
916
+ that returns one, as below.
917
+
918
+ The app's client calls every update as the signed-in user and attaches
919
+ nothing to a call, so steps 1 and 3 each go through a second client on the
920
+ same network, built for that one call and disposed after it:
921
+
922
+ - Step 1 through a client built with `new AnonymousIdentity()` from
923
+ `@icp-sdk/core/agent`, which may send an update as the anonymous principal.
924
+ A client built with `identity: "anonymous"`, like a signed-out one, refuses
925
+ an update before it sends it.
926
+ - Step 3 through a client built with an `AttributesIdentity` from
927
+ `@icp-sdk/core/identity`, which attaches `data` and `signature` to each call
928
+ it signs.
929
+
930
+ Step 2 needs the `AuthClient` itself, which the client does not hand out, so
931
+ you keep your own reference to it.
932
+
933
+ ### Your own reference to the AuthClient
934
+
935
+ Keep what each client's factory builds, beside the client:
936
+
937
+ ```ts
938
+ import { createClient, type Client } from "@ic-reactor/core"
939
+ import { AuthClient } from "@icp-sdk/auth/client"
940
+
941
+ /** The app's network, for its client and the clients built beside it. */
942
+ export const network = "ic"
943
+
944
+ /** Internet Identity's canister, where the factory is handed no provider. */
945
+ const INTERNET_IDENTITY = "rdmx6-jaaaa-aaaaa-aaadq-cai"
946
+
947
+ interface Built {
948
+ /**
949
+ * The client itself, whose keys are the live caller's. A view of it that
950
+ * `useClient()` returns keys reads by the caller of the render it came from.
951
+ */
952
+ readonly client: Client
953
+ readonly authClient: AuthClient
954
+ /** The canister that mints the sign-in, which signs the attributes too. */
955
+ readonly signer: string
956
+ }
957
+
958
+ // Keyed by the client's QueryClient, which every view of the client that
959
+ // `useClient()` returns shares: a view is an object of its own.
960
+ const builtBy = new WeakMap<Client["queryClient"], () => Built | undefined>()
961
+
962
+ /** What `client`'s auth factory built, once it has run. */
963
+ export const getAuthClient = (client: Client) =>
964
+ builtBy.get(client.queryClient)?.()
965
+
966
+ export function createAppClient(): Client {
967
+ let built: Built | undefined
968
+ const client: Client = createClient({
969
+ network,
970
+ auth: (handed) => {
971
+ const authClient = new AuthClient({ ...handed, openIdProvider: "google" })
972
+ built = {
973
+ client,
974
+ authClient,
975
+ signer: handed.identityProvider?.canisterId ?? INTERNET_IDENTITY,
976
+ }
977
+ return authClient
978
+ },
979
+ })
980
+ builtBy.set(client.queryClient, () => built)
981
+ return client
982
+ }
983
+ ```
984
+
985
+ Hand it to the provider, `<ReactorProvider client={createAppClient}>`, or, in
986
+ an app with no server render, call it once in a module. The client still owns
987
+ the `AuthClient` and disposes it with itself. The factory runs in a browser,
988
+ on first use, so `getAuthClient(client)` is `undefined` on a server and until
989
+ the client has built its auth. In a component, pass it what `useClient()`
990
+ returns: that is a view of the provider's client, another object, but it has
991
+ the client's `queryClient`, which the map is keyed by.
992
+
993
+ ### Sign in with attributes
994
+
995
+ ```ts
996
+ import { createClient, type Canister, type Client } from "@ic-reactor/core"
997
+ import { scopedKeys } from "@icp-sdk/auth/client"
998
+ import { AnonymousIdentity, type Identity } from "@icp-sdk/core/agent"
999
+ import { AttributesIdentity } from "@icp-sdk/core/identity"
1000
+ import { Principal } from "@icp-sdk/core/principal"
1001
+ import { getAuthClient, network } from "./auth-client"
1002
+ import { actor, type Actor as Accounts } from "./generated/accounts"
1003
+
1004
+ const ACCOUNTS_ID = "be2us-64aaa-aaaaa-qaabq-cai"
1005
+
1006
+ /** One call to the accounts canister as `identity`, through a client of its own. */
1007
+ async function callAs<T>(
1008
+ identity: Identity,
1009
+ call: (accounts: Canister<Accounts>) => Promise<T>
1010
+ ): Promise<T> {
1011
+ const client = createClient({ network, identity })
1012
+ try {
1013
+ return await call(client.canister<Accounts>(actor, { id: ACCOUNTS_ID }))
1014
+ } finally {
1015
+ client.dispose()
1016
+ }
1017
+ }
1018
+
1019
+ /**
1020
+ * Signs in, has the accounts canister verify the user's name and email, and
1021
+ * returns what Internet Identity signed.
1022
+ */
1023
+ export async function signInWithAttributes(app: Client) {
1024
+ // Builds the auth if the client has not yet, and opens Internet Identity.
1025
+ const signedIn = app.signIn()
1026
+ const built = getAuthClient(app)
1027
+ if (built === undefined) {
1028
+ await signedIn // on a server it rejects, and says why
1029
+ throw new Error("This client was not built by createAppClient")
1030
+ }
1031
+ const { client, authClient, signer } = built
1032
+
1033
+ // 1 and 2: the nonce, and the attributes in the same interaction.
1034
+ const [, attributes] = await Promise.all([
1035
+ signedIn,
1036
+ authClient.requestAttributes({
1037
+ keys: scopedKeys({
1038
+ openIdProvider: "google",
1039
+ keys: ["name", "verified_email"],
1040
+ }),
1041
+ nonce: () =>
1042
+ callAs(new AnonymousIdentity(), (accounts) =>
1043
+ accounts._internet_identity_sign_in_start()
1044
+ ),
1045
+ }),
1046
+ ])
1047
+
1048
+ // 3: the finish call, with the attributes as its sender_info.
1049
+ const identity = new AttributesIdentity({
1050
+ inner: await authClient.getIdentity(),
1051
+ attributes,
1052
+ signer: { canisterId: Principal.fromText(signer) },
1053
+ })
1054
+ await callAs(identity, (accounts) =>
1055
+ accounts._internet_identity_sign_in_finish()
1056
+ )
1057
+
1058
+ // The app's client did not send that write, so it cannot invalidate for it.
1059
+ // The key is the client's, for the user now signed in: `app` may be a view
1060
+ // from a render before the sign-in, whose keys are the anonymous caller's.
1061
+ await client.queryClient.invalidateQueries({
1062
+ queryKey: client.queryKey(
1063
+ client.canister<Accounts>(actor, { id: ACCOUNTS_ID })
1064
+ ),
1065
+ })
1066
+ return attributes
1067
+ }
1068
+ ```
1069
+
1070
+ This imports `./auth-client`, the module above, and `./generated/accounts`,
1071
+ the module `meant gen` writes for the accounts canister's `.did`.
1072
+
1073
+ - Call it straight from a click handler, with no `await` before it:
1074
+ Internet Identity's window opens only inside a click. Catch it as you catch
1075
+ `signIn()`.
1076
+ - That is the window transport. With `transport: "redirect"`, `AuthClient`
1077
+ asks for `signIn()` and `requestAttributes()` to be called on the page's
1078
+ load, not from a click, each flow on a route of its own (see
1079
+ [Redirect sign-in](#redirect-sign-in)). So call it on each load of that
1080
+ route: `requestAttributes()` keeps the nonce across the loads, so the
1081
+ canister issues one.
1082
+ - For a user who is signed in already, skip the sign-in: call
1083
+ `authClient.requestAttributes()` alone, with a new nonce, then the finish
1084
+ call.
1085
+ - A failure after the sign-in leaves the user signed in without the
1086
+ attributes, so offer to try again.
1087
+ - `_internet_identity_sign_in_finish` answers `variant { ok; err : … }`, so
1088
+ attributes the canister refuses reject as a `canister_err` whose `err.tag`
1089
+ says why (see [Errors](/v4/guides/errors/)). On `Stale` or `UnknownNonce`,
1090
+ ask for them again, with a new nonce. A signer the canister does not trust,
1091
+ or a canister with no `trusted_attribute_signers`, traps instead: a
1092
+ `rejected` error with reject code 5.
1093
+ - The signer is the canister that minted the sign-in: Internet Identity's,
1094
+ `rdmx6-jaaaa-aaaaa-aaadq-cai`, on mainnet and in icp-cli's built-in one, or
1095
+ the `identityProvider` canister the factory is handed. The accounts canister
1096
+ must list it in `trusted_attribute_signers`.
1097
+
1098
+ ### Which attributes to ask for
1099
+
1100
+ | Key | What it is |
1101
+ | ---------------- | ----------------------------------------------------------------------------------------------- |
1102
+ | `name` | The name on the account the user signed in with |
1103
+ | `email` | An email address from that account. Internet Identity does not check it: treat it as user input |
1104
+ | `verified_email` | Present only when Internet Identity established that the user controls the address |
1105
+
1106
+ Grant access on `verified_email`, not `email`. `scopedKeys` from
1107
+ `@icp-sdk/auth/client` scopes keys to the provider of a one-click sign-in, so
1108
+ the user shares them in the same step:
1109
+ `scopedKeys({ openIdProvider: "google", keys: ["verified_email"] })` is
1110
+ `["openid:https://accounts.google.com:verified_email"]`. An organization's
1111
+ SSO is the exception: `scopedKeys({ ssoDomain })` gives `sso:<domain>:name`
1112
+ and `sso:<domain>:email`, with no `verified_email`, and the library takes the
1113
+ email from `sso:<domain>:email` only for a domain the canister lists in
1114
+ `trusted_sso_domains`.
1115
+
1116
+ <Aside type="caution" title="The canister checks, not the app">
1117
+ What the app holds is not proof. Any canister can sign attributes, so your
1118
+ canister must check that Internet Identity signed them, that their origin is
1119
+ your app's, and that their nonce is one it issued and has not used, within a
1120
+ few minutes. The `identity-attributes` library makes these checks; its README
1121
+ says how to configure them (`trusted_attribute_signers`, `frontend_origins`,
1122
+ `trusted_sso_domains`).
1123
+ </Aside>
1124
+
1125
+ ### Show what the user shared
1126
+
1127
+ `signInWithAttributes` returns what Internet Identity signed. Its `data` is a
1128
+ Candid-encoded ICRC-3 `Value`: a `Map` of the requested keys, plus
1129
+ `implicit:nonce`, `implicit:origin` and `implicit:issued_at_timestamp_ns`. A
1130
+ scoped key stays scoped in the map. To show the user what they shared,
1131
+ describe that type with `@meantjs/schema`'s builders and read it with
1132
+ `decode`:
1133
+
1134
+ ```ts
1135
+ import { c, type Schema } from "@meantjs/schema"
1136
+ import { decode } from "@meantjs/schema/codec"
1137
+
1138
+ type Icrc3Value =
1139
+ | { tag: "Nat"; value: bigint }
1140
+ | { tag: "Int"; value: bigint }
1141
+ | { tag: "Blob"; value: Uint8Array }
1142
+ | { tag: "Text"; value: string }
1143
+ | { tag: "Array"; value: Icrc3Value[] }
1144
+ | { tag: "Map"; value: Array<[string, Icrc3Value]> }
1145
+
1146
+ const Icrc3Value: Schema<Icrc3Value> = c.rec(() =>
1147
+ c.variant({
1148
+ Nat: c.nat,
1149
+ Int: c.int,
1150
+ Blob: c.blob(),
1151
+ Text: c.text,
1152
+ Array: c.vec(Icrc3Value),
1153
+ Map: c.vec(c.tuple([c.text, Icrc3Value])),
1154
+ })
1155
+ )
1156
+
1157
+ /** The text the attributes hold under `key`, for display. */
1158
+ export function readAttribute(data: Uint8Array, key: string) {
1159
+ const decoded = decode(Icrc3Value, data) // never throws
1160
+ if (!decoded.ok) throw new Error(decoded.issues[0]?.message)
1161
+ const value = decoded.value as Icrc3Value // `decode` checked it against the schema
1162
+
1163
+ if (value.tag !== "Map") return undefined
1164
+ const entry = value.value.find(([name]) => name === key)
1165
+ return entry?.[1].tag === "Text" ? entry[1].value : undefined
1166
+ }
1167
+ ```
1168
+
1169
+ `readAttribute(attributes.data, "openid:https://accounts.google.com:name")`
1170
+ is the name the user shared.
1171
+
1172
+ ## See also
1173
+
1174
+ - [The client](/v4/guides/client/): `identity` and `auth`, networks, `dispose`.
1175
+ - [SSR and hydration](/v4/guides/ssr/): `useAuth()` and `useClient()` while a
1176
+ page hydrates.
1177
+ - [Errors](/v4/guides/errors/): `unauthenticated` and `cancelled`.
1178
+ - [Testing](/v4/guides/testing/): `createTestClient()` has a test auth you can
1179
+ sign in, switch and expire.
1180
+ - [Vite wallet](/v4/examples/vite-wallet/): Internet Identity, a dev account
1181
+ and one client.