@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.
- package/.github/ISSUE_TEMPLATE/bug_report.yml +108 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +77 -0
- package/.github/actions/setup-rust-wasm/action.yml +25 -0
- package/.github/dependabot.yml +107 -0
- package/.github/workflows/auth-latest.yml +67 -0
- package/.github/workflows/b3pay-site.yml +49 -0
- package/.github/workflows/ci.yml +430 -0
- package/.github/workflows/codeql.yml +41 -0
- package/.github/workflows/dependency-review.yml +68 -0
- package/.github/workflows/docs-check.yml +98 -0
- package/.github/workflows/docs.yml +265 -0
- package/.github/workflows/e2e.yml +90 -0
- package/.github/workflows/examples-published.yml +97 -0
- package/.github/workflows/release.yml +326 -0
- package/.husky/pre-commit +12 -0
- package/.prettierignore +109 -0
- package/.prettierrc +6 -0
- package/AGENTS.md +103 -0
- package/CHANGELOG.md +3268 -0
- package/CLAUDE.md +93 -0
- package/CNAME +1 -0
- package/CODE_OF_CONDUCT.md +7 -0
- package/CONTRIBUTING.md +433 -0
- package/LICENSE +21 -0
- package/README.md +2 -2
- package/SECURITY.md +74 -0
- package/b3pay-module.json +194 -0
- package/docs/.remarkrc.json +10 -0
- package/docs/README.md +64 -0
- package/docs/astro.config.mjs +205 -0
- package/docs/favicon.svg +15 -0
- package/docs/package.json +39 -0
- package/docs/public/favicon.svg +15 -0
- package/docs/public/ic-reactor-social-card.png +0 -0
- package/docs/scripts/b3pay-static.mjs +22 -0
- package/docs/scripts/check-example-docs.mjs +214 -0
- package/docs/scripts/check-links.mjs +212 -0
- package/docs/scripts/fix-dist-links.js +125 -0
- package/docs/scripts/fix-frontmatter.js +71 -0
- package/docs/scripts/remove-redundant-h1.cjs +48 -0
- package/docs/scripts/rewrite-typedoc-links.js +110 -0
- package/docs/scripts/split-index.js +69 -0
- package/docs/src/assets/ic-reactor-hero-dark.svg +23 -0
- package/docs/src/assets/ic-reactor-hero-light.svg +23 -0
- package/docs/src/assets/ic-reactor-lockup-dark.svg +15 -0
- package/docs/src/assets/ic-reactor-lockup-light.svg +15 -0
- package/docs/src/assets/ic-reactor-mark-dark.svg +14 -0
- package/docs/src/assets/ic-reactor-mark-light.svg +14 -0
- package/docs/src/assets/layers/candid-core-layer-icon-dark.svg +4 -0
- package/docs/src/assets/layers/candid-core-layer-icon-light.svg +4 -0
- package/docs/src/assets/layers/candid-profile-layer-icon-dark.svg +4 -0
- package/docs/src/assets/layers/candid-profile-layer-icon-light.svg +4 -0
- package/docs/src/assets/layers/ic-reactor-layer-icon-dark.svg +4 -0
- package/docs/src/assets/layers/ic-reactor-layer-icon-light.svg +4 -0
- package/docs/src/components/LibraryCards.astro +172 -0
- package/docs/src/components/LibraryIcon.astro +28 -0
- package/docs/src/components/SiteTitle.astro +241 -0
- package/docs/src/content/docs/404.mdx +19 -0
- package/docs/src/content/docs/build/agent-tools.mdx +593 -0
- package/docs/src/content/docs/build/icrc1-wallet.mdx +619 -0
- package/docs/src/content/docs/build/ssr-per-user.mdx +552 -0
- package/docs/src/content/docs/examples/canister-studio.mdx +95 -0
- package/docs/src/content/docs/examples/icrc-ledger.mdx +45 -0
- package/docs/src/content/docs/examples/index.mdx +38 -0
- package/docs/src/content/docs/examples/next-ssr.mdx +73 -0
- package/docs/src/content/docs/examples/node-agent-tool.mdx +80 -0
- package/docs/src/content/docs/examples/vite-wallet.mdx +71 -0
- package/docs/src/content/docs/guides/auth.mdx +1181 -0
- package/docs/src/content/docs/guides/client.mdx +551 -0
- package/docs/src/content/docs/guides/deploy.mdx +180 -0
- package/docs/src/content/docs/guides/errors.mdx +475 -0
- package/docs/src/content/docs/guides/getting-started.mdx +620 -0
- package/docs/src/content/docs/guides/reads.mdx +586 -0
- package/docs/src/content/docs/guides/ssr.mdx +529 -0
- package/docs/src/content/docs/guides/testing.mdx +401 -0
- package/docs/src/content/docs/guides/values.mdx +261 -0
- package/docs/src/content/docs/guides/vite-plugin.mdx +690 -0
- package/docs/src/content/docs/guides/writes.mdx +572 -0
- package/docs/src/content/docs/ic-reactor/index.mdx +167 -0
- package/docs/src/content/docs/index.mdx +65 -0
- package/docs/src/content/docs/migrating-from-3.mdx +535 -0
- package/docs/src/content/docs/packages/core.mdx +186 -0
- package/docs/src/content/docs/packages/mcp.mdx +163 -0
- package/docs/src/content/docs/packages/react.mdx +207 -0
- package/docs/src/content/docs/packages/vite-plugin.mdx +73 -0
- package/docs/src/content/docs/versioning.mdx +104 -0
- package/docs/src/content.config.ts +7 -0
- package/docs/src/styles/custom.css +189 -0
- package/docs/tsconfig.typedoc.json +26 -0
- package/docs/typedoc-entry.ts +17 -0
- package/docs/typedoc.json +37 -0
- package/e2e/Cargo.lock +646 -0
- package/e2e/Cargo.toml +3 -0
- package/e2e/README.md +101 -0
- package/e2e/frontends/build.mjs +94 -0
- package/e2e/frontends/index.html +10 -0
- package/e2e/global-setup.ts +65 -0
- package/e2e/icp.yaml +38 -0
- package/e2e/package.json +40 -0
- package/e2e/setup.ts +6 -0
- package/e2e/src/actor/Cargo.toml +14 -0
- package/e2e/src/actor/hello_actor.did +10 -0
- package/e2e/src/actor/src/lib.rs +73 -0
- package/e2e/src/calls.test.ts +132 -0
- package/e2e/src/declarations/hello_actor.envelope.json +175 -0
- package/e2e/src/declarations/hello_actor.ts +15 -0
- package/e2e/src/errors.test.ts +107 -0
- package/e2e/src/frontend-headers.test.ts +253 -0
- package/e2e/src/identity.test.ts +61 -0
- package/e2e/src/react.test.tsx +59 -0
- package/e2e/src/replica.ts +70 -0
- package/e2e/src/vite-env.test.ts +108 -0
- package/e2e/test.sh +47 -0
- package/e2e/tsconfig.json +20 -0
- package/e2e/tsconfig.typecheck.json +9 -0
- package/e2e/vitest.config.ts +22 -0
- package/eslint.config.mjs +100 -0
- package/evals/PREREGISTRATION.md +1346 -0
- package/evals/README.md +756 -0
- package/evals/conditions/thin/condition.json +8 -0
- package/evals/conditions/thin/docs/candid-core-cli.README.md +90 -0
- package/evals/conditions/thin/docs/candid-core-schema.README.md +339 -0
- package/evals/conditions/thin/package.json +25 -0
- package/evals/conditions/thin/starter/src/generated/icrc1.ts +57 -0
- package/evals/conditions/thin-guide/condition.json +10 -0
- package/evals/conditions/thin-guide/docs/llms.txt +292 -0
- package/evals/conditions/v3/condition.json +9 -0
- package/evals/conditions/v3/docs/ic-reactor-core.llms.txt +232 -0
- package/evals/conditions/v3/docs/ic-reactor-react.llms.txt +280 -0
- package/evals/conditions/v3/docs/llms-full.txt +1053 -0
- package/evals/conditions/v3/package.json +26 -0
- package/evals/conditions/v3/starter/src/declarations/icrc1.did.d.ts +95 -0
- package/evals/conditions/v3/starter/src/declarations/icrc1.did.js +140 -0
- package/evals/conditions/v4/PORTING.md +384 -0
- package/evals/conditions/v4/README.md +106 -0
- package/evals/conditions/v4/condition.json +5 -0
- package/evals/conditions/v4/docs/llms.txt +323 -0
- package/evals/conditions/v4/package.json +27 -0
- package/evals/conditions/v4/starter/src/generated/icrc1.ts +78 -0
- package/evals/conditions/v4-proto/condition.json +6 -0
- package/evals/conditions/v4-proto/docs/llms.txt +291 -0
- package/evals/conditions/v4-proto/lib/SHIM-NOTES.md +20 -0
- package/evals/conditions/v4-proto/lib/package.json +27 -0
- package/evals/conditions/v4-proto/lib/src/client.ts +471 -0
- package/evals/conditions/v4-proto/lib/src/errors.ts +214 -0
- package/evals/conditions/v4-proto/lib/src/index.ts +36 -0
- package/evals/conditions/v4-proto/lib/src/principal.ts +175 -0
- package/evals/conditions/v4-proto/lib/src/service.ts +69 -0
- package/evals/conditions/v4-proto/lib/src/types.ts +174 -0
- package/evals/conditions/v4-proto/lib/test/runtime.test.ts +170 -0
- package/evals/conditions/v4-proto/lib/test/tsconfig.json +10 -0
- package/evals/conditions/v4-proto/lib/test/types.test-d.ts +145 -0
- package/evals/conditions/v4-proto/lib/test/vitest.config.mjs +8 -0
- package/evals/conditions/v4-proto/lib/tsconfig.json +17 -0
- package/evals/conditions/v4-proto/package.json +26 -0
- package/evals/conditions/v4-proto/starter/src/generated/icrc1.service.ts +19 -0
- package/evals/conditions/v4-proto/starter/src/generated/icrc1.ts +57 -0
- package/evals/drive.mjs +1221 -0
- package/evals/gate.mjs +161 -0
- package/evals/harness/aggregate.mjs +534 -0
- package/evals/harness/aggregate.test.mjs +344 -0
- package/evals/harness/assemble.mjs +216 -0
- package/evals/harness/assemble.test.mjs +143 -0
- package/evals/harness/auth.mjs +91 -0
- package/evals/harness/check-docs.mjs +157 -0
- package/evals/harness/declarations/icrc1.did.d.ts +95 -0
- package/evals/harness/declarations/icrc1.did.js +140 -0
- package/evals/harness/drive-auth.test.mjs +584 -0
- package/evals/harness/drive.test.mjs +509 -0
- package/evals/harness/fake-auth.ts +67 -0
- package/evals/harness/fake-ledger.ts +178 -0
- package/evals/harness/gate-plan.mjs +104 -0
- package/evals/harness/gate-plan.test.mjs +243 -0
- package/evals/harness/icrc1.did +88 -0
- package/evals/harness/judge.mjs +63 -0
- package/evals/harness/judge.test.mjs +81 -0
- package/evals/harness/leak-scan.mjs +1373 -0
- package/evals/harness/leak-scan.test.mjs +1300 -0
- package/evals/harness/probes/amounts.ts +14 -0
- package/evals/harness/probes/node-tool.probe.ts +48 -0
- package/evals/harness/probes/probe.mjs +149 -0
- package/evals/harness/probes/react-wallet.probe.ts +96 -0
- package/evals/harness/public/support/auth.ts +38 -0
- package/evals/harness/public/support/fake-replica.d.ts +28 -0
- package/evals/harness/public/support/fake-replica.js +434 -0
- package/evals/harness/public/support/ledger.idl.d.ts +95 -0
- package/evals/harness/public/support/ledger.idl.js +140 -0
- package/evals/harness/public/support/world.ts +179 -0
- package/evals/harness/runs.mjs +139 -0
- package/evals/harness/sandbox.mjs +88 -0
- package/evals/harness/sandbox.test.mjs +134 -0
- package/evals/harness/ship.mjs +264 -0
- package/evals/harness/ship.test.mjs +552 -0
- package/evals/harness/world.ts +291 -0
- package/evals/package.json +26 -0
- package/evals/pnpm-lock.yaml +1537 -0
- package/evals/pnpm-workspace.yaml +12 -0
- package/evals/results/2026-09-30T14-22-05-924Z/pilot.json +384 -0
- package/evals/results/2026-09-30T14-22-05-924Z/pilot.rescanned.json +404 -0
- package/evals/results/2026-09-30T14-22-05-924Z/pilot.rescanned.rescored.json +404 -0
- package/evals/results/2026-09-30T14-22-05-924Z/plan.json +240 -0
- package/evals/results/2026-09-30T14-22-05-924Z/summary.json +1800 -0
- package/evals/results/2026-09-30T14-22-05-924Z/summary.rescanned.json +1843 -0
- package/evals/results/2026-09-30T14-22-05-924Z/summary.rescanned.rescored.json +2100 -0
- package/evals/results/2026-09-30T15-48-23-343Z/pilot.json +404 -0
- package/evals/results/2026-09-30T15-48-23-343Z/pilot.rescored.json +404 -0
- package/evals/results/2026-09-30T15-48-23-343Z/plan.json +242 -0
- package/evals/results/2026-09-30T15-48-23-343Z/summary.json +1843 -0
- package/evals/results/2026-09-30T15-48-23-343Z/summary.rescored.json +2195 -0
- package/evals/results/2026-10-03-beta1-gate/pilot.json +162 -0
- package/evals/results/2026-10-03-beta1-gate/plan.json +141 -0
- package/evals/results/2026-10-03-beta1-gate/summary.json +983 -0
- package/evals/results/2026-10-05-ga-gate/contaminated-run.json +55 -0
- package/evals/results/2026-10-05-ga-gate/pilot.json +162 -0
- package/evals/results/2026-10-05-ga-gate/plan.json +457 -0
- package/evals/results/2026-10-05-ga-gate/summary.json +1037 -0
- package/evals/results/2026-10-05-ga-gate/summary.rescanned.json +1037 -0
- package/evals/results/README.md +31 -0
- package/evals/runs-pilot.log +150 -0
- package/evals/runs-pilot2.log +150 -0
- package/evals/score.mjs +256 -0
- package/evals/setup.mjs +547 -0
- package/evals/tasks/node-tool/faulty/thin-accepts-exponent/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-accepts-exponent/src/index.ts +121 -0
- package/evals/tasks/node-tool/faulty/thin-anonymous-transfer/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-anonymous-transfer/src/index.ts +116 -0
- package/evals/tasks/node-tool/faulty/thin-every-reject-may-have-executed/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/thin-every-reject-may-have-executed/src/index.ts +118 -0
- package/evals/tasks/node-tool/faulty/thin-fetches-root-key-off-local/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-fetches-root-key-off-local/src/index.ts +118 -0
- package/evals/tasks/node-tool/faulty/thin-ignores-root-key/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-ignores-root-key/src/index.ts +117 -0
- package/evals/tasks/node-tool/faulty/thin-misclassifies-reject-codes/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/thin-misclassifies-reject-codes/src/index.ts +119 -0
- package/evals/tasks/node-tool/faulty/thin-no-nat64-cap/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/thin-no-nat64-cap/src/index.ts +118 -0
- package/evals/tasks/node-tool/faulty/thin-number-amount/meta.json +10 -0
- package/evals/tasks/node-tool/faulty/thin-number-amount/src/index.ts +117 -0
- package/evals/tasks/node-tool/faulty/thin-truncates-fraction-digits/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-truncates-fraction-digits/src/index.ts +120 -0
- package/evals/tasks/node-tool/faulty/thin-unvalidated-recipient/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-unvalidated-recipient/src/index.ts +118 -0
- package/evals/tasks/node-tool/faulty/v3-retry-call-errors/meta.json +11 -0
- package/evals/tasks/node-tool/faulty/v3-retry-call-errors/src/index.ts +149 -0
- package/evals/tasks/node-tool/faulty/v4-anonymous-identity-sent/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/v4-anonymous-identity-sent/src/index.ts +71 -0
- package/evals/tasks/node-tool/faulty/v4-never-may-have-executed/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/v4-never-may-have-executed/src/index.ts +84 -0
- package/evals/tasks/node-tool/faulty/v4-proto-never-may-have-executed/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/v4-proto-never-may-have-executed/src/index.ts +72 -0
- package/evals/tasks/node-tool/faulty/v4-proto-refuses-nat64-max/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/v4-proto-refuses-nat64-max/src/index.ts +72 -0
- package/evals/tasks/node-tool/faulty/v4-refuses-nat64-max/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/v4-refuses-nat64-max/src/index.ts +84 -0
- package/evals/tasks/node-tool/hidden/node-tool.test.ts +312 -0
- package/evals/tasks/node-tool/prompt.md +55 -0
- package/evals/tasks/node-tool/prompt.minimal.md +30 -0
- package/evals/tasks/node-tool/solutions/thin/reference/src/index.ts +118 -0
- package/evals/tasks/node-tool/solutions/thin/reference-module-scope/src/index.ts +145 -0
- package/evals/tasks/node-tool/solutions/thin-guide/reference/src/index.ts +118 -0
- package/evals/tasks/node-tool/solutions/thin-guide/reference-module-scope/src/index.ts +145 -0
- package/evals/tasks/node-tool/solutions/v3/reference/src/index.ts +140 -0
- package/evals/tasks/node-tool/solutions/v3/reference-module-scope/src/index.ts +153 -0
- package/evals/tasks/node-tool/solutions/v4/reference/src/index.ts +84 -0
- package/evals/tasks/node-tool/solutions/v4/reference-module-scope/src/index.ts +105 -0
- package/evals/tasks/node-tool/solutions/v4-proto/reference/src/index.ts +72 -0
- package/evals/tasks/node-tool/solutions/v4-proto/reference-module-scope/src/index.ts +87 -0
- package/evals/tasks/node-tool/starter/src/contract.ts +31 -0
- package/evals/tasks/node-tool/starter/src/index.ts +7 -0
- package/evals/tasks/node-tool/starter/test/smoke.test.ts +22 -0
- package/evals/tasks/node-tool/starter/tsconfig.json +17 -0
- package/evals/tasks/node-tool/task.json +63 -0
- package/evals/tasks/react-wallet/faulty/thin-accepts-exponent/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-accepts-exponent/src/Wallet.tsx +216 -0
- package/evals/tasks/react-wallet/faulty/thin-anonymous-transfer/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-anonymous-transfer/src/Wallet.tsx +212 -0
- package/evals/tasks/react-wallet/faulty/thin-both-auth-buttons/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-both-auth-buttons/src/Wallet.tsx +210 -0
- package/evals/tasks/react-wallet/faulty/thin-constant-balance-key/meta.json +8 -0
- package/evals/tasks/react-wallet/faulty/thin-constant-balance-key/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/faulty/thin-no-nat64-cap/meta.json +9 -0
- package/evals/tasks/react-wallet/faulty/thin-no-nat64-cap/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/faulty/thin-number-balance/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-number-balance/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/faulty/thin-transfer-as-query/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-transfer-as-query/src/Wallet.tsx +254 -0
- package/evals/tasks/react-wallet/faulty/thin-truncates-fraction-digits/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-truncates-fraction-digits/src/Wallet.tsx +215 -0
- package/evals/tasks/react-wallet/faulty/thin-unguarded-balance-effect/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-unguarded-balance-effect/src/Wallet.tsx +214 -0
- package/evals/tasks/react-wallet/faulty/v3-http-4xx-unknown/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v3-http-4xx-unknown/src/Wallet.tsx +224 -0
- package/evals/tasks/react-wallet/faulty/v3-mutation-retry-3/meta.json +12 -0
- package/evals/tasks/react-wallet/faulty/v3-mutation-retry-3/src/Wallet.tsx +225 -0
- package/evals/tasks/react-wallet/faulty/v3-unknown-as-error/meta.json +11 -0
- package/evals/tasks/react-wallet/faulty/v3-unknown-as-error/src/Wallet.tsx +182 -0
- package/evals/tasks/react-wallet/faulty/v4-every-reject-unknown/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-every-reject-unknown/src/Wallet.tsx +160 -0
- package/evals/tasks/react-wallet/faulty/v4-keep-previous-data/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-keep-previous-data/src/Wallet.tsx +166 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-every-reject-unknown/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-every-reject-unknown/src/Wallet.tsx +161 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-keep-previous-data/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-keep-previous-data/src/Wallet.tsx +163 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-retry-spread/meta.json +12 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-retry-spread/src/Wallet.tsx +162 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-status-not-idle/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-status-not-idle/src/Wallet.tsx +163 -0
- package/evals/tasks/react-wallet/faulty/v4-retry-spread/meta.json +12 -0
- package/evals/tasks/react-wallet/faulty/v4-retry-spread/src/Wallet.tsx +163 -0
- package/evals/tasks/react-wallet/faulty/v4-status-not-idle/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-status-not-idle/src/Wallet.tsx +162 -0
- package/evals/tasks/react-wallet/hidden/react-wallet.test.ts +536 -0
- package/evals/tasks/react-wallet/prompt.md +88 -0
- package/evals/tasks/react-wallet/prompt.minimal.md +51 -0
- package/evals/tasks/react-wallet/solutions/thin/reference/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/solutions/thin/reference-module-scope/src/Wallet.tsx +227 -0
- package/evals/tasks/react-wallet/solutions/thin-guide/reference/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/solutions/thin-guide/reference-module-scope/src/Wallet.tsx +227 -0
- package/evals/tasks/react-wallet/solutions/v3/reference/src/Wallet.tsx +224 -0
- package/evals/tasks/react-wallet/solutions/v3/reference-module-scope/src/Wallet.tsx +230 -0
- package/evals/tasks/react-wallet/solutions/v4/reference/src/Wallet.tsx +160 -0
- package/evals/tasks/react-wallet/solutions/v4/reference-module-scope/src/Wallet.tsx +178 -0
- package/evals/tasks/react-wallet/solutions/v4-proto/reference/src/Wallet.tsx +161 -0
- package/evals/tasks/react-wallet/solutions/v4-proto/reference-module-scope/src/Wallet.tsx +161 -0
- package/evals/tasks/react-wallet/starter/src/Wallet.tsx +12 -0
- package/evals/tasks/react-wallet/starter/src/auth.ts +16 -0
- package/evals/tasks/react-wallet/starter/src/config.ts +14 -0
- package/evals/tasks/react-wallet/starter/src/ii-auth.ts +43 -0
- package/evals/tasks/react-wallet/starter/src/main.tsx +15 -0
- package/evals/tasks/react-wallet/starter/test/smoke.test.ts +34 -0
- package/evals/tasks/react-wallet/starter/tsconfig.json +18 -0
- package/evals/tasks/react-wallet/task.json +84 -0
- package/examples/canister-studio/.stackblitzrc +4 -0
- package/examples/canister-studio/README.md +183 -0
- package/examples/canister-studio/did/ckbtc_minter.did +806 -0
- package/examples/canister-studio/did/icp_ledger.did +586 -0
- package/examples/canister-studio/did/icrc1.did +88 -0
- package/examples/canister-studio/package.json +45 -0
- package/examples/canister-studio/scripts/smoke.ts +188 -0
- package/examples/canister-studio/src/calls/CacheKeyPanel.tsx +104 -0
- package/examples/canister-studio/src/calls/ConfirmWrite.tsx +265 -0
- package/examples/canister-studio/src/calls/ErrorPanel.test.tsx +113 -0
- package/examples/canister-studio/src/calls/ErrorPanel.tsx +214 -0
- package/examples/canister-studio/src/calls/MethodRunner.test.tsx +354 -0
- package/examples/canister-studio/src/calls/MethodRunner.tsx +57 -0
- package/examples/canister-studio/src/calls/ReadRunner.tsx +244 -0
- package/examples/canister-studio/src/calls/ResendPanel.tsx +165 -0
- package/examples/canister-studio/src/calls/ShareLink.tsx +59 -0
- package/examples/canister-studio/src/calls/WriteRunner.test.tsx +678 -0
- package/examples/canister-studio/src/calls/WriteRunner.tsx +670 -0
- package/examples/canister-studio/src/calls/dedupe.ts +189 -0
- package/examples/canister-studio/src/calls/error-info.ts +168 -0
- package/examples/canister-studio/src/calls/history.test.ts +284 -0
- package/examples/canister-studio/src/calls/history.ts +287 -0
- package/examples/canister-studio/src/calls/kinds.ts +68 -0
- package/examples/canister-studio/src/calls/prepare.ts +32 -0
- package/examples/canister-studio/src/calls/query-options.ts +30 -0
- package/examples/canister-studio/src/calls/read.ts +47 -0
- package/examples/canister-studio/src/calls/readback.ts +100 -0
- package/examples/canister-studio/src/calls/record.ts +123 -0
- package/examples/canister-studio/src/calls/safe-calls.test.ts +299 -0
- package/examples/canister-studio/src/calls/share.ts +46 -0
- package/examples/canister-studio/src/calls/testing/doubles.tsx +108 -0
- package/examples/canister-studio/src/calls/testing/fixtures.ts +185 -0
- package/examples/canister-studio/src/calls/useCanisterHandle.ts +35 -0
- package/examples/canister-studio/src/canisters/ckbtc_minter.envelope.json +4228 -0
- package/examples/canister-studio/src/canisters/ckbtc_minter.ts +868 -0
- package/examples/canister-studio/src/canisters/icp_ledger.envelope.json +3454 -0
- package/examples/canister-studio/src/canisters/icp_ledger.ts +584 -0
- package/examples/canister-studio/src/canisters/icrc1.envelope.json +840 -0
- package/examples/canister-studio/src/canisters/icrc1.ts +78 -0
- package/examples/canister-studio/src/components/ActionButton.tsx +32 -0
- package/examples/canister-studio/src/components/AppHeader.tsx +83 -0
- package/examples/canister-studio/src/components/AppShell.tsx +29 -0
- package/examples/canister-studio/src/components/AuthButton.tsx +79 -0
- package/examples/canister-studio/src/components/Badge.tsx +79 -0
- package/examples/canister-studio/src/components/CanisterHeader.tsx +200 -0
- package/examples/canister-studio/src/components/CanisterJump.tsx +130 -0
- package/examples/canister-studio/src/components/Card.tsx +64 -0
- package/examples/canister-studio/src/components/Code.tsx +101 -0
- package/examples/canister-studio/src/components/CopyButton.tsx +126 -0
- package/examples/canister-studio/src/components/Disclosure.tsx +34 -0
- package/examples/canister-studio/src/components/EmptyState.tsx +34 -0
- package/examples/canister-studio/src/components/MethodList.test.tsx +137 -0
- package/examples/canister-studio/src/components/MethodList.tsx +244 -0
- package/examples/canister-studio/src/components/Notice.tsx +36 -0
- package/examples/canister-studio/src/components/ProvenanceBadge.tsx +44 -0
- package/examples/canister-studio/src/components/RouteError.tsx +42 -0
- package/examples/canister-studio/src/components/SectionBoundary.tsx +76 -0
- package/examples/canister-studio/src/components/Spinner.tsx +33 -0
- package/examples/canister-studio/src/components/Tabs.tsx +96 -0
- package/examples/canister-studio/src/components/canister/CanisterLoadFailure.test.tsx +56 -0
- package/examples/canister-studio/src/components/canister/CanisterLoadFailure.tsx +165 -0
- package/examples/canister-studio/src/components/canister/CanisterNotFound.tsx +59 -0
- package/examples/canister-studio/src/components/canister/CanisterPending.tsx +33 -0
- package/examples/canister-studio/src/components/canister/MethodOverview.tsx +93 -0
- package/examples/canister-studio/src/components/canister/MethodWorkspace.test.tsx +201 -0
- package/examples/canister-studio/src/components/canister/MethodWorkspace.tsx +187 -0
- package/examples/canister-studio/src/components/canister/shared-call.test.ts +186 -0
- package/examples/canister-studio/src/components/canister/shared-call.ts +133 -0
- package/examples/canister-studio/src/components/canister/shared-link-loader.test.ts +116 -0
- package/examples/canister-studio/src/components/canister/use-canister-page.ts +44 -0
- package/examples/canister-studio/src/components/canister/workspace-key.test.ts +27 -0
- package/examples/canister-studio/src/components/canister/workspace-key.ts +36 -0
- package/examples/canister-studio/src/components/canister-id-input.ts +69 -0
- package/examples/canister-studio/src/components/canister-names.ts +11 -0
- package/examples/canister-studio/src/components/download.ts +34 -0
- package/examples/canister-studio/src/components/fallbacks.tsx +33 -0
- package/examples/canister-studio/src/components/helpers.test.ts +107 -0
- package/examples/canister-studio/src/components/history/HistoryList.tsx +284 -0
- package/examples/canister-studio/src/components/home/FeaturedLedger.tsx +149 -0
- package/examples/canister-studio/src/components/home/OpenCanister.tsx +99 -0
- package/examples/canister-studio/src/components/home/featured.test.tsx +92 -0
- package/examples/canister-studio/src/components/home/featured.ts +64 -0
- package/examples/canister-studio/src/components/interface/CandidTab.tsx +38 -0
- package/examples/canister-studio/src/components/interface/CompatReport.tsx +92 -0
- package/examples/canister-studio/src/components/interface/CompatibilityTab.tsx +190 -0
- package/examples/canister-studio/src/components/interface/ProjectTab.tsx +196 -0
- package/examples/canister-studio/src/components/interface/TypeScriptTab.tsx +114 -0
- package/examples/canister-studio/src/components/interface/tools.test.tsx +169 -0
- package/examples/canister-studio/src/components/modes.ts +31 -0
- package/examples/canister-studio/src/components/playground/MethodPicker.tsx +67 -0
- package/examples/canister-studio/src/components/playground/PlaygroundForms.tsx +112 -0
- package/examples/canister-studio/src/components/playground/PlaygroundTools.tsx +219 -0
- package/examples/canister-studio/src/components/playground/sample.ts +43 -0
- package/examples/canister-studio/src/components/playground/target.test.tsx +86 -0
- package/examples/canister-studio/src/components/primitives.test.tsx +121 -0
- package/examples/canister-studio/src/components/provenance.ts +38 -0
- package/examples/canister-studio/src/components/route-render.test.tsx +71 -0
- package/examples/canister-studio/src/components/use-task.ts +56 -0
- package/examples/canister-studio/src/components/wallet/BalancePanel.tsx +110 -0
- package/examples/canister-studio/src/components/wallet/LedgerSummary.tsx +63 -0
- package/examples/canister-studio/src/components/wallet/MinterPanel.tsx +255 -0
- package/examples/canister-studio/src/components/wallet/SendPanel.test.tsx +297 -0
- package/examples/canister-studio/src/components/wallet/SendPanel.tsx +446 -0
- package/examples/canister-studio/src/components/wallet/ledgers.test.ts +36 -0
- package/examples/canister-studio/src/components/wallet/ledgers.ts +111 -0
- package/examples/canister-studio/src/forms/JsonPanel.tsx +157 -0
- package/examples/canister-studio/src/forms/MethodForm.test.tsx +369 -0
- package/examples/canister-studio/src/forms/MethodForm.tsx +368 -0
- package/examples/canister-studio/src/forms/TypedForm.tsx +55 -0
- package/examples/canister-studio/src/forms/context.ts +62 -0
- package/examples/canister-studio/src/forms/convert.ts +131 -0
- package/examples/canister-studio/src/forms/edge.test.ts +252 -0
- package/examples/canister-studio/src/forms/engine.test.ts +358 -0
- package/examples/canister-studio/src/forms/engine.ts +1492 -0
- package/examples/canister-studio/src/forms/fields/BytesField.tsx +210 -0
- package/examples/canister-studio/src/forms/fields/Field.tsx +106 -0
- package/examples/canister-studio/src/forms/fields/FieldShell.tsx +101 -0
- package/examples/canister-studio/src/forms/fields/Group.tsx +74 -0
- package/examples/canister-studio/src/forms/fields/ListField.tsx +256 -0
- package/examples/canister-studio/src/forms/fields/Segmented.tsx +78 -0
- package/examples/canister-studio/src/forms/fields/TimestampField.tsx +108 -0
- package/examples/canister-studio/src/forms/fields/UnitsField.tsx +119 -0
- package/examples/canister-studio/src/forms/fields/composites.tsx +389 -0
- package/examples/canister-studio/src/forms/fields/leaves.tsx +350 -0
- package/examples/canister-studio/src/forms/fields.test.tsx +396 -0
- package/examples/canister-studio/src/forms/helpers.test.ts +225 -0
- package/examples/canister-studio/src/forms/hints.ts +128 -0
- package/examples/canister-studio/src/forms/json.ts +119 -0
- package/examples/canister-studio/src/forms/parsing.test.ts +217 -0
- package/examples/canister-studio/src/forms/useMethodForm.ts +251 -0
- package/examples/canister-studio/src/interface/browser.test.ts +23 -0
- package/examples/canister-studio/src/interface/browser.ts +153 -0
- package/examples/canister-studio/src/interface/cache.ts +68 -0
- package/examples/canister-studio/src/interface/cli-cache.test.ts +155 -0
- package/examples/canister-studio/src/interface/cli-cache.ts +125 -0
- package/examples/canister-studio/src/interface/compile.server.test.ts +198 -0
- package/examples/canister-studio/src/interface/compile.server.ts +262 -0
- package/examples/canister-studio/src/interface/compile.test.ts +108 -0
- package/examples/canister-studio/src/interface/compile.ts +305 -0
- package/examples/canister-studio/src/interface/docs.test.ts +75 -0
- package/examples/canister-studio/src/interface/docs.ts +100 -0
- package/examples/canister-studio/src/interface/functions.test.ts +42 -0
- package/examples/canister-studio/src/interface/functions.ts +200 -0
- package/examples/canister-studio/src/interface/live-candid.server.ts +91 -0
- package/examples/canister-studio/src/interface/live-loader.test.ts +515 -0
- package/examples/canister-studio/src/interface/live-loader.ts +364 -0
- package/examples/canister-studio/src/interface/load.test.ts +328 -0
- package/examples/canister-studio/src/interface/load.ts +249 -0
- package/examples/canister-studio/src/interface/read-candid.test.ts +185 -0
- package/examples/canister-studio/src/interface/read-candid.ts +233 -0
- package/examples/canister-studio/src/interface/server-result.ts +42 -0
- package/examples/canister-studio/src/interface/typed.ts +68 -0
- package/examples/canister-studio/src/interface/types.ts +121 -0
- package/examples/canister-studio/src/lib/format.test.ts +107 -0
- package/examples/canister-studio/src/lib/format.ts +139 -0
- package/examples/canister-studio/src/lib/hex.test.ts +43 -0
- package/examples/canister-studio/src/lib/hex.ts +33 -0
- package/examples/canister-studio/src/lib/ids.test.ts +70 -0
- package/examples/canister-studio/src/lib/ids.ts +93 -0
- package/examples/canister-studio/src/lib/reactor.test.ts +55 -0
- package/examples/canister-studio/src/lib/reactor.ts +55 -0
- package/examples/canister-studio/src/lib/registry.test.ts +74 -0
- package/examples/canister-studio/src/lib/registry.ts +238 -0
- package/examples/canister-studio/src/lib/schema.ts +148 -0
- package/examples/canister-studio/src/routeTree.gen.ts +227 -0
- package/examples/canister-studio/src/router.test.ts +290 -0
- package/examples/canister-studio/src/router.tsx +127 -0
- package/examples/canister-studio/src/routes/__root.tsx +58 -0
- package/examples/canister-studio/src/routes/canister.$canisterId.index.tsx +172 -0
- package/examples/canister-studio/src/routes/canister.$canisterId.interface.tsx +98 -0
- package/examples/canister-studio/src/routes/canister.$canisterId.tsx +91 -0
- package/examples/canister-studio/src/routes/history.tsx +55 -0
- package/examples/canister-studio/src/routes/index.tsx +169 -0
- package/examples/canister-studio/src/routes/playground.tsx +286 -0
- package/examples/canister-studio/src/routes/safety.tsx +57 -0
- package/examples/canister-studio/src/routes/wallet.tsx +213 -0
- package/examples/canister-studio/src/safety/LabTransferForm.tsx +84 -0
- package/examples/canister-studio/src/safety/RequestLog.tsx +79 -0
- package/examples/canister-studio/src/safety/SafetyLab.test.tsx +89 -0
- package/examples/canister-studio/src/safety/SafetyLab.tsx +140 -0
- package/examples/canister-studio/src/safety/ScenarioCard.tsx +262 -0
- package/examples/canister-studio/src/safety/lab-run.ts +283 -0
- package/examples/canister-studio/src/safety/mock-ledger.test.ts +99 -0
- package/examples/canister-studio/src/safety/mock-ledger.ts +263 -0
- package/examples/canister-studio/src/safety/scenarios.test.ts +157 -0
- package/examples/canister-studio/src/safety/scenarios.ts +924 -0
- package/examples/canister-studio/src/styles.css +3453 -0
- package/examples/canister-studio/src/styles.test.ts +46 -0
- package/examples/canister-studio/src/values/CallPreview.test.tsx +86 -0
- package/examples/canister-studio/src/values/CallPreview.tsx +148 -0
- package/examples/canister-studio/src/values/ErrValueView.tsx +66 -0
- package/examples/canister-studio/src/values/Inspector.tsx +133 -0
- package/examples/canister-studio/src/values/ReplyView.test.tsx +341 -0
- package/examples/canister-studio/src/values/ReplyView.tsx +164 -0
- package/examples/canister-studio/src/values/candid-text.test.ts +516 -0
- package/examples/canister-studio/src/values/candid-text.ts +479 -0
- package/examples/canister-studio/src/values/hints.ts +58 -0
- package/examples/canister-studio/src/values/json.test.ts +66 -0
- package/examples/canister-studio/src/values/json.ts +31 -0
- package/examples/canister-studio/src/values/leaves.tsx +309 -0
- package/examples/canister-studio/src/values/schema.test.ts +123 -0
- package/examples/canister-studio/src/values/schema.ts +78 -0
- package/examples/canister-studio/src/values/test-router.tsx +21 -0
- package/examples/canister-studio/src/values/tree.tsx +670 -0
- package/examples/canister-studio/src/values/use-sha256.ts +29 -0
- package/examples/canister-studio/tsconfig.json +20 -0
- package/examples/canister-studio/vite.config.ts +50 -0
- package/examples/canister-studio/vitest.config.ts +20 -0
- package/examples/icrc-ledger/.stackblitzrc +4 -0
- package/examples/icrc-ledger/README.md +100 -0
- package/examples/icrc-ledger/ckbtc_minter.did +12 -0
- package/examples/icrc-ledger/icp_ledger.did +147 -0
- package/examples/icrc-ledger/icrc1.did +88 -0
- package/examples/icrc-ledger/index.html +13 -0
- package/examples/icrc-ledger/package.json +40 -0
- package/examples/icrc-ledger/scripts/smoke.ts +151 -0
- package/examples/icrc-ledger/src/App.tsx +71 -0
- package/examples/icrc-ledger/src/ErrorPanel.tsx +105 -0
- package/examples/icrc-ledger/src/MainnetTab.tsx +450 -0
- package/examples/icrc-ledger/src/SandboxTab.test.tsx +379 -0
- package/examples/icrc-ledger/src/SandboxTab.tsx +761 -0
- package/examples/icrc-ledger/src/blocks.test.ts +247 -0
- package/examples/icrc-ledger/src/blocks.ts +140 -0
- package/examples/icrc-ledger/src/canisters/ckbtc_minter.envelope.json +96 -0
- package/examples/icrc-ledger/src/canisters/ckbtc_minter.ts +16 -0
- package/examples/icrc-ledger/src/canisters/icp_ledger.envelope.json +690 -0
- package/examples/icrc-ledger/src/canisters/icp_ledger.ts +223 -0
- package/examples/icrc-ledger/src/canisters/icrc1.envelope.json +840 -0
- package/examples/icrc-ledger/src/canisters/icrc1.ts +78 -0
- package/examples/icrc-ledger/src/format.test.ts +41 -0
- package/examples/icrc-ledger/src/format.ts +68 -0
- package/examples/icrc-ledger/src/ledger.ts +15 -0
- package/examples/icrc-ledger/src/main.tsx +10 -0
- package/examples/icrc-ledger/src/minter.ts +16 -0
- package/examples/icrc-ledger/src/sandbox.test.ts +464 -0
- package/examples/icrc-ledger/src/sandbox.ts +281 -0
- package/examples/icrc-ledger/src/styles.css +391 -0
- package/examples/icrc-ledger/src/transfer-form.test.ts +62 -0
- package/examples/icrc-ledger/src/transfer-form.ts +97 -0
- package/examples/icrc-ledger/tsconfig.json +19 -0
- package/examples/icrc-ledger/vite.config.ts +44 -0
- package/examples/icrc-ledger/vitest.config.ts +12 -0
- package/examples/next-ssr/.stackblitzrc +4 -0
- package/examples/next-ssr/README.md +112 -0
- package/examples/next-ssr/icrc1.did +88 -0
- package/examples/next-ssr/next.config.ts +10 -0
- package/examples/next-ssr/package.json +41 -0
- package/examples/next-ssr/scripts/smoke.ts +169 -0
- package/examples/next-ssr/src/app/account/CertifiedBalances.tsx +58 -0
- package/examples/next-ssr/src/app/account/account.test.tsx +165 -0
- package/examples/next-ssr/src/app/account/page.tsx +82 -0
- package/examples/next-ssr/src/app/api/balance/[ledger]/[principal]/route.ts +10 -0
- package/examples/next-ssr/src/app/globals.css +278 -0
- package/examples/next-ssr/src/app/layout.tsx +34 -0
- package/examples/next-ssr/src/app/page.tsx +46 -0
- package/examples/next-ssr/src/app/providers.browser.test.tsx +127 -0
- package/examples/next-ssr/src/app/providers.test.tsx +73 -0
- package/examples/next-ssr/src/app/providers.tsx +60 -0
- package/examples/next-ssr/src/canisters/icrc1.envelope.json +840 -0
- package/examples/next-ssr/src/canisters/icrc1.ts +78 -0
- package/examples/next-ssr/src/components/BalanceTable.tsx +43 -0
- package/examples/next-ssr/src/components/LedgerCard.test.tsx +96 -0
- package/examples/next-ssr/src/components/LedgerCard.tsx +230 -0
- package/examples/next-ssr/src/components/LedgerError.tsx +32 -0
- package/examples/next-ssr/src/components/LedgerSections.tsx +22 -0
- package/examples/next-ssr/src/components/MyBalances.test.tsx +253 -0
- package/examples/next-ssr/src/components/MyBalances.tsx +129 -0
- package/examples/next-ssr/src/components/SessionBadge.tsx +18 -0
- package/examples/next-ssr/src/components/hydration.test.tsx +259 -0
- package/examples/next-ssr/src/components/server-data.ts +10 -0
- package/examples/next-ssr/src/format.ts +46 -0
- package/examples/next-ssr/src/ledgers.ts +38 -0
- package/examples/next-ssr/src/server/balance-route.test.ts +151 -0
- package/examples/next-ssr/src/server/balance-route.ts +157 -0
- package/examples/next-ssr/src/server/error-summary.test.ts +34 -0
- package/examples/next-ssr/src/server/error-summary.ts +37 -0
- package/examples/next-ssr/src/server/parse-owner.test.ts +39 -0
- package/examples/next-ssr/src/server/parse-owner.ts +34 -0
- package/examples/next-ssr/src/server/prefetch-ledgers.test.ts +137 -0
- package/examples/next-ssr/src/server/prefetch-ledgers.ts +70 -0
- package/examples/next-ssr/src/server/read-balances.test.ts +103 -0
- package/examples/next-ssr/src/server/read-balances.ts +78 -0
- package/examples/next-ssr/src/server/request-client.rsc.test.tsx +110 -0
- package/examples/next-ssr/src/server/request-client.ts +24 -0
- package/examples/next-ssr/src/testing/mock-ledgers.ts +115 -0
- package/examples/next-ssr/src/testing/react-server-dom-turbopack.d.ts +15 -0
- package/examples/next-ssr/src/testing/setup.ts +10 -0
- package/examples/next-ssr/tsconfig.json +31 -0
- package/examples/next-ssr/vitest.config.ts +59 -0
- package/examples/node-agent-tool/.stackblitzrc +4 -0
- package/examples/node-agent-tool/README.md +165 -0
- package/examples/node-agent-tool/icp.yaml +11 -0
- package/examples/node-agent-tool/icrc1.did +88 -0
- package/examples/node-agent-tool/package.json +32 -0
- package/examples/node-agent-tool/src/canisters/icrc1.envelope.json +840 -0
- package/examples/node-agent-tool/src/canisters/icrc1.ts +78 -0
- package/examples/node-agent-tool/src/cli.test.ts +64 -0
- package/examples/node-agent-tool/src/cli.ts +23 -0
- package/examples/node-agent-tool/src/command-line.ts +159 -0
- package/examples/node-agent-tool/src/commands/balance.ts +73 -0
- package/examples/node-agent-tool/src/commands/demo.test.ts +51 -0
- package/examples/node-agent-tool/src/commands/demo.ts +359 -0
- package/examples/node-agent-tool/src/commands/info.ts +69 -0
- package/examples/node-agent-tool/src/commands/reads.test.ts +133 -0
- package/examples/node-agent-tool/src/commands/resend.test.ts +363 -0
- package/examples/node-agent-tool/src/commands/transfer.test.ts +313 -0
- package/examples/node-agent-tool/src/commands/transfer.ts +415 -0
- package/examples/node-agent-tool/src/commands/watch.test.ts +159 -0
- package/examples/node-agent-tool/src/commands/watch.ts +135 -0
- package/examples/node-agent-tool/src/commands/whoami.ts +36 -0
- package/examples/node-agent-tool/src/context.ts +20 -0
- package/examples/node-agent-tool/src/dispatch.ts +70 -0
- package/examples/node-agent-tool/src/failure.test.ts +59 -0
- package/examples/node-agent-tool/src/failure.ts +176 -0
- package/examples/node-agent-tool/src/identity.test.ts +242 -0
- package/examples/node-agent-tool/src/identity.ts +228 -0
- package/examples/node-agent-tool/src/input.ts +110 -0
- package/examples/node-agent-tool/src/ledgers.test.ts +74 -0
- package/examples/node-agent-tool/src/ledgers.ts +62 -0
- package/examples/node-agent-tool/src/mock-ledger.ts +211 -0
- package/examples/node-agent-tool/src/network.test.ts +128 -0
- package/examples/node-agent-tool/src/network.ts +101 -0
- package/examples/node-agent-tool/src/output.test.ts +208 -0
- package/examples/node-agent-tool/src/output.ts +163 -0
- package/examples/node-agent-tool/src/run.ts +73 -0
- package/examples/node-agent-tool/src/test-kit.ts +167 -0
- package/examples/node-agent-tool/tsconfig.json +18 -0
- package/examples/node-agent-tool/vitest.config.ts +8 -0
- package/examples/vite-wallet/.stackblitzrc +4 -0
- package/examples/vite-wallet/Cargo.lock +646 -0
- package/examples/vite-wallet/Cargo.toml +5 -0
- package/examples/vite-wallet/README.md +107 -0
- package/examples/vite-wallet/backend/Cargo.toml +12 -0
- package/examples/vite-wallet/backend/backend.did +37 -0
- package/examples/vite-wallet/backend/src/lib.rs +133 -0
- package/examples/vite-wallet/icp.yaml +44 -0
- package/examples/vite-wallet/index.html +13 -0
- package/examples/vite-wallet/ledger.did +54 -0
- package/examples/vite-wallet/package.json +46 -0
- package/examples/vite-wallet/public/.ic-assets.json5 +26 -0
- package/examples/vite-wallet/scripts/faucet-args.test.ts +30 -0
- package/examples/vite-wallet/scripts/faucet-args.ts +41 -0
- package/examples/vite-wallet/scripts/faucet.ts +41 -0
- package/examples/vite-wallet/src/AddressBook.test.tsx +191 -0
- package/examples/vite-wallet/src/AddressBook.tsx +147 -0
- package/examples/vite-wallet/src/App.tsx +53 -0
- package/examples/vite-wallet/src/Balance.test.tsx +57 -0
- package/examples/vite-wallet/src/Balance.tsx +58 -0
- package/examples/vite-wallet/src/EnvironmentPanel.test.tsx +83 -0
- package/examples/vite-wallet/src/EnvironmentPanel.tsx +103 -0
- package/examples/vite-wallet/src/ErrorNote.tsx +70 -0
- package/examples/vite-wallet/src/Profile.test.tsx +145 -0
- package/examples/vite-wallet/src/Profile.tsx +92 -0
- package/examples/vite-wallet/src/SendIcp.test.tsx +231 -0
- package/examples/vite-wallet/src/SendIcp.tsx +244 -0
- package/examples/vite-wallet/src/SendToContact.test.tsx +113 -0
- package/examples/vite-wallet/src/SendToContact.tsx +102 -0
- package/examples/vite-wallet/src/SignIn.test.tsx +106 -0
- package/examples/vite-wallet/src/SignIn.tsx +120 -0
- package/examples/vite-wallet/src/Wallet.test.tsx +89 -0
- package/examples/vite-wallet/src/account-switch.test.tsx +108 -0
- package/examples/vite-wallet/src/auth/dev-accounts.test.ts +113 -0
- package/examples/vite-wallet/src/auth/dev-accounts.ts +216 -0
- package/examples/vite-wallet/src/auth/local-page.test.ts +28 -0
- package/examples/vite-wallet/src/auth/local-page.ts +20 -0
- package/examples/vite-wallet/src/auth/wallet-auth.test.ts +159 -0
- package/examples/vite-wallet/src/auth/wallet-auth.ts +131 -0
- package/examples/vite-wallet/src/canisters/backend.envelope.json +275 -0
- package/examples/vite-wallet/src/canisters/backend.ts +58 -0
- package/examples/vite-wallet/src/canisters/ledger.envelope.json +451 -0
- package/examples/vite-wallet/src/canisters/ledger.ts +56 -0
- package/examples/vite-wallet/src/client.ts +45 -0
- package/examples/vite-wallet/src/main.tsx +18 -0
- package/examples/vite-wallet/src/optimistic-contacts.ts +113 -0
- package/examples/vite-wallet/src/refusal.ts +17 -0
- package/examples/vite-wallet/src/styles.css +282 -0
- package/examples/vite-wallet/src/test/test-wallet.tsx +322 -0
- package/examples/vite-wallet/src/token.ts +50 -0
- package/examples/vite-wallet/src/transfer.test.ts +178 -0
- package/examples/vite-wallet/src/transfer.ts +110 -0
- package/examples/vite-wallet/src/use-canisters.ts +49 -0
- package/examples/vite-wallet/tsconfig.json +19 -0
- package/examples/vite-wallet/vite.config.ts +47 -0
- package/examples/vite-wallet/vitest.config.ts +17 -0
- package/package.json +9 -4
- package/packages/core/.size-limit.js +47 -0
- package/packages/core/LICENSE +21 -0
- package/packages/core/README.md +84 -0
- package/packages/core/llms.txt +610 -0
- package/packages/core/package.json +89 -0
- package/packages/core/src/call.ts +961 -0
- package/packages/core/src/canister.ts +259 -0
- package/packages/core/src/client.ts +2061 -0
- package/packages/core/src/errors.ts +1079 -0
- package/packages/core/src/hydration.ts +239 -0
- package/packages/core/src/index.ts +23 -0
- package/packages/core/src/keys.ts +108 -0
- package/packages/core/src/management.ts +138 -0
- package/packages/core/src/network.ts +1020 -0
- package/packages/core/src/options.ts +1000 -0
- package/packages/core/src/runtime.ts +50 -0
- package/packages/core/src/testing/fake-replica.ts +1166 -0
- package/packages/core/src/testing/index.ts +16 -0
- package/packages/core/src/testing/test-auth.ts +340 -0
- package/packages/core/src/testing/test-client.ts +559 -0
- package/packages/core/src/types.ts +541 -0
- package/packages/core/src/units.ts +299 -0
- package/packages/core/src/version.ts +4 -0
- package/packages/core/tests/canister-helpers.ts +187 -0
- package/packages/core/tests/canister-id.test.ts +158 -0
- package/packages/core/tests/canister-unwrap.test.ts +94 -0
- package/packages/core/tests/canister.test-d.ts +406 -0
- package/packages/core/tests/canister.test.ts +1921 -0
- package/packages/core/tests/client-account-change.test.ts +131 -0
- package/packages/core/tests/client-agents.test.ts +402 -0
- package/packages/core/tests/client-auth-network.test.ts +719 -0
- package/packages/core/tests/client-disposed.test.ts +403 -0
- package/packages/core/tests/client-helpers.ts +136 -0
- package/packages/core/tests/client-hydration.test.ts +166 -0
- package/packages/core/tests/client-pinned.test.ts +626 -0
- package/packages/core/tests/client-session.test.ts +348 -0
- package/packages/core/tests/client.test-d.ts +181 -0
- package/packages/core/tests/client.test.ts +1162 -0
- package/packages/core/tests/encode.test.ts +171 -0
- package/packages/core/tests/env-canister-id.test.ts +666 -0
- package/packages/core/tests/env-cookie-copies.test.ts +182 -0
- package/packages/core/tests/error-guard.test.ts +222 -0
- package/packages/core/tests/errors.test-d.ts +280 -0
- package/packages/core/tests/errors.test.ts +1359 -0
- package/packages/core/tests/fixtures/README.md +28 -0
- package/packages/core/tests/fixtures/accounts.did +21 -0
- package/packages/core/tests/fixtures/accounts.envelope.json +367 -0
- package/packages/core/tests/fixtures/accounts.ts +26 -0
- package/packages/core/tests/fixtures/archive.did +31 -0
- package/packages/core/tests/fixtures/archive.envelope.json +259 -0
- package/packages/core/tests/fixtures/archive.ts +55 -0
- package/packages/core/tests/fixtures/icrc1.did +88 -0
- package/packages/core/tests/fixtures/icrc1.envelope.json +840 -0
- package/packages/core/tests/fixtures/icrc1.ts +78 -0
- package/packages/core/tests/fixtures/management.did +724 -0
- package/packages/core/tests/fixtures/management.envelope.json +4455 -0
- package/packages/core/tests/fixtures/management.ts +486 -0
- package/packages/core/tests/fixtures/shapes.did +33 -0
- package/packages/core/tests/fixtures/shapes.envelope.json +440 -0
- package/packages/core/tests/fixtures/shapes.ts +56 -0
- package/packages/core/tests/fixtures/skippable.did +15 -0
- package/packages/core/tests/fixtures/skippable.envelope.json +182 -0
- package/packages/core/tests/fixtures/skippable.ts +33 -0
- package/packages/core/tests/func.test.ts +154 -0
- package/packages/core/tests/identity-attributes.test.ts +214 -0
- package/packages/core/tests/keys.test.ts +289 -0
- package/packages/core/tests/management.test.ts +206 -0
- package/packages/core/tests/network-helpers.ts +121 -0
- package/packages/core/tests/network.test-d.ts +78 -0
- package/packages/core/tests/network.test.ts +1051 -0
- package/packages/core/tests/options.test.ts +1594 -0
- package/packages/core/tests/redirect-sign-in.test.ts +393 -0
- package/packages/core/tests/resend.test-d.ts +81 -0
- package/packages/core/tests/resend.test.ts +723 -0
- package/packages/core/tests/skip.test-d.ts +125 -0
- package/packages/core/tests/testing-entry.test.ts +73 -0
- package/packages/core/tests/testing-fake-replica.test.ts +1242 -0
- package/packages/core/tests/testing-test-auth.test-d.ts +84 -0
- package/packages/core/tests/testing-test-auth.test.ts +483 -0
- package/packages/core/tests/testing-test-client.test-d.ts +184 -0
- package/packages/core/tests/testing-test-client.test.ts +1272 -0
- package/packages/core/tests/time-realm.test.ts +63 -0
- package/packages/core/tests/time.test.ts +238 -0
- package/packages/core/tests/traps/README.md +39 -0
- package/packages/core/tests/traps/anonymous-write.test.ts +145 -0
- package/packages/core/tests/traps/classification-table.test.ts +256 -0
- package/packages/core/tests/traps/err-arm.test.ts +144 -0
- package/packages/core/tests/traps/fetch-spy.ts +39 -0
- package/packages/core/tests/traps/invalidation-after-write.test.ts +178 -0
- package/packages/core/tests/traps/ledger.ts +248 -0
- package/packages/core/tests/traps/root-key-off-local.test.ts +130 -0
- package/packages/core/tests/traps/stale-data-across-users.test.ts +173 -0
- package/packages/core/tests/traps/unresolved-name.test.ts +155 -0
- package/packages/core/tests/traps/update-as-query.test.ts +244 -0
- package/packages/core/tests/traps/update-not-resent.test.ts +126 -0
- package/packages/core/tests/traps/update-resent-when-never-delivered.test.ts +159 -0
- package/packages/core/tests/traps.test-d.ts +476 -0
- package/packages/core/tests/units.test-d.ts +118 -0
- package/packages/core/tests/units.test.ts +634 -0
- package/packages/core/tsconfig.json +19 -0
- package/packages/core/tsconfig.typecheck.json +16 -0
- package/packages/core/vitest.config.ts +13 -0
- package/packages/mcp/LICENSE +21 -0
- package/packages/mcp/README.md +189 -0
- package/packages/mcp/package.json +62 -0
- package/packages/mcp/src/candid/candid-text.test.ts +455 -0
- package/packages/mcp/src/candid/candid-text.ts +501 -0
- package/packages/mcp/src/candid/contract.test.ts +398 -0
- package/packages/mcp/src/candid/formats.ts +155 -0
- package/packages/mcp/src/candid/hex.ts +29 -0
- package/packages/mcp/src/candid/json-schema.test.ts +758 -0
- package/packages/mcp/src/candid/json-schema.ts +454 -0
- package/packages/mcp/src/candid/json.test.ts +1207 -0
- package/packages/mcp/src/candid/json.ts +1053 -0
- package/packages/mcp/src/candid/schema-walk.ts +189 -0
- package/packages/mcp/src/candid/type-text.test.ts +179 -0
- package/packages/mcp/src/candid/type-text.ts +238 -0
- package/packages/mcp/src/cli.ts +134 -0
- package/packages/mcp/src/identity.ts +188 -0
- package/packages/mcp/src/interface/cache.test.ts +48 -0
- package/packages/mcp/src/interface/cache.ts +68 -0
- package/packages/mcp/src/interface/cli-cache.test.ts +150 -0
- package/packages/mcp/src/interface/cli-cache.ts +122 -0
- package/packages/mcp/src/interface/compile-worker.test.ts +246 -0
- package/packages/mcp/src/interface/compile-worker.ts +290 -0
- package/packages/mcp/src/interface/compile.test.ts +155 -0
- package/packages/mcp/src/interface/compile.ts +281 -0
- package/packages/mcp/src/interface/docs.test.ts +105 -0
- package/packages/mcp/src/interface/docs.ts +86 -0
- package/packages/mcp/src/interface/fixtures/icrc1.did +88 -0
- package/packages/mcp/src/interface/hex.ts +8 -0
- package/packages/mcp/src/interface/ids.test.ts +71 -0
- package/packages/mcp/src/interface/ids.ts +87 -0
- package/packages/mcp/src/interface/loader.test.ts +804 -0
- package/packages/mcp/src/interface/loader.ts +519 -0
- package/packages/mcp/src/interface/read-candid.test.ts +300 -0
- package/packages/mcp/src/interface/read-candid.ts +259 -0
- package/packages/mcp/src/interface/types.ts +113 -0
- package/packages/mcp/src/network.ts +122 -0
- package/packages/mcp/src/options.ts +149 -0
- package/packages/mcp/src/server/approval.ts +159 -0
- package/packages/mcp/src/server/naming.ts +43 -0
- package/packages/mcp/src/server/results.ts +102 -0
- package/packages/mcp/src/server/server.ts +797 -0
- package/packages/mcp/src/server/tools.ts +116 -0
- package/packages/mcp/src/usage.ts +40 -0
- package/packages/mcp/tests/approval.test.ts +60 -0
- package/packages/mcp/tests/identity.test.ts +234 -0
- package/packages/mcp/tests/naming.test.ts +62 -0
- package/packages/mcp/tests/options.test.ts +140 -0
- package/packages/mcp/tests/server.test.ts +997 -0
- package/packages/mcp/tsconfig.json +19 -0
- package/packages/mcp/tsconfig.typecheck.json +10 -0
- package/packages/mcp/vitest.config.ts +10 -0
- package/packages/react/LICENSE +21 -0
- package/packages/react/README.md +328 -0
- package/packages/react/llms.txt +95 -0
- package/packages/react/package.json +95 -0
- package/packages/react/src/index.tsx +678 -0
- package/packages/react/tests/abandoned-render.test.tsx +816 -0
- package/packages/react/tests/auth.test.tsx +315 -0
- package/packages/react/tests/caller-keys.test.tsx +2334 -0
- package/packages/react/tests/client-time.test.ts +40 -0
- package/packages/react/tests/entry.test.ts +52 -0
- package/packages/react/tests/helpers.tsx +291 -0
- package/packages/react/tests/hydration.test.tsx +262 -0
- package/packages/react/tests/ownership.test.tsx +260 -0
- package/packages/react/tests/provider.server.test.tsx +169 -0
- package/packages/react/tests/query-client.test.tsx +107 -0
- package/packages/react/tests/strict-mode.test.tsx +288 -0
- package/packages/react/tests/suspense.test-d.tsx +357 -0
- package/packages/react/tests/two-query-cores.test.tsx +135 -0
- package/packages/react/tests/types.test-d.tsx +63 -0
- package/packages/react/tsconfig.json +23 -0
- package/packages/react/tsconfig.test.json +8 -0
- package/packages/react/tsconfig.typecheck.json +16 -0
- package/packages/react/vitest.config.ts +39 -0
- package/packages/vite-plugin/LICENSE +21 -0
- package/packages/vite-plugin/README.md +532 -0
- package/packages/vite-plugin/package.json +76 -0
- package/packages/vite-plugin/src/describe-value.test.ts +43 -0
- package/packages/vite-plugin/src/describe-value.ts +167 -0
- package/packages/vite-plugin/src/dev-environment.test.ts +747 -0
- package/packages/vite-plugin/src/dev-environment.ts +510 -0
- package/packages/vite-plugin/src/env.ts +431 -0
- package/packages/vite-plugin/src/fetch.ts +348 -0
- package/packages/vite-plugin/src/file-identity.ts +106 -0
- package/packages/vite-plugin/src/generate.ts +691 -0
- package/packages/vite-plugin/src/index.test.ts +1243 -0
- package/packages/vite-plugin/src/index.ts +2565 -0
- package/packages/vite-plugin/src/interface.ts +339 -0
- package/packages/vite-plugin/src/local-host.ts +34 -0
- package/packages/vite-plugin/src/options.ts +641 -0
- package/packages/vite-plugin/src/principal-text.test.ts +87 -0
- package/packages/vite-plugin/src/principal-text.ts +98 -0
- package/packages/vite-plugin/tests/close.test.ts +141 -0
- package/packages/vite-plugin/tests/environment-mode.test.ts +136 -0
- package/packages/vite-plugin/tests/fake-ic.ts +214 -0
- package/packages/vite-plugin/tests/fetch-sdk.test.ts +27 -0
- package/packages/vite-plugin/tests/fetch.test.ts +1196 -0
- package/packages/vite-plugin/tests/fixtures/fake-cli/bin.js +90 -0
- package/packages/vite-plugin/tests/fixtures/fake-cli/package.json +8 -0
- package/packages/vite-plugin/tests/fixtures/icrc1.did +88 -0
- package/packages/vite-plugin/tests/generation.test.ts +1036 -0
- package/packages/vite-plugin/tests/icp-command.test.ts +194 -0
- package/packages/vite-plugin/tests/icp-timeout.test.ts +83 -0
- package/packages/vite-plugin/tests/no-process-exit.test.ts +83 -0
- package/packages/vite-plugin/tests/on-generated.test.ts +323 -0
- package/packages/vite-plugin/tests/output-collision.test.ts +329 -0
- package/packages/vite-plugin/tests/package.test.ts +62 -0
- package/packages/vite-plugin/tests/project.test.ts +2993 -0
- package/packages/vite-plugin/tests/support.ts +339 -0
- package/packages/vite-plugin/tests/timeout.test.ts +107 -0
- package/packages/vite-plugin/tsconfig.json +23 -0
- package/packages/vite-plugin/tsconfig.typecheck.json +16 -0
- package/packages/vite-plugin/vitest.config.ts +9 -0
- package/pnpm-workspace.yaml +23 -0
- package/scripts/ai-context-files.js +72 -0
- package/scripts/assemble-docs-site.mjs +485 -0
- package/scripts/assemble-docs-site.test.mjs +568 -0
- package/scripts/build-examples.js +58 -0
- package/scripts/check-ai-context.js +963 -0
- package/scripts/check-ai-context.test.mjs +811 -0
- package/scripts/check-exports.mjs +767 -0
- package/scripts/check-exports.test.mjs +1136 -0
- package/scripts/check-snippets/ambient.d.ts +428 -0
- package/scripts/check-snippets/app/generated/backend.did +7 -0
- package/scripts/check-snippets/app/generated/backend.ts +15 -0
- package/scripts/check-snippets/app/generated/icrc1.did +88 -0
- package/scripts/check-snippets/app/generated/icrc1.ts +78 -0
- package/scripts/check-snippets/app/globals.ts +26 -0
- package/scripts/check-snippets/docs/guides/App.tsx +21 -0
- package/scripts/check-snippets/docs/guides/app/providers.tsx +23 -0
- package/scripts/check-snippets/docs/guides/auth-client.ts +47 -0
- package/scripts/check-snippets/docs/guides/canisters/backend.ts +3 -0
- package/scripts/check-snippets/docs/guides/canisters/icrc1.ts +3 -0
- package/scripts/check-snippets/docs/guides/components/LedgerCard.tsx +26 -0
- package/scripts/check-snippets/docs/guides/components/shell.tsx +11 -0
- package/scripts/check-snippets/docs/guides/components/sign-in-page.tsx +29 -0
- package/scripts/check-snippets/docs/guides/components/slow-section.tsx +5 -0
- package/scripts/check-snippets/docs/guides/generated/accounts.ts +95 -0
- package/scripts/check-snippets/docs/guides/generated/ckbtc_minter.ts +40 -0
- package/scripts/check-snippets/docs/guides/generated/icp_ledger.ts +267 -0
- package/scripts/check-snippets/docs/guides/ledger.ts +10 -0
- package/scripts/check-snippets/docs/guides/server/request-client.ts +8 -0
- package/scripts/check-snippets.mjs +993 -0
- package/scripts/check-snippets.test.mjs +338 -0
- package/scripts/check-stack.mjs +501 -0
- package/scripts/check-stack.test.mjs +800 -0
- package/scripts/clean-node-modules.js +67 -0
- package/scripts/example-projects.js +58 -0
- package/scripts/export-budget.mjs +145 -0
- package/scripts/faults.json +6749 -0
- package/scripts/lib/fault-workspace.mjs +210 -0
- package/scripts/lib/io.mjs +29 -0
- package/scripts/lib/io.test.mjs +38 -0
- package/scripts/lib/markdown-fences.mjs +56 -0
- package/scripts/lib/markdown-fences.test.mjs +84 -0
- package/scripts/lib/package-exports.mjs +54 -0
- package/scripts/lib/package-exports.test.mjs +66 -0
- package/scripts/lib/release-pr-steps.mjs +47 -0
- package/scripts/release-tag.mjs +95 -0
- package/scripts/release-tag.test.mjs +278 -0
- package/scripts/release-workflow.test.mjs +98 -0
- package/scripts/release.js +167 -0
- package/scripts/release.test.mjs +347 -0
- package/scripts/removed-v3-names.js +125 -0
- package/scripts/size-app/.size-limit.js +90 -0
- package/scripts/size-app/core.js +3 -0
- package/scripts/size-app/package.json +24 -0
- package/scripts/size-app/react.js +4 -0
- package/scripts/size-app.test.mjs +73 -0
- package/scripts/sync-ai-context-versions.js +102 -0
- package/scripts/sync-example-versions.js +151 -0
- package/scripts/test-examples-published.mjs +1585 -0
- package/scripts/test-examples-published.test.mjs +1586 -0
- package/scripts/traps/any-method-vars-not-a-list.json +5 -0
- package/scripts/traps/canister-method-unknown.json +5 -0
- package/scripts/traps/client-says-who-calls-once.json +5 -0
- package/scripts/traps/client-says-who-calls.json +5 -0
- package/scripts/traps/err-only-on-canister-err.json +14 -0
- package/scripts/traps/format-units-refuses-missing-value.json +5 -0
- package/scripts/traps/format-units-refuses-number.json +5 -0
- package/scripts/traps/format-units-unknown-option.json +5 -0
- package/scripts/traps/guard-err-is-the-methods.json +5 -0
- package/scripts/traps/guard-false-keeps-every-kind.json +5 -0
- package/scripts/traps/internals-not-exported.json +9 -0
- package/scripts/traps/network-refuses-unknown-name.json +5 -0
- package/scripts/traps/never-err-has-no-type.json +5 -0
- package/scripts/traps/options-method-unknown.json +5 -0
- package/scripts/traps/options-vars-wrong-type.json +5 -0
- package/scripts/traps/parse-units-refuses-number.json +5 -0
- package/scripts/traps/parse-units-unknown-option.json +5 -0
- package/scripts/traps/principal-is-not-plain-text.json +14 -0
- package/scripts/traps/query-options-refuses-oneway.json +5 -0
- package/scripts/traps/query-options-refuses-update.json +5 -0
- package/scripts/traps/refuse-next-unknown-option.json +5 -0
- package/scripts/traps/resend-key-reads-the-methods-arg.json +5 -0
- package/scripts/traps/resend-states-its-dedupe-key.json +5 -0
- package/scripts/traps/suspense-refuses-argument-skip.json +5 -0
- package/scripts/traps/suspense-refuses-skippable-read.json +5 -0
- package/scripts/traps/suspense-refuses-vars-skip-fits.json +5 -0
- package/scripts/traps/test-handler-method-unknown.json +5 -0
- package/scripts/traps/test-handler-nat-is-bigint.json +5 -0
- package/scripts/traps/test-handler-takes-the-domain-value.json +5 -0
- package/scripts/traps/vars-of-two-arguments-are-the-tuple.json +5 -0
- package/scripts/typecheck-examples.js +122 -0
- package/scripts/verify-faults.mjs +375 -0
- package/scripts/verify-faults.test.mjs +402 -0
- package/scripts/verify-package-artifacts.mjs +590 -0
- package/scripts/verify-peer-floors.js +399 -0
- package/scripts/verify-peer-floors.test.mjs +422 -0
- package/scripts/verify-test-fails-rules.mjs +104 -0
- package/scripts/verify-test-fails-rules.test.mjs +215 -0
- package/scripts/verify-test-fails.js +371 -0
- package/scripts/verify-traps.mjs +505 -0
- package/scripts/verify-traps.test.mjs +521 -0
- package/scripts/verify-typescript-floor.js +239 -0
- package/skill-packages/ic-reactor/SKILL.md +103 -0
- package/stack.json +8 -0
- package/tsconfig.base.json +23 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,610 @@
|
|
|
1
|
+
# @ic-reactor/core
|
|
2
|
+
|
|
3
|
+
> How to call Internet Computer canisters with a module `meant gen`
|
|
4
|
+
> generated from a `.did`, a client from `@ic-reactor/core`, and TanStack
|
|
5
|
+
> Query. The client applies the rules a hand-written integration must get
|
|
6
|
+
> right; this guide names the call for each.
|
|
7
|
+
|
|
8
|
+
Applies to `@ic-reactor/core` 4.1.1.
|
|
9
|
+
|
|
10
|
+
## Imports
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { createClient, formatUnits, isReactorError, parseUnits } from "@ic-reactor/core"
|
|
14
|
+
import { ReactorProvider, useAuth, useClient } from "@ic-reactor/react"
|
|
15
|
+
import { isPrincipal, principal, type Principal } from "@meantjs/schema"
|
|
16
|
+
import { skipToken, useMutation, useQuery } from "@tanstack/react-query"
|
|
17
|
+
import { actor, type Actor } from "./generated/icrc1"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
One import path per name: Candid values only from `@meantjs/schema`,
|
|
21
|
+
`skipToken` and the hooks only from TanStack Query.
|
|
22
|
+
|
|
23
|
+
`@ic-reactor/core` and `@ic-reactor/react` are ES modules only. A Node
|
|
24
|
+
project needs `"type": "module"` in its `package.json`
|
|
25
|
+
(`npm pkg set type=module`), or a bundler; `npx tsx` with
|
|
26
|
+
top-level `await` fails in a CommonJS package. Under TypeScript's
|
|
27
|
+
`moduleResolution: "nodenext"`, import local files with their `.js`
|
|
28
|
+
extension (`./generated/icrc1.js`).
|
|
29
|
+
|
|
30
|
+
The generated module (from `meant gen` or `@ic-reactor/vite-plugin`; do not edit
|
|
31
|
+
it) exports a type and schema per Candid type, the service schema `actor`, and
|
|
32
|
+
`type Actor`.
|
|
33
|
+
|
|
34
|
+
## Setup
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
// src/ledger.ts
|
|
38
|
+
import { createClient } from "@ic-reactor/core"
|
|
39
|
+
import { actor, type Actor } from "./generated/icrc1"
|
|
40
|
+
|
|
41
|
+
export const client = createClient({ network: "ic", identity: "anonymous" })
|
|
42
|
+
export const ledger = client.canister<Actor>(actor, { id: "ryjl3-tyaaa-aaaaa-aaaba-cai" })
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`client.canister()` returns the same object each time: safe in render.
|
|
46
|
+
|
|
47
|
+
With React, install `@tanstack/query-core` at the exact version your
|
|
48
|
+
`@tanstack/react-query` depends on (`npm view @tanstack/react-query@<version>
|
|
49
|
+
dependencies`), and check that `npm ls @tanstack/query-core` shows one copy.
|
|
50
|
+
With two copies, core and the hooks each have their own `skipToken`:
|
|
51
|
+
`client.queryOptions()` throws a `TypeError` for the hooks' one, and in
|
|
52
|
+
development `ReactorProvider` throws when it is handed such a client.
|
|
53
|
+
|
|
54
|
+
`network` and the root key:
|
|
55
|
+
|
|
56
|
+
- `"ic"`: mainnet (`https://icp-api.io`) and its built-in root key.
|
|
57
|
+
- `"local"`: icp-cli's local network, `http://127.0.0.1:8000`; its root key
|
|
58
|
+
is fetched. A dfx replica is `{ host: "http://127.0.0.1:4943" }`.
|
|
59
|
+
- `{ host, rootKey }`: any other replica. A given `rootKey` is used, never
|
|
60
|
+
fetched; without one, it is fetched only from a local `host` (`localhost`,
|
|
61
|
+
`127.0.0.1`, `[::1]`). Never fetch one from any other host.
|
|
62
|
+
- `"env"`: the page's network. Canisters can be named, `{ name: "backend" }`,
|
|
63
|
+
from the `ic_env` cookie, believed only on a local replica or with
|
|
64
|
+
`allowEnvConfig: true`. A server has no cookie: use `{ id }` there.
|
|
65
|
+
`"env"` is for `localhost` pages: a LAN or Tailscale address, a LAN name
|
|
66
|
+
with no dot, `*.local`, `*.test`, `*.internal`, `*.ts.net`, a tunnel or a
|
|
67
|
+
dev container routes to its own origin (never mainnet) but does not
|
|
68
|
+
believe the cookie or take a root key.
|
|
69
|
+
`allowEnvConfig: true` throws on `ic0.app`, `*.app.github.dev`,
|
|
70
|
+
`*.gitpod.io`, `*.loca.lt` and `*.devtunnels.ms` pages (not public
|
|
71
|
+
suffixes: any sibling site can set the cookie), and never takes the
|
|
72
|
+
cookie's root key for a mainnet host.
|
|
73
|
+
`client.canisterId({ name })` says, without a call, what a name resolves
|
|
74
|
+
to: `{ ok: true, id }`, or `{ ok: false, reason, message }` with `reason`
|
|
75
|
+
`"no_browser"`, `"untrusted_host"` or `"absent"`, and the resolver's reason
|
|
76
|
+
text, which a call's error includes after the method and target.
|
|
77
|
+
- Without the Vite plugin (Next.js, webpack, esbuild) there is no cookie and no
|
|
78
|
+
`/api` proxy, so `"env"` and `{ name }` do not work on a local network. Use
|
|
79
|
+
`network: "local"` with `{ id }` from a build-time variable
|
|
80
|
+
(`NEXT_PUBLIC_BACKEND_ID`, written from
|
|
81
|
+
`icp canister status -e local -i backend` into
|
|
82
|
+
`.env.development.local`, which only `next dev` reads).
|
|
83
|
+
|
|
84
|
+
Deploying to mainnet (`icp deploy -e ic`): with `"env"`, a canister's own
|
|
85
|
+
`<id>.icp0.io` (or `<id>.raw.icp0.io`) page believes its cookie's canister
|
|
86
|
+
ids (a public suffix: no sibling can set it) and nothing else: never its root
|
|
87
|
+
key or its `INTERNET_IDENTITY_PROVIDER` (sign-in stays mainnet's). Off a local
|
|
88
|
+
page, when the page receives more than one `ic_env` cookie and they differ,
|
|
89
|
+
none is believed (`{ name }` gets `untrusted_host`). On `<id>.ic0.app` and
|
|
90
|
+
custom domains `{ name }` does not resolve. For a mainnet app, which should not
|
|
91
|
+
depend on the cookie, and a page that works everywhere, name canisters
|
|
92
|
+
`{ id: import.meta.env.VITE_BACKEND_ID }`,
|
|
93
|
+
with the local id in `.env.development` and the mainnet id
|
|
94
|
+
(`icp canister status backend -e ic -i`) in `.env.production`. Never set
|
|
95
|
+
`allowEnvConfig: true` on `ic0.app`; on a custom domain only when every
|
|
96
|
+
subdomain is yours.
|
|
97
|
+
|
|
98
|
+
Serve the frontend canister with security headers. For DFINITY's asset
|
|
99
|
+
canister, put `.ic-assets.json5` in Vite's `public/` (icp-cli's static-site
|
|
100
|
+
recipe reads the same headers from a `_headers` file):
|
|
101
|
+
|
|
102
|
+
```json5
|
|
103
|
+
[
|
|
104
|
+
{
|
|
105
|
+
match: "**/*",
|
|
106
|
+
security_policy: "hardened",
|
|
107
|
+
headers: {
|
|
108
|
+
"Content-Security-Policy": "default-src 'none'; script-src 'self'; connect-src 'self' https://icp-api.io; img-src 'self' data:; style-src 'self'; font-src 'self'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'",
|
|
109
|
+
"Cross-Origin-Opener-Policy": "same-origin-allow-popups",
|
|
110
|
+
},
|
|
111
|
+
allow_raw_access: false,
|
|
112
|
+
},
|
|
113
|
+
]
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
A `Cross-Origin-Opener-Policy` of `same-origin` cuts off the Internet
|
|
117
|
+
Identity window, so sign-in never completes. The HTTP gateway checks a page
|
|
118
|
+
against the canister's certified state on `<id>.icp0.io`, not on
|
|
119
|
+
`<id>.raw.icp0.io`: never link to the raw domain.
|
|
120
|
+
|
|
121
|
+
`createClient` throws a `TypeError` for an option it does not have (`host`
|
|
122
|
+
goes inside `network`), an `allowEnvConfig` or `fetchRootKey` that is not a
|
|
123
|
+
boolean (environment text: `=== "true"`), a `rootKey` that is not 133 bytes
|
|
124
|
+
in a `Uint8Array` (decode hex first), and a `host` the agent cannot call over
|
|
125
|
+
`http:` or `https:`, including one `"env"` takes from the page or from
|
|
126
|
+
`ICP_HOST` (`localhost:4943` reads as the scheme `localhost:`; write
|
|
127
|
+
`http://localhost:4943`).
|
|
128
|
+
|
|
129
|
+
Who calls (exactly one):
|
|
130
|
+
|
|
131
|
+
- `identity`: a fixed `Identity` (scripts, servers, tests), or `"anonymous"`,
|
|
132
|
+
read-only: every update is refused before sending. A
|
|
133
|
+
`new AnonymousIdentity()` signs writes, so map one you are handed:
|
|
134
|
+
`identity: id && !id.getPrincipal().isAnonymous() ? id : "anonymous"`.
|
|
135
|
+
- `auth: (network) => new AuthClient(network)` (`@icp-sdk/auth/client`):
|
|
136
|
+
users sign in and out. The factory runs once, in a browser only; if it
|
|
137
|
+
throws (blocked `localStorage`) or returns no auth (a Promise, from an
|
|
138
|
+
`async` factory), the client stays anonymous, public reads still work, and
|
|
139
|
+
`signIn()` rejects with the error. `network`
|
|
140
|
+
is `{ agentOptions, identityProvider? }`: the client's host and root key
|
|
141
|
+
(and its `fetch`, when you gave one), and the Internet Identity to sign in
|
|
142
|
+
with (that of an `ic_env` cookie believed in full, on a local page or with
|
|
143
|
+
`allowEnvConfig: true`, never a canister's `icp0.io` page's; or icp-cli's
|
|
144
|
+
built-in one for a local host). Absent on a mainnet client, it
|
|
145
|
+
means mainnet's. Absent on any other network (a project that deploys its
|
|
146
|
+
own `internet_identity`, `"env"` on a local page with no
|
|
147
|
+
`INTERNET_IDENTITY_PROVIDER` in the cookie, a replica with its own root
|
|
148
|
+
key), sign-in cannot work, and a factory that reads
|
|
149
|
+
`network.identityProvider`, as `new AuthClient(network)` does, gets a
|
|
150
|
+
warning once in development. Name the provider there, which never warns:
|
|
151
|
+
`(network) => new AuthClient({ ...network, identityProvider: { authorizeUrl, canisterId } })`.
|
|
152
|
+
A spread that adds other options, `{ ...network, derivationOrigin }`, reads no
|
|
153
|
+
provider and gets no warning, so name one there too.
|
|
154
|
+
`() => new AuthClient()` ignores `network`, so it suits mainnet only. On a
|
|
155
|
+
dfx replica (`{ host: "http://127.0.0.1:4943" }`) the factory is handed
|
|
156
|
+
icp-cli's built-in Internet Identity on port 4943, which dfx does not serve:
|
|
157
|
+
name the one the dfx project deploys.
|
|
158
|
+
Two `signIn()` calls with the same options in one synchronous run, as
|
|
159
|
+
`StrictMode`'s double effect makes them, are one sign-in.
|
|
160
|
+
With `new AuthClient({ ...network, transport: "redirect" })` (Internet
|
|
161
|
+
Identity's ICRC-167 redirect), sign in only on a route of its own that calls
|
|
162
|
+
`signIn()` on every load, from an effect that starts it on a timer its
|
|
163
|
+
cleanup clears (a hydrating render shows `"anonymous"` whatever the
|
|
164
|
+
session). Enter that route with a full page load (`<a href="/sign-in">`, not
|
|
165
|
+
a router link): `AuthClient` takes its callback from the page it is built
|
|
166
|
+
on. List that URL in the origin's `/.well-known/ii-auth-callbacks`.
|
|
167
|
+
|
|
168
|
+
Internet Identity's sign-in features, 2.0's among them, are `AuthClient`
|
|
169
|
+
options. Pass them in the
|
|
170
|
+
factory beside `...network` (`openIdProvider`, `ssoDomain`,
|
|
171
|
+
`derivationOrigin`, `stateStorage: new CookieStateStorage({ domain })`,
|
|
172
|
+
`namespace`, `disableBrowserActivity`, `transport: "redirect"`, which needs
|
|
173
|
+
`signIn()` called on the page's load, not from a click), or to
|
|
174
|
+
`signIn()` (`maxTimeToLive`, `maxTimeToIdle`, `returnTo`). `signIn()` rejects
|
|
175
|
+
with the auth's own errors (its window closed or blocked, a
|
|
176
|
+
`SupersededError`), never a `ReactorError`: always catch it.
|
|
177
|
+
|
|
178
|
+
Identity attributes reach a canister as a call's `sender_info`, never as
|
|
179
|
+
arguments. With DFINITY's `identity-attributes` library on the canister: keep
|
|
180
|
+
the `AuthClient` the factory builds, and the `identityProvider` canister it is
|
|
181
|
+
handed (mainnet: `rdmx6-jaaaa-aaaaa-aaadq-cai`), per client; mint the nonce
|
|
182
|
+
(`_internet_identity_sign_in_start`, an update) through a second client on the
|
|
183
|
+
same network built with `identity: new AnonymousIdentity()`, since
|
|
184
|
+
`identity: "anonymous"` and a signed-out client refuse updates; start
|
|
185
|
+
`client.signIn()` and `requestAttributes({ keys, nonce })` together, from a
|
|
186
|
+
click; then call `_internet_identity_sign_in_finish` through a client built
|
|
187
|
+
with `identity: new AttributesIdentity({ inner: await authClient.getIdentity(), attributes, signer: { canisterId } })`,
|
|
188
|
+
dispose both, and invalidate the app client's reads of that canister. Its
|
|
189
|
+
`err` rejects as a `canister_err`; an untrusted signer traps (`rejected`, code
|
|
190
|
+
5). Trust `verified_email`, never `email` (for an organization's SSO, the
|
|
191
|
+
canister reads `sso:<domain>:email` for its `trusted_sso_domains`), and let
|
|
192
|
+
the canister check the attributes.
|
|
193
|
+
|
|
194
|
+
Who is calling, and may they write:
|
|
195
|
+
|
|
196
|
+
| Question | Answer |
|
|
197
|
+
| ---------------------- | ------------------------------------------------------------------------- |
|
|
198
|
+
| the caller's principal | `useAuth().principal`, `client.caller()` (`"2vxsx-fae"` unless signed in) |
|
|
199
|
+
| may a write be sent | `useAuth().status === "signed-in"`; the client refuses the rest itself |
|
|
200
|
+
| when did it change | `useAuth()` re-renders; `client.subscribe(fn)` |
|
|
201
|
+
|
|
202
|
+
`"signed-in"` may be a read-only session (Internet Identity can scope one to
|
|
203
|
+
queries, and the network refuses its updates); nothing tells the two apart
|
|
204
|
+
yet. A session ends by the clock: `useAuth()` re-renders with `"expired"` at
|
|
205
|
+
`expiresAt` (ms since the epoch, present while signed in), with no user
|
|
206
|
+
activity.
|
|
207
|
+
|
|
208
|
+
The client keeps one agent per principal: a call goes out as the principal
|
|
209
|
+
current when it was made, or not at all.
|
|
210
|
+
|
|
211
|
+
One client per browser tab, or per request on a server. In React,
|
|
212
|
+
`<ReactorProvider client={() => createClient(...)}>` builds it once per
|
|
213
|
+
mounted tree and disposes it on unmount; a module-scope client passed as
|
|
214
|
+
`client={() => client}` is borrowed, never disposed. A client made outside a
|
|
215
|
+
provider, or kept across its unmount, is the app's to release with
|
|
216
|
+
`client.dispose()` (calling it again does nothing; later calls reject
|
|
217
|
+
`cancelled`, code `client_disposed`, and send nothing); one that lives as long
|
|
218
|
+
as the page needs none. Inside, `useClient()`
|
|
219
|
+
returns a view of it for the caller the render shows (anonymous while
|
|
220
|
+
hydrating): a new object after each sign-in, switch or sign-out, the same one
|
|
221
|
+
while the caller stays, whose `mutationOptions` send only as that caller (a
|
|
222
|
+
write pressed before a switch reaches the render is refused `cancelled`,
|
|
223
|
+
`caller_changed`, and sends nothing). `useAuth()` returns
|
|
224
|
+
`{ status, principal, expiresAt?, signIn, signOut }`, `"anonymous"` on a server and in a
|
|
225
|
+
hydrating page's first render.
|
|
226
|
+
|
|
227
|
+
An app that already uses TanStack Query keeps one `QueryClient` per tree,
|
|
228
|
+
the client's: run its own queries (REST too) under `ReactorProvider`, on
|
|
229
|
+
`client.queryClient`. An error that is not a `ReactorError` is retried there
|
|
230
|
+
as TanStack Query retries it (up to 3 times in a browser), and
|
|
231
|
+
`client.dispose()` clears those queries too. A nested `QueryClientProvider` of
|
|
232
|
+
the app's still has its reads invalidated by a write that ran on it, but a
|
|
233
|
+
server render dehydrates `client.queryClient`.
|
|
234
|
+
|
|
235
|
+
Any other sign-in that hands over an `Identity` (a delegation, or a key)
|
|
236
|
+
becomes an `AuthLike`. A wallet that signs each call itself (ICRC-25 and
|
|
237
|
+
ICRC-49: OISY, Plug, NFID accounts) is not one: keep the client anonymous for
|
|
238
|
+
reads, send the wallet's writes with `SignerAgent` from `@icp-sdk/signer`, and
|
|
239
|
+
then invalidate the reads yourself with
|
|
240
|
+
`client.queryClient.invalidateQueries({ queryKey: client.queryKey(canister) })`.
|
|
241
|
+
Such a write gets no `ReactorError` and no `mayHaveExecuted`.
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
// src/auth-like.ts
|
|
245
|
+
import type { AuthLike } from "@ic-reactor/core"
|
|
246
|
+
import type { Identity } from "@icp-sdk/core/agent"
|
|
247
|
+
|
|
248
|
+
export interface SignInSource {
|
|
249
|
+
getIdentity(): Identity // anonymous while signed out
|
|
250
|
+
isAuthenticated(): boolean
|
|
251
|
+
login(): Promise<void>
|
|
252
|
+
logout(): Promise<void>
|
|
253
|
+
subscribe(listener: () => void): () => void
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function toAuthLike(source: SignInSource): AuthLike {
|
|
257
|
+
const signedIn = () =>
|
|
258
|
+
source.isAuthenticated() && !source.getIdentity().getPrincipal().isAnonymous()
|
|
259
|
+
return {
|
|
260
|
+
getPrincipal: () => (signedIn() ? source.getIdentity().getPrincipal() : undefined),
|
|
261
|
+
getStatus: () => ({ state: signedIn() ? "signed-in" : "signed-out" }),
|
|
262
|
+
getIdentity: async () => source.getIdentity(),
|
|
263
|
+
subscribe: (listener) => source.subscribe(listener),
|
|
264
|
+
signIn: () => source.login(),
|
|
265
|
+
signOut: () => source.logout(),
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Values
|
|
271
|
+
|
|
272
|
+
Methods use the generated types:
|
|
273
|
+
|
|
274
|
+
| Candid | Value |
|
|
275
|
+
| ---------------------------------------- | ---------------------------------------------- |
|
|
276
|
+
| `nat`, `int`, `nat64`, `int64` | `bigint` (never `number`) |
|
|
277
|
+
| `nat8`..`nat32`, `int8`..`int32`, floats | `number` |
|
|
278
|
+
| `text`, `bool` | `string`, `boolean` |
|
|
279
|
+
| `principal` | `Principal`: branded principal text |
|
|
280
|
+
| `blob` / `vec nat8` | `Uint8Array` |
|
|
281
|
+
| `opt T` | `T \| null` (the property is always present) |
|
|
282
|
+
| `opt opt T`, `opt null` | `{ some: T \| null } \| null`, `{ some: null } \| null` |
|
|
283
|
+
| `vec T` | `T[]` |
|
|
284
|
+
| `record { a : T }` | `{ a: T }`, every field present |
|
|
285
|
+
| `variant { A : T; B }` | `{ tag: "A"; value: T } \| { tag: "B" }` |
|
|
286
|
+
|
|
287
|
+
Make principals from user input with `principal(text)`, which throws a
|
|
288
|
+
`TypeError` for invalid text: catch it and refuse the input. In render, test with `isPrincipal(text)` first.
|
|
289
|
+
|
|
290
|
+
Direct calls take the parameters `type Actor` lists; the builders below take
|
|
291
|
+
them as one value: nothing for none, the value for one, a tuple `[a, b]` for
|
|
292
|
+
more.
|
|
293
|
+
|
|
294
|
+
Token amounts are base units:
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
/// <reference lib="es2023.intl" />
|
|
298
|
+
import { formatUnits, parseUnits } from "@ic-reactor/core"
|
|
299
|
+
|
|
300
|
+
const units = parseUnits("1.5", 8) // 150000000n
|
|
301
|
+
const text = formatUnits(units, 8, { minFractionDigits: 8 }) // "1.50000000"
|
|
302
|
+
const local = new Intl.NumberFormat(undefined, { maximumFractionDigits: 8 }).format(
|
|
303
|
+
text as Intl.StringNumericLiteral // the cast needs lib ES2023
|
|
304
|
+
)
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
`parseUnits` throws for text that is not a plain decimal (`"1e3"`, `"1,5"`),
|
|
308
|
+
a negative, or more significant fraction digits than `decimals`: refuse that
|
|
309
|
+
input. Trailing zeros, `"5."`, `".5"` and whitespace around the number are
|
|
310
|
+
accepted (`"1.500"` at 2 decimals is `150n`), so validate the field with
|
|
311
|
+
`parseUnits` itself, not another parser. A cap is the Candid
|
|
312
|
+
type's: a `nat64` field refuses 2^64 at encoding (`invalid_args`); an ICRC-1
|
|
313
|
+
`amount` is a `nat`, with none.
|
|
314
|
+
|
|
315
|
+
### Results
|
|
316
|
+
|
|
317
|
+
A method whose result is `variant { Ok : T; Err : E }` resolves with the `Ok`
|
|
318
|
+
value; `Err` rejects as kind `"canister_err"`, with the `Err` value in `err`
|
|
319
|
+
(typed on a query's or mutation's `error`).
|
|
320
|
+
|
|
321
|
+
## Reads
|
|
322
|
+
|
|
323
|
+
```tsx
|
|
324
|
+
import type { Principal } from "@meantjs/schema"
|
|
325
|
+
import { formatUnits } from "@ic-reactor/core"
|
|
326
|
+
import { useClient } from "@ic-reactor/react"
|
|
327
|
+
import { skipToken, useQuery } from "@tanstack/react-query"
|
|
328
|
+
import { actor, type Actor } from "./generated/icrc1"
|
|
329
|
+
|
|
330
|
+
export function Balance({ owner }: { owner: Principal | undefined }) {
|
|
331
|
+
const client = useClient()
|
|
332
|
+
const ledger = client.canister<Actor>(actor, { id: "ryjl3-tyaaa-aaaaa-aaaba-cai" })
|
|
333
|
+
const balance = useQuery(
|
|
334
|
+
client.queryOptions(ledger, "icrc1_balance_of", owner ? { owner, subaccount: null } : skipToken)
|
|
335
|
+
)
|
|
336
|
+
return <p>{balance.data === undefined ? "…" : formatUnits(balance.data, 8)}</p>
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
`skipToken` stands in for arguments not known yet;
|
|
341
|
+
arguments that do not encode make the read reject `invalid_args`.
|
|
342
|
+
|
|
343
|
+
Keys are `["ic-reactor", network, caller, canisterId, method, args]`, so one
|
|
344
|
+
principal's cached answer is never served to another: after a sign-in,
|
|
345
|
+
sign-out or switch, the new caller's key is empty (`data` is `undefined`)
|
|
346
|
+
until it loads, and a read made for the previous caller never lands in it.
|
|
347
|
+
A sign-out, an expired session or a switch also removes the previous
|
|
348
|
+
caller's reads from the cache; the anonymous reads stay.
|
|
349
|
+
Keep it so: build the options in render from that render's `useClient()`,
|
|
350
|
+
listing it in the dependencies of any `useMemo` or effect built from it
|
|
351
|
+
(React Compiler does), and add nothing that carries data across keys
|
|
352
|
+
(`placeholderData: keepPreviousData`, cross-key `initialData`).
|
|
353
|
+
`client.queryKey(ledger, method?, args?)` gives keys for the cache.
|
|
354
|
+
|
|
355
|
+
Reads retry transient failures (never on a server). Spread to add options:
|
|
356
|
+
`{ ...client.queryOptions(...), staleTime }`.
|
|
357
|
+
|
|
358
|
+
`queryOptions` with an update or oneway method of a generated `Actor` does
|
|
359
|
+
not compile (an `Actor` written by hand says no mode: it throws at run time).
|
|
360
|
+
An update that answers the same however often it runs (ckBTC's
|
|
361
|
+
`get_btc_address`) opts in with a fourth argument, `{ update: "idempotent" }`,
|
|
362
|
+
after the arguments (`undefined` when it takes none); a oneway never compiles.
|
|
363
|
+
Such a read is still an update, so a signed-out or `"anonymous"` client
|
|
364
|
+
refuses it (`unauthenticated`) and sends nothing. Read an ICRC-21 consent
|
|
365
|
+
message as the caller who will send the write: the message can depend on the
|
|
366
|
+
caller (the DFINITY ICRC-1 ledger names the sender as `From`).
|
|
367
|
+
A method TypeScript cannot tell is a read does not compile: a type parameter
|
|
368
|
+
(`M extends keyof A & string`), a union that may name an update
|
|
369
|
+
(`keyof Actor & string`), or any method of a `Canister<A>` with a generic `A`.
|
|
370
|
+
Give the type arguments,
|
|
371
|
+
`client.queryOptions<A, any>(canister, method, vars)`, which keeps the
|
|
372
|
+
run-time check and types the data `unknown`. The variables follow the same
|
|
373
|
+
rule, checked at run time: the value for one argument, a tuple for several,
|
|
374
|
+
`undefined` or `[]` for none (`[arg]` compiles but is refused
|
|
375
|
+
`invalid_args`). `mutationOptions`, `queryKey` and `resendOf` take
|
|
376
|
+
`<A, any>` the same way; for a generic `A` only `queryOptions` widens the
|
|
377
|
+
variables, so cast them for the other three.
|
|
378
|
+
The target `{ id, certified: true }` certifies `query` replies: they are sent
|
|
379
|
+
as replicated calls and checked against the subnet's certificate, where a plain
|
|
380
|
+
query's reply is signed by the one replica that answered. A certified read
|
|
381
|
+
costs what an update costs (as long, and the canister pays cycles). Certify the
|
|
382
|
+
reads that decide where value goes or what a person approves (a recipient, a
|
|
383
|
+
deposit address, an allowance, the details shown before someone confirms) and
|
|
384
|
+
read the rest plainly, through two canister objects of one id.
|
|
385
|
+
|
|
386
|
+
## Writes
|
|
387
|
+
|
|
388
|
+
```tsx
|
|
389
|
+
import { useClient } from "@ic-reactor/react"
|
|
390
|
+
import { useMutation } from "@tanstack/react-query"
|
|
391
|
+
import { actor, type Actor, type TransferArg } from "./generated/icrc1"
|
|
392
|
+
|
|
393
|
+
export function Send({ arg }: { arg: TransferArg }) {
|
|
394
|
+
const client = useClient()
|
|
395
|
+
const ledger = client.canister<Actor>(actor, { id: "ryjl3-tyaaa-aaaaa-aaaba-cai" })
|
|
396
|
+
const transfer = useMutation(client.mutationOptions(ledger, "icrc1_transfer"))
|
|
397
|
+
return <button disabled={transfer.isPending} onClick={() => transfer.mutate(arg)}>Send</button>
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
- The mutation invalidates the canister's reads, for every caller, after a
|
|
402
|
+
success, a `canister_err` and a failure that may have executed. Nothing
|
|
403
|
+
else is needed after an unknown outcome.
|
|
404
|
+
A third argument, `{ invalidates: [canister, [canister, "method"]] }`,
|
|
405
|
+
names the reads to invalidate instead (name the written canister too if
|
|
406
|
+
its reads change); `[]`, none. To add an `onSettled`, call the client's
|
|
407
|
+
from yours.
|
|
408
|
+
- A write that timed out (`timeoutMs`, below in Errors) whose request went
|
|
409
|
+
out is `outcome_unknown`: never send it again blindly.
|
|
410
|
+
- Do not retry a write. `retry` is `false`; keep it. The client itself
|
|
411
|
+
re-sends an update, at most twice, only after a failure proving the canister
|
|
412
|
+
never got it (reject code 2, status 429); any other failure is final.
|
|
413
|
+
- A write is sent as the caller current when `mutate()` was called, or not at
|
|
414
|
+
all. Held back by TanStack Query (offline, queued behind its `scope`, or
|
|
415
|
+
retried) while the account changes, it is refused (`cancelled`,
|
|
416
|
+
`caller_changed`, `mayHaveExecuted: false`) and nothing is sent; a
|
|
417
|
+
re-send `resendOf` offered is refused as `outcome_unknown` instead (below). This holds
|
|
418
|
+
with an `onMutate` of yours that replaces the client's, on
|
|
419
|
+
`client.queryClient`. A mutation restored from a persister is always
|
|
420
|
+
refused that way: call `mutate()` again. On another `QueryClient`, keep the
|
|
421
|
+
client's `onMutate` (spread its result into yours; before TanStack Query
|
|
422
|
+
5.89, pass it unwrapped). If nobody is signed in,
|
|
423
|
+
the client refuses it (`unauthenticated`) before calling anything.
|
|
424
|
+
- Send the same write again after `mayHaveExecuted: true` only to a method
|
|
425
|
+
that runs the same argument from the same sender at most once, such as an
|
|
426
|
+
ICRC-1 transfer with `created_at_time` set (it answers `Duplicate`).
|
|
427
|
+
Stamp that key from the IC's clock, `await client.time(ledger)` (a certified
|
|
428
|
+
`bigint` of nanoseconds), not from `Date.now()`. That time moves about once
|
|
429
|
+
a second, so give each transfer its own `memo` too.
|
|
430
|
+
`client.resendOf(transfer.error, ledger, "icrc1_transfer", { dedupedBy: (arg) => arg.created_at_time })`
|
|
431
|
+
is `undefined` unless that write's outcome is unknown, `dedupedBy` finds a
|
|
432
|
+
key (not `null`) in its argument, the argument is unchanged since it was
|
|
433
|
+
sent, the canister still resolves where the write went, and its sender is
|
|
434
|
+
still the caller; then `again.send()` sends the same bytes to the same
|
|
435
|
+
canister as that sender, and `transfer.mutate(again.arg)` sends the
|
|
436
|
+
argument only as that same write, or sends nothing (`code`
|
|
437
|
+
`caller_changed`, `target_changed`, `arg_changed`). A re-send that did not
|
|
438
|
+
run, refused that way or turned away (a 429 or another 4xx status, reject
|
|
439
|
+
code 1 to 3), rejects `outcome_unknown` with `mayHaveExecuted: true`, because
|
|
440
|
+
the first attempt may have run: its `code`, `httpStatus` or `rejectCode`
|
|
441
|
+
and its `cause` say why, `resendOf` offers that write again while its
|
|
442
|
+
sender is the caller, and you read the state back before anything else. Never change an offered argument: build a new one for a new transfer. A method with no
|
|
443
|
+
such key has no safe re-send: read the state back.
|
|
444
|
+
- For the exact bytes a write will send, such as an ICRC-21 consent
|
|
445
|
+
request's `arg`, use `client.encode(ledger, "icrc1_transfer", arg)` (a
|
|
446
|
+
`Uint8Array`, made by the call's own encoder; variables that do not encode
|
|
447
|
+
throw `invalid_args`), never a second encoding of your own. An offered
|
|
448
|
+
re-send carries the bytes it sent as `again.bytes`.
|
|
449
|
+
- A `canister_err` is a known outcome, so `resendOf` offers nothing after it.
|
|
450
|
+
When the canister calls it temporary (an ICRC-1 `TemporarilyUnavailable`),
|
|
451
|
+
send the same argument object again with `transfer.mutate(arg)`: with
|
|
452
|
+
`created_at_time` set, that is the same bytes and the same key, answered
|
|
453
|
+
`Duplicate` if an earlier attempt ran.
|
|
454
|
+
- To keep an offer in state, type it from the method:
|
|
455
|
+
`NonNullable<ReturnType<typeof client.resendOf<Actor, "icrc1_transfer">>>`.
|
|
456
|
+
- Call update methods only from `useMutation` or directly, never from
|
|
457
|
+
`useQuery`; call query methods from `useQuery` or directly.
|
|
458
|
+
|
|
459
|
+
## Errors
|
|
460
|
+
|
|
461
|
+
Every rejection is a `ReactorError`: test with `isReactorError(error)`, then
|
|
462
|
+
read `kind` and `mayHaveExecuted`. For a direct call, test with
|
|
463
|
+
`isReactorError(error, canister, method)`: it narrows `error.err` to that
|
|
464
|
+
method's `Err` arm after `kind === "canister_err"` (no cast), and it is `false`
|
|
465
|
+
for an error of any other method, canister object or `client.func` call (it
|
|
466
|
+
checks at run time). A failed write either certainly had no effect, or may
|
|
467
|
+
have executed:
|
|
468
|
+
|
|
469
|
+
| What happened | `kind` | May have executed |
|
|
470
|
+
| ------------------------------------------------------------------------------- | --------------------------------- | ----------------- |
|
|
471
|
+
| refused before sending: arguments that do not encode, a write while signed out | `invalid_args`, `unauthenticated` | no |
|
|
472
|
+
| HTTP 4xx except 408 (429 included): the replica or a boundary node refused it | `not_delivered` | no |
|
|
473
|
+
| the identity did not sign it (a declined passkey or hardware-wallet prompt: the signer's error is the `cause`), or the request could not be built | `not_delivered` | no |
|
|
474
|
+
| reject code 1, 2 (transient) or 3: rejected before any canister code ran | `rejected` (2: `not_delivered`) | no |
|
|
475
|
+
| reject code 4 or 5: the canister rejected or trapped, maybe after changing state | `rejected` | yes (a write) |
|
|
476
|
+
| a sent write got no trustworthy answer: network drop, timeout, 5xx, 408 | `outcome_unknown` | yes |
|
|
477
|
+
| a reply that did not decode | `invalid_reply` | yes (a write) |
|
|
478
|
+
| the canister returned `Err` | `canister_err` | no |
|
|
479
|
+
| the caller changed, the call was aborted, or a read's `timeoutMs` passed (`code: "timeout"`) | `cancelled` | no (an aborted write: yes) |
|
|
480
|
+
| a `client.resendOf()` re-send that did not run, refused (its `code` says why) or turned away by any of the rows above (its `httpStatus` or `rejectCode` says why); the first attempt may have run | `outcome_unknown` | yes |
|
|
481
|
+
|
|
482
|
+
A write that got no answer (`outcome_unknown`, or `cancelled` with
|
|
483
|
+
`mayHaveExecuted: true`) carries `error.expiresAt`: the latest ingress expiry
|
|
484
|
+
its sends were signed with, a `bigint` of nanoseconds on the IC's clock
|
|
485
|
+
(about five minutes after the send). A `client.resendOf()` re-send that did
|
|
486
|
+
not run carries the `expiresAt` of the write it re-sends. Once the IC's time is past it, no send
|
|
487
|
+
of that write can still start running. For a method that commits without
|
|
488
|
+
awaiting another canister (an ICRC-1 transfer), a certified read-back of
|
|
489
|
+
state newer than that which finds nothing is final. Compare with a margin,
|
|
490
|
+
since the host's clock may differ from the IC's.
|
|
491
|
+
|
|
492
|
+
On the management canister (`aaaaa-aa`), codes 1 to 3 prove nothing: a write
|
|
493
|
+
there may have executed. A query changes nothing, so a failed read never "may
|
|
494
|
+
have executed".
|
|
495
|
+
|
|
496
|
+
How long a call waits: unless the call has a `timeoutMs` (below), neither the
|
|
497
|
+
client nor the agent puts a timeout on an HTTP request (the call or query, or a `read_state` that polls), so a request
|
|
498
|
+
that gets no answer waits as long as the `fetch` in use does. An accepted
|
|
499
|
+
update is polled for about five minutes (a deadline checked when a poll is
|
|
500
|
+
answered) before it rejects `outcome_unknown`. A read made with `queryOptions` stops
|
|
501
|
+
waiting at any point when TanStack Query cancels it
|
|
502
|
+
(`queryClient.cancelQueries(...)`, or its last observer unmounts), and
|
|
503
|
+
rejects `cancelled` (with `mayHaveExecuted: true` for an update read with
|
|
504
|
+
`{ update: "idempotent" }` whose request went out).
|
|
505
|
+
|
|
506
|
+
To bound the wait, give the canister target `timeoutMs`:
|
|
507
|
+
`client.canister<Actor>(actor, { id, timeoutMs: 15_000 })` bounds each of its
|
|
508
|
+
direct calls, its `queryOptions` reads, its mutations and `client.time()` on
|
|
509
|
+
it, counted from the call.
|
|
510
|
+
`client.mutationOptions(ledger, "icrc1_transfer", { timeoutMs: 15_000 })`
|
|
511
|
+
bounds that mutation's runs instead (1 to 2147483647 ms; anything else
|
|
512
|
+
throws). When it passes, the call stops waiting and rejects with
|
|
513
|
+
`code: "timeout"`: `cancelled`, `mayHaveExecuted: false`, for a read and for a
|
|
514
|
+
write that had not gone out; `outcome_unknown`, `mayHaveExecuted: true`, for a
|
|
515
|
+
write whose request went out, for an `{ update: "idempotent" }` read whose
|
|
516
|
+
request went out, and for a re-send of an offered write at any point. That
|
|
517
|
+
write may still execute: it is an unknown outcome to reconcile like any other
|
|
518
|
+
(read the state back, or `resendOf` for a method that deduplicates, given the
|
|
519
|
+
canister object the write went through: another `timeoutMs` is another
|
|
520
|
+
object), never one to send again blindly. Nothing is sent again for a
|
|
521
|
+
timeout, and the request is not torn down. Unlike other `cancelled` errors, a
|
|
522
|
+
`cancelled` with `code: "timeout"` is a real timeout: show it, do not ignore
|
|
523
|
+
it. Canister objects that differ only in `timeoutMs` share query keys, so a
|
|
524
|
+
read observed through two of them is bounded by the options TanStack Query
|
|
525
|
+
was given last.
|
|
526
|
+
|
|
527
|
+
## Outside React
|
|
528
|
+
|
|
529
|
+
```ts
|
|
530
|
+
import { principal } from "@meantjs/schema"
|
|
531
|
+
import { isReactorError, parseUnits } from "@ic-reactor/core"
|
|
532
|
+
import { client, ledger } from "./ledger"
|
|
533
|
+
|
|
534
|
+
const account = { owner: principal("aaaaa-aa"), subaccount: null }
|
|
535
|
+
|
|
536
|
+
const cached = await client.queryClient.fetchQuery(client.queryOptions(ledger, "icrc1_balance_of", account))
|
|
537
|
+
await client.queryClient.invalidateQueries({ queryKey: client.queryKey(ledger) })
|
|
538
|
+
const fresh = await ledger.icrc1_balance_of(account)
|
|
539
|
+
|
|
540
|
+
try {
|
|
541
|
+
const arg = { to: account, amount: parseUnits("1.5", 8), fee: null, memo: null, from_subaccount: null, created_at_time: null }
|
|
542
|
+
await ledger.icrc1_transfer(arg) // refused unless `client` was built with an Identity
|
|
543
|
+
} catch (error) {
|
|
544
|
+
if (!isReactorError(error, ledger, "icrc1_transfer")) throw error
|
|
545
|
+
if (error.kind === "canister_err") console.error(error.err.tag) // a TransferError
|
|
546
|
+
else console.error(error.mayHaveExecuted ? "unknown outcome: re-read first" : error.kind)
|
|
547
|
+
}
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
Direct calls never touch a cache. To test, `createTestClient()` from
|
|
551
|
+
`@ic-reactor/core/testing` gives a real client over an in-memory replica with
|
|
552
|
+
a sign-in you control.
|
|
553
|
+
|
|
554
|
+
## Example
|
|
555
|
+
|
|
556
|
+
```tsx
|
|
557
|
+
import { principal } from "@meantjs/schema"
|
|
558
|
+
import { createClient } from "@ic-reactor/core"
|
|
559
|
+
import { ReactorProvider, useAuth, useClient } from "@ic-reactor/react"
|
|
560
|
+
import { skipToken, useMutation, useQuery } from "@tanstack/react-query"
|
|
561
|
+
import { toAuthLike, type SignInSource } from "./auth-like"
|
|
562
|
+
import { actor, type Actor } from "./generated/backend"
|
|
563
|
+
|
|
564
|
+
export function App({ auth }: { auth: SignInSource }) {
|
|
565
|
+
return (
|
|
566
|
+
<ReactorProvider client={() => createClient({ network: "ic", auth: () => toAuthLike(auth) })}>
|
|
567
|
+
<Profile />
|
|
568
|
+
</ReactorProvider>
|
|
569
|
+
)
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function Profile() {
|
|
573
|
+
const client = useClient()
|
|
574
|
+
const { status, principal: caller, signIn } = useAuth()
|
|
575
|
+
const backend = client.canister<Actor>(actor, { id: "rrkah-fqaaa-aaaaa-aaaaq-cai" })
|
|
576
|
+
const me = principal(caller)
|
|
577
|
+
const signedIn = status === "signed-in"
|
|
578
|
+
const profile = useQuery(client.queryOptions(backend, "get_profile", signedIn ? me : skipToken))
|
|
579
|
+
const rename = useMutation(client.mutationOptions(backend, "set_name"))
|
|
580
|
+
|
|
581
|
+
if (!signedIn) return <button onClick={() => signIn().catch(console.error)}>Sign in</button>
|
|
582
|
+
if (profile.data === undefined) return <p>Loading…</p>
|
|
583
|
+
return (
|
|
584
|
+
<>
|
|
585
|
+
<p>{profile.data.name}</p>
|
|
586
|
+
<button disabled={rename.isPending} onClick={() => rename.mutate([me, "Ada"])}>Rename</button>
|
|
587
|
+
{rename.error && <p>{rename.error.mayHaveExecuted ? "Unknown outcome" : rename.error.message}</p>}
|
|
588
|
+
</>
|
|
589
|
+
)
|
|
590
|
+
}
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
## Do not
|
|
594
|
+
|
|
595
|
+
- Cast text to `Principal`: use `principal(text)`.
|
|
596
|
+
- Convert `bigint` values to `number`: use `parseUnits` and `formatUnits`.
|
|
597
|
+
- Add `retry` to a write (`{ ...client.mutationOptions(...), retry: 3 }`
|
|
598
|
+
compiles), or call a write from `useQuery`: TanStack Query may run a query's
|
|
599
|
+
function again whenever it refetches, and every run of an update executes
|
|
600
|
+
again.
|
|
601
|
+
- Write a query key by hand (it leaves the caller out), or carry data across
|
|
602
|
+
keys (`keepPreviousData`, cross-key `initialData`).
|
|
603
|
+
- Build agents yourself, a client per render, or one client for every user of
|
|
604
|
+
a server.
|
|
605
|
+
- Send a write as the anonymous identity: pass `identity: "anonymous"`, never
|
|
606
|
+
an `AnonymousIdentity` you were handed.
|
|
607
|
+
- Treat every failed write as "not executed": read `mayHaveExecuted`.
|
|
608
|
+
- Pay, or ask a person to approve, a value a plain query read: read
|
|
609
|
+
recipients, deposit addresses, allowances and approval details through a
|
|
610
|
+
`certified: true` canister.
|