@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,1166 @@
1
+ /**
2
+ * A fake replica, reached through the `fetch` an `HttpAgent` is given.
3
+ *
4
+ * {@link createFakeReplica} returns a `fetch` to pass as
5
+ * `HttpAgentOptions.fetch`, so the agents that use it are the only code that
6
+ * reaches the fake and nothing global is touched.
7
+ *
8
+ * It holds its own root key and node key, and signs what a replica signs: a
9
+ * BLS signature over each certificate and a node signature over each query
10
+ * response. The agent verifies both exactly as it would against a replica, so
11
+ * nothing in the agent is mocked, and an agent that checks a certificate
12
+ * against the wrong root key fails here as it would there.
13
+ *
14
+ * Like a replica, it checks who sent each request before any canister sees it,
15
+ * so the caller a canister is told about is the one a replica would report.
16
+ *
17
+ * It implements the endpoints an agent uses for canister calls and nothing
18
+ * else: the status endpoint (the root key), and a canister's `query`, `call`
19
+ * (which always answers synchronously) and `read_state` (the subnet's node
20
+ * keys and canister ranges, which an agent reads before it trusts a query).
21
+ *
22
+ * Three fault hooks reproduce what a real network does to a call: a canister
23
+ * that rejects it with a chosen reject code, a reply that is lost after the
24
+ * canister ran, and an HTTP refusal before any canister sees the call.
25
+ */
26
+ import { bls12_381 } from "@noble/curves/bls12-381.js"
27
+ import { ed25519 } from "@noble/curves/ed25519.js"
28
+ import { p256 } from "@noble/curves/nist.js"
29
+ import { secp256k1 } from "@noble/curves/secp256k1.js"
30
+ import {
31
+ BLS12_381_G2_OID,
32
+ Cbor,
33
+ IC_REQUEST_AUTH_DELEGATION_DOMAIN_SEPARATOR,
34
+ IC_REQUEST_DOMAIN_SEPARATOR,
35
+ IC_RESPONSE_DOMAIN_SEPARATOR,
36
+ IC_STATE_ROOT_DOMAIN_SEPARATOR,
37
+ NodeType,
38
+ ReplicaRejectCode,
39
+ hashOfMap,
40
+ reconstruct,
41
+ requestIdOf,
42
+ wrapDER,
43
+ type HashTree,
44
+ } from "@icp-sdk/core/agent"
45
+ import { Ed25519KeyIdentity } from "@icp-sdk/core/identity"
46
+ import { Principal } from "@icp-sdk/core/principal"
47
+
48
+ /**
49
+ * Whether a page on this hostname talks to a replica it serves itself: a
50
+ * local host (`localhost`, its subdomains, all of 127.0.0.0/8, `::1`) or a
51
+ * Codespaces/Gitpod forward. Kept from v3's `getNetworkByHostname` so the
52
+ * fake routes a page's same-origin requests as it always did.
53
+ */
54
+ const isNonMainnetPageHost = (hostname: string): boolean =>
55
+ hostname === "localhost" ||
56
+ hostname.endsWith(".localhost") ||
57
+ hostname.endsWith("127.0.0.1") ||
58
+ /^127\.(?:\d{1,3}\.){2}\d{1,3}$/.test(hostname) ||
59
+ hostname === "::1" ||
60
+ hostname === "[::1]" ||
61
+ hostname.endsWith(".github.dev") ||
62
+ hostname.endsWith(".gitpod.io")
63
+
64
+ /** Who sent a call, as the fake replica reports it to a canister. */
65
+ export interface FakeCallContext {
66
+ /**
67
+ * The principal that sent the call: the anonymous principal, or the one
68
+ * the signing identity names (the root of its delegation chain, if it has
69
+ * one), after the fake has checked the request's signatures.
70
+ */
71
+ readonly caller: Principal
72
+ }
73
+
74
+ /**
75
+ * A canister the fake replica routes calls to, by method name and raw Candid.
76
+ *
77
+ * Each handler receives the method name, the Candid-encoded argument and the
78
+ * call context, and returns the Candid-encoded reply. A handler that throws
79
+ * rejects the call as a canister trap does, and one that calls
80
+ * {@link FakeReplica.reject} rejects it with the reject code it names. A
81
+ * canister without `query` rejects every query, and one without `update`
82
+ * every update call.
83
+ */
84
+ export interface FakeCanister {
85
+ query?(
86
+ method: string,
87
+ arg: Uint8Array,
88
+ context: FakeCallContext
89
+ ): Uint8Array | Promise<Uint8Array>
90
+ update?(
91
+ method: string,
92
+ arg: Uint8Array,
93
+ context: FakeCallContext
94
+ ): Uint8Array | Promise<Uint8Array>
95
+ }
96
+
97
+ /** A request an agent sent to the fake replica. */
98
+ export interface FakeReplicaRequest {
99
+ readonly endpoint: "status" | "query" | "call" | "read_state"
100
+ /** The canister the request was addressed to, as text. */
101
+ readonly canisterId?: string
102
+ /**
103
+ * The effective canister id the agent put in the request path
104
+ * (`/api/v3/canister/<id>/call`), as text. It is the canister the request is
105
+ * routed by, and it differs from {@link FakeReplicaRequest.canisterId} when
106
+ * a call goes to the management canister (`aaaaa-aa`), where the client
107
+ * chooses it from the call's arguments. Set on `query`, `call` and
108
+ * `read_state` requests.
109
+ */
110
+ readonly effectiveCanisterId?: string
111
+ /** The canister method a query or call named. */
112
+ readonly methodName?: string
113
+ /** The principal the request came from, as text, once it was checked. */
114
+ readonly caller?: string
115
+ /**
116
+ * Why the fake refused the request before any canister saw it: either the
117
+ * signature, a delegation, or its targets did not check out, as a replica
118
+ * refuses it (HTTP 400), or {@link FakeReplica.refuseNext} told the fake to
119
+ * answer with an HTTP status.
120
+ */
121
+ readonly refused?: string
122
+ /**
123
+ * Whether the reply to this request was lost by
124
+ * {@link FakeReplica.dropNextReply}: the agent saw a network failure. The
125
+ * first send of a dropped call ran the canister; a re-send of it did not.
126
+ */
127
+ readonly dropped?: true
128
+ }
129
+
130
+ /** Options for {@link createFakeReplica}. */
131
+ export interface FakeReplicaOptions {
132
+ /**
133
+ * The origin the fake answers for. Point the agents under test at it, for
134
+ * example with `HttpAgent.createSync({ host: replica.host, ... })`.
135
+ *
136
+ * @defaultValue The page's origin when the test environment has a local one
137
+ * (`http://localhost:3000` in Vitest's jsdom and happy-dom), which is where
138
+ * an agent built with no `host` calls, and `"http://127.0.0.1:8000"`
139
+ * (the client's `"local"` network) otherwise.
140
+ */
141
+ host?: string
142
+ /**
143
+ * The canisters the fake runs, by canister ID. A call to any other
144
+ * canister is rejected, as a replica rejects a call to a canister that
145
+ * does not exist.
146
+ */
147
+ canisters?: Record<string, FakeCanister>
148
+ /**
149
+ * The time its certificates carry, in nanoseconds since the epoch: the
150
+ * IC's clock as an agent reads it from the `time` path. Internal, for the
151
+ * tests of `client.time()`; every other check the fake makes reads the
152
+ * host's clock.
153
+ *
154
+ * @defaultValue The host's clock.
155
+ */
156
+ now?: () => bigint
157
+ }
158
+
159
+ /**
160
+ * The reject codes a canister call can end with, as the Internet Computer
161
+ * interface specification numbers them: `1` SYS_FATAL, `2` SYS_TRANSIENT,
162
+ * `3` DESTINATION_INVALID, `4` CANISTER_REJECT, `5` CANISTER_ERROR and `6`
163
+ * SYS_UNKNOWN.
164
+ */
165
+ export type FakeRejectCode = 1 | 2 | 3 | 4 | 5 | 6
166
+
167
+ /** A fake replica made by {@link createFakeReplica}. */
168
+ export interface FakeReplica {
169
+ /** The origin the fake answers for. */
170
+ readonly host: string
171
+ /**
172
+ * The DER-encoded root key the fake signs certificates with. Each fake has
173
+ * its own. Pass it as `rootKey` to an agent that does not fetch its root
174
+ * key, or let the agent fetch it from the fake with `shouldFetchRootKey`.
175
+ */
176
+ readonly rootKey: Uint8Array
177
+ /**
178
+ * The `fetch` to give an agent, as `HttpAgent.createSync({ host, fetch,
179
+ * rootKey })`. It answers the IC API on {@link FakeReplica.host} and
180
+ * refuses the IC API on any other origin with a network error, which it
181
+ * also logs once, so an agent built for the wrong host fails at once. It
182
+ * does not touch `globalThis.fetch`.
183
+ */
184
+ readonly fetch: typeof globalThis.fetch
185
+ /** Every request an agent sent to the fake, in order. */
186
+ readonly requests: readonly FakeReplicaRequest[]
187
+ /**
188
+ * Runs a canister at `canisterId`, replacing the one already there. For a
189
+ * canister that is not known when the fake is created.
190
+ */
191
+ addCanister(canisterId: string, canister: FakeCanister): void
192
+ /**
193
+ * Rejects the call being handled with `code`, as a canister does: call it
194
+ * from inside a canister handler. An update is rejected in a certificate,
195
+ * as a replica certifies a reject, and a query is rejected in the signed
196
+ * query response.
197
+ *
198
+ * @param code - The reject code the agent receives.
199
+ * @param message - The reject message. A default naming the code is used
200
+ * when it is left out.
201
+ */
202
+ reject(code: FakeRejectCode, message?: string): never
203
+ /**
204
+ * Loses the reply to the next update call. The canister runs and its state
205
+ * changes, but the agent sees a network failure instead of the answer, so
206
+ * it cannot know the call happened.
207
+ *
208
+ * The request is remembered, and every send of it, and every `read_state`
209
+ * of its status, fails as a lost connection without running the canister
210
+ * again. The agent's own retries, which re-send the same request, therefore
211
+ * cannot recover the reply and cannot run the call twice, and the agent
212
+ * cannot learn the outcome by polling. A real replica would still answer a
213
+ * `read_state` for a request id it holds: the fake models a network
214
+ * partition for that one request id, so the call stays outcome-unknown.
215
+ *
216
+ * With no argument it loses the reply of whatever call request comes next,
217
+ * a certified read or an update read included. Given {@link FakeRefusal}
218
+ * options, it loses only the replies of the next `times` call requests that
219
+ * name `method` and are addressed to `canister` (each one that is given),
220
+ * and lets every other request through, with the matching rules of
221
+ * {@link FakeReplica.refuseNext}. A request that several armed drops match
222
+ * uses up the one armed first.
223
+ *
224
+ * @param which - Which call requests to lose the reply of, and how many.
225
+ */
226
+ dropNextReply(which?: FakeRefusal): void
227
+ /**
228
+ * Answers the next `times` canister requests (a `query` or a `call`) with an
229
+ * HTTP error `status` before any canister sees them, as a gateway or a
230
+ * replica does when it throttles or refuses a request. The status endpoint
231
+ * and `read_state`, which an agent makes on its own, are not counted.
232
+ *
233
+ * An agent retries a refused request on its own unless it is built with
234
+ * `retryTimes: 0`; `times` is how many sends to refuse, so a test can refuse
235
+ * the first and let a retry through.
236
+ *
237
+ * Given {@link FakeRefusal} options instead of a count, it refuses only the
238
+ * requests that name `method` and are addressed to `canister` (each one
239
+ * that is given), and lets every other request through. A request that
240
+ * several armed refusals match is refused by the one armed first.
241
+ *
242
+ * @param status - An HTTP error status, from 400 to 599.
243
+ * @param times - How many requests to refuse, or which ones and how many.
244
+ * @defaultValue 1
245
+ */
246
+ refuseNext(status: number, times?: number | FakeRefusal): void
247
+ }
248
+
249
+ /**
250
+ * Which canister requests {@link FakeReplica.refuseNext} refuses, and how
251
+ * many. A request matches when it names `method` and is addressed to
252
+ * `canister`, each when it is given: options with neither match any query or
253
+ * call, as a count does.
254
+ */
255
+ export interface FakeRefusal {
256
+ /**
257
+ * The method a matching `query` or `call` names. A query and a replicated
258
+ * call of the same method both match.
259
+ */
260
+ readonly method?: string
261
+ /**
262
+ * The canister a matching request is addressed to, as text: the canister
263
+ * the request names, not the effective canister it is routed by, so
264
+ * `aaaaa-aa` for a call to the management canister. It need not run on
265
+ * the fake: a gateway refuses a request for a canister that does not exist.
266
+ */
267
+ readonly canister?: string
268
+ /**
269
+ * How many matching requests to refuse: each send counts, an agent's own
270
+ * re-send of a refused request included.
271
+ *
272
+ * @defaultValue 1
273
+ */
274
+ readonly times?: number
275
+ }
276
+
277
+ /** The options of {@link FakeRefusal}, for the message of one that is not. */
278
+ const REFUSAL_OPTIONS = ["method", "canister", "times"] as const
279
+
280
+ /** An armed fault: the requests it matches, and how many it has left. */
281
+ interface Armed {
282
+ readonly method: string | undefined
283
+ readonly canister: string | undefined
284
+ left: number
285
+ }
286
+
287
+ /**
288
+ * Checks the options of `refuseNext` or `dropNextReply`, and returns what
289
+ * they match, with the canister id in its canonical text.
290
+ */
291
+ function readMatch(call: string, options: FakeRefusal): Armed {
292
+ if (
293
+ typeof options !== "object" ||
294
+ options === null ||
295
+ Array.isArray(options)
296
+ ) {
297
+ throw new TypeError(
298
+ `${call}() takes { ${REFUSAL_OPTIONS.join(", ")} }, got ${typeof options}.`
299
+ )
300
+ }
301
+ const unknown = Object.keys(options).filter(
302
+ (key) => !(REFUSAL_OPTIONS as readonly string[]).includes(key)
303
+ )
304
+ if (unknown.length > 0) {
305
+ throw new TypeError(
306
+ `${call}() has no option ${unknown.join(", ")}. Its options: ${REFUSAL_OPTIONS.join(", ")}.`
307
+ )
308
+ }
309
+ const { method, canister, times = 1 } = options
310
+ if (!Number.isInteger(times) || times < 1) {
311
+ throw new RangeError(
312
+ `${call}: \`times\` is ${times}, not a count of at least 1`
313
+ )
314
+ }
315
+ if (method !== undefined && (typeof method !== "string" || !method)) {
316
+ throw new TypeError(
317
+ `${call}: \`method\` is the name of a canister method, got ${
318
+ typeof method === "string" ? '""' : typeof method
319
+ }`
320
+ )
321
+ }
322
+ let canisterId: string | undefined
323
+ if (canister !== undefined) {
324
+ try {
325
+ canisterId = Principal.fromText(canister).toText()
326
+ } catch {
327
+ throw new TypeError(
328
+ `${call}: \`canister\` is a canister id, such as "ryjl3-tyaaa-aaaaa-aaaba-cai" or "aaaaa-aa", got ${
329
+ typeof canister === "string"
330
+ ? JSON.stringify(canister)
331
+ : typeof canister
332
+ }`
333
+ )
334
+ }
335
+ }
336
+ return { method, canister: canisterId, left: times }
337
+ }
338
+
339
+ /**
340
+ * The first fault in `armed` that a request for `method` on `canisterId`
341
+ * matches, with one use taken from it (and removed once it has none left);
342
+ * `undefined` when none matches.
343
+ */
344
+ function useUp<T extends Armed>(
345
+ armed: T[],
346
+ canisterId: string,
347
+ method: string | undefined
348
+ ): T | undefined {
349
+ const index = armed.findIndex(
350
+ (fault) =>
351
+ (fault.method === undefined || fault.method === method) &&
352
+ (fault.canister === undefined || fault.canister === canisterId)
353
+ )
354
+ if (index === -1) return undefined
355
+ const fault = armed[index]
356
+ fault.left -= 1
357
+ if (fault.left === 0) armed.splice(index, 1)
358
+ return fault
359
+ }
360
+
361
+ /**
362
+ * Rejects a call with a reject code. Thrown by {@link FakeReplica.reject}.
363
+ *
364
+ * @internal
365
+ */
366
+ export class FakeReplicaReject extends Error {
367
+ constructor(
368
+ readonly rejectCode: number,
369
+ readonly errorCode: string | undefined,
370
+ message: string
371
+ ) {
372
+ super(message)
373
+ this.name = "FakeReplicaReject"
374
+ }
375
+ }
376
+
377
+ /**
378
+ * Thrown out of the fake's `fetch` when a reply is lost, in the form of a
379
+ * network failure.
380
+ */
381
+ class LostReply extends TypeError {}
382
+
383
+ /** The client's `"local"` network: icp-cli's gateway on its default port. */
384
+ const DEFAULT_HOST = "http://127.0.0.1:8000"
385
+
386
+ /**
387
+ * The page's origin when it is one the fake can answer for, which is where an
388
+ * agent built with no `host` calls: a local or remote development origin,
389
+ * such as jsdom's `http://localhost:3000`. A mainnet origin is left out, as
390
+ * its agents check certificates against mainnet's root key.
391
+ */
392
+ function localPageOrigin(): string | undefined {
393
+ try {
394
+ const origin = (globalThis as { location?: { origin?: string } }).location
395
+ ?.origin
396
+ if (!origin) return undefined
397
+ const { protocol, hostname } = new URL(origin)
398
+ return (protocol === "http:" || protocol === "https:") &&
399
+ isNonMainnetPageHost(hostname)
400
+ ? origin
401
+ : undefined
402
+ } catch {
403
+ // No page (Node), an opaque origin ("null"), or a `location` that throws.
404
+ return undefined
405
+ }
406
+ }
407
+
408
+ /**
409
+ * The IC HTTP API paths an agent requests: the status endpoint, and a
410
+ * canister's or subnet's `query`, `call` and `read_state`. Anything else, such
411
+ * as an app's own `/api/v1/...` REST calls, is not the fake's to answer.
412
+ */
413
+ const IC_API_PATH =
414
+ /^\/api\/v\d+\/(?:status|(?:canister|subnet)\/[^/]+\/(?:query|call|read_state))$/
415
+
416
+ /**
417
+ * The URL a request is for. An agent always asks for an absolute one; an app
418
+ * may ask for a path, which a browser, happy-dom or a request mock such as
419
+ * MSW reads against the page. `undefined` when it cannot be read at all.
420
+ */
421
+ function urlOf(input: RequestInfo | URL): URL | undefined {
422
+ const raw = input instanceof Request ? input.url : String(input)
423
+ let base: string | undefined
424
+ try {
425
+ base = (globalThis as { location?: { href?: string } }).location?.href
426
+ } catch {
427
+ base = undefined
428
+ }
429
+ try {
430
+ return new URL(raw, base)
431
+ } catch {
432
+ return undefined
433
+ }
434
+ }
435
+
436
+ const encoder = new TextEncoder()
437
+ // Copied: a jsdom test setup often installs Node's `TextEncoder`, whose bytes
438
+ // come from another realm than the environment's `Uint8Array`. The CBOR
439
+ // encoder does not recognise them as bytes and writes them out as a map.
440
+ const utf8 = (text: string) => new Uint8Array(encoder.encode(text))
441
+
442
+ /** A subtree to certify: a leaf's bytes, or labelled children. */
443
+ type TreeNode = Uint8Array | Array<[string | Uint8Array, TreeNode]>
444
+
445
+ function compareBytes(a: Uint8Array, b: Uint8Array): number {
446
+ const length = Math.min(a.length, b.length)
447
+ for (let i = 0; i < length; i += 1) {
448
+ if (a[i] !== b[i]) return a[i] - b[i]
449
+ }
450
+ return a.length - b.length
451
+ }
452
+
453
+ function toHashTree(node: TreeNode): HashTree {
454
+ if (!Array.isArray(node)) {
455
+ return [NodeType.Leaf, node] as HashTree
456
+ }
457
+ // Ascending, because the agent's label search stops at the first label
458
+ // greater than the one it wants.
459
+ const labelled = node
460
+ .map(([label, child]) => ({
461
+ label: typeof label === "string" ? utf8(label) : label,
462
+ child,
463
+ }))
464
+ .sort((a, b) => compareBytes(a.label, b.label))
465
+ .map(
466
+ ({ label, child }) =>
467
+ [NodeType.Labeled, label, toHashTree(child)] as HashTree
468
+ )
469
+ return fork(labelled)
470
+ }
471
+
472
+ function fork(nodes: HashTree[]): HashTree {
473
+ if (nodes.length === 0) return [NodeType.Empty]
474
+ if (nodes.length === 1) return nodes[0]
475
+ const middle = Math.ceil(nodes.length / 2)
476
+ return [
477
+ NodeType.Fork,
478
+ fork(nodes.slice(0, middle)),
479
+ fork(nodes.slice(middle)),
480
+ ]
481
+ }
482
+
483
+ function leb128(value: bigint): Uint8Array {
484
+ const out: number[] = []
485
+ let rest = value
486
+ do {
487
+ let byte = Number(rest & 0x7fn)
488
+ rest >>= 7n
489
+ if (rest !== 0n) byte |= 0x80
490
+ out.push(byte)
491
+ } while (rest !== 0n)
492
+ return new Uint8Array(out)
493
+ }
494
+
495
+ function concat(...parts: Uint8Array[]): Uint8Array {
496
+ const out = new Uint8Array(parts.reduce((n, part) => n + part.length, 0))
497
+ let offset = 0
498
+ for (const part of parts) {
499
+ out.set(part, offset)
500
+ offset += part.length
501
+ }
502
+ return out
503
+ }
504
+
505
+ const nowNanos = () => BigInt(Date.now()) * 1_000_000n
506
+
507
+ function cborResponse(body: unknown, status = 200): Response {
508
+ return new Response(Cbor.encode(body) as BodyInit, {
509
+ status,
510
+ headers: { "content-type": "application/cbor" },
511
+ })
512
+ }
513
+
514
+ interface Envelope {
515
+ content: {
516
+ canister_id?: Uint8Array
517
+ method_name?: string
518
+ arg?: Uint8Array
519
+ paths?: Uint8Array[][]
520
+ sender: Uint8Array
521
+ }
522
+ sender_pubkey?: Uint8Array
523
+ sender_sig?: Uint8Array
524
+ sender_delegation?: Array<{
525
+ delegation: {
526
+ pubkey: Uint8Array
527
+ expiration: bigint | number
528
+ targets?: Uint8Array[]
529
+ }
530
+ signature: Uint8Array
531
+ }>
532
+ }
533
+
534
+ // The DER prefix of each kind of key an identity in `@icp-sdk/core` signs
535
+ // with, before the raw key: Ed25519, ECDSA on P-256 (`ECDSAKeyIdentity`, and
536
+ // the session keys `@icp-sdk/auth` makes) and ECDSA on secp256k1.
537
+ const hex = (text: string) =>
538
+ Uint8Array.from(text.match(/../g) ?? [], (byte) => parseInt(byte, 16))
539
+ const ED25519_SPKI_PREFIX = hex("302a300506032b6570032100")
540
+ const P256_SPKI_PREFIX = hex(
541
+ "3059301306072a8648ce3d020106082a8648ce3d030107034200"
542
+ )
543
+ const SECP256K1_SPKI_PREFIX = hex(
544
+ "3056301006072a8648ce3d020106052b8104000a034200"
545
+ )
546
+
547
+ const startsWith = (bytes: Uint8Array, prefix: Uint8Array) =>
548
+ bytes.length > prefix.length && prefix.every((byte, i) => bytes[i] === byte)
549
+
550
+ /**
551
+ * Whether `signature` is the signature of the key `publicKey` (DER) over
552
+ * `message`, or `undefined` for a kind of key the fake cannot check.
553
+ */
554
+ function verifySignature(
555
+ publicKey: Uint8Array,
556
+ signature: Uint8Array,
557
+ message: Uint8Array
558
+ ): boolean | undefined {
559
+ try {
560
+ if (startsWith(publicKey, ED25519_SPKI_PREFIX)) {
561
+ const raw = publicKey.subarray(ED25519_SPKI_PREFIX.length)
562
+ return ed25519.verify(signature, message, raw)
563
+ }
564
+ if (startsWith(publicKey, P256_SPKI_PREFIX)) {
565
+ // WebCrypto, which signs for `ECDSAKeyIdentity`, does not normalise S.
566
+ const raw = publicKey.subarray(P256_SPKI_PREFIX.length)
567
+ return p256.verify(signature, message, raw, { lowS: false })
568
+ }
569
+ if (startsWith(publicKey, SECP256K1_SPKI_PREFIX)) {
570
+ const raw = publicKey.subarray(SECP256K1_SPKI_PREFIX.length)
571
+ return secp256k1.verify(signature, message, raw)
572
+ }
573
+ } catch {
574
+ // A malformed key or signature does not verify.
575
+ return false
576
+ }
577
+ return undefined
578
+ }
579
+
580
+ /** A canister's reply, or the reject a replica sends in its place. */
581
+ type Outcome =
582
+ | { reply: Uint8Array }
583
+ | { reject: { code: number; message: string; errorCode?: string } }
584
+
585
+ const messageOf = (error: unknown) =>
586
+ error instanceof Error ? error.message : String(error)
587
+
588
+ /** Lower-case hex of `bytes`: a map key for a request id. */
589
+ const toHex = (bytes: Uint8Array) =>
590
+ Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("")
591
+
592
+ /** The names the interface specification gives each reject code. */
593
+ const REJECT_NAMES: Record<FakeRejectCode, string> = {
594
+ 1: "SYS_FATAL",
595
+ 2: "SYS_TRANSIENT",
596
+ 3: "DESTINATION_INVALID",
597
+ 4: "CANISTER_REJECT",
598
+ 5: "CANISTER_ERROR",
599
+ 6: "SYS_UNKNOWN",
600
+ }
601
+
602
+ /**
603
+ * Creates a fake replica that runs `options.canisters`, to give to the agents
604
+ * under test as their `fetch`. Nothing global is touched, so two fakes run
605
+ * side by side in one process, each with its own root key, node key and
606
+ * request log, and the agents that use one never reach the other.
607
+ *
608
+ * Point an agent at it with its `host`, its `fetch` and its root key:
609
+ * `HttpAgent.createSync({ host: replica.host, fetch: replica.fetch, rootKey:
610
+ * replica.rootKey })`, or pass `shouldFetchRootKey: true` instead of the
611
+ * `rootKey` to let the agent fetch it from the fake as it does from a local
612
+ * replica. The fake answers the IC API on `replica.host` and refuses the IC
613
+ * API on any other origin as a network error, which it also logs once, so a
614
+ * test never reaches a real network by mistake.
615
+ *
616
+ * It checks each request's signatures as a replica does, and refuses one that
617
+ * does not verify with HTTP 400. It can check Ed25519, ECDSA P-256 and
618
+ * secp256k1 keys, including delegation chains between them, which covers
619
+ * `Ed25519KeyIdentity`, `ECDSAKeyIdentity`, `Secp256k1KeyIdentity` and a
620
+ * `DelegationIdentity` built from them. It refuses any other kind of key.
621
+ *
622
+ * An agent keeps the node keys it reads in IndexedDB when the environment has
623
+ * one, under a name that holds only the host. Agents of two fakes that share a
624
+ * host therefore share cached keys. The agent notices a signature that does
625
+ * not verify and reads fresh keys, but pass each agent its own
626
+ * `subnetNodeKeyExpirableStore` to keep them apart.
627
+ *
628
+ * The signing uses `@noble/curves`, an optional peer dependency of
629
+ * `@ic-reactor/core` that `@icp-sdk/core` already installs. Add it to your
630
+ * devDependencies if your package manager does not let this package resolve
631
+ * it.
632
+ *
633
+ * @param options - The canisters to run and the origin to answer for.
634
+ * @returns The fake: its `fetch`, `host` and `rootKey`, the requests it
635
+ * received, and the hooks that fail a call on purpose.
636
+ *
637
+ * @example
638
+ * ```typescript
639
+ * import { HttpAgent } from "@icp-sdk/core/agent"
640
+ * import { IDL } from "@icp-sdk/core/candid"
641
+ * // Internal: core's own tests import it from its module.
642
+ * import { createFakeReplica } from "../src/testing/fake-replica.js"
643
+ *
644
+ * const BACKEND = "bkyz2-fmaaa-aaaaa-qaaaq-cai"
645
+ *
646
+ * const replica = createFakeReplica({
647
+ * canisters: {
648
+ * [BACKEND]: {
649
+ * query: () => new Uint8Array(IDL.encode([IDL.Text], ["Hello, Ada!"])),
650
+ * update: () => replica.reject(4, "not today"),
651
+ * },
652
+ * },
653
+ * })
654
+ * const agent = HttpAgent.createSync({
655
+ * host: replica.host,
656
+ * fetch: replica.fetch,
657
+ * rootKey: replica.rootKey,
658
+ * })
659
+ *
660
+ * const answer = await agent.query(BACKEND, {
661
+ * methodName: "greet",
662
+ * arg: new Uint8Array(IDL.encode([IDL.Text], ["Ada"])),
663
+ * })
664
+ * ```
665
+ */
666
+ export function createFakeReplica(
667
+ options: FakeReplicaOptions = {}
668
+ ): FakeReplica {
669
+ const host = new URL(options.host ?? localPageOrigin() ?? DEFAULT_HOST).origin
670
+ const canisters: Record<string, FakeCanister> = {}
671
+ const requests: FakeReplicaRequest[] = []
672
+
673
+ // Throws for an ID that is not a canister ID.
674
+ function canisterIdOf(id: string): Principal {
675
+ try {
676
+ return Principal.fromText(id)
677
+ } catch {
678
+ throw new Error(
679
+ `fake replica: "${id}" in \`canisters\` is not a canister ID`
680
+ )
681
+ }
682
+ }
683
+ function addCanister(id: string, canister: FakeCanister) {
684
+ canisters[canisterIdOf(id).toText()] = canister
685
+ }
686
+ for (const [id, canister] of Object.entries(options.canisters ?? {})) {
687
+ addCanister(id, canister)
688
+ }
689
+
690
+ const secretKey = bls12_381.utils.randomSecretKey()
691
+ const rootKey = wrapDER(
692
+ bls12_381.shortSignatures.getPublicKey(secretKey).toBytes(),
693
+ BLS12_381_G2_OID
694
+ )
695
+ // With no delegation in its certificates, the subnet an agent checks node
696
+ // keys and canister ranges under is the one the root key names.
697
+ const subnetId = Principal.selfAuthenticating(rootKey)
698
+ const node = Ed25519KeyIdentity.generate()
699
+ const nodeKey = new Uint8Array(node.getPublicKey().toDer())
700
+ const nodeId = Principal.selfAuthenticating(nodeKey)
701
+
702
+ // The fault hooks' state: the drops and the refusals still armed, each in
703
+ // the order they were armed, and the calls whose reply was lost.
704
+ const drops: Armed[] = []
705
+ const refusals: Array<Armed & { readonly status: number }> = []
706
+ const lostRequests = new Set<string>()
707
+
708
+ /**
709
+ * The status to refuse a `query` or `call` with, from the first armed
710
+ * refusal it matches, which it uses up; `undefined` to let it through.
711
+ */
712
+ function refusalFor(canisterId: string, method: string | undefined) {
713
+ return useUp(refusals, canisterId, method)?.status
714
+ }
715
+
716
+ async function certify(entries: Array<[string, TreeNode]>) {
717
+ const tree = toHashTree([
718
+ ...entries,
719
+ ["time", leb128((options.now ?? nowNanos)())],
720
+ ])
721
+ const rootHash = await reconstruct(tree)
722
+ const message = bls12_381.shortSignatures.hash(
723
+ concat(IC_STATE_ROOT_DOMAIN_SEPARATOR, rootHash)
724
+ )
725
+ const signature = bls12_381.shortSignatures.sign(message, secretKey)
726
+ return Cbor.encode({ tree, signature: signature.toBytes() })
727
+ }
728
+
729
+ /**
730
+ * Who sent `envelope`, checked as a replica checks it, or why it is refused.
731
+ */
732
+ function authenticate(
733
+ envelope: Envelope,
734
+ canisterId: string
735
+ ): Principal | string {
736
+ const sender = Principal.fromUint8Array(envelope.content.sender)
737
+ const { sender_pubkey, sender_sig, sender_delegation = [] } = envelope
738
+
739
+ if (sender.isAnonymous()) {
740
+ return sender_pubkey || sender_sig
741
+ ? "an anonymous request carries a signature"
742
+ : sender
743
+ }
744
+ if (!sender_pubkey || !sender_sig) {
745
+ return "the request is not signed"
746
+ }
747
+ if (
748
+ Principal.selfAuthenticating(sender_pubkey).toText() !== sender.toText()
749
+ ) {
750
+ return "the sender is not the principal of sender_pubkey"
751
+ }
752
+
753
+ const now = nowNanos()
754
+ let signer = sender_pubkey
755
+ for (const { delegation, signature } of sender_delegation) {
756
+ const challenge = concat(
757
+ IC_REQUEST_AUTH_DELEGATION_DOMAIN_SEPARATOR,
758
+ requestIdOf(delegation)
759
+ )
760
+ const signed = verifySignature(signer, signature, challenge)
761
+ if (signed === undefined) {
762
+ return "a delegation is signed by a kind of key the fake replica cannot check"
763
+ }
764
+ if (!signed) {
765
+ return "a delegation is not signed by the key before it"
766
+ }
767
+ if (BigInt(delegation.expiration) <= now) {
768
+ return "a delegation has expired"
769
+ }
770
+ if (
771
+ delegation.targets &&
772
+ !delegation.targets.some(
773
+ (target) => Principal.fromUint8Array(target).toText() === canisterId
774
+ )
775
+ ) {
776
+ return `a delegation does not allow calls to ${canisterId}`
777
+ }
778
+ signer = delegation.pubkey
779
+ }
780
+
781
+ const message = concat(
782
+ IC_REQUEST_DOMAIN_SEPARATOR,
783
+ requestIdOf(envelope.content)
784
+ )
785
+ const signed = verifySignature(signer, sender_sig, message)
786
+ if (signed === undefined) {
787
+ return "the request is signed by a kind of key the fake replica cannot check"
788
+ }
789
+ if (!signed) {
790
+ return "sender_sig is not the signing key's signature over the request"
791
+ }
792
+ return sender
793
+ }
794
+
795
+ /** Runs a canister's handler, and turns what it throws into a reject. */
796
+ async function execute(
797
+ kind: "query" | "update",
798
+ canisterId: string,
799
+ method: string,
800
+ arg: Uint8Array,
801
+ caller: Principal
802
+ ): Promise<Outcome> {
803
+ const reject = (
804
+ code: number,
805
+ errorCode: string | undefined,
806
+ message: string
807
+ ): Outcome => ({ reject: { code, errorCode, message } })
808
+
809
+ const canister = Object.prototype.hasOwnProperty.call(canisters, canisterId)
810
+ ? canisters[canisterId]
811
+ : undefined
812
+ if (!canister) {
813
+ return reject(
814
+ ReplicaRejectCode.DestinationInvalid,
815
+ "IC0301",
816
+ `fake replica: no canister is installed at ${canisterId}`
817
+ )
818
+ }
819
+ const handler = kind === "query" ? canister.query : canister.update
820
+ if (!handler) {
821
+ return reject(
822
+ ReplicaRejectCode.DestinationInvalid,
823
+ "IC0536",
824
+ `fake replica: canister ${canisterId} answers no ${kind === "query" ? "queries" : "update calls"}`
825
+ )
826
+ }
827
+ try {
828
+ return {
829
+ reply: new Uint8Array(
830
+ await handler.call(canister, method, arg, { caller })
831
+ ),
832
+ }
833
+ } catch (error) {
834
+ if (error instanceof FakeReplicaReject) {
835
+ return reject(error.rejectCode, error.errorCode, error.message)
836
+ }
837
+ return reject(
838
+ ReplicaRejectCode.CanisterError,
839
+ "IC0503",
840
+ `Canister ${canisterId} trapped: ${messageOf(error)}`
841
+ )
842
+ }
843
+ }
844
+
845
+ async function handleQuery(
846
+ canisterId: string,
847
+ effectiveCanisterId: string,
848
+ envelope: Envelope,
849
+ caller: Principal
850
+ ) {
851
+ const { method_name = "", arg = new Uint8Array() } = envelope.content
852
+ requests.push({
853
+ endpoint: "query",
854
+ canisterId,
855
+ effectiveCanisterId,
856
+ methodName: method_name,
857
+ caller: caller.toText(),
858
+ })
859
+ const outcome = await execute("query", canisterId, method_name, arg, caller)
860
+ const timestamp = nowNanos()
861
+ const request_id = requestIdOf(envelope.content)
862
+ const body =
863
+ "reply" in outcome
864
+ ? { status: "replied", reply: { arg: outcome.reply } }
865
+ : {
866
+ status: "rejected",
867
+ reject_code: outcome.reject.code,
868
+ reject_message: outcome.reject.message,
869
+ ...(outcome.reject.errorCode === undefined
870
+ ? {}
871
+ : { error_code: outcome.reject.errorCode }),
872
+ }
873
+ const hash = hashOfMap({ ...body, timestamp, request_id })
874
+ const signature = await node.sign(
875
+ concat(IC_RESPONSE_DOMAIN_SEPARATOR, hash)
876
+ )
877
+ return cborResponse({
878
+ ...body,
879
+ signatures: [
880
+ {
881
+ timestamp,
882
+ signature: new Uint8Array(signature),
883
+ identity: nodeId.toUint8Array(),
884
+ },
885
+ ],
886
+ })
887
+ }
888
+
889
+ async function handleCall(
890
+ canisterId: string,
891
+ effectiveCanisterId: string,
892
+ envelope: Envelope,
893
+ caller: Principal
894
+ ) {
895
+ const { method_name = "", arg = new Uint8Array() } = envelope.content
896
+ const requestId = toHex(requestIdOf(envelope.content))
897
+ // A request id whose reply was lost stays lost: a re-send is neither run
898
+ // nor answered again, and its status cannot be read (see
899
+ // `readsLostRequest`). That models a partition for that one request id,
900
+ // not what a replica does, which would still answer a `read_state`.
901
+ const resent = lostRequests.has(requestId)
902
+ const lose = resent || useUp(drops, canisterId, method_name) !== undefined
903
+ if (lose && !resent) lostRequests.add(requestId)
904
+ requests.push({
905
+ endpoint: "call",
906
+ canisterId,
907
+ effectiveCanisterId,
908
+ methodName: method_name,
909
+ caller: caller.toText(),
910
+ ...(lose ? { dropped: true as const } : {}),
911
+ })
912
+ if (resent) throw lostReply(method_name)
913
+
914
+ const outcome = await execute(
915
+ "update",
916
+ canisterId,
917
+ method_name,
918
+ arg,
919
+ caller
920
+ )
921
+ // The canister has run and its state has changed; only the answer is lost.
922
+ if (lose) throw lostReply(method_name)
923
+
924
+ const status: Array<[string, TreeNode]> =
925
+ "reply" in outcome
926
+ ? [
927
+ ["status", utf8("replied")],
928
+ ["reply", outcome.reply],
929
+ ]
930
+ : [
931
+ ["status", utf8("rejected")],
932
+ ["reject_code", leb128(BigInt(outcome.reject.code))],
933
+ ["reject_message", utf8(outcome.reject.message)],
934
+ ...(outcome.reject.errorCode === undefined
935
+ ? []
936
+ : ([["error_code", utf8(outcome.reject.errorCode)]] as Array<
937
+ [string, TreeNode]
938
+ >)),
939
+ ]
940
+ const certificate = await certify([
941
+ ["request_status", [[requestIdOf(envelope.content), status]]],
942
+ ])
943
+ return cborResponse({ status: "replied", certificate })
944
+ }
945
+
946
+ /** Whether `envelope` reads the status of a call whose reply was lost. */
947
+ const readsLostRequest = (envelope: Envelope) =>
948
+ (envelope.content.paths ?? []).some(
949
+ ([label, id]) =>
950
+ label !== undefined &&
951
+ id !== undefined &&
952
+ new TextDecoder().decode(label) === "request_status" &&
953
+ lostRequests.has(toHex(id))
954
+ )
955
+
956
+ async function handleReadState(canisterId: string) {
957
+ requests.push({
958
+ endpoint: "read_state",
959
+ canisterId,
960
+ effectiveCanisterId: canisterId,
961
+ })
962
+ // The subnet holds the installed canisters and the one asked about, so a
963
+ // query to a canister that is not installed reaches the canister lookup
964
+ // and is rejected there, rather than failing the agent's range check.
965
+ const inSubnet = [
966
+ ...Object.keys(canisters).map((id) => Principal.fromText(id)),
967
+ Principal.fromText(canisterId),
968
+ ]
969
+ .map((id) => id.toUint8Array())
970
+ .sort(compareBytes)
971
+ .filter((id, i, ids) => i === 0 || compareBytes(ids[i - 1], id) !== 0)
972
+ const certificate = await certify([
973
+ [
974
+ "subnet",
975
+ [
976
+ [
977
+ subnetId.toUint8Array(),
978
+ [
979
+ ["canister_ranges", Cbor.encode(inSubnet.map((id) => [id, id]))],
980
+ ["node", [[nodeId.toUint8Array(), [["public_key", nodeKey]]]]],
981
+ ],
982
+ ],
983
+ ],
984
+ ],
985
+ ])
986
+ return cborResponse({ certificate })
987
+ }
988
+
989
+ // Origins a misrouted IC API request came from, each logged once.
990
+ const misrouted = new Set<string>()
991
+
992
+ const fakeFetch = async (
993
+ input: RequestInfo | URL,
994
+ init?: RequestInit
995
+ ): Promise<Response> => {
996
+ const url = urlOf(input)
997
+ if (!url || !IC_API_PATH.test(url.pathname)) {
998
+ throw new TypeError(
999
+ `fake replica: ${url?.href ?? String(input)} is not an IC API request, ` +
1000
+ `which is all the fake answers`
1001
+ )
1002
+ }
1003
+
1004
+ if (url.origin !== host) {
1005
+ const message =
1006
+ `fake replica: no route to ${url.origin}. The fake answers ${host}; ` +
1007
+ `build the agent with \`host: replica.host\` and \`fetch: replica.fetch\`, ` +
1008
+ `or create the fake with \`host: "${url.origin}"\``
1009
+ // The agent retries a failed request, and a query hook retries a
1010
+ // failed query, so the error below can surface long after the test
1011
+ // timed out. Logged here, the cause shows up at once.
1012
+ if (!misrouted.has(url.origin)) {
1013
+ misrouted.add(url.origin)
1014
+ console.error(message)
1015
+ }
1016
+ throw new TypeError(message)
1017
+ }
1018
+
1019
+ if (url.pathname === "/api/v2/status") {
1020
+ requests.push({ endpoint: "status" })
1021
+ return cborResponse({
1022
+ ic_api_version: "0.18.0",
1023
+ impl_version: "fake",
1024
+ replica_health_status: "healthy",
1025
+ root_key: rootKey,
1026
+ })
1027
+ }
1028
+
1029
+ const match =
1030
+ /^\/api\/v[234]\/canister\/([^/]+)\/(query|call|read_state)$/.exec(
1031
+ url.pathname
1032
+ )
1033
+ if (!match) {
1034
+ return new Response(`fake replica: no endpoint ${url.pathname}`, {
1035
+ status: 404,
1036
+ })
1037
+ }
1038
+
1039
+ const [, effectiveCanisterId, path] = match
1040
+ const endpoint = path as "query" | "call" | "read_state"
1041
+
1042
+ try {
1043
+ const body = new Uint8Array(
1044
+ await new Response(
1045
+ input instanceof Request ? input.body : (init?.body as BodyInit)
1046
+ ).arrayBuffer()
1047
+ )
1048
+ const envelope = Cbor.decode(body) as Envelope
1049
+ // A call goes to the canister it names, as on a replica. The path
1050
+ // names the effective canister, which only routes the request to a
1051
+ // subnet and differs when the caller passes `effectiveCanisterId`.
1052
+ const canisterId = envelope.content.canister_id
1053
+ ? Principal.fromUint8Array(envelope.content.canister_id).toText()
1054
+ : effectiveCanisterId
1055
+
1056
+ // Before the signatures are read, as a gateway refuses a request.
1057
+ const status =
1058
+ endpoint === "read_state"
1059
+ ? undefined
1060
+ : refusalFor(canisterId, envelope.content.method_name)
1061
+ if (status !== undefined) {
1062
+ const refused = `refuseNext(${status}) answered the request with HTTP ${status}`
1063
+ requests.push({
1064
+ endpoint,
1065
+ canisterId,
1066
+ effectiveCanisterId,
1067
+ methodName: envelope.content.method_name,
1068
+ refused,
1069
+ })
1070
+ return new Response(`fake replica: ${refused}`, { status })
1071
+ }
1072
+
1073
+ const caller = authenticate(envelope, canisterId)
1074
+ if (typeof caller === "string") {
1075
+ requests.push({
1076
+ endpoint,
1077
+ canisterId,
1078
+ effectiveCanisterId,
1079
+ methodName: envelope.content.method_name,
1080
+ refused: caller,
1081
+ })
1082
+ return new Response(`fake replica: ${caller}`, { status: 400 })
1083
+ }
1084
+
1085
+ if (endpoint === "query") {
1086
+ return await handleQuery(
1087
+ canisterId,
1088
+ effectiveCanisterId,
1089
+ envelope,
1090
+ caller
1091
+ )
1092
+ }
1093
+ if (endpoint === "call") {
1094
+ return await handleCall(
1095
+ canisterId,
1096
+ effectiveCanisterId,
1097
+ envelope,
1098
+ caller
1099
+ )
1100
+ }
1101
+ if (readsLostRequest(envelope)) {
1102
+ requests.push({
1103
+ endpoint,
1104
+ canisterId: effectiveCanisterId,
1105
+ effectiveCanisterId,
1106
+ dropped: true,
1107
+ })
1108
+ throw lostReply()
1109
+ }
1110
+ return await handleReadState(effectiveCanisterId)
1111
+ } catch (error) {
1112
+ // A lost reply is the network failing, which the agent sees as the
1113
+ // fetch rejecting, not as an HTTP answer.
1114
+ if (error instanceof LostReply) throw error
1115
+ // A request the fake cannot read, or a bug in the fake. The agent sees
1116
+ // an HTTP error, which fails the test; the details go to its output.
1117
+ console.error("fake replica:", error)
1118
+ return new Response(
1119
+ `fake replica: the request failed: ${messageOf(error)}`,
1120
+ { status: 500 }
1121
+ )
1122
+ }
1123
+ }
1124
+
1125
+ return {
1126
+ host,
1127
+ rootKey,
1128
+ fetch: fakeFetch,
1129
+ requests,
1130
+ addCanister,
1131
+ reject(code, message) {
1132
+ throw new FakeReplicaReject(
1133
+ code,
1134
+ undefined,
1135
+ message ??
1136
+ `fake replica: the canister rejected the call with reject code ${code} (${REJECT_NAMES[code]})`
1137
+ )
1138
+ },
1139
+ dropNextReply(which) {
1140
+ drops.push(readMatch("dropNextReply", which === undefined ? {} : which))
1141
+ },
1142
+ refuseNext(status, which = 1) {
1143
+ if (!Number.isInteger(status) || status < 400 || status > 599) {
1144
+ throw new RangeError(
1145
+ `refuseNext: ${status} is not an HTTP error status (400 to 599)`
1146
+ )
1147
+ }
1148
+ // A count, or anything that is not an object, is the published
1149
+ // `(status, times?)` form, checked as it always was.
1150
+ const options: FakeRefusal =
1151
+ typeof which === "object" && which !== null && !Array.isArray(which)
1152
+ ? which
1153
+ : { times: which as number }
1154
+ refusals.push({ status, ...readMatch("refuseNext", options) })
1155
+ },
1156
+ }
1157
+ }
1158
+
1159
+ /**
1160
+ * The error a request fails with when its reply is lost: a `fetch` rejection,
1161
+ * as a dropped connection is.
1162
+ */
1163
+ const lostReply = (method?: string) =>
1164
+ new LostReply(
1165
+ `fake replica: the connection was lost before the reply${method ? ` to ${method}` : ""} arrived`
1166
+ )