@fangorn-network/westmarch 0.0.20-dev → 2026.10.2-0.0-dev

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 (590) hide show
  1. package/README.md +33 -3
  2. package/docs/app-to-agent.md +100 -27
  3. package/package.json +9 -5
  4. package/plugin/scripts/fx.mjs +7 -9
  5. package/site/dist/assets/AccountNotFoundScreen-C4njXc69-RUyAWRzV.js +1 -0
  6. package/site/dist/assets/AddFundsSelectionScreen-RAoCn7ej-ZV-LlYBe.js +31 -0
  7. package/site/dist/assets/Address-H8kD1d9O-CGQnt7Pu.js +17 -0
  8. package/site/dist/assets/AffirmativeConsentScreen-BG0MJxku-CKn2JLwq.js +6 -0
  9. package/site/dist/assets/AllowlistRejectionScreen-Cae6e1Od-9oIP9fma.js +1 -0
  10. package/site/dist/assets/ArrowsRightLeftIcon-BEhBD_6N.js +1 -0
  11. package/site/dist/assets/AuthenticateWithWalletScreen-CU6hIcFT-D1wLlSJs.js +1 -0
  12. package/site/dist/assets/AwaitingEvmToSolBridgingScreen-D0e_sZMS-CSBbHTyz.js +1 -0
  13. package/site/dist/assets/AwaitingExternalEthereumTransferScreen-ur5HL4R7-BsRq-xBt.js +1 -0
  14. package/site/dist/assets/AwaitingPasswordlessCodeScreen-DRHz76mM-BPdhsKvN.js +103 -0
  15. package/site/dist/assets/AwaitingSolToEvmBridgingScreen-CdLRrGD2-CEGNdrkr.js +1 -0
  16. package/site/dist/assets/BridgeNetworkSelectionView-CFGjB2nO-Da9P7eSx.js +68 -0
  17. package/site/dist/assets/CaptchaScreen-DbpvkIGx-BecgMnD_.js +1 -0
  18. package/site/dist/assets/CheckCircleIcon-DBiWFjO6.js +1 -0
  19. package/site/dist/assets/CheckCircleIcon-DzG2ROJZ.js +1 -0
  20. package/site/dist/assets/Checkbox-D1EDeo41-DMHcj9o_.js +52 -0
  21. package/site/dist/assets/ChevronDownIcon-2Os56gUt.js +1 -0
  22. package/site/dist/assets/Chip-CZKIKt9K-BWzs9fj5.js +26 -0
  23. package/site/dist/assets/CoinbaseOnrampStatusScreen-BbyCJDXL-CFvcSiDs.js +16 -0
  24. package/site/dist/assets/ConnectEmailForm-B-VRE0MN-BozkCg8q.js +3 -0
  25. package/site/dist/assets/ConnectLedgerScreen-DWHABGot-DaCnbBzh.js +10 -0
  26. package/site/dist/assets/ConnectOnlyLandingScreen-CZYx9Bmp-DUkCLkxD.js +1 -0
  27. package/site/dist/assets/ConnectOnlyStatusScreen-DCRzjxHx-Dv_5nMkZ.js +1 -0
  28. package/site/dist/assets/ConnectOrCreateScreen-CUUYUO07-DSGEeB3Y.js +1 -0
  29. package/site/dist/assets/ConnectPhoneForm-Dek5xn4C-C-s4s_Lq.js +95 -0
  30. package/site/dist/assets/ConnectWalletView-DqI-PTvX-BKX7fdYr.js +74 -0
  31. package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-DSoAuMFZ.js +7 -0
  32. package/site/dist/assets/CopyToClipboard-i_OQSBJr-CZTXyfV0.js +39 -0
  33. package/site/dist/assets/CopyableText-CQapvaMr-DHO818I0.js +28 -0
  34. package/site/dist/assets/CrossAppAuthScreen-CLw7ymZq-DW4nRGfz.js +1 -0
  35. package/site/dist/assets/CustomLandingScreenView-Cm_MBSyX-DH8Nnb4Y.js +22 -0
  36. package/site/dist/assets/DelegatedActionsConsentScreen-DYF2U4y5-gfUS_uV5.js +1 -0
  37. package/site/dist/assets/DelegatedActionsRevokeScreen-bPp6Uwyh-DZj9HTHc.js +1 -0
  38. package/site/dist/assets/DepositAddressAddressStepView-4vdkb55L-eHYsDK9W.js +187 -0
  39. package/site/dist/assets/DepositAddressScreen-DBLRs7aI-DK_XVgVk.js +8 -0
  40. package/site/dist/assets/DepositAddressV3Screen-CDqIEMQw-6gRZzhLe.js +1 -0
  41. package/site/dist/assets/{EmailInputForm-Cqo1mda8-B2NG3K5V.js → EmailInputForm-Cqo1mda8-CZD4r5LM.js} +11 -11
  42. package/site/dist/assets/EmbeddedWalletConnectingScreen-D4T7DUzs-BZu2ae0k.js +1 -0
  43. package/site/dist/assets/EmbeddedWalletCreatedScreen-D7WhW5ve-86pviemJ.js +1 -0
  44. package/site/dist/assets/EmbeddedWalletKeyExportScreen-CqV4NYQ3-vDcvT53Y.js +23 -0
  45. package/site/dist/assets/EmbeddedWalletOnAccountCreateScreen-BoKb3Q2S-rNJAtSJc.js +1 -0
  46. package/site/dist/assets/EmbeddedWalletPasswordUpdateScreen-D3rMlqS7-I8Q95280.js +1 -0
  47. package/site/dist/assets/EmbeddedWalletPasswordUpdateSplashScreen-BPFkWJeE-Coi7OxoI.js +1 -0
  48. package/site/dist/assets/EnrollTotp-Dibew4dp-DC7FrDgo.js +66 -0
  49. package/site/dist/assets/EnvelopeIcon-DY6ERnW7.js +1 -0
  50. package/site/dist/assets/ErrorBanner-BcpGRt0h-BvESwN99.js +21 -0
  51. package/site/dist/assets/{ErrorMessage-D8VaAP5m-CrZOnUyg.js → ErrorMessage-D8VaAP5m-oSruKN8L.js} +2 -2
  52. package/site/dist/assets/ErrorScreen-DipdTWzE-DnKGxH1Z.js +4 -0
  53. package/site/dist/assets/ExclamationCircleIcon-BZhlqH0r.js +1 -0
  54. package/site/dist/assets/ExclamationTriangleIcon-CkAOJIYV.js +1 -0
  55. package/site/dist/assets/FarcasterConnectStatusScreen-51tjUxqq-4pi7jooW.js +75 -0
  56. package/site/dist/assets/FarcasterSignerStatusScreen-6x-Uh95G-z2XCMaLL.js +28 -0
  57. package/site/dist/assets/FiatOnrampScreen-BAhYeiTI-CBVA9v1-.js +491 -0
  58. package/site/dist/assets/FingerPrintIcon-ra2dqmJO.js +1 -0
  59. package/site/dist/assets/FundSolWalletWithExternalSolanaWallet-WtLwYaOl-DwAwc6Ny.js +1 -0
  60. package/site/dist/assets/FundWalletMethodHeader-BWNkokCT-CZszQsZf.js +1 -0
  61. package/site/dist/assets/FundWithBankDepositScreen-DajkHxBD-DfX6nvFQ.js +58 -0
  62. package/site/dist/assets/FundingEditAmountScreen-CpvpiO4M-CDS_sk_t.js +1 -0
  63. package/site/dist/assets/FundingMethodSelectionScreen-Db7vhRlE-CPfNQemT.js +1 -0
  64. package/site/dist/assets/GlobeAltIcon-SEUEIe_E.js +1 -0
  65. package/site/dist/assets/GooglePay-B53WnudL-aap7zwag.js +1 -0
  66. package/site/dist/assets/HCaptchaWrapper-CUi9LJsp-DgSjCjQI.js +4 -0
  67. package/site/dist/assets/InAppBrowserLoginNotPossible-BMR9br1T-DO4wICml.js +1 -0
  68. package/site/dist/assets/InfoBanner-Cb3p1z12-CDWt2ADo.js +22 -0
  69. package/site/dist/assets/InjectedWalletIcon-DLcYOGDj-Ba19XoBr.js +1 -0
  70. package/site/dist/assets/InstallWalletScreen-DTA8dwLv-DGpewEch.js +1 -0
  71. package/site/dist/assets/{JsonTree-BHzNC-ic-DcNcbSoM.js → JsonTree-BHzNC-ic-pAEq1bl9.js} +3 -3
  72. package/site/dist/assets/{LabelXs-oqZNqbm_-iafrj25N.js → LabelXs-oqZNqbm_-D09YjVR4.js} +2 -2
  73. package/site/dist/assets/LandingScreen-CGWUoSUG-CUOCWUXd.js +1 -0
  74. package/site/dist/assets/{Layouts-BMRfo5hw-CeCOyCLK.js → Layouts-BMRfo5hw-D2u1-w8g.js} +16 -16
  75. package/site/dist/assets/Link-BdDilT2T-BYiP1zvW.js +40 -0
  76. package/site/dist/assets/LinkConflictScreen-C3ZEPsgl-Tb6cAepT.js +77 -0
  77. package/site/dist/assets/LinkEmailScreen-dKo9frwc-pq0NF2JO.js +1 -0
  78. package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-D9MOmDqg.js +117 -0
  79. package/site/dist/assets/LinkPhoneScreen-oIUpfj0w-B80UJqAZ.js +1 -0
  80. package/site/dist/assets/{LoadingSkeleton-BMsgO5PV-CiEyS5PZ.js → LoadingSkeleton-BMsgO5PV-BRMh4Fv4.js} +6 -6
  81. package/site/dist/assets/LockClosedIcon-BqkoEL9J.js +1 -0
  82. package/site/dist/assets/LoginFailedScreen-CN0dJV6U-DlnOM-Kh.js +1 -0
  83. package/site/dist/assets/ManualTransferScreen-CHqcuqbs-DSShupq9.js +1 -0
  84. package/site/dist/assets/MfaAuthEnrollmentFlowScreen-Dj7gPTRC-DUPV_SLA.js +1 -0
  85. package/site/dist/assets/MfaAuthVerifyFlowScreen-DbFpyWMy-D96GpzXX.js +1 -0
  86. package/site/dist/assets/MfaEnrollmentFlowScreen-DhLnGgnr-CYQDa4ND.js +1 -0
  87. package/site/dist/assets/MfaVerifyFlowScreen-C_XPjMRP-CJtSAXGN.js +1 -0
  88. package/site/dist/assets/ModalFooter-BCuEK_nz-D2I8KWtk.js +403 -0
  89. package/site/dist/assets/MoonpayStatusScreen-CzTUtokc-Bx5aHy-z.js +16 -0
  90. package/site/dist/assets/OAuthStatusScreen-ufbOa-da-CS6988X2.js +1 -0
  91. package/site/dist/assets/OpenLink-CUpJ1mOr-EZWVSX2r.js +39 -0
  92. package/site/dist/assets/PasskeySelectSignupOrLogin-xh2ScC_l-BY4eK5Jh.js +1 -0
  93. package/site/dist/assets/PasskeyStatusScreen-Bla8MaOk-LXys76u9.js +6 -0
  94. package/site/dist/assets/PasswordRecoveryScreen-awGXZkQk-RczvLvmo.js +20 -0
  95. package/site/dist/assets/{PhArrowCircleDown-D97G-BOA.js → PhArrowCircleDown-BtlNV0TZ.js} +5 -5
  96. package/site/dist/assets/PhArrowClockwise-mOiWYLMV.js +14 -0
  97. package/site/dist/assets/PhArrowDown-CkoOD89h.js +14 -0
  98. package/site/dist/assets/PhArrowLeft-C0jlxVhM.js +14 -0
  99. package/site/dist/assets/PhArrowRight-BI-V03Xf.js +14 -0
  100. package/site/dist/assets/{PhArrowSquareOut-Bk2CMG3I.js → PhArrowSquareOut-DnQ7n_B4.js} +5 -5
  101. package/site/dist/assets/PhArrowUp-izKvURUW.js +14 -0
  102. package/site/dist/assets/PhArrowUpRight-Bn-JhHsY.js +14 -0
  103. package/site/dist/assets/{PhArrowsClockwise-BXRn1GEl.js → PhArrowsClockwise-Brtx2Re-.js} +5 -5
  104. package/site/dist/assets/{PhArrowsDownUp-DM09Jo_3.js → PhArrowsDownUp-PZosTqZG.js} +5 -5
  105. package/site/dist/assets/PhArrowsLeftRight-CYsRQ2qh.js +14 -0
  106. package/site/dist/assets/{PhBank-fHbgCqqZ.js → PhBank-hhPAIPVb.js} +5 -5
  107. package/site/dist/assets/PhBrowser-BjzAmrHO.js +14 -0
  108. package/site/dist/assets/PhCaretDown-ddSjwcwm.js +14 -0
  109. package/site/dist/assets/PhCaretLeft-B7YLoNEF.js +14 -0
  110. package/site/dist/assets/PhCaretRight-BY8D5MIg.js +14 -0
  111. package/site/dist/assets/PhCaretUp-BG10nSut.js +14 -0
  112. package/site/dist/assets/PhCheck-DrKd7pBC.js +14 -0
  113. package/site/dist/assets/{PhCircleHalf-MJZeRBGF.js → PhCircleHalf-Bk9C4DvT.js} +5 -5
  114. package/site/dist/assets/PhClock-Sj17weCB.js +14 -0
  115. package/site/dist/assets/{PhCompass-hYn3HhGN.js → PhCompass-Df1ugFO-.js} +5 -5
  116. package/site/dist/assets/PhCopy-rgttky8E.js +14 -0
  117. package/site/dist/assets/{PhCreditCard-Fy4pzwtt.js → PhCreditCard-CZpdid2n.js} +5 -5
  118. package/site/dist/assets/{PhCurrencyDollar-BgiaenCi.js → PhCurrencyDollar-B6IKKjue.js} +5 -5
  119. package/site/dist/assets/{PhDesktop-CxrzCSv5.js → PhDesktop-BuCDXYJj.js} +5 -5
  120. package/site/dist/assets/PhDeviceMobile-CnybhXY-.js +14 -0
  121. package/site/dist/assets/PhDotsThree-CSAEcba1.js +14 -0
  122. package/site/dist/assets/PhEnvelope-SmaNeXoQ.js +14 -0
  123. package/site/dist/assets/PhFunnelSimple-DKx35ITq.js +14 -0
  124. package/site/dist/assets/{PhGlobe-DvmSc9_A.js → PhGlobe-q1mqj65V.js} +5 -5
  125. package/site/dist/assets/{PhIdentificationCard-CfkZm-5K.js → PhIdentificationCard-BeLXJpfZ.js} +5 -5
  126. package/site/dist/assets/{PhImage-Cf0J2ZfJ.js → PhImage-BYrKfN9k.js} +5 -5
  127. package/site/dist/assets/{PhInfo-Bwi51-2X.js → PhInfo-X33f06Ej.js} +5 -5
  128. package/site/dist/assets/{PhLightbulb-C4FZV7Es.js → PhLightbulb-DMZJsowR.js} +5 -5
  129. package/site/dist/assets/PhMagnifyingGlass-B6D0sWFL.js +14 -0
  130. package/site/dist/assets/{PhPaperPlaneRight-zxQVvPLX.js → PhPaperPlaneRight-Dvo-nXr9.js} +5 -5
  131. package/site/dist/assets/PhPlus-CBvZvLax.js +14 -0
  132. package/site/dist/assets/{PhPower-CFyWDmgD.js → PhPower-D8-AcNM6.js} +5 -5
  133. package/site/dist/assets/{PhPuzzlePiece-BjoNVfST.js → PhPuzzlePiece-C-7mYqGO.js} +5 -5
  134. package/site/dist/assets/{PhQrCode-CP3tFauY.js → PhQrCode-uIXlI5ER.js} +5 -5
  135. package/site/dist/assets/{PhQuestion-wOWJBd3G.js → PhQuestion-rUoqC2sC.js} +5 -5
  136. package/site/dist/assets/{PhQuestionMark-CV0k9C0Y.js → PhQuestionMark-W55Txvvb.js} +5 -5
  137. package/site/dist/assets/{PhSealCheck-vIKzREuN.js → PhSealCheck-BeVLq9PH.js} +5 -5
  138. package/site/dist/assets/{PhSignOut-CxELV-i0.js → PhSignOut-Cq2PivQ6.js} +5 -5
  139. package/site/dist/assets/{PhSpinner-CGDmbzUd.js → PhSpinner-CZMtAFdX.js} +5 -5
  140. package/site/dist/assets/{PhTrash-C9PD0SAt.js → PhTrash-BamrmMsN.js} +5 -5
  141. package/site/dist/assets/{PhUser-0sWNXQeZ.js → PhUser-A2fxqIV0.js} +5 -5
  142. package/site/dist/assets/{PhVault-6JTskUcC.js → PhVault-B8m1usHw.js} +5 -5
  143. package/site/dist/assets/{PhWarning-CoKs3gz6.js → PhWarning-CpkID9oi.js} +5 -5
  144. package/site/dist/assets/PhWarningCircle-Cm58gXb9.js +14 -0
  145. package/site/dist/assets/PhX-C3b4cCEy.js +14 -0
  146. package/site/dist/assets/PhoneIcon-CzbssTb8.js +1 -0
  147. package/site/dist/assets/PinInput-DbZ0b1i1-1DtLWL81.js +247 -0
  148. package/site/dist/assets/QrCode-DbnZwlkH-ChwcUk_h.js +22 -0
  149. package/site/dist/assets/RecoveryOAuthStatusScreen-CsgtTI2x-C79jd345.js +1 -0
  150. package/site/dist/assets/RecoveryPasswordCreateScreen-Be-qJ-LU-C9c0x-yq.js +1 -0
  151. package/site/dist/assets/RecoverySelectionScreen-D1iGtpmi-PNqHb6CI.js +7 -0
  152. package/site/dist/assets/{Screen-D30meWsY-CCeVNuWs.js → Screen-D30meWsY-DDum2qlY.js} +22 -22
  153. package/site/dist/assets/{ScreenHeader-CHmc4-Lu-DjyrH7IK.js → ScreenHeader-CHmc4-Lu-BqrAEXbV.js} +4 -4
  154. package/site/dist/assets/ScreenLayout-OwaQQcxH-B4Z8FjFp.js +1 -0
  155. package/site/dist/assets/{SelectSourceAsset-CWFog6gm-D7yTw87h.js → SelectSourceAsset-CWFog6gm-8iXuqbAs.js} +18 -18
  156. package/site/dist/assets/SetAutomaticRecoveryScreen-BO_OEqAZ-CUpQZ9wq.js +14 -0
  157. package/site/dist/assets/SetWalletPasswordForm-DwCTVtAh-ZzvPLj2s.js +15 -0
  158. package/site/dist/assets/ShieldCheckIcon-Bjwe_-PV.js +1 -0
  159. package/site/dist/assets/SignRequestScreen-BHKv32KR-0qGeNipB.js +26 -0
  160. package/site/dist/assets/{StackedContainer-B2vaEl56-eQCM2cmv.js → StackedContainer-B2vaEl56-C-ojzCoQ.js} +2 -2
  161. package/site/dist/assets/StandardSignAndSendTransactionScreen-CfhIXVtd-C3lgJb68.js +20 -0
  162. package/site/dist/assets/{Subtitle-CV-2yKE4-zxWw2m1Q.js → Subtitle-CV-2yKE4-o-1FQLlX.js} +2 -2
  163. package/site/dist/assets/TelegramAuthScreen-UL9zLfO8-l35_C2DG.js +1 -0
  164. package/site/dist/assets/{Title-BnzYV3Is-B_JpTatT.js → Title-BnzYV3Is-RX1f0RV-.js} +2 -2
  165. package/site/dist/assets/TodoList-DnyULl18-JxWWU9KA.js +36 -0
  166. package/site/dist/assets/TransactionDetails-e9nesl30-C91nJPM9.js +109 -0
  167. package/site/dist/assets/TransactionErrorView-BDBNqA_f-Cpm-4xzm.js +178 -0
  168. package/site/dist/assets/TransferFromWalletScreen-Qvn1Yuno-BWCH7-Si.js +31 -0
  169. package/site/dist/assets/TransferOrBridgeLoadingScreen-Dl1I_iIz-BWMeJabk.js +6 -0
  170. package/site/dist/assets/TurnstileWrapper-B7sNddys-Dgr80Gih.js +1 -0
  171. package/site/dist/assets/UpdateEmailScreen-DVOhPV0H-Clk4zk-8.js +1 -0
  172. package/site/dist/assets/UpdatePhoneScreen-CXRswTNZ-BgRsoR3B.js +1 -0
  173. package/site/dist/assets/UserLimitReachedScreen-5we2DHn8-D-SU-vAz.js +1 -0
  174. package/site/dist/assets/{Value-DTgR824E-BRuIGiec.js → Value-DTgR824E-DZpvBCWi.js} +7 -7
  175. package/site/dist/assets/WalletCards-DH1rqayz-UuZ4i_Ze.js +1 -0
  176. package/site/dist/assets/WalletIcon-B1i03Vqc.js +1 -0
  177. package/site/dist/assets/WalletInfoCard-sq_2wgFg-TXTxmb8L.js +29 -0
  178. package/site/dist/assets/WalletInterstitialScreen-Sh7LfsAh-CbrFb0ON.js +1 -0
  179. package/site/dist/assets/WalletLink-DK5LB5Ha-BYQZV7UV.js +20 -0
  180. package/site/dist/assets/WalletOverflowButton-bfCnp-9T-CNgSPnTS.js +1 -0
  181. package/site/dist/assets/WarningBanner-ZZqCEtZK-DNZUUOph.js +21 -0
  182. package/site/dist/assets/__vite-browser-external-BIHI7g3E.js +1 -0
  183. package/site/dist/assets/analytics-mkkvFRju-DOXuftJB.js +1 -0
  184. package/site/dist/assets/basic-C9wn6QoQ.js +1575 -0
  185. package/site/dist/assets/bytes-CjWw8TJh.js +1 -0
  186. package/site/dist/assets/capitalizeFirstLetter-DmLYqXsO-tV1Idewc.js +1 -0
  187. package/site/dist/assets/ccip-BhHEqVIW.js +1 -0
  188. package/site/dist/assets/check-C_DTyjLS.js +1 -0
  189. package/site/dist/assets/chevron-down-iklXXH-z.js +1 -0
  190. package/site/dist/assets/circle-alert-KEOUF48T.js +1 -0
  191. package/site/dist/assets/circle-check-big-BJ_ADwB4.js +1 -0
  192. package/site/dist/assets/circle-x-BSfWmhYk.js +1 -0
  193. package/site/dist/assets/client-BnDcP42J.js +9 -0
  194. package/site/dist/assets/client-DH86IrJA.js +125 -0
  195. package/site/dist/assets/coinbase-DCPC2L_R-2ivYfoMv.js +3 -0
  196. package/site/dist/assets/copy-sK00DOfH.js +1 -0
  197. package/site/dist/assets/core-CRE213RM.js +211 -0
  198. package/site/dist/assets/createLucideIcon-D9OK_uxG.js +1 -0
  199. package/site/dist/assets/custom-V1wex-Di.js +1 -0
  200. package/site/dist/assets/dijkstra-COg3n3zL.js +1 -0
  201. package/site/dist/assets/embed.worker-BRIYO7m8.js +1 -0
  202. package/site/dist/assets/encodePacked-DyXYq3Cc.js +1 -0
  203. package/site/dist/assets/ethers-zTjbodk5-DSYOi6tU.js +1 -0
  204. package/site/dist/assets/external-link-Cdp8NBio.js +1 -0
  205. package/site/dist/assets/fallback-DiFue5Zm.js +1 -0
  206. package/site/dist/assets/farcaster-DPlSjvF5-DP2DLoHZ.js +1 -0
  207. package/site/dist/assets/features-B6BTj_BL.js +5 -0
  208. package/site/dist/assets/fingerprint-pattern-gFJTz5e4.js +1 -0
  209. package/site/dist/assets/floating-ui.react-D9ndYqYK.js +1 -0
  210. package/site/dist/assets/floating-ui.react-dom-CNbOgOFt.js +1 -0
  211. package/site/dist/assets/formatErc20TokenAmount-BuPk9xcy-CkAr4Oc0.js +1 -0
  212. package/site/dist/assets/getChainName-DjpPdUSc-c2urPd0g.js +1 -0
  213. package/site/dist/assets/getErc20Balance-jXNpFf0N-mFQ9Iqk-.js +1 -0
  214. package/site/dist/assets/getErc20TokenInfo-BNTrzLMP-Dx5he_uG.js +1 -0
  215. package/site/dist/assets/getFormattedUsdFromLamports-De3U9GlO-C446pzMl.js +1 -0
  216. package/site/dist/assets/getTransactionCount-80UHlwAV.js +1 -0
  217. package/site/dist/assets/getUsdcMintAddress-BVgm9GRo-FDalV59C.js +1 -0
  218. package/site/dist/assets/hashTypedData-Beq57Ogb.js +22 -0
  219. package/site/dist/assets/hooks.module-ClpaQ1Tg.js +1 -0
  220. package/site/dist/assets/hourglass-CB7z_I9H.js +1 -0
  221. package/site/dist/assets/http-BocEfKYb.js +19 -0
  222. package/site/dist/assets/index-0knDOgU9.js +1 -0
  223. package/site/dist/assets/index-9jNeS_nC.js +1 -0
  224. package/site/dist/assets/index-B--T-Fmt.js +16 -0
  225. package/site/dist/assets/index-BDkarAkX.js +2 -0
  226. package/site/dist/assets/index-BMfMy017.js +679 -0
  227. package/site/dist/assets/index-BOd8jv8-.js +1 -0
  228. package/site/dist/assets/index-BdEw5wyl-2VGMzHIs.js +1 -0
  229. package/site/dist/assets/index-C8ThRelw.js +9 -0
  230. package/site/dist/assets/{index-CWARkn2w-Cezl_uBr.js → index-CWARkn2w-D6ikWJWj.js} +7 -7
  231. package/site/dist/assets/{wui-ux-by-reown-D34ILNLS.js → index-CztIxJB6.js} +296 -296
  232. package/site/dist/assets/index-D4LdLFDC.js +1 -0
  233. package/site/dist/assets/index-D6T-s6sR.js +1 -0
  234. package/site/dist/assets/index-D7396TWe.js +1 -0
  235. package/site/dist/assets/index-DdxtHe81.js +2 -0
  236. package/site/dist/assets/index-DvMddJcd-D7AEQrzj.js +12 -0
  237. package/site/dist/assets/index-nibyPLVP.js +1 -0
  238. package/site/dist/assets/index.browser-B6Bt5URJ.js +1 -0
  239. package/site/dist/assets/isPaymentRequestAvailable-Bq1cemEn-D7xtzRqA.js +1 -0
  240. package/site/dist/assets/landmark-CMLKifhk.js +1 -0
  241. package/site/dist/assets/lock-BkyjNE8h.js +1 -0
  242. package/site/dist/assets/mail-B6-Tq9Ld.js +1 -0
  243. package/site/dist/assets/native-CJ5et6AR.js +1 -0
  244. package/site/dist/assets/nonceManager-zkW7cM66.js +1 -0
  245. package/site/dist/assets/parseEther-C7aOvuze.js +1 -0
  246. package/site/dist/assets/parseSignature-BIjcuWdB.js +1 -0
  247. package/site/dist/assets/preload-helper-PPVm8Dsz.js +1 -0
  248. package/site/dist/assets/privateKeyToAccount-CRvvpHWf.js +1 -0
  249. package/site/dist/assets/property-CnFDNXw5.js +3 -0
  250. package/site/dist/assets/react-auth_false-DedQs79w.js +1 -0
  251. package/site/dist/assets/reservoir-x-nGuZkT-DFxAFt2v.js +1 -0
  252. package/site/dist/assets/roles-DV_6FRBZ.js +1 -0
  253. package/site/dist/assets/safe-url-D7SRPu33-A8zMgOTd.js +1 -0
  254. package/site/dist/assets/serializeErc6492Signature-CeJeL3h6.js +1 -0
  255. package/site/dist/assets/serializeTransaction-L-_Ej-jW.js +8 -0
  256. package/site/dist/assets/{shared-DRZUmnL5-xqAUARWo.js → shared-DRZUmnL5-MWD-C-pp.js} +33 -33
  257. package/site/dist/assets/{shared-FM0rljBt--Avg6q2R.js → shared-FM0rljBt-c4eSjzGj.js} +6 -6
  258. package/site/dist/assets/shouldProceedtoEmbeddedWalletCreationFlow-B3vyavrh-CF2QteTJ.js +1 -0
  259. package/site/dist/assets/simulateTransaction-CfuOrae4-BHUMPf6Q.js +1 -0
  260. package/site/dist/assets/smartphone-DAN5rY0T.js +1 -0
  261. package/site/dist/assets/stripe.esm-Dv8C3q95.js +2 -0
  262. package/site/dist/assets/styles-BsotlekN-Cjuu2SDV.js +9 -0
  263. package/site/dist/assets/{styles-Cm9H63WO-Br4QtzUL.js → styles-Cm9H63WO-Cv1TbqYi.js} +17 -17
  264. package/site/dist/assets/{styles-DVyDvTdj-BTABn2K8.js → styles-DVyDvTdj-CI4xZNHp.js} +8 -8
  265. package/site/dist/assets/{styles-hslXy6xG-D-49b1rk.js → styles-hslXy6xG-DeVcFoDD.js} +23 -23
  266. package/site/dist/assets/telegram-B-JqnkqZ-DTjJLkIF.js +1 -0
  267. package/site/dist/assets/to-ui-error-DWe-qwS3-Dx3yzcV0.js +4 -0
  268. package/site/dist/assets/toAccount-Bq6rbpbI.js +1 -0
  269. package/site/dist/assets/transaction-BNTP-bFm-CrebgH-D.js +1 -0
  270. package/site/dist/assets/transactionReceipt-BwJl-gjg.js +1 -0
  271. package/site/dist/assets/transfer-6YztDh-t-DU6hH7CZ.js +1 -0
  272. package/site/dist/assets/transformers.web-BEKVh7pD.js +40 -0
  273. package/site/dist/assets/transformers.web-aWa49tv1.js +40 -0
  274. package/site/dist/assets/triangle-alert-ndoiBs4y.js +1 -0
  275. package/site/dist/assets/twitch-5IOe4sIQ-BXviIywg.js +1 -0
  276. package/site/dist/assets/useGetSolPrice-x7gfUIHJ-C7axYJ--.js +1 -0
  277. package/site/dist/assets/useGetTokenPrice-CaoUkb79-CR4CrguU.js +1 -0
  278. package/site/dist/assets/useI18n-C-5n_noF-C_t8QqBJ.js +1 -0
  279. package/site/dist/assets/useWalletBalance-CZnP5f_f-BnSHLVI_.js +1 -0
  280. package/site/dist/assets/w3m-modal-Bz5KWTQ-.js +1174 -0
  281. package/site/dist/assets/wallet-DTM31trz.js +2 -0
  282. package/site/dist/assets/wallet-UESEqPei.js +1 -0
  283. package/site/dist/assets/wallet-connect-BvJtUsDt-CnvUnFbz.js +1 -0
  284. package/site/dist/assets/walletconnect-v2-3frQFwbg-CzQk99gS.js +15 -0
  285. package/site/dist/assets/x-B2_XdOVQ.js +1 -0
  286. package/site/dist/index.html +118 -6
  287. package/site/feed.js +16 -1
  288. package/site/no-model.js +4 -0
  289. package/site/worker.js +597 -58
  290. package/src/agent/agent-card.js +20 -11
  291. package/src/agent/mcp.js +150 -316
  292. package/src/agent/view-tools.js +53 -12
  293. package/src/agent/x402.js +379 -44
  294. package/src/core/embed.js +51 -52
  295. package/src/core/embed.worker.js +1 -1
  296. package/src/core/shard.js +7 -3
  297. package/src/discover/apps.js +4 -3
  298. package/src/discover/explore.js +36 -22
  299. package/src/market/reactions.js +2 -2
  300. package/src/publish/devnet.js +95 -0
  301. package/src/publish/lint.js +2 -1
  302. package/src/publish/ship.js +517 -236
  303. package/src/publish/view-cli.js +11 -10
  304. package/src/publish/view.js +359 -206
  305. package/src/taste/taste-doc.js +3 -2
  306. package/src/taste/taste.js +2 -2
  307. package/src/taste/vault.js +3 -1
  308. package/site/dist/assets/AccountNotFoundScreen-C4njXc69-BOfmiSH1.js +0 -1
  309. package/site/dist/assets/AddFundsSelectionScreen-RAoCn7ej-D_EsIeJu.js +0 -31
  310. package/site/dist/assets/Address-H8kD1d9O-C85sJ79B.js +0 -17
  311. package/site/dist/assets/AffirmativeConsentScreen-BG0MJxku-DdEPFOww.js +0 -6
  312. package/site/dist/assets/AllowlistRejectionScreen-Cae6e1Od-DhVy9iGN.js +0 -1
  313. package/site/dist/assets/ApiController-CYdiyu9B.js +0 -5
  314. package/site/dist/assets/ArrowsRightLeftIcon-cp60yobq.js +0 -1
  315. package/site/dist/assets/AuthenticateWithWalletScreen-CU6hIcFT-8rbYiYYE.js +0 -1
  316. package/site/dist/assets/AwaitingEvmToSolBridgingScreen-D0e_sZMS-2pkNfCno.js +0 -1
  317. package/site/dist/assets/AwaitingExternalEthereumTransferScreen-ur5HL4R7-7AQt25_k.js +0 -1
  318. package/site/dist/assets/AwaitingPasswordlessCodeScreen-DRHz76mM-BZY30TGs.js +0 -103
  319. package/site/dist/assets/AwaitingSolToEvmBridgingScreen-CdLRrGD2-BILOOLi_.js +0 -1
  320. package/site/dist/assets/BridgeNetworkSelectionView-CFGjB2nO-CvsbQcFv.js +0 -68
  321. package/site/dist/assets/CaptchaScreen-DbpvkIGx-D8eDcAkc.js +0 -1
  322. package/site/dist/assets/CheckCircleIcon-BM409mGI.js +0 -1
  323. package/site/dist/assets/CheckCircleIcon-NCOQc0Gs.js +0 -1
  324. package/site/dist/assets/Checkbox-D1EDeo41-rHlvsZzP.js +0 -52
  325. package/site/dist/assets/ChevronDownIcon-CW-4MSpE.js +0 -1
  326. package/site/dist/assets/Chip-CZKIKt9K-CutJG010.js +0 -26
  327. package/site/dist/assets/CoinbaseOnrampStatusScreen-BbyCJDXL-DLs9zX-Q.js +0 -16
  328. package/site/dist/assets/ConnectEmailForm-B-VRE0MN-N9J6T_YL.js +0 -3
  329. package/site/dist/assets/ConnectLedgerScreen-DWHABGot-h0uYIUi6.js +0 -10
  330. package/site/dist/assets/ConnectOnlyLandingScreen-CZYx9Bmp-LeuDMN1E.js +0 -1
  331. package/site/dist/assets/ConnectOnlyStatusScreen-DCRzjxHx-DaRa59tZ.js +0 -1
  332. package/site/dist/assets/ConnectOrCreateScreen-CUUYUO07-crHzh-TL.js +0 -1
  333. package/site/dist/assets/ConnectPhoneForm-Dek5xn4C-BEA4FmhI.js +0 -95
  334. package/site/dist/assets/ConnectWalletView-DqI-PTvX-CMQIad63.js +0 -74
  335. package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-BeWLchcf.js +0 -7
  336. package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-wu3a3kw4.js +0 -1
  337. package/site/dist/assets/ConnectorUtil-Cq4lWnfe.js +0 -21
  338. package/site/dist/assets/ConstantsUtil-DmLsRHAl.js +0 -198
  339. package/site/dist/assets/CopyToClipboard-i_OQSBJr-DujUHNzW.js +0 -39
  340. package/site/dist/assets/CopyableText-CQapvaMr-DMIdpDaU.js +0 -28
  341. package/site/dist/assets/CrossAppAuthScreen-CLw7ymZq-Csju14vF.js +0 -1
  342. package/site/dist/assets/CustomLandingScreenView-Cm_MBSyX-CBOrbNLo.js +0 -22
  343. package/site/dist/assets/DelegatedActionsConsentScreen-DYF2U4y5-BL5hzNUI.js +0 -1
  344. package/site/dist/assets/DelegatedActionsRevokeScreen-bPp6Uwyh-fcO51q5H.js +0 -1
  345. package/site/dist/assets/DepositAddressAddressStepView-4vdkb55L-B3vY888G.js +0 -187
  346. package/site/dist/assets/DepositAddressScreen-DBLRs7aI-DmdQaFI2.js +0 -8
  347. package/site/dist/assets/DepositAddressV3Screen-CDqIEMQw-BoupRyfV.js +0 -1
  348. package/site/dist/assets/EmbeddedWalletConnectingScreen-D4T7DUzs-D_AVgO4s.js +0 -1
  349. package/site/dist/assets/EmbeddedWalletCreatedScreen-D7WhW5ve-CLsJbPYQ.js +0 -1
  350. package/site/dist/assets/EmbeddedWalletKeyExportScreen-CqV4NYQ3-C9sAExzE.js +0 -23
  351. package/site/dist/assets/EmbeddedWalletOnAccountCreateScreen-BoKb3Q2S-DxaWAAKa.js +0 -1
  352. package/site/dist/assets/EmbeddedWalletPasswordUpdateScreen-D3rMlqS7-CxrfLr5q.js +0 -1
  353. package/site/dist/assets/EmbeddedWalletPasswordUpdateSplashScreen-BPFkWJeE-DHZRGoTN.js +0 -1
  354. package/site/dist/assets/EnrollTotp-Dibew4dp-SA2pvNEc.js +0 -66
  355. package/site/dist/assets/EnvelopeIcon-Dh2vSVj4.js +0 -1
  356. package/site/dist/assets/ErrorBanner-BcpGRt0h-BKOYTyCi.js +0 -21
  357. package/site/dist/assets/ErrorScreen-DipdTWzE-DcxVjMO4.js +0 -1
  358. package/site/dist/assets/ErrorScreen-DipdTWzE-c8g8En21.js +0 -4
  359. package/site/dist/assets/ExclamationCircleIcon-DUA2wMfO.js +0 -1
  360. package/site/dist/assets/ExclamationTriangleIcon-eZfaqcFq.js +0 -1
  361. package/site/dist/assets/FarcasterConnectStatusScreen-51tjUxqq-s_s5M2CZ.js +0 -75
  362. package/site/dist/assets/FarcasterSignerStatusScreen-6x-Uh95G-BHBR4k8H.js +0 -28
  363. package/site/dist/assets/FiatOnrampScreen-BAhYeiTI-BH_sU6EV.js +0 -491
  364. package/site/dist/assets/FingerPrintIcon-Dm6kxmg7.js +0 -1
  365. package/site/dist/assets/FundSolWalletWithExternalSolanaWallet-WtLwYaOl-B8TRV36j.js +0 -1
  366. package/site/dist/assets/FundWalletMethodHeader-BWNkokCT-BQdbJ5Bb.js +0 -1
  367. package/site/dist/assets/FundWithBankDepositScreen-DajkHxBD-9rPtyA3d.js +0 -58
  368. package/site/dist/assets/FundingEditAmountScreen-CpvpiO4M-GaXigGI9.js +0 -1
  369. package/site/dist/assets/FundingMethodSelectionScreen-Db7vhRlE-UsmtTqv4.js +0 -1
  370. package/site/dist/assets/GlobeAltIcon-vqrVV5ho.js +0 -1
  371. package/site/dist/assets/GooglePay-B53WnudL-BX5_WtCx.js +0 -1
  372. package/site/dist/assets/HCaptchaWrapper-CUi9LJsp-D-I8j7NO.js +0 -4
  373. package/site/dist/assets/InAppBrowserLoginNotPossible-BMR9br1T-BY3j50El.js +0 -1
  374. package/site/dist/assets/InfoBanner-Cb3p1z12-DLBl_Ywy.js +0 -22
  375. package/site/dist/assets/InjectedWalletIcon-DLcYOGDj-DLSV_NjP.js +0 -1
  376. package/site/dist/assets/InstallWalletScreen-DTA8dwLv-CxreyXoD.js +0 -1
  377. package/site/dist/assets/LandingScreen-CGWUoSUG-DK1EY-6v.js +0 -1
  378. package/site/dist/assets/Link-BdDilT2T-BEDEdHuS.js +0 -40
  379. package/site/dist/assets/LinkConflictScreen-C3ZEPsgl-ClWoqvEL.js +0 -77
  380. package/site/dist/assets/LinkEmailScreen-dKo9frwc-C3v7glH0.js +0 -1
  381. package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-D72Gb0LW.js +0 -117
  382. package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-DYIl5Kr2.js +0 -1
  383. package/site/dist/assets/LinkPhoneScreen-oIUpfj0w-C0DuD14j.js +0 -1
  384. package/site/dist/assets/Loader-UAZqxsnw-Cy7hEE2f.js +0 -62
  385. package/site/dist/assets/LockClosedIcon-BgY_5v_Z.js +0 -1
  386. package/site/dist/assets/LoginFailedScreen-CN0dJV6U-DhUMiJZJ.js +0 -1
  387. package/site/dist/assets/ManualTransferScreen-CHqcuqbs-tXiZDHmN.js +0 -1
  388. package/site/dist/assets/MfaAuthEnrollmentFlowScreen-Dj7gPTRC-CaW7xeCC.js +0 -1
  389. package/site/dist/assets/MfaAuthVerifyFlowScreen-DbFpyWMy-CeRqvx8k.js +0 -1
  390. package/site/dist/assets/MfaEnrollmentFlowScreen-DhLnGgnr-BkN1k4lh.js +0 -1
  391. package/site/dist/assets/MfaVerifyFlowScreen-C_XPjMRP-CXSqLVbE.js +0 -1
  392. package/site/dist/assets/ModalFooter-BCuEK_nz-c-khvG4Y.js +0 -403
  393. package/site/dist/assets/MoonpayStatusScreen-CzTUtokc-BRFN2eXr.js +0 -16
  394. package/site/dist/assets/OAuthStatusScreen-ufbOa-da-CeiGcSia.js +0 -1
  395. package/site/dist/assets/OpenLink-CUpJ1mOr-DfAvJRyK.js +0 -39
  396. package/site/dist/assets/PasskeySelectSignupOrLogin-xh2ScC_l-CIf5I7wU.js +0 -1
  397. package/site/dist/assets/PasskeyStatusScreen-Bla8MaOk-CLoL7QC-.js +0 -6
  398. package/site/dist/assets/PasswordRecoveryScreen-awGXZkQk-B9F67IYV.js +0 -20
  399. package/site/dist/assets/PhArrowClockwise-DVgyFuez.js +0 -14
  400. package/site/dist/assets/PhArrowDown-87b1BizM.js +0 -14
  401. package/site/dist/assets/PhArrowLeft-Da0MfnbK.js +0 -14
  402. package/site/dist/assets/PhArrowRight-AdrIL4DW.js +0 -14
  403. package/site/dist/assets/PhArrowUp-4sgyKPGx.js +0 -14
  404. package/site/dist/assets/PhArrowUpRight-BNghD2zq.js +0 -14
  405. package/site/dist/assets/PhArrowsLeftRight-MuKBLUoF.js +0 -14
  406. package/site/dist/assets/PhBrowser-2-9m-AkM.js +0 -14
  407. package/site/dist/assets/PhCaretDown-BDNabFuL.js +0 -14
  408. package/site/dist/assets/PhCaretLeft-CI460R-A.js +0 -14
  409. package/site/dist/assets/PhCaretRight-D7ZS3Ls8.js +0 -14
  410. package/site/dist/assets/PhCaretUp-C-iIfyvO.js +0 -14
  411. package/site/dist/assets/PhCheck-DxQXn57r.js +0 -14
  412. package/site/dist/assets/PhClock-x3MS3Mwi.js +0 -14
  413. package/site/dist/assets/PhCopy-CWNYcABI.js +0 -14
  414. package/site/dist/assets/PhDeviceMobile-CsyA5Goi.js +0 -14
  415. package/site/dist/assets/PhDotsThree-D-k1BiYg.js +0 -14
  416. package/site/dist/assets/PhEnvelope-D8kzeNox.js +0 -14
  417. package/site/dist/assets/PhFunnelSimple-CfQs5DAW.js +0 -14
  418. package/site/dist/assets/PhMagnifyingGlass-C9u8jSCJ.js +0 -14
  419. package/site/dist/assets/PhPlus-C4UoW-2n.js +0 -14
  420. package/site/dist/assets/PhWarningCircle-BXHw1fCt.js +0 -14
  421. package/site/dist/assets/PhX-DX0SFIqC.js +0 -14
  422. package/site/dist/assets/PhoneIcon-CvIiPwYQ.js +0 -1
  423. package/site/dist/assets/PinInput-DbZ0b1i1-CDXZBdQx.js +0 -247
  424. package/site/dist/assets/PrivyPluginContext-DA-yS5vO-CtQWBiV2.js +0 -1
  425. package/site/dist/assets/QrCode-DbnZwlkH-h6Bhoe5U.js +0 -22
  426. package/site/dist/assets/RecoveryOAuthStatusScreen-CsgtTI2x-D-A5P3PX.js +0 -1
  427. package/site/dist/assets/RecoveryPasswordCreateScreen-Be-qJ-LU-C8lTSeSr.js +0 -1
  428. package/site/dist/assets/RecoverySelectionScreen-D1iGtpmi-P5P3plkH.js +0 -7
  429. package/site/dist/assets/SIWXUtil-TUCxa7aA.js +0 -1
  430. package/site/dist/assets/ScreenLayout-OwaQQcxH-CrQM6kvA.js +0 -1
  431. package/site/dist/assets/SetAutomaticRecoveryScreen-BO_OEqAZ-f0iDIGmw.js +0 -14
  432. package/site/dist/assets/SetWalletPasswordForm-DwCTVtAh-kq1zvA7d.js +0 -11
  433. package/site/dist/assets/ShieldCheckIcon-o6RHYev1.js +0 -1
  434. package/site/dist/assets/SignRequestScreen-BHKv32KR-DDpMYyJ1.js +0 -26
  435. package/site/dist/assets/SolanaWalletConnector-C7Lqk-Wz-DPwhuzcI.js +0 -1
  436. package/site/dist/assets/StandardSignAndSendTransactionScreen-CfhIXVtd-BJ-onCjv.js +0 -20
  437. package/site/dist/assets/TelegramAuthScreen-UL9zLfO8-NWlMgNRX.js +0 -1
  438. package/site/dist/assets/TodoList-DnyULl18-C8Eyy28X.js +0 -36
  439. package/site/dist/assets/TransactionDetails-e9nesl30-C4MpIHR-.js +0 -109
  440. package/site/dist/assets/TransactionErrorView-BDBNqA_f-p1T9WVMx.js +0 -178
  441. package/site/dist/assets/TransferFromWalletScreen-Qvn1Yuno-88IQcRnY.js +0 -31
  442. package/site/dist/assets/TransferOrBridgeLoadingScreen-Dl1I_iIz-1fDAIxAf.js +0 -6
  443. package/site/dist/assets/TurnstileWrapper-B7sNddys-Jwy1tJtm.js +0 -1
  444. package/site/dist/assets/UpdateEmailScreen-DVOhPV0H-Jj2DQW8D.js +0 -1
  445. package/site/dist/assets/UpdatePhoneScreen-CXRswTNZ-DwYIUBqi.js +0 -1
  446. package/site/dist/assets/UserLimitReachedScreen-5we2DHn8-D7m70C4b.js +0 -1
  447. package/site/dist/assets/WalletCards-DH1rqayz-Bgp9Fsgs.js +0 -1
  448. package/site/dist/assets/WalletIcon-gKf0gTw6.js +0 -1
  449. package/site/dist/assets/WalletInfoCard-sq_2wgFg-DpNSAGte.js +0 -29
  450. package/site/dist/assets/WalletInterstitialScreen-Sh7LfsAh-DG-RuO-F.js +0 -1
  451. package/site/dist/assets/WalletLink-DK5LB5Ha-DHaL350n.js +0 -20
  452. package/site/dist/assets/WalletOverflowButton-bfCnp-9T-CUyIJFzt.js +0 -1
  453. package/site/dist/assets/WarningBanner-ZZqCEtZK-2eU4Qo74.js +0 -21
  454. package/site/dist/assets/__vite-browser-external-CitKSmYk.js +0 -1
  455. package/site/dist/assets/_esm-B26FZg5Y.js +0 -7
  456. package/site/dist/assets/_esm-BdeM6pxJ.js +0 -1
  457. package/site/dist/assets/accounts-D96UKWkC.js +0 -1
  458. package/site/dist/assets/accounts-DiZ-0VmN.js +0 -1
  459. package/site/dist/assets/analytics-mkkvFRju-BRBcadka.js +0 -1
  460. package/site/dist/assets/baseSepolia-DX-qGsik.js +0 -1
  461. package/site/dist/assets/basic-oIwwSyu4.js +0 -1575
  462. package/site/dist/assets/capitalizeFirstLetter-DmLYqXsO-DtOXx-2n.js +0 -1
  463. package/site/dist/assets/ccip-65sIfSPR.js +0 -1
  464. package/site/dist/assets/ccip-BZvRTL6g.js +0 -7
  465. package/site/dist/assets/ccip-DA_zG341.js +0 -1
  466. package/site/dist/assets/chain-DM3oH6Px.js +0 -8
  467. package/site/dist/assets/check-BPgcwEPP.js +0 -1
  468. package/site/dist/assets/chevron-down-BSsbXkK-.js +0 -1
  469. package/site/dist/assets/circle-alert-DWaeLZNj.js +0 -1
  470. package/site/dist/assets/circle-check-big-Chb1ivw9.js +0 -1
  471. package/site/dist/assets/circle-x-AV9Cet0R.js +0 -1
  472. package/site/dist/assets/client-CZG0ndth.js +0 -2
  473. package/site/dist/assets/client-Dsa7_3V3.js +0 -9
  474. package/site/dist/assets/coinbase-DCPC2L_R-D3aIgpyd.js +0 -3
  475. package/site/dist/assets/copy-Ckr0AkL6.js +0 -1
  476. package/site/dist/assets/core-snws5xwv.js +0 -12
  477. package/site/dist/assets/createLucideIcon-IPW50ckY.js +0 -1
  478. package/site/dist/assets/defineChain-CiuCXUZW.js +0 -1
  479. package/site/dist/assets/dijkstra-Drfl93V4.js +0 -1
  480. package/site/dist/assets/dist-Cm7pNAtL.js +0 -1
  481. package/site/dist/assets/dist-CoS6E-3x.js +0 -1
  482. package/site/dist/assets/dist-Dl07uGq1.js +0 -1
  483. package/site/dist/assets/dist-DnGANz51.js +0 -16
  484. package/site/dist/assets/embed.worker-ugGhEqCV.js +0 -1
  485. package/site/dist/assets/errors-BQ3N-RVt-BLqjTPNR.js +0 -1
  486. package/site/dist/assets/esm-B5cbIQaz.js +0 -37
  487. package/site/dist/assets/esm-ByALO6mA.js +0 -1
  488. package/site/dist/assets/esm-C3DslVJx.js +0 -1
  489. package/site/dist/assets/esm-Ci1ogKuK.js +0 -1
  490. package/site/dist/assets/esm-n2lWo7kz.js +0 -1
  491. package/site/dist/assets/ethers-zTjbodk5-wHhL_BQ1.js +0 -1
  492. package/site/dist/assets/eventemitter3-CL76jPsW.js +0 -1
  493. package/site/dist/assets/external-link-D-uehwM2.js +0 -1
  494. package/site/dist/assets/farcaster-DPlSjvF5-BqTvDXBR.js +0 -1
  495. package/site/dist/assets/features-DQ0UYy6K.js +0 -2
  496. package/site/dist/assets/fingerprint-pattern-D8ytA16Q.js +0 -1
  497. package/site/dist/assets/floating-ui.react-dom-DKWOL9UG.js +0 -1
  498. package/site/dist/assets/floating-ui.react-xRkl9O3u.js +0 -1
  499. package/site/dist/assets/formatErc20TokenAmount-BuPk9xcy-BVqOKQif.js +0 -1
  500. package/site/dist/assets/formatter-CVbp4SlJ.js +0 -1
  501. package/site/dist/assets/get-entropy-details-for-user-dHRH5Gpi-Dukf7_kJ.js +0 -1
  502. package/site/dist/assets/getChainName-DjpPdUSc-DUyKDrnp.js +0 -1
  503. package/site/dist/assets/getErc20Balance-jXNpFf0N-Bb9WM31M.js +0 -1
  504. package/site/dist/assets/getErc20TokenInfo-BNTrzLMP-KPrdn04K.js +0 -1
  505. package/site/dist/assets/getFormattedUsdFromLamports-De3U9GlO-Gx4_wxON.js +0 -1
  506. package/site/dist/assets/getUsdcMintAddress-BVgm9GRo-r2UnDeEy.js +0 -1
  507. package/site/dist/assets/guards-BIW-GiMJ-CHfXo8XI.js +0 -1
  508. package/site/dist/assets/hooks.module-BYZGfwDl.js +0 -1
  509. package/site/dist/assets/hourglass-CPG1HZmf.js +0 -1
  510. package/site/dist/assets/id-UqEwL2BI-BkKm533U.js +0 -1
  511. package/site/dist/assets/index-1HYFYA-W.js +0 -8
  512. package/site/dist/assets/index-BdEw5wyl-ChSJvPZk.js +0 -1
  513. package/site/dist/assets/index-DvMddJcd-BatvgC-S.js +0 -12
  514. package/site/dist/assets/index-YiCw0Y_x-CX5i3Z87.js +0 -437
  515. package/site/dist/assets/index.browser-B-i-Lj3J.js +0 -1
  516. package/site/dist/assets/index.browser-BMmUcykv.js +0 -1
  517. package/site/dist/assets/index.es-BmqyoBEM.js +0 -2
  518. package/site/dist/assets/index.es-C1v1or--.js +0 -3
  519. package/site/dist/assets/isPaymentRequestAvailable-Bq1cemEn-By6r0dVB.js +0 -1
  520. package/site/dist/assets/jsx-runtime-BbDfbRii.js +0 -1
  521. package/site/dist/assets/landmark-CH6LV6F0.js +0 -1
  522. package/site/dist/assets/lib-BsS8z8Lj.js +0 -1
  523. package/site/dist/assets/localBatchGatewayRequest-3kLrX_c7.js +0 -32
  524. package/site/dist/assets/lock-DcskI4Bb.js +0 -1
  525. package/site/dist/assets/logger-CsXm3oIv-B0UYpNFI.js +0 -1
  526. package/site/dist/assets/mail-Bs0r5yOi.js +0 -1
  527. package/site/dist/assets/modal-context-CwmSeFcv-DruX9J1E.js +0 -1
  528. package/site/dist/assets/native-BKj27wfc.js +0 -1
  529. package/site/dist/assets/ofetch.CWycOUEr-CHp-crOQ.js +0 -1
  530. package/site/dist/assets/parseAbi-Csg-8t59.js +0 -2
  531. package/site/dist/assets/parseAbiParameters-BWbIMYe4.js +0 -1
  532. package/site/dist/assets/parseEther-VjhVo3dd.js +0 -1
  533. package/site/dist/assets/pkce-DXF0yKjP-ChQhE0st.js +0 -1
  534. package/site/dist/assets/preload-helper-uBIymjUX.js +0 -1
  535. package/site/dist/assets/privy-context-81KmsBw2-CjWGzyg7.js +0 -2
  536. package/site/dist/assets/property-DuZ9DLP4.js +0 -3
  537. package/site/dist/assets/react-DCXkXSrv.js +0 -1
  538. package/site/dist/assets/react-DQnMl2Xv.js +0 -1
  539. package/site/dist/assets/react-DrJ0MmMO.js +0 -1
  540. package/site/dist/assets/react-auth-sHnipzbS.js +0 -1
  541. package/site/dist/assets/react-dom-5dW7aKoP.js +0 -1
  542. package/site/dist/assets/reservoir-x-nGuZkT-BMX127i6.js +0 -1
  543. package/site/dist/assets/roles-32M1l9jI.js +0 -1
  544. package/site/dist/assets/roles-DKPW79Ca.js +0 -1
  545. package/site/dist/assets/rolldown-runtime-BcKkbAw3.js +0 -1
  546. package/site/dist/assets/safe-url-D7SRPu33-CkMedGro.js +0 -1
  547. package/site/dist/assets/secp256k1-C4nzcPo-.js +0 -1
  548. package/site/dist/assets/secp256k1-D92aGNnU.js +0 -1
  549. package/site/dist/assets/secp256k1-DmbwyFau.js +0 -1
  550. package/site/dist/assets/secp256k1-_MleGpqL.js +0 -1
  551. package/site/dist/assets/secp256k1-xl2og-wO.js +0 -1
  552. package/site/dist/assets/serializeAuthorizationList-CX8hGL56.js +0 -1
  553. package/site/dist/assets/serializeSignature-DfxkPnu-.js +0 -2
  554. package/site/dist/assets/sha2-BU_QyRTx.js +0 -1
  555. package/site/dist/assets/shouldProceedtoEmbeddedWalletCreationFlow-B3vyavrh-BK_FBkaE.js +0 -1
  556. package/site/dist/assets/simulateTransaction-CfuOrae4-64lWYJAL.js +0 -1
  557. package/site/dist/assets/smartphone-CcEZ-XAy.js +0 -1
  558. package/site/dist/assets/src-BBjkfi-Q.js +0 -1
  559. package/site/dist/assets/storage-Ufl800Ne-D0bZBw-H.js +0 -9
  560. package/site/dist/assets/stringify-BlDm7tuc.js +0 -21
  561. package/site/dist/assets/stripe.esm-CZRDpc-N.js +0 -2
  562. package/site/dist/assets/styles-BsotlekN-CXEB4Ud9.js +0 -9
  563. package/site/dist/assets/telegram-B-JqnkqZ-RBoY3PLx.js +0 -1
  564. package/site/dist/assets/to-ui-error-DWe-qwS3-Cx2bk1kZ.js +0 -4
  565. package/site/dist/assets/toViemAccount-B5iDGq1b-Ba8L7zed.js +0 -2
  566. package/site/dist/assets/transaction-BNTP-bFm-M5tJx8vY.js +0 -1
  567. package/site/dist/assets/transfer-6YztDh-t-BVQkTvG-.js +0 -1
  568. package/site/dist/assets/transformers.web-CVP3pJOS.js +0 -40
  569. package/site/dist/assets/transformers.web-D8W1u_I2.js +0 -49
  570. package/site/dist/assets/triangle-alert-CWjYH75H.js +0 -1
  571. package/site/dist/assets/twitch-5IOe4sIQ-lDtgk0os.js +0 -1
  572. package/site/dist/assets/types-4CuOD23i.js +0 -1
  573. package/site/dist/assets/use-headless-crypto-deposit-Yn-QRLB3-LUIVFBSd.js +0 -1
  574. package/site/dist/assets/use-unlink-wallet-BKK4_5Ur-CC2pq27z.js +0 -1
  575. package/site/dist/assets/useActiveWallet-B-yZYGc6-D7Ik-LxJ.js +0 -123
  576. package/site/dist/assets/useGetSolPrice-x7gfUIHJ-D1hmQfpA.js +0 -1
  577. package/site/dist/assets/useGetTokenPrice-CaoUkb79-ZnbuJ-vP.js +0 -1
  578. package/site/dist/assets/useI18n-C-5n_noF-BcqC76yj.js +0 -1
  579. package/site/dist/assets/useWalletBalance-CZnP5f_f-Dw2GIJ4g.js +0 -1
  580. package/site/dist/assets/useWallets-X1ndvJ_U-DRjz7uYD.js +0 -1
  581. package/site/dist/assets/utils-BkR7EQjg.js +0 -1
  582. package/site/dist/assets/utils-DJhBNOZA.js +0 -1
  583. package/site/dist/assets/utils-DdckVfQr.js +0 -1
  584. package/site/dist/assets/w3m-modal-BeVrBOIf.js +0 -1174
  585. package/site/dist/assets/wallet-Bn85Sg2W.js +0 -1
  586. package/site/dist/assets/wallet-Bnzeiqed.js +0 -2
  587. package/site/dist/assets/wallet-connect-BvJtUsDt-Y03hhqFN.js +0 -1
  588. package/site/dist/assets/walletconnect-registry-xxG8XLCb-D1SSFvMp.js +0 -1
  589. package/site/dist/assets/walletconnect-v2-3frQFwbg-CrtLXofr.js +0 -12
  590. package/site/dist/assets/x-rlSp9U7W.js +0 -1
package/site/worker.js CHANGED
@@ -1,38 +1,222 @@
1
- // The app's front door (Cloudflare Pages advanced mode): the static site, plus two things a
2
- // static site cannot do. `westmarch-ship` writes this to site/_worker.js with CONFIG filled in.
1
+ // A Fangorn app on the free tier: one Cloudflare Worker that is the app's indexer, its view,
2
+ // its MCP server and its site. `westmarch-ship` deploys it with the app's CONFIG.
3
3
  //
4
+ // cron the indexer. Follows the update log from where it left off, and runs
5
+ // the embedding lens (view.js, the Worker's AI binding as the encoder)
6
+ // over every member's repo whose head moved, into R2. A repo whose
7
+ // publisher leaves the app, or that the app excludes, loses its domain
8
+ // on the next run.
9
+ // GET /view/… the view, from R2: catalog, manifests, content-named shards
10
+ // POST /mcp the view as MCP tools (describe, search, get, similar, count, browse,
11
+ // threads) over streamable HTTP: no install, no browser
4
12
  // GET /doc?u=<url> a record's source document, served from this origin so the page can
5
13
  // show it inline. Source sites forbid framing and send no CORS, so the
6
14
  // page cannot fetch or frame them itself. Only hosts the app's own
7
- // records link to (CONFIG.docHosts), only PDFs, cached for a day.
8
- // GET /paid/<item id> with CONFIG.paid: 402 + the price; with a valid X-PAYMENT header, the
9
- // facilitator verifies and settles it, then the record is returned
10
- // GET /_paid/* 404 to everyone: the records sit here as static files, and the
11
- // only way to one is through a settled payment
12
- // anything else the static site, with the headers _headers would have set
15
+ // records link to (each domain's `link_hosts`), only PDFs, cached a day.
16
+ // GET /paid/<item id> with CONFIG.paid: 402 + the price (x402 v2); with a valid
17
+ // PAYMENT-SIGNATURE header, the facilitator verifies and settles it, then
18
+ // the record's KEY is returned
19
+ // POST /paid {ids} many keys for one price, paid by one payment or several (vouchers).
20
+ // Its 402 carries the Bazaar extension, so the facilitator lists it on
21
+ // the first sale; /openapi.json and /.well-known/x402 name it for x402scan
22
+ // POST /key {ids, tokenId, issuedAt, signature}
23
+ // keys for a member: Barliman checks the signed request against the
24
+ // MembershipRegistry (`canRead`), and nothing is paid here
25
+ // anything else the static site (the stock page, the card)
13
26
  //
14
- // A record that does not exist is a 404 before any price is quoted: nobody pays for nothing.
15
- // Each record's sha256 is in the app's public (committed) data, so a buyer can check it.
27
+ // The paid records are not here. Each is already in the app's committed rows on IPFS,
28
+ // encrypted (`paid_ct`, AES-256-GCM), with the sha256 of its plaintext beside it. This worker
29
+ // sells only the key, HMAC-SHA256(PAID_SECRET, id): the buyer holds the ciphertext before
30
+ // paying, so nobody pays for a record that does not exist, and decrypts and checks it after.
31
+ //
32
+ // Bindings: VIEW (R2), AI (Workers AI), ASSETS (the site), CONFIG (a JSON var: app, name,
33
+ // description, fromBlock, repos, paid, deployment), and optionally RPC_URL and IPFS_GATEWAY
34
+ // (vars) and PAID_SECRET (a secret).
35
+
36
+ import { Fangorn, FangornConfig, SupportedNetworks, repoExcluded } from "@fangorn-network/sdk";
37
+ import { createPublicClient, http } from "viem";
38
+ import { generatePrivateKey } from "viem/accounts";
39
+ import { EMBED_MODEL, DOCUMENT, QUERY, matryoshka } from "../src/core/embed.js";
40
+ import { configure, resetShard } from "../src/core/shard.js";
41
+ import { publishView, r2Store } from "../src/publish/view.js";
42
+ import { viewTools } from "../src/agent/view-tools.js";
43
+
44
+ let CONFIG = { paid: null };
45
+
46
+ // ── the lens's encoder ────────────────────────────────────────────────────────
47
+
48
+ const AI_MODEL = "@cf/google/embeddinggemma-300m";
49
+ /** What a view built here records: the same model as embed.js, another runtime of it. */
50
+ export const WORKER_EMBEDDER = { runtime: "workers-ai", model: EMBED_MODEL, dtype: "workers-ai" };
51
+ // EMBED_URL: an encoder answering as the AI binding does ({text} → {data}), on a devnet, so
52
+ // nothing leaves the machine. Its views say so: {runtime, model, dtype} come back with it.
53
+ const ai = (env) => env.EMBED_URL
54
+ ? async (body) => (await fetch(env.EMBED_URL, { method: "POST", body: JSON.stringify(body) })).json()
55
+ : (body) => env.AI.run(AI_MODEL, body);
56
+ const embedderOf = async (env) => env.EMBED_URL ? (await (await fetch(env.EMBED_URL)).json()) : WORKER_EMBEDDER;
57
+ const encode = (env, prompt) => async (texts) =>
58
+ (await ai(env)({ text: texts.map((t) => prompt + t) })).data.map((v) => matryoshka(v));
59
+
60
+ // ── the indexer ───────────────────────────────────────────────────────────────
61
+
62
+ const STATE = "state.json", LOCK = "index.lock";
63
+ // A run past this is presumed dead and its lock taken over. Cron runs get 15 minutes.
64
+ const LOCK_MS = 14 * 60_000;
65
+
66
+ // CONFIG.network: the SDK's network name ("baseSepolia"); absent, its default.
67
+ const network = () => SupportedNetworks[CONFIG.network] ?? FangornConfig;
68
+
69
+ function reader(env) {
70
+ // CONFIG.deployment: another deployment's addresses (and appRegistryFromBlock as a string),
71
+ // for a testnet fork or a local chain. Absent, the network's.
72
+ const d = CONFIG.deployment ?? {};
73
+ const config = { ...network(), ...d, ...(d.appRegistryFromBlock ? { appRegistryFromBlock: BigInt(d.appRegistryFromBlock) } : {}),
74
+ ...(env.RPC_URL ? { rpcUrl: env.RPC_URL } : {}) };
75
+ const fangorn = Fangorn.create({ privateKey: generatePrivateKey(), config, appId: CONFIG.app,
76
+ storage: { signedUrl: env.IPFS_GATEWAY ? { gateway: env.IPFS_GATEWAY } : {} } });
77
+ return { fangorn, chain: createPublicClient({ chain: config.chain, transport: http(config.rpcUrl) }) };
78
+ }
79
+
80
+ /**
81
+ * What the app presents now, kept across runs in R2: each run reads only the updates since
82
+ * the last, then asks which repos the app presents: its members' (`presents`), less what it
83
+ * excludes. Neither membership nor exclusions move a head, so they are read, not followed.
84
+ * ponytail: reads every publisher's updates, and 4 contract reads per repo per run; follow
85
+ * the app's members and ExclusionChanged events when an app holds enough repos to show it.
86
+ */
87
+ export async function presented({ fangorn, chain }, state) {
88
+ const to = await chain.getBlockNumber();
89
+ const from = state.block == null ? BigInt(CONFIG.fromBlock ?? network().appRegistryFromBlock) : BigInt(state.block) + 1n;
90
+ const app = fangorn.getAppId();
91
+ const registry = fangorn.getRegistry();
92
+ if (from <= to) for (const e of await registry.log({}, from, to))
93
+ state.repos[`${e.publisher.toLowerCase()}/${e.repo}`] = { owner: e.publisher, repo: e.repo, root: e.head };
94
+ state.block = String(to);
95
+ const all = Object.values(state.repos);
96
+ const kept = await Promise.all(all.map(async (r) => await registry.presents(app, r.owner)
97
+ && !(await repoExcluded(registry, app, { publisher: r.owner, repo: r.repo }))));
98
+ return all.filter((_, i) => kept[i]);
99
+ }
100
+
101
+ export async function index(env, { log = console.log } = {}) {
102
+ const lock = await env.VIEW.get(LOCK);
103
+ if (lock && Date.now() - Number(await lock.text()) < LOCK_MS) return log("index: a run is in progress; skipped");
104
+ await env.VIEW.put(LOCK, String(Date.now()));
105
+ try {
106
+ const state = (await (await env.VIEW.get(STATE))?.json()) ?? { block: null, repos: {} };
107
+ const r = reader(env);
108
+ // Imported here: x402.js's self-check imports this module, and a cycle at load would deadlock it.
109
+ const { openRow } = await import("../src/agent/x402.js");
110
+ const report = await publishView({
111
+ fangorn: r.fangorn, app: CONFIG.app, repos: CONFIG.repos, store: r2Store(env.VIEW),
112
+ presented: await presented(r, state), embedBatch: encode(env, DOCUMENT), embedder: await embedderOf(env), log,
113
+ ...(CONFIG.private ? { open: (p) => openRow(env.PAID_SECRET, p) } : {}),
114
+ });
115
+ await env.VIEW.put(STATE, JSON.stringify(state));
116
+ log(`index: through block ${state.block}, ${Object.keys(report).length} domain(s) changed`);
117
+ return report;
118
+ } finally {
119
+ await env.VIEW.delete(LOCK);
120
+ }
121
+ }
16
122
 
17
- const CONFIG = /*CONFIG*/ { docHosts: [], paid: null } /*END*/;
123
+ // ── the view, from R2 ─────────────────────────────────────────────────────────
124
+
125
+ const CONTENT = { ".gz": "application/gzip" };
126
+ async function viewFile(env, path) {
127
+ const o = await env.VIEW.get(`view/${path}`);
128
+ if (!o) return new Response("not found", { status: 404, headers: CORS });
129
+ const type = CONTENT[path.slice(path.lastIndexOf("."))] ?? "application/json";
130
+ // Shards are content-named, so a reader's browser keeps one for good: a change or a
131
+ // retraction writes new names. `private`: kept out of shared caches, so a retracted
132
+ // record's shard stops being served the moment the indexer deletes it.
133
+ const cache = path.includes("/shards/") ? "private, max-age=31536000, immutable" : "no-cache";
134
+ return new Response(o.body, { headers: { "content-type": type, "cache-control": cache, ...CORS } });
135
+ }
136
+
137
+ // ── MCP over streamable HTTP ──────────────────────────────────────────────────
138
+ //
139
+ // Stateless: every POST is one JSON-RPC message, answered with one JSON body. The tools are
140
+ // view-tools.js's, reading the view straight from R2, ranking by a query embedded here by the
141
+ // same runtime that embedded the rows. They are rebuilt when the indexer writes a new catalog.
18
142
 
19
- const CORS = { "access-control-allow-origin": "*", "access-control-allow-headers": "X-PAYMENT, content-type", "access-control-expose-headers": "X-PAYMENT-RESPONSE" };
143
+ let mcp = null;
144
+ async function tools(env, origin) {
145
+ const catalog = await env.VIEW.get("view/cdn/catalog");
146
+ const at = catalog?.uploaded?.getTime() ?? 0;
147
+ if (mcp?.at !== at) {
148
+ resetShard();
149
+ configure({ fetch: (url) => viewFile(env, new URL(url).pathname.replace(/^\/view\//, "")) });
150
+ const qv = encode(env, QUERY);
151
+ mcp = { at, tools: viewTools({ name: CONFIG.name ?? CONFIG.app, desc: CONFIG.description ?? "", views: [`${origin}/view`] },
152
+ { fetchCatalog: (url) => viewFile(env, new URL(url).pathname.replace(/^\/view\//, "")),
153
+ queryVector: async (q) => (await qv([q]).catch(() => [null]))[0] }) };
154
+ // viewTools starts its catalog survey unawaited. workerd cancels a request's I/O when
155
+ // it returns, so a survey begun under tools/list never settles and every later call
156
+ // waits on it forever. Finish it here, in the request that started it.
157
+ await mcp.tools.call("describe").catch(() => {});
158
+ }
159
+ return mcp.tools;
160
+ }
161
+
162
+ export async function mcpCall(env, origin, msg, request = null) {
163
+ const ok = (result) => ({ jsonrpc: "2.0", id: msg.id, result });
164
+ switch (msg.method) {
165
+ case "initialize": return ok({
166
+ protocolVersion: msg.params?.protocolVersion ?? "2025-06-18",
167
+ capabilities: { tools: { listChanged: false } },
168
+ serverInfo: { name: CONFIG.name ?? CONFIG.app ?? "fangorn-app", version: "0.1.0" },
169
+ instructions: `${CONFIG.description ?? ""} Call describe first, then search.`.trim(),
170
+ });
171
+ case "ping": return ok({});
172
+ case "tools/list": {
173
+ const t = await tools(env, origin), X = CONFIG.private;
174
+ const price = X && `${Number(X.call) / 10 ** (X.decimals ?? 6)} ${X.symbol ?? "USDC"}`;
175
+ return ok({ tools: (t ? t.tools : []).map((d) => !X || FREE_TOOLS.has(d.name) ? d
176
+ : { ...d, description: `${d.description} Paid: ${price} a call over x402, or a pass from POST ${origin}/pass.` }) });
177
+ }
178
+ case "tools/call": {
179
+ const t = await tools(env, origin), name = msg.params?.name;
180
+ const run = async () => {
181
+ try { return await t.call(name, msg.params?.arguments ?? {}); }
182
+ catch (e) { return { isError: true, content: [{ type: "text", text: e?.message ?? String(e) }] }; }
183
+ };
184
+ const tool = t.tools.find((d) => d.name === name);
185
+ if (!CONFIG.private || !tool || FREE_TOOLS.has(name) || (request && await passOf(env, request))) return ok(await run());
186
+ return ok(await paidCall(origin, tool, msg.params?._meta?.["x402/payment"], run));
187
+ }
188
+ default: return { jsonrpc: "2.0", id: msg.id, error: { code: -32601, message: `unknown method ${msg.method}` } };
189
+ }
190
+ }
191
+
192
+ async function serveMcp(request, env, url) {
193
+ if (request.method !== "POST") return new Response("POST JSON-RPC here (MCP streamable HTTP)", { status: 405, headers: { allow: "POST", ...CORS } });
194
+ let msg;
195
+ try { msg = await request.json(); } catch { return json({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "not JSON" } }, 400); }
196
+ if (Array.isArray(msg)) return json({ jsonrpc: "2.0", id: null, error: { code: -32600, message: "one message per request" } }, 400);
197
+ if (msg.id === undefined) return new Response(null, { status: 202, headers: CORS }); // a notification
198
+ return json(await mcpCall(env, url.origin, msg, request));
199
+ }
200
+
201
+ const CORS = { "access-control-allow-origin": "*", "access-control-allow-headers": "PAYMENT-SIGNATURE, authorization, content-type",
202
+ "access-control-expose-headers": "PAYMENT-REQUIRED, PAYMENT-RESPONSE" };
20
203
  const json = (o, status = 200, headers = {}) =>
21
204
  new Response(JSON.stringify(o), { status, headers: { "content-type": "application/json", ...CORS, ...headers } });
22
205
  const note = (msg, status) => new Response(`<!doctype html><meta charset="utf-8"><body style="font:15px system-ui;padding:24px;color:#555">${msg}</body>`,
23
206
  { status, headers: { "content-type": "text/html; charset=utf-8" } });
24
207
 
25
- async function doc(request, url) {
208
+ async function doc(request, env, url) {
26
209
  let src;
27
210
  try { src = new URL(url.searchParams.get("u") ?? ""); } catch { return note("No document named.", 400); }
28
- if (src.protocol !== "https:" || !CONFIG.docHosts.includes(src.hostname)) return note("Not one of this app's sources.", 403);
211
+ const hosts = new Set(((await (await env.VIEW.get("view/cdn/catalog"))?.json())?.domains ?? []).flatMap((d) => d.link_hosts ?? []));
212
+ if (src.protocol !== "https:" || !hosts.has(src.hostname)) return note("Not one of this app's sources.", 403);
29
213
  const cache = caches.default, key = new Request(url.href);
30
214
  const hit = await cache.match(key);
31
215
  if (hit) return hit;
32
216
  const up = await fetch(src.href, { headers: { "user-agent": "Mozilla/5.0 (compatible; fangorn-app/0.1; +https://fangorn.network)" }, redirect: "follow" });
33
217
  // A redirect may not leave the allowed hosts, and only a PDF is shown: an HTML page from
34
218
  // someone else's site, served from this origin, would run as this app.
35
- if (!CONFIG.docHosts.includes(new URL(up.url).hostname)) return note("The source redirected elsewhere.", 403);
219
+ if (!hosts.has(new URL(up.url).hostname)) return note("The source redirected elsewhere.", 403);
36
220
  if (!up.ok || !(up.headers.get("content-type") ?? "").includes("pdf"))
37
221
  return note(`This document is not a PDF. <a href="${src.href.replace(/"/g, "&quot;")}" target="_blank" rel="noopener">Open it on the source site</a>.`, 415);
38
222
  const res = new Response(up.body, { headers: { "content-type": "application/pdf", "content-disposition": "inline",
@@ -41,65 +225,420 @@ async function doc(request, url) {
41
225
  return res;
42
226
  }
43
227
 
44
- async function fileFor(id) {
45
- const d = new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(id)));
46
- return [...d].map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 32);
228
+ /** A record's key: HMAC-SHA256(PAID_SECRET, id), hex. The same derivation as the sources that
229
+ * encrypt (and x402.js's paidKey). */
230
+ async function keyFor(env, id) {
231
+ if (!env.PAID_SECRET) throw new Error("PAID_SECRET is not set (wrangler pages secret put PAID_SECRET)");
232
+ const k = await crypto.subtle.importKey("raw", new TextEncoder().encode(env.PAID_SECRET), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
233
+ const mac = new Uint8Array(await crypto.subtle.sign("HMAC", k, new TextEncoder().encode(id)));
234
+ return [...mac].map((b) => b.toString(16).padStart(2, "0")).join("");
47
235
  }
236
+ const keysFor = async (env, ids) => Object.fromEntries(await Promise.all(ids.map(async (id) => [id, await keyFor(env, id)])));
237
+
238
+ // ── x402 v2 ───────────────────────────────────────────────────────────────────
239
+ // Over HTTP the 402's PaymentRequired is in the PAYMENT-REQUIRED header (base64 JSON) and in the
240
+ // body, the buyer pays in PAYMENT-SIGNATURE, the settlement comes back in PAYMENT-RESPONSE. Over
241
+ // MCP (a private app's tools) the same objects ride in the tool result and `_meta`.
242
+ // Only a payment's `payload` (the signed EIP-3009 authorization) is taken from the buyer: what
243
+ // goes to the facilitator is rebuilt here around it, so `accepted`, `resource` and the Bazaar
244
+ // extension are always this worker's, including on vouchers signed weeks ago.
245
+ //
246
+ // A sale is what one route sells: its terms `P` (CONFIG.paid or CONFIG.private: network, asset,
247
+ // payTo, facilitator, the token's EIP-712 name and version), what a catalog says it is
248
+ // (`resource`), and its Bazaar entry, if the facilitator should list it.
249
+
250
+ const MAX_BATCH = 1000, MAX_PAYMENTS = 10;
251
+ const b64json = (o) => btoa(JSON.stringify(o));
252
+ const requirement = (P, amount) => ({ scheme: "exact", network: P.network, amount: String(amount), asset: P.asset,
253
+ payTo: P.payTo, maxTimeoutSeconds: 120, extra: { name: P.name, version: P.version } });
254
+ const resource = (url, description) => ({ url, mimeType: "application/json", serviceName: CONFIG.name, description });
255
+ const lead = (P) => (P.description ? `${P.description}. ` : "");
48
256
 
49
- async function facilitator(path, payment, requirements) {
50
- const r = await fetch(`${CONFIG.paid.facilitator}/${path}`, {
51
- method: "POST", headers: { "content-type": "application/json" },
52
- body: JSON.stringify({ x402Version: 1, paymentPayload: payment, paymentRequirements: requirements }),
53
- });
257
+ const SCHEMA = "https://json-schema.org/draft/2020-12/schema";
258
+ const OUTPUT = { type: "object", required: ["type"], properties: { type: { type: "string" }, example: { type: "object" } } };
259
+ /** A Bazaar entry for a POST route taking JSON. */
260
+ const httpBazaar = (body, bodySchema, example) => ({
261
+ info: { input: { type: "http", method: "POST", bodyType: "json", body }, output: { type: "json", example } },
262
+ schema: { $schema: SCHEMA, type: "object", required: ["input"], properties: {
263
+ input: { type: "object", required: ["type", "method", "bodyType", "body"], additionalProperties: false, properties: {
264
+ type: { type: "string", const: "http" }, method: { type: "string", enum: ["POST"] }, bodyType: { type: "string", enum: ["json"] }, body: bodySchema } },
265
+ output: OUTPUT } },
266
+ });
267
+ /** A Bazaar entry for one MCP tool: listed by (the server's URL, its name). */
268
+ const mcpBazaar = (tool) => ({
269
+ info: { input: { type: "mcp", toolName: tool.name, description: tool.description, inputSchema: tool.inputSchema, transport: "streamable-http" } },
270
+ schema: { $schema: SCHEMA, type: "object", required: ["input"], properties: {
271
+ input: { type: "object", required: ["type", "toolName", "inputSchema"], additionalProperties: false, properties: {
272
+ type: { type: "string", const: "mcp" }, toolName: { type: "string" }, description: { type: "string" },
273
+ transport: { type: "string", enum: ["streamable-http", "sse"] }, inputSchema: { type: "object" }, example: { type: "object" } } },
274
+ output: OUTPUT } },
275
+ });
276
+
277
+ // The keys to sealed records. Only POST /paid is listed: GET /paid/<id>'s URL differs per record,
278
+ // and each would be listed apart.
279
+ const KEYS_BAZAAR = httpBazaar({ ids: ["<record id>"] },
280
+ { type: "object", required: ["ids"], properties: { ids: { type: "array", items: { type: "string" }, minItems: 1, maxItems: MAX_BATCH } } },
281
+ { keys: { "<record id>": "<hex key>" }, missing: [], receipts: [], paid: [] });
282
+ const keySale = (url, listed) => ({ P: CONFIG.paid, bazaar: listed ? KEYS_BAZAAR : null,
283
+ resource: resource(url.href, `${lead(CONFIG.paid)}Sells the keys to ${CONFIG.name}'s sealed records (AES-256-GCM, in its rows as `
284
+ + `paid_ct). Find records and their ids with the MCP server at ${url.origin}/mcp.`) });
285
+
286
+ // A private app's pass, and its tools one call at a time.
287
+ const PASS_BAZAAR = httpBazaar({}, { type: "object" }, { token: "<pass>", expires: 1900000000 });
288
+ const days = (s) => Math.round(s / 86400);
289
+ const passSale = (url) => ({ P: CONFIG.private, bazaar: PASS_BAZAAR,
290
+ resource: resource(url.href, `${lead(CONFIG.private)}A ${days(CONFIG.private.pass.seconds)}-day pass to ${CONFIG.name}: every tool of its MCP server `
291
+ + `at ${url.origin}/mcp and its view, with Authorization: Bearer <token>.`) });
292
+ const callSale = (origin, tool) => ({ P: CONFIG.private, bazaar: mcpBazaar(tool),
293
+ resource: resource(`${origin}/mcp`, `${lead(CONFIG.private)}${CONFIG.name}'s ${tool.name} tool, one call. A pass (POST ${origin}/pass) covers every call.`) });
294
+
295
+ const paymentRequired = (sale, amount, error) => ({ x402Version: 2, error, resource: sale.resource, accepts: [requirement(sale.P, amount)],
296
+ ...(sale.bazaar ? { extensions: { bazaar: sale.bazaar } } : {}) });
297
+
298
+ /** 402 with the price of `amount`; `more` rides in the body only. */
299
+ function quote(sale, amount, error, more = {}) {
300
+ const required = paymentRequired(sale, amount, error);
301
+ return json({ ...required, ...more }, 402, { "payment-required": b64json(required) });
302
+ }
303
+
304
+ /** The PaymentPayload the facilitator sees: the buyer's signed `payload`, the rest ours. */
305
+ const payloadOf = (sale, p, amount) => ({ x402Version: 2, resource: sale.resource, accepted: requirement(sale.P, amount),
306
+ payload: p?.payload, ...(sale.bazaar ? { extensions: { bazaar: sale.bazaar } } : {}) });
307
+
308
+ async function facilitator(P, path, paymentPayload) {
309
+ // A network failure is an answer too: thrown, it would turn a half-settled batch into a 500.
310
+ let r;
311
+ try {
312
+ r = await fetch(`${P.facilitator}/${path}`, {
313
+ method: "POST", headers: { "content-type": "application/json" },
314
+ body: JSON.stringify({ x402Version: 2, paymentPayload, paymentRequirements: paymentPayload.accepted }),
315
+ });
316
+ } catch (e) { return { error: `facilitator ${path}: ${e.message}` }; }
54
317
  const text = await r.text();
55
318
  try { return JSON.parse(text); } catch { return { error: `facilitator ${path}: HTTP ${r.status} ${text.slice(0, 200)}` }; }
56
319
  }
57
320
 
321
+ const signatures = (request) => {
322
+ const header = request.headers.get("PAYMENT-SIGNATURE");
323
+ if (!header) return { error: "PAYMENT-SIGNATURE header is required" };
324
+ try { return { payments: [JSON.parse(atob(header))].flat() }; } catch { return { error: "PAYMENT-SIGNATURE is not base64 JSON" }; }
325
+ };
326
+
327
+ /** One payment for `amount`, verified and settled: `{settled, payer}`, or `{refused}`, the 402 to answer with. */
328
+ async function payOnce(request, sale, amount) {
329
+ const { payments, error } = signatures(request);
330
+ if (error) return { refused: quote(sale, amount, error) };
331
+ if (payments.length !== 1) return { refused: quote(sale, amount, "one payment, not several") };
332
+ const payment = payloadOf(sale, payments[0], amount);
333
+ const verified = await facilitator(sale.P, "verify", payment);
334
+ if (!verified.isValid) return { refused: quote(sale, amount, verified.invalidReason ?? verified.error ?? "payment did not verify") };
335
+ const settled = await facilitator(sale.P, "settle", payment);
336
+ if (!settled.success) return { refused: quote(sale, amount, settled.errorReason ?? settled.error ?? "settlement failed") };
337
+ return { settled, payer: settled.payer ?? payment.payload?.authorization?.from };
338
+ }
339
+
58
340
  async function sell(request, env, url) {
59
- const P = CONFIG.paid;
60
341
  const id = decodeURIComponent(url.pathname.slice("/paid/".length));
61
- const record = await env.ASSETS.fetch(new URL(`/_paid/${await fileFor(id)}.json`, url));
62
- // Pages answers an unknown path with index.html and a 200 (its single-page fallback), so
63
- // "ok" is not "exists": only a JSON body is a record. Nobody is quoted a price for nothing.
64
- if (!record.ok || !(record.headers.get("content-type") ?? "").includes("json")) return json({ error: `no paid record for ${id}` }, 404);
65
- const requirements = {
66
- scheme: "exact", network: P.network, maxAmountRequired: P.price, resource: url.href,
67
- description: P.description, mimeType: "application/json", payTo: P.payTo,
68
- maxTimeoutSeconds: 120, asset: P.asset, extra: { name: P.name, version: P.version },
342
+ if (!id) return json({ error: "no id" }, 400);
343
+ const { settled, refused } = await payOnce(request, keySale(url, false), CONFIG.paid.price);
344
+ if (refused) return refused;
345
+ return json({ id, key: await keyFor(env, id) }, 200, { "payment-response": b64json(settled) });
346
+ }
347
+
348
+ // POST /paid {ids}: many keys, one price. 402 with the total; then PAYMENT-SIGNATURE may be one
349
+ // payment or a JSON array of them (an agent's vouchers) that add up to it. The only subrequests
350
+ // are the facilitator's (2 per payment, 50 on the free plan), hence MAX_PAYMENTS; keys cost nothing.
351
+ async function sellBatch(request, env, url) {
352
+ const P = CONFIG.paid, sale = keySale(url, true);
353
+ const { payments, error } = signatures(request);
354
+ let ids;
355
+ try { ids = [...new Set((await request.json()).ids)].filter((x) => typeof x === "string"); } catch { ids = null; }
356
+ if (!ids?.length || ids.length > MAX_BATCH) {
357
+ // A probe (x402scan, a Bazaar crawler) posts no body: it gets the price of one record.
358
+ if (error) return quote(sale, P.price, `${error}; the body is {"ids": [...]}, ${P.price} per id`);
359
+ return json({ error: `body must be {"ids": [...]}, between 1 and ${MAX_BATCH} ids per purchase` }, 400);
360
+ }
361
+ const found = ids, missing = [];
362
+ const total = BigInt(P.price) * BigInt(found.length);
363
+ const refuse = (error, more = {}) => quote(sale, total, error, { found, missing, ...more });
364
+ if (error) return refuse(error);
365
+ if (payments.length > MAX_PAYMENTS) return refuse(`at most ${MAX_PAYMENTS} payments per purchase`);
366
+ const auths = payments.map((p) => p?.payload?.authorization ?? {});
367
+ if (new Set(auths.map((a) => a.nonce)).size !== auths.length) return refuse("a payment is repeated");
368
+ if (auths.some((a) => String(a.to).toLowerCase() !== P.payTo.toLowerCase())) return refuse("a payment is not to this app");
369
+ let sum = 0n;
370
+ try { for (const a of auths) sum += BigInt(a.value); } catch { return refuse("a payment has no amount"); }
371
+ if (sum !== total) return refuse(`payments add up to ${sum}, the price is ${total}`);
372
+ const signed = payments.map((p, i) => payloadOf(sale, p, auths[i].value));
373
+ for (const [i, p] of signed.entries()) {
374
+ const v = await facilitator(P, "verify", p);
375
+ if (!v.isValid) return refuse(`payment ${i + 1}: ${v.invalidReason ?? v.error ?? "did not verify"}`);
376
+ }
377
+ // Settle one by one. A spent voucher (or one the wallet can no longer cover) passes verify
378
+ // and fails here. If that happens after others settled, the buyer still gets what the
379
+ // settled money pays for, never more: a spent voucher riding along with a fresh one buys
380
+ // only what the fresh one pays for. `paid` and `rejected` name the vouchers (by nonce) so
381
+ // the buyer's stack can drop them either way.
382
+ const receipts = [];
383
+ let settled = 0n;
384
+ for (const [i, p] of signed.entries()) {
385
+ const s = await facilitator(P, "settle", p);
386
+ if (!s.success) {
387
+ const error = `payment ${i + 1}: ${s.errorReason ?? s.error ?? "settlement failed"}`;
388
+ if (!receipts.length) return refuse(error, { rejected: [auths[i].nonce] });
389
+ const n = Number(settled / BigInt(P.price));
390
+ return json({ keys: await keysFor(env, found.slice(0, n)), missing, undelivered: found.slice(n), receipts, error,
391
+ paid: auths.slice(0, i).map((a) => a.nonce), rejected: [auths[i].nonce] });
392
+ }
393
+ receipts.push(s);
394
+ settled += BigInt(auths[i].value);
395
+ }
396
+ return json({ keys: await keysFor(env, found), missing, receipts, paid: auths.map((a) => a.nonce) });
397
+ }
398
+
399
+ // POST /key: keys for a member. Barliman recovers who signed the request and asks the
400
+ // MembershipRegistry whether that address may read this app now; this worker trusts its answer.
401
+ // ponytail: one Barliman call per request; cache {tokenId, reader} → until if it gets busy.
402
+ async function member(request, env) {
403
+ const M = CONFIG.paid.membership;
404
+ if (!M) return json({ error: "this app sells no memberships" }, 404);
405
+ let b;
406
+ try { b = await request.json(); } catch { return json({ error: "body must be JSON" }, 400); }
407
+ const ids = [...new Set(b?.ids ?? [])].filter((x) => typeof x === "string");
408
+ if (!ids.length || ids.length > MAX_BATCH) return json({ error: `between 1 and ${MAX_BATCH} ids` }, 400);
409
+ let check;
410
+ try {
411
+ const r = await fetch(`${M.barliman}/check`, { method: "POST", headers: { "content-type": "application/json" },
412
+ body: JSON.stringify({ appId: M.appId, tokenId: String(b.tokenId), ids, issuedAt: b.issuedAt, signature: b.signature }) });
413
+ check = await r.json();
414
+ } catch (e) { return json({ error: `could not check the membership: ${e.message}` }, 502); }
415
+ if (!check.ok) return json({ error: check.error ?? "this membership cannot read this app now", until: check.until ?? null }, 403);
416
+ return json({ keys: await keysFor(env, ids), reader: check.reader, until: check.until });
417
+ }
418
+
419
+ // ── a private app ─────────────────────────────────────────────────────────────
420
+ // CONFIG.private: the rows are sealed on chain (x402.js's sealRow), opened by the cron with
421
+ // PAID_SECRET, and the view is served only with access: a pass bought at POST /pass (one x402
422
+ // payment, a token good for `pass.seconds`), or, on /mcp, one x402 payment per tool call. What a
423
+ // stranger needs to decide whether to pay stays free: the card, the catalog (views, counts) and
424
+ // the describe tool.
425
+ // ponytail: a pass is a signed token, not a record: it cannot be revoked before it expires, and
426
+ // changing PAID_SECRET voids every pass (and every key). A list of revoked payers in R2 if that matters.
427
+
428
+ const FREE_VIEW = new Set(["cdn/catalog"]), FREE_TOOLS = new Set(["describe"]);
429
+ const b64url = (bytes) => btoa(String.fromCharCode(...bytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
430
+ const unb64url = (s) => Uint8Array.from(atob(s.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0));
431
+ const passKey = (env) => crypto.subtle.importKey("raw", new TextEncoder().encode(`${env.PAID_SECRET}:pass`), { name: "HMAC", hash: "SHA-256" }, false, ["sign", "verify"]);
432
+
433
+ async function issuePass(env, payer, exp) {
434
+ const claims = b64url(new TextEncoder().encode(JSON.stringify({ app: CONFIG.app, sub: payer, exp })));
435
+ return `${claims}.${b64url(new Uint8Array(await crypto.subtle.sign("HMAC", await passKey(env), new TextEncoder().encode(claims))))}`;
436
+ }
437
+
438
+ /** The pass a request carries (Authorization: Bearer), if it is this app's and unexpired. */
439
+ async function passOf(env, request) {
440
+ const m = /^Bearer ([\w-]+)\.([\w-]+)$/.exec(request.headers.get("authorization") ?? "");
441
+ if (!m || !env.PAID_SECRET) return null;
442
+ try {
443
+ if (!await crypto.subtle.verify("HMAC", await passKey(env), unb64url(m[2]), new TextEncoder().encode(m[1]))) return null;
444
+ const c = JSON.parse(new TextDecoder().decode(unb64url(m[1])));
445
+ return c.app === CONFIG.app && c.exp > Date.now() / 1000 ? c : null;
446
+ } catch { return null; }
447
+ }
448
+
449
+ // POST /pass: one payment, a pass. A probe posts nothing and gets the price.
450
+ async function sellPass(request, env, url) {
451
+ const X = CONFIG.private;
452
+ const { settled, payer, refused } = await payOnce(request, passSale(url), X.pass.price);
453
+ if (refused) return refused;
454
+ const expires = Math.floor(Date.now() / 1000) + X.pass.seconds;
455
+ return json({ token: await issuePass(env, payer, expires), expires,
456
+ use: `Authorization: Bearer <token> on ${url.origin}/mcp and ${url.origin}/view/…` }, 200, { "payment-response": b64json(settled) });
457
+ }
458
+
459
+ /** A paid tool call over x402's MCP transport: verify, run, settle. A call that fails is not
460
+ * charged (its payment is never settled), and a settlement that fails returns no content. */
461
+ async function paidCall(origin, tool, payment, run) {
462
+ const X = CONFIG.private, sale = callSale(origin, tool);
463
+ const required = (error) => {
464
+ const pr = paymentRequired(sale, X.call, error);
465
+ return { isError: true, structuredContent: pr, content: [{ type: "text", text: JSON.stringify(pr) }] };
69
466
  };
70
- const refuse = (error) => json({ x402Version: 1, error, accepts: [requirements] }, 402);
71
- const header = request.headers.get("X-PAYMENT");
72
- if (!header) return refuse("X-PAYMENT header is required");
73
- let payment;
74
- try { payment = JSON.parse(atob(header)); } catch { return refuse("X-PAYMENT is not base64 JSON"); }
75
- const verified = await facilitator("verify", payment, requirements);
76
- if (!verified.isValid) return refuse(verified.invalidReason ?? verified.error ?? "payment did not verify");
77
- const settled = await facilitator("settle", payment, requirements);
78
- if (!settled.success) return refuse(settled.errorReason ?? settled.error ?? "settlement failed");
79
- return new Response(await record.text(), {
80
- headers: { "content-type": "application/json", "x-payment-response": btoa(JSON.stringify(settled)), ...CORS },
81
- });
82
- }
83
-
84
- export default {
467
+ if (!payment) return required(`${tool.name} is paid: one x402 payment per call in _meta["x402/payment"], or a pass from POST ${origin}/pass`);
468
+ const p = payloadOf(sale, payment, X.call);
469
+ const verified = await facilitator(X, "verify", p);
470
+ if (!verified.isValid) return required(verified.invalidReason ?? verified.error ?? "payment did not verify");
471
+ const result = await run();
472
+ // view-tools answers a miss ("not in a loaded view") with {error} in the text, not isError.
473
+ let missed = false;
474
+ try { missed = !!JSON.parse(result.content?.[0]?.text ?? "{}").error; } catch { /* not JSON: an answer */ }
475
+ if (result.isError || missed) return result;
476
+ const settled = await facilitator(X, "settle", p);
477
+ if (!settled.success) return required(settled.errorReason ?? settled.error ?? "settlement failed");
478
+ return { ...result, _meta: { ...result._meta, "x402/payment-response": settled } };
479
+ }
480
+
481
+ const worker = {
85
482
  async fetch(request, env) {
483
+ CONFIG = env.CONFIG ?? CONFIG;
86
484
  const url = new URL(request.url);
485
+ const p = url.pathname;
87
486
  if (request.method === "OPTIONS") return new Response(null, { status: 204, headers: CORS });
88
- if (url.pathname.startsWith("/_paid/") || url.pathname === "/_worker.js") return new Response("not found", { status: 404 });
89
- if (url.pathname === "/doc") return doc(request, url);
90
- if (url.pathname.startsWith("/paid/")) return CONFIG.paid ? sell(request, env, url) : json({ error: "nothing is sold here" }, 404);
487
+ if (p.startsWith("/view/")) {
488
+ const path = p.slice("/view/".length);
489
+ if (CONFIG.private && !FREE_VIEW.has(path) && !await passOf(env, request))
490
+ return json({ error: `${CONFIG.name}'s data is private: send Authorization: Bearer <pass>, from POST ${url.origin}/pass (x402)` }, 401);
491
+ return viewFile(env, path);
492
+ }
493
+ if (p === "/pass" && request.method === "POST") return CONFIG.private ? sellPass(request, env, url) : json({ error: "nothing is sold here" }, 404);
494
+ if (p === "/mcp") return serveMcp(request, env, url);
495
+ if (p === "/doc") return doc(request, env, url);
496
+ if (p === "/paid" && request.method === "POST") return CONFIG.paid ? sellBatch(request, env, url) : json({ error: "nothing is sold here" }, 404);
497
+ if (p.startsWith("/paid/")) return CONFIG.paid ? sell(request, env, url) : json({ error: "nothing is sold here" }, 404);
498
+ if (p === "/key" && request.method === "POST") return CONFIG.paid ? member(request, env) : json({ error: "nothing is sold here" }, 404);
91
499
 
92
500
  const res = await env.ASSETS.fetch(request);
93
501
  const out = new Response(res.body, res);
94
- const p = url.pathname;
95
- if (p === "/.well-known/agent-card.json" || p.startsWith("/view/")) out.headers.set("access-control-allow-origin", "*");
502
+ if (p === "/.well-known/agent-card.json") out.headers.set("access-control-allow-origin", "*");
96
503
  if (p.startsWith("/assets/")) out.headers.set("cache-control", "public, max-age=31536000, immutable");
97
- // Shards are content-named, so a reader's browser keeps one for good: a change or a
98
- // retraction writes new names. `private`: pages.dev's edge cache cannot be purged, so it
99
- // must never hold one, and a retracted record's shard stops being served when the deploy
100
- // drops it. (This worker's header wins over _headers, which Pages skips for worker responses.)
101
- else if (/^\/view\/cdn\/domains\/[^/]+\/shards\//.test(p))
102
- out.headers.set("cache-control", (res.headers.get("content-type") ?? "").includes("html") ? "no-store" : "private, max-age=31536000, immutable");
103
504
  return out;
104
505
  },
506
+ async scheduled(_event, env, ctx) {
507
+ CONFIG = env.CONFIG ?? CONFIG;
508
+ ctx.waitUntil(index(env));
509
+ },
105
510
  };
511
+ export default worker;
512
+
513
+ // ── self-check: `node site/worker.js` — a fake bucket, a fake AI binding, a fake registry ──
514
+ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv[1]}` && process.argv[1]?.endsWith("/worker.js")) {
515
+ const { localFangorn, SCHEMA_REPO, TYPE_TAG } = await import("../src/publish/view.js");
516
+ const eq = (a, b, m) => { if (JSON.stringify(a) !== JSON.stringify(b)) throw new Error(`${m}: ${JSON.stringify(a)} != ${JSON.stringify(b)}`); };
517
+
518
+ const objs = new Map();
519
+ const object = (k) => { const b = objs.get(k).bytes; return { body: new Blob([b]).stream(), uploaded: objs.get(k).at,
520
+ arrayBuffer: async () => b, text: async () => new TextDecoder().decode(b), json: async () => JSON.parse(new TextDecoder().decode(b)) }; };
521
+ const VIEW = {
522
+ get: async (k) => (objs.has(k) ? object(k) : null),
523
+ head: async (k) => (objs.has(k) ? {} : null),
524
+ put: async (k, b) => { objs.set(k, { bytes: typeof b === "string" ? new TextEncoder().encode(b) : b, at: new Date(Date.now() + objs.size) }); },
525
+ delete: async (ks) => { for (const k of [ks].flat()) objs.delete(k); },
526
+ list: async ({ prefix, delimiter }) => {
527
+ const ks = [...objs.keys()].filter((k) => k.startsWith(prefix)).sort();
528
+ const rest = (k) => k.slice(prefix.length);
529
+ if (!delimiter) return { objects: ks.map((key) => ({ key })), truncated: false };
530
+ return { objects: ks.filter((k) => !rest(k).includes("/")).map((key) => ({ key })), truncated: false,
531
+ delimitedPrefixes: [...new Set(ks.filter((k) => rest(k).includes("/")).map((k) => `${prefix + rest(k).split("/")[0]}/`))] };
532
+ },
533
+ };
534
+ // Words → a 768-d vector, so a query shares dimensions with the rows that share its words.
535
+ const calls = [];
536
+ const AI = { run: async (model, { text }) => { calls.push({ model, text });
537
+ return { data: text.map((t) => { const v = new Array(768).fill(0); for (const w of t.toLowerCase().split(/\W+/)) if (w.length > 3) v[[...w].reduce((h, c) => (h * 31 + c.charCodeAt(0)) % 256, 7)] += 1; return v; }) }; } };
538
+ const env = { VIEW, AI, ASSETS: { fetch: async () => new Response("<!doctype html>site") },
539
+ CONFIG: { app: "shop", name: "Shop", description: "Things for a room.", repos: [] } };
540
+ CONFIG = env.CONFIG;
541
+
542
+ const APP = `0x${"ab".repeat(32)}`, OWNER = `0x${"11".repeat(20)}`, PUB = `0x${"22".repeat(20)}`, TAG = "shop.item.v1";
543
+ const rec = (cid, type, payload) => ({ id: cid, cid, type, payload });
544
+ const chain = {
545
+ [`${OWNER}/${SCHEMA_REPO}`]: { records: [rec("t", TYPE_TAG, { tag: TAG, role_map: { identity: "sku", title: "name", text: "about", media: "doc" } })] },
546
+ [`${PUB}/shop`]: { records: [
547
+ rec("c1", TAG, { sku: "a1", name: "Oak table", about: "a solid oak dining table", doc: "https://docs.example/oak.pdf" }),
548
+ rec("c2", TAG, { sku: "b2", name: "Brass lamp", about: "a brass reading lamp" })] },
549
+ };
550
+ const fangorn = localFangorn(chain, { appId: APP, owner: OWNER });
551
+ await publishView({ fangorn, app: APP, store: r2Store(VIEW), embedBatch: encode(env, DOCUMENT), embedder: WORKER_EMBEDDER, log: () => {} });
552
+ eq([calls[0].model, calls[0].text[0].startsWith(DOCUMENT)], [AI_MODEL, true], "documents go to the AI binding with the document prompt");
553
+
554
+ const call = async (method, params) => (await (await worker.fetch(new Request("https://shop.test/mcp",
555
+ { method: "POST", body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }) }), env)).json());
556
+ eq((await call("initialize", {})).result.serverInfo.name, "Shop", "initialize names the app");
557
+ const names = (await call("tools/list")).result.tools.map((t) => t.name);
558
+ for (const t of ["describe", "search", "get", "similar", "count", "browse"]) if (!names.includes(t)) throw new Error(`missing tool ${t}: ${names}`);
559
+ const described = JSON.parse((await call("tools/call", { name: "describe", arguments: {} })).result.content[0].text);
560
+ eq(described.views.map((v) => v.rows), [2], "describe reads the catalog from R2");
561
+ const found = JSON.parse((await call("tools/call", { name: "search", arguments: { query: "reading lamp", limit: 1 } })).result.content[0].text);
562
+ eq([found.ranked_by, found.hits[0].title], ["meaning", "Brass lamp"], "search ranks by meaning, the query embedded by the same runtime");
563
+ if (!calls.at(-1).text[0].startsWith(QUERY)) throw new Error("the query goes to the AI binding with the query prompt");
564
+ eq((await (await worker.fetch(new Request("https://shop.test/mcp", { method: "POST", body: '{"jsonrpc":"2.0","method":"notifications/initialized"}' }), env)).status), 202, "a notification is accepted, not answered");
565
+
566
+ const cat = await worker.fetch(new Request("https://shop.test/view/cdn/catalog"), env);
567
+ eq([cat.status, cat.headers.get("access-control-allow-origin"), (await cat.json()).domains[0].link_hosts], [200, "*", ["docs.example"]], "the view is served from R2, with the hosts its records link to");
568
+ eq((await worker.fetch(new Request("https://shop.test/doc?u=https://evil.example/x.pdf"), env)).status, 403, "/doc refuses a host no record links to");
569
+ eq((await worker.fetch(new Request("https://shop.test/view/cdn/nope"), env)).status, 404, "a missing file is a 404");
570
+
571
+ // A private app: its rows sealed on chain, opened by the indexer, served only with a pass or a paid call.
572
+ const { sealRow, openRow } = await import("../src/agent/x402.js");
573
+ const SECRET = "s3cret";
574
+ chain[`${PUB}/vault`] = { records: [rec("v1", TAG, await sealRow(SECRET, { sku: "v1", name: "Velvet chair", about: "a green velvet armchair" }))] };
575
+ const sealedAgain = await sealRow(SECRET, { sku: "v1", name: "Velvet chair", about: "a green velvet armchair" });
576
+ eq(sealedAgain, chain[`${PUB}/vault`].records[0].payload, "an unchanged row seals to the same bytes (the same CID: not embedded again)");
577
+ if (JSON.stringify(sealedAgain).includes("Velvet")) throw new Error("a sealed row must not carry its plaintext");
578
+ await publishView({ fangorn, app: APP, store: r2Store(VIEW), embedBatch: encode(env, DOCUMENT), embedder: WORKER_EMBEDDER, log: () => {},
579
+ open: (p) => openRow(SECRET, p) });
580
+ env.PAID_SECRET = SECRET;
581
+ CONFIG = env.CONFIG = { ...env.CONFIG, private: { network: "eip155:84532", asset: `0x${"aa".repeat(20)}`, payTo: `0x${"5e".repeat(20)}`,
582
+ facilitator: "https://fac", name: "USDC", version: "2", pass: { price: "1000000", seconds: 86400 }, call: "10000" } };
583
+ const settles = [];
584
+ const realFetch = globalThis.fetch;
585
+ globalThis.fetch = async (u, init) => {
586
+ const { paymentPayload: p } = JSON.parse(init.body);
587
+ if (u === "https://fac/verify") return new Response(JSON.stringify({ isValid: true, payer: p.payload.authorization.from }));
588
+ settles.push(p);
589
+ return new Response(JSON.stringify({ success: true, transaction: `0x${settles.length}`, network: "eip155:84532", payer: p.payload.authorization.from }));
590
+ };
591
+ try {
592
+ const payment = { x402Version: 2, payload: { signature: "0x", authorization: { from: "0xbuyer", to: CONFIG.private.payTo, value: "1", nonce: "0x1" } } };
593
+ const shard = [...objs.keys()].find((k) => k.startsWith("view/cdn/domains/") && k.endsWith("/manifest")).slice("view/".length);
594
+ const get = (path, headers = {}) => worker.fetch(new Request(`https://shop.test/${path}`, { headers }), env);
595
+ eq([(await get("view/cdn/catalog")).status, (await get(`view/${shard}`)).status], [200, 401], "the catalog is free, the rest of the view is not");
596
+ const asMcp = async (params, headers = {}) => (await (await worker.fetch(new Request("https://shop.test/mcp", { method: "POST", headers,
597
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/call", params }) }), env)).json()).result;
598
+ const search = { name: "search", arguments: { query: "velvet armchair", limit: 1 } };
599
+ const ask = await asMcp(search);
600
+ eq([ask.isError, ask.structuredContent.accepts[0].amount, ask.structuredContent.extensions.bazaar.info.input.toolName, JSON.parse(ask.content[0].text).x402Version],
601
+ [true, "10000", "search", 2], "a paid tool without payment answers with x402's PaymentRequired, listed as an MCP tool");
602
+ eq(JSON.parse((await asMcp({ name: "describe", arguments: {} })).content[0].text).views[0].rows, 3, "describe stays free, and counts the sealed row");
603
+ if (!(await call("tools/list")).result.tools.find((t) => t.name === "search").description.includes("Paid: 0.01 USDC")) throw new Error("tools/list names the price");
604
+
605
+ const quote402 = await worker.fetch(new Request("https://shop.test/pass", { method: "POST" }), env);
606
+ const pr = JSON.parse(atob(quote402.headers.get("payment-required")));
607
+ eq([quote402.status, pr.accepts[0].amount, pr.extensions.bazaar.info.input.method], [402, "1000000", "POST"], "a pass is quoted over x402, Bazaar entry and all");
608
+ const bought = await (await worker.fetch(new Request("https://shop.test/pass", { method: "POST", headers: { "PAYMENT-SIGNATURE": btoa(JSON.stringify(payment)) } }), env)).json();
609
+ const auth = { authorization: `Bearer ${bought.token}` };
610
+ eq([(await get(`view/${shard}`, auth)).status, settles.length], [200, 1], "a pass opens the view, paid once");
611
+ const withPass = JSON.parse((await asMcp(search, auth)).content[0].text);
612
+ eq([withPass.hits[0].title, settles.length], ["Velvet chair", 1], "a pass covers tool calls, and the sealed row was opened and embedded");
613
+ const forged = `${bought.token.split(".")[0]}.${"A".repeat(43)}`;
614
+ eq((await get(`view/${shard}`, { authorization: `Bearer ${forged}` })).status, 401, "a forged pass is refused");
615
+
616
+ const paidOnce = await asMcp({ ...search, _meta: { "x402/payment": payment } });
617
+ eq([JSON.parse(paidOnce.content[0].text).hits[0].title, paidOnce._meta["x402/payment-response"].transaction, settles.at(-1).resource.url],
618
+ ["Velvet chair", "0x2", "https://shop.test/mcp"], "one call, one payment, settled after it ran");
619
+ const failed = await asMcp({ name: "get", arguments: { id: "no-such-row" }, _meta: { "x402/payment": payment } });
620
+ eq([!!JSON.parse(failed.content[0].text).error, !!failed._meta, settles.length], [true, false, 2], "a call that misses is not charged");
621
+ } finally { globalThis.fetch = realFetch; }
622
+ CONFIG = env.CONFIG = { ...env.CONFIG, private: null };
623
+
624
+ // The incremental scan: only updates since the last run, membership and exclusions applied every run.
625
+ const STRANGER = "0x" + "9".repeat(40);
626
+ const logs = [{ publisher: PUB, repo: "shop", head: "0x01", t: 10n }, { publisher: OWNER, repo: "notes", head: "0x02", t: 12n },
627
+ { publisher: STRANGER, repo: "spam", head: "0x04", t: 14n }];
628
+ const asked = [];
629
+ let excluded = null, block = 20n;
630
+ const r = { chain: { getBlockNumber: async () => block }, fangorn: { getAppId: () => APP, getRegistry: () => ({
631
+ log: async (_f, from, to) => { asked.push([from, to]); return logs.filter((l) => l.t >= from && l.t <= to); },
632
+ presents: async (_app, p) => p !== STRANGER,
633
+ exclusionCount: async (_app, x) => (excluded && x.publisher === excluded && !x.repo ? 1 : 0),
634
+ }) } };
635
+ CONFIG = { ...CONFIG, fromBlock: "5" };
636
+ const state = { block: null, repos: {} };
637
+ eq((await presented(r, state)).map((t) => t.repo).sort(), ["notes", "shop"], "the first run scans from the app's fromBlock, and keeps members only");
638
+ logs.push({ publisher: PUB, repo: "shop", head: "0x03", t: 25n });
639
+ block = 30n;
640
+ excluded = OWNER;
641
+ eq((await presented(r, state)).map((t) => [t.repo, t.root]), [["shop", "0x03"]], "the next reads only what is new, and drops what the app excludes");
642
+ eq(asked.map((a) => a.map(String)), [["5", "20"], ["21", "30"]], "each run starts where the last ended");
643
+ console.log("worker.js self-check ok — the lens embeds through the AI binding, /mcp serves the view's tools from R2 with queries embedded by the same runtime, the view and /doc are served from R2, and the indexer scans only new updates and applies membership and exclusions every run");
644
+ }