@ic-reactor/mcp 0.0.0-stage → 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1041) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.yml +108 -0
  2. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.yml +77 -0
  4. package/.github/actions/setup-rust-wasm/action.yml +25 -0
  5. package/.github/dependabot.yml +107 -0
  6. package/.github/workflows/auth-latest.yml +67 -0
  7. package/.github/workflows/b3pay-site.yml +49 -0
  8. package/.github/workflows/ci.yml +430 -0
  9. package/.github/workflows/codeql.yml +41 -0
  10. package/.github/workflows/dependency-review.yml +68 -0
  11. package/.github/workflows/docs-check.yml +98 -0
  12. package/.github/workflows/docs.yml +265 -0
  13. package/.github/workflows/e2e.yml +90 -0
  14. package/.github/workflows/examples-published.yml +97 -0
  15. package/.github/workflows/release.yml +326 -0
  16. package/.husky/pre-commit +12 -0
  17. package/.prettierignore +109 -0
  18. package/.prettierrc +6 -0
  19. package/AGENTS.md +103 -0
  20. package/CHANGELOG.md +3268 -0
  21. package/CLAUDE.md +93 -0
  22. package/CNAME +1 -0
  23. package/CODE_OF_CONDUCT.md +7 -0
  24. package/CONTRIBUTING.md +433 -0
  25. package/LICENSE +21 -0
  26. package/README.md +2 -2
  27. package/SECURITY.md +74 -0
  28. package/b3pay-module.json +194 -0
  29. package/docs/.remarkrc.json +10 -0
  30. package/docs/README.md +64 -0
  31. package/docs/astro.config.mjs +205 -0
  32. package/docs/favicon.svg +15 -0
  33. package/docs/package.json +39 -0
  34. package/docs/public/favicon.svg +15 -0
  35. package/docs/public/ic-reactor-social-card.png +0 -0
  36. package/docs/scripts/b3pay-static.mjs +22 -0
  37. package/docs/scripts/check-example-docs.mjs +214 -0
  38. package/docs/scripts/check-links.mjs +212 -0
  39. package/docs/scripts/fix-dist-links.js +125 -0
  40. package/docs/scripts/fix-frontmatter.js +71 -0
  41. package/docs/scripts/remove-redundant-h1.cjs +48 -0
  42. package/docs/scripts/rewrite-typedoc-links.js +110 -0
  43. package/docs/scripts/split-index.js +69 -0
  44. package/docs/src/assets/ic-reactor-hero-dark.svg +23 -0
  45. package/docs/src/assets/ic-reactor-hero-light.svg +23 -0
  46. package/docs/src/assets/ic-reactor-lockup-dark.svg +15 -0
  47. package/docs/src/assets/ic-reactor-lockup-light.svg +15 -0
  48. package/docs/src/assets/ic-reactor-mark-dark.svg +14 -0
  49. package/docs/src/assets/ic-reactor-mark-light.svg +14 -0
  50. package/docs/src/assets/layers/candid-core-layer-icon-dark.svg +4 -0
  51. package/docs/src/assets/layers/candid-core-layer-icon-light.svg +4 -0
  52. package/docs/src/assets/layers/candid-profile-layer-icon-dark.svg +4 -0
  53. package/docs/src/assets/layers/candid-profile-layer-icon-light.svg +4 -0
  54. package/docs/src/assets/layers/ic-reactor-layer-icon-dark.svg +4 -0
  55. package/docs/src/assets/layers/ic-reactor-layer-icon-light.svg +4 -0
  56. package/docs/src/components/LibraryCards.astro +172 -0
  57. package/docs/src/components/LibraryIcon.astro +28 -0
  58. package/docs/src/components/SiteTitle.astro +241 -0
  59. package/docs/src/content/docs/404.mdx +19 -0
  60. package/docs/src/content/docs/build/agent-tools.mdx +593 -0
  61. package/docs/src/content/docs/build/icrc1-wallet.mdx +619 -0
  62. package/docs/src/content/docs/build/ssr-per-user.mdx +552 -0
  63. package/docs/src/content/docs/examples/canister-studio.mdx +95 -0
  64. package/docs/src/content/docs/examples/icrc-ledger.mdx +45 -0
  65. package/docs/src/content/docs/examples/index.mdx +38 -0
  66. package/docs/src/content/docs/examples/next-ssr.mdx +73 -0
  67. package/docs/src/content/docs/examples/node-agent-tool.mdx +80 -0
  68. package/docs/src/content/docs/examples/vite-wallet.mdx +71 -0
  69. package/docs/src/content/docs/guides/auth.mdx +1181 -0
  70. package/docs/src/content/docs/guides/client.mdx +551 -0
  71. package/docs/src/content/docs/guides/deploy.mdx +180 -0
  72. package/docs/src/content/docs/guides/errors.mdx +475 -0
  73. package/docs/src/content/docs/guides/getting-started.mdx +620 -0
  74. package/docs/src/content/docs/guides/reads.mdx +586 -0
  75. package/docs/src/content/docs/guides/ssr.mdx +529 -0
  76. package/docs/src/content/docs/guides/testing.mdx +401 -0
  77. package/docs/src/content/docs/guides/values.mdx +261 -0
  78. package/docs/src/content/docs/guides/vite-plugin.mdx +690 -0
  79. package/docs/src/content/docs/guides/writes.mdx +572 -0
  80. package/docs/src/content/docs/ic-reactor/index.mdx +167 -0
  81. package/docs/src/content/docs/index.mdx +65 -0
  82. package/docs/src/content/docs/migrating-from-3.mdx +535 -0
  83. package/docs/src/content/docs/packages/core.mdx +186 -0
  84. package/docs/src/content/docs/packages/mcp.mdx +163 -0
  85. package/docs/src/content/docs/packages/react.mdx +207 -0
  86. package/docs/src/content/docs/packages/vite-plugin.mdx +73 -0
  87. package/docs/src/content/docs/versioning.mdx +104 -0
  88. package/docs/src/content.config.ts +7 -0
  89. package/docs/src/styles/custom.css +189 -0
  90. package/docs/tsconfig.typedoc.json +26 -0
  91. package/docs/typedoc-entry.ts +17 -0
  92. package/docs/typedoc.json +37 -0
  93. package/e2e/Cargo.lock +646 -0
  94. package/e2e/Cargo.toml +3 -0
  95. package/e2e/README.md +101 -0
  96. package/e2e/frontends/build.mjs +94 -0
  97. package/e2e/frontends/index.html +10 -0
  98. package/e2e/global-setup.ts +65 -0
  99. package/e2e/icp.yaml +38 -0
  100. package/e2e/package.json +40 -0
  101. package/e2e/setup.ts +6 -0
  102. package/e2e/src/actor/Cargo.toml +14 -0
  103. package/e2e/src/actor/hello_actor.did +10 -0
  104. package/e2e/src/actor/src/lib.rs +73 -0
  105. package/e2e/src/calls.test.ts +132 -0
  106. package/e2e/src/declarations/hello_actor.envelope.json +175 -0
  107. package/e2e/src/declarations/hello_actor.ts +15 -0
  108. package/e2e/src/errors.test.ts +107 -0
  109. package/e2e/src/frontend-headers.test.ts +253 -0
  110. package/e2e/src/identity.test.ts +61 -0
  111. package/e2e/src/react.test.tsx +59 -0
  112. package/e2e/src/replica.ts +70 -0
  113. package/e2e/src/vite-env.test.ts +108 -0
  114. package/e2e/test.sh +47 -0
  115. package/e2e/tsconfig.json +20 -0
  116. package/e2e/tsconfig.typecheck.json +9 -0
  117. package/e2e/vitest.config.ts +22 -0
  118. package/eslint.config.mjs +100 -0
  119. package/evals/PREREGISTRATION.md +1346 -0
  120. package/evals/README.md +756 -0
  121. package/evals/conditions/thin/condition.json +8 -0
  122. package/evals/conditions/thin/docs/candid-core-cli.README.md +90 -0
  123. package/evals/conditions/thin/docs/candid-core-schema.README.md +339 -0
  124. package/evals/conditions/thin/package.json +25 -0
  125. package/evals/conditions/thin/starter/src/generated/icrc1.ts +57 -0
  126. package/evals/conditions/thin-guide/condition.json +10 -0
  127. package/evals/conditions/thin-guide/docs/llms.txt +292 -0
  128. package/evals/conditions/v3/condition.json +9 -0
  129. package/evals/conditions/v3/docs/ic-reactor-core.llms.txt +232 -0
  130. package/evals/conditions/v3/docs/ic-reactor-react.llms.txt +280 -0
  131. package/evals/conditions/v3/docs/llms-full.txt +1053 -0
  132. package/evals/conditions/v3/package.json +26 -0
  133. package/evals/conditions/v3/starter/src/declarations/icrc1.did.d.ts +95 -0
  134. package/evals/conditions/v3/starter/src/declarations/icrc1.did.js +140 -0
  135. package/evals/conditions/v4/PORTING.md +384 -0
  136. package/evals/conditions/v4/README.md +106 -0
  137. package/evals/conditions/v4/condition.json +5 -0
  138. package/evals/conditions/v4/docs/llms.txt +323 -0
  139. package/evals/conditions/v4/package.json +27 -0
  140. package/evals/conditions/v4/starter/src/generated/icrc1.ts +78 -0
  141. package/evals/conditions/v4-proto/condition.json +6 -0
  142. package/evals/conditions/v4-proto/docs/llms.txt +291 -0
  143. package/evals/conditions/v4-proto/lib/SHIM-NOTES.md +20 -0
  144. package/evals/conditions/v4-proto/lib/package.json +27 -0
  145. package/evals/conditions/v4-proto/lib/src/client.ts +471 -0
  146. package/evals/conditions/v4-proto/lib/src/errors.ts +214 -0
  147. package/evals/conditions/v4-proto/lib/src/index.ts +36 -0
  148. package/evals/conditions/v4-proto/lib/src/principal.ts +175 -0
  149. package/evals/conditions/v4-proto/lib/src/service.ts +69 -0
  150. package/evals/conditions/v4-proto/lib/src/types.ts +174 -0
  151. package/evals/conditions/v4-proto/lib/test/runtime.test.ts +170 -0
  152. package/evals/conditions/v4-proto/lib/test/tsconfig.json +10 -0
  153. package/evals/conditions/v4-proto/lib/test/types.test-d.ts +145 -0
  154. package/evals/conditions/v4-proto/lib/test/vitest.config.mjs +8 -0
  155. package/evals/conditions/v4-proto/lib/tsconfig.json +17 -0
  156. package/evals/conditions/v4-proto/package.json +26 -0
  157. package/evals/conditions/v4-proto/starter/src/generated/icrc1.service.ts +19 -0
  158. package/evals/conditions/v4-proto/starter/src/generated/icrc1.ts +57 -0
  159. package/evals/drive.mjs +1221 -0
  160. package/evals/gate.mjs +161 -0
  161. package/evals/harness/aggregate.mjs +534 -0
  162. package/evals/harness/aggregate.test.mjs +344 -0
  163. package/evals/harness/assemble.mjs +216 -0
  164. package/evals/harness/assemble.test.mjs +143 -0
  165. package/evals/harness/auth.mjs +91 -0
  166. package/evals/harness/check-docs.mjs +157 -0
  167. package/evals/harness/declarations/icrc1.did.d.ts +95 -0
  168. package/evals/harness/declarations/icrc1.did.js +140 -0
  169. package/evals/harness/drive-auth.test.mjs +584 -0
  170. package/evals/harness/drive.test.mjs +509 -0
  171. package/evals/harness/fake-auth.ts +67 -0
  172. package/evals/harness/fake-ledger.ts +178 -0
  173. package/evals/harness/gate-plan.mjs +104 -0
  174. package/evals/harness/gate-plan.test.mjs +243 -0
  175. package/evals/harness/icrc1.did +88 -0
  176. package/evals/harness/judge.mjs +63 -0
  177. package/evals/harness/judge.test.mjs +81 -0
  178. package/evals/harness/leak-scan.mjs +1373 -0
  179. package/evals/harness/leak-scan.test.mjs +1300 -0
  180. package/evals/harness/probes/amounts.ts +14 -0
  181. package/evals/harness/probes/node-tool.probe.ts +48 -0
  182. package/evals/harness/probes/probe.mjs +149 -0
  183. package/evals/harness/probes/react-wallet.probe.ts +96 -0
  184. package/evals/harness/public/support/auth.ts +38 -0
  185. package/evals/harness/public/support/fake-replica.d.ts +28 -0
  186. package/evals/harness/public/support/fake-replica.js +434 -0
  187. package/evals/harness/public/support/ledger.idl.d.ts +95 -0
  188. package/evals/harness/public/support/ledger.idl.js +140 -0
  189. package/evals/harness/public/support/world.ts +179 -0
  190. package/evals/harness/runs.mjs +139 -0
  191. package/evals/harness/sandbox.mjs +88 -0
  192. package/evals/harness/sandbox.test.mjs +134 -0
  193. package/evals/harness/ship.mjs +264 -0
  194. package/evals/harness/ship.test.mjs +552 -0
  195. package/evals/harness/world.ts +291 -0
  196. package/evals/package.json +26 -0
  197. package/evals/pnpm-lock.yaml +1537 -0
  198. package/evals/pnpm-workspace.yaml +12 -0
  199. package/evals/results/2026-09-30T14-22-05-924Z/pilot.json +384 -0
  200. package/evals/results/2026-09-30T14-22-05-924Z/pilot.rescanned.json +404 -0
  201. package/evals/results/2026-09-30T14-22-05-924Z/pilot.rescanned.rescored.json +404 -0
  202. package/evals/results/2026-09-30T14-22-05-924Z/plan.json +240 -0
  203. package/evals/results/2026-09-30T14-22-05-924Z/summary.json +1800 -0
  204. package/evals/results/2026-09-30T14-22-05-924Z/summary.rescanned.json +1843 -0
  205. package/evals/results/2026-09-30T14-22-05-924Z/summary.rescanned.rescored.json +2100 -0
  206. package/evals/results/2026-09-30T15-48-23-343Z/pilot.json +404 -0
  207. package/evals/results/2026-09-30T15-48-23-343Z/pilot.rescored.json +404 -0
  208. package/evals/results/2026-09-30T15-48-23-343Z/plan.json +242 -0
  209. package/evals/results/2026-09-30T15-48-23-343Z/summary.json +1843 -0
  210. package/evals/results/2026-09-30T15-48-23-343Z/summary.rescored.json +2195 -0
  211. package/evals/results/2026-10-03-beta1-gate/pilot.json +162 -0
  212. package/evals/results/2026-10-03-beta1-gate/plan.json +141 -0
  213. package/evals/results/2026-10-03-beta1-gate/summary.json +983 -0
  214. package/evals/results/2026-10-05-ga-gate/contaminated-run.json +55 -0
  215. package/evals/results/2026-10-05-ga-gate/pilot.json +162 -0
  216. package/evals/results/2026-10-05-ga-gate/plan.json +457 -0
  217. package/evals/results/2026-10-05-ga-gate/summary.json +1037 -0
  218. package/evals/results/2026-10-05-ga-gate/summary.rescanned.json +1037 -0
  219. package/evals/results/README.md +31 -0
  220. package/evals/runs-pilot.log +150 -0
  221. package/evals/runs-pilot2.log +150 -0
  222. package/evals/score.mjs +256 -0
  223. package/evals/setup.mjs +547 -0
  224. package/evals/tasks/node-tool/faulty/thin-accepts-exponent/meta.json +5 -0
  225. package/evals/tasks/node-tool/faulty/thin-accepts-exponent/src/index.ts +121 -0
  226. package/evals/tasks/node-tool/faulty/thin-anonymous-transfer/meta.json +5 -0
  227. package/evals/tasks/node-tool/faulty/thin-anonymous-transfer/src/index.ts +116 -0
  228. package/evals/tasks/node-tool/faulty/thin-every-reject-may-have-executed/meta.json +9 -0
  229. package/evals/tasks/node-tool/faulty/thin-every-reject-may-have-executed/src/index.ts +118 -0
  230. package/evals/tasks/node-tool/faulty/thin-fetches-root-key-off-local/meta.json +5 -0
  231. package/evals/tasks/node-tool/faulty/thin-fetches-root-key-off-local/src/index.ts +118 -0
  232. package/evals/tasks/node-tool/faulty/thin-ignores-root-key/meta.json +5 -0
  233. package/evals/tasks/node-tool/faulty/thin-ignores-root-key/src/index.ts +117 -0
  234. package/evals/tasks/node-tool/faulty/thin-misclassifies-reject-codes/meta.json +9 -0
  235. package/evals/tasks/node-tool/faulty/thin-misclassifies-reject-codes/src/index.ts +119 -0
  236. package/evals/tasks/node-tool/faulty/thin-no-nat64-cap/meta.json +9 -0
  237. package/evals/tasks/node-tool/faulty/thin-no-nat64-cap/src/index.ts +118 -0
  238. package/evals/tasks/node-tool/faulty/thin-number-amount/meta.json +10 -0
  239. package/evals/tasks/node-tool/faulty/thin-number-amount/src/index.ts +117 -0
  240. package/evals/tasks/node-tool/faulty/thin-truncates-fraction-digits/meta.json +5 -0
  241. package/evals/tasks/node-tool/faulty/thin-truncates-fraction-digits/src/index.ts +120 -0
  242. package/evals/tasks/node-tool/faulty/thin-unvalidated-recipient/meta.json +5 -0
  243. package/evals/tasks/node-tool/faulty/thin-unvalidated-recipient/src/index.ts +118 -0
  244. package/evals/tasks/node-tool/faulty/v3-retry-call-errors/meta.json +11 -0
  245. package/evals/tasks/node-tool/faulty/v3-retry-call-errors/src/index.ts +149 -0
  246. package/evals/tasks/node-tool/faulty/v4-anonymous-identity-sent/meta.json +5 -0
  247. package/evals/tasks/node-tool/faulty/v4-anonymous-identity-sent/src/index.ts +71 -0
  248. package/evals/tasks/node-tool/faulty/v4-never-may-have-executed/meta.json +9 -0
  249. package/evals/tasks/node-tool/faulty/v4-never-may-have-executed/src/index.ts +84 -0
  250. package/evals/tasks/node-tool/faulty/v4-proto-never-may-have-executed/meta.json +9 -0
  251. package/evals/tasks/node-tool/faulty/v4-proto-never-may-have-executed/src/index.ts +72 -0
  252. package/evals/tasks/node-tool/faulty/v4-proto-refuses-nat64-max/meta.json +5 -0
  253. package/evals/tasks/node-tool/faulty/v4-proto-refuses-nat64-max/src/index.ts +72 -0
  254. package/evals/tasks/node-tool/faulty/v4-refuses-nat64-max/meta.json +5 -0
  255. package/evals/tasks/node-tool/faulty/v4-refuses-nat64-max/src/index.ts +84 -0
  256. package/evals/tasks/node-tool/hidden/node-tool.test.ts +312 -0
  257. package/evals/tasks/node-tool/prompt.md +55 -0
  258. package/evals/tasks/node-tool/prompt.minimal.md +30 -0
  259. package/evals/tasks/node-tool/solutions/thin/reference/src/index.ts +118 -0
  260. package/evals/tasks/node-tool/solutions/thin/reference-module-scope/src/index.ts +145 -0
  261. package/evals/tasks/node-tool/solutions/thin-guide/reference/src/index.ts +118 -0
  262. package/evals/tasks/node-tool/solutions/thin-guide/reference-module-scope/src/index.ts +145 -0
  263. package/evals/tasks/node-tool/solutions/v3/reference/src/index.ts +140 -0
  264. package/evals/tasks/node-tool/solutions/v3/reference-module-scope/src/index.ts +153 -0
  265. package/evals/tasks/node-tool/solutions/v4/reference/src/index.ts +84 -0
  266. package/evals/tasks/node-tool/solutions/v4/reference-module-scope/src/index.ts +105 -0
  267. package/evals/tasks/node-tool/solutions/v4-proto/reference/src/index.ts +72 -0
  268. package/evals/tasks/node-tool/solutions/v4-proto/reference-module-scope/src/index.ts +87 -0
  269. package/evals/tasks/node-tool/starter/src/contract.ts +31 -0
  270. package/evals/tasks/node-tool/starter/src/index.ts +7 -0
  271. package/evals/tasks/node-tool/starter/test/smoke.test.ts +22 -0
  272. package/evals/tasks/node-tool/starter/tsconfig.json +17 -0
  273. package/evals/tasks/node-tool/task.json +63 -0
  274. package/evals/tasks/react-wallet/faulty/thin-accepts-exponent/meta.json +5 -0
  275. package/evals/tasks/react-wallet/faulty/thin-accepts-exponent/src/Wallet.tsx +216 -0
  276. package/evals/tasks/react-wallet/faulty/thin-anonymous-transfer/meta.json +5 -0
  277. package/evals/tasks/react-wallet/faulty/thin-anonymous-transfer/src/Wallet.tsx +212 -0
  278. package/evals/tasks/react-wallet/faulty/thin-both-auth-buttons/meta.json +5 -0
  279. package/evals/tasks/react-wallet/faulty/thin-both-auth-buttons/src/Wallet.tsx +210 -0
  280. package/evals/tasks/react-wallet/faulty/thin-constant-balance-key/meta.json +8 -0
  281. package/evals/tasks/react-wallet/faulty/thin-constant-balance-key/src/Wallet.tsx +213 -0
  282. package/evals/tasks/react-wallet/faulty/thin-no-nat64-cap/meta.json +9 -0
  283. package/evals/tasks/react-wallet/faulty/thin-no-nat64-cap/src/Wallet.tsx +213 -0
  284. package/evals/tasks/react-wallet/faulty/thin-number-balance/meta.json +5 -0
  285. package/evals/tasks/react-wallet/faulty/thin-number-balance/src/Wallet.tsx +213 -0
  286. package/evals/tasks/react-wallet/faulty/thin-transfer-as-query/meta.json +5 -0
  287. package/evals/tasks/react-wallet/faulty/thin-transfer-as-query/src/Wallet.tsx +254 -0
  288. package/evals/tasks/react-wallet/faulty/thin-truncates-fraction-digits/meta.json +5 -0
  289. package/evals/tasks/react-wallet/faulty/thin-truncates-fraction-digits/src/Wallet.tsx +215 -0
  290. package/evals/tasks/react-wallet/faulty/thin-unguarded-balance-effect/meta.json +5 -0
  291. package/evals/tasks/react-wallet/faulty/thin-unguarded-balance-effect/src/Wallet.tsx +214 -0
  292. package/evals/tasks/react-wallet/faulty/v3-http-4xx-unknown/meta.json +5 -0
  293. package/evals/tasks/react-wallet/faulty/v3-http-4xx-unknown/src/Wallet.tsx +224 -0
  294. package/evals/tasks/react-wallet/faulty/v3-mutation-retry-3/meta.json +12 -0
  295. package/evals/tasks/react-wallet/faulty/v3-mutation-retry-3/src/Wallet.tsx +225 -0
  296. package/evals/tasks/react-wallet/faulty/v3-unknown-as-error/meta.json +11 -0
  297. package/evals/tasks/react-wallet/faulty/v3-unknown-as-error/src/Wallet.tsx +182 -0
  298. package/evals/tasks/react-wallet/faulty/v4-every-reject-unknown/meta.json +5 -0
  299. package/evals/tasks/react-wallet/faulty/v4-every-reject-unknown/src/Wallet.tsx +160 -0
  300. package/evals/tasks/react-wallet/faulty/v4-keep-previous-data/meta.json +5 -0
  301. package/evals/tasks/react-wallet/faulty/v4-keep-previous-data/src/Wallet.tsx +166 -0
  302. package/evals/tasks/react-wallet/faulty/v4-proto-every-reject-unknown/meta.json +5 -0
  303. package/evals/tasks/react-wallet/faulty/v4-proto-every-reject-unknown/src/Wallet.tsx +161 -0
  304. package/evals/tasks/react-wallet/faulty/v4-proto-keep-previous-data/meta.json +5 -0
  305. package/evals/tasks/react-wallet/faulty/v4-proto-keep-previous-data/src/Wallet.tsx +163 -0
  306. package/evals/tasks/react-wallet/faulty/v4-proto-retry-spread/meta.json +12 -0
  307. package/evals/tasks/react-wallet/faulty/v4-proto-retry-spread/src/Wallet.tsx +162 -0
  308. package/evals/tasks/react-wallet/faulty/v4-proto-status-not-idle/meta.json +5 -0
  309. package/evals/tasks/react-wallet/faulty/v4-proto-status-not-idle/src/Wallet.tsx +163 -0
  310. package/evals/tasks/react-wallet/faulty/v4-retry-spread/meta.json +12 -0
  311. package/evals/tasks/react-wallet/faulty/v4-retry-spread/src/Wallet.tsx +163 -0
  312. package/evals/tasks/react-wallet/faulty/v4-status-not-idle/meta.json +5 -0
  313. package/evals/tasks/react-wallet/faulty/v4-status-not-idle/src/Wallet.tsx +162 -0
  314. package/evals/tasks/react-wallet/hidden/react-wallet.test.ts +536 -0
  315. package/evals/tasks/react-wallet/prompt.md +88 -0
  316. package/evals/tasks/react-wallet/prompt.minimal.md +51 -0
  317. package/evals/tasks/react-wallet/solutions/thin/reference/src/Wallet.tsx +213 -0
  318. package/evals/tasks/react-wallet/solutions/thin/reference-module-scope/src/Wallet.tsx +227 -0
  319. package/evals/tasks/react-wallet/solutions/thin-guide/reference/src/Wallet.tsx +213 -0
  320. package/evals/tasks/react-wallet/solutions/thin-guide/reference-module-scope/src/Wallet.tsx +227 -0
  321. package/evals/tasks/react-wallet/solutions/v3/reference/src/Wallet.tsx +224 -0
  322. package/evals/tasks/react-wallet/solutions/v3/reference-module-scope/src/Wallet.tsx +230 -0
  323. package/evals/tasks/react-wallet/solutions/v4/reference/src/Wallet.tsx +160 -0
  324. package/evals/tasks/react-wallet/solutions/v4/reference-module-scope/src/Wallet.tsx +178 -0
  325. package/evals/tasks/react-wallet/solutions/v4-proto/reference/src/Wallet.tsx +161 -0
  326. package/evals/tasks/react-wallet/solutions/v4-proto/reference-module-scope/src/Wallet.tsx +161 -0
  327. package/evals/tasks/react-wallet/starter/src/Wallet.tsx +12 -0
  328. package/evals/tasks/react-wallet/starter/src/auth.ts +16 -0
  329. package/evals/tasks/react-wallet/starter/src/config.ts +14 -0
  330. package/evals/tasks/react-wallet/starter/src/ii-auth.ts +43 -0
  331. package/evals/tasks/react-wallet/starter/src/main.tsx +15 -0
  332. package/evals/tasks/react-wallet/starter/test/smoke.test.ts +34 -0
  333. package/evals/tasks/react-wallet/starter/tsconfig.json +18 -0
  334. package/evals/tasks/react-wallet/task.json +84 -0
  335. package/examples/canister-studio/.stackblitzrc +4 -0
  336. package/examples/canister-studio/README.md +183 -0
  337. package/examples/canister-studio/did/ckbtc_minter.did +806 -0
  338. package/examples/canister-studio/did/icp_ledger.did +586 -0
  339. package/examples/canister-studio/did/icrc1.did +88 -0
  340. package/examples/canister-studio/package.json +45 -0
  341. package/examples/canister-studio/scripts/smoke.ts +188 -0
  342. package/examples/canister-studio/src/calls/CacheKeyPanel.tsx +104 -0
  343. package/examples/canister-studio/src/calls/ConfirmWrite.tsx +265 -0
  344. package/examples/canister-studio/src/calls/ErrorPanel.test.tsx +113 -0
  345. package/examples/canister-studio/src/calls/ErrorPanel.tsx +214 -0
  346. package/examples/canister-studio/src/calls/MethodRunner.test.tsx +354 -0
  347. package/examples/canister-studio/src/calls/MethodRunner.tsx +57 -0
  348. package/examples/canister-studio/src/calls/ReadRunner.tsx +244 -0
  349. package/examples/canister-studio/src/calls/ResendPanel.tsx +165 -0
  350. package/examples/canister-studio/src/calls/ShareLink.tsx +59 -0
  351. package/examples/canister-studio/src/calls/WriteRunner.test.tsx +678 -0
  352. package/examples/canister-studio/src/calls/WriteRunner.tsx +670 -0
  353. package/examples/canister-studio/src/calls/dedupe.ts +189 -0
  354. package/examples/canister-studio/src/calls/error-info.ts +168 -0
  355. package/examples/canister-studio/src/calls/history.test.ts +284 -0
  356. package/examples/canister-studio/src/calls/history.ts +287 -0
  357. package/examples/canister-studio/src/calls/kinds.ts +68 -0
  358. package/examples/canister-studio/src/calls/prepare.ts +32 -0
  359. package/examples/canister-studio/src/calls/query-options.ts +30 -0
  360. package/examples/canister-studio/src/calls/read.ts +47 -0
  361. package/examples/canister-studio/src/calls/readback.ts +100 -0
  362. package/examples/canister-studio/src/calls/record.ts +123 -0
  363. package/examples/canister-studio/src/calls/safe-calls.test.ts +299 -0
  364. package/examples/canister-studio/src/calls/share.ts +46 -0
  365. package/examples/canister-studio/src/calls/testing/doubles.tsx +108 -0
  366. package/examples/canister-studio/src/calls/testing/fixtures.ts +185 -0
  367. package/examples/canister-studio/src/calls/useCanisterHandle.ts +35 -0
  368. package/examples/canister-studio/src/canisters/ckbtc_minter.envelope.json +4228 -0
  369. package/examples/canister-studio/src/canisters/ckbtc_minter.ts +868 -0
  370. package/examples/canister-studio/src/canisters/icp_ledger.envelope.json +3454 -0
  371. package/examples/canister-studio/src/canisters/icp_ledger.ts +584 -0
  372. package/examples/canister-studio/src/canisters/icrc1.envelope.json +840 -0
  373. package/examples/canister-studio/src/canisters/icrc1.ts +78 -0
  374. package/examples/canister-studio/src/components/ActionButton.tsx +32 -0
  375. package/examples/canister-studio/src/components/AppHeader.tsx +83 -0
  376. package/examples/canister-studio/src/components/AppShell.tsx +29 -0
  377. package/examples/canister-studio/src/components/AuthButton.tsx +79 -0
  378. package/examples/canister-studio/src/components/Badge.tsx +79 -0
  379. package/examples/canister-studio/src/components/CanisterHeader.tsx +200 -0
  380. package/examples/canister-studio/src/components/CanisterJump.tsx +130 -0
  381. package/examples/canister-studio/src/components/Card.tsx +64 -0
  382. package/examples/canister-studio/src/components/Code.tsx +101 -0
  383. package/examples/canister-studio/src/components/CopyButton.tsx +126 -0
  384. package/examples/canister-studio/src/components/Disclosure.tsx +34 -0
  385. package/examples/canister-studio/src/components/EmptyState.tsx +34 -0
  386. package/examples/canister-studio/src/components/MethodList.test.tsx +137 -0
  387. package/examples/canister-studio/src/components/MethodList.tsx +244 -0
  388. package/examples/canister-studio/src/components/Notice.tsx +36 -0
  389. package/examples/canister-studio/src/components/ProvenanceBadge.tsx +44 -0
  390. package/examples/canister-studio/src/components/RouteError.tsx +42 -0
  391. package/examples/canister-studio/src/components/SectionBoundary.tsx +76 -0
  392. package/examples/canister-studio/src/components/Spinner.tsx +33 -0
  393. package/examples/canister-studio/src/components/Tabs.tsx +96 -0
  394. package/examples/canister-studio/src/components/canister/CanisterLoadFailure.test.tsx +56 -0
  395. package/examples/canister-studio/src/components/canister/CanisterLoadFailure.tsx +165 -0
  396. package/examples/canister-studio/src/components/canister/CanisterNotFound.tsx +59 -0
  397. package/examples/canister-studio/src/components/canister/CanisterPending.tsx +33 -0
  398. package/examples/canister-studio/src/components/canister/MethodOverview.tsx +93 -0
  399. package/examples/canister-studio/src/components/canister/MethodWorkspace.test.tsx +201 -0
  400. package/examples/canister-studio/src/components/canister/MethodWorkspace.tsx +187 -0
  401. package/examples/canister-studio/src/components/canister/shared-call.test.ts +186 -0
  402. package/examples/canister-studio/src/components/canister/shared-call.ts +133 -0
  403. package/examples/canister-studio/src/components/canister/shared-link-loader.test.ts +116 -0
  404. package/examples/canister-studio/src/components/canister/use-canister-page.ts +44 -0
  405. package/examples/canister-studio/src/components/canister/workspace-key.test.ts +27 -0
  406. package/examples/canister-studio/src/components/canister/workspace-key.ts +36 -0
  407. package/examples/canister-studio/src/components/canister-id-input.ts +69 -0
  408. package/examples/canister-studio/src/components/canister-names.ts +11 -0
  409. package/examples/canister-studio/src/components/download.ts +34 -0
  410. package/examples/canister-studio/src/components/fallbacks.tsx +33 -0
  411. package/examples/canister-studio/src/components/helpers.test.ts +107 -0
  412. package/examples/canister-studio/src/components/history/HistoryList.tsx +284 -0
  413. package/examples/canister-studio/src/components/home/FeaturedLedger.tsx +149 -0
  414. package/examples/canister-studio/src/components/home/OpenCanister.tsx +99 -0
  415. package/examples/canister-studio/src/components/home/featured.test.tsx +92 -0
  416. package/examples/canister-studio/src/components/home/featured.ts +64 -0
  417. package/examples/canister-studio/src/components/interface/CandidTab.tsx +38 -0
  418. package/examples/canister-studio/src/components/interface/CompatReport.tsx +92 -0
  419. package/examples/canister-studio/src/components/interface/CompatibilityTab.tsx +190 -0
  420. package/examples/canister-studio/src/components/interface/ProjectTab.tsx +196 -0
  421. package/examples/canister-studio/src/components/interface/TypeScriptTab.tsx +114 -0
  422. package/examples/canister-studio/src/components/interface/tools.test.tsx +169 -0
  423. package/examples/canister-studio/src/components/modes.ts +31 -0
  424. package/examples/canister-studio/src/components/playground/MethodPicker.tsx +67 -0
  425. package/examples/canister-studio/src/components/playground/PlaygroundForms.tsx +112 -0
  426. package/examples/canister-studio/src/components/playground/PlaygroundTools.tsx +219 -0
  427. package/examples/canister-studio/src/components/playground/sample.ts +43 -0
  428. package/examples/canister-studio/src/components/playground/target.test.tsx +86 -0
  429. package/examples/canister-studio/src/components/primitives.test.tsx +121 -0
  430. package/examples/canister-studio/src/components/provenance.ts +38 -0
  431. package/examples/canister-studio/src/components/route-render.test.tsx +71 -0
  432. package/examples/canister-studio/src/components/use-task.ts +56 -0
  433. package/examples/canister-studio/src/components/wallet/BalancePanel.tsx +110 -0
  434. package/examples/canister-studio/src/components/wallet/LedgerSummary.tsx +63 -0
  435. package/examples/canister-studio/src/components/wallet/MinterPanel.tsx +255 -0
  436. package/examples/canister-studio/src/components/wallet/SendPanel.test.tsx +297 -0
  437. package/examples/canister-studio/src/components/wallet/SendPanel.tsx +446 -0
  438. package/examples/canister-studio/src/components/wallet/ledgers.test.ts +36 -0
  439. package/examples/canister-studio/src/components/wallet/ledgers.ts +111 -0
  440. package/examples/canister-studio/src/forms/JsonPanel.tsx +157 -0
  441. package/examples/canister-studio/src/forms/MethodForm.test.tsx +369 -0
  442. package/examples/canister-studio/src/forms/MethodForm.tsx +368 -0
  443. package/examples/canister-studio/src/forms/TypedForm.tsx +55 -0
  444. package/examples/canister-studio/src/forms/context.ts +62 -0
  445. package/examples/canister-studio/src/forms/convert.ts +131 -0
  446. package/examples/canister-studio/src/forms/edge.test.ts +252 -0
  447. package/examples/canister-studio/src/forms/engine.test.ts +358 -0
  448. package/examples/canister-studio/src/forms/engine.ts +1492 -0
  449. package/examples/canister-studio/src/forms/fields/BytesField.tsx +210 -0
  450. package/examples/canister-studio/src/forms/fields/Field.tsx +106 -0
  451. package/examples/canister-studio/src/forms/fields/FieldShell.tsx +101 -0
  452. package/examples/canister-studio/src/forms/fields/Group.tsx +74 -0
  453. package/examples/canister-studio/src/forms/fields/ListField.tsx +256 -0
  454. package/examples/canister-studio/src/forms/fields/Segmented.tsx +78 -0
  455. package/examples/canister-studio/src/forms/fields/TimestampField.tsx +108 -0
  456. package/examples/canister-studio/src/forms/fields/UnitsField.tsx +119 -0
  457. package/examples/canister-studio/src/forms/fields/composites.tsx +389 -0
  458. package/examples/canister-studio/src/forms/fields/leaves.tsx +350 -0
  459. package/examples/canister-studio/src/forms/fields.test.tsx +396 -0
  460. package/examples/canister-studio/src/forms/helpers.test.ts +225 -0
  461. package/examples/canister-studio/src/forms/hints.ts +128 -0
  462. package/examples/canister-studio/src/forms/json.ts +119 -0
  463. package/examples/canister-studio/src/forms/parsing.test.ts +217 -0
  464. package/examples/canister-studio/src/forms/useMethodForm.ts +251 -0
  465. package/examples/canister-studio/src/interface/browser.test.ts +23 -0
  466. package/examples/canister-studio/src/interface/browser.ts +153 -0
  467. package/examples/canister-studio/src/interface/cache.ts +68 -0
  468. package/examples/canister-studio/src/interface/cli-cache.test.ts +155 -0
  469. package/examples/canister-studio/src/interface/cli-cache.ts +125 -0
  470. package/examples/canister-studio/src/interface/compile.server.test.ts +198 -0
  471. package/examples/canister-studio/src/interface/compile.server.ts +262 -0
  472. package/examples/canister-studio/src/interface/compile.test.ts +108 -0
  473. package/examples/canister-studio/src/interface/compile.ts +305 -0
  474. package/examples/canister-studio/src/interface/docs.test.ts +75 -0
  475. package/examples/canister-studio/src/interface/docs.ts +100 -0
  476. package/examples/canister-studio/src/interface/functions.test.ts +42 -0
  477. package/examples/canister-studio/src/interface/functions.ts +200 -0
  478. package/examples/canister-studio/src/interface/live-candid.server.ts +91 -0
  479. package/examples/canister-studio/src/interface/live-loader.test.ts +515 -0
  480. package/examples/canister-studio/src/interface/live-loader.ts +364 -0
  481. package/examples/canister-studio/src/interface/load.test.ts +328 -0
  482. package/examples/canister-studio/src/interface/load.ts +249 -0
  483. package/examples/canister-studio/src/interface/read-candid.test.ts +185 -0
  484. package/examples/canister-studio/src/interface/read-candid.ts +233 -0
  485. package/examples/canister-studio/src/interface/server-result.ts +42 -0
  486. package/examples/canister-studio/src/interface/typed.ts +68 -0
  487. package/examples/canister-studio/src/interface/types.ts +121 -0
  488. package/examples/canister-studio/src/lib/format.test.ts +107 -0
  489. package/examples/canister-studio/src/lib/format.ts +139 -0
  490. package/examples/canister-studio/src/lib/hex.test.ts +43 -0
  491. package/examples/canister-studio/src/lib/hex.ts +33 -0
  492. package/examples/canister-studio/src/lib/ids.test.ts +70 -0
  493. package/examples/canister-studio/src/lib/ids.ts +93 -0
  494. package/examples/canister-studio/src/lib/reactor.test.ts +55 -0
  495. package/examples/canister-studio/src/lib/reactor.ts +55 -0
  496. package/examples/canister-studio/src/lib/registry.test.ts +74 -0
  497. package/examples/canister-studio/src/lib/registry.ts +238 -0
  498. package/examples/canister-studio/src/lib/schema.ts +148 -0
  499. package/examples/canister-studio/src/routeTree.gen.ts +227 -0
  500. package/examples/canister-studio/src/router.test.ts +290 -0
  501. package/examples/canister-studio/src/router.tsx +127 -0
  502. package/examples/canister-studio/src/routes/__root.tsx +58 -0
  503. package/examples/canister-studio/src/routes/canister.$canisterId.index.tsx +172 -0
  504. package/examples/canister-studio/src/routes/canister.$canisterId.interface.tsx +98 -0
  505. package/examples/canister-studio/src/routes/canister.$canisterId.tsx +91 -0
  506. package/examples/canister-studio/src/routes/history.tsx +55 -0
  507. package/examples/canister-studio/src/routes/index.tsx +169 -0
  508. package/examples/canister-studio/src/routes/playground.tsx +286 -0
  509. package/examples/canister-studio/src/routes/safety.tsx +57 -0
  510. package/examples/canister-studio/src/routes/wallet.tsx +213 -0
  511. package/examples/canister-studio/src/safety/LabTransferForm.tsx +84 -0
  512. package/examples/canister-studio/src/safety/RequestLog.tsx +79 -0
  513. package/examples/canister-studio/src/safety/SafetyLab.test.tsx +89 -0
  514. package/examples/canister-studio/src/safety/SafetyLab.tsx +140 -0
  515. package/examples/canister-studio/src/safety/ScenarioCard.tsx +262 -0
  516. package/examples/canister-studio/src/safety/lab-run.ts +283 -0
  517. package/examples/canister-studio/src/safety/mock-ledger.test.ts +99 -0
  518. package/examples/canister-studio/src/safety/mock-ledger.ts +263 -0
  519. package/examples/canister-studio/src/safety/scenarios.test.ts +157 -0
  520. package/examples/canister-studio/src/safety/scenarios.ts +924 -0
  521. package/examples/canister-studio/src/styles.css +3453 -0
  522. package/examples/canister-studio/src/styles.test.ts +46 -0
  523. package/examples/canister-studio/src/values/CallPreview.test.tsx +86 -0
  524. package/examples/canister-studio/src/values/CallPreview.tsx +148 -0
  525. package/examples/canister-studio/src/values/ErrValueView.tsx +66 -0
  526. package/examples/canister-studio/src/values/Inspector.tsx +133 -0
  527. package/examples/canister-studio/src/values/ReplyView.test.tsx +341 -0
  528. package/examples/canister-studio/src/values/ReplyView.tsx +164 -0
  529. package/examples/canister-studio/src/values/candid-text.test.ts +516 -0
  530. package/examples/canister-studio/src/values/candid-text.ts +479 -0
  531. package/examples/canister-studio/src/values/hints.ts +58 -0
  532. package/examples/canister-studio/src/values/json.test.ts +66 -0
  533. package/examples/canister-studio/src/values/json.ts +31 -0
  534. package/examples/canister-studio/src/values/leaves.tsx +309 -0
  535. package/examples/canister-studio/src/values/schema.test.ts +123 -0
  536. package/examples/canister-studio/src/values/schema.ts +78 -0
  537. package/examples/canister-studio/src/values/test-router.tsx +21 -0
  538. package/examples/canister-studio/src/values/tree.tsx +670 -0
  539. package/examples/canister-studio/src/values/use-sha256.ts +29 -0
  540. package/examples/canister-studio/tsconfig.json +20 -0
  541. package/examples/canister-studio/vite.config.ts +50 -0
  542. package/examples/canister-studio/vitest.config.ts +20 -0
  543. package/examples/icrc-ledger/.stackblitzrc +4 -0
  544. package/examples/icrc-ledger/README.md +100 -0
  545. package/examples/icrc-ledger/ckbtc_minter.did +12 -0
  546. package/examples/icrc-ledger/icp_ledger.did +147 -0
  547. package/examples/icrc-ledger/icrc1.did +88 -0
  548. package/examples/icrc-ledger/index.html +13 -0
  549. package/examples/icrc-ledger/package.json +40 -0
  550. package/examples/icrc-ledger/scripts/smoke.ts +151 -0
  551. package/examples/icrc-ledger/src/App.tsx +71 -0
  552. package/examples/icrc-ledger/src/ErrorPanel.tsx +105 -0
  553. package/examples/icrc-ledger/src/MainnetTab.tsx +450 -0
  554. package/examples/icrc-ledger/src/SandboxTab.test.tsx +379 -0
  555. package/examples/icrc-ledger/src/SandboxTab.tsx +761 -0
  556. package/examples/icrc-ledger/src/blocks.test.ts +247 -0
  557. package/examples/icrc-ledger/src/blocks.ts +140 -0
  558. package/examples/icrc-ledger/src/canisters/ckbtc_minter.envelope.json +96 -0
  559. package/examples/icrc-ledger/src/canisters/ckbtc_minter.ts +16 -0
  560. package/examples/icrc-ledger/src/canisters/icp_ledger.envelope.json +690 -0
  561. package/examples/icrc-ledger/src/canisters/icp_ledger.ts +223 -0
  562. package/examples/icrc-ledger/src/canisters/icrc1.envelope.json +840 -0
  563. package/examples/icrc-ledger/src/canisters/icrc1.ts +78 -0
  564. package/examples/icrc-ledger/src/format.test.ts +41 -0
  565. package/examples/icrc-ledger/src/format.ts +68 -0
  566. package/examples/icrc-ledger/src/ledger.ts +15 -0
  567. package/examples/icrc-ledger/src/main.tsx +10 -0
  568. package/examples/icrc-ledger/src/minter.ts +16 -0
  569. package/examples/icrc-ledger/src/sandbox.test.ts +464 -0
  570. package/examples/icrc-ledger/src/sandbox.ts +281 -0
  571. package/examples/icrc-ledger/src/styles.css +391 -0
  572. package/examples/icrc-ledger/src/transfer-form.test.ts +62 -0
  573. package/examples/icrc-ledger/src/transfer-form.ts +97 -0
  574. package/examples/icrc-ledger/tsconfig.json +19 -0
  575. package/examples/icrc-ledger/vite.config.ts +44 -0
  576. package/examples/icrc-ledger/vitest.config.ts +12 -0
  577. package/examples/next-ssr/.stackblitzrc +4 -0
  578. package/examples/next-ssr/README.md +112 -0
  579. package/examples/next-ssr/icrc1.did +88 -0
  580. package/examples/next-ssr/next.config.ts +10 -0
  581. package/examples/next-ssr/package.json +41 -0
  582. package/examples/next-ssr/scripts/smoke.ts +169 -0
  583. package/examples/next-ssr/src/app/account/CertifiedBalances.tsx +58 -0
  584. package/examples/next-ssr/src/app/account/account.test.tsx +165 -0
  585. package/examples/next-ssr/src/app/account/page.tsx +82 -0
  586. package/examples/next-ssr/src/app/api/balance/[ledger]/[principal]/route.ts +10 -0
  587. package/examples/next-ssr/src/app/globals.css +278 -0
  588. package/examples/next-ssr/src/app/layout.tsx +34 -0
  589. package/examples/next-ssr/src/app/page.tsx +46 -0
  590. package/examples/next-ssr/src/app/providers.browser.test.tsx +127 -0
  591. package/examples/next-ssr/src/app/providers.test.tsx +73 -0
  592. package/examples/next-ssr/src/app/providers.tsx +60 -0
  593. package/examples/next-ssr/src/canisters/icrc1.envelope.json +840 -0
  594. package/examples/next-ssr/src/canisters/icrc1.ts +78 -0
  595. package/examples/next-ssr/src/components/BalanceTable.tsx +43 -0
  596. package/examples/next-ssr/src/components/LedgerCard.test.tsx +96 -0
  597. package/examples/next-ssr/src/components/LedgerCard.tsx +230 -0
  598. package/examples/next-ssr/src/components/LedgerError.tsx +32 -0
  599. package/examples/next-ssr/src/components/LedgerSections.tsx +22 -0
  600. package/examples/next-ssr/src/components/MyBalances.test.tsx +253 -0
  601. package/examples/next-ssr/src/components/MyBalances.tsx +129 -0
  602. package/examples/next-ssr/src/components/SessionBadge.tsx +18 -0
  603. package/examples/next-ssr/src/components/hydration.test.tsx +259 -0
  604. package/examples/next-ssr/src/components/server-data.ts +10 -0
  605. package/examples/next-ssr/src/format.ts +46 -0
  606. package/examples/next-ssr/src/ledgers.ts +38 -0
  607. package/examples/next-ssr/src/server/balance-route.test.ts +151 -0
  608. package/examples/next-ssr/src/server/balance-route.ts +157 -0
  609. package/examples/next-ssr/src/server/error-summary.test.ts +34 -0
  610. package/examples/next-ssr/src/server/error-summary.ts +37 -0
  611. package/examples/next-ssr/src/server/parse-owner.test.ts +39 -0
  612. package/examples/next-ssr/src/server/parse-owner.ts +34 -0
  613. package/examples/next-ssr/src/server/prefetch-ledgers.test.ts +137 -0
  614. package/examples/next-ssr/src/server/prefetch-ledgers.ts +70 -0
  615. package/examples/next-ssr/src/server/read-balances.test.ts +103 -0
  616. package/examples/next-ssr/src/server/read-balances.ts +78 -0
  617. package/examples/next-ssr/src/server/request-client.rsc.test.tsx +110 -0
  618. package/examples/next-ssr/src/server/request-client.ts +24 -0
  619. package/examples/next-ssr/src/testing/mock-ledgers.ts +115 -0
  620. package/examples/next-ssr/src/testing/react-server-dom-turbopack.d.ts +15 -0
  621. package/examples/next-ssr/src/testing/setup.ts +10 -0
  622. package/examples/next-ssr/tsconfig.json +31 -0
  623. package/examples/next-ssr/vitest.config.ts +59 -0
  624. package/examples/node-agent-tool/.stackblitzrc +4 -0
  625. package/examples/node-agent-tool/README.md +165 -0
  626. package/examples/node-agent-tool/icp.yaml +11 -0
  627. package/examples/node-agent-tool/icrc1.did +88 -0
  628. package/examples/node-agent-tool/package.json +32 -0
  629. package/examples/node-agent-tool/src/canisters/icrc1.envelope.json +840 -0
  630. package/examples/node-agent-tool/src/canisters/icrc1.ts +78 -0
  631. package/examples/node-agent-tool/src/cli.test.ts +64 -0
  632. package/examples/node-agent-tool/src/cli.ts +23 -0
  633. package/examples/node-agent-tool/src/command-line.ts +159 -0
  634. package/examples/node-agent-tool/src/commands/balance.ts +73 -0
  635. package/examples/node-agent-tool/src/commands/demo.test.ts +51 -0
  636. package/examples/node-agent-tool/src/commands/demo.ts +359 -0
  637. package/examples/node-agent-tool/src/commands/info.ts +69 -0
  638. package/examples/node-agent-tool/src/commands/reads.test.ts +133 -0
  639. package/examples/node-agent-tool/src/commands/resend.test.ts +363 -0
  640. package/examples/node-agent-tool/src/commands/transfer.test.ts +313 -0
  641. package/examples/node-agent-tool/src/commands/transfer.ts +415 -0
  642. package/examples/node-agent-tool/src/commands/watch.test.ts +159 -0
  643. package/examples/node-agent-tool/src/commands/watch.ts +135 -0
  644. package/examples/node-agent-tool/src/commands/whoami.ts +36 -0
  645. package/examples/node-agent-tool/src/context.ts +20 -0
  646. package/examples/node-agent-tool/src/dispatch.ts +70 -0
  647. package/examples/node-agent-tool/src/failure.test.ts +59 -0
  648. package/examples/node-agent-tool/src/failure.ts +176 -0
  649. package/examples/node-agent-tool/src/identity.test.ts +242 -0
  650. package/examples/node-agent-tool/src/identity.ts +228 -0
  651. package/examples/node-agent-tool/src/input.ts +110 -0
  652. package/examples/node-agent-tool/src/ledgers.test.ts +74 -0
  653. package/examples/node-agent-tool/src/ledgers.ts +62 -0
  654. package/examples/node-agent-tool/src/mock-ledger.ts +211 -0
  655. package/examples/node-agent-tool/src/network.test.ts +128 -0
  656. package/examples/node-agent-tool/src/network.ts +101 -0
  657. package/examples/node-agent-tool/src/output.test.ts +208 -0
  658. package/examples/node-agent-tool/src/output.ts +163 -0
  659. package/examples/node-agent-tool/src/run.ts +73 -0
  660. package/examples/node-agent-tool/src/test-kit.ts +167 -0
  661. package/examples/node-agent-tool/tsconfig.json +18 -0
  662. package/examples/node-agent-tool/vitest.config.ts +8 -0
  663. package/examples/vite-wallet/.stackblitzrc +4 -0
  664. package/examples/vite-wallet/Cargo.lock +646 -0
  665. package/examples/vite-wallet/Cargo.toml +5 -0
  666. package/examples/vite-wallet/README.md +107 -0
  667. package/examples/vite-wallet/backend/Cargo.toml +12 -0
  668. package/examples/vite-wallet/backend/backend.did +37 -0
  669. package/examples/vite-wallet/backend/src/lib.rs +133 -0
  670. package/examples/vite-wallet/icp.yaml +44 -0
  671. package/examples/vite-wallet/index.html +13 -0
  672. package/examples/vite-wallet/ledger.did +54 -0
  673. package/examples/vite-wallet/package.json +46 -0
  674. package/examples/vite-wallet/public/.ic-assets.json5 +26 -0
  675. package/examples/vite-wallet/scripts/faucet-args.test.ts +30 -0
  676. package/examples/vite-wallet/scripts/faucet-args.ts +41 -0
  677. package/examples/vite-wallet/scripts/faucet.ts +41 -0
  678. package/examples/vite-wallet/src/AddressBook.test.tsx +191 -0
  679. package/examples/vite-wallet/src/AddressBook.tsx +147 -0
  680. package/examples/vite-wallet/src/App.tsx +53 -0
  681. package/examples/vite-wallet/src/Balance.test.tsx +57 -0
  682. package/examples/vite-wallet/src/Balance.tsx +58 -0
  683. package/examples/vite-wallet/src/EnvironmentPanel.test.tsx +83 -0
  684. package/examples/vite-wallet/src/EnvironmentPanel.tsx +103 -0
  685. package/examples/vite-wallet/src/ErrorNote.tsx +70 -0
  686. package/examples/vite-wallet/src/Profile.test.tsx +145 -0
  687. package/examples/vite-wallet/src/Profile.tsx +92 -0
  688. package/examples/vite-wallet/src/SendIcp.test.tsx +231 -0
  689. package/examples/vite-wallet/src/SendIcp.tsx +244 -0
  690. package/examples/vite-wallet/src/SendToContact.test.tsx +113 -0
  691. package/examples/vite-wallet/src/SendToContact.tsx +102 -0
  692. package/examples/vite-wallet/src/SignIn.test.tsx +106 -0
  693. package/examples/vite-wallet/src/SignIn.tsx +120 -0
  694. package/examples/vite-wallet/src/Wallet.test.tsx +89 -0
  695. package/examples/vite-wallet/src/account-switch.test.tsx +108 -0
  696. package/examples/vite-wallet/src/auth/dev-accounts.test.ts +113 -0
  697. package/examples/vite-wallet/src/auth/dev-accounts.ts +216 -0
  698. package/examples/vite-wallet/src/auth/local-page.test.ts +28 -0
  699. package/examples/vite-wallet/src/auth/local-page.ts +20 -0
  700. package/examples/vite-wallet/src/auth/wallet-auth.test.ts +159 -0
  701. package/examples/vite-wallet/src/auth/wallet-auth.ts +131 -0
  702. package/examples/vite-wallet/src/canisters/backend.envelope.json +275 -0
  703. package/examples/vite-wallet/src/canisters/backend.ts +58 -0
  704. package/examples/vite-wallet/src/canisters/ledger.envelope.json +451 -0
  705. package/examples/vite-wallet/src/canisters/ledger.ts +56 -0
  706. package/examples/vite-wallet/src/client.ts +45 -0
  707. package/examples/vite-wallet/src/main.tsx +18 -0
  708. package/examples/vite-wallet/src/optimistic-contacts.ts +113 -0
  709. package/examples/vite-wallet/src/refusal.ts +17 -0
  710. package/examples/vite-wallet/src/styles.css +282 -0
  711. package/examples/vite-wallet/src/test/test-wallet.tsx +322 -0
  712. package/examples/vite-wallet/src/token.ts +50 -0
  713. package/examples/vite-wallet/src/transfer.test.ts +178 -0
  714. package/examples/vite-wallet/src/transfer.ts +110 -0
  715. package/examples/vite-wallet/src/use-canisters.ts +49 -0
  716. package/examples/vite-wallet/tsconfig.json +19 -0
  717. package/examples/vite-wallet/vite.config.ts +47 -0
  718. package/examples/vite-wallet/vitest.config.ts +17 -0
  719. package/package.json +9 -4
  720. package/packages/core/.size-limit.js +47 -0
  721. package/packages/core/LICENSE +21 -0
  722. package/packages/core/README.md +84 -0
  723. package/packages/core/llms.txt +610 -0
  724. package/packages/core/package.json +89 -0
  725. package/packages/core/src/call.ts +961 -0
  726. package/packages/core/src/canister.ts +259 -0
  727. package/packages/core/src/client.ts +2061 -0
  728. package/packages/core/src/errors.ts +1079 -0
  729. package/packages/core/src/hydration.ts +239 -0
  730. package/packages/core/src/index.ts +23 -0
  731. package/packages/core/src/keys.ts +108 -0
  732. package/packages/core/src/management.ts +138 -0
  733. package/packages/core/src/network.ts +1020 -0
  734. package/packages/core/src/options.ts +1000 -0
  735. package/packages/core/src/runtime.ts +50 -0
  736. package/packages/core/src/testing/fake-replica.ts +1166 -0
  737. package/packages/core/src/testing/index.ts +16 -0
  738. package/packages/core/src/testing/test-auth.ts +340 -0
  739. package/packages/core/src/testing/test-client.ts +559 -0
  740. package/packages/core/src/types.ts +541 -0
  741. package/packages/core/src/units.ts +299 -0
  742. package/packages/core/src/version.ts +4 -0
  743. package/packages/core/tests/canister-helpers.ts +187 -0
  744. package/packages/core/tests/canister-id.test.ts +158 -0
  745. package/packages/core/tests/canister-unwrap.test.ts +94 -0
  746. package/packages/core/tests/canister.test-d.ts +406 -0
  747. package/packages/core/tests/canister.test.ts +1921 -0
  748. package/packages/core/tests/client-account-change.test.ts +131 -0
  749. package/packages/core/tests/client-agents.test.ts +402 -0
  750. package/packages/core/tests/client-auth-network.test.ts +719 -0
  751. package/packages/core/tests/client-disposed.test.ts +403 -0
  752. package/packages/core/tests/client-helpers.ts +136 -0
  753. package/packages/core/tests/client-hydration.test.ts +166 -0
  754. package/packages/core/tests/client-pinned.test.ts +626 -0
  755. package/packages/core/tests/client-session.test.ts +348 -0
  756. package/packages/core/tests/client.test-d.ts +181 -0
  757. package/packages/core/tests/client.test.ts +1162 -0
  758. package/packages/core/tests/encode.test.ts +171 -0
  759. package/packages/core/tests/env-canister-id.test.ts +666 -0
  760. package/packages/core/tests/env-cookie-copies.test.ts +182 -0
  761. package/packages/core/tests/error-guard.test.ts +222 -0
  762. package/packages/core/tests/errors.test-d.ts +280 -0
  763. package/packages/core/tests/errors.test.ts +1359 -0
  764. package/packages/core/tests/fixtures/README.md +28 -0
  765. package/packages/core/tests/fixtures/accounts.did +21 -0
  766. package/packages/core/tests/fixtures/accounts.envelope.json +367 -0
  767. package/packages/core/tests/fixtures/accounts.ts +26 -0
  768. package/packages/core/tests/fixtures/archive.did +31 -0
  769. package/packages/core/tests/fixtures/archive.envelope.json +259 -0
  770. package/packages/core/tests/fixtures/archive.ts +55 -0
  771. package/packages/core/tests/fixtures/icrc1.did +88 -0
  772. package/packages/core/tests/fixtures/icrc1.envelope.json +840 -0
  773. package/packages/core/tests/fixtures/icrc1.ts +78 -0
  774. package/packages/core/tests/fixtures/management.did +724 -0
  775. package/packages/core/tests/fixtures/management.envelope.json +4455 -0
  776. package/packages/core/tests/fixtures/management.ts +486 -0
  777. package/packages/core/tests/fixtures/shapes.did +33 -0
  778. package/packages/core/tests/fixtures/shapes.envelope.json +440 -0
  779. package/packages/core/tests/fixtures/shapes.ts +56 -0
  780. package/packages/core/tests/fixtures/skippable.did +15 -0
  781. package/packages/core/tests/fixtures/skippable.envelope.json +182 -0
  782. package/packages/core/tests/fixtures/skippable.ts +33 -0
  783. package/packages/core/tests/func.test.ts +154 -0
  784. package/packages/core/tests/identity-attributes.test.ts +214 -0
  785. package/packages/core/tests/keys.test.ts +289 -0
  786. package/packages/core/tests/management.test.ts +206 -0
  787. package/packages/core/tests/network-helpers.ts +121 -0
  788. package/packages/core/tests/network.test-d.ts +78 -0
  789. package/packages/core/tests/network.test.ts +1051 -0
  790. package/packages/core/tests/options.test.ts +1594 -0
  791. package/packages/core/tests/redirect-sign-in.test.ts +393 -0
  792. package/packages/core/tests/resend.test-d.ts +81 -0
  793. package/packages/core/tests/resend.test.ts +723 -0
  794. package/packages/core/tests/skip.test-d.ts +125 -0
  795. package/packages/core/tests/testing-entry.test.ts +73 -0
  796. package/packages/core/tests/testing-fake-replica.test.ts +1242 -0
  797. package/packages/core/tests/testing-test-auth.test-d.ts +84 -0
  798. package/packages/core/tests/testing-test-auth.test.ts +483 -0
  799. package/packages/core/tests/testing-test-client.test-d.ts +184 -0
  800. package/packages/core/tests/testing-test-client.test.ts +1272 -0
  801. package/packages/core/tests/time-realm.test.ts +63 -0
  802. package/packages/core/tests/time.test.ts +238 -0
  803. package/packages/core/tests/traps/README.md +39 -0
  804. package/packages/core/tests/traps/anonymous-write.test.ts +145 -0
  805. package/packages/core/tests/traps/classification-table.test.ts +256 -0
  806. package/packages/core/tests/traps/err-arm.test.ts +144 -0
  807. package/packages/core/tests/traps/fetch-spy.ts +39 -0
  808. package/packages/core/tests/traps/invalidation-after-write.test.ts +178 -0
  809. package/packages/core/tests/traps/ledger.ts +248 -0
  810. package/packages/core/tests/traps/root-key-off-local.test.ts +130 -0
  811. package/packages/core/tests/traps/stale-data-across-users.test.ts +173 -0
  812. package/packages/core/tests/traps/unresolved-name.test.ts +155 -0
  813. package/packages/core/tests/traps/update-as-query.test.ts +244 -0
  814. package/packages/core/tests/traps/update-not-resent.test.ts +126 -0
  815. package/packages/core/tests/traps/update-resent-when-never-delivered.test.ts +159 -0
  816. package/packages/core/tests/traps.test-d.ts +476 -0
  817. package/packages/core/tests/units.test-d.ts +118 -0
  818. package/packages/core/tests/units.test.ts +634 -0
  819. package/packages/core/tsconfig.json +19 -0
  820. package/packages/core/tsconfig.typecheck.json +16 -0
  821. package/packages/core/vitest.config.ts +13 -0
  822. package/packages/mcp/LICENSE +21 -0
  823. package/packages/mcp/README.md +189 -0
  824. package/packages/mcp/package.json +62 -0
  825. package/packages/mcp/src/candid/candid-text.test.ts +455 -0
  826. package/packages/mcp/src/candid/candid-text.ts +501 -0
  827. package/packages/mcp/src/candid/contract.test.ts +398 -0
  828. package/packages/mcp/src/candid/formats.ts +155 -0
  829. package/packages/mcp/src/candid/hex.ts +29 -0
  830. package/packages/mcp/src/candid/json-schema.test.ts +758 -0
  831. package/packages/mcp/src/candid/json-schema.ts +454 -0
  832. package/packages/mcp/src/candid/json.test.ts +1207 -0
  833. package/packages/mcp/src/candid/json.ts +1053 -0
  834. package/packages/mcp/src/candid/schema-walk.ts +189 -0
  835. package/packages/mcp/src/candid/type-text.test.ts +179 -0
  836. package/packages/mcp/src/candid/type-text.ts +238 -0
  837. package/packages/mcp/src/cli.ts +134 -0
  838. package/packages/mcp/src/identity.ts +188 -0
  839. package/packages/mcp/src/interface/cache.test.ts +48 -0
  840. package/packages/mcp/src/interface/cache.ts +68 -0
  841. package/packages/mcp/src/interface/cli-cache.test.ts +150 -0
  842. package/packages/mcp/src/interface/cli-cache.ts +122 -0
  843. package/packages/mcp/src/interface/compile-worker.test.ts +246 -0
  844. package/packages/mcp/src/interface/compile-worker.ts +290 -0
  845. package/packages/mcp/src/interface/compile.test.ts +155 -0
  846. package/packages/mcp/src/interface/compile.ts +281 -0
  847. package/packages/mcp/src/interface/docs.test.ts +105 -0
  848. package/packages/mcp/src/interface/docs.ts +86 -0
  849. package/packages/mcp/src/interface/fixtures/icrc1.did +88 -0
  850. package/packages/mcp/src/interface/hex.ts +8 -0
  851. package/packages/mcp/src/interface/ids.test.ts +71 -0
  852. package/packages/mcp/src/interface/ids.ts +87 -0
  853. package/packages/mcp/src/interface/loader.test.ts +804 -0
  854. package/packages/mcp/src/interface/loader.ts +519 -0
  855. package/packages/mcp/src/interface/read-candid.test.ts +300 -0
  856. package/packages/mcp/src/interface/read-candid.ts +259 -0
  857. package/packages/mcp/src/interface/types.ts +113 -0
  858. package/packages/mcp/src/network.ts +122 -0
  859. package/packages/mcp/src/options.ts +149 -0
  860. package/packages/mcp/src/server/approval.ts +159 -0
  861. package/packages/mcp/src/server/naming.ts +43 -0
  862. package/packages/mcp/src/server/results.ts +102 -0
  863. package/packages/mcp/src/server/server.ts +797 -0
  864. package/packages/mcp/src/server/tools.ts +116 -0
  865. package/packages/mcp/src/usage.ts +40 -0
  866. package/packages/mcp/tests/approval.test.ts +60 -0
  867. package/packages/mcp/tests/identity.test.ts +234 -0
  868. package/packages/mcp/tests/naming.test.ts +62 -0
  869. package/packages/mcp/tests/options.test.ts +140 -0
  870. package/packages/mcp/tests/server.test.ts +997 -0
  871. package/packages/mcp/tsconfig.json +19 -0
  872. package/packages/mcp/tsconfig.typecheck.json +10 -0
  873. package/packages/mcp/vitest.config.ts +10 -0
  874. package/packages/react/LICENSE +21 -0
  875. package/packages/react/README.md +328 -0
  876. package/packages/react/llms.txt +95 -0
  877. package/packages/react/package.json +95 -0
  878. package/packages/react/src/index.tsx +678 -0
  879. package/packages/react/tests/abandoned-render.test.tsx +816 -0
  880. package/packages/react/tests/auth.test.tsx +315 -0
  881. package/packages/react/tests/caller-keys.test.tsx +2334 -0
  882. package/packages/react/tests/client-time.test.ts +40 -0
  883. package/packages/react/tests/entry.test.ts +52 -0
  884. package/packages/react/tests/helpers.tsx +291 -0
  885. package/packages/react/tests/hydration.test.tsx +262 -0
  886. package/packages/react/tests/ownership.test.tsx +260 -0
  887. package/packages/react/tests/provider.server.test.tsx +169 -0
  888. package/packages/react/tests/query-client.test.tsx +107 -0
  889. package/packages/react/tests/strict-mode.test.tsx +288 -0
  890. package/packages/react/tests/suspense.test-d.tsx +357 -0
  891. package/packages/react/tests/two-query-cores.test.tsx +135 -0
  892. package/packages/react/tests/types.test-d.tsx +63 -0
  893. package/packages/react/tsconfig.json +23 -0
  894. package/packages/react/tsconfig.test.json +8 -0
  895. package/packages/react/tsconfig.typecheck.json +16 -0
  896. package/packages/react/vitest.config.ts +39 -0
  897. package/packages/vite-plugin/LICENSE +21 -0
  898. package/packages/vite-plugin/README.md +532 -0
  899. package/packages/vite-plugin/package.json +76 -0
  900. package/packages/vite-plugin/src/describe-value.test.ts +43 -0
  901. package/packages/vite-plugin/src/describe-value.ts +167 -0
  902. package/packages/vite-plugin/src/dev-environment.test.ts +747 -0
  903. package/packages/vite-plugin/src/dev-environment.ts +510 -0
  904. package/packages/vite-plugin/src/env.ts +431 -0
  905. package/packages/vite-plugin/src/fetch.ts +348 -0
  906. package/packages/vite-plugin/src/file-identity.ts +106 -0
  907. package/packages/vite-plugin/src/generate.ts +691 -0
  908. package/packages/vite-plugin/src/index.test.ts +1243 -0
  909. package/packages/vite-plugin/src/index.ts +2565 -0
  910. package/packages/vite-plugin/src/interface.ts +339 -0
  911. package/packages/vite-plugin/src/local-host.ts +34 -0
  912. package/packages/vite-plugin/src/options.ts +641 -0
  913. package/packages/vite-plugin/src/principal-text.test.ts +87 -0
  914. package/packages/vite-plugin/src/principal-text.ts +98 -0
  915. package/packages/vite-plugin/tests/close.test.ts +141 -0
  916. package/packages/vite-plugin/tests/environment-mode.test.ts +136 -0
  917. package/packages/vite-plugin/tests/fake-ic.ts +214 -0
  918. package/packages/vite-plugin/tests/fetch-sdk.test.ts +27 -0
  919. package/packages/vite-plugin/tests/fetch.test.ts +1196 -0
  920. package/packages/vite-plugin/tests/fixtures/fake-cli/bin.js +90 -0
  921. package/packages/vite-plugin/tests/fixtures/fake-cli/package.json +8 -0
  922. package/packages/vite-plugin/tests/fixtures/icrc1.did +88 -0
  923. package/packages/vite-plugin/tests/generation.test.ts +1036 -0
  924. package/packages/vite-plugin/tests/icp-command.test.ts +194 -0
  925. package/packages/vite-plugin/tests/icp-timeout.test.ts +83 -0
  926. package/packages/vite-plugin/tests/no-process-exit.test.ts +83 -0
  927. package/packages/vite-plugin/tests/on-generated.test.ts +323 -0
  928. package/packages/vite-plugin/tests/output-collision.test.ts +329 -0
  929. package/packages/vite-plugin/tests/package.test.ts +62 -0
  930. package/packages/vite-plugin/tests/project.test.ts +2993 -0
  931. package/packages/vite-plugin/tests/support.ts +339 -0
  932. package/packages/vite-plugin/tests/timeout.test.ts +107 -0
  933. package/packages/vite-plugin/tsconfig.json +23 -0
  934. package/packages/vite-plugin/tsconfig.typecheck.json +16 -0
  935. package/packages/vite-plugin/vitest.config.ts +9 -0
  936. package/pnpm-workspace.yaml +23 -0
  937. package/scripts/ai-context-files.js +72 -0
  938. package/scripts/assemble-docs-site.mjs +485 -0
  939. package/scripts/assemble-docs-site.test.mjs +568 -0
  940. package/scripts/build-examples.js +58 -0
  941. package/scripts/check-ai-context.js +963 -0
  942. package/scripts/check-ai-context.test.mjs +811 -0
  943. package/scripts/check-exports.mjs +767 -0
  944. package/scripts/check-exports.test.mjs +1136 -0
  945. package/scripts/check-snippets/ambient.d.ts +428 -0
  946. package/scripts/check-snippets/app/generated/backend.did +7 -0
  947. package/scripts/check-snippets/app/generated/backend.ts +15 -0
  948. package/scripts/check-snippets/app/generated/icrc1.did +88 -0
  949. package/scripts/check-snippets/app/generated/icrc1.ts +78 -0
  950. package/scripts/check-snippets/app/globals.ts +26 -0
  951. package/scripts/check-snippets/docs/guides/App.tsx +21 -0
  952. package/scripts/check-snippets/docs/guides/app/providers.tsx +23 -0
  953. package/scripts/check-snippets/docs/guides/auth-client.ts +47 -0
  954. package/scripts/check-snippets/docs/guides/canisters/backend.ts +3 -0
  955. package/scripts/check-snippets/docs/guides/canisters/icrc1.ts +3 -0
  956. package/scripts/check-snippets/docs/guides/components/LedgerCard.tsx +26 -0
  957. package/scripts/check-snippets/docs/guides/components/shell.tsx +11 -0
  958. package/scripts/check-snippets/docs/guides/components/sign-in-page.tsx +29 -0
  959. package/scripts/check-snippets/docs/guides/components/slow-section.tsx +5 -0
  960. package/scripts/check-snippets/docs/guides/generated/accounts.ts +95 -0
  961. package/scripts/check-snippets/docs/guides/generated/ckbtc_minter.ts +40 -0
  962. package/scripts/check-snippets/docs/guides/generated/icp_ledger.ts +267 -0
  963. package/scripts/check-snippets/docs/guides/ledger.ts +10 -0
  964. package/scripts/check-snippets/docs/guides/server/request-client.ts +8 -0
  965. package/scripts/check-snippets.mjs +993 -0
  966. package/scripts/check-snippets.test.mjs +338 -0
  967. package/scripts/check-stack.mjs +501 -0
  968. package/scripts/check-stack.test.mjs +800 -0
  969. package/scripts/clean-node-modules.js +67 -0
  970. package/scripts/example-projects.js +58 -0
  971. package/scripts/export-budget.mjs +145 -0
  972. package/scripts/faults.json +6749 -0
  973. package/scripts/lib/fault-workspace.mjs +210 -0
  974. package/scripts/lib/io.mjs +29 -0
  975. package/scripts/lib/io.test.mjs +38 -0
  976. package/scripts/lib/markdown-fences.mjs +56 -0
  977. package/scripts/lib/markdown-fences.test.mjs +84 -0
  978. package/scripts/lib/package-exports.mjs +54 -0
  979. package/scripts/lib/package-exports.test.mjs +66 -0
  980. package/scripts/lib/release-pr-steps.mjs +47 -0
  981. package/scripts/release-tag.mjs +95 -0
  982. package/scripts/release-tag.test.mjs +278 -0
  983. package/scripts/release-workflow.test.mjs +98 -0
  984. package/scripts/release.js +167 -0
  985. package/scripts/release.test.mjs +347 -0
  986. package/scripts/removed-v3-names.js +125 -0
  987. package/scripts/size-app/.size-limit.js +90 -0
  988. package/scripts/size-app/core.js +3 -0
  989. package/scripts/size-app/package.json +24 -0
  990. package/scripts/size-app/react.js +4 -0
  991. package/scripts/size-app.test.mjs +73 -0
  992. package/scripts/sync-ai-context-versions.js +102 -0
  993. package/scripts/sync-example-versions.js +151 -0
  994. package/scripts/test-examples-published.mjs +1585 -0
  995. package/scripts/test-examples-published.test.mjs +1586 -0
  996. package/scripts/traps/any-method-vars-not-a-list.json +5 -0
  997. package/scripts/traps/canister-method-unknown.json +5 -0
  998. package/scripts/traps/client-says-who-calls-once.json +5 -0
  999. package/scripts/traps/client-says-who-calls.json +5 -0
  1000. package/scripts/traps/err-only-on-canister-err.json +14 -0
  1001. package/scripts/traps/format-units-refuses-missing-value.json +5 -0
  1002. package/scripts/traps/format-units-refuses-number.json +5 -0
  1003. package/scripts/traps/format-units-unknown-option.json +5 -0
  1004. package/scripts/traps/guard-err-is-the-methods.json +5 -0
  1005. package/scripts/traps/guard-false-keeps-every-kind.json +5 -0
  1006. package/scripts/traps/internals-not-exported.json +9 -0
  1007. package/scripts/traps/network-refuses-unknown-name.json +5 -0
  1008. package/scripts/traps/never-err-has-no-type.json +5 -0
  1009. package/scripts/traps/options-method-unknown.json +5 -0
  1010. package/scripts/traps/options-vars-wrong-type.json +5 -0
  1011. package/scripts/traps/parse-units-refuses-number.json +5 -0
  1012. package/scripts/traps/parse-units-unknown-option.json +5 -0
  1013. package/scripts/traps/principal-is-not-plain-text.json +14 -0
  1014. package/scripts/traps/query-options-refuses-oneway.json +5 -0
  1015. package/scripts/traps/query-options-refuses-update.json +5 -0
  1016. package/scripts/traps/refuse-next-unknown-option.json +5 -0
  1017. package/scripts/traps/resend-key-reads-the-methods-arg.json +5 -0
  1018. package/scripts/traps/resend-states-its-dedupe-key.json +5 -0
  1019. package/scripts/traps/suspense-refuses-argument-skip.json +5 -0
  1020. package/scripts/traps/suspense-refuses-skippable-read.json +5 -0
  1021. package/scripts/traps/suspense-refuses-vars-skip-fits.json +5 -0
  1022. package/scripts/traps/test-handler-method-unknown.json +5 -0
  1023. package/scripts/traps/test-handler-nat-is-bigint.json +5 -0
  1024. package/scripts/traps/test-handler-takes-the-domain-value.json +5 -0
  1025. package/scripts/traps/vars-of-two-arguments-are-the-tuple.json +5 -0
  1026. package/scripts/typecheck-examples.js +122 -0
  1027. package/scripts/verify-faults.mjs +375 -0
  1028. package/scripts/verify-faults.test.mjs +402 -0
  1029. package/scripts/verify-package-artifacts.mjs +590 -0
  1030. package/scripts/verify-peer-floors.js +399 -0
  1031. package/scripts/verify-peer-floors.test.mjs +422 -0
  1032. package/scripts/verify-test-fails-rules.mjs +104 -0
  1033. package/scripts/verify-test-fails-rules.test.mjs +215 -0
  1034. package/scripts/verify-test-fails.js +371 -0
  1035. package/scripts/verify-traps.mjs +505 -0
  1036. package/scripts/verify-traps.test.mjs +521 -0
  1037. package/scripts/verify-typescript-floor.js +239 -0
  1038. package/skill-packages/ic-reactor/SKILL.md +103 -0
  1039. package/stack.json +8 -0
  1040. package/tsconfig.base.json +23 -0
  1041. package/tsconfig.json +8 -0
@@ -0,0 +1,1585 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Runs every example against the @ic-reactor/* packages published on npm, the
4
+ * way someone who copies the example out of this repository gets them, and the
5
+ * way StackBlitz installs it.
6
+ *
7
+ * The examples job of CI runs the examples inside the workspace, where
8
+ * `linkWorkspacePackages` links each @ic-reactor/* range to packages/*. That
9
+ * proves the examples against the code on the branch, not against the release:
10
+ * an example that uses a name the published release lacks stays green there.
11
+ * This script tests against one dist-tag per run (see `resolveRun`): `beta`
12
+ * for a prerelease and `latest` for a stable release, of the `--wait-for`
13
+ * version or else of the branch's own. A run without `--wait-for` whose
14
+ * examples all wait on the branch's own, unpublished version (a release pull
15
+ * request, or its merge before the tag: `awaitsRelease`) runs only the checks
16
+ * that need no registry (`staticFindings`) and defers to the release's run.
17
+ * For each example, it:
18
+ *
19
+ * 1. copies its git-tracked files to a directory outside the repository,
20
+ * and refuses to run if a parent of that directory holds a node_modules
21
+ * or a package.json (Node, Vite and vitest resolve a bare import by
22
+ * walking up into a parent's node_modules, so an undeclared import would
23
+ * be found there);
24
+ * 2. refuses a `workspace:`, `file:`, `link:` or `portal:` range, which no
25
+ * standalone install resolves, and a tracked `.npmrc` (it could point the
26
+ * @ic-reactor scope at another registry, for this install and on
27
+ * StackBlitz); requires the `typecheck`, `test` and `build` scripts; and
28
+ * checks each @ic-reactor/* range is satisfied by the version the run's
29
+ * dist-tag names (asking npm, so its own semver decides);
30
+ * 3. installs from registry.npmjs.org with npm (no workspace, no links, no
31
+ * lockfile of ours), the default registry and the @ic-reactor and
32
+ * @meantjs scopes all pinned to it on the command line, over any
33
+ * `.npmrc`, with an environment that holds nothing of the repository: no
34
+ * `npm_*` or `pnpm_*` variable a `pnpm run` set, and no PATH entry
35
+ * inside the repository;
36
+ * 4. checks every installed @ic-reactor/* package is a real directory, not
37
+ * a symlink, at exactly that version, and that npm's lockfile
38
+ * records it as the registry's own tarball, with the integrity the
39
+ * registry publishes for that version (the proof the bytes are the
40
+ * published ones);
41
+ * 5. runs the example's `typecheck`, `test` and `build` scripts, as the
42
+ * examples job does (a Next example gets the same `next-env.d.ts` shim
43
+ * `typecheck-examples.js` writes);
44
+ * 6. runs the `startCommand` of its `.stackblitzrc`, the command StackBlitz
45
+ * runs after its install, under a model of what StackBlitz's WebContainer
46
+ * lacks (WEBCONTAINER_MODEL: no global `Iterator`, and an
47
+ * AsyncLocalStorage that keeps no store past the synchronous part of
48
+ * `run()`): `npm run dev [-- <args>]` is started, its first page fetched
49
+ * with every same-origin script on it and every app module those import
50
+ * (a TanStack Start example's from its router and route tree as well:
51
+ * `startEntrySeeds`), and the server stopped (a Next example with
52
+ * `NEXT_TEST_WASM=1`, so Next
53
+ * loads the WebAssembly bindings a WebContainer loads); any other command
54
+ * must exit 0, a script step 5 already ran on plain Node included.
55
+ *
56
+ * Every example's tests run without a replica (each is a `createTestClient()`
57
+ * over an in-memory one), so nothing here starts a network. The vite-wallet
58
+ * example needs icp-cli's local network to run the wallet itself, which is why
59
+ * its `.stackblitzrc` runs its tests instead of its dev server. next-ssr's
60
+ * runs its tests too: Next 16 renders no page in a WebContainer (see
61
+ * WEBCONTAINER_MODEL).
62
+ *
63
+ * Usage: node scripts/test-examples-published.mjs [--keep] [--tmp <dir>]
64
+ * [--wait-for <version>] [<example> ...]
65
+ * --keep leave the copies on disk and print where they are
66
+ * --tmp <dir> make the copies under <dir> (default: the OS tmpdir)
67
+ * --wait-for <version> wait (up to 10 minutes) until the dist-tag the
68
+ * release of <version> publishes under (`beta` for a
69
+ * prerelease, `latest` for a stable version) of core
70
+ * and of every @ic-reactor/* package the examples
71
+ * declare names <version> (a leading "v" is
72
+ * dropped), and the registry serves its integrity
73
+ * and its tarball: the release workflow runs this
74
+ * right after publishing, with the tag it published.
75
+ * Without it, the run tests the dist-tag of the
76
+ * branch's version (packages/core/package.json), or
77
+ * defers while the examples wait on that version's
78
+ * release
79
+ * <example> a directory under examples/ (default: every one)
80
+ */
81
+ import { execFileSync, spawn, spawnSync } from "node:child_process"
82
+ import {
83
+ copyFileSync,
84
+ existsSync,
85
+ lstatSync,
86
+ mkdirSync,
87
+ mkdtempSync,
88
+ readFileSync,
89
+ readdirSync,
90
+ realpathSync,
91
+ rmSync,
92
+ writeFileSync,
93
+ } from "node:fs"
94
+ import { createServer } from "node:net"
95
+ import { tmpdir } from "node:os"
96
+ import { delimiter, dirname, join, relative, resolve, sep } from "node:path"
97
+ import { setTimeout as sleep } from "node:timers/promises"
98
+ import { fileURLToPath } from "node:url"
99
+
100
+ import { discoverExampleDirs, root as repoRoot } from "./example-projects.js"
101
+
102
+ /** Where every install and every `npm view` goes, whatever ~/.npmrc says. */
103
+ export const REGISTRY = "https://registry.npmjs.org/"
104
+
105
+ /** The packages this repository publishes. */
106
+ export const SCOPE = "@ic-reactor/"
107
+
108
+ /** A version, or a tag of one: MAJOR.MINOR.PATCH, an optional -prerelease. */
109
+ const RELEASE_VERSION =
110
+ /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/
111
+
112
+ /**
113
+ * The dist-tag a run tests against.
114
+ *
115
+ * With `--wait-for`, the one the release of that version publishes under:
116
+ * `beta` for a prerelease (a `-` part after MAJOR.MINOR.PATCH, with or without
117
+ * a leading `v`), `latest` for a stable version. This mirrors the rule of
118
+ * `releaseFor` in scripts/release-tag.mjs, with which release.yml chooses the
119
+ * dist-tag it publishes under once the GA flip (#836) brings that file; the
120
+ * rule is repeated here rather than imported, so this script works with or
121
+ * without it.
122
+ *
123
+ * A run without `--wait-for` (push, pull request, weekly, manual) passes the
124
+ * branch's own version instead (see `resolveRun`), so it gets the tag of the
125
+ * branch's last release. With no value at all, `latest`.
126
+ *
127
+ * @param {string | undefined} waitFor the `--wait-for` value (or the
128
+ * branch's version), if any
129
+ * @returns {"latest" | "beta"}
130
+ * @throws {Error} when `waitFor` is not a version
131
+ */
132
+ export function distTagFor(waitFor) {
133
+ if (waitFor === undefined) return "latest"
134
+ const match = RELEASE_VERSION.exec(waitFor)
135
+ if (!match) {
136
+ throw new Error(
137
+ `--wait-for ${waitFor} is not a release version (MAJOR.MINOR.PATCH, with an optional -prerelease and no +build).`
138
+ )
139
+ }
140
+ return match[4] === undefined ? "latest" : "beta"
141
+ }
142
+
143
+ /** Range protocols that only resolve inside a workspace or on one disk. */
144
+ export const LOCAL_PROTOCOLS = ["workspace:", "file:", "link:", "portal:"]
145
+
146
+ /**
147
+ * The scopes pinned to REGISTRY on every npm command. `--registry` replaces
148
+ * only the default registry: a `@scope:registry=` setting in any `.npmrc`
149
+ * (the user's, or one in the project) still wins for its scope.
150
+ */
151
+ export const PINNED_SCOPES = ["@ic-reactor", "@meantjs"]
152
+
153
+ /** The registry flags of every npm command this script runs. */
154
+ export const REGISTRY_ARGS = [
155
+ `--registry=${REGISTRY}`,
156
+ ...PINNED_SCOPES.map((scope) => `--${scope}:registry=${REGISTRY}`),
157
+ ]
158
+
159
+ /** The scripts every example must have: what the examples job runs. */
160
+ export const REQUIRED_SCRIPTS = ["typecheck", "test", "build"]
161
+
162
+ /**
163
+ * Examples allowed to lack one of REQUIRED_SCRIPTS: { example: { script:
164
+ * reason } }. Empty: all five have all three.
165
+ */
166
+ export const SCRIPT_EXCEPTIONS = {}
167
+
168
+ const DEPENDENCY_FIELDS = [
169
+ "dependencies",
170
+ "devDependencies",
171
+ "optionalDependencies",
172
+ "peerDependencies",
173
+ ]
174
+
175
+ /** Same shim as typecheck-examples.js: `next build` writes the real one. */
176
+ const NEXT_ENV = `/// <reference types="next" />\n/// <reference types="next/image-types/global" />\n`
177
+
178
+ const MINUTE = 60_000
179
+
180
+ /**
181
+ * A model of what StackBlitz's WebContainer lacks, as the examples' start
182
+ * commands met it there (its `node --version` says v22.22.3), for a preload
183
+ * that `--require` puts into every Node process the start command starts:
184
+ *
185
+ * - No global `Iterator`: `typeof Iterator` is "undefined" there, though Node
186
+ * 22 defines it. jsdom 30.1 subclasses it, so all of vite-wallet's test
187
+ * files failed to start there with "ReferenceError: Iterator is not
188
+ * defined"; the examples pin jsdom 30.0.1.
189
+ * - An AsyncLocalStorage whose store is gone once `run()` returns, and so
190
+ * after any await: StackBlitz says WebContainer does not implement
191
+ * AsyncLocalStorage (stackblitz/starters#122), and next-ssr's `next dev`
192
+ * answered 500 there with "Invariant: Expected workStore to be
193
+ * initialized". Under the model `next dev` fails with the same stack, and
194
+ * `next build --webpack` fails at its first prerender.
195
+ *
196
+ * Under this model each of the two failures happens here as it did on
197
+ * StackBlitz, and what worked there (icrc-ledger's dev server, node-agent-tool's
198
+ * demo) still works. It is the two gaps the examples have met, not a
199
+ * WebContainer: a start command green under it can still meet another one.
200
+ */
201
+ export const WEBCONTAINER_MODEL = `"use strict"
202
+ // Written by scripts/test-examples-published.mjs: see WEBCONTAINER_MODEL there.
203
+ delete globalThis.Iterator
204
+ class AsyncLocalStorage {
205
+ #store = undefined
206
+ getStore() {
207
+ return this.#store
208
+ }
209
+ run(store, fn, ...args) {
210
+ const outer = this.#store
211
+ this.#store = store
212
+ try {
213
+ return fn(...args)
214
+ } finally {
215
+ this.#store = outer
216
+ }
217
+ }
218
+ exit(fn, ...args) {
219
+ return this.run(undefined, fn, ...args)
220
+ }
221
+ enterWith(store) {
222
+ this.#store = store
223
+ }
224
+ disable() {
225
+ this.#store = undefined
226
+ }
227
+ static bind(fn) {
228
+ return fn
229
+ }
230
+ static snapshot() {
231
+ return (fn, ...args) => fn(...args)
232
+ }
233
+ }
234
+ Object.defineProperty(require("node:async_hooks"), "AsyncLocalStorage", {
235
+ value: AsyncLocalStorage,
236
+ writable: true,
237
+ enumerable: true,
238
+ configurable: true,
239
+ })
240
+ require("node:module").syncBuiltinESMExports()
241
+ `
242
+
243
+ /**
244
+ * `env` with the preload at `preload` (WEBCONTAINER_MODEL) added to
245
+ * NODE_OPTIONS, which every Node process the start command starts inherits:
246
+ * vitest's workers and Next's servers included.
247
+ *
248
+ * @param {NodeJS.ProcessEnv} env
249
+ * @param {string} preload
250
+ * @returns {NodeJS.ProcessEnv}
251
+ */
252
+ export function webContainerEnv(env, preload) {
253
+ const option = `--require ${JSON.stringify(preload)}`
254
+ return {
255
+ ...env,
256
+ NODE_OPTIONS: env.NODE_OPTIONS ? `${env.NODE_OPTIONS} ${option}` : option,
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Every dependency a manifest declares, with the field it is declared in.
262
+ *
263
+ * @param {Record<string, any>} manifest
264
+ * @returns {{ field: string, name: string, range: string }[]}
265
+ */
266
+ export function declaredDependencies(manifest) {
267
+ return DEPENDENCY_FIELDS.flatMap((field) =>
268
+ Object.entries(manifest[field] ?? {}).map(([name, range]) => ({
269
+ field,
270
+ name,
271
+ range: String(range),
272
+ }))
273
+ )
274
+ }
275
+
276
+ /**
277
+ * What stops this manifest from installing standalone against the version
278
+ * `tag` names on npm (`version`). `satisfying(name, range)` resolves with the
279
+ * published versions of `name` the range accepts (npm's answer, in the
280
+ * script).
281
+ *
282
+ * @param {Record<string, any>} manifest
283
+ * @param {{
284
+ * tag: string,
285
+ * version: string,
286
+ * satisfying: (name: string, range: string) => Promise<string[]> | string[],
287
+ * }} options
288
+ * @returns {Promise<string[]>}
289
+ */
290
+ export async function checkManifest(manifest, { tag, version, satisfying }) {
291
+ const findings = []
292
+ for (const { field, name, range } of declaredDependencies(manifest)) {
293
+ const protocol = LOCAL_PROTOCOLS.find((p) => range.startsWith(p))
294
+ if (protocol) {
295
+ findings.push(
296
+ `${field}.${name} is "${range}": a ${protocol} range resolves only inside this repository, never in a standalone install or on StackBlitz`
297
+ )
298
+ continue
299
+ }
300
+ if (!name.startsWith(SCOPE)) continue
301
+ const versions = await satisfying(name, range)
302
+ if (!versions.includes(version)) {
303
+ findings.push(
304
+ `${field}.${name} is "${range}", which ${tag} (${version}) does not satisfy` +
305
+ (versions.length > 0
306
+ ? `: npm would install ${versions.at(-1)}`
307
+ : ": no published version satisfies it")
308
+ )
309
+ }
310
+ }
311
+ return findings
312
+ }
313
+
314
+ /**
315
+ * Whether the examples wait on a release that is not published yet, so that
316
+ * a run without `--wait-for` has nothing it can test. That is so when the
317
+ * branch's own version (`packages/core/package.json`, which `release.js`
318
+ * bumps, syncing every example to `^<version>`) is not among the registry's
319
+ * versions, and every @ic-reactor/* range of every example is exactly
320
+ * `^<version>`: a release pull request, or its merge before the tag publishes
321
+ * it. No published version can satisfy those ranges yet, and `release.yml`'s
322
+ * `examples-published` job tests the examples with `--wait-for` once the
323
+ * release is out. Any other range is checked as usual and fails as usual, and
324
+ * so does a local protocol (`workspace:`, `file:` …) on any dependency of any
325
+ * example, @ic-reactor or not: no deferral skips that check.
326
+ *
327
+ * @param {Record<string, any>[]} manifests the examples' package.json files
328
+ * @param {{ branchVersion: string | undefined, publishedVersions: string[] }} state
329
+ * @returns {boolean}
330
+ */
331
+ export function awaitsRelease(manifests, { branchVersion, publishedVersions }) {
332
+ if (!branchVersion || publishedVersions.includes(branchVersion)) return false
333
+ // A local protocol on any dependency, not only an @ic-reactor one, is what
334
+ // checkManifest refuses without asking the registry: never defer past it.
335
+ const local = manifests.some((manifest) =>
336
+ declaredDependencies(manifest).some(({ range }) =>
337
+ LOCAL_PROTOCOLS.some((protocol) => range.startsWith(protocol))
338
+ )
339
+ )
340
+ if (local) return false
341
+ // Every example must wait on the release itself: one with no @ic-reactor
342
+ // range, or any other range, can be tested now and is not deferred.
343
+ return (
344
+ manifests.length > 0 &&
345
+ manifests.every((manifest) => {
346
+ const ranges = declaredDependencies(manifest)
347
+ .filter(({ name }) => name.startsWith(SCOPE))
348
+ .map(({ range }) => range)
349
+ return (
350
+ ranges.length > 0 &&
351
+ ranges.every((range) => range === `^${branchVersion}`)
352
+ )
353
+ })
354
+ )
355
+ }
356
+
357
+ /**
358
+ * The @ic-reactor/* packages installed in `projectDir`, and what is wrong with
359
+ * them: one the manifest declares that is missing, a symlink (a link into a
360
+ * workspace, not a package from the registry), or a version other than
361
+ * `expectedVersion`, the one `tag` names.
362
+ *
363
+ * @param {string} projectDir
364
+ * @param {string[]} declared the @ic-reactor/* names the manifest declares
365
+ * @param {string} expectedVersion
366
+ * @param {string} tag the dist-tag that names `expectedVersion`
367
+ * @returns {{ installed: { name: string, version: string }[], findings: string[] }}
368
+ */
369
+ export function checkInstalled(projectDir, declared, expectedVersion, tag) {
370
+ const scopeDir = join(projectDir, "node_modules", SCOPE.slice(0, -1))
371
+ const present = existsSync(scopeDir)
372
+ ? readdirSync(scopeDir).map((entry) => `${SCOPE}${entry}`)
373
+ : []
374
+ const names = [...new Set([...declared, ...present])].sort()
375
+ const installed = []
376
+ const findings = []
377
+ for (const name of names) {
378
+ const dir = join(projectDir, "node_modules", name)
379
+ let stat
380
+ try {
381
+ stat = lstatSync(dir)
382
+ } catch {
383
+ findings.push(`${name} is declared but not installed`)
384
+ continue
385
+ }
386
+ if (stat.isSymbolicLink()) {
387
+ findings.push(
388
+ `${name} is a symlink (to ${realpathSync(dir)}), not a package installed from the registry`
389
+ )
390
+ continue
391
+ }
392
+ if (!stat.isDirectory()) {
393
+ findings.push(`${name} is not a directory`)
394
+ continue
395
+ }
396
+ let version
397
+ try {
398
+ version = JSON.parse(
399
+ readFileSync(join(dir, "package.json"), "utf8")
400
+ ).version
401
+ } catch {
402
+ findings.push(`${name} has no readable package.json`)
403
+ continue
404
+ }
405
+ installed.push({ name, version })
406
+ if (version !== expectedVersion) {
407
+ findings.push(
408
+ `${name} installed at ${version}, not ${expectedVersion} (${tag})`
409
+ )
410
+ }
411
+ }
412
+ return { installed, findings }
413
+ }
414
+
415
+ /** The @ic-reactor/* entries of a lockfile's `packages`, nested ones too. */
416
+ export function lockedScopePackages(lock) {
417
+ const scope = SCOPE.slice(0, -1)
418
+ return Object.entries(lock?.packages ?? {})
419
+ .map(([path, entry]) => {
420
+ const match = path.match(/(?:^|\/)node_modules\/(@[^/]+\/[^/]+)$/)
421
+ return match && match[1].startsWith(`${scope}/`)
422
+ ? { path, name: match[1], entry }
423
+ : undefined
424
+ })
425
+ .filter(Boolean)
426
+ }
427
+
428
+ /**
429
+ * What shows that an @ic-reactor/* package npm installed is not the registry's
430
+ * published tarball: a lockfile entry that is a link, whose `resolved` is not
431
+ * the tarball the registry names for that version, or whose `integrity` is not
432
+ * the one it publishes. Also an installed package the lockfile does not
433
+ * record. `published` is the registry's `dist` for each name at the version
434
+ * under test.
435
+ *
436
+ * @param {Record<string, any> | undefined} lock package-lock.json
437
+ * @param {{
438
+ * installed: string[],
439
+ * published: Record<string, { tarball: string, integrity: string }>,
440
+ * }} options
441
+ * @returns {string[]}
442
+ */
443
+ export function checkLockfile(lock, { installed, published }) {
444
+ if (!lock || typeof lock.packages !== "object") {
445
+ return [
446
+ "npm wrote no package-lock.json with a `packages` map, so where the @ic-reactor/* packages came from is unproven",
447
+ ]
448
+ }
449
+ const findings = []
450
+ const entries = lockedScopePackages(lock)
451
+ for (const name of installed) {
452
+ if (!entries.some((e) => e.path === `node_modules/${name}`)) {
453
+ findings.push(
454
+ `${name} is installed but package-lock.json does not record it`
455
+ )
456
+ }
457
+ }
458
+ for (const { path, name, entry } of entries) {
459
+ const dist = published[name]
460
+ if (entry.link) {
461
+ findings.push(
462
+ `${path} is a link (to ${entry.resolved}) in package-lock.json, not a tarball from the registry`
463
+ )
464
+ continue
465
+ }
466
+ if (!dist) {
467
+ findings.push(
468
+ `${path} is ${entry.version}: the registry's tarball for it was not looked up`
469
+ )
470
+ continue
471
+ }
472
+ if (entry.resolved !== dist.tarball || !dist.tarball.startsWith(REGISTRY)) {
473
+ findings.push(
474
+ `${path} was resolved from ${entry.resolved ?? "nowhere"}, not ${dist.tarball}`
475
+ )
476
+ }
477
+ if (entry.integrity !== dist.integrity) {
478
+ findings.push(
479
+ `${path} has integrity ${entry.integrity ?? "(none)"}, not the registry's ${dist.integrity}`
480
+ )
481
+ }
482
+ }
483
+ return findings
484
+ }
485
+
486
+ /**
487
+ * The example's tracked files that change how npm resolves its packages: a
488
+ * `.npmrc` can point a scope at another registry, for the install here and
489
+ * for StackBlitz's.
490
+ *
491
+ * @param {string[]} files paths relative to the example
492
+ * @returns {string[]}
493
+ */
494
+ export function trackedConfigFindings(files) {
495
+ return files
496
+ .filter((file) => file.split("/").at(-1) === ".npmrc")
497
+ .map(
498
+ (file) =>
499
+ `${file} is tracked: an example's .npmrc could point @ic-reactor/* at another registry, here and on StackBlitz, so none is allowed`
500
+ )
501
+ }
502
+
503
+ /**
504
+ * Whether `scripts` defines `name` as npm runs it: a non-empty string. npm
505
+ * skips any other value, and `npm run <name>` then fails with "Missing script".
506
+ *
507
+ * @param {Record<string, unknown> | undefined} scripts
508
+ * @param {string} name
509
+ * @returns {boolean}
510
+ */
511
+ export function definesScript(scripts, name) {
512
+ const value =
513
+ scripts && Object.hasOwn(scripts, name) ? scripts[name] : undefined
514
+ return typeof value === "string" && value.trim() !== ""
515
+ }
516
+
517
+ /**
518
+ * The required scripts an example lacks (a script is defined only as a
519
+ * non-empty string: `definesScript`), unless `exceptions` names them.
520
+ *
521
+ * @param {string} example
522
+ * @param {Record<string, string> | undefined} scripts
523
+ * @param {Record<string, Record<string, string>>} [exceptions]
524
+ * @returns {string[]}
525
+ */
526
+ export function requiredScriptFindings(
527
+ example,
528
+ scripts,
529
+ exceptions = SCRIPT_EXCEPTIONS
530
+ ) {
531
+ return REQUIRED_SCRIPTS.filter(
532
+ (script) =>
533
+ !definesScript(scripts, script) && !exceptions[example]?.[script]
534
+ ).map(
535
+ (script) =>
536
+ `package.json has no "${script}" script: every example runs typecheck, test and build here (an exception goes in SCRIPT_EXCEPTIONS, with its reason)`
537
+ )
538
+ }
539
+
540
+ /**
541
+ * The parents of `dir` holding a node_modules or a package.json, from which
542
+ * Node, Vite or vitest would resolve an import the example does not declare.
543
+ * Walks up to the filesystem root, or to `stopAt` (included).
544
+ *
545
+ * @param {string} dir
546
+ * @param {{ stopAt?: string }} [options]
547
+ * @returns {string[]}
548
+ */
549
+ export function ancestorFindings(dir, { stopAt } = {}) {
550
+ const findings = []
551
+ let current = resolve(dir)
552
+ const last = stopAt === undefined ? undefined : resolve(stopAt)
553
+ while (current !== last) {
554
+ const parent = dirname(current)
555
+ if (parent === current) break
556
+ current = parent
557
+ for (const entry of ["node_modules", "package.json"]) {
558
+ if (existsSync(join(current, entry))) {
559
+ findings.push(
560
+ `${join(current, entry)} is above the scratch directory: an import the example does not declare would resolve there (pass --tmp <dir> with no node_modules or package.json above it)`
561
+ )
562
+ }
563
+ }
564
+ }
565
+ return findings
566
+ }
567
+
568
+ /**
569
+ * A child environment that holds nothing of this repository. A `pnpm run`
570
+ * sets `npm_*` variables (the workspace's config and package among them) and
571
+ * puts the repository's `node_modules/.bin` on PATH, where a binary the
572
+ * example failed to install would still be found.
573
+ *
574
+ * @param {NodeJS.ProcessEnv} env
575
+ * @param {string} root the repository root
576
+ * @returns {NodeJS.ProcessEnv}
577
+ */
578
+ export function isolatedEnv(env, root) {
579
+ const inside = (entry) => {
580
+ const rel = relative(root, resolve(entry))
581
+ return rel === "" || (!rel.startsWith("..") && !rel.startsWith(sep))
582
+ }
583
+ const out = {}
584
+ for (const [key, value] of Object.entries(env)) {
585
+ if (value === undefined) continue
586
+ if (/^(npm|pnpm)_/i.test(key)) continue
587
+ if (["NODE_PATH", "INIT_CWD", "PNPM_SCRIPT_SRC_DIR"].includes(key)) continue
588
+ out[key] = value
589
+ }
590
+ out.PATH = (env.PATH ?? "")
591
+ .split(delimiter)
592
+ .filter((entry) => entry && !inside(entry))
593
+ .join(delimiter)
594
+ out.npm_config_registry = REGISTRY
595
+ out.npm_config_update_notifier = "false"
596
+ return out
597
+ }
598
+
599
+ /**
600
+ * The checks that need no registry, for one example: its tracked config files
601
+ * (`trackedConfigFindings`), its required scripts (`requiredScriptFindings`)
602
+ * and its `.stackblitzrc` start command (`stackblitzStartCommand`'s finding,
603
+ * and the npm script it names: `startScriptFindings`).
604
+ * `testExample` runs them on the copy before installing, and `deferredRun`
605
+ * runs them on the checkout when a run defers to the release
606
+ * (`awaitsRelease`), so a deferral never skips them.
607
+ *
608
+ * @param {string} name the example
609
+ * @param {{ files: string[], scripts: Record<string, string> | undefined, start: { finding?: string } }} example
610
+ * @returns {string[]}
611
+ */
612
+ export function staticFindings(name, { files, scripts, start }) {
613
+ return [
614
+ ...trackedConfigFindings(files),
615
+ ...requiredScriptFindings(name, scripts),
616
+ ...(start.finding ? [start.finding] : []),
617
+ ...startScriptFindings(start.command, { files, scripts }),
618
+ ]
619
+ }
620
+
621
+ /**
622
+ * A start command must be a plain npm script command, `npm run <script>`
623
+ * (or `npm run-script`, or a bare lifecycle command: `npm test`/`npm t`,
624
+ * `npm start`, `npm stop`, `npm restart`), optionally with
625
+ * arguments after a bare `--`, naming a script the example defines. npm's one
626
+ * default, `npm start` with no `start` script, runs `node server.js`, so it
627
+ * passes when `server.js` is tracked. Anything else is refused, npm options
628
+ * (`--loglevel=silent`) and other programs (`node x.js`, `npx vite`)
629
+ * included: this checks the command without running it, so it accepts only
630
+ * the form it can check (it fails closed).
631
+ *
632
+ * @param {string | undefined} command the `.stackblitzrc` start command
633
+ * @param {{ files: string[], scripts: Record<string, string> | undefined }} example
634
+ * @returns {string[]}
635
+ */
636
+ export function startScriptFindings(command, { files, scripts }) {
637
+ if (!command) return []
638
+ const parsed = parseNpmCommand(command)
639
+ if (!parsed) {
640
+ return [
641
+ `.stackblitzrc's start command "${command}" is not a plain npm script command: write it as "npm run <script>" (arguments after a bare "--"), so its script can be checked`,
642
+ ]
643
+ }
644
+ if (definesScript(scripts, parsed.script)) return []
645
+ if (parsed.script === "start" && files.includes("server.js")) return []
646
+ return [
647
+ `.stackblitzrc's start command "${command}" runs the npm script "${parsed.script}", which package.json does not define`,
648
+ ]
649
+ }
650
+
651
+ /**
652
+ * The command StackBlitz runs after installing, from `.stackblitzrc`.
653
+ *
654
+ * @param {string} projectDir
655
+ * @returns {{ command?: string, finding?: string }}
656
+ */
657
+ export function stackblitzStartCommand(projectDir) {
658
+ const file = join(projectDir, ".stackblitzrc")
659
+ if (!existsSync(file)) {
660
+ return {
661
+ finding:
662
+ ".stackblitzrc is missing: StackBlitz's own choice of start command is not checked here, so each example names its own",
663
+ }
664
+ }
665
+ let config
666
+ try {
667
+ config = JSON.parse(readFileSync(file, "utf8"))
668
+ } catch (error) {
669
+ return { finding: `.stackblitzrc is not JSON: ${error.message}` }
670
+ }
671
+ if (typeof config.startCommand !== "string" || !config.startCommand.trim()) {
672
+ return { finding: ".stackblitzrc has no startCommand string" }
673
+ }
674
+ return { command: config.startCommand.trim() }
675
+ }
676
+
677
+ /**
678
+ * npm's bare commands that run the package script of the same name: the
679
+ * lifecycle scripts, and `t` for `test`. Any other script runs only as
680
+ * `npm run <script>`: `npm dev` is an unknown command to npm.
681
+ */
682
+ const NPM_LIFECYCLE_COMMANDS = {
683
+ test: "test",
684
+ t: "test",
685
+ start: "start",
686
+ stop: "stop",
687
+ restart: "restart",
688
+ }
689
+
690
+ /**
691
+ * The package script a start command runs, and the arguments it passes after
692
+ * `--`. `npm run <script>` (or `npm run-script`) for any script, and the bare
693
+ * lifecycle commands (`npm test`, `npm t`, `npm start`, `npm stop`, `npm
694
+ * restart`) for theirs; `npm test` and `npm run test` are the same script.
695
+ * A script name is any unquoted word not starting with `-` (an npm option):
696
+ * `npm run dev.web` names `dev.web`. Anything else, `npm dev` included, is
697
+ * not a script command.
698
+ *
699
+ * @param {string} command
700
+ * @returns {{ script: string, args: string[] } | undefined}
701
+ */
702
+ export function parseNpmCommand(command) {
703
+ const match = command.match(
704
+ /^npm\s+(?:(run(?:-script)?)\s+)?([^\s-]\S*)(?:\s+--((?:\s+\S+)*))?\s*$/
705
+ )
706
+ if (!match) return undefined
707
+ const [, run, name, rest] = match
708
+ if (name === "run" || name === "run-script") return undefined
709
+ const script = run ? name : NPM_LIFECYCLE_COMMANDS[name]
710
+ if (!script) return undefined
711
+ const args = (rest ?? "").split(/\s+/).filter(Boolean)
712
+ return { script, args }
713
+ }
714
+
715
+ /**
716
+ * The same-origin scripts a page loads, as absolute URLs, each with whether it
717
+ * is an ES module (`type="module"`).
718
+ *
719
+ * @param {string} html
720
+ * @param {string} pageUrl
721
+ * @returns {{ url: string, module: boolean }[]}
722
+ */
723
+ export function pageScripts(html, pageUrl) {
724
+ const origin = new URL(pageUrl).origin
725
+ const seen = new Set()
726
+ const scripts = []
727
+ for (const match of html.matchAll(/<script\b([^>]*)>/gi)) {
728
+ const src = match[1].match(/\bsrc="([^"]+)"/i)?.[1]
729
+ if (!src) continue
730
+ const url = new URL(src.replaceAll("&amp;", "&"), pageUrl)
731
+ if (url.origin !== origin || seen.has(url.href)) continue
732
+ seen.add(url.href)
733
+ scripts.push({
734
+ url: url.href,
735
+ module: /\btype=["']?module\b/i.test(match[1]),
736
+ })
737
+ }
738
+ return scripts
739
+ }
740
+
741
+ /**
742
+ * The app modules an ES module served by a Vite dev server imports, as
743
+ * absolute URLs: its static `import`/`export ... from` and string `import()`
744
+ * specifiers on its own origin. A statement starts a line or follows a `;`:
745
+ * Vite joins its HMR preamble and the module's first statement onto one line
746
+ * (`... from "/@vite/client";import { A } from "/src/A.tsx";`). Only
747
+ * root-relative specifiers are taken: Vite serves every import it resolved as
748
+ * one (`/src/...`), so a relative one left in served code is text in a string
749
+ * or a comment (a code sample in a template literal), not an import.
750
+ * Pre-bundled dependencies (`/node_modules/`) and the dev server's own modules
751
+ * (`/@vite/client`, `/@id/...`, `/@fs/...`) are left out: they are not the
752
+ * example's code, and a dependency re-optimisation could answer them 504
753
+ * while it runs.
754
+ *
755
+ * @param {string} code
756
+ * @param {string} moduleUrl
757
+ * @returns {string[]}
758
+ */
759
+ export function moduleImports(code, moduleUrl) {
760
+ const origin = new URL(moduleUrl).origin
761
+ const specifiers = [
762
+ ...code.matchAll(
763
+ /(?:^|;)[ \t]*(?:import|export)[ \t\n{*][^'"`;]*?\bfrom[ \t]*["']([^"'\n]+)["']/gm
764
+ ),
765
+ ...code.matchAll(/(?:^|;)[ \t]*import[ \t]*["']([^"'\n]+)["']/gm),
766
+ ...code.matchAll(/\bimport\([ \t]*["']([^"'\n]+)["'][ \t]*\)/g),
767
+ ].map((match) => match[1])
768
+ const urls = new Set()
769
+ for (const specifier of specifiers) {
770
+ if (!specifier.startsWith("/")) continue
771
+ const url = new URL(specifier, moduleUrl)
772
+ if (url.origin !== origin) continue
773
+ if (/^\/(?:node_modules\/|@)/.test(url.pathname)) continue
774
+ urls.add(url.href)
775
+ }
776
+ return [...urls]
777
+ }
778
+
779
+ /**
780
+ * The app's own entry modules of a TanStack Start example, from which the walk
781
+ * also starts: its router (what `#tanstack-router-entry` resolves to) and the
782
+ * route tree TanStack Router generates. Each is seeded only when the example
783
+ * tracks it.
784
+ */
785
+ export const START_ENTRY_FILES = [
786
+ "src/router.tsx",
787
+ "src/router.ts",
788
+ "src/router.jsx",
789
+ "src/router.js",
790
+ "src/routeTree.gen.ts",
791
+ ]
792
+
793
+ /**
794
+ * The modules the walk also starts from when the page's scripts are a TanStack
795
+ * Start dev entry (a `/@id/virtual:tanstack-start-*` URL): that entry reaches
796
+ * the app only through @tanstack/react-start's own modules under `/@fs/`,
797
+ * which `moduleImports` leaves out, so without a seed not one module of the
798
+ * example's would be fetched. The seeds are START_ENTRY_FILES the example
799
+ * tracks, as URLs on the page's origin; a finding when it tracks none. No
800
+ * seeds for any other page.
801
+ *
802
+ * @param {{ url: string }[]} scripts the page's scripts (`pageScripts`)
803
+ * @param {string[]} files the example's tracked files, relative to it
804
+ * @returns {{ seeds: string[], finding?: string }}
805
+ */
806
+ export function startEntrySeeds(scripts, files) {
807
+ const entry = scripts.find(({ url }) =>
808
+ new URL(url).pathname.startsWith("/@id/virtual:tanstack-start-")
809
+ )
810
+ if (!entry) return { seeds: [] }
811
+ const seeds = START_ENTRY_FILES.filter((file) => files.includes(file)).map(
812
+ (file) => new URL(`/${file}`, entry.url).href
813
+ )
814
+ if (seeds.length > 0) return { seeds }
815
+ return {
816
+ seeds,
817
+ finding: `the page's script ${entry.url} is TanStack Start's dev entry, which reaches the app only through /@fs/, and the example tracks none of ${START_ENTRY_FILES.join(", ")} to start the walk from`,
818
+ }
819
+ }
820
+
821
+ /** `npm view <spec> <field> --json`, from the registry; undefined on E404. */
822
+ function npmView(spec, field) {
823
+ const result = spawnSync(
824
+ "npm",
825
+ ["view", spec, field, "--json", ...REGISTRY_ARGS],
826
+ { encoding: "utf8", env: isolatedEnv(process.env, repoRoot) }
827
+ )
828
+ if (result.status !== 0) {
829
+ if (/E404/.test(result.stdout + result.stderr)) return undefined
830
+ throw new Error(
831
+ `npm view ${spec} ${field} failed: ${result.stderr || result.stdout}`
832
+ )
833
+ }
834
+ return result.stdout.trim() ? JSON.parse(result.stdout) : undefined
835
+ }
836
+
837
+ /** The version a dist-tag names, from the registry. */
838
+ function distTagVersion(name, tag, view = npmView) {
839
+ const version = view(`${name}@${tag}`, "version")
840
+ if (typeof version !== "string") {
841
+ throw new Error(`${name} has no ${tag} dist-tag on ${REGISTRY}`)
842
+ }
843
+ return version
844
+ }
845
+
846
+ /** The published versions of `name` that `range` accepts, from the registry. */
847
+ function npmSatisfying(name, range) {
848
+ const parsed = npmView(`${name}@${range}`, "version")
849
+ if (parsed === undefined) return []
850
+ return Array.isArray(parsed) ? parsed : [parsed]
851
+ }
852
+
853
+ /** The registry's tarball URL and integrity for each name at `version`. */
854
+ function publishedDist(names, version) {
855
+ const out = {}
856
+ for (const name of names) {
857
+ const dist = npmView(`${name}@${version}`, "dist")
858
+ if (dist?.tarball && dist?.integrity) {
859
+ out[name] = { tarball: dist.tarball, integrity: dist.integrity }
860
+ }
861
+ }
862
+ return out
863
+ }
864
+
865
+ /** The example's git-tracked files, relative to it. */
866
+ function trackedFiles(name) {
867
+ const prefix = `examples/${name}`
868
+ return execFileSync("git", ["-C", repoRoot, "ls-files", "-z", "--", prefix], {
869
+ encoding: "utf8",
870
+ })
871
+ .split("\0")
872
+ .filter(Boolean)
873
+ .map((file) => relative(prefix, file))
874
+ }
875
+
876
+ /** Copies the example's git-tracked files to `dest`. */
877
+ function copyTracked(name, files, dest) {
878
+ const prefix = join(repoRoot, "examples", name)
879
+ for (const file of files) {
880
+ const source = join(prefix, file)
881
+ if (!existsSync(source)) continue
882
+ const target = join(dest, file)
883
+ mkdirSync(dirname(target), { recursive: true })
884
+ copyFileSync(source, target)
885
+ }
886
+ return files.length
887
+ }
888
+
889
+ function seconds(ms) {
890
+ return `${(ms / 1000).toFixed(1)}s`
891
+ }
892
+
893
+ /** Runs one command with its output shown, and times it. */
894
+ function runStep(label, command, args, cwd, env, timeoutMs = 15 * MINUTE) {
895
+ console.log(`\n ▶ ${label}: ${[command, ...args].join(" ")}`)
896
+ const started = Date.now()
897
+ const result = spawnSync(command, args, {
898
+ cwd,
899
+ env,
900
+ stdio: "inherit",
901
+ timeout: timeoutMs,
902
+ killSignal: "SIGKILL",
903
+ })
904
+ const ms = Date.now() - started
905
+ const ok = result.status === 0
906
+ if (!ok) {
907
+ const why = result.error
908
+ ? result.error.message
909
+ : result.signal
910
+ ? `killed by ${result.signal}`
911
+ : `exit ${result.status}`
912
+ console.error(` ✗ ${label} failed (${why}) after ${seconds(ms)}`)
913
+ }
914
+ return { ok, ms }
915
+ }
916
+
917
+ function freePort() {
918
+ return new Promise((resolvePort, reject) => {
919
+ const server = createServer()
920
+ server.unref()
921
+ server.on("error", reject)
922
+ server.listen(0, () => {
923
+ const { port } = server.address()
924
+ server.close(() => resolvePort(port))
925
+ })
926
+ })
927
+ }
928
+
929
+ /** Ends a detached child and everything it started. */
930
+ async function killGroup(child) {
931
+ if (child.exitCode !== null || child.signalCode !== null) return
932
+ const exited = new Promise((done) => child.once("exit", done))
933
+ try {
934
+ process.kill(-child.pid, "SIGTERM")
935
+ } catch {
936
+ return
937
+ }
938
+ const timedOut = await Promise.race([
939
+ exited.then(() => false),
940
+ sleep(5000).then(() => true),
941
+ ])
942
+ if (timedOut) {
943
+ try {
944
+ process.kill(-child.pid, "SIGKILL")
945
+ } catch {
946
+ // already gone
947
+ }
948
+ await exited
949
+ }
950
+ }
951
+
952
+ /** At most this many app modules are fetched from one dev server. */
953
+ const MODULE_LIMIT = 500
954
+
955
+ /**
956
+ * Fetches the page's scripts and the `seeds` (`startEntrySeeds`) and, from
957
+ * each ES module among them, every app module it imports, transitively: a
958
+ * Vite dev server compiles a module only when it is requested, so a module
959
+ * below the entry that fails to transform (an unresolvable import, say)
960
+ * answers 500 only when fetched.
961
+ */
962
+ async function loadScripts(scripts, deadline, seeds = []) {
963
+ const queue = [
964
+ ...scripts.map((s) => ({ ...s, from: "the page" })),
965
+ ...seeds.map((url) => ({
966
+ url,
967
+ module: true,
968
+ from: "TanStack Start's dev entry, through /@fs/ (seeded)",
969
+ })),
970
+ ]
971
+ const seen = new Set(queue.map((s) => s.url))
972
+ const broken = []
973
+ let modules = 0
974
+ while (queue.length > 0) {
975
+ const { url, module, from } = queue.shift()
976
+ const res = await fetch(url, {
977
+ signal: AbortSignal.timeout(Math.max(1000, deadline - Date.now())),
978
+ })
979
+ const code = await res.text()
980
+ if (!res.ok) {
981
+ broken.push(`${url} (${res.status}, imported by ${from})`)
982
+ continue
983
+ }
984
+ if (!module) continue
985
+ modules++
986
+ for (const next of moduleImports(code, url)) {
987
+ if (seen.has(next) || seen.size >= MODULE_LIMIT) continue
988
+ seen.add(next)
989
+ queue.push({ url: next, module: true, from: url })
990
+ }
991
+ }
992
+ const app = [...seen].filter((url) =>
993
+ new URL(url).pathname.startsWith("/src/")
994
+ ).length
995
+ return { broken, fetched: seen.size, modules, app }
996
+ }
997
+
998
+ /**
999
+ * Starts `npm run dev -- <args> --port N` on a free port, fetches its first
1000
+ * page and what that page loads, and stops it. The port is passed as
1001
+ * `--port`, which both Vite and Next take, so a server already on the
1002
+ * example's own port on this machine does not fail the run. `files`, the
1003
+ * example's tracked files, are where a TanStack Start example's entry modules
1004
+ * are found (`startEntrySeeds`).
1005
+ */
1006
+ async function smokeDevServer(
1007
+ cwd,
1008
+ env,
1009
+ extraArgs,
1010
+ files,
1011
+ timeoutMs = 4 * MINUTE
1012
+ ) {
1013
+ const port = await freePort()
1014
+ const url = `http://localhost:${port}/`
1015
+ const args = ["run", "dev", "--", ...extraArgs, "--port", String(port)]
1016
+ const shown = env.NEXT_TEST_WASM ? "NEXT_TEST_WASM=1 " : ""
1017
+ console.log(
1018
+ `\n ▶ start, under the WebContainer model: ${shown}npm ${args.join(" ")}, then GET ${url}`
1019
+ )
1020
+ const started = Date.now()
1021
+ const child = spawn("npm", args, {
1022
+ cwd,
1023
+ env,
1024
+ detached: true,
1025
+ stdio: ["ignore", "inherit", "inherit"],
1026
+ })
1027
+ let exit
1028
+ child.once("exit", (code, signal) => (exit = signal ?? `exit ${code}`))
1029
+ let failure = "no page before the deadline"
1030
+ try {
1031
+ const deadline = started + timeoutMs
1032
+ while (Date.now() < deadline) {
1033
+ if (exit) {
1034
+ failure = `the dev server stopped (${exit}) before serving a page`
1035
+ break
1036
+ }
1037
+ let response
1038
+ let body
1039
+ try {
1040
+ response = await fetch(url, {
1041
+ signal: AbortSignal.timeout(Math.max(1000, deadline - Date.now())),
1042
+ })
1043
+ body = await response.text()
1044
+ } catch {
1045
+ // not listening yet
1046
+ await sleep(1000)
1047
+ continue
1048
+ }
1049
+ if (response.ok && /<html[\s>]/i.test(body)) {
1050
+ // The page alone proves little for Vite, whose index.html is static:
1051
+ // its scripts, and the modules they import, are what the dev server
1052
+ // compiles on request.
1053
+ const scripts = pageScripts(body, url)
1054
+ const { seeds, finding } = startEntrySeeds(scripts, files)
1055
+ if (finding) {
1056
+ failure = finding
1057
+ break
1058
+ }
1059
+ const loaded = await loadScripts(scripts, deadline, seeds)
1060
+ if (loaded.broken.length > 0) {
1061
+ failure = `what the page loads did not load: ${loaded.broken.join(", ")}`
1062
+ break
1063
+ }
1064
+ const ms = Date.now() - started
1065
+ const what =
1066
+ seeds.length > 0
1067
+ ? `its ${scripts.length} script(s), TanStack Start's dev entry among them, the app's entry modules that entry reaches only through /@fs/ (${seeds.map((s) => new URL(s).pathname).join(", ")}), and the app modules they import loaded (${loaded.fetched} fetched, ${loaded.app} under /src/, ${loaded.modules} ES modules)`
1068
+ : `its ${scripts.length} script(s) and the app modules they import loaded (${loaded.fetched} fetched, ${loaded.modules} ES modules)`
1069
+ console.log(
1070
+ ` ✓ ${url} answered ${response.status} with ${body.length} bytes of HTML; ${what}, after ${seconds(ms)}`
1071
+ )
1072
+ return { ok: true, ms }
1073
+ }
1074
+ failure = `${url} answered ${response.status}${response.ok ? " without an <html> document" : ""}`
1075
+ if (!response.ok) break
1076
+ await sleep(1000)
1077
+ }
1078
+ } catch (error) {
1079
+ failure = error.message
1080
+ } finally {
1081
+ await killGroup(child)
1082
+ }
1083
+ const ms = Date.now() - started
1084
+ console.error(` ✗ start failed: ${failure} after ${seconds(ms)}`)
1085
+ return { ok: false, ms }
1086
+ }
1087
+
1088
+ /** One example, start to finish. */
1089
+ async function testExample(name, { tag, version, workDir, preload }) {
1090
+ const dir = join(workDir, name.replaceAll("/", "__"))
1091
+ const steps = {}
1092
+ const findings = []
1093
+ console.log(`\n━━ ${name} → ${dir}`)
1094
+
1095
+ const files = trackedFiles(name)
1096
+ copyTracked(name, files, dir)
1097
+ console.log(` copied ${files.length} tracked files`)
1098
+
1099
+ const manifest = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"))
1100
+ const start = stackblitzStartCommand(dir)
1101
+ findings.push(
1102
+ ...staticFindings(name, { files, scripts: manifest.scripts, start })
1103
+ )
1104
+ findings.push(
1105
+ ...(await checkManifest(manifest, {
1106
+ tag,
1107
+ version,
1108
+ satisfying: npmSatisfying,
1109
+ }))
1110
+ )
1111
+ if (findings.length > 0) return { name, steps, findings }
1112
+
1113
+ const env = isolatedEnv(process.env, repoRoot)
1114
+ steps.install = runStep(
1115
+ "install",
1116
+ "npm",
1117
+ [
1118
+ "install",
1119
+ "--no-audit",
1120
+ "--no-fund",
1121
+ "--package-lock=true",
1122
+ ...REGISTRY_ARGS,
1123
+ ],
1124
+ dir,
1125
+ env
1126
+ )
1127
+ if (!steps.install.ok) return { name, steps, findings }
1128
+
1129
+ const declared = declaredDependencies(manifest)
1130
+ .map((d) => d.name)
1131
+ .filter((n) => n.startsWith(SCOPE))
1132
+ const { installed, findings: installFindings } = checkInstalled(
1133
+ dir,
1134
+ declared,
1135
+ version,
1136
+ tag
1137
+ )
1138
+ findings.push(...installFindings)
1139
+ let lock
1140
+ try {
1141
+ lock = JSON.parse(readFileSync(join(dir, "package-lock.json"), "utf8"))
1142
+ } catch {
1143
+ lock = undefined
1144
+ }
1145
+ const locked = [...new Set(lockedScopePackages(lock).map((e) => e.name))]
1146
+ findings.push(
1147
+ ...checkLockfile(lock, {
1148
+ installed: installed.map((p) => p.name),
1149
+ published: publishedDist(locked, version),
1150
+ })
1151
+ )
1152
+ console.log(
1153
+ ` installed from ${REGISTRY} (lockfile resolved and integrity match the registry's): ` +
1154
+ installed.map((p) => `${p.name}@${p.version}`).join(", ")
1155
+ )
1156
+ if (findings.length > 0) return { name, steps, findings }
1157
+
1158
+ const isNext = Boolean(
1159
+ manifest.dependencies?.next || manifest.devDependencies?.next
1160
+ )
1161
+ if (isNext && !existsSync(join(dir, "next-env.d.ts"))) {
1162
+ writeFileSync(join(dir, "next-env.d.ts"), NEXT_ENV)
1163
+ }
1164
+ for (const script of REQUIRED_SCRIPTS) {
1165
+ if (!manifest.scripts?.[script]) continue
1166
+ steps[script] = runStep(script, "npm", ["run", script], dir, env)
1167
+ }
1168
+
1169
+ // Under the model of what a WebContainer lacks, even a script step 5 ran:
1170
+ // green on Node says nothing about StackBlitz (vite-wallet's tests were).
1171
+ const modelEnv = webContainerEnv(env, preload)
1172
+ const parsed = parseNpmCommand(start.command)
1173
+ if (parsed?.script === "dev") {
1174
+ // A WebContainer has no native binary: Next loads its WebAssembly
1175
+ // bindings there, and NEXT_TEST_WASM makes it do the same here.
1176
+ const devEnv = isNext ? { ...modelEnv, NEXT_TEST_WASM: "1" } : modelEnv
1177
+ steps.start = await smokeDevServer(dir, devEnv, parsed.args, files)
1178
+ } else {
1179
+ const [command, ...args] = start.command.split(/\s+/)
1180
+ steps.start = runStep(
1181
+ "start, under the WebContainer model",
1182
+ command,
1183
+ args,
1184
+ dir,
1185
+ modelEnv,
1186
+ 5 * MINUTE
1187
+ )
1188
+ }
1189
+ return { name, steps, findings }
1190
+ }
1191
+
1192
+ function report(results, totalMs) {
1193
+ const columns = ["install", "typecheck", "test", "build", "start"]
1194
+ const cell = (step) =>
1195
+ !step ? "-" : `${step.ok ? "ok" : "FAIL"} ${seconds(step.ms)}`
1196
+ const rows = results.map((r) => {
1197
+ const failed =
1198
+ r.findings.length > 0 || Object.values(r.steps).some((s) => !s.ok)
1199
+ return [
1200
+ r.name,
1201
+ ...columns.map((c) => cell(r.steps[c])),
1202
+ failed ? "FAIL" : "ok",
1203
+ ]
1204
+ })
1205
+ const header = ["example", ...columns, "result"]
1206
+ const widths = header.map((h, i) =>
1207
+ Math.max(h.length, ...rows.map((row) => row[i].length))
1208
+ )
1209
+ const line = (row) => row.map((v, i) => v.padEnd(widths[i])).join(" ")
1210
+ console.log(
1211
+ `\n${line(header)}\n${widths.map((w) => "-".repeat(w)).join(" ")}`
1212
+ )
1213
+ for (const row of rows) console.log(line(row))
1214
+ for (const r of results) {
1215
+ for (const finding of r.findings) console.error(`\n✗ ${r.name}: ${finding}`)
1216
+ }
1217
+ console.log(`\nTotal ${seconds(totalMs)}`)
1218
+ return rows.some((row) => row.at(-1) === "FAIL")
1219
+ }
1220
+
1221
+ /**
1222
+ * The command line: `--keep`, `--tmp <dir>`, `--wait-for <version>` and the
1223
+ * example names.
1224
+ *
1225
+ * @param {string[]} argv
1226
+ * @returns {{ keep: boolean, tmp?: string, waitFor?: string, names: string[], error?: string }}
1227
+ */
1228
+ export function parseArgs(argv) {
1229
+ const out = { keep: false, names: [] }
1230
+ for (let i = 0; i < argv.length; i++) {
1231
+ const arg = argv[i]
1232
+ if (arg === "--keep") out.keep = true
1233
+ else if (arg === "--tmp" || arg === "--wait-for") {
1234
+ const value = argv[++i]
1235
+ if (!value || value.startsWith("--")) {
1236
+ return { ...out, error: `${arg} needs a value` }
1237
+ }
1238
+ if (arg === "--tmp") out.tmp = value
1239
+ else out.waitFor = value.replace(/^v/, "")
1240
+ } else if (arg.startsWith("--")) {
1241
+ return { ...out, error: `Unknown option ${arg}` }
1242
+ } else out.names.push(arg)
1243
+ }
1244
+ return out
1245
+ }
1246
+
1247
+ /**
1248
+ * The @ic-reactor/* packages a run reads from the registry: every one the
1249
+ * manifests declare, and core (whose dist-tag names the version under test).
1250
+ *
1251
+ * @param {Record<string, any>[]} manifests
1252
+ * @returns {string[]}
1253
+ */
1254
+ export function scopePackageNames(manifests) {
1255
+ const names = new Set([`${SCOPE}core`])
1256
+ for (const manifest of manifests) {
1257
+ for (const { name } of declaredDependencies(manifest)) {
1258
+ if (name.startsWith(SCOPE)) names.add(name)
1259
+ }
1260
+ }
1261
+ return [...names].sort()
1262
+ }
1263
+
1264
+ /**
1265
+ * Polls each package until its `tag` dist-tag names `version`, the registry
1266
+ * answers with `version`'s integrity, and it serves `version`'s tarball, for
1267
+ * up to `timeoutMs`. The release workflow publishes the lane's packages
1268
+ * (core, react, vite-plugin and mcp) one after another, so the last one can
1269
+ * lag the first by minutes; every package the run reads must be served before
1270
+ * the examples install. The tarball can lag that metadata by minutes: on
1271
+ * 4.1.0's release run, core's tarball answered 404 for about five minutes
1272
+ * after its dist-tag and integrity named 4.1.0, and every example's install
1273
+ * failed on it.
1274
+ *
1275
+ * `lookup(name)` resolves with what the registry serves now: the version the
1276
+ * dist-tag names (undefined when it has none), `version`'s integrity
1277
+ * (undefined when that version is not served yet), and whether `version`'s
1278
+ * tarball downloads (`served`).
1279
+ *
1280
+ * @param {string[]} names
1281
+ * @param {string} tag
1282
+ * @param {string} version
1283
+ * @param {{
1284
+ * lookup: (name: string) => Promise<{ tagged?: string, integrity?: string, served?: boolean }> | { tagged?: string, integrity?: string, served?: boolean },
1285
+ * timeoutMs?: number,
1286
+ * pollMs?: number,
1287
+ * wait?: (ms: number) => Promise<unknown>,
1288
+ * now?: () => number,
1289
+ * log?: (line: string) => void,
1290
+ * }} options
1291
+ * @returns {Promise<string>} `version`, once every package serves it
1292
+ */
1293
+ export async function waitForPublished(
1294
+ names,
1295
+ tag,
1296
+ version,
1297
+ {
1298
+ lookup,
1299
+ timeoutMs = 10 * MINUTE,
1300
+ pollMs = 15_000,
1301
+ wait = sleep,
1302
+ now = Date.now,
1303
+ log = console.log,
1304
+ }
1305
+ ) {
1306
+ const deadline = now() + timeoutMs
1307
+ for (;;) {
1308
+ const pending = []
1309
+ for (const name of names) {
1310
+ const { tagged, integrity, served } = await lookup(name)
1311
+ if (tagged !== version) {
1312
+ pending.push(`${name}@${tag} is ${tagged ?? "unset"}`)
1313
+ } else if (!integrity) {
1314
+ pending.push(`${name}@${version} has no dist.integrity yet`)
1315
+ } else if (!served) {
1316
+ pending.push(`${name}@${version}'s tarball is not served yet`)
1317
+ }
1318
+ }
1319
+ if (pending.length === 0) return version
1320
+ if (now() >= deadline) {
1321
+ throw new Error(
1322
+ `Not published as ${version} after ${seconds(timeoutMs)}: ${pending.join("; ")}`
1323
+ )
1324
+ }
1325
+ log(`Waiting for ${version}: ${pending.join("; ")}`)
1326
+ await wait(pollMs)
1327
+ }
1328
+ }
1329
+
1330
+ /**
1331
+ * The HTTP status the registry answers a HEAD of `url` with now, or 0 when
1332
+ * the request fails.
1333
+ */
1334
+ async function headStatus(url) {
1335
+ try {
1336
+ const response = await fetch(url, {
1337
+ method: "HEAD",
1338
+ signal: AbortSignal.timeout(30_000),
1339
+ })
1340
+ return response.status
1341
+ } catch {
1342
+ return 0
1343
+ }
1344
+ }
1345
+
1346
+ /**
1347
+ * What the registry serves for `name` now, for `waitForPublished`. The
1348
+ * tarball is asked for only once the dist-tag and the integrity name
1349
+ * `version`, at the URL the registry gives for it (`dist.tarball`), which is
1350
+ * the one npm's install fetches.
1351
+ */
1352
+ async function registryState(
1353
+ name,
1354
+ tag,
1355
+ version,
1356
+ view = npmView,
1357
+ status = headStatus
1358
+ ) {
1359
+ const tagged = view(`${name}@${tag}`, "version")
1360
+ const integrity =
1361
+ tagged === version
1362
+ ? view(`${name}@${version}`, "dist.integrity")
1363
+ : undefined
1364
+ const tarball =
1365
+ typeof integrity === "string"
1366
+ ? view(`${name}@${version}`, "dist.tarball")
1367
+ : undefined
1368
+ return {
1369
+ tagged: typeof tagged === "string" ? tagged : undefined,
1370
+ integrity: typeof integrity === "string" ? integrity : undefined,
1371
+ served: typeof tarball === "string" && (await status(tarball)) === 200,
1372
+ }
1373
+ }
1374
+
1375
+ /**
1376
+ * A run's dist-tag and the version under test, or that the run defers.
1377
+ *
1378
+ * With `--wait-for` (the release's run, which never defers): the tag that
1379
+ * release publishes under (`distTagFor(waitFor)`), and the version is
1380
+ * `waitFor` once every one of `packages` serves it under that tag
1381
+ * (`waitForPublished`).
1382
+ *
1383
+ * Without it (push, pull request, weekly and manual runs), the branch's
1384
+ * version (`branchVersion`, from packages/core/package.json) decides:
1385
+ *
1386
+ * - When the examples wait on it (`awaitsRelease`: it is not among core's
1387
+ * published versions, every @ic-reactor/* range of every example is exactly
1388
+ * `^<it>`, and no dependency uses a local protocol), a release pull request
1389
+ * or its merge before the tag publishes it, the run defers:
1390
+ * `{ deferred: true, version: branchVersion }`. The caller still runs the
1391
+ * checks that need no registry (`deferredRun`, over `staticFindings`), and a
1392
+ * finding there fails the run. Core's versions are asked for only when every example pins
1393
+ * `^<branchVersion>`.
1394
+ * - Otherwise the tag is that of the branch's version, which is the version
1395
+ * of its last release: release.js syncs the examples to exactly that
1396
+ * version (sync-example-versions.js), so `latest` after a stable release
1397
+ * such as 4.0.0, and `beta` through a later prerelease cycle such as
1398
+ * 4.1.0's, whose ranges no `latest` satisfies; the version is the one that
1399
+ * tag names. With no branch version, `latest`.
1400
+ *
1401
+ * @param {{
1402
+ * waitFor?: string,
1403
+ * branchVersion?: string,
1404
+ * manifests?: Record<string, any>[],
1405
+ * packages?: string[],
1406
+ * }} run `manifests` are the examples' package.json files; `packages`, the
1407
+ * ones a release run waits on, default to `scopePackageNames(manifests)`
1408
+ * @param {{ view?: (spec: string, field: string) => unknown, status?: (url: string) => Promise<number> } & Partial<Parameters<typeof waitForPublished>[3]>} [options]
1409
+ * `view(spec, field)` answers as `npm view <spec> <field> --json` does
1410
+ * (undefined for a 404); `status(url)` with the HTTP status of a HEAD of a
1411
+ * tarball's URL; the rest goes to `waitForPublished`
1412
+ * @returns {Promise<{ tag: "latest" | "beta", version: string, deferred?: undefined } | { deferred: true, version: string }>}
1413
+ */
1414
+ export async function resolveRun(
1415
+ {
1416
+ waitFor,
1417
+ branchVersion,
1418
+ manifests = [],
1419
+ packages = scopePackageNames(manifests),
1420
+ },
1421
+ { view = npmView, status = headStatus, ...waitOptions } = {}
1422
+ ) {
1423
+ if (
1424
+ !waitFor &&
1425
+ // Every example pins ^<branchVersion>: only then is npm asked whether
1426
+ // that version is out.
1427
+ awaitsRelease(manifests, { branchVersion, publishedVersions: [] }) &&
1428
+ awaitsRelease(manifests, {
1429
+ branchVersion,
1430
+ publishedVersions: [view(`${SCOPE}core`, "versions") ?? []].flat(),
1431
+ })
1432
+ ) {
1433
+ return { deferred: true, version: branchVersion }
1434
+ }
1435
+ const tag = distTagFor(waitFor ?? branchVersion)
1436
+ const version = waitFor
1437
+ ? await waitForPublished(packages, tag, waitFor, {
1438
+ ...waitOptions,
1439
+ lookup: (name) => registryState(name, tag, waitFor, view, status),
1440
+ })
1441
+ : distTagVersion(`${SCOPE}core`, tag, view)
1442
+ return { tag, version }
1443
+ }
1444
+
1445
+ /**
1446
+ * A deferred run (`resolveRun`'s `{ deferred: true }`): it still runs the
1447
+ * checks that need no registry (`staticFindings`) on each example of the
1448
+ * checkout, so deferring never skips them. A finding fails the run (exit 1,
1449
+ * reported); with none it passes (exit 0) and says what it deferred to.
1450
+ *
1451
+ * @param {string[]} names the examples
1452
+ * @param {{
1453
+ * version: string,
1454
+ * manifests: Record<string, any>[],
1455
+ * files?: (name: string) => string[],
1456
+ * startCommand?: (name: string) => { command?: string, finding?: string },
1457
+ * onFindings?: (results: { name: string, steps: {}, findings: string[] }[]) => void,
1458
+ * log?: (message: string) => void,
1459
+ * }} run `manifests` are the examples' package.json files, in `names`'
1460
+ * order; `files`, `startCommand`, `onFindings` and `log` default to the
1461
+ * checkout's tracked files, its `.stackblitzrc`, the run's report and
1462
+ * `console.log`
1463
+ * @returns {0 | 1} the run's exit code
1464
+ */
1465
+ export function deferredRun(
1466
+ names,
1467
+ {
1468
+ version,
1469
+ manifests,
1470
+ files = trackedFiles,
1471
+ startCommand = (name) =>
1472
+ stackblitzStartCommand(join(repoRoot, "examples", name)),
1473
+ onFindings = (results) => report(results, 0),
1474
+ log = console.log,
1475
+ }
1476
+ ) {
1477
+ const results = names.map((name, i) => ({
1478
+ name,
1479
+ steps: {},
1480
+ findings: staticFindings(name, {
1481
+ files: files(name),
1482
+ scripts: manifests[i].scripts,
1483
+ start: startCommand(name),
1484
+ }),
1485
+ }))
1486
+ if (results.some((result) => result.findings.length > 0)) {
1487
+ onFindings(results)
1488
+ return 1
1489
+ }
1490
+ log(
1491
+ `The examples pin ^${version}, this branch's own version, which is not on ${REGISTRY} yet: ` +
1492
+ `a release that has not been published. The checks that need no registry pass. release.yml's examples-published job tests them ` +
1493
+ `against it once it is (--wait-for v${version}). Nothing to test here.`
1494
+ )
1495
+ return 0
1496
+ }
1497
+
1498
+ async function main(argv) {
1499
+ const args = parseArgs(argv)
1500
+ if (args.error) {
1501
+ console.error(args.error)
1502
+ return 1
1503
+ }
1504
+ const all = discoverExampleDirs()
1505
+ const unknown = args.names.filter((name) => !all.includes(name))
1506
+ if (unknown.length > 0) {
1507
+ console.error(
1508
+ `Not an example: ${unknown.join(", ")} (examples: ${all.join(", ")})`
1509
+ )
1510
+ return 1
1511
+ }
1512
+ const names = args.names.length > 0 ? args.names : all
1513
+ if (names.length === 0) {
1514
+ console.error("No examples found under examples/.")
1515
+ return 1
1516
+ }
1517
+
1518
+ const readManifest = (...path) =>
1519
+ JSON.parse(readFileSync(join(repoRoot, ...path), "utf8"))
1520
+ const manifests = names.map((name) =>
1521
+ readManifest("examples", name, "package.json")
1522
+ )
1523
+ let run
1524
+ try {
1525
+ run = await resolveRun({
1526
+ waitFor: args.waitFor,
1527
+ branchVersion: readManifest("packages", "core", "package.json").version,
1528
+ manifests,
1529
+ })
1530
+ } catch (error) {
1531
+ console.error(error.message)
1532
+ return 1
1533
+ }
1534
+ if (run.deferred) {
1535
+ return deferredRun(names, { version: run.version, manifests })
1536
+ }
1537
+ const { tag, version } = run
1538
+ console.log(
1539
+ `${SCOPE}core@${tag} is ${version} on ${REGISTRY}; testing ${names.join(", ")}`
1540
+ )
1541
+
1542
+ const base = realpathSync(args.tmp ? resolve(args.tmp) : tmpdir())
1543
+ const workDir = realpathSync(
1544
+ mkdtempSync(join(base, "ic-reactor-published-examples-"))
1545
+ )
1546
+ const rel = relative(repoRoot, workDir)
1547
+ const refusals = []
1548
+ if (!rel.startsWith("..") && !rel.startsWith(sep)) {
1549
+ refusals.push(`The scratch directory ${workDir} is inside the repository.`)
1550
+ }
1551
+ refusals.push(...ancestorFindings(workDir))
1552
+ if (refusals.length > 0) {
1553
+ rmSync(workDir, { recursive: true, force: true })
1554
+ for (const refusal of refusals) console.error(refusal)
1555
+ return 1
1556
+ }
1557
+ const keep = args.keep
1558
+ const preload = join(workDir, "webcontainer-model.cjs")
1559
+ writeFileSync(preload, WEBCONTAINER_MODEL)
1560
+
1561
+ const started = Date.now()
1562
+ const results = []
1563
+ try {
1564
+ for (const name of names) {
1565
+ results.push(await testExample(name, { tag, version, workDir, preload }))
1566
+ }
1567
+ } finally {
1568
+ if (keep) console.log(`\nCopies kept in ${workDir}`)
1569
+ else rmSync(workDir, { recursive: true, force: true })
1570
+ }
1571
+ const failed = report(results, Date.now() - started)
1572
+ if (!failed) {
1573
+ console.log(
1574
+ `✅ ${results.length} example(s) green against ${SCOPE}*@${version} (${tag}) from npm`
1575
+ )
1576
+ }
1577
+ return failed ? 1 : 0
1578
+ }
1579
+
1580
+ if (
1581
+ process.argv[1] &&
1582
+ resolve(process.argv[1]) === fileURLToPath(import.meta.url)
1583
+ ) {
1584
+ process.exitCode = await main(process.argv.slice(2))
1585
+ }