@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,180 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Deploy to a frontend canister"
|
|
3
|
+
description: "Serve the app from an asset canister with a strict Content-Security-Policy and the other security headers, keep it off raw domains, and know what the HTTP gateway checks"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
A frontend canister serves the app's HTML and JavaScript, and a signed-in
|
|
7
|
+
person's session lives in that page: one injected script, or a framed
|
|
8
|
+
"Approve" button, acts as that person. An asset canister sends no security
|
|
9
|
+
headers unless its configuration asks for them. This page gives a
|
|
10
|
+
configuration that the [wallet example](/v4/examples/vite-wallet/) deploys,
|
|
11
|
+
says what each line does, and what the HTTP gateway checks for you.
|
|
12
|
+
|
|
13
|
+
## The headers
|
|
14
|
+
|
|
15
|
+
For DFINITY's asset canister (`dfx deploy`, or icp-cli's
|
|
16
|
+
`@dfinity/asset-canister` recipe), put `.ic-assets.json5` in Vite's `public/`.
|
|
17
|
+
`vite build` copies it into `dist/`, and the asset canister reads it from the
|
|
18
|
+
directory it is synced from:
|
|
19
|
+
|
|
20
|
+
```json5
|
|
21
|
+
// public/.ic-assets.json5
|
|
22
|
+
[
|
|
23
|
+
{
|
|
24
|
+
match: "**/*",
|
|
25
|
+
// The asset canister's own security headers, with the ones below in
|
|
26
|
+
// place of its Content-Security-Policy.
|
|
27
|
+
security_policy: "hardened",
|
|
28
|
+
headers: {
|
|
29
|
+
"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'",
|
|
30
|
+
"Cross-Origin-Opener-Policy": "same-origin-allow-popups",
|
|
31
|
+
},
|
|
32
|
+
allow_raw_access: false,
|
|
33
|
+
},
|
|
34
|
+
]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
# icp.yaml
|
|
39
|
+
canisters:
|
|
40
|
+
- name: frontend
|
|
41
|
+
recipe:
|
|
42
|
+
type: "@dfinity/asset-canister@v2.3.0"
|
|
43
|
+
configuration:
|
|
44
|
+
version: 0.30.2
|
|
45
|
+
build:
|
|
46
|
+
- pnpm run build
|
|
47
|
+
dir: dist
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`icp deploy frontend` builds the app and uploads `dist/`. On a local network,
|
|
51
|
+
check what the page is served with:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
curl -sI http://frontend.local.localhost:8000/
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Vite's dev server sends none of these headers, and its hot reload needs
|
|
58
|
+
inline scripts that this policy refuses, so check a deployed canister. Open
|
|
59
|
+
it with the browser's console showing: a resource the policy refuses is
|
|
60
|
+
reported there.
|
|
61
|
+
|
|
62
|
+
### What each line does
|
|
63
|
+
|
|
64
|
+
- `security_policy: "hardened"` adds the asset canister's own security
|
|
65
|
+
headers to every file: `Strict-Transport-Security` (HTTPS only, for a
|
|
66
|
+
year), `X-Frame-Options: DENY`, `X-Content-Type-Options: nosniff`,
|
|
67
|
+
`Referrer-Policy: same-origin`, `X-XSS-Protection`, and a
|
|
68
|
+
`Permissions-Policy` that turns off every feature it lists. A header in
|
|
69
|
+
`headers` replaces the policy's header of the same name. `"standard"` adds
|
|
70
|
+
the same set with the canister's own CSP, which lets the page call any
|
|
71
|
+
canister (`connect-src https://*.icp0.io`) and load styles and fonts from
|
|
72
|
+
anywhere, and asset sync warns that it should be tightened.
|
|
73
|
+
- `default-src 'none'` refuses everything the other directives do not allow:
|
|
74
|
+
frames, plugins, workers, media.
|
|
75
|
+
- `script-src 'self'`: ic-reactor, `@meantjs/schema`, `@icp-sdk/core` and
|
|
76
|
+
`@icp-sdk/auth` run no `eval`, `new Function` or WebAssembly in a browser,
|
|
77
|
+
and Vite's production build has no inline script, so the app's own files
|
|
78
|
+
are all the page runs.
|
|
79
|
+
- `connect-src 'self' https://icp-api.io`: where the client's calls go.
|
|
80
|
+
`network: "env"` calls through the page's origin on `<id>.icp0.io` and on a
|
|
81
|
+
local network, and through `https://icp-api.io` on a custom domain;
|
|
82
|
+
`network: "ic"` calls `https://icp-api.io`. Sign-in needs nothing here:
|
|
83
|
+
Internet Identity runs in a window of its own.
|
|
84
|
+
- `img-src 'self' data:`, `style-src 'self'`, `font-src 'self'`: the app's own
|
|
85
|
+
files, and `data:` images. Add a font or style host here if the app uses
|
|
86
|
+
one. A library that inserts `<style>` elements as it runs needs more than
|
|
87
|
+
`'self'`.
|
|
88
|
+
- `frame-ancestors 'none'`, with the policy's `X-Frame-Options: DENY`: no
|
|
89
|
+
other page can frame the app and steer a click.
|
|
90
|
+
- `base-uri 'none'` and `form-action 'none'`: no `<base>` element can
|
|
91
|
+
redirect the app's relative URLs, and no form submits anywhere. Forms
|
|
92
|
+
handled in JavaScript, with `preventDefault()`, are not affected.
|
|
93
|
+
- `Cross-Origin-Opener-Policy: same-origin-allow-popups` keeps windows the
|
|
94
|
+
page did not open from reaching it, while the Internet Identity window it
|
|
95
|
+
opens can still answer it. `same-origin` cuts that window off too: it has
|
|
96
|
+
no `window.opener`, so its answer never reaches the page, and the sign-in
|
|
97
|
+
cannot complete.
|
|
98
|
+
- `allow_raw_access: false` answers a request for `<id>.raw.icp0.io` with a
|
|
99
|
+
redirect (308) to the same path on `https://<id>.icp0.io`. See
|
|
100
|
+
[What the gateway checks](#what-the-gateway-checks).
|
|
101
|
+
|
|
102
|
+
An app with redirect sign-in serves `/.well-known/ii-auth-callbacks` from the
|
|
103
|
+
same canister: add the entries of
|
|
104
|
+
[Redirect sign-in](/v4/guides/auth/#redirect-sign-in) to the same array.
|
|
105
|
+
|
|
106
|
+
### A copy button
|
|
107
|
+
|
|
108
|
+
The asset canister's `Permissions-Policy` turns `clipboard-write` off, so
|
|
109
|
+
`navigator.clipboard.writeText` rejects with `NotAllowedError` on the
|
|
110
|
+
deployed page, though it works under the dev server. An app that copies an
|
|
111
|
+
address or a principal gives a `Permissions-Policy` of its own in `headers`,
|
|
112
|
+
which replaces the whole list:
|
|
113
|
+
|
|
114
|
+
```json5
|
|
115
|
+
"Permissions-Policy": "camera=(), microphone=(), geolocation=(), payment=(), usb=(), serial=(), hid=(), midi=(), display-capture=(), clipboard-read=(), clipboard-write=(self)",
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Chrome warns once in the console for each feature of the asset canister's
|
|
119
|
+
own list that it does not know. The warnings are harmless.
|
|
120
|
+
|
|
121
|
+
## The static-site recipe
|
|
122
|
+
|
|
123
|
+
icp-cli's `@dfinity/static-site` recipe deploys a different canister,
|
|
124
|
+
`dfinity/certified-assets`. It adds no security headers of its own, and reads
|
|
125
|
+
a `_headers` file in the synced directory (in a Vite app, `public/`) in place
|
|
126
|
+
of `.ic-assets.json5`. The same headers, without `X-XSS-Protection` and with
|
|
127
|
+
a shorter `Permissions-Policy`:
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
/*
|
|
131
|
+
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'
|
|
132
|
+
Cross-Origin-Opener-Policy: same-origin-allow-popups
|
|
133
|
+
Strict-Transport-Security: max-age=31536000; includeSubDomains
|
|
134
|
+
X-Frame-Options: DENY
|
|
135
|
+
X-Content-Type-Options: nosniff
|
|
136
|
+
Referrer-Policy: same-origin
|
|
137
|
+
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), serial=(), hid=(), midi=(), display-capture=(), clipboard-read=(), clipboard-write=()
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
# icp.yaml
|
|
142
|
+
canisters:
|
|
143
|
+
- name: frontend
|
|
144
|
+
recipe:
|
|
145
|
+
type: "@dfinity/static-site@v0.4.2"
|
|
146
|
+
configuration:
|
|
147
|
+
build:
|
|
148
|
+
- pnpm run build
|
|
149
|
+
dir: dist
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
It has no `allow_raw_access`: it serves its `raw` host as it serves the
|
|
153
|
+
other.
|
|
154
|
+
|
|
155
|
+
## What the gateway checks
|
|
156
|
+
|
|
157
|
+
A browser does not check a canister's answer itself. On `<id>.icp0.io` the
|
|
158
|
+
HTTP gateway does: it passes a response on only if it matches the
|
|
159
|
+
canister's certified state, and both asset canisters certify each file with
|
|
160
|
+
the headers above. So no node can change the app's code, or loosen its
|
|
161
|
+
policy, on the way. Trusting the app's code is trusting that gateway. The
|
|
162
|
+
client's own checks, the signatures on query replies and the certificates of
|
|
163
|
+
[certified reads](/v4/guides/reads/), cover the calls the code makes, not the
|
|
164
|
+
code.
|
|
165
|
+
|
|
166
|
+
On `<id>.raw.icp0.io` the gateway checks nothing: whichever node answers can
|
|
167
|
+
serve any page. Never link to a raw URL. `allow_raw_access: false` sends
|
|
168
|
+
whoever follows one to the checked domain, but a node that lies there can
|
|
169
|
+
answer in its place, so the redirect protects visitors from honest mistakes,
|
|
170
|
+
not from that node.
|
|
171
|
+
|
|
172
|
+
Internet Identity gives each origin its own principals, so a page on the
|
|
173
|
+
raw domain gets other principals for the same people, which hold none of
|
|
174
|
+
their assets.
|
|
175
|
+
Do not list a raw origin among the app's alternative origins
|
|
176
|
+
(`/.well-known/ii-alternative-origins`): that would give a page nobody checks
|
|
177
|
+
the principals of the real app.
|
|
178
|
+
|
|
179
|
+
For the canister ids a mainnet build calls, see
|
|
180
|
+
[Deploy to mainnet](/v4/guides/client/#deploy-to-mainnet).
|
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Errors and mayHaveExecuted"
|
|
3
|
+
description: "ReactorError: its kinds and codes, which failures may have executed, and what to do for each"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Every call the client makes rejects with a `ReactorError`, whether it is a
|
|
7
|
+
direct call, a query function, a mutation function or a `client.func` call. It
|
|
8
|
+
carries two things you need most: a `kind` that says what went wrong, and
|
|
9
|
+
`mayHaveExecuted`, which says whether a write may have taken effect anyway.
|
|
10
|
+
|
|
11
|
+
## Testing for a ReactorError
|
|
12
|
+
|
|
13
|
+
`ReactorError` is a type. There is no class, so `instanceof` does not work.
|
|
14
|
+
Test with `isReactorError`, which also recognises an error made by another copy
|
|
15
|
+
of the package:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { isReactorError } from "@ic-reactor/core"
|
|
19
|
+
import { ledger } from "./ledger"
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
await ledger.icrc1_fee()
|
|
23
|
+
} catch (error) {
|
|
24
|
+
if (!isReactorError(error)) throw error // not ours: a bug, not a failed call
|
|
25
|
+
console.error(error.kind, error.mayHaveExecuted, error.message)
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`isReactorError` narrows to `ReactorError<unknown>`. `ReactorError<E>` is the
|
|
30
|
+
same error with a typed `err`. For a method whose result is
|
|
31
|
+
`variant { Ok : T; Err : E }`, the `error` of a query or mutation is
|
|
32
|
+
`ReactorError<E>`, and `err` is typed `E` exactly when `kind` is
|
|
33
|
+
`"canister_err"`.
|
|
34
|
+
|
|
35
|
+
For a direct call, name the canister and the method the error came from:
|
|
36
|
+
`isReactorError(error, canister, method)` narrows to that method's
|
|
37
|
+
`ReactorError<E>`, so `err` is typed after the `kind` check, with no cast. For
|
|
38
|
+
a method without an `Err` arm, `err` stays `undefined`.
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { isReactorError } from "@ic-reactor/core"
|
|
42
|
+
import type { Account } from "./generated/icrc1"
|
|
43
|
+
import { ledger } from "./ledger"
|
|
44
|
+
|
|
45
|
+
/** Sends a transfer, and says what happened. */
|
|
46
|
+
export async function pay(to: Account, amount: bigint): Promise<string> {
|
|
47
|
+
const arg = {
|
|
48
|
+
to,
|
|
49
|
+
amount,
|
|
50
|
+
fee: null,
|
|
51
|
+
memo: null,
|
|
52
|
+
from_subaccount: null,
|
|
53
|
+
created_at_time: null,
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
return `Sent in block ${await ledger.icrc1_transfer(arg)}.`
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (!isReactorError(error, ledger, "icrc1_transfer")) throw error
|
|
59
|
+
if (
|
|
60
|
+
error.kind === "canister_err" &&
|
|
61
|
+
error.err.tag === "InsufficientFunds"
|
|
62
|
+
) {
|
|
63
|
+
return `The balance is ${error.err.value.balance}.` // error.err is a TransferError
|
|
64
|
+
}
|
|
65
|
+
return error.message
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The check is made when the code runs, not only by the compiler: the guard is
|
|
71
|
+
`true` only for an error that a call of that method on that canister object
|
|
72
|
+
rejected with, whether the call was direct, a query function or a mutation
|
|
73
|
+
function built from it. An error of another method, of another canister
|
|
74
|
+
object, or of a `client.func` call is `false`, even when it is a
|
|
75
|
+
`ReactorError`, so the guard never types one call's error as another's. The
|
|
76
|
+
canister made with `certified: true` is another object, and so is the same
|
|
77
|
+
canister made by another client. `client.canister()` returns the same object
|
|
78
|
+
for the same module and target, so a canister made again where the error is
|
|
79
|
+
caught is the one the call was made on. A `false` result says only that the
|
|
80
|
+
error is not that call's: it can still be of any `kind`.
|
|
81
|
+
|
|
82
|
+
## The fields
|
|
83
|
+
|
|
84
|
+
| Field | Meaning |
|
|
85
|
+
| ----------------- | ----------------------------------------------------------------------------------------------------- |
|
|
86
|
+
| `kind` | what went wrong: one of the eight kinds below |
|
|
87
|
+
| `mayHaveExecuted` | whether the call may have taken effect although you cannot tell what it did |
|
|
88
|
+
| `method` | the Candid method called |
|
|
89
|
+
| `canisterId` | the target canister, as text |
|
|
90
|
+
| `code` | a machine-readable sub-reason inside a kind, when there is one (see [Codes](#codes)) |
|
|
91
|
+
| `rejectCode` | the IC reject code (1 to 6), when the call was rejected |
|
|
92
|
+
| `httpStatus` | the HTTP status the replica or a boundary node answered with, when there was one |
|
|
93
|
+
| `issues` | which parts of the arguments or the reply failed to encode or decode: `{ code, path, message }` each |
|
|
94
|
+
| `err` | the typed `Err` payload, only when `kind` is `canister_err` |
|
|
95
|
+
| `cause` | the error that caused this one, when there is one (for example the agent's error) |
|
|
96
|
+
| `expiresAt` | for a write that got no answer: the latest ingress expiry of its sends, nanoseconds on the IC's clock |
|
|
97
|
+
| `message` | one line: `[ic-reactor] <method> on <canisterId>: <reason>` |
|
|
98
|
+
|
|
99
|
+
## The eight kinds
|
|
100
|
+
|
|
101
|
+
| `kind` | Meaning |
|
|
102
|
+
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
103
|
+
| `invalid_args` | the arguments could not be encoded, or the target canister id could not be resolved. Nothing was sent |
|
|
104
|
+
| `unauthenticated` | an update was attempted while nobody is signed in. Nothing was sent |
|
|
105
|
+
| `not_delivered` | nothing that matters ran: the request was refused or never taken in, or it was a query that got no answer |
|
|
106
|
+
| `outcome_unknown` | an update went out and no trustworthy answer came back, so the canister may or may not have run it; or a re-send `client.resendOf()` offered did not run, and the write it re-sends may have (its `code`, `httpStatus` or `rejectCode`, and its `cause`, say why the re-send did not run) |
|
|
107
|
+
| `rejected` | the IC or the canister rejected the call; `rejectCode` says which |
|
|
108
|
+
| `invalid_reply` | a reply arrived but did not decode as the method's result |
|
|
109
|
+
| `canister_err` | the canister ran the call and answered with the `Err` arm of its result; `err` is typed |
|
|
110
|
+
| `cancelled` | the caller abandoned the call: an aborted call, a read whose caller is no longer current, a call on a disposed client, or a read or unsent write whose `timeoutMs` passed (`timeout`) |
|
|
111
|
+
|
|
112
|
+
## `mayHaveExecuted`
|
|
113
|
+
|
|
114
|
+
- **`true` is a warning, not a verdict.** The IC or the network left the
|
|
115
|
+
outcome open: the canister may have changed state, and you cannot tell.
|
|
116
|
+
Sending the write again could run it twice. Read the state back before you
|
|
117
|
+
try again.
|
|
118
|
+
- **`false` means the outcome is known.** The call was refused before it ran,
|
|
119
|
+
or the canister ran it and answered `Err`. It does not mean "nothing
|
|
120
|
+
changed" for `canister_err`: a canister may change state before it returns
|
|
121
|
+
an `Err`. It means the answer is the decision, and sending again is a new
|
|
122
|
+
decision, not a retry.
|
|
123
|
+
|
|
124
|
+
A query changes nothing, so a failed read never "may have executed".
|
|
125
|
+
|
|
126
|
+
### The classification
|
|
127
|
+
|
|
128
|
+
The client turns every failure of an agent into a kind with one table, for
|
|
129
|
+
an update and for a query:
|
|
130
|
+
|
|
131
|
+
| Failure | Update: kind | Update: `mayHaveExecuted` | Query: kind |
|
|
132
|
+
| ----------------------------------------------------------------------------------------------------------------- | --------------------------- | ------------------------- | --------------------------- |
|
|
133
|
+
| the call was aborted (an `AbortError`, or its signal aborted) | `cancelled` | true | `cancelled` |
|
|
134
|
+
| reject code 1 or 3 | `rejected` | false | `rejected` |
|
|
135
|
+
| reject code 2 | `not_delivered` (retryable) | false | `not_delivered` (retryable) |
|
|
136
|
+
| reject code 1, 2 or 3 from the management canister (`aaaaa-aa`) | `rejected` | true | `rejected` |
|
|
137
|
+
| reject code 4 or 5 | `rejected` | true | `rejected` |
|
|
138
|
+
| reject code 6, an unknown code, HTTP 408 or 5xx, a network failure, a polling timeout, a failed certificate check | `outcome_unknown` | true | `not_delivered` (retryable) |
|
|
139
|
+
| HTTP 429 | `not_delivered` (retryable) | false | `not_delivered` (retryable) |
|
|
140
|
+
| any other HTTP 4xx, `IngressExpiryInvalid` | `not_delivered` | false | `not_delivered` |
|
|
141
|
+
| a request that could not be built or signed | `not_delivered` | false | `not_delivered` |
|
|
142
|
+
| the signer did not sign it (a declined prompt; the `cause` is the signer's error) | `not_delivered` | false | `not_delivered` |
|
|
143
|
+
|
|
144
|
+
A query's `mayHaveExecuted` is `false` in every row.
|
|
145
|
+
|
|
146
|
+
Three rules sit behind the table.
|
|
147
|
+
|
|
148
|
+
- **Once the request may be in the IC, the HTTP rows change.** The HTTP rows,
|
|
149
|
+
`IngressExpiryInvalid`, the "could not be built" row and the signer's row
|
|
150
|
+
hold for an update only before the request may have been accepted. After the replica answered
|
|
151
|
+
202 (the client is polling for the reply), a later refusal says nothing
|
|
152
|
+
about the call, so all of those rows read `outcome_unknown` with
|
|
153
|
+
`mayHaveExecuted: true`. This is why a 429 on the first send is safe to send
|
|
154
|
+
again, and a 429 on a later poll is not.
|
|
155
|
+
- **The management canister is the exception for reject codes 1 to 3.** For
|
|
156
|
+
every other canister, codes 1 to 3 prove no canister code ran. For
|
|
157
|
+
`aaaaa-aa` they prove nothing, so an update there may have executed.
|
|
158
|
+
- **A re-send `client.resendOf()` offered keeps its write's unknown outcome.**
|
|
159
|
+
A failure that proves only that the re-send did not run (a row with `false`
|
|
160
|
+
above, or a refusal before it is sent) says nothing about the earlier
|
|
161
|
+
attempt, so it reads `outcome_unknown` with `mayHaveExecuted: true`. See
|
|
162
|
+
[A re-send that did not run](#what-to-do-for-each-kind) below.
|
|
163
|
+
|
|
164
|
+
### How long a call waits
|
|
165
|
+
|
|
166
|
+
Unless the call has a `timeoutMs` (below), neither the client nor the agent
|
|
167
|
+
puts a timeout on an HTTP request. A request that gets no HTTP answer, from a proxy that holds it say, waits as long as the
|
|
168
|
+
`fetch` in use waits. That holds for the call or query request, for each
|
|
169
|
+
`read_state` request that polls for an accepted call's answer, and for the
|
|
170
|
+
`read_state` of `client.time()`.
|
|
171
|
+
|
|
172
|
+
An update (or a certified read) the replica accepted with a 202 is polled for
|
|
173
|
+
with `read_state` for about five minutes in all, then an update rejects
|
|
174
|
+
`outcome_unknown`. That deadline is checked only when a poll is answered: a
|
|
175
|
+
`read_state` request that gets no answer is not cut short by it.
|
|
176
|
+
|
|
177
|
+
A read made with `client.queryOptions()` stops waiting at any of these points
|
|
178
|
+
as soon as TanStack Query cancels it (`queryClient.cancelQueries(...)`, or its
|
|
179
|
+
last observer unmounts), and rejects `cancelled`. Its `mayHaveExecuted` is
|
|
180
|
+
`false`, except for an update read with `{ update: "idempotent" }` whose call
|
|
181
|
+
request had gone out: that one may have run. The request itself is not torn
|
|
182
|
+
down; nobody waits for its answer.
|
|
183
|
+
|
|
184
|
+
To stop waiting sooner, give a call a bound with `timeoutMs`, in milliseconds
|
|
185
|
+
(1 to 2147483647):
|
|
186
|
+
|
|
187
|
+
- on the canister target, `client.canister(actor, { id, timeoutMs })`, it
|
|
188
|
+
bounds every call made through that canister object: its direct calls, its
|
|
189
|
+
reads made with `queryOptions`, its mutations, and `client.time()` on it;
|
|
190
|
+
- in the third argument of `client.mutationOptions()`,
|
|
191
|
+
`{ invalidates, timeoutMs }`, it bounds that mutation's runs in place of the
|
|
192
|
+
canister's.
|
|
193
|
+
|
|
194
|
+
The bound counts from the moment the call is made, the wait for the caller's
|
|
195
|
+
identity included. When it passes, the call stops waiting at whatever point it
|
|
196
|
+
is, and rejects with `code: "timeout"`:
|
|
197
|
+
|
|
198
|
+
| When the bound passed | `kind` | `mayHaveExecuted` |
|
|
199
|
+
| ---------------------------------------------------------------------- | ----------------- | ----------------- |
|
|
200
|
+
| a read, at any point (an `{ update: "idempotent" }` read: as a write) | `cancelled` | `false` |
|
|
201
|
+
| a write before its request went out (or while it waited to be re-sent) | `cancelled` | `false` |
|
|
202
|
+
| a re-send of a write `client.resendOf()` offered, at any point | `outcome_unknown` | `true` |
|
|
203
|
+
| a write whose request went out, while it waits for the answer or polls | `outcome_unknown` | `true` |
|
|
204
|
+
|
|
205
|
+
A write that timed out after its request went out may still execute, or may
|
|
206
|
+
have executed already. Treat it as any other unknown outcome: read the state
|
|
207
|
+
back, or offer the same write again with `client.resendOf()` when the method
|
|
208
|
+
deduplicates it. Never send it again blindly: that can run the write twice.
|
|
209
|
+
The client sends nothing again for a timeout, and, as with an abort, the
|
|
210
|
+
request itself is not torn down. An update read with `{ update: "idempotent" }`
|
|
211
|
+
counts as a write here.
|
|
212
|
+
|
|
213
|
+
`client.resendOf()` and `isReactorError(error, canister, method)` need the
|
|
214
|
+
canister object the call was made on, and a target with another `timeoutMs`
|
|
215
|
+
is another canister object: pass the one the write went through.
|
|
216
|
+
|
|
217
|
+
Canister objects that differ only in `timeoutMs` share query keys, so their
|
|
218
|
+
reads share one cache entry. When two observers read the same key through
|
|
219
|
+
canisters with different bounds, a fetch is bounded by the options TanStack
|
|
220
|
+
Query was given last.
|
|
221
|
+
|
|
222
|
+
The errors the client makes itself, without an agent error to classify, are
|
|
223
|
+
simpler:
|
|
224
|
+
|
|
225
|
+
- `invalid_args`, `unauthenticated` and `canister_err` always say `false`.
|
|
226
|
+
- `cancelled` says `false` when nothing was sent. An update aborted in flight
|
|
227
|
+
says `true`, as the first row of the table.
|
|
228
|
+
- `invalid_reply` says `true` for an update, because the canister ran it and
|
|
229
|
+
only the answer is unreadable, and `false` for a query.
|
|
230
|
+
|
|
231
|
+
### Codes
|
|
232
|
+
|
|
233
|
+
`code` narrows a kind. The client sets exactly these eleven. Only
|
|
234
|
+
`canister_not_found` comes from the IC's answer; the client decides the others
|
|
235
|
+
itself:
|
|
236
|
+
|
|
237
|
+
| `code` | `kind` | When |
|
|
238
|
+
| ------------------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
239
|
+
| `canister_id_unresolved` | `invalid_args` | a `{ name }` target the `ic_env` cookie cannot give: on a server, an untrusted host, or no such entry |
|
|
240
|
+
| `no_certified_path` | `invalid_args` | a `composite_query` called on a `certified: true` canister |
|
|
241
|
+
| `effective_canister_id_unknown` | `invalid_args` | a management canister call that cannot be routed from its arguments |
|
|
242
|
+
| `arg_changed` | `outcome_unknown` | a mutation given an argument `client.resendOf()` offered, which was changed after the write it re-sends went out. Nothing was sent, and that write may have run |
|
|
243
|
+
| `anonymous_write` | `unauthenticated` | an update or oneway method by a caller who is not signed in |
|
|
244
|
+
| `identity_unavailable` | `unauthenticated` | the auth's `getIdentity()` rejected |
|
|
245
|
+
| `caller_changed` | `cancelled` or `outcome_unknown` | the call was made for a principal that is no longer current. Nothing was sent: `outcome_unknown` for a re-send `client.resendOf()` offered, whose write may have run, `cancelled` otherwise |
|
|
246
|
+
| `target_changed` | `outcome_unknown` | a mutation given an argument `client.resendOf()` offered would send it to another method or canister than the write it re-sends: a `{ name }` the `ic_env` cookie maps elsewhere since. Nothing was sent, and that write may have run |
|
|
247
|
+
| `client_disposed` | `cancelled` or `outcome_unknown` | a call on a disposed client: `outcome_unknown` for a re-send `client.resendOf()` offered, `cancelled` otherwise |
|
|
248
|
+
| `timeout` | `cancelled` or `outcome_unknown` | the call's `timeoutMs` passed: `outcome_unknown` for a write whose request went out or a re-send `client.resendOf()` offered, `cancelled` otherwise (see How long a call waits) |
|
|
249
|
+
| `canister_not_found` | `not_delivered`, `rejected` or `outcome_unknown` | the IC answered that the canister does not exist: a boundary node's HTTP 400 `canister_not_found` (an id outside every subnet's range), or a replica's reject 3 with IC error code `IC0301` (an id inside a range that holds no canister). A write the IC may already hold keeps the code under `outcome_unknown` |
|
|
250
|
+
|
|
251
|
+
An aborted call is `cancelled` with no code. On a re-send `client.resendOf()`
|
|
252
|
+
offered, a code that says nothing was sent (any of these but
|
|
253
|
+
`canister_not_found`) comes with kind `outcome_unknown`, as the rows above
|
|
254
|
+
say for the codes a re-send meets most.
|
|
255
|
+
|
|
256
|
+
## What to do for each kind
|
|
257
|
+
|
|
258
|
+
| `kind` | What to do |
|
|
259
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
260
|
+
| `invalid_args` | Fix the input or the target. Read `issues` for the field and the reason. Nothing was sent. |
|
|
261
|
+
| `unauthenticated` | Ask the user to sign in, then send again. `anonymous_write` means nobody is signed in. `identity_unavailable` means the auth could not hand over an identity. |
|
|
262
|
+
| `not_delivered` | It is safe to try again. The client already retried a read, and sent an update again where that was proven safe, so this is the end of what it will do alone. |
|
|
263
|
+
| `outcome_unknown` | Say the outcome is unknown. Read the state back before anything else. Never send again blindly. A re-send `client.resendOf()` offered that did not run says why in its `code`, `httpStatus` or `rejectCode`, and its `cause`: the write it re-sends is still offered while its sender is the caller. |
|
|
264
|
+
| `rejected` | Read `rejectCode`. Code 4 is a reject the canister chose, and code 5 is a trap. If `mayHaveExecuted` is `true`, read the state back before sending again. |
|
|
265
|
+
| `invalid_reply` | The generated module and the canister disagree about the method's result: regenerate the module from the canister's current `.did`. For an update, it did run. |
|
|
266
|
+
| `canister_err` | Show or act on the typed `err`. The canister's answer is final. Sending again is a new decision. A mutation has already refreshed its reads. |
|
|
267
|
+
| `cancelled` | Usually ignore it: the caller moved on. A `caller_changed` read lands nowhere, and the component reads the new caller's key. A `caller_changed` write (held back offline or by its `scope` across an account switch) was never sent: say so, since what was asked did not happen. Ignore it in a global error handler as well, except code `timeout`: that is a real timeout the user waited for, so show it. |
|
|
268
|
+
|
|
269
|
+
**A re-send that did not run is not the end of the write.** A re-send of a
|
|
270
|
+
write `client.resendOf()` offered can be refused before it goes out (codes
|
|
271
|
+
`caller_changed`, `target_changed`, `arg_changed`, `client_disposed`,
|
|
272
|
+
`identity_unavailable`, `canister_id_unresolved`, an argument that no longer
|
|
273
|
+
encodes, or a `timeout` while it waits for the caller's identity or to be
|
|
274
|
+
sent again after a 429), or turned away when it is sent (an HTTP 4xx such as
|
|
275
|
+
429, or reject code 1 to 3). Each proves only that the re-send did not run.
|
|
276
|
+
The earlier attempt may have run all the same, so the re-send rejects
|
|
277
|
+
`outcome_unknown` with `mayHaveExecuted: true`: its `code`, `httpStatus`,
|
|
278
|
+
`rejectCode` or `issues` say why the re-send did not run, its `cause` is the
|
|
279
|
+
re-send's own error, and its `expiresAt` is the latest of the write's sends.
|
|
280
|
+
Its `message` says only that the re-send did not run. The write stays kept,
|
|
281
|
+
so `client.resendOf()` of this error offers it again while its sender is the
|
|
282
|
+
caller and its argument and canister are what they were, and the mutation's
|
|
283
|
+
error keeps leading back to it. Read the state back before
|
|
284
|
+
anything else, as for any `outcome_unknown`. A re-send the signer does not
|
|
285
|
+
sign, such as a declined prompt, rejects the same way, with the signer's own
|
|
286
|
+
error as its `cause`. The same failures of a first send mean what the table
|
|
287
|
+
above says: nothing ran.
|
|
288
|
+
|
|
289
|
+
For every `mayHaveExecuted: true` failure of a write, a mutation has already
|
|
290
|
+
invalidated the canister's reads, so the page shows what the canister holds
|
|
291
|
+
when the re-read lands. See [Writes](/v4/guides/writes/).
|
|
292
|
+
|
|
293
|
+
### In React
|
|
294
|
+
|
|
295
|
+
A query's or mutation's `error` is `ReactorError<E> | null`. A function over
|
|
296
|
+
the kinds is a good place for the wording. The `never` check makes TypeScript
|
|
297
|
+
tell you when a kind is added:
|
|
298
|
+
|
|
299
|
+
```tsx
|
|
300
|
+
import type { ReactorError } from "@ic-reactor/core"
|
|
301
|
+
|
|
302
|
+
export function describe(error: ReactorError<unknown>): string {
|
|
303
|
+
switch (error.kind) {
|
|
304
|
+
case "invalid_args":
|
|
305
|
+
return error.issues?.[0]?.message ?? "The input is not valid."
|
|
306
|
+
case "unauthenticated":
|
|
307
|
+
return "Sign in first."
|
|
308
|
+
case "not_delivered":
|
|
309
|
+
return "The request did not get through. Try again."
|
|
310
|
+
case "outcome_unknown":
|
|
311
|
+
return "The outcome is unknown. It may have gone through: check before sending again."
|
|
312
|
+
case "rejected":
|
|
313
|
+
return error.mayHaveExecuted
|
|
314
|
+
? `Rejected (code ${error.rejectCode}). It may have run: check before sending again.`
|
|
315
|
+
: `Rejected (code ${error.rejectCode}).`
|
|
316
|
+
case "invalid_reply":
|
|
317
|
+
return "The canister's answer did not match its interface."
|
|
318
|
+
case "canister_err":
|
|
319
|
+
return "The canister refused."
|
|
320
|
+
case "cancelled":
|
|
321
|
+
return "Cancelled."
|
|
322
|
+
default: {
|
|
323
|
+
const unhandled: never = error
|
|
324
|
+
return String(unhandled)
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
A canister's own `Err` is typed. For the ICRC-1 ledger's `icrc1_transfer`, a
|
|
331
|
+
mutation's `error` narrows like this:
|
|
332
|
+
|
|
333
|
+
```tsx
|
|
334
|
+
import { useClient } from "@ic-reactor/react"
|
|
335
|
+
import { useMutation } from "@tanstack/react-query"
|
|
336
|
+
import { actor, type Actor } from "./generated/icrc1"
|
|
337
|
+
|
|
338
|
+
export function TransferStatus() {
|
|
339
|
+
const client = useClient()
|
|
340
|
+
const ledger = client.canister<Actor>(actor, {
|
|
341
|
+
id: "ryjl3-tyaaa-aaaaa-aaaba-cai",
|
|
342
|
+
})
|
|
343
|
+
const transfer = useMutation(client.mutationOptions(ledger, "icrc1_transfer"))
|
|
344
|
+
const error = transfer.error // ReactorError<TransferError> | null
|
|
345
|
+
if (error?.kind === "canister_err" && error.err.tag === "InsufficientFunds") {
|
|
346
|
+
return <p>The balance is {error.err.value.balance.toString()}.</p>
|
|
347
|
+
}
|
|
348
|
+
return error ? <p>{error.message}</p> : null
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Recipes
|
|
353
|
+
|
|
354
|
+
### A write with an unknown outcome
|
|
355
|
+
|
|
356
|
+
After `mayHaveExecuted: true`, do not send the same write again until you know
|
|
357
|
+
what happened. Two ways to know:
|
|
358
|
+
|
|
359
|
+
- **Read the state back.** Read the balance, the profile or the list the write
|
|
360
|
+
changed, and decide from what you find. In React, the mutation has already
|
|
361
|
+
invalidated the canister's reads, so the page shows it. A read-back that
|
|
362
|
+
finds nothing is final only once no send of the write can still start: for
|
|
363
|
+
`outcome_unknown` (and `cancelled` with `mayHaveExecuted: true`),
|
|
364
|
+
`error.expiresAt` is the latest ingress expiry its sends were signed with,
|
|
365
|
+
in nanoseconds on the IC's clock, about five minutes after the send (a
|
|
366
|
+
`client.resendOf()` re-send that did not run carries the latest of the
|
|
367
|
+
write's sends). Past
|
|
368
|
+
it, the IC starts no send of the write: the
|
|
369
|
+
[IC interface specification](https://docs.internetcomputer.org/references/ic-interface-spec/https-interface/)
|
|
370
|
+
says the IC neither accepts a call nor moves one from `received` to
|
|
371
|
+
`processing` once its `ingress_expiry` is past. The expiry does not stop a
|
|
372
|
+
send that started before it, so a method that awaits another canister can
|
|
373
|
+
still commit after that, and this makes a read-back final only for a
|
|
374
|
+
method that commits without awaiting (an ICRC-1 transfer does), and only
|
|
375
|
+
from a certified read of state newer than the expiry. Compare with a
|
|
376
|
+
margin, since the host's clock may differ from the IC's. `expiresAt` is not enumerable, so
|
|
377
|
+
`JSON.stringify(error)` leaves it out.
|
|
378
|
+
- **Let the canister deduplicate.** If the method can tell a repeat from a new
|
|
379
|
+
call, send the same argument again. The ICRC-1 ledger does: a second
|
|
380
|
+
transfer from the same account identical to the first, `created_at_time`
|
|
381
|
+
and `memo` included, is answered `Duplicate`, which means the first one
|
|
382
|
+
went through. Give each transfer its own `memo`, or two different
|
|
383
|
+
transfers of the same amount stamped with the same time look like one (the
|
|
384
|
+
IC's time, which `client.time()` reads, moves about once a second),
|
|
385
|
+
and the second is reported as done when it never ran. It is the ledger's
|
|
386
|
+
feature: `client.resendOf()` offers the re-send only for a key you say the
|
|
387
|
+
canister deduplicates on, and only to the account that sent it (see
|
|
388
|
+
[Writes](/v4/guides/writes/#sending-the-same-write-again)).
|
|
389
|
+
|
|
390
|
+
```ts
|
|
391
|
+
import { isReactorError } from "@ic-reactor/core"
|
|
392
|
+
import type { Account } from "./generated/icrc1"
|
|
393
|
+
import { client, ledger } from "./ledger"
|
|
394
|
+
|
|
395
|
+
/** Sends a transfer, and after an unknown outcome sends the same argument once more. */
|
|
396
|
+
export async function transferOnce(to: Account, amount: bigint) {
|
|
397
|
+
const arg = {
|
|
398
|
+
to,
|
|
399
|
+
amount,
|
|
400
|
+
fee: null,
|
|
401
|
+
// This transfer's own: only a repeat of this argument is a duplicate.
|
|
402
|
+
memo: crypto.getRandomValues(new Uint8Array(16)),
|
|
403
|
+
from_subaccount: null,
|
|
404
|
+
// The IC's clock, in nanoseconds, which the ledger checks the stamp
|
|
405
|
+
// against; it makes a repeat detectable.
|
|
406
|
+
created_at_time: await client.time(ledger),
|
|
407
|
+
}
|
|
408
|
+
try {
|
|
409
|
+
return await ledger.icrc1_transfer(arg)
|
|
410
|
+
} catch (error) {
|
|
411
|
+
// Offered only after an unknown outcome, while its sender is the caller.
|
|
412
|
+
const again = client.resendOf(error, ledger, "icrc1_transfer", {
|
|
413
|
+
dedupedBy: (sent) => sent.created_at_time,
|
|
414
|
+
})
|
|
415
|
+
if (again === undefined) throw error
|
|
416
|
+
try {
|
|
417
|
+
return await again.send() // the identical argument, as the same sender
|
|
418
|
+
} catch (second) {
|
|
419
|
+
if (
|
|
420
|
+
isReactorError(second, ledger, "icrc1_transfer") &&
|
|
421
|
+
second.kind === "canister_err" &&
|
|
422
|
+
second.err.tag === "Duplicate"
|
|
423
|
+
) {
|
|
424
|
+
return second.err.value.duplicate_of // the first one went through
|
|
425
|
+
}
|
|
426
|
+
throw second
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Mapping kinds to exit codes or HTTP statuses
|
|
433
|
+
|
|
434
|
+
A command-line tool or a route handler turns a kind into an exit code or an
|
|
435
|
+
HTTP status. Type the table with `satisfies Record<ReactorErrorKind, number>`:
|
|
436
|
+
a kind added later then fails the type check.
|
|
437
|
+
|
|
438
|
+
```ts
|
|
439
|
+
import { isReactorError, type ReactorErrorKind } from "@ic-reactor/core"
|
|
440
|
+
|
|
441
|
+
const STATUS = {
|
|
442
|
+
invalid_args: 400,
|
|
443
|
+
unauthenticated: 401,
|
|
444
|
+
rejected: 502,
|
|
445
|
+
invalid_reply: 502,
|
|
446
|
+
canister_err: 502,
|
|
447
|
+
outcome_unknown: 504,
|
|
448
|
+
not_delivered: 503,
|
|
449
|
+
cancelled: 503,
|
|
450
|
+
} as const satisfies Record<ReactorErrorKind, number>
|
|
451
|
+
|
|
452
|
+
export function statusOf(error: unknown): number {
|
|
453
|
+
return isReactorError(error) ? STATUS[error.kind] : 500
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
Two examples do this in full. The
|
|
458
|
+
[Node agent tool](/v4/examples/node-agent-tool/) gives each kind an exit code
|
|
459
|
+
and a sentence of advice. The [Next.js SSR example](/v4/examples/next-ssr/)
|
|
460
|
+
has a route handler that maps `kind` to an HTTP status and uses `httpStatus` to
|
|
461
|
+
tell a refusal that passes (429, 408, 5xx) from one that stands (any other
|
|
462
|
+
4xx).
|
|
463
|
+
|
|
464
|
+
### Cancelled reads in a global handler
|
|
465
|
+
|
|
466
|
+
A read built by one caller can be cancelled when another becomes current. If
|
|
467
|
+
you log errors in one place, such as a listener on
|
|
468
|
+
`client.queryClient.getQueryCache()`, skip the `cancelled` kind there, except
|
|
469
|
+
one with code `timeout`: that read timed out after `timeoutMs`, and is worth
|
|
470
|
+
showing. A
|
|
471
|
+
component that reads with `useQuery` never shows it: it renders again under
|
|
472
|
+
the new caller's key. The
|
|
473
|
+
[SSR page](/v4/guides/ssr/#a-read-the-hydrating-render-built-may-be-cancelled-once)
|
|
474
|
+
shows the listener, and the one case where a read the hydrating render built
|
|
475
|
+
is cancelled once.
|