@fangorn-network/westmarch 2026.10.29 → 2026.11.4-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 (360) hide show
  1. package/README.md +5 -5
  2. package/docs/app-to-agent.md +61 -625
  3. package/package.json +12 -17
  4. package/site/dist/assets/__vite-browser-external-D2U8RZpp.js +1 -0
  5. package/site/dist/assets/embed.worker-CmS57Zti.js +1 -0
  6. package/site/dist/assets/index-Djs8f08m.js +8 -0
  7. package/site/dist/assets/rolldown-runtime-COiEfhsA.js +1 -0
  8. package/site/dist/assets/{transformers.web-BTyOEJ0C.js → transformers.web-CwR_IYQV.js} +1 -1
  9. package/site/dist/index.html +3 -4
  10. package/site/worker.js +115 -338
  11. package/src/agent/agent-card.js +33 -45
  12. package/src/agent/mcp.js +168 -371
  13. package/src/agent/tools.js +2 -1
  14. package/src/agent/view-tools.js +4 -56
  15. package/src/agent/x402.js +182 -369
  16. package/src/core/roles.js +6 -6
  17. package/src/core/shard.js +4 -4
  18. package/src/discover/apps.js +67 -81
  19. package/src/discover/directory.js +2 -2
  20. package/src/market/reactions.js +21 -15
  21. package/src/publish/devnet.js +69 -18
  22. package/src/publish/init.js +1 -1
  23. package/src/publish/ship.js +74 -275
  24. package/src/publish/view.js +52 -53
  25. package/template/README.md +9 -11
  26. package/template/package.json +1 -1
  27. package/plugin/scripts/fx.mjs +0 -266
  28. package/site/dist/assets/AccountNotFoundScreen-C4njXc69-DyVH4CEz.js +0 -1
  29. package/site/dist/assets/AddFundsSelectionScreen-RAoCn7ej-Dz1--SS9.js +0 -31
  30. package/site/dist/assets/Address-H8kD1d9O-BdFZmRwI.js +0 -17
  31. package/site/dist/assets/AffirmativeConsentScreen-BG0MJxku-CxaCAisL.js +0 -6
  32. package/site/dist/assets/AllowlistRejectionScreen-Cae6e1Od-JGk7vndN.js +0 -1
  33. package/site/dist/assets/ApiController-CTLbMCcH.js +0 -5
  34. package/site/dist/assets/ArrowsRightLeftIcon-B8g9adpz.js +0 -1
  35. package/site/dist/assets/AuthenticateWithWalletScreen-CU6hIcFT-CXD9_OP8.js +0 -1
  36. package/site/dist/assets/AwaitingEvmToSolBridgingScreen-D0e_sZMS-BtJCglvU.js +0 -1
  37. package/site/dist/assets/AwaitingExternalEthereumTransferScreen-ur5HL4R7-BgC2TsqH.js +0 -1
  38. package/site/dist/assets/AwaitingPasswordlessCodeScreen-DRHz76mM-B9OzLeEO.js +0 -103
  39. package/site/dist/assets/AwaitingSolToEvmBridgingScreen-CdLRrGD2-C7r5snUL.js +0 -1
  40. package/site/dist/assets/BridgeNetworkSelectionView-CFGjB2nO-BTV0NRio.js +0 -68
  41. package/site/dist/assets/CaptchaScreen-DbpvkIGx-7rSZIuM-.js +0 -1
  42. package/site/dist/assets/CheckCircleIcon-B1l17ioc.js +0 -1
  43. package/site/dist/assets/CheckCircleIcon-BGSI8nKf.js +0 -1
  44. package/site/dist/assets/Checkbox-D1EDeo41-BUfq0w99.js +0 -52
  45. package/site/dist/assets/ChevronDownIcon-B6uJvPHu.js +0 -1
  46. package/site/dist/assets/Chip-CZKIKt9K-r9Nk__0-.js +0 -26
  47. package/site/dist/assets/CoinbaseOnrampStatusScreen-BbyCJDXL-DWWNHxmR.js +0 -16
  48. package/site/dist/assets/ConnectEmailForm-B-VRE0MN-CRQwS0Xu.js +0 -3
  49. package/site/dist/assets/ConnectLedgerScreen-DWHABGot-CZcCt31O.js +0 -10
  50. package/site/dist/assets/ConnectOnlyLandingScreen-CZYx9Bmp-C5IOf-SQ.js +0 -1
  51. package/site/dist/assets/ConnectOnlyStatusScreen-DCRzjxHx-cwg74F3A.js +0 -1
  52. package/site/dist/assets/ConnectOrCreateScreen-CUUYUO07-D28oeK6b.js +0 -1
  53. package/site/dist/assets/ConnectPhoneForm-Dek5xn4C-EEdkKeTp.js +0 -95
  54. package/site/dist/assets/ConnectWalletView-DqI-PTvX-C2mEzukj.js +0 -74
  55. package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-CH_7r8iV.js +0 -7
  56. package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-Z33kis0B.js +0 -1
  57. package/site/dist/assets/ConnectorUtil-DH4NePk5.js +0 -21
  58. package/site/dist/assets/ConstantsUtil-DmLsRHAl.js +0 -198
  59. package/site/dist/assets/CopyToClipboard-i_OQSBJr-_G88JCVR.js +0 -39
  60. package/site/dist/assets/CopyableText-CQapvaMr-CGGfc_zM.js +0 -28
  61. package/site/dist/assets/CrossAppAuthScreen-CLw7ymZq-C9Okoc0V.js +0 -1
  62. package/site/dist/assets/CustomLandingScreenView-Cm_MBSyX-D2l6hdSl.js +0 -22
  63. package/site/dist/assets/DelegatedActionsConsentScreen-DYF2U4y5-Dda3KKqS.js +0 -1
  64. package/site/dist/assets/DelegatedActionsRevokeScreen-bPp6Uwyh-DG8kJPt1.js +0 -1
  65. package/site/dist/assets/DepositAddressAddressStepView-4vdkb55L-CcOUfn6f.js +0 -187
  66. package/site/dist/assets/DepositAddressScreen-DBLRs7aI-DeituDNh.js +0 -8
  67. package/site/dist/assets/DepositAddressV3Screen-CDqIEMQw-FDg6K14-.js +0 -1
  68. package/site/dist/assets/EmailInputForm-Cqo1mda8-BmbxvPHC.js +0 -124
  69. package/site/dist/assets/EmbeddedWalletConnectingScreen-D4T7DUzs-B05CQ9rx.js +0 -1
  70. package/site/dist/assets/EmbeddedWalletCreatedScreen-D7WhW5ve-Cxd1b9XH.js +0 -1
  71. package/site/dist/assets/EmbeddedWalletKeyExportScreen-CqV4NYQ3-CrJy0ViX.js +0 -23
  72. package/site/dist/assets/EmbeddedWalletOnAccountCreateScreen-BoKb3Q2S-Bakaa3zu.js +0 -1
  73. package/site/dist/assets/EmbeddedWalletPasswordUpdateScreen-D3rMlqS7-j78vKrcj.js +0 -1
  74. package/site/dist/assets/EmbeddedWalletPasswordUpdateSplashScreen-BPFkWJeE-D3dr7W9_.js +0 -1
  75. package/site/dist/assets/EnrollTotp-Dibew4dp-BXbYV8nI.js +0 -66
  76. package/site/dist/assets/EnvelopeIcon-DjPofnRI.js +0 -1
  77. package/site/dist/assets/ErrorBanner-BcpGRt0h-BhH6_V-9.js +0 -21
  78. package/site/dist/assets/ErrorMessage-D8VaAP5m-Bs7uX2a9.js +0 -8
  79. package/site/dist/assets/ErrorScreen-DipdTWzE-BgPRgnOb.js +0 -4
  80. package/site/dist/assets/ErrorScreen-DipdTWzE-CvxXC6pz.js +0 -1
  81. package/site/dist/assets/ExclamationCircleIcon-BE-WGrut.js +0 -1
  82. package/site/dist/assets/ExclamationTriangleIcon-Ca1Xlc_f.js +0 -1
  83. package/site/dist/assets/FarcasterConnectStatusScreen-51tjUxqq-De2JvZdV.js +0 -75
  84. package/site/dist/assets/FarcasterSignerStatusScreen-6x-Uh95G-bLp3hXoO.js +0 -28
  85. package/site/dist/assets/FiatOnrampScreen-BAhYeiTI-Jr6D6JiZ.js +0 -491
  86. package/site/dist/assets/FingerPrintIcon-DOCbS93y.js +0 -1
  87. package/site/dist/assets/FundSolWalletWithExternalSolanaWallet-WtLwYaOl-A_G5kfa1.js +0 -1
  88. package/site/dist/assets/FundWalletMethodHeader-BWNkokCT-LPv35wkD.js +0 -1
  89. package/site/dist/assets/FundWithBankDepositScreen-DajkHxBD-0hfGrfvf.js +0 -58
  90. package/site/dist/assets/FundingEditAmountScreen-CpvpiO4M-Dz0s_NWR.js +0 -1
  91. package/site/dist/assets/FundingMethodSelectionScreen-Db7vhRlE-ZGm-3-Io.js +0 -1
  92. package/site/dist/assets/GlobeAltIcon-BBRl2MMn.js +0 -1
  93. package/site/dist/assets/GooglePay-B53WnudL-BGiVpB8y.js +0 -1
  94. package/site/dist/assets/HCaptchaWrapper-CUi9LJsp-CHdfIeD_.js +0 -4
  95. package/site/dist/assets/InAppBrowserLoginNotPossible-BMR9br1T-Cgoiow3m.js +0 -1
  96. package/site/dist/assets/InfoBanner-Cb3p1z12-_YqQmRiu.js +0 -22
  97. package/site/dist/assets/InjectedWalletIcon-DLcYOGDj-tuIrKQHH.js +0 -1
  98. package/site/dist/assets/InstallWalletScreen-DTA8dwLv-BMU_wa61.js +0 -1
  99. package/site/dist/assets/JsonTree-BHzNC-ic-DcVr0YF0.js +0 -34
  100. package/site/dist/assets/LabelXs-oqZNqbm_-CNprGVQM.js +0 -6
  101. package/site/dist/assets/LandingScreen-CGWUoSUG-fH6rsQen.js +0 -1
  102. package/site/dist/assets/Layouts-BMRfo5hw-e-sepi6F.js +0 -77
  103. package/site/dist/assets/Link-BdDilT2T-BdwlRJch.js +0 -40
  104. package/site/dist/assets/LinkConflictScreen-C3ZEPsgl-BXKN2Qm5.js +0 -77
  105. package/site/dist/assets/LinkEmailScreen-dKo9frwc-Cyn7Q8p1.js +0 -1
  106. package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-CWiqnwLM.js +0 -117
  107. package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-YmDevJzf.js +0 -1
  108. package/site/dist/assets/LinkPhoneScreen-oIUpfj0w-h7shW-Ay.js +0 -1
  109. package/site/dist/assets/Loader-UAZqxsnw-DJEVblm1.js +0 -62
  110. package/site/dist/assets/LoadingSkeleton-BMsgO5PV-D2atjsP5.js +0 -17
  111. package/site/dist/assets/LockClosedIcon-9EFzWK1C.js +0 -1
  112. package/site/dist/assets/LoginFailedScreen-CN0dJV6U-By3Si77a.js +0 -1
  113. package/site/dist/assets/ManualTransferScreen-CHqcuqbs-BAHPY8rs.js +0 -1
  114. package/site/dist/assets/MfaAuthEnrollmentFlowScreen-Dj7gPTRC-CLjffFG1.js +0 -1
  115. package/site/dist/assets/MfaAuthVerifyFlowScreen-DbFpyWMy-BmQg1Y61.js +0 -1
  116. package/site/dist/assets/MfaEnrollmentFlowScreen-DhLnGgnr-DmBtTtlw.js +0 -1
  117. package/site/dist/assets/MfaVerifyFlowScreen-C_XPjMRP-4a683Bmf.js +0 -1
  118. package/site/dist/assets/ModalFooter-BCuEK_nz-C_71qsaz.js +0 -403
  119. package/site/dist/assets/MoonpayStatusScreen-CzTUtokc-DEHHcEf8.js +0 -16
  120. package/site/dist/assets/OAuthStatusScreen-ufbOa-da-BjAb_WsY.js +0 -1
  121. package/site/dist/assets/OpenLink-CUpJ1mOr-BLWFsPOW.js +0 -39
  122. package/site/dist/assets/PasskeySelectSignupOrLogin-xh2ScC_l-2PJTJxX-.js +0 -1
  123. package/site/dist/assets/PasskeyStatusScreen-Bla8MaOk-DCEg761l.js +0 -6
  124. package/site/dist/assets/PasswordRecoveryScreen-awGXZkQk-8nVjNc8k.js +0 -20
  125. package/site/dist/assets/PhArrowCircleDown-D97G-BOA.js +0 -14
  126. package/site/dist/assets/PhArrowClockwise-DVgyFuez.js +0 -14
  127. package/site/dist/assets/PhArrowDown-87b1BizM.js +0 -14
  128. package/site/dist/assets/PhArrowLeft-Da0MfnbK.js +0 -14
  129. package/site/dist/assets/PhArrowRight-AdrIL4DW.js +0 -14
  130. package/site/dist/assets/PhArrowSquareOut-Bk2CMG3I.js +0 -14
  131. package/site/dist/assets/PhArrowUp-4sgyKPGx.js +0 -14
  132. package/site/dist/assets/PhArrowUpRight-BNghD2zq.js +0 -14
  133. package/site/dist/assets/PhArrowsClockwise-BXRn1GEl.js +0 -14
  134. package/site/dist/assets/PhArrowsDownUp-DM09Jo_3.js +0 -14
  135. package/site/dist/assets/PhArrowsLeftRight-MuKBLUoF.js +0 -14
  136. package/site/dist/assets/PhBank-fHbgCqqZ.js +0 -14
  137. package/site/dist/assets/PhBrowser-2-9m-AkM.js +0 -14
  138. package/site/dist/assets/PhCaretDown-BDNabFuL.js +0 -14
  139. package/site/dist/assets/PhCaretLeft-CI460R-A.js +0 -14
  140. package/site/dist/assets/PhCaretRight-D7ZS3Ls8.js +0 -14
  141. package/site/dist/assets/PhCaretUp-C-iIfyvO.js +0 -14
  142. package/site/dist/assets/PhCheck-DxQXn57r.js +0 -14
  143. package/site/dist/assets/PhCircleHalf-MJZeRBGF.js +0 -14
  144. package/site/dist/assets/PhClock-x3MS3Mwi.js +0 -14
  145. package/site/dist/assets/PhCompass-hYn3HhGN.js +0 -14
  146. package/site/dist/assets/PhCopy-CWNYcABI.js +0 -14
  147. package/site/dist/assets/PhCreditCard-Fy4pzwtt.js +0 -14
  148. package/site/dist/assets/PhCurrencyDollar-BgiaenCi.js +0 -14
  149. package/site/dist/assets/PhDesktop-CxrzCSv5.js +0 -14
  150. package/site/dist/assets/PhDeviceMobile-CsyA5Goi.js +0 -14
  151. package/site/dist/assets/PhDotsThree-D-k1BiYg.js +0 -14
  152. package/site/dist/assets/PhEnvelope-D8kzeNox.js +0 -14
  153. package/site/dist/assets/PhFunnelSimple-CfQs5DAW.js +0 -14
  154. package/site/dist/assets/PhGlobe-DvmSc9_A.js +0 -14
  155. package/site/dist/assets/PhIdentificationCard-CfkZm-5K.js +0 -14
  156. package/site/dist/assets/PhImage-Cf0J2ZfJ.js +0 -14
  157. package/site/dist/assets/PhInfo-Bwi51-2X.js +0 -14
  158. package/site/dist/assets/PhLightbulb-C4FZV7Es.js +0 -14
  159. package/site/dist/assets/PhMagnifyingGlass-C9u8jSCJ.js +0 -14
  160. package/site/dist/assets/PhPaperPlaneRight-zxQVvPLX.js +0 -14
  161. package/site/dist/assets/PhPlus-C4UoW-2n.js +0 -14
  162. package/site/dist/assets/PhPower-CFyWDmgD.js +0 -14
  163. package/site/dist/assets/PhPuzzlePiece-BjoNVfST.js +0 -14
  164. package/site/dist/assets/PhQrCode-CP3tFauY.js +0 -14
  165. package/site/dist/assets/PhQuestion-wOWJBd3G.js +0 -14
  166. package/site/dist/assets/PhQuestionMark-CV0k9C0Y.js +0 -14
  167. package/site/dist/assets/PhSealCheck-vIKzREuN.js +0 -14
  168. package/site/dist/assets/PhSignOut-CxELV-i0.js +0 -14
  169. package/site/dist/assets/PhSpinner-CGDmbzUd.js +0 -14
  170. package/site/dist/assets/PhTrash-C9PD0SAt.js +0 -14
  171. package/site/dist/assets/PhUser-0sWNXQeZ.js +0 -14
  172. package/site/dist/assets/PhVault-6JTskUcC.js +0 -14
  173. package/site/dist/assets/PhWarning-CoKs3gz6.js +0 -14
  174. package/site/dist/assets/PhWarningCircle-BXHw1fCt.js +0 -14
  175. package/site/dist/assets/PhX-DX0SFIqC.js +0 -14
  176. package/site/dist/assets/PhoneIcon-CZ47md80.js +0 -1
  177. package/site/dist/assets/PinInput-DbZ0b1i1-BrTXu3Km.js +0 -247
  178. package/site/dist/assets/PrivyPluginContext-DA-yS5vO-CY60yubk.js +0 -1
  179. package/site/dist/assets/QrCode-DbnZwlkH-CcMrWV5D.js +0 -22
  180. package/site/dist/assets/RecoveryOAuthStatusScreen-CsgtTI2x-DgeDnHOK.js +0 -1
  181. package/site/dist/assets/RecoveryPasswordCreateScreen-Be-qJ-LU-CvJJwLhK.js +0 -1
  182. package/site/dist/assets/RecoverySelectionScreen-D1iGtpmi-CADtGtSV.js +0 -7
  183. package/site/dist/assets/SIWXUtil-Cpiv91-M.js +0 -1
  184. package/site/dist/assets/Screen-D30meWsY-vEusJ7KX.js +0 -175
  185. package/site/dist/assets/ScreenHeader-CHmc4-Lu-BvGTLg53.js +0 -31
  186. package/site/dist/assets/ScreenLayout-OwaQQcxH-cfOTmyl0.js +0 -1
  187. package/site/dist/assets/SelectSourceAsset-CWFog6gm-DxYklZYs.js +0 -140
  188. package/site/dist/assets/SetAutomaticRecoveryScreen-BO_OEqAZ-oeqeo05x.js +0 -14
  189. package/site/dist/assets/SetWalletPasswordForm-DwCTVtAh-BxFee9UA.js +0 -11
  190. package/site/dist/assets/ShieldCheckIcon-eFjsosCA.js +0 -1
  191. package/site/dist/assets/SignRequestScreen-BHKv32KR-z8ixfIma.js +0 -26
  192. package/site/dist/assets/SolanaWalletConnector-C7Lqk-Wz-Bc_lvdiF.js +0 -1
  193. package/site/dist/assets/StackedContainer-B2vaEl56-Do5dXB8-.js +0 -24
  194. package/site/dist/assets/StandardSignAndSendTransactionScreen-CfhIXVtd-DudetZAc.js +0 -20
  195. package/site/dist/assets/Subtitle-CV-2yKE4-DV0o1av3.js +0 -13
  196. package/site/dist/assets/TelegramAuthScreen-UL9zLfO8-Bo3sONvf.js +0 -1
  197. package/site/dist/assets/Title-BnzYV3Is-C3qOPnO_.js +0 -7
  198. package/site/dist/assets/TodoList-DnyULl18-BvxvubbF.js +0 -36
  199. package/site/dist/assets/TransactionDetails-e9nesl30-WWflkOIi.js +0 -109
  200. package/site/dist/assets/TransactionErrorView-BDBNqA_f-CotYKcgf.js +0 -178
  201. package/site/dist/assets/TransferFromWalletScreen-Qvn1Yuno-sVFlWqa8.js +0 -31
  202. package/site/dist/assets/TransferOrBridgeLoadingScreen-Dl1I_iIz-CV2-mY19.js +0 -6
  203. package/site/dist/assets/TurnstileWrapper-B7sNddys-oPbuMTQt.js +0 -1
  204. package/site/dist/assets/UpdateEmailScreen-DVOhPV0H-D_mjSpAy.js +0 -1
  205. package/site/dist/assets/UpdatePhoneScreen-CXRswTNZ-6RLG0ahv.js +0 -1
  206. package/site/dist/assets/UserLimitReachedScreen-5we2DHn8-CaVN0bti.js +0 -1
  207. package/site/dist/assets/Value-DTgR824E-Bp6WGZZm.js +0 -27
  208. package/site/dist/assets/WalletCards-DH1rqayz-D3cOTb9x.js +0 -1
  209. package/site/dist/assets/WalletIcon-DOIZhb2l.js +0 -1
  210. package/site/dist/assets/WalletInfoCard-sq_2wgFg-bOqfl5MA.js +0 -29
  211. package/site/dist/assets/WalletInterstitialScreen-Sh7LfsAh-DWaVkMCA.js +0 -1
  212. package/site/dist/assets/WalletLink-DK5LB5Ha-DjUZvqs-.js +0 -20
  213. package/site/dist/assets/WalletOverflowButton-bfCnp-9T-B6P7DQXA.js +0 -1
  214. package/site/dist/assets/WarningBanner-ZZqCEtZK-Bc2YKZb7.js +0 -21
  215. package/site/dist/assets/__vite-browser-external-NciY4Vu1.js +0 -1
  216. package/site/dist/assets/_esm-BZP3cXTv.js +0 -1
  217. package/site/dist/assets/_esm-ZmzBJpEs.js +0 -6
  218. package/site/dist/assets/accounts-D4AXF17G.js +0 -1
  219. package/site/dist/assets/accounts-IkdFx9nq.js +0 -1
  220. package/site/dist/assets/analytics-mkkvFRju-BRBcadka.js +0 -1
  221. package/site/dist/assets/baseSepolia-Bn1j1Ysw.js +0 -1
  222. package/site/dist/assets/basic-Cz1YiCSk.js +0 -1575
  223. package/site/dist/assets/capitalizeFirstLetter-DmLYqXsO-DtOXx-2n.js +0 -1
  224. package/site/dist/assets/ccip-B1J3oTZx.js +0 -7
  225. package/site/dist/assets/ccip-Bd7261zy.js +0 -1
  226. package/site/dist/assets/ccip-D6EHKpjI.js +0 -1
  227. package/site/dist/assets/chain-scefkYIH.js +0 -5
  228. package/site/dist/assets/check-DHnllI8N.js +0 -1
  229. package/site/dist/assets/chevron-down-1y-r4bGO.js +0 -1
  230. package/site/dist/assets/circle-alert-OwxamXUX.js +0 -1
  231. package/site/dist/assets/circle-check-big-3sZGVC10.js +0 -1
  232. package/site/dist/assets/circle-x-DQjNUV9J.js +0 -1
  233. package/site/dist/assets/client-B-BpRtwY.js +0 -1
  234. package/site/dist/assets/client-BfIR1FvH.js +0 -9
  235. package/site/dist/assets/coinbase-DCPC2L_R-YEuIn3jh.js +0 -3
  236. package/site/dist/assets/copy-DMOX_yn7.js +0 -1
  237. package/site/dist/assets/core-GIEmxmAa.js +0 -12
  238. package/site/dist/assets/createLucideIcon-BsERoFTA.js +0 -1
  239. package/site/dist/assets/defineChain-B-SQDLTG.js +0 -1
  240. package/site/dist/assets/dijkstra-CY95afk4.js +0 -1
  241. package/site/dist/assets/dist-CoS6E-3x.js +0 -1
  242. package/site/dist/assets/dist-Cp6IXeJd.js +0 -1
  243. package/site/dist/assets/dist-CrNxmdZj.js +0 -1
  244. package/site/dist/assets/dist-DYGtf4F0.js +0 -16
  245. package/site/dist/assets/embed.worker-Cnl4VGr3.js +0 -1
  246. package/site/dist/assets/errors-BQ3N-RVt-CZPAWCgC.js +0 -1
  247. package/site/dist/assets/esm-C3DslVJx.js +0 -1
  248. package/site/dist/assets/esm-Ci1ogKuK.js +0 -1
  249. package/site/dist/assets/esm-Co94ENUV.js +0 -37
  250. package/site/dist/assets/esm-bb8SANZh.js +0 -1
  251. package/site/dist/assets/esm-n2lWo7kz.js +0 -1
  252. package/site/dist/assets/ethers-zTjbodk5-Cs648CnD.js +0 -1
  253. package/site/dist/assets/eventemitter3-Dzc_0Uq2.js +0 -1
  254. package/site/dist/assets/external-link-BBPG3rG7.js +0 -1
  255. package/site/dist/assets/farcaster-DPlSjvF5-CzBCmgyL.js +0 -1
  256. package/site/dist/assets/features-CuiHbgEJ.js +0 -2
  257. package/site/dist/assets/fingerprint-pattern-CjLtyIxB.js +0 -1
  258. package/site/dist/assets/floating-ui.react-DmaCfayr.js +0 -1
  259. package/site/dist/assets/floating-ui.react-dom-CaoMF8mP.js +0 -1
  260. package/site/dist/assets/formatErc20TokenAmount-BuPk9xcy-BVqOKQif.js +0 -1
  261. package/site/dist/assets/formatter-CVbp4SlJ.js +0 -1
  262. package/site/dist/assets/get-entropy-details-for-user-dHRH5Gpi-BNiOFXbK.js +0 -1
  263. package/site/dist/assets/getChainName-DjpPdUSc-DUyKDrnp.js +0 -1
  264. package/site/dist/assets/getErc20Balance-jXNpFf0N-q4bV8kQq.js +0 -1
  265. package/site/dist/assets/getErc20TokenInfo-BNTrzLMP-DcnTFrXN.js +0 -1
  266. package/site/dist/assets/getFormattedUsdFromLamports-De3U9GlO-Gx4_wxON.js +0 -1
  267. package/site/dist/assets/getUsdcMintAddress-BVgm9GRo-r2UnDeEy.js +0 -1
  268. package/site/dist/assets/guards-BIW-GiMJ-D3tWTQAR.js +0 -1
  269. package/site/dist/assets/hooks.module-BYZGfwDl.js +0 -1
  270. package/site/dist/assets/hourglass-D_GfQdJr.js +0 -1
  271. package/site/dist/assets/id-UqEwL2BI-CTlvRMA5.js +0 -1
  272. package/site/dist/assets/index-BdEw5wyl-kLbhqLbv.js +0 -1
  273. package/site/dist/assets/index-C2h3EneX.js +0 -8
  274. package/site/dist/assets/index-CWARkn2w-DxuckIFn.js +0 -61
  275. package/site/dist/assets/index-DvMddJcd-CNBb4VUn.js +0 -12
  276. package/site/dist/assets/index-YiCw0Y_x-Czl0tWfF.js +0 -436
  277. package/site/dist/assets/index.browser-B-i-Lj3J.js +0 -1
  278. package/site/dist/assets/index.browser-BMmUcykv.js +0 -1
  279. package/site/dist/assets/index.es-Crd0TyUS.js +0 -2
  280. package/site/dist/assets/index.es-DQbup1WG.js +0 -3
  281. package/site/dist/assets/isPaymentRequestAvailable-Bq1cemEn-Cjf3l05I.js +0 -1
  282. package/site/dist/assets/jsx-runtime-CndCZlyt.js +0 -1
  283. package/site/dist/assets/landmark-BZPqMFEf.js +0 -1
  284. package/site/dist/assets/lib-DGtzi2DK.js +0 -1
  285. package/site/dist/assets/localBatchGatewayRequest-B71J8sQ9.js +0 -29
  286. package/site/dist/assets/lock-DyN_c-ud.js +0 -1
  287. package/site/dist/assets/logger-CsXm3oIv-B0UYpNFI.js +0 -1
  288. package/site/dist/assets/mail-V_mcPb64.js +0 -1
  289. package/site/dist/assets/modal-context-CwmSeFcv-DPWNJrfK.js +0 -1
  290. package/site/dist/assets/native-BKj27wfc.js +0 -1
  291. package/site/dist/assets/ofetch.CWycOUEr-Duby3iHT.js +0 -1
  292. package/site/dist/assets/parseAbi-Csg-8t59.js +0 -2
  293. package/site/dist/assets/parseAbiParameters-BWbIMYe4.js +0 -1
  294. package/site/dist/assets/parseEther-CHS0GNkM.js +0 -1
  295. package/site/dist/assets/pkce-DXF0yKjP-7_VY-d83.js +0 -1
  296. package/site/dist/assets/preload-helper-CRzLMJPS.js +0 -1
  297. package/site/dist/assets/privy-context-81KmsBw2-DiR6-Yq8.js +0 -2
  298. package/site/dist/assets/property-DuZ9DLP4.js +0 -3
  299. package/site/dist/assets/react-BfYA1q0G.js +0 -1
  300. package/site/dist/assets/react-CK2HRI1t.js +0 -1
  301. package/site/dist/assets/react-DxGeY8B8.js +0 -1
  302. package/site/dist/assets/react-auth-sHnipzbS.js +0 -1
  303. package/site/dist/assets/react-dom-BI2Koe4o.js +0 -1
  304. package/site/dist/assets/reservoir-x-nGuZkT-BguVFH3D.js +0 -1
  305. package/site/dist/assets/rolldown-runtime-Bjp52BOI.js +0 -1
  306. package/site/dist/assets/safe-url-D7SRPu33-CkMedGro.js +0 -1
  307. package/site/dist/assets/secp256k1-BeYL8aZl.js +0 -1
  308. package/site/dist/assets/secp256k1-Bh4MSkhz.js +0 -1
  309. package/site/dist/assets/secp256k1-Ci4cqHl0.js +0 -1
  310. package/site/dist/assets/secp256k1-DsxXqbXv.js +0 -1
  311. package/site/dist/assets/secp256k1-N9RUmafO.js +0 -1
  312. package/site/dist/assets/serializeAuthorizationList-DGMik9Wx.js +0 -1
  313. package/site/dist/assets/serializeSignature-CWKpxoab.js +0 -2
  314. package/site/dist/assets/sha2-C6s7zZmb.js +0 -1
  315. package/site/dist/assets/shared-DRZUmnL5-BewE5wK8.js +0 -193
  316. package/site/dist/assets/shared-FM0rljBt-CxLACri_.js +0 -21
  317. package/site/dist/assets/shouldProceedtoEmbeddedWalletCreationFlow-B3vyavrh-BkAKsRNi.js +0 -1
  318. package/site/dist/assets/simulateTransaction-CfuOrae4-PjA_tGjX.js +0 -1
  319. package/site/dist/assets/smartphone-3p8nFSTE.js +0 -1
  320. package/site/dist/assets/src-BBjkfi-Q.js +0 -1
  321. package/site/dist/assets/storage-Ufl800Ne-1qCR2JMO.js +0 -8
  322. package/site/dist/assets/stringify-DqUj9VzO.js +0 -20
  323. package/site/dist/assets/stripe.esm-DEi2D291.js +0 -2
  324. package/site/dist/assets/styles-BsotlekN-Aq27nZGc.js +0 -9
  325. package/site/dist/assets/styles-Cm9H63WO-p_ic_dxE.js +0 -92
  326. package/site/dist/assets/styles-DVyDvTdj-CjsWqAld.js +0 -74
  327. package/site/dist/assets/styles-hslXy6xG-D5QHIrJU.js +0 -164
  328. package/site/dist/assets/telegram-B-JqnkqZ-Dqkm4rDn.js +0 -1
  329. package/site/dist/assets/to-ui-error-DWe-qwS3-Bi1HUQI9.js +0 -4
  330. package/site/dist/assets/toViemAccount-B5iDGq1b-CdFZwv07.js +0 -2
  331. package/site/dist/assets/transaction-BNTP-bFm-M5tJx8vY.js +0 -1
  332. package/site/dist/assets/transfer-6YztDh-t-BVQkTvG-.js +0 -1
  333. package/site/dist/assets/triangle-alert-BG3Qw-Hq.js +0 -1
  334. package/site/dist/assets/twitch-5IOe4sIQ-CaXHFlAu.js +0 -1
  335. package/site/dist/assets/types-4CuOD23i.js +0 -1
  336. package/site/dist/assets/use-headless-crypto-deposit-Yn-QRLB3-CQqeyhGY.js +0 -1
  337. package/site/dist/assets/use-unlink-wallet-BKK4_5Ur-C0xQN_Lp.js +0 -1
  338. package/site/dist/assets/useActiveWallet-B-yZYGc6-BkK6rFBm.js +0 -123
  339. package/site/dist/assets/useGetSolPrice-x7gfUIHJ-CLVXqv6I.js +0 -1
  340. package/site/dist/assets/useGetTokenPrice-CaoUkb79-DAXXs3rs.js +0 -1
  341. package/site/dist/assets/useI18n-C-5n_noF-CGpkgIVy.js +0 -1
  342. package/site/dist/assets/useWalletBalance-CZnP5f_f-Cfd64m4n.js +0 -1
  343. package/site/dist/assets/useWallets-X1ndvJ_U-CAYqg7Za.js +0 -1
  344. package/site/dist/assets/utils-BkR7EQjg.js +0 -1
  345. package/site/dist/assets/utils-DJhBNOZA.js +0 -1
  346. package/site/dist/assets/utils-DdckVfQr.js +0 -1
  347. package/site/dist/assets/w3m-modal-B4H_uiPH.js +0 -1174
  348. package/site/dist/assets/wallet-BNI12IYk.js +0 -1
  349. package/site/dist/assets/wallet-CITSaPlB.js +0 -2
  350. package/site/dist/assets/wallet-connect-BvJtUsDt-CVlSNIXP.js +0 -1
  351. package/site/dist/assets/walletconnect-registry-xxG8XLCb-BpzpBq5s.js +0 -1
  352. package/site/dist/assets/walletconnect-v2-3frQFwbg-CzZ6oybX.js +0 -12
  353. package/site/dist/assets/wui-ux-by-reown-XyHdtV1O.js +0 -1147
  354. package/site/dist/assets/x-gjDrY2rk.js +0 -1
  355. package/src/discover/explore.js +0 -291
  356. package/src/market/settle.js +0 -165
  357. package/src/market/terms.js +0 -200
  358. package/src/publish/cli.js +0 -336
  359. package/src/publish/envelope.js +0 -185
  360. package/src/publish/manifest.js +0 -142
@@ -1,200 +0,0 @@
1
- // Who gets paid, and how much, when something sells.
2
- //
3
- // An app owner registers terms; publishers join under them; a buyer pays once.
4
- // This file is the arithmetic in the middle, and it is the only revenue
5
- // mechanism in the whole architecture — discovery cannot be charged for (the
6
- // query never leaves the client and the index holds 4 KB per corpus), so a take
7
- // at settlement is the business model or there isn't one.
8
- //
9
- // Two layers, because they are set by different people at different times:
10
- //
11
- // app terms the owner's cut, fixed when the app is registered and hashed so
12
- // a publisher can prove what they agreed to
13
- // lineage what a publisher owes UPSTREAM, declared per resource when they
14
- // publish. Paid out of the publisher's share, never the app's:
15
- // a derivative's author pays their sources, and the app's cut does
16
- // not shrink because someone built on someone else.
17
- //
18
- // That second layer is the point. An agent buys three corpora, synthesises a
19
- // fourth, publishes it with lineage naming the three, and every later sale of
20
- // the derivative pays back up the chain. Knowledge in, concept out, concept
21
- // becomes knowledge someone else builds on — with the money following the
22
- // citations instead of stopping at the last hop.
23
- //
24
- // ponytail: BigInt base units, one level of lineage, no recursion. A derivative
25
- // OF a derivative declares its own immediate sources and each hop settles on its
26
- // own sale — walking the tree at settlement time would mean fetching a stranger's
27
- // terms mid-payment, and a payment that depends on someone else's server being
28
- // up is a payment that fails.
29
-
30
- const BPS = 10000n;
31
- const ADDR = /^0x[0-9a-fA-F]{40}$/;
32
-
33
- const addr = (a) => {
34
- const s = String(a ?? "").toLowerCase();
35
- if (!ADDR.test(s)) throw new Error(`not an address: ${a}`);
36
- return s;
37
- };
38
- const bps = (n, what) => {
39
- const v = BigInt(n ?? 0);
40
- if (v < 0n || v > BPS) throw new Error(`${what} must be 0..10000 bps, got ${n}`);
41
- return v;
42
- };
43
-
44
- /**
45
- * An app's terms, canonical.
46
- *
47
- * Canonical because the hash is the thing a publisher agrees to and a buyer can
48
- * check: same terms must produce the same bytes on any machine, in any key
49
- * order, forever. So: fixed field order, lowercase addresses, decimal strings
50
- * for numbers (JSON has no integers), and nothing else in the object.
51
- */
52
- export function appTerms({ appId, owner, appBps = 0, currency = "USDC", chainId = 421614 }) {
53
- if (!appId) throw new Error("terms need an appId");
54
- return {
55
- v: 1,
56
- appId: String(appId),
57
- owner: addr(owner),
58
- appBps: String(bps(appBps, "appBps")),
59
- currency: String(currency),
60
- chainId: Number(chainId),
61
- };
62
- }
63
-
64
- /** Canonical bytes → sha-256. Async because that is the only hash both node and
65
- * a browser have without a dependency. */
66
- export async function termsHash(t) {
67
- const canon = JSON.stringify(appTerms(t));
68
- const d = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(canon));
69
- return `0x${[...new Uint8Array(d)].map((b) => b.toString(16).padStart(2, "0")).join("")}`;
70
- }
71
-
72
- /** What a publisher owes upstream for one resource. Deduped by payee — the same
73
- * source cited twice is one debt, not two, and merging is the only reading that
74
- * cannot be gamed by repeating an entry. */
75
- export function lineage(entries = []) {
76
- const by = new Map();
77
- for (const e of entries) {
78
- const to = addr(e.to);
79
- by.set(to, { to, bps: (by.get(to)?.bps ?? 0n) + bps(e.bps, "lineage bps"), note: e.note ?? by.get(to)?.note ?? "" });
80
- }
81
- const out = [...by.values()];
82
- const total = out.reduce((s, e) => s + e.bps, 0n);
83
- if (total > BPS) throw new Error(`lineage owes ${total} bps of the publisher's share — more than all of it`);
84
- return out.map((e) => ({ to: e.to, bps: String(e.bps), ...(e.note ? { note: e.note } : {}) }));
85
- }
86
-
87
- /**
88
- * One payment → the payouts it becomes.
89
- *
90
- * Integer base units end to end, and the dust is given to the publisher rather
91
- * than rounded away: the payouts MUST sum to exactly what the buyer paid, or
92
- * settlement is inventing or destroying money. Every share rounds down; the
93
- * publisher absorbs the difference, which is at most one base unit per payee.
94
- */
95
- export function splitPayment(amount, { terms, publisher, lineage: up = [] } = {}) {
96
- const total = BigInt(amount);
97
- if (total < 0n) throw new Error("amount must not be negative");
98
- const t = appTerms(terms);
99
- const pub = addr(publisher);
100
-
101
- const payouts = [];
102
- const appCut = (total * BigInt(t.appBps)) / BPS;
103
- if (appCut > 0n) payouts.push({ to: t.owner, amount: appCut, why: `app ${t.appId} (${t.appBps} bps)` });
104
-
105
- // Everything the app did not take is the publisher's, and upstream is paid
106
- // out of that — so a publisher who cites nobody keeps it all, and one who
107
- // builds on three sources pays them from their own half.
108
- const publisherPool = total - appCut;
109
- let owed = 0n;
110
- for (const e of lineage(up)) {
111
- const cut = (publisherPool * BigInt(e.bps)) / BPS;
112
- if (cut === 0n) continue;
113
- owed += cut;
114
- payouts.push({ to: e.to, amount: cut, why: `upstream ${e.note || e.to.slice(0, 10)} (${e.bps} bps of the publisher's share)` });
115
- }
116
-
117
- const keeps = publisherPool - owed;
118
- payouts.push({ to: pub, amount: keeps, why: "publisher" });
119
-
120
- // Merge payees — an app owner who is also the publisher gets one payout, not
121
- // two, and a downstream reconciliation that sees the same address twice has
122
- // no way to tell a split from a double-pay.
123
- const by = new Map();
124
- for (const p of payouts) {
125
- const at = by.get(p.to);
126
- by.set(p.to, at ? { ...at, amount: at.amount + p.amount, why: `${at.why} + ${p.why}` } : p);
127
- }
128
- const merged = [...by.values()];
129
- const sum = merged.reduce((s, p) => s + p.amount, 0n);
130
- if (sum !== total) throw new Error(`payouts sum to ${sum}, buyer paid ${total}`);
131
- return merged;
132
- }
133
-
134
- /** Human-readable, for a receipt or a quote. 6-decimal base units — every asset
135
- * this settles on is 6-decimal, and a bare "50000" on a buy button is not a
136
- * price anyone reads. */
137
- export const label = (base, currency = "USDC") => `${(Number(base) / 1e6).toFixed(2)} ${currency}`;
138
-
139
- // ── self-check: `node src/market/terms.js` ────────────────────────────────────
140
- if (typeof process !== "undefined" && import.meta.url === `file://${process.argv[1]}` && process.argv[1].endsWith("/terms.js")) {
141
- const A = "0x" + "a".repeat(40); // app owner
142
- const P = "0x" + "b".repeat(40); // publisher
143
- const S1 = "0x" + "c".repeat(40); // a source
144
- const S2 = "0x" + "d".repeat(40); // another
145
- const T = { appId: "fangorn.tv", owner: A, appBps: 1000 };
146
- const at = (ps, to) => ps.find((p) => p.to === to)?.amount ?? 0n;
147
-
148
- // The plain case: 10% to the app, the rest to whoever published it.
149
- let ps = splitPayment(1_000_000n, { terms: T, publisher: P });
150
- if (at(ps, A) !== 100_000n || at(ps, P) !== 900_000n) throw new Error(`plain split wrong: ${JSON.stringify(ps, (k, v) => typeof v === "bigint" ? String(v) : v)}`);
151
-
152
- // A derivative: two sources, 20% and 5% OF THE PUBLISHER'S SHARE. The app's
153
- // cut must not move — that is the whole reason lineage comes out of the
154
- // publisher's half.
155
- ps = splitPayment(1_000_000n, { terms: T, publisher: P, lineage: [{ to: S1, bps: 2000 }, { to: S2, bps: 500 }] });
156
- if (at(ps, A) !== 100_000n) throw new Error("the app's cut must not shrink because the publisher cited someone");
157
- if (at(ps, S1) !== 180_000n || at(ps, S2) !== 45_000n) throw new Error(`upstream is a share of 900000: ${at(ps, S1)}/${at(ps, S2)}`);
158
- if (at(ps, P) !== 675_000n) throw new Error(`publisher keeps the rest: ${at(ps, P)}`);
159
-
160
- // Money is neither created nor destroyed, at any amount.
161
- for (const amt of [0n, 1n, 3n, 7n, 999n, 1_000_001n, 123_456_789n]) {
162
- const out = splitPayment(amt, { terms: T, publisher: P, lineage: [{ to: S1, bps: 3333 }, { to: S2, bps: 3333 }] });
163
- const sum = out.reduce((s, p) => s + p.amount, 0n);
164
- if (sum !== amt) throw new Error(`${amt} split into ${sum}`);
165
- if (out.some((p) => p.amount < 0n)) throw new Error(`negative payout at ${amt}`);
166
- }
167
-
168
- // Dust goes to the publisher, never to rounding.
169
- ps = splitPayment(7n, { terms: { ...T, appBps: 3333 }, publisher: P });
170
- if (at(ps, A) !== 2n || at(ps, P) !== 5n) throw new Error(`dust must land on the publisher: ${JSON.stringify(ps.map((p) => [p.to.slice(0, 4), String(p.amount)]))}`);
171
-
172
- // One payee, one payout: an app owner who publishes under their own app.
173
- ps = splitPayment(1_000_000n, { terms: T, publisher: A });
174
- if (ps.length !== 1 || at(ps, A) !== 1_000_000n) throw new Error("the same address must be paid once, not twice");
175
-
176
- // Citing the same source twice is one debt.
177
- ps = splitPayment(1_000_000n, { terms: T, publisher: P, lineage: [{ to: S1, bps: 1000 }, { to: S1, bps: 1000 }] });
178
- if (at(ps, S1) !== 180_000n) throw new Error(`a repeated citation must merge, not double-pay: ${at(ps, S1)}`);
179
-
180
- // Terms are refused, not silently clamped.
181
- for (const bad of [{ ...T, appBps: 10001 }, { ...T, appBps: -1 }, { ...T, owner: "0xnope" }, { appId: "", owner: A }]) {
182
- let threw = false;
183
- try { splitPayment(1n, { terms: bad, publisher: P }); } catch { threw = true; }
184
- if (!threw) throw new Error(`bad terms must throw: ${JSON.stringify(bad)}`);
185
- }
186
- let threw = false;
187
- try { lineage([{ to: S1, bps: 6000 }, { to: S2, bps: 6000 }]); } catch { threw = true; }
188
- if (!threw) throw new Error("a publisher cannot owe more than they have");
189
-
190
- // The hash is what a publisher agreed to: stable across key order, and it
191
- // moves the moment a single term does.
192
- const h1 = await termsHash(T);
193
- const h2 = await termsHash({ owner: A, appBps: 1000, appId: "fangorn.tv" });
194
- if (h1 !== h2) throw new Error("key order must not change the hash");
195
- if (h1 === await termsHash({ ...T, appBps: 1001 })) throw new Error("a changed cut must change the hash");
196
- if (!/^0x[0-9a-f]{64}$/.test(h1)) throw new Error(`hash shape: ${h1}`);
197
-
198
- console.log("terms.js self-check ok — app cut fixed, lineage paid from the publisher's share, payouts always sum to what was paid, "
199
- + "dust to the publisher, repeated payees merged, bad terms refused, terms hash canonical");
200
- }
@@ -1,336 +0,0 @@
1
- #!/usr/bin/env node
2
- // The publisher's CLI. Everything an app's publish UI does, with a local key.
3
- //
4
- // WHY THIS IS NOT IN AN APP
5
- // -------------------------
6
- // A publisher should not have to clone the app they are publishing to. The
7
- // browser flow costs one file-picker click and one wallet confirmation PER FILE,
8
- // which makes seeding a library impossible and publishing from a chat message
9
- // impossible for the same reason — but the deeper problem is that it made the
10
- // app's repo a dependency of publishing to it.
11
- //
12
- // So this is a CLIENT of the relay's HTTP surface and of nothing else. The only
13
- // app-specific thing it needs is `ns` — the namespace folded into every
14
- // resourceId — and the relay declares that itself, so a publisher needs a URL, a
15
- // key, and a price.
16
- //
17
- // PUBLISHER_PRIVATE_KEY=0x… westmarch-publish <relay> <path…> [flags]
18
- //
19
- // --ns=name app namespace. Defaults to what the relay declares.
20
- // NEVER guessed: it is folded into every resourceId, so a
21
- // wrong one mints ids nobody can buy from and orphans a
22
- // library that already exists.
23
- // --dir=sub/folder stage under this folder instead of the library root
24
- // --price=1000 USDC base units per file (default: the relay's)
25
- // --desc="…" description for every file in this run
26
- // --catalog-only publish as FREE catalog entries: committed to the graph,
27
- // searchable, but never encrypted, uploaded or minted as a
28
- // resource. One commitStateRoot covers a graph of any size,
29
- // so this is what makes bulk ingest cost one transaction
30
- // instead of one per file.
31
- // --register send the one-time, fee-paying register() tx if needed
32
- // --setup onboard only — terms and registration. Publishes nothing,
33
- // and without --register sends nothing at all: it reports
34
- // what is missing and what it would cost. Ends with one
35
- // `SETUP <json>` line for a caller to parse.
36
- // --selfcheck run the offline self-check and exit
37
- //
38
- // A description is the highest-signal thing a file carries — for an image it is
39
- // the ONLY thing, since nothing in a JPEG's bytes says what it is. So per-file
40
- // descriptions come from a `<file>.txt` sidecar when one exists (--desc is the
41
- // fallback for the rest).
42
- //
43
- // The key comes from the environment and never from argv — argv is visible in
44
- // `ps` to every process on the box.
45
-
46
- import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
47
- import { basename, join, relative, resolve, sep } from "node:path";
48
- import { createPublicClient, createWalletClient, defineChain, http } from "viem";
49
- import { privateKeyToAccount } from "viem/accounts";
50
- import { encryptAndUpload } from "../market/settle.js";
51
- import { resourceIdFor } from "./envelope.js";
52
- import { newUid, readManifest, writeManifest } from "./manifest.js";
53
-
54
- // ── argv ──────────────────────────────────────────────────────────────────────
55
-
56
- const flags = {};
57
- const args = [];
58
- for (const a of process.argv.slice(2)) {
59
- const m = /^--([^=]+)(?:=([\s\S]*))?$/.exec(a);
60
- if (m) flags[m[1]] = m[2] ?? true;
61
- else args.push(a);
62
- }
63
-
64
- // ── file collection ───────────────────────────────────────────────────────────
65
-
66
- /** Sidecars and dotfiles are not products. A `.txt` NEXT TO a file it describes
67
- * is a caption; an orphan `.txt` is a document someone may want to sell. */
68
- export const skip = (name, isSidecar) =>
69
- name.startsWith(".") || name.endsWith(".vtt") || isSidecar;
70
-
71
- function collect(abs, root = abs) {
72
- const st = statSync(abs);
73
- if (st.isDirectory()) {
74
- return readdirSync(abs).sort().flatMap((n) => collect(join(abs, n), root));
75
- }
76
- const name = basename(abs);
77
- const described = name.endsWith(".txt") && existsSync(abs.slice(0, -4));
78
- if (skip(name, described)) return [];
79
- const rel = (root === abs ? name : relative(root, abs)).split(sep).join("/");
80
- return [{ abs, rel }];
81
- }
82
-
83
- /** `<file>.txt` beside the file, else --desc, else nothing. */
84
- const descFor = (abs) => {
85
- const side = `${abs}.txt`;
86
- if (existsSync(side)) return readFileSync(side, "utf8").trim().slice(0, 2000);
87
- return typeof flags.desc === "string" ? flags.desc : null;
88
- };
89
-
90
- // ── relay client ──────────────────────────────────────────────────────────────
91
-
92
- function client(relay) {
93
- let token = null;
94
- // Origin is sent explicitly and identically on every request: the relay
95
- // derives both the SIWE message's domain and the terms URL from it, so a
96
- // nonce issued under one origin and a terms acceptance under another would
97
- // sign two different documents.
98
- const headers = (extra = {}) => ({ Origin: relay, ...(token ? { Authorization: `Bearer ${token}` } : {}), ...extra });
99
- const j = async (res) => {
100
- const body = await res.json().catch(() => ({}));
101
- if (!res.ok) throw new Error(body.error ?? `${res.status} ${res.statusText}`);
102
- return body;
103
- };
104
- return {
105
- setToken: (t) => { token = t; },
106
- get: (path) => fetch(`${relay}${path}`, { headers: headers() }).then(j),
107
- post: (path, body) => fetch(`${relay}${path}`, {
108
- method: "POST", headers: headers({ "Content-Type": "application/json" }), body: JSON.stringify(body),
109
- }).then(j),
110
- prepare: (library) => fetch(`${relay}/api/publish/prepare`, {
111
- method: "POST", headers: headers({ "Content-Type": "application/json" }), body: JSON.stringify({ library }),
112
- }).then(j),
113
- };
114
- }
115
-
116
- // ── main ──────────────────────────────────────────────────────────────────────
117
-
118
- async function main() {
119
- const [relayArg, ...paths] = args;
120
- if (!relayArg) {
121
- console.error("usage: PUBLISHER_PRIVATE_KEY=0x… westmarch-publish <relay> <path…> [--ns=] [--dir=] [--price=] [--desc=] [--register] [--setup]");
122
- process.exit(2);
123
- }
124
- const relay = relayArg.replace(/\/$/, "");
125
-
126
- const key = process.env.PUBLISHER_PRIVATE_KEY;
127
- if (!/^0x[0-9a-fA-F]{64}$/.test(key ?? "")) throw new Error("PUBLISHER_PRIVATE_KEY must be a 0x-prefixed 32-byte hex key (env only — never argv)");
128
- const account = privateKeyToAccount(key);
129
- const api = client(relay);
130
-
131
- const cfg = await api.get("/api/config");
132
- if (cfg.readOnly) throw new Error(`${relay} is read-only — it serves a published catalog but accepts no publishes. Point at the relay for the app you are publishing to.`);
133
-
134
- // Never defaulted, never guessed. `ns` is folded into every resourceId this
135
- // wallet mints, so the wrong one produces ids that address nobody's bytes and
136
- // a manifest key that reads back as an empty library.
137
- const ns = typeof flags.ns === "string" ? flags.ns : cfg.ns;
138
- if (!ns) throw new Error(`${relay} does not declare an app namespace (config.ns) — pass --ns=<name> explicitly, and be sure it is the one this app already publishes under`);
139
-
140
- const chain = defineChain({
141
- id: cfg.chainId,
142
- name: `chain-${cfg.chainId}`,
143
- nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
144
- rpcUrls: { default: { http: [cfg.rpc] } },
145
- });
146
- const wallet = createWalletClient({ account, chain, transport: http(cfg.rpc) });
147
- const node = createPublicClient({ chain, transport: http(cfg.rpc) });
148
- const send = async (tx) => {
149
- const hash = await wallet.sendTransaction({ to: tx.to, data: tx.data, ...(tx.value ? { value: BigInt(tx.value) } : {}) });
150
- const rc = await node.waitForTransactionReceipt({ hash });
151
- if (rc.status !== "success") throw new Error(`tx reverted: ${hash}`);
152
- return hash;
153
- };
154
-
155
- // ── sign in ───────────────────────────────────────────────────────────────
156
- // This signature is also the rights attestation the relay appends to its log
157
- // before minting a session. Automating it does not make it mean less: the
158
- // key holder is asserting they are licensed to distribute what follows.
159
- const { nonce, message } = await api.post("/api/session/nonce", { address: account.address });
160
- const { token } = await api.post("/api/session", { nonce, signature: await account.signMessage({ message }) });
161
- api.setToken(token);
162
- console.log(`signed in as ${account.address} — publishing to ${relay} as "${ns}"`);
163
-
164
- // ── terms + registration ──────────────────────────────────────────────────
165
- let reg = await api.get("/api/registration");
166
- if (!reg.acceptedTerms) {
167
- const t = await api.get("/api/terms");
168
- await api.post("/api/terms/accept", { signature: await account.signMessage({ message: t.message }) });
169
- console.log(`accepted publisher terms (${t.hash.slice(0, 12)}…) — ${t.url}`);
170
- reg = await api.get("/api/registration");
171
- }
172
- if (!reg.registered) {
173
- // Registration costs a fee in ETH and is irreversible, so it is never
174
- // sent implicitly. Two txs, in the order the relay gave: global standing
175
- // in the data registry, then membership of this app. Both are needed —
176
- // commitStateRoot cross-calls the app registry, so stopping after the
177
- // first buys a revert at the end of the publish instead of an error here.
178
- const total = BigInt(reg.fee ?? 0) + BigInt(reg.appFee ?? 0);
179
- if (!flags.register) {
180
- if (!flags.setup) throw new Error(`${account.address} is not a registered publisher. Re-run with --register to send ${reg.txs.length} registration tx(s) (fee: ${total} wei), or register at https://fangorn.network`);
181
- } else {
182
- console.log(`registering as a publisher (${reg.txs.length} tx, fee ${total} wei)…`);
183
- for (const tx of reg.txs) await send(tx);
184
- reg = await api.get("/api/registration");
185
- }
186
- }
187
-
188
- // ── setup mode ────────────────────────────────────────────────────────────
189
- // Onboarding a publisher — terms, registration txs, and a bucket to put bytes
190
- // in — used to be reachable only by attempting a publish and reading the
191
- // error. A caller that wants to ASK "am I set up?" had nothing to call.
192
- //
193
- // Without --register it is a dry run: it says what is missing and what the
194
- // fees would be, and sends nothing. The last line is `SETUP <json>` so a
195
- // caller parses one line instead of scraping prose.
196
- if (flags.setup) {
197
- const state = { address: account.address, ns, registered: !!reg.registered, acceptedTerms: true };
198
- const w = await api.get("/api/worker").catch(() => null);
199
- // Null until this wallet is a registered publisher — the relay withholds
200
- // both, which is the only way storage can be "not ready" now.
201
- state.workerUrl = w?.workerUrl ?? null;
202
- state.storage = !!w?.workerUrl;
203
- if (!reg.registered) {
204
- state.fee = (BigInt(reg.fee ?? 0) + BigInt(reg.appFee ?? 0)).toString();
205
- state.txs = reg.txs?.length ?? 0;
206
- }
207
- console.log(`SETUP ${JSON.stringify(state)}`);
208
- return;
209
- }
210
-
211
- // ── stage ─────────────────────────────────────────────────────────────────
212
- const under = typeof flags.dir === "string" ? flags.dir.replace(/^\/+|\/+$/g, "") : "";
213
- const files = paths.flatMap((p) => collect(resolve(p)));
214
- if (paths.length && !files.length) throw new Error("nothing to upload — every path was a dotfile, a .vtt or a description sidecar");
215
-
216
- // The manifest lives in the bucket, not on the relay, so this client reads
217
- // it, edits it and writes it back. Both the worker and this wallet's upload
218
- // token come from the relay, which stores neither: the URL is its own config
219
- // and the token is derived from the address.
220
- const { workerUrl, uploadToken } = await api.get("/api/worker");
221
- if (!workerUrl) throw new Error(`${account.address} has no storage — it is not a registered Fangorn publisher yet (run with --setup --register, or sign up at https://fangorn.network)`);
222
- const store = { ns, workerUrl, uploadToken, owner: account.address };
223
- const manifest = await readManifest(store);
224
-
225
- for (const f of files) {
226
- const rel = under ? `${under}/${f.rel}` : f.rel;
227
- const entry = (manifest.files[rel] ??= { uid: newUid() });
228
- if (flags["catalog-only"]) entry.forSale = false;
229
- else if (flags.price) entry.price = String(flags.price);
230
- const desc = descFor(f.abs);
231
- if (desc) entry.desc = desc;
232
-
233
- // A free catalog entry is committed to the graph but never encrypted,
234
- // uploaded or minted — which is what makes bulk ingest cost one commit
235
- // instead of one createResource per file.
236
- if (entry.forSale === false) {
237
- console.log(`↑ ${rel} … ok (free entry)${desc ? " (described)" : ""}`);
238
- continue;
239
- }
240
- process.stdout.write(`↑ ${rel} … `);
241
- const out = await encryptAndUpload({
242
- file: f.abs, workerUrl, uploadToken,
243
- resourceId: entry.published?.resourceId ?? resourceIdFor(ns, account.address, entry.uid),
244
- });
245
- entry.published = { ...out, resourceId: entry.published?.resourceId, workerUrl, mime: entry.mime };
246
- // Written per file: a run that dies partway must not lose the pointers
247
- // already paid for in bandwidth.
248
- await writeManifest({ ...store, manifest });
249
- console.log(`ok${desc ? " (described)" : ""}`);
250
- }
251
-
252
- // ── publish ───────────────────────────────────────────────────────────────
253
- const library = Object.entries(manifest.files).map(([path, f]) => ({
254
- path, type: "video", uid: f.uid, price: f.price, mime: f.mime,
255
- desc: f.desc, forSale: f.forSale, cues: f.cues, published: f.published,
256
- }));
257
- const prep = await api.prepare(library);
258
-
259
- for (const [i, c] of prep.creates.entries()) {
260
- console.log(`createResource ${i + 1}/${prep.creates.length} — ${c.path}`);
261
- await send(c);
262
- }
263
-
264
- // No vectors. A publisher builds and publishes the graph; embedding is not
265
- // its job and never was. The commit route still takes a `vectors` map because
266
- // an app's own browser flow may fill it, and an empty one is the ordinary
267
- // case, not a degraded one.
268
- // The pin is authorized by the publisher's own signature against their own
269
- // storage quota. The challenge carries an Issued-At the gate only honours for
270
- // a few minutes, so it is fetched here and not at the start of the run.
271
- //
272
- // `storageGate: null` is not a broken relay — it is one pinning directly on
273
- // its own account, which ignores storageAuth entirely. Asking a gate that
274
- // isn't there for a challenge failed a publish the relay would have accepted,
275
- // and blamed a service that was never in the path.
276
- let storageAuth;
277
- if (cfg.storageGate) {
278
- const gate = await fetch(cfg.storageGate, {
279
- method: "POST", headers: { "content-type": "application/json" },
280
- body: JSON.stringify({ address: account.address, size: 1 }),
281
- }).then((r) => r.json()).catch(() => ({}));
282
- if (!gate.challenge) throw new Error(`storage gate issued no challenge — ${cfg.storageGate} may be down`);
283
- storageAuth = { message: gate.challenge, signature: await account.signMessage({ message: gate.challenge }) };
284
- } else {
285
- console.log("relay pins on its own account — no storage gate to authorize against");
286
- }
287
-
288
- const sealed = await api.post("/api/publish/commit", { vectors: {}, storageAuth });
289
- console.log("commitStateRoot…");
290
- await send(sealed.commitTx);
291
- for (const [path, ptr] of Object.entries(sealed.published)) {
292
- manifest.files[path].published = { ...(manifest.files[path].published ?? {}), ...ptr };
293
- }
294
- await writeManifest({ ...store, manifest });
295
- await api.post("/api/settle", {});
296
-
297
- const { vertices, edges } = sealed.staged;
298
- console.log(`published — ${vertices} vertices, ${edges} edges`);
299
- for (const [path, ptr] of Object.entries(sealed.published)) console.log(` ${path} ${ptr.resourceId}`);
300
- }
301
-
302
- // ── self-check: `node src/publish/cli.js --selfcheck` (offline) ──────────────────
303
-
304
- if (flags.selfcheck) {
305
- const assert = (cond, msg) => { if (!cond) throw new Error(msg); };
306
-
307
- // Collection: sidecars are descriptions, not products; a .txt with no file
308
- // beside it still sells; nested paths keep their shape.
309
- const here = new Set(["/lib/a.jpg", "/lib/notes.txt", "/lib/sub/b.mp3"]);
310
- const survives = (name, abs) => !skip(name, name.endsWith(".txt") && here.has(abs.slice(0, -4)));
311
- assert(survives("a.jpg", "/lib/a.jpg"), "a real file was skipped");
312
- assert(!survives("a.jpg.txt", "/lib/a.jpg.txt"), "a description sidecar was published as a file");
313
- assert(survives("notes.txt", "/lib/notes.txt"), "an orphan .txt should publish as a text file");
314
- assert(!survives(".hidden", "/lib/.hidden"), "a dotfile was published");
315
- assert(!survives("c.mp4.vtt", "/lib/c.mp4.vtt"), "a .vtt was published — /api/upload rejects these");
316
-
317
- // A read-only relay and a relay that declares no namespace must both fail
318
- // BEFORE anything is signed, uploaded or sent — and say which it was.
319
- const real = globalThis.fetch;
320
- const runAgainst = async (config) => {
321
- globalThis.fetch = async (url) => String(url).endsWith("/api/config")
322
- ? { ok: true, json: async () => config }
323
- : { ok: false, json: async () => ({ error: "should never be reached" }) };
324
- process.env.PUBLISHER_PRIVATE_KEY = `0x${"11".repeat(32)}`;
325
- args.length = 0; args.push("http://relay", "/tmp");
326
- return main().then(() => "no error", (e) => e.message);
327
- };
328
- try {
329
- assert(/read-only/.test(await runAgainst({ readOnly: true })), "a read-only relay must be refused by name");
330
- assert(/namespace/.test(await runAgainst({ chainId: 1, rpc: "http://r" })), "a relay declaring no ns must be refused, not guessed at");
331
- } finally { globalThis.fetch = real; delete process.env.PUBLISHER_PRIVATE_KEY; }
332
-
333
- console.log("cli.js self-check ok — sidecars, read-only relay refused, missing ns refused");
334
- } else {
335
- await main().catch((e) => { console.error(`✗ ${e.message}`); process.exit(1); });
336
- }