@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,1079 @@
1
+ /**
2
+ * One error type for every failure an ic-reactor call reports, and the
3
+ * classifier that turns what `@icp-sdk/core` throws into it.
4
+ *
5
+ * The question a UI has to answer after a failed write is not "what went
6
+ * wrong" but "did it happen anyway". Every {@link ReactorError} therefore
7
+ * carries `mayHaveExecuted`, derived here from the failure and the call mode
8
+ * so that no application has to read reject codes or HTTP statuses itself.
9
+ *
10
+ * Only {@link ReactorError}, {@link ReactorErrorKind} and
11
+ * {@link isReactorError} are part of the package entry. Everything else in
12
+ * this module is internal and exported only for the client that builds on it.
13
+ *
14
+ * @module
15
+ */
16
+ import { MANAGEMENT_CANISTER } from "./management.js"
17
+ import { isServer } from "./runtime.js"
18
+ import type { Canister, ErrorOf } from "./types.js"
19
+
20
+ /**
21
+ * What kind of failure a {@link ReactorError} reports.
22
+ *
23
+ * - `invalid_args`: the arguments could not be encoded, or the target canister
24
+ * id could not be resolved. Nothing was sent.
25
+ * - `unauthenticated`: an update was attempted while not signed in. Nothing was
26
+ * sent.
27
+ * - `not_delivered`: nothing that matters ran. Either the request was refused
28
+ * or never taken in (the replica or a boundary node turned it away, or the
29
+ * system could not take it in), or it was a query, which changes nothing, and
30
+ * no answer came back. A failed query may well have reached the canister,
31
+ * so `mayHaveExecuted` carries the guarantee: it is `false` on every
32
+ * `not_delivered`, because a refused update never ran and a query changes
33
+ * nothing.
34
+ * - `outcome_unknown`: an update went out and no trustworthy answer came back,
35
+ * so the canister may or may not have run it. So does a re-send of a write
36
+ * `client.resendOf()` offered that did not run, refused before it went out
37
+ * or turned away: the write it re-sends may have run all the same. Its
38
+ * `code`, `httpStatus` and `rejectCode` say why the re-send did not run
39
+ * (such as `caller_changed`, `target_changed` or `arg_changed`), and its
40
+ * `cause` is the re-send's own error.
41
+ * - `rejected`: the IC or the canister rejected the call; `rejectCode` says which.
42
+ * - `invalid_reply`: a reply arrived but did not decode as the method's result.
43
+ * - `canister_err`: the canister ran the call and replied with the `Err` arm of
44
+ * its result; `err` is typed. The outcome is that answer, so
45
+ * `mayHaveExecuted` is `false`: re-sending is a new decision, not a retry.
46
+ * - `cancelled`: the caller abandoned the call (an aborted query, a key whose
47
+ * principal is no longer current, a call on a disposed client
48
+ * (`client_disposed`), a read or an unsent write whose `timeoutMs` passed
49
+ * (`timeout`), or an update aborted in flight). A write whose `timeoutMs` passed after its request went out
50
+ * is `outcome_unknown` (`timeout`) instead.
51
+ * `mayHaveExecuted` is `false` when nothing was sent, and `true` for an
52
+ * update aborted after its request may already have been delivered.
53
+ */
54
+ export type ReactorErrorKind =
55
+ | "invalid_args"
56
+ | "unauthenticated"
57
+ | "not_delivered"
58
+ | "outcome_unknown"
59
+ | "rejected"
60
+ | "invalid_reply"
61
+ | "canister_err"
62
+ | "cancelled"
63
+
64
+ type ReactorErrorBase = Error & {
65
+ readonly name: "ReactorError"
66
+ /**
67
+ * Whether the call may have taken effect although the caller cannot tell
68
+ * what it did. `true` is a warning, not a verdict: the IC or the network
69
+ * left the outcome open, so re-sending could run the call twice; read the
70
+ * state back before trying again. `false` means the outcome is known: the
71
+ * call was refused before it ran, or, for `canister_err`, the canister ran
72
+ * it and answered with its decision in `err` (a mutation still invalidates
73
+ * its reads after one, since a canister may change state before returning
74
+ * an `Err`).
75
+ */
76
+ readonly mayHaveExecuted: boolean
77
+ /** The Candid method that was called. */
78
+ readonly method: string
79
+ /** The target canister, as text. */
80
+ readonly canisterId: string
81
+ /**
82
+ * A machine-readable sub-reason within a `kind`, such as
83
+ * `"canister_id_unresolved"` for an unresolved `{ name }` target,
84
+ * `"anonymous_write"` for an update without a signed-in identity, or
85
+ * `"canister_not_found"` when the IC answered that the canister the request
86
+ * was routed to does not exist (for a call to `aaaaa-aa`, the canister its
87
+ * arguments name, while `canisterId` stays `aaaaa-aa`).
88
+ */
89
+ readonly code?: string
90
+ /** The IC reject code (1 to 6, or whatever the replica sent), when there was one. */
91
+ readonly rejectCode?: number
92
+ /** The HTTP status the replica or a boundary node answered with, when there was one. */
93
+ readonly httpStatus?: number
94
+ /** Which parts of the arguments or the reply failed to encode or decode. */
95
+ readonly issues?: readonly { code: string; path: string; message: string }[]
96
+ /** The error that caused this one, when there is one. */
97
+ readonly cause?: unknown
98
+ /**
99
+ * For a write that got no answer (`outcome_unknown`, or `cancelled` with
100
+ * `mayHaveExecuted: true`): the latest ingress expiry its sends were signed
101
+ * with, in nanoseconds since the epoch, on the IC's clock. Once the IC's
102
+ * time is past it, no send of this write can still start executing (the IC
103
+ * interface specification: the IC neither accepts a call nor moves it from
104
+ * `received` to `processing` past its `ingress_expiry`:
105
+ * https://docs.internetcomputer.org/references/ic-interface-spec/https-interface/).
106
+ * The expiry does not stop a send that started before it, so only for a
107
+ * method that commits without awaiting another canister is a certified
108
+ * read-back of later state that finds nothing final. The host's clock may
109
+ * differ from the IC's: compare with a margin. Absent on every other error.
110
+ * Not enumerable, so `JSON.stringify(error)` still works.
111
+ */
112
+ readonly expiresAt?: bigint
113
+ }
114
+
115
+ /**
116
+ * The error every ic-reactor call rejects with.
117
+ *
118
+ * Narrow on `kind`. For a method whose result has an `Err` arm, `E` is that
119
+ * arm's type, and `err` is typed `E` exactly when `kind` is `"canister_err"`
120
+ * (and `undefined` for every other kind). `E` defaults to `never`, which
121
+ * stands for a method without an `Err` arm: `err` is then always `undefined`.
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * try {
126
+ * await ledger.icrc1_transfer(args)
127
+ * } catch (e) {
128
+ * if (isReactorError(e) && e.mayHaveExecuted) {
129
+ * // Do not re-send: read the balance back first.
130
+ * }
131
+ * }
132
+ * ```
133
+ */
134
+ export type ReactorError<E = never> = [E] extends [never]
135
+ ? ReactorErrorBase & {
136
+ readonly kind: ReactorErrorKind
137
+ readonly err?: undefined
138
+ }
139
+ : ReactorErrorBase &
140
+ (
141
+ | {
142
+ readonly kind: Exclude<ReactorErrorKind, "canister_err">
143
+ readonly err?: undefined
144
+ }
145
+ | { readonly kind: "canister_err"; readonly err: E }
146
+ )
147
+
148
+ /**
149
+ * Brand on every error this module creates. `Symbol.for` returns the same
150
+ * symbol in every copy of the package, so a guard from one copy recognises an
151
+ * error thrown by another (a version range the package manager cannot dedupe,
152
+ * or a bundler that pre-bundles one importer and not the other), which
153
+ * `instanceof` cannot do.
154
+ */
155
+ const BRAND = Symbol.for("ic-reactor.ReactorError")
156
+
157
+ /**
158
+ * Marks an error as one that is safe to send again. Internal: it is not part
159
+ * of {@link ReactorError}. Shared across copies for the same reason as
160
+ * {@link BRAND}.
161
+ */
162
+ const RETRYABLE = Symbol.for("ic-reactor.ReactorError.retryable")
163
+
164
+ /**
165
+ * The canister object a call was made on, on every error a call made through
166
+ * one rejects with (see {@link fromCanister}). Internal: it is not part of
167
+ * {@link ReactorError}. Shared across copies for the same reason as
168
+ * {@link BRAND}.
169
+ */
170
+ const CANISTER = Symbol.for("ic-reactor.ReactorError.canister")
171
+
172
+ /**
173
+ * Whether `error` is a {@link ReactorError} that a call of `method` on
174
+ * `canister` rejected with. Narrows to `ReactorError<E>`, where `E` is the
175
+ * method's `Err` arm, and whose `method` is `method`: after a check on
176
+ * `kind === "canister_err"`, `err` is typed. For a method without an `Err`
177
+ * arm, `err` is `undefined`. When it is `false`, the error is only not that
178
+ * call's: it keeps every `kind`.
179
+ *
180
+ * The check is made at run time, not only in the types: it is `false` for an
181
+ * error from another method, from another canister object (the one made with
182
+ * `certified: true` is another object, and so is a canister of another
183
+ * client), and from a func reference, so it never narrows an error to the
184
+ * wrong `Err` type. `client.canister()` returns the same object for the same
185
+ * generated module and target, so the canister can be made again where the
186
+ * error is caught.
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * try {
191
+ * await ledger.icrc1_transfer(arg)
192
+ * } catch (error) {
193
+ * if (isReactorError(error, ledger, "icrc1_transfer") && error.kind === "canister_err") {
194
+ * error.err // the ledger's TransferError
195
+ * }
196
+ * }
197
+ * ```
198
+ */
199
+ export function isReactorError<A, M extends keyof A & string>(
200
+ error: unknown,
201
+ canister: Canister<A>,
202
+ method: M
203
+ ): error is ReactorError<ErrorOf<A, M>> & { readonly method: M }
204
+ /**
205
+ * Whether `error` is a {@link ReactorError}, including one created by another
206
+ * copy of this package. Narrows to `ReactorError<unknown>`: after a check on
207
+ * `kind === "canister_err"`, `err` is `unknown`. It can be passed point-free,
208
+ * as in `errors.filter(isReactorError)`: the index and the array an array
209
+ * method passes are not a canister and a method. This signature is listed
210
+ * after the three-argument one so that point-free use infers it.
211
+ */
212
+ export function isReactorError(error: unknown): error is ReactorError<unknown>
213
+ export function isReactorError(
214
+ error: unknown,
215
+ canister?: unknown,
216
+ method?: unknown
217
+ ): boolean {
218
+ const own = error as Record<PropertyKey, unknown>
219
+ return (
220
+ typeof error === "object" &&
221
+ error !== null &&
222
+ own[BRAND] === true &&
223
+ // With a canister object or a method name, the error must say it came
224
+ // from exactly that call, and either one alone is never enough. Other
225
+ // extra arguments are not this form's: passed point-free, as in
226
+ // `errors.filter(isReactorError)`, the guard is called with an index and
227
+ // an array, and stays the plain guard.
228
+ (typeof canister === "object" || typeof method === "string"
229
+ ? !!canister && own[CANISTER] === canister && own.method === method
230
+ : true)
231
+ )
232
+ }
233
+
234
+ /**
235
+ * Marks `error`, when it is a {@link ReactorError}, as one a call on
236
+ * `canister` rejected with, for the guard's three-argument form, and returns
237
+ * it. Without a canister (a func reference) nothing is marked. An error
238
+ * already marked keeps its first canister, as it keeps its `method` and
239
+ * `canisterId`.
240
+ */
241
+ export const fromCanister = (error: unknown, canister?: object): unknown => {
242
+ if (canister && isReactorError(error) && !(CANISTER in error)) {
243
+ Object.defineProperty(error, CANISTER, { value: canister })
244
+ }
245
+ return error
246
+ }
247
+
248
+ // ---------------------------------------------------------------------------
249
+ // Creating errors
250
+ // ---------------------------------------------------------------------------
251
+
252
+ type Issues = NonNullable<ReactorErrorBase["issues"]>
253
+
254
+ /** Whether a call reads (`query`) or writes (`update`). */
255
+ export type CallMode = "query" | "update"
256
+
257
+ /** Fields shared by every error the client creates itself. */
258
+ export interface ReactorErrorFields {
259
+ /** The Candid method that was called. */
260
+ readonly method: string
261
+ /** The target canister as text, or the `$unresolved:<name>` placeholder. */
262
+ readonly canisterId: string
263
+ /**
264
+ * A short, readable reason. It is appended to
265
+ * `[ic-reactor] <method> on <canisterId>: ` to form `message`. Each kind has
266
+ * a default.
267
+ */
268
+ readonly reason?: string
269
+ /** A machine-readable sub-reason: `ReactorError.code`. */
270
+ readonly code?: string
271
+ readonly issues?: Issues
272
+ readonly cause?: unknown
273
+ }
274
+
275
+ interface BuildInit extends ReactorErrorFields {
276
+ readonly kind: ReactorErrorKind
277
+ readonly mayHaveExecuted: boolean
278
+ readonly reason: string
279
+ readonly rejectCode?: number
280
+ readonly httpStatus?: number
281
+ readonly err?: unknown
282
+ readonly retryable?: boolean
283
+ }
284
+
285
+ class ReactorFailure extends Error {
286
+ declare readonly kind: ReactorErrorKind
287
+ declare readonly mayHaveExecuted: boolean
288
+ declare readonly method: string
289
+ declare readonly canisterId: string
290
+ declare readonly code?: string
291
+ declare readonly rejectCode?: number
292
+ declare readonly httpStatus?: number
293
+ declare readonly issues?: Issues
294
+ declare readonly err?: unknown
295
+ declare readonly cause?: unknown
296
+ declare readonly expiresAt?: bigint
297
+
298
+ constructor(init: BuildInit) {
299
+ super(`[ic-reactor] ${init.method} on ${init.canisterId}: ${init.reason}`)
300
+ // Absent fields stay absent (no own key), so `"err" in error` and
301
+ // `JSON.stringify` mean what they say.
302
+ const own: Record<string, unknown> = {
303
+ kind: init.kind,
304
+ mayHaveExecuted: init.mayHaveExecuted,
305
+ method: init.method,
306
+ canisterId: init.canisterId,
307
+ }
308
+ for (const key of ["code", "rejectCode", "httpStatus", "issues"]) {
309
+ const value = init[key as keyof BuildInit]
310
+ if (value !== undefined) own[key] = value
311
+ }
312
+ if (init.kind === "canister_err") own.err = init.err
313
+ Object.assign(this, own)
314
+ // Like the platform's own `cause`: present, but not enumerable.
315
+ if (init.cause !== undefined) {
316
+ Object.defineProperty(this, "cause", {
317
+ value: init.cause,
318
+ writable: true,
319
+ configurable: true,
320
+ })
321
+ }
322
+ Object.defineProperty(this, BRAND, { value: true })
323
+ Object.defineProperty(this, RETRYABLE, { value: init.retryable === true })
324
+ }
325
+ }
326
+
327
+ // Defined on the prototype so the stack header reads `ReactorError: ...`.
328
+ Object.defineProperty(ReactorFailure.prototype, "name", {
329
+ value: "ReactorError",
330
+ writable: true,
331
+ configurable: true,
332
+ })
333
+
334
+ /**
335
+ * `error` with `expiresAt`, when it is a write's failure that got no answer
336
+ * (`outcome_unknown`, or `cancelled` with `mayHaveExecuted: true`) and a send
337
+ * of it recorded an ingress expiry. Not enumerable, as `cause` is not: a
338
+ * `bigint` would make `JSON.stringify(error)` throw.
339
+ */
340
+ export const withExpiry = (
341
+ error: unknown,
342
+ expiresAt: bigint | undefined
343
+ ): unknown => {
344
+ if (
345
+ expiresAt !== undefined &&
346
+ isReactorError(error) &&
347
+ error.mayHaveExecuted &&
348
+ (error.kind === "outcome_unknown" || error.kind === "cancelled")
349
+ ) {
350
+ Object.defineProperty(error, "expiresAt", {
351
+ value: expiresAt,
352
+ configurable: true,
353
+ })
354
+ }
355
+ return error
356
+ }
357
+
358
+ const build = <E = never>(init: BuildInit): ReactorError<E> =>
359
+ new ReactorFailure(init) as unknown as ReactorError<E>
360
+
361
+ const DEFAULT_REASON = {
362
+ invalid_args: "the arguments could not be encoded",
363
+ unauthenticated: "an update needs a signed-in identity",
364
+ cancelled: "the call was cancelled",
365
+ invalid_reply: "the reply did not decode as the method's result",
366
+ canister_err: "the canister returned an Err",
367
+ } as const
368
+
369
+ /**
370
+ * Creates a {@link ReactorError} for a failure the client detects itself,
371
+ * where there is no agent error to classify.
372
+ *
373
+ * `mayHaveExecuted` is derived, never passed in: `invalid_args`,
374
+ * `unauthenticated`, `cancelled` and `canister_err` always say `false` (the
375
+ * client refuses before sending, or the canister answered with a decision),
376
+ * and `invalid_reply` needs the call `mode` because a write whose reply cannot
377
+ * be read has still run, and a read has not.
378
+ *
379
+ * Errors made here are never retryable.
380
+ */
381
+ export function createReactorError(
382
+ kind: "invalid_args" | "unauthenticated" | "cancelled",
383
+ fields: ReactorErrorFields
384
+ ): ReactorError
385
+ export function createReactorError(
386
+ kind: "invalid_reply",
387
+ fields: ReactorErrorFields & { readonly mode: CallMode }
388
+ ): ReactorError
389
+ export function createReactorError<E>(
390
+ kind: "canister_err",
391
+ fields: ReactorErrorFields & { readonly err: E }
392
+ ): ReactorError<E>
393
+ export function createReactorError(
394
+ kind: keyof typeof DEFAULT_REASON,
395
+ fields: ReactorErrorFields & {
396
+ readonly mode?: CallMode
397
+ readonly err?: unknown
398
+ }
399
+ ): ReactorError<unknown> {
400
+ const { mode, err, reason, ...rest } = fields
401
+ return build({
402
+ ...rest,
403
+ kind,
404
+ reason: reason ?? DEFAULT_REASON[kind],
405
+ mayHaveExecuted: kind === "invalid_reply" && mode === "update",
406
+ err,
407
+ })
408
+ }
409
+
410
+ /**
411
+ * The error of a call whose `timeoutMs` passed (code `"timeout"`). `sent` is
412
+ * whether a write (an update or a oneway, or an update read with
413
+ * `{ update: "idempotent" }`) may have been delivered: an attempt of it was
414
+ * out. Then `outcome_unknown` with `mayHaveExecuted: true`, as when the
415
+ * polling bound passes. Otherwise `cancelled`, with nothing executed: nothing
416
+ * was out, or the call was a plain read. A re-send of a write
417
+ * `client.resendOf()` offered that times out before it goes out keeps the
418
+ * unknown outcome all the same ({@link resendDidNotRun}).
419
+ */
420
+ export const timedOutError = (
421
+ where: { readonly method: string; readonly canisterId: string },
422
+ sent: boolean
423
+ ): ReactorError =>
424
+ build({
425
+ ...where,
426
+ kind: sent ? "outcome_unknown" : "cancelled",
427
+ mayHaveExecuted: sent,
428
+ code: "timeout",
429
+ reason: `timeoutMs passed${sent ? " with no answer; the write may have executed" : ""}`,
430
+ })
431
+
432
+ /**
433
+ * The error of a re-send of a write `client.resendOf()` offered that did not
434
+ * run: refused before it went out (`caller_changed`, `target_changed`,
435
+ * `arg_changed`, `client_disposed`, a `timeout` before it went out, and any
436
+ * other refusal before sending), or turned away (an HTTP 4xx, reject code 1
437
+ * to 3). `failure`, what the re-send itself rejected with, proves only that
438
+ * the re-send did not run. The write it re-sends may have run all the same,
439
+ * so its outcome stays unknown: `outcome_unknown` with `mayHaveExecuted:
440
+ * true`, `failure`'s `method`, `canisterId`, `code`, `rejectCode`,
441
+ * `httpStatus` and `issues` (the call that was refused), `failure` itself as
442
+ * the `cause` (its message says why the re-send did not run), and
443
+ * `expiresAt`, the latest of the write's sends. A re-send that ran is
444
+ * answered by the canister (`canister_err`, such as a ledger's `Duplicate`),
445
+ * and one that may have run says so itself: neither comes here.
446
+ */
447
+ export const resendDidNotRun = (
448
+ failure: ReactorError | ReactorError<unknown>,
449
+ expiresAt: bigint | undefined
450
+ ): ReactorError =>
451
+ withExpiry(
452
+ // The spread takes `failure`'s own enumerable fields (method, canisterId,
453
+ // code, rejectCode, httpStatus, issues); its kind and verdict are replaced.
454
+ build({
455
+ ...failure,
456
+ kind: "outcome_unknown",
457
+ mayHaveExecuted: true,
458
+ reason: "the re-send did not run; the write may have executed",
459
+ cause: failure,
460
+ }),
461
+ expiresAt
462
+ ) as ReactorError
463
+
464
+ /**
465
+ * Creates the `invalid_reply` error for a reply that did not decode as the
466
+ * method's result type: `mayHaveExecuted` is `true` on an update (the canister
467
+ * ran it, and only the answer is unreadable) and `false` on a query.
468
+ */
469
+ export function invalidReplyError(
470
+ context: Pick<ErrorContext, "method" | "canisterId" | "mode">,
471
+ details: Pick<ReactorErrorFields, "reason" | "issues" | "cause"> = {}
472
+ ): ReactorError {
473
+ return createReactorError("invalid_reply", {
474
+ method: context.method,
475
+ canisterId: context.canisterId,
476
+ mode: context.mode,
477
+ ...details,
478
+ })
479
+ }
480
+
481
+ // ---------------------------------------------------------------------------
482
+ // Classifying what the agent (@icp-sdk/core 6) throws. Read structurally:
483
+ // `kind`, `code.name`, `code.rejectCode`, `code.status`; never `instanceof`, so
484
+ // an error from another copy of the agent classifies the same way.
485
+ // ---------------------------------------------------------------------------
486
+
487
+ interface ErrorContextBase {
488
+ readonly method: string
489
+ /** The target canister, as text. `aaaaa-aa` is the management canister. */
490
+ readonly canisterId: string
491
+ /**
492
+ * The signal the call ran under. If it has aborted, the caller is gone and
493
+ * the failure is `cancelled`, whatever the agent reported.
494
+ */
495
+ readonly signal?: AbortSignal
496
+ }
497
+
498
+ /**
499
+ * What the classifier needs to know about the call that failed.
500
+ *
501
+ * An update must say whether the replica may already have accepted the request
502
+ * (`accepted`). It is required there, not defaulted, because the unsafe
503
+ * reading is the one a caller gets by forgetting it: an HTTP refusal that
504
+ * arrives after the update is in the IC would read as "never delivered, safe
505
+ * to re-send", and the call would run twice.
506
+ */
507
+ export type ErrorContext = ErrorContextBase &
508
+ (
509
+ | {
510
+ readonly mode: "query"
511
+ /** Ignored: a query has no accepted state. */
512
+ readonly accepted?: boolean
513
+ }
514
+ | {
515
+ readonly mode: "update"
516
+ /**
517
+ * Whether the request may already be in the IC. Pass `false` only when
518
+ * you know it is not: no attempt of this call got past the replica's
519
+ * front door. Pass `true`:
520
+ *
521
+ * - once the agent's `onPollingStarted` has fired (the replica answered
522
+ * 202). From then on an HTTP error, such as a 429 from a rate-limited
523
+ * `read_state` or an expired delegation, says nothing about the
524
+ * update, so it classifies as `outcome_unknown`, not as `not_delivered`.
525
+ * - when the agent has re-sent this request itself after a failure that
526
+ * could have followed a delivery, a fetch exception or a 5xx. The
527
+ * agent keeps only the status of its last attempt, so a 429 that ends
528
+ * such a sequence proves nothing about the first one. The simplest way
529
+ * to keep the history out of the picture is to build the agent that
530
+ * sends updates with `retryTimes: 0` and let {@link retryUpdate} do
531
+ * the re-sending, which it only does when it is safe.
532
+ *
533
+ * Anything other than an explicit `false` is read as `true`, so an
534
+ * untyped caller that leaves it out gets the safe answer.
535
+ */
536
+ readonly accepted: boolean
537
+ /**
538
+ * Whether the call re-sends a write that `resendOf()` offered, whose
539
+ * earlier attempt may have run. A signer that does not sign the
540
+ * re-send leaves that write's outcome unknown.
541
+ */
542
+ readonly again?: boolean
543
+ }
544
+ )
545
+
546
+ // Which reject codes prove that an update call changed nothing.
547
+ //
548
+ // Per the IC interface specification (docs/references/ic-interface-spec.md in
549
+ // dfinity/portal, section "Reject codes" and the rules of "Abstract behavior"):
550
+ //
551
+ // - SYS_FATAL (1) and SYS_TRANSIENT (2) reach an ingress call only from
552
+ // "Request rejection" ("The IC may reject a received message for internal
553
+ // reasons ... Code = SYS_FATAL or Code = SYS_TRANSIENT"), before the request
554
+ // is processed, and SYS_TRANSIENT also from "Calls to frozen canisters are
555
+ // rejected", which happens before a call context is created. No canister
556
+ // code runs. Exception: a pending `stop_canister` on the management canister
557
+ // "may be rejected by the system at any time (the canister stays stopping in
558
+ // this case)" with SYS_TRANSIENT, after its effect, so calls to aaaaa-aa
559
+ // are not given this guarantee.
560
+ // - DESTINATION_INVALID (3): "Invalid destination (e.g. canister/account does
561
+ // not exist)": there was nothing to run.
562
+ // - CANISTER_REJECT (4) is "always" what `ic0.msg_reject` produces ("the
563
+ // canister cannot freely specify the reject code"); the execution that
564
+ // rejects returns normally, and "If message execution returns ..., the
565
+ // state is updated". So the canister's changes stand.
566
+ // - CANISTER_ERROR (5) covers a trap, whose "state mutation is discarded"
567
+ // only for the trapping execution: executions of the same call before an
568
+ // inter-canister await were already committed. It also covers call-context
569
+ // starvation, where "the state changes are persisted even when the IC is
570
+ // set to synthesize a CANISTER_ERROR reject". It can also mean the canister
571
+ // was stopped and never ran, but a client cannot tell which.
572
+ // - SYS_UNKNOWN (6) "is only applicable to inter-canister calls that used
573
+ // ic0.call_with_best_effort_response"; seen on an ingress call it proves
574
+ // nothing, so it counts as unknown.
575
+ //
576
+ // So: 1, 2, 3 are no effect (2 alone is also safe to re-send); 4, 5, 6 and any
577
+ // code not listed may have executed.
578
+ const SYS_FATAL = 1
579
+ const SYS_TRANSIENT = 2
580
+ const DESTINATION_INVALID = 3
581
+
582
+ const REJECT_NAMES: Readonly<Record<number, string>> = {
583
+ 1: "SYS_FATAL",
584
+ 2: "SYS_TRANSIENT",
585
+ 3: "DESTINATION_INVALID",
586
+ 4: "CANISTER_REJECT",
587
+ 5: "CANISTER_ERROR",
588
+ 6: "SYS_UNKNOWN",
589
+ }
590
+
591
+ /**
592
+ * Agent error codes thrown while the agent builds, encodes or signs a request,
593
+ * before it calls `fetch` (read in `@icp-sdk/core` 6.1: `cbor.js`, `der.js`,
594
+ * `agent/http/index.js`, `polling/index.js`, `actor.js`). Nothing of that
595
+ * request left the process, and the same input fails the same way again, so
596
+ * none of them is worth a retry.
597
+ */
598
+ const PRE_SEND_CODES: ReadonlySet<string> = new Set([
599
+ "CborEncodeErrorCode",
600
+ "DerEncodeErrorCode",
601
+ "IdentityInvalidErrorCode",
602
+ "MissingFetchErrorCode",
603
+ "CreateHttpAgentErrorCode",
604
+ "MissingCanisterIdErrorCode",
605
+ "InvalidReadStateRequestErrorCode",
606
+ ])
607
+
608
+ /** The errors {@link notSigned} made, which {@link classifyError} unwraps. */
609
+ const unsigned = new WeakSet<object>()
610
+
611
+ /**
612
+ * What a failure of an identity's `transformRequest` is thrown to the agent
613
+ * as (see `agentFor`): a user who declines a passkey or hardware-wallet
614
+ * prompt, a signer that is gone. {@link classifyError} reads it as a request
615
+ * that was not signed, whatever the signer's error (its `cause`) says, and
616
+ * makes that error the result's `cause`.
617
+ */
618
+ export const notSigned = (cause: unknown): Error => {
619
+ const error = Object.assign(new Error("the signer did not sign"), { cause })
620
+ unsigned.add(error)
621
+ return error
622
+ }
623
+
624
+ /**
625
+ * The signer's error, when `error` is a {@link notSigned} failure or wraps
626
+ * one: the agent throws a failure from inside its own error handling (a
627
+ * query's `read_state` for the subnet's keys) as
628
+ * `UnknownError(UnexpectedErrorCode(error))`.
629
+ */
630
+ function signerError(
631
+ error: unknown,
632
+ depth = 0
633
+ ): { cause: unknown } | undefined {
634
+ if (depth > 3) return undefined
635
+ const record = asRecord(error)
636
+ if (unsigned.has(record)) return { cause: record.cause }
637
+ return signerError(asRecord(record.code).error, depth + 1)
638
+ }
639
+
640
+ /**
641
+ * `ReactorError.code` when the IC answers that the canister a request was
642
+ * addressed to does not exist.
643
+ */
644
+ const CANISTER_NOT_FOUND = "canister_not_found"
645
+
646
+ /**
647
+ * The error line of the body a boundary node answers with HTTP 400 for a
648
+ * canister id outside every subnet's range (the HTTP gateway of a local
649
+ * network answers the same): `error: canister_not_found`, then a `details:`
650
+ * line. The cause token is the gateway's machine-readable marker; the details
651
+ * line is free text and is not read. With the `m` flag, `$` also matches
652
+ * before a `\r`, so a CRLF body reads the same.
653
+ */
654
+ const CANISTER_NOT_FOUND_BODY = /^error:[ \t]*canister_not_found[ \t]*$/m
655
+
656
+ /**
657
+ * The IC error code (`CanisterNotFound`) a replica puts on a reject 3 for a
658
+ * canister id inside its subnet's range that holds no canister. Mainnet
659
+ * answers a query and an update that way, and so does the fake replica of
660
+ * `@ic-reactor/core/testing`.
661
+ */
662
+ const IC_CANISTER_NOT_FOUND = "IC0301"
663
+
664
+ /** The longest detail text a ReactorError's `message` carries. */
665
+ const MAX_DETAIL = 160
666
+
667
+ /**
668
+ * What the classifier reads off whatever was thrown. Every field comes from a
669
+ * property read, so a plain object of the same shape reads the same as the
670
+ * agent's own classes.
671
+ */
672
+ interface Shape {
673
+ /** The agent's `ErrorKindEnum` value, such as `"Reject"` or `"Transport"`. */
674
+ readonly kind: string | undefined
675
+ /** The `name` of the agent's `ErrorCode`, such as `"HttpErrorCode"`. */
676
+ readonly codeName: string | undefined
677
+ readonly rejectCode: number | undefined
678
+ /** The IC error code of a reject, such as `"IC0301"`. */
679
+ readonly rejectErrorCode: string | undefined
680
+ readonly httpStatus: number | undefined
681
+ /** The body of an HTTP refusal, unshortened. */
682
+ readonly bodyText: string | undefined
683
+ /** Short human text from the error: a reject message, an HTTP body, ... */
684
+ readonly detail: string
685
+ readonly statusText: string
686
+ }
687
+
688
+ /** `value` when it is an object, so its fields can be read; `{}` otherwise. */
689
+ export const asRecord = (value: unknown): Record<string, unknown> =>
690
+ typeof value === "object" && value !== null
691
+ ? (value as Record<string, unknown>)
692
+ : {}
693
+
694
+ const asString = (value: unknown): string | undefined =>
695
+ typeof value === "string" ? value : undefined
696
+
697
+ /**
698
+ * The reject code of a `RejectError`. The agent nests it (the error's `code` is
699
+ * a `...RejectErrorCode` carrying `rejectCode`); the flat position is read too,
700
+ * so a hand-built or future-shaped error still classifies.
701
+ */
702
+ function readRejectCode(error: Record<string, unknown>): number | undefined {
703
+ const flat = error.rejectCode
704
+ if (typeof flat === "number") return flat
705
+ const nested = asRecord(error.code).rejectCode
706
+ return typeof nested === "number" ? nested : undefined
707
+ }
708
+
709
+ /**
710
+ * The HTTP status of a `ProtocolError` whose `code` is an `HttpErrorCode`.
711
+ * Recognised by the code's `name` and `status`, not with `instanceof`, so an
712
+ * error from another copy of `@icp-sdk/core` classifies the same way. A
713
+ * `status` on any other code says nothing about an HTTP answer and is ignored.
714
+ */
715
+ export function readHttpStatus(error: unknown): number | undefined {
716
+ const code = asRecord(asRecord(error).code)
717
+ return code.name === "HttpErrorCode" && typeof code.status === "number"
718
+ ? code.status
719
+ : undefined
720
+ }
721
+
722
+ /**
723
+ * One line of at most {@link MAX_DETAIL} characters. The agent's own messages
724
+ * run to many lines (headers, the request context, an HTTP body), which would
725
+ * bury what a person reading a toast or a log needs.
726
+ */
727
+ function condense(text: string | undefined): string {
728
+ if (text === undefined) return ""
729
+ const line = text.replace(/\s+/g, " ").trim()
730
+ return line.length > MAX_DETAIL ? `${line.slice(0, MAX_DETAIL - 1)}…` : line
731
+ }
732
+
733
+ function messageOf(value: unknown): string | undefined {
734
+ return typeof value === "string" ? value : asString(asRecord(value).message)
735
+ }
736
+
737
+ function readShape(error: unknown): Shape {
738
+ const record = asRecord(error)
739
+ const code = asRecord(record.code)
740
+ const codeName = asString(code.name)
741
+ const rejectCode = readRejectCode(record)
742
+ const httpStatus = readHttpStatus(record)
743
+ // The text that says the most, per code. An HTTP refusal's body names the
744
+ // problem; a reject carries the canister's or the IC's message; a transport
745
+ // failure wraps the fetch error. Anything else falls back to the error's
746
+ // own message, which a non-agent error keeps short.
747
+ const detail =
748
+ asString(code.rejectMessage) ??
749
+ asString(code.bodyText) ??
750
+ (codeName === "HttpFetchErrorCode" ? messageOf(code.error) : undefined) ??
751
+ asString(code.message) ??
752
+ messageOf(error)
753
+ return {
754
+ kind: asString(record.kind),
755
+ codeName,
756
+ rejectCode,
757
+ // Flat first, like the reject code, so a hand-built error reads the same.
758
+ rejectErrorCode:
759
+ asString(record.rejectErrorCode) ?? asString(code.rejectErrorCode),
760
+ httpStatus,
761
+ bodyText: asString(code.bodyText),
762
+ detail: condense(detail),
763
+ statusText: condense(asString(code.statusText)),
764
+ }
765
+ }
766
+
767
+ /**
768
+ * Whether the answer says that the canister the request was addressed to does
769
+ * not exist: an HTTP 400 whose body's error line is `canister_not_found`, or
770
+ * a reject 3 carrying the IC error code `IC0301`. Read from the shape only, so
771
+ * any other 400 or reject 3 says nothing of the kind.
772
+ */
773
+ const saysCanisterNotFound = (shape: Shape): boolean =>
774
+ shape.httpStatus === 400
775
+ ? CANISTER_NOT_FOUND_BODY.test(shape.bodyText ?? "")
776
+ : shape.rejectCode === DESTINATION_INVALID &&
777
+ shape.rejectErrorCode === IC_CANISTER_NOT_FOUND
778
+
779
+ /** Whether `error`, or what it wraps, is an abort. */
780
+ function isAbort(error: unknown, depth = 0): boolean {
781
+ if (depth > 3) return false
782
+ const record = asRecord(error)
783
+ if (record.name === "AbortError") return true
784
+ // The agent wraps a fetch failure, abort included, as
785
+ // `TransportError(HttpFetchErrorCode(error))`.
786
+ return isAbort(asRecord(record.code).error, depth + 1)
787
+ }
788
+
789
+ const withDetail = (lead: string, detail: string): string =>
790
+ detail === "" ? lead : `${lead}: ${detail}`
791
+
792
+ /**
793
+ * Classifies a failure from the agent (or anything thrown around it) into a
794
+ * {@link ReactorError}, following one table. `mayHaveExecuted` is `true`
795
+ * exactly when the failure leaves open that the canister ran the call.
796
+ *
797
+ * | Failure | kind (update / query) | mayHaveExecuted (update / query) |
798
+ * | --- | --- | --- |
799
+ * | already a ReactorError | unchanged | unchanged |
800
+ * | `AbortError`, or the signal aborted | `cancelled` | true / false |
801
+ * | reject 1 or 3 | `rejected` | false / false |
802
+ * | reject 2 | `not_delivered`, retryable | false / false |
803
+ * | reject 1, 2 or 3 from `aaaaa-aa` | `rejected` | true / false |
804
+ * | reject 4 or 5 | `rejected` | true / false |
805
+ * | reject 6, an unknown code, HTTP 408 or 5xx, a network failure, a polling timeout, a `Trust` failure | `outcome_unknown` / `not_delivered`, retryable for a query | true / false |
806
+ * | HTTP 429 | `not_delivered`, retryable | false / false |
807
+ * | any other HTTP 4xx, `IngressExpiryInvalid` | `not_delivered` | false / false |
808
+ * | a request that could not be built or signed (CBOR or DER encoding, an invalid identity, no `fetch`, no canister id) | `not_delivered` | false / false |
809
+ * | the signer did not sign a request (a declined prompt: {@link notSigned}) | `not_delivered` | false / false |
810
+ *
811
+ * A canister that does not exist also sets `code: "canister_not_found"`, and
812
+ * changes nothing else. The IC says it in one of two ways. For a canister id
813
+ * outside every subnet's range, a boundary node answers HTTP 400 with a body
814
+ * whose error line is `canister_not_found` (a row of "any other HTTP 4xx").
815
+ * For an id inside a subnet's range that holds no canister, the replica
816
+ * rejects with code 3 and the IC error code `IC0301`: mainnet does, for a
817
+ * query and an update, and so does the fake replica of
818
+ * `@ic-reactor/core/testing` (a row of "reject 1 or 3", or of the `aaaaa-aa`
819
+ * row for a call to the management canister). No other 400 and no other
820
+ * reject gets the code. The code names the canister the request was routed
821
+ * to: for `aaaaa-aa`, the one its arguments name. It stays on an update that
822
+ * may already be in the IC, whose 400 reads as `outcome_unknown` like any
823
+ * other, and is never set on `cancelled`.
824
+ *
825
+ * For a query nothing that matters executes, so every doubt is `not_delivered`
826
+ * and `mayHaveExecuted` is `false`. The HTTP rows, and `IngressExpiryInvalid`,
827
+ * hold for an update only when `context.accepted` is `false`, and so do the
828
+ * rows of a request that could not be built or signed. Once the request
829
+ * may be in the IC (see {@link ErrorContext}), they all read as
830
+ * `outcome_unknown` with `mayHaveExecuted: true`, because a refusal that comes
831
+ * later says nothing about the call.
832
+ *
833
+ * An abort during an update is `cancelled` with `mayHaveExecuted: true`: the
834
+ * request may already have been delivered. Use
835
+ * `createReactorError("cancelled", ...)` for a refusal before anything was
836
+ * sent, which says `false`.
837
+ *
838
+ * An error that is already a ReactorError comes back as the same object, so
839
+ * it may carry an `err` that the return type does not promise.
840
+ *
841
+ * The thrown error becomes the result's `cause` (for a signer that did not
842
+ * sign, the signer's own error), and the result's `message`
843
+ * is one short line (`[ic-reactor] <method> on <canisterId>: <reason>`): a
844
+ * missing canister arrives from the agent as an HTTP 400 whose own message
845
+ * runs to thousands of characters.
846
+ */
847
+ export function classifyError(
848
+ error: unknown,
849
+ context: ErrorContext
850
+ ): ReactorError {
851
+ if (isReactorError(error)) return error as unknown as ReactorError
852
+ const { method, canisterId } = context
853
+ const update = context.mode === "update"
854
+ // Fail closed: only an explicit `false` says the request never got in.
855
+ const mayBeAccepted = update && context.accepted !== false
856
+ const shape = readShape(error)
857
+ const { rejectCode, httpStatus } = shape
858
+ const signer = signerError(error)
859
+ const thrown = signer === undefined ? error : signer.cause
860
+
861
+ const make = (
862
+ kind: ReactorErrorKind,
863
+ mayHaveExecuted: boolean,
864
+ reason: string,
865
+ retryable = false,
866
+ code?: string
867
+ ): ReactorError =>
868
+ build({
869
+ kind,
870
+ mayHaveExecuted,
871
+ reason,
872
+ retryable,
873
+ code,
874
+ method,
875
+ canisterId,
876
+ rejectCode,
877
+ httpStatus,
878
+ cause: thrown,
879
+ })
880
+
881
+ if (context.signal?.aborted || isAbort(thrown)) {
882
+ return make("cancelled", update, DEFAULT_REASON.cancelled)
883
+ }
884
+
885
+ // Before anything else the agent wrapped it in: what the signer threw says
886
+ // nothing about the call. Only a poll of an update the IC may already hold
887
+ // leaves the outcome open, and a re-send of an offered write, whose earlier
888
+ // attempt may have run (as a re-send that times out does). A read's
889
+ // signature is asked for again by any retry, so a read is not retried.
890
+ if (signer !== undefined) {
891
+ const unknown =
892
+ mayBeAccepted || (context.mode === "update" && context.again === true)
893
+ const reason = mayBeAccepted
894
+ ? "the call was sent, but the signer did not sign a request for its answer"
895
+ : `the signer did not sign the request${update ? ", so it was not sent" : ""}`
896
+ return make(
897
+ unknown ? "outcome_unknown" : "not_delivered",
898
+ unknown,
899
+ withDetail(reason, condense(messageOf(thrown)))
900
+ )
901
+ }
902
+
903
+ // An agent error has a `kind`. One without (a bug, or some other agent) is
904
+ // classified the same way but never retried: nothing says another attempt
905
+ // would end differently.
906
+ const agentShaped =
907
+ shape.kind !== undefined ||
908
+ rejectCode !== undefined ||
909
+ httpStatus !== undefined
910
+
911
+ // A query executes nothing that matters, so every doubt is "not delivered".
912
+ const doubt = (reason: string): ReactorError =>
913
+ update
914
+ ? make("outcome_unknown", true, reason)
915
+ : make("not_delivered", false, reason, agentShaped)
916
+
917
+ if (shape.kind === "Reject" || rejectCode !== undefined) {
918
+ const name = rejectCode === undefined ? undefined : REJECT_NAMES[rejectCode]
919
+ const reason = withDetail(
920
+ `the IC rejected the call${
921
+ rejectCode === undefined
922
+ ? ""
923
+ : ` with code ${rejectCode}${name === undefined ? "" : ` (${name})`}`
924
+ }`,
925
+ shape.detail
926
+ )
927
+ // aaaaa-aa is exempt from the "no canister code ran" reading of 1, 2 and 3.
928
+ const noCodeRan = canisterId !== MANAGEMENT_CANISTER
929
+ if (rejectCode === SYS_TRANSIENT && noCodeRan) {
930
+ return make("not_delivered", false, reason, true)
931
+ }
932
+ if (
933
+ rejectCode === SYS_TRANSIENT ||
934
+ rejectCode === SYS_FATAL ||
935
+ rejectCode === DESTINATION_INVALID
936
+ ) {
937
+ const code = saysCanisterNotFound(shape) ? CANISTER_NOT_FOUND : undefined
938
+ return make("rejected", !noCodeRan && update, reason, false, code)
939
+ }
940
+ if (rejectCode === 4 || rejectCode === 5) {
941
+ return make("rejected", update, reason)
942
+ }
943
+ // 6, a code outside 1 to 6, or a rejection whose code cannot be read.
944
+ return doubt(reason)
945
+ }
946
+
947
+ if (shape.codeName !== undefined && PRE_SEND_CODES.has(shape.codeName)) {
948
+ const reason = withDetail(
949
+ "the request could not be built or signed, so it was not sent",
950
+ shape.detail
951
+ )
952
+ // A request that could not be built says nothing about one sent before
953
+ // it: for an update the replica may already hold (a poll that could not
954
+ // be encoded), the call's outcome is still unknown.
955
+ return mayBeAccepted
956
+ ? make("outcome_unknown", true, reason)
957
+ : make("not_delivered", false, reason)
958
+ }
959
+
960
+ if (shape.codeName === "IngressExpiryInvalidErrorCode") {
961
+ const reason = withDetail(
962
+ "the replica refused the request's ingress expiry",
963
+ shape.detail
964
+ )
965
+ return mayBeAccepted
966
+ ? make("outcome_unknown", true, reason)
967
+ : make("not_delivered", false, reason)
968
+ }
969
+
970
+ if (httpStatus !== undefined) {
971
+ const reason = withDetail(
972
+ `the replica answered HTTP ${httpStatus}${
973
+ shape.statusText === "" ? "" : ` ${shape.statusText}`
974
+ }`,
975
+ shape.detail
976
+ )
977
+ // A 429 or a 4xx is the replica or a boundary node refusing the request
978
+ // itself (rate limit, bad signature, expired delegation, no such
979
+ // canister): the canister never saw it. 408 is the exception, a timeout
980
+ // after the request may have been passed on. 5xx may follow a delivery.
981
+ const refused = httpStatus >= 400 && httpStatus < 500 && httpStatus !== 408
982
+ if (!refused) return doubt(reason)
983
+ // The code says what the answer said; `kind` still says what it proves.
984
+ const code = saysCanisterNotFound(shape) ? CANISTER_NOT_FOUND : undefined
985
+ if (mayBeAccepted) return make("outcome_unknown", true, reason, false, code)
986
+ return make("not_delivered", false, reason, httpStatus === 429, code)
987
+ }
988
+
989
+ // Transport, Protocol, Trust, External, Limit, Unknown, a polling timeout,
990
+ // and anything that is not an agent error at all.
991
+ const lead =
992
+ shape.kind === "Transport"
993
+ ? "could not reach the replica"
994
+ : shape.kind === "Trust"
995
+ ? "the replica's answer could not be verified"
996
+ : "the call failed"
997
+ return doubt(withDetail(lead, shape.detail || "unknown error"))
998
+ }
999
+
1000
+ // ---------------------------------------------------------------------------
1001
+ // Retry
1002
+ // ---------------------------------------------------------------------------
1003
+
1004
+ /**
1005
+ * Whether the classifier marked `error` as safe to send again: a
1006
+ * `not_delivered` that another attempt can change. {@link retryQuery} and
1007
+ * {@link retryUpdate} add their own limits; a direct read re-sends on this
1008
+ * alone, at most twice.
1009
+ *
1010
+ * It narrows `error` to a {@link ReactorError} when it returns `true`. Its
1011
+ * `false` says nothing about the type, though TypeScript reads it as "not a
1012
+ * `ReactorError`", so call it on an `unknown`, as both callers do.
1013
+ */
1014
+ export const isRetryable = (error: unknown): error is ReactorError =>
1015
+ isReactorError(error) &&
1016
+ error.kind === "not_delivered" &&
1017
+ (error as unknown as Record<symbol, unknown>)[RETRYABLE] === true
1018
+
1019
+ /**
1020
+ * How long to wait before each re-send of an update: 300 ms, then 600 ms.
1021
+ * Its length is the most re-sends one call gets.
1022
+ */
1023
+ export const UPDATE_RESEND_DELAYS_MS: readonly [300, 600] = [300, 600]
1024
+
1025
+ /**
1026
+ * Whether an update may be sent again. Every attempt at an update is a new
1027
+ * request id, so the IC cannot tell a retry from a second call and runs both.
1028
+ * A re-send is safe only when the failure proves the first attempt was never
1029
+ * accepted, and only two do: a SysTransient reject (code 2, from anything but
1030
+ * the management canister) and an HTTP 429. Any other failure, a network
1031
+ * error included, may have come after the replica accepted the call.
1032
+ *
1033
+ * The 429 proof holds for one attempt. The agent can re-send a request on its
1034
+ * own (`retryTimes`, three by default), and it reports only the status of the
1035
+ * last attempt, so a 429 that follows a fetch failure or a 5xx may hide an
1036
+ * earlier delivery. The client must therefore either build the agent that sends
1037
+ * updates with `retryTimes: 0`, or classify with `accepted: true` when an
1038
+ * earlier attempt may have been delivered; see {@link ErrorContext}.
1039
+ *
1040
+ * `resendsSoFar` is how many times this call has been re-sent already; the
1041
+ * answer is `false` once it reaches the length of
1042
+ * {@link UPDATE_RESEND_DELAYS_MS}.
1043
+ */
1044
+ export function retryUpdate(error: unknown, resendsSoFar: number): boolean {
1045
+ if (resendsSoFar >= UPDATE_RESEND_DELAYS_MS.length) return false
1046
+ // A retryable error is a `not_delivered`, whose `mayHaveExecuted` is always
1047
+ // `false`, so that needs no check of its own here.
1048
+ return (
1049
+ isRetryable(error) &&
1050
+ (error.rejectCode === SYS_TRANSIENT || error.httpStatus === 429)
1051
+ )
1052
+ }
1053
+
1054
+ /**
1055
+ * A TanStack Query `retry` for a query: at most 3 retries, and only of a
1056
+ * failure the classifier marked as safe to try again (a `not_delivered` that a
1057
+ * later attempt can change). Never on a server: TanStack defaults to no
1058
+ * retries there, and supplying a predicate would override that and add the
1059
+ * 1s/2s/4s backoff to a request that used to fail fast.
1060
+ *
1061
+ * `failureCount` is how many failures there have been before this one, as
1062
+ * TanStack passes it (0 after the first failure).
1063
+ */
1064
+ export function retryQuery(failureCount: number, error: unknown): boolean {
1065
+ if (isServer()) return false
1066
+ return failureCount < 3 && isRetryable(error)
1067
+ }
1068
+
1069
+ /**
1070
+ * The default `retry` of a client's `QueryClient`. A client's own reads set
1071
+ * `retry` themselves, so this default reaches only the other queries on that
1072
+ * `QueryClient`, such as an app's REST queries. A `ReactorError` is retried as
1073
+ * {@link retryQuery} says; any other error as TanStack Query retries it by
1074
+ * default: up to 3 times in a browser, never on a server (#903).
1075
+ */
1076
+ export function retryDefault(failureCount: number, error: unknown): boolean {
1077
+ if (isReactorError(error)) return retryQuery(failureCount, error)
1078
+ return !isServer() && failureCount < 3
1079
+ }