@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.
- package/README.md +5 -5
- package/docs/app-to-agent.md +61 -625
- package/package.json +12 -17
- package/site/dist/assets/__vite-browser-external-D2U8RZpp.js +1 -0
- package/site/dist/assets/embed.worker-CmS57Zti.js +1 -0
- package/site/dist/assets/index-Djs8f08m.js +8 -0
- package/site/dist/assets/rolldown-runtime-COiEfhsA.js +1 -0
- package/site/dist/assets/{transformers.web-BTyOEJ0C.js → transformers.web-CwR_IYQV.js} +1 -1
- package/site/dist/index.html +3 -4
- package/site/worker.js +115 -338
- package/src/agent/agent-card.js +33 -45
- package/src/agent/mcp.js +168 -371
- package/src/agent/tools.js +2 -1
- package/src/agent/view-tools.js +4 -56
- package/src/agent/x402.js +182 -369
- package/src/core/roles.js +6 -6
- package/src/core/shard.js +4 -4
- package/src/discover/apps.js +67 -81
- package/src/discover/directory.js +2 -2
- package/src/market/reactions.js +21 -15
- package/src/publish/devnet.js +69 -18
- package/src/publish/init.js +1 -1
- package/src/publish/ship.js +74 -275
- package/src/publish/view.js +52 -53
- package/template/README.md +9 -11
- package/template/package.json +1 -1
- package/plugin/scripts/fx.mjs +0 -266
- package/site/dist/assets/AccountNotFoundScreen-C4njXc69-DyVH4CEz.js +0 -1
- package/site/dist/assets/AddFundsSelectionScreen-RAoCn7ej-Dz1--SS9.js +0 -31
- package/site/dist/assets/Address-H8kD1d9O-BdFZmRwI.js +0 -17
- package/site/dist/assets/AffirmativeConsentScreen-BG0MJxku-CxaCAisL.js +0 -6
- package/site/dist/assets/AllowlistRejectionScreen-Cae6e1Od-JGk7vndN.js +0 -1
- package/site/dist/assets/ApiController-CTLbMCcH.js +0 -5
- package/site/dist/assets/ArrowsRightLeftIcon-B8g9adpz.js +0 -1
- package/site/dist/assets/AuthenticateWithWalletScreen-CU6hIcFT-CXD9_OP8.js +0 -1
- package/site/dist/assets/AwaitingEvmToSolBridgingScreen-D0e_sZMS-BtJCglvU.js +0 -1
- package/site/dist/assets/AwaitingExternalEthereumTransferScreen-ur5HL4R7-BgC2TsqH.js +0 -1
- package/site/dist/assets/AwaitingPasswordlessCodeScreen-DRHz76mM-B9OzLeEO.js +0 -103
- package/site/dist/assets/AwaitingSolToEvmBridgingScreen-CdLRrGD2-C7r5snUL.js +0 -1
- package/site/dist/assets/BridgeNetworkSelectionView-CFGjB2nO-BTV0NRio.js +0 -68
- package/site/dist/assets/CaptchaScreen-DbpvkIGx-7rSZIuM-.js +0 -1
- package/site/dist/assets/CheckCircleIcon-B1l17ioc.js +0 -1
- package/site/dist/assets/CheckCircleIcon-BGSI8nKf.js +0 -1
- package/site/dist/assets/Checkbox-D1EDeo41-BUfq0w99.js +0 -52
- package/site/dist/assets/ChevronDownIcon-B6uJvPHu.js +0 -1
- package/site/dist/assets/Chip-CZKIKt9K-r9Nk__0-.js +0 -26
- package/site/dist/assets/CoinbaseOnrampStatusScreen-BbyCJDXL-DWWNHxmR.js +0 -16
- package/site/dist/assets/ConnectEmailForm-B-VRE0MN-CRQwS0Xu.js +0 -3
- package/site/dist/assets/ConnectLedgerScreen-DWHABGot-CZcCt31O.js +0 -10
- package/site/dist/assets/ConnectOnlyLandingScreen-CZYx9Bmp-C5IOf-SQ.js +0 -1
- package/site/dist/assets/ConnectOnlyStatusScreen-DCRzjxHx-cwg74F3A.js +0 -1
- package/site/dist/assets/ConnectOrCreateScreen-CUUYUO07-D28oeK6b.js +0 -1
- package/site/dist/assets/ConnectPhoneForm-Dek5xn4C-EEdkKeTp.js +0 -95
- package/site/dist/assets/ConnectWalletView-DqI-PTvX-C2mEzukj.js +0 -74
- package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-CH_7r8iV.js +0 -7
- package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-Z33kis0B.js +0 -1
- package/site/dist/assets/ConnectorUtil-DH4NePk5.js +0 -21
- package/site/dist/assets/ConstantsUtil-DmLsRHAl.js +0 -198
- package/site/dist/assets/CopyToClipboard-i_OQSBJr-_G88JCVR.js +0 -39
- package/site/dist/assets/CopyableText-CQapvaMr-CGGfc_zM.js +0 -28
- package/site/dist/assets/CrossAppAuthScreen-CLw7ymZq-C9Okoc0V.js +0 -1
- package/site/dist/assets/CustomLandingScreenView-Cm_MBSyX-D2l6hdSl.js +0 -22
- package/site/dist/assets/DelegatedActionsConsentScreen-DYF2U4y5-Dda3KKqS.js +0 -1
- package/site/dist/assets/DelegatedActionsRevokeScreen-bPp6Uwyh-DG8kJPt1.js +0 -1
- package/site/dist/assets/DepositAddressAddressStepView-4vdkb55L-CcOUfn6f.js +0 -187
- package/site/dist/assets/DepositAddressScreen-DBLRs7aI-DeituDNh.js +0 -8
- package/site/dist/assets/DepositAddressV3Screen-CDqIEMQw-FDg6K14-.js +0 -1
- package/site/dist/assets/EmailInputForm-Cqo1mda8-BmbxvPHC.js +0 -124
- package/site/dist/assets/EmbeddedWalletConnectingScreen-D4T7DUzs-B05CQ9rx.js +0 -1
- package/site/dist/assets/EmbeddedWalletCreatedScreen-D7WhW5ve-Cxd1b9XH.js +0 -1
- package/site/dist/assets/EmbeddedWalletKeyExportScreen-CqV4NYQ3-CrJy0ViX.js +0 -23
- package/site/dist/assets/EmbeddedWalletOnAccountCreateScreen-BoKb3Q2S-Bakaa3zu.js +0 -1
- package/site/dist/assets/EmbeddedWalletPasswordUpdateScreen-D3rMlqS7-j78vKrcj.js +0 -1
- package/site/dist/assets/EmbeddedWalletPasswordUpdateSplashScreen-BPFkWJeE-D3dr7W9_.js +0 -1
- package/site/dist/assets/EnrollTotp-Dibew4dp-BXbYV8nI.js +0 -66
- package/site/dist/assets/EnvelopeIcon-DjPofnRI.js +0 -1
- package/site/dist/assets/ErrorBanner-BcpGRt0h-BhH6_V-9.js +0 -21
- package/site/dist/assets/ErrorMessage-D8VaAP5m-Bs7uX2a9.js +0 -8
- package/site/dist/assets/ErrorScreen-DipdTWzE-BgPRgnOb.js +0 -4
- package/site/dist/assets/ErrorScreen-DipdTWzE-CvxXC6pz.js +0 -1
- package/site/dist/assets/ExclamationCircleIcon-BE-WGrut.js +0 -1
- package/site/dist/assets/ExclamationTriangleIcon-Ca1Xlc_f.js +0 -1
- package/site/dist/assets/FarcasterConnectStatusScreen-51tjUxqq-De2JvZdV.js +0 -75
- package/site/dist/assets/FarcasterSignerStatusScreen-6x-Uh95G-bLp3hXoO.js +0 -28
- package/site/dist/assets/FiatOnrampScreen-BAhYeiTI-Jr6D6JiZ.js +0 -491
- package/site/dist/assets/FingerPrintIcon-DOCbS93y.js +0 -1
- package/site/dist/assets/FundSolWalletWithExternalSolanaWallet-WtLwYaOl-A_G5kfa1.js +0 -1
- package/site/dist/assets/FundWalletMethodHeader-BWNkokCT-LPv35wkD.js +0 -1
- package/site/dist/assets/FundWithBankDepositScreen-DajkHxBD-0hfGrfvf.js +0 -58
- package/site/dist/assets/FundingEditAmountScreen-CpvpiO4M-Dz0s_NWR.js +0 -1
- package/site/dist/assets/FundingMethodSelectionScreen-Db7vhRlE-ZGm-3-Io.js +0 -1
- package/site/dist/assets/GlobeAltIcon-BBRl2MMn.js +0 -1
- package/site/dist/assets/GooglePay-B53WnudL-BGiVpB8y.js +0 -1
- package/site/dist/assets/HCaptchaWrapper-CUi9LJsp-CHdfIeD_.js +0 -4
- package/site/dist/assets/InAppBrowserLoginNotPossible-BMR9br1T-Cgoiow3m.js +0 -1
- package/site/dist/assets/InfoBanner-Cb3p1z12-_YqQmRiu.js +0 -22
- package/site/dist/assets/InjectedWalletIcon-DLcYOGDj-tuIrKQHH.js +0 -1
- package/site/dist/assets/InstallWalletScreen-DTA8dwLv-BMU_wa61.js +0 -1
- package/site/dist/assets/JsonTree-BHzNC-ic-DcVr0YF0.js +0 -34
- package/site/dist/assets/LabelXs-oqZNqbm_-CNprGVQM.js +0 -6
- package/site/dist/assets/LandingScreen-CGWUoSUG-fH6rsQen.js +0 -1
- package/site/dist/assets/Layouts-BMRfo5hw-e-sepi6F.js +0 -77
- package/site/dist/assets/Link-BdDilT2T-BdwlRJch.js +0 -40
- package/site/dist/assets/LinkConflictScreen-C3ZEPsgl-BXKN2Qm5.js +0 -77
- package/site/dist/assets/LinkEmailScreen-dKo9frwc-Cyn7Q8p1.js +0 -1
- package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-CWiqnwLM.js +0 -117
- package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-YmDevJzf.js +0 -1
- package/site/dist/assets/LinkPhoneScreen-oIUpfj0w-h7shW-Ay.js +0 -1
- package/site/dist/assets/Loader-UAZqxsnw-DJEVblm1.js +0 -62
- package/site/dist/assets/LoadingSkeleton-BMsgO5PV-D2atjsP5.js +0 -17
- package/site/dist/assets/LockClosedIcon-9EFzWK1C.js +0 -1
- package/site/dist/assets/LoginFailedScreen-CN0dJV6U-By3Si77a.js +0 -1
- package/site/dist/assets/ManualTransferScreen-CHqcuqbs-BAHPY8rs.js +0 -1
- package/site/dist/assets/MfaAuthEnrollmentFlowScreen-Dj7gPTRC-CLjffFG1.js +0 -1
- package/site/dist/assets/MfaAuthVerifyFlowScreen-DbFpyWMy-BmQg1Y61.js +0 -1
- package/site/dist/assets/MfaEnrollmentFlowScreen-DhLnGgnr-DmBtTtlw.js +0 -1
- package/site/dist/assets/MfaVerifyFlowScreen-C_XPjMRP-4a683Bmf.js +0 -1
- package/site/dist/assets/ModalFooter-BCuEK_nz-C_71qsaz.js +0 -403
- package/site/dist/assets/MoonpayStatusScreen-CzTUtokc-DEHHcEf8.js +0 -16
- package/site/dist/assets/OAuthStatusScreen-ufbOa-da-BjAb_WsY.js +0 -1
- package/site/dist/assets/OpenLink-CUpJ1mOr-BLWFsPOW.js +0 -39
- package/site/dist/assets/PasskeySelectSignupOrLogin-xh2ScC_l-2PJTJxX-.js +0 -1
- package/site/dist/assets/PasskeyStatusScreen-Bla8MaOk-DCEg761l.js +0 -6
- package/site/dist/assets/PasswordRecoveryScreen-awGXZkQk-8nVjNc8k.js +0 -20
- package/site/dist/assets/PhArrowCircleDown-D97G-BOA.js +0 -14
- package/site/dist/assets/PhArrowClockwise-DVgyFuez.js +0 -14
- package/site/dist/assets/PhArrowDown-87b1BizM.js +0 -14
- package/site/dist/assets/PhArrowLeft-Da0MfnbK.js +0 -14
- package/site/dist/assets/PhArrowRight-AdrIL4DW.js +0 -14
- package/site/dist/assets/PhArrowSquareOut-Bk2CMG3I.js +0 -14
- package/site/dist/assets/PhArrowUp-4sgyKPGx.js +0 -14
- package/site/dist/assets/PhArrowUpRight-BNghD2zq.js +0 -14
- package/site/dist/assets/PhArrowsClockwise-BXRn1GEl.js +0 -14
- package/site/dist/assets/PhArrowsDownUp-DM09Jo_3.js +0 -14
- package/site/dist/assets/PhArrowsLeftRight-MuKBLUoF.js +0 -14
- package/site/dist/assets/PhBank-fHbgCqqZ.js +0 -14
- package/site/dist/assets/PhBrowser-2-9m-AkM.js +0 -14
- package/site/dist/assets/PhCaretDown-BDNabFuL.js +0 -14
- package/site/dist/assets/PhCaretLeft-CI460R-A.js +0 -14
- package/site/dist/assets/PhCaretRight-D7ZS3Ls8.js +0 -14
- package/site/dist/assets/PhCaretUp-C-iIfyvO.js +0 -14
- package/site/dist/assets/PhCheck-DxQXn57r.js +0 -14
- package/site/dist/assets/PhCircleHalf-MJZeRBGF.js +0 -14
- package/site/dist/assets/PhClock-x3MS3Mwi.js +0 -14
- package/site/dist/assets/PhCompass-hYn3HhGN.js +0 -14
- package/site/dist/assets/PhCopy-CWNYcABI.js +0 -14
- package/site/dist/assets/PhCreditCard-Fy4pzwtt.js +0 -14
- package/site/dist/assets/PhCurrencyDollar-BgiaenCi.js +0 -14
- package/site/dist/assets/PhDesktop-CxrzCSv5.js +0 -14
- package/site/dist/assets/PhDeviceMobile-CsyA5Goi.js +0 -14
- package/site/dist/assets/PhDotsThree-D-k1BiYg.js +0 -14
- package/site/dist/assets/PhEnvelope-D8kzeNox.js +0 -14
- package/site/dist/assets/PhFunnelSimple-CfQs5DAW.js +0 -14
- package/site/dist/assets/PhGlobe-DvmSc9_A.js +0 -14
- package/site/dist/assets/PhIdentificationCard-CfkZm-5K.js +0 -14
- package/site/dist/assets/PhImage-Cf0J2ZfJ.js +0 -14
- package/site/dist/assets/PhInfo-Bwi51-2X.js +0 -14
- package/site/dist/assets/PhLightbulb-C4FZV7Es.js +0 -14
- package/site/dist/assets/PhMagnifyingGlass-C9u8jSCJ.js +0 -14
- package/site/dist/assets/PhPaperPlaneRight-zxQVvPLX.js +0 -14
- package/site/dist/assets/PhPlus-C4UoW-2n.js +0 -14
- package/site/dist/assets/PhPower-CFyWDmgD.js +0 -14
- package/site/dist/assets/PhPuzzlePiece-BjoNVfST.js +0 -14
- package/site/dist/assets/PhQrCode-CP3tFauY.js +0 -14
- package/site/dist/assets/PhQuestion-wOWJBd3G.js +0 -14
- package/site/dist/assets/PhQuestionMark-CV0k9C0Y.js +0 -14
- package/site/dist/assets/PhSealCheck-vIKzREuN.js +0 -14
- package/site/dist/assets/PhSignOut-CxELV-i0.js +0 -14
- package/site/dist/assets/PhSpinner-CGDmbzUd.js +0 -14
- package/site/dist/assets/PhTrash-C9PD0SAt.js +0 -14
- package/site/dist/assets/PhUser-0sWNXQeZ.js +0 -14
- package/site/dist/assets/PhVault-6JTskUcC.js +0 -14
- package/site/dist/assets/PhWarning-CoKs3gz6.js +0 -14
- package/site/dist/assets/PhWarningCircle-BXHw1fCt.js +0 -14
- package/site/dist/assets/PhX-DX0SFIqC.js +0 -14
- package/site/dist/assets/PhoneIcon-CZ47md80.js +0 -1
- package/site/dist/assets/PinInput-DbZ0b1i1-BrTXu3Km.js +0 -247
- package/site/dist/assets/PrivyPluginContext-DA-yS5vO-CY60yubk.js +0 -1
- package/site/dist/assets/QrCode-DbnZwlkH-CcMrWV5D.js +0 -22
- package/site/dist/assets/RecoveryOAuthStatusScreen-CsgtTI2x-DgeDnHOK.js +0 -1
- package/site/dist/assets/RecoveryPasswordCreateScreen-Be-qJ-LU-CvJJwLhK.js +0 -1
- package/site/dist/assets/RecoverySelectionScreen-D1iGtpmi-CADtGtSV.js +0 -7
- package/site/dist/assets/SIWXUtil-Cpiv91-M.js +0 -1
- package/site/dist/assets/Screen-D30meWsY-vEusJ7KX.js +0 -175
- package/site/dist/assets/ScreenHeader-CHmc4-Lu-BvGTLg53.js +0 -31
- package/site/dist/assets/ScreenLayout-OwaQQcxH-cfOTmyl0.js +0 -1
- package/site/dist/assets/SelectSourceAsset-CWFog6gm-DxYklZYs.js +0 -140
- package/site/dist/assets/SetAutomaticRecoveryScreen-BO_OEqAZ-oeqeo05x.js +0 -14
- package/site/dist/assets/SetWalletPasswordForm-DwCTVtAh-BxFee9UA.js +0 -11
- package/site/dist/assets/ShieldCheckIcon-eFjsosCA.js +0 -1
- package/site/dist/assets/SignRequestScreen-BHKv32KR-z8ixfIma.js +0 -26
- package/site/dist/assets/SolanaWalletConnector-C7Lqk-Wz-Bc_lvdiF.js +0 -1
- package/site/dist/assets/StackedContainer-B2vaEl56-Do5dXB8-.js +0 -24
- package/site/dist/assets/StandardSignAndSendTransactionScreen-CfhIXVtd-DudetZAc.js +0 -20
- package/site/dist/assets/Subtitle-CV-2yKE4-DV0o1av3.js +0 -13
- package/site/dist/assets/TelegramAuthScreen-UL9zLfO8-Bo3sONvf.js +0 -1
- package/site/dist/assets/Title-BnzYV3Is-C3qOPnO_.js +0 -7
- package/site/dist/assets/TodoList-DnyULl18-BvxvubbF.js +0 -36
- package/site/dist/assets/TransactionDetails-e9nesl30-WWflkOIi.js +0 -109
- package/site/dist/assets/TransactionErrorView-BDBNqA_f-CotYKcgf.js +0 -178
- package/site/dist/assets/TransferFromWalletScreen-Qvn1Yuno-sVFlWqa8.js +0 -31
- package/site/dist/assets/TransferOrBridgeLoadingScreen-Dl1I_iIz-CV2-mY19.js +0 -6
- package/site/dist/assets/TurnstileWrapper-B7sNddys-oPbuMTQt.js +0 -1
- package/site/dist/assets/UpdateEmailScreen-DVOhPV0H-D_mjSpAy.js +0 -1
- package/site/dist/assets/UpdatePhoneScreen-CXRswTNZ-6RLG0ahv.js +0 -1
- package/site/dist/assets/UserLimitReachedScreen-5we2DHn8-CaVN0bti.js +0 -1
- package/site/dist/assets/Value-DTgR824E-Bp6WGZZm.js +0 -27
- package/site/dist/assets/WalletCards-DH1rqayz-D3cOTb9x.js +0 -1
- package/site/dist/assets/WalletIcon-DOIZhb2l.js +0 -1
- package/site/dist/assets/WalletInfoCard-sq_2wgFg-bOqfl5MA.js +0 -29
- package/site/dist/assets/WalletInterstitialScreen-Sh7LfsAh-DWaVkMCA.js +0 -1
- package/site/dist/assets/WalletLink-DK5LB5Ha-DjUZvqs-.js +0 -20
- package/site/dist/assets/WalletOverflowButton-bfCnp-9T-B6P7DQXA.js +0 -1
- package/site/dist/assets/WarningBanner-ZZqCEtZK-Bc2YKZb7.js +0 -21
- package/site/dist/assets/__vite-browser-external-NciY4Vu1.js +0 -1
- package/site/dist/assets/_esm-BZP3cXTv.js +0 -1
- package/site/dist/assets/_esm-ZmzBJpEs.js +0 -6
- package/site/dist/assets/accounts-D4AXF17G.js +0 -1
- package/site/dist/assets/accounts-IkdFx9nq.js +0 -1
- package/site/dist/assets/analytics-mkkvFRju-BRBcadka.js +0 -1
- package/site/dist/assets/baseSepolia-Bn1j1Ysw.js +0 -1
- package/site/dist/assets/basic-Cz1YiCSk.js +0 -1575
- package/site/dist/assets/capitalizeFirstLetter-DmLYqXsO-DtOXx-2n.js +0 -1
- package/site/dist/assets/ccip-B1J3oTZx.js +0 -7
- package/site/dist/assets/ccip-Bd7261zy.js +0 -1
- package/site/dist/assets/ccip-D6EHKpjI.js +0 -1
- package/site/dist/assets/chain-scefkYIH.js +0 -5
- package/site/dist/assets/check-DHnllI8N.js +0 -1
- package/site/dist/assets/chevron-down-1y-r4bGO.js +0 -1
- package/site/dist/assets/circle-alert-OwxamXUX.js +0 -1
- package/site/dist/assets/circle-check-big-3sZGVC10.js +0 -1
- package/site/dist/assets/circle-x-DQjNUV9J.js +0 -1
- package/site/dist/assets/client-B-BpRtwY.js +0 -1
- package/site/dist/assets/client-BfIR1FvH.js +0 -9
- package/site/dist/assets/coinbase-DCPC2L_R-YEuIn3jh.js +0 -3
- package/site/dist/assets/copy-DMOX_yn7.js +0 -1
- package/site/dist/assets/core-GIEmxmAa.js +0 -12
- package/site/dist/assets/createLucideIcon-BsERoFTA.js +0 -1
- package/site/dist/assets/defineChain-B-SQDLTG.js +0 -1
- package/site/dist/assets/dijkstra-CY95afk4.js +0 -1
- package/site/dist/assets/dist-CoS6E-3x.js +0 -1
- package/site/dist/assets/dist-Cp6IXeJd.js +0 -1
- package/site/dist/assets/dist-CrNxmdZj.js +0 -1
- package/site/dist/assets/dist-DYGtf4F0.js +0 -16
- package/site/dist/assets/embed.worker-Cnl4VGr3.js +0 -1
- package/site/dist/assets/errors-BQ3N-RVt-CZPAWCgC.js +0 -1
- package/site/dist/assets/esm-C3DslVJx.js +0 -1
- package/site/dist/assets/esm-Ci1ogKuK.js +0 -1
- package/site/dist/assets/esm-Co94ENUV.js +0 -37
- package/site/dist/assets/esm-bb8SANZh.js +0 -1
- package/site/dist/assets/esm-n2lWo7kz.js +0 -1
- package/site/dist/assets/ethers-zTjbodk5-Cs648CnD.js +0 -1
- package/site/dist/assets/eventemitter3-Dzc_0Uq2.js +0 -1
- package/site/dist/assets/external-link-BBPG3rG7.js +0 -1
- package/site/dist/assets/farcaster-DPlSjvF5-CzBCmgyL.js +0 -1
- package/site/dist/assets/features-CuiHbgEJ.js +0 -2
- package/site/dist/assets/fingerprint-pattern-CjLtyIxB.js +0 -1
- package/site/dist/assets/floating-ui.react-DmaCfayr.js +0 -1
- package/site/dist/assets/floating-ui.react-dom-CaoMF8mP.js +0 -1
- package/site/dist/assets/formatErc20TokenAmount-BuPk9xcy-BVqOKQif.js +0 -1
- package/site/dist/assets/formatter-CVbp4SlJ.js +0 -1
- package/site/dist/assets/get-entropy-details-for-user-dHRH5Gpi-BNiOFXbK.js +0 -1
- package/site/dist/assets/getChainName-DjpPdUSc-DUyKDrnp.js +0 -1
- package/site/dist/assets/getErc20Balance-jXNpFf0N-q4bV8kQq.js +0 -1
- package/site/dist/assets/getErc20TokenInfo-BNTrzLMP-DcnTFrXN.js +0 -1
- package/site/dist/assets/getFormattedUsdFromLamports-De3U9GlO-Gx4_wxON.js +0 -1
- package/site/dist/assets/getUsdcMintAddress-BVgm9GRo-r2UnDeEy.js +0 -1
- package/site/dist/assets/guards-BIW-GiMJ-D3tWTQAR.js +0 -1
- package/site/dist/assets/hooks.module-BYZGfwDl.js +0 -1
- package/site/dist/assets/hourglass-D_GfQdJr.js +0 -1
- package/site/dist/assets/id-UqEwL2BI-CTlvRMA5.js +0 -1
- package/site/dist/assets/index-BdEw5wyl-kLbhqLbv.js +0 -1
- package/site/dist/assets/index-C2h3EneX.js +0 -8
- package/site/dist/assets/index-CWARkn2w-DxuckIFn.js +0 -61
- package/site/dist/assets/index-DvMddJcd-CNBb4VUn.js +0 -12
- package/site/dist/assets/index-YiCw0Y_x-Czl0tWfF.js +0 -436
- package/site/dist/assets/index.browser-B-i-Lj3J.js +0 -1
- package/site/dist/assets/index.browser-BMmUcykv.js +0 -1
- package/site/dist/assets/index.es-Crd0TyUS.js +0 -2
- package/site/dist/assets/index.es-DQbup1WG.js +0 -3
- package/site/dist/assets/isPaymentRequestAvailable-Bq1cemEn-Cjf3l05I.js +0 -1
- package/site/dist/assets/jsx-runtime-CndCZlyt.js +0 -1
- package/site/dist/assets/landmark-BZPqMFEf.js +0 -1
- package/site/dist/assets/lib-DGtzi2DK.js +0 -1
- package/site/dist/assets/localBatchGatewayRequest-B71J8sQ9.js +0 -29
- package/site/dist/assets/lock-DyN_c-ud.js +0 -1
- package/site/dist/assets/logger-CsXm3oIv-B0UYpNFI.js +0 -1
- package/site/dist/assets/mail-V_mcPb64.js +0 -1
- package/site/dist/assets/modal-context-CwmSeFcv-DPWNJrfK.js +0 -1
- package/site/dist/assets/native-BKj27wfc.js +0 -1
- package/site/dist/assets/ofetch.CWycOUEr-Duby3iHT.js +0 -1
- package/site/dist/assets/parseAbi-Csg-8t59.js +0 -2
- package/site/dist/assets/parseAbiParameters-BWbIMYe4.js +0 -1
- package/site/dist/assets/parseEther-CHS0GNkM.js +0 -1
- package/site/dist/assets/pkce-DXF0yKjP-7_VY-d83.js +0 -1
- package/site/dist/assets/preload-helper-CRzLMJPS.js +0 -1
- package/site/dist/assets/privy-context-81KmsBw2-DiR6-Yq8.js +0 -2
- package/site/dist/assets/property-DuZ9DLP4.js +0 -3
- package/site/dist/assets/react-BfYA1q0G.js +0 -1
- package/site/dist/assets/react-CK2HRI1t.js +0 -1
- package/site/dist/assets/react-DxGeY8B8.js +0 -1
- package/site/dist/assets/react-auth-sHnipzbS.js +0 -1
- package/site/dist/assets/react-dom-BI2Koe4o.js +0 -1
- package/site/dist/assets/reservoir-x-nGuZkT-BguVFH3D.js +0 -1
- package/site/dist/assets/rolldown-runtime-Bjp52BOI.js +0 -1
- package/site/dist/assets/safe-url-D7SRPu33-CkMedGro.js +0 -1
- package/site/dist/assets/secp256k1-BeYL8aZl.js +0 -1
- package/site/dist/assets/secp256k1-Bh4MSkhz.js +0 -1
- package/site/dist/assets/secp256k1-Ci4cqHl0.js +0 -1
- package/site/dist/assets/secp256k1-DsxXqbXv.js +0 -1
- package/site/dist/assets/secp256k1-N9RUmafO.js +0 -1
- package/site/dist/assets/serializeAuthorizationList-DGMik9Wx.js +0 -1
- package/site/dist/assets/serializeSignature-CWKpxoab.js +0 -2
- package/site/dist/assets/sha2-C6s7zZmb.js +0 -1
- package/site/dist/assets/shared-DRZUmnL5-BewE5wK8.js +0 -193
- package/site/dist/assets/shared-FM0rljBt-CxLACri_.js +0 -21
- package/site/dist/assets/shouldProceedtoEmbeddedWalletCreationFlow-B3vyavrh-BkAKsRNi.js +0 -1
- package/site/dist/assets/simulateTransaction-CfuOrae4-PjA_tGjX.js +0 -1
- package/site/dist/assets/smartphone-3p8nFSTE.js +0 -1
- package/site/dist/assets/src-BBjkfi-Q.js +0 -1
- package/site/dist/assets/storage-Ufl800Ne-1qCR2JMO.js +0 -8
- package/site/dist/assets/stringify-DqUj9VzO.js +0 -20
- package/site/dist/assets/stripe.esm-DEi2D291.js +0 -2
- package/site/dist/assets/styles-BsotlekN-Aq27nZGc.js +0 -9
- package/site/dist/assets/styles-Cm9H63WO-p_ic_dxE.js +0 -92
- package/site/dist/assets/styles-DVyDvTdj-CjsWqAld.js +0 -74
- package/site/dist/assets/styles-hslXy6xG-D5QHIrJU.js +0 -164
- package/site/dist/assets/telegram-B-JqnkqZ-Dqkm4rDn.js +0 -1
- package/site/dist/assets/to-ui-error-DWe-qwS3-Bi1HUQI9.js +0 -4
- package/site/dist/assets/toViemAccount-B5iDGq1b-CdFZwv07.js +0 -2
- package/site/dist/assets/transaction-BNTP-bFm-M5tJx8vY.js +0 -1
- package/site/dist/assets/transfer-6YztDh-t-BVQkTvG-.js +0 -1
- package/site/dist/assets/triangle-alert-BG3Qw-Hq.js +0 -1
- package/site/dist/assets/twitch-5IOe4sIQ-CaXHFlAu.js +0 -1
- package/site/dist/assets/types-4CuOD23i.js +0 -1
- package/site/dist/assets/use-headless-crypto-deposit-Yn-QRLB3-CQqeyhGY.js +0 -1
- package/site/dist/assets/use-unlink-wallet-BKK4_5Ur-C0xQN_Lp.js +0 -1
- package/site/dist/assets/useActiveWallet-B-yZYGc6-BkK6rFBm.js +0 -123
- package/site/dist/assets/useGetSolPrice-x7gfUIHJ-CLVXqv6I.js +0 -1
- package/site/dist/assets/useGetTokenPrice-CaoUkb79-DAXXs3rs.js +0 -1
- package/site/dist/assets/useI18n-C-5n_noF-CGpkgIVy.js +0 -1
- package/site/dist/assets/useWalletBalance-CZnP5f_f-Cfd64m4n.js +0 -1
- package/site/dist/assets/useWallets-X1ndvJ_U-CAYqg7Za.js +0 -1
- package/site/dist/assets/utils-BkR7EQjg.js +0 -1
- package/site/dist/assets/utils-DJhBNOZA.js +0 -1
- package/site/dist/assets/utils-DdckVfQr.js +0 -1
- package/site/dist/assets/w3m-modal-B4H_uiPH.js +0 -1174
- package/site/dist/assets/wallet-BNI12IYk.js +0 -1
- package/site/dist/assets/wallet-CITSaPlB.js +0 -2
- package/site/dist/assets/wallet-connect-BvJtUsDt-CVlSNIXP.js +0 -1
- package/site/dist/assets/walletconnect-registry-xxG8XLCb-BpzpBq5s.js +0 -1
- package/site/dist/assets/walletconnect-v2-3frQFwbg-CzZ6oybX.js +0 -12
- package/site/dist/assets/wui-ux-by-reown-XyHdtV1O.js +0 -1147
- package/site/dist/assets/x-gjDrY2rk.js +0 -1
- package/src/discover/explore.js +0 -291
- package/src/market/settle.js +0 -165
- package/src/market/terms.js +0 -200
- package/src/publish/cli.js +0 -336
- package/src/publish/envelope.js +0 -185
- package/src/publish/manifest.js +0 -142
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./createLucideIcon-BsERoFTA.js";var t=e(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]);export{t};
|
package/src/discover/explore.js
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
// The Fangorn explorer: every verified app, what it is about, and what the
|
|
2
|
-
// ERC-8004 registries say about it — read live, with no bake of its own.
|
|
3
|
-
//
|
|
4
|
-
// Everything here is already published by someone else:
|
|
5
|
-
// AppRegistry `AppAgentChanged` which apps exist and where their cards are
|
|
6
|
-
// each card name, tools, views; checked against the chain
|
|
7
|
-
// each view's catalog rows, domains, and coverage centroids (what it is about)
|
|
8
|
-
// ERC-8004 identity `Registered` the agent minted for the app
|
|
9
|
-
// ERC-8004 reputation feedback count and average per agent
|
|
10
|
-
//
|
|
11
|
-
// Both registries are scanned from their first event in windows as wide as the
|
|
12
|
-
// chain's RPC allows (`chainOf`), in parallel, so the page and the MCP tool read
|
|
13
|
-
// the same chain the same way, and a new app shows up on the next read.
|
|
14
|
-
//
|
|
15
|
-
// `client` is a viem PublicClient (getLogs, readContract): passed in, so this
|
|
16
|
-
// runs in a tab and in node, and the self-check needs no chain.
|
|
17
|
-
//
|
|
18
|
-
// Windows grow with the chain. Pass `store` (apps.js cachedLogs) and only the
|
|
19
|
-
// blocks since the last read are scanned; the page passes none.
|
|
20
|
-
|
|
21
|
-
import { parseAbi, parseAbiItem } from "viem";
|
|
22
|
-
// The config module alone (viem only), not the SDK's root: this runs in a tab too.
|
|
23
|
-
import { BaseSepoliaConfig } from "@fangorn-network/sdk/lib/config.js";
|
|
24
|
-
import { APP_EXTENSION, cachedLogs } from "./apps.js";
|
|
25
|
-
import { survey, comparable } from "./directory.js";
|
|
26
|
-
import { rankDomains, zFloor, lexScore } from "../core/rank.js";
|
|
27
|
-
|
|
28
|
-
// The ERC-8004 registries per chain id, where `fangorn app agent` mints (agent0-sdk's
|
|
29
|
-
// defaults, and the CLI's override for Arbitrum Sepolia, which agent0-sdk lacks).
|
|
30
|
-
const ERC8004 = {
|
|
31
|
-
421614: { identity: "0x8004A818BFB912233c491871b3d84c89A494BD9e", reputation: "0x8004B663056A597Dffe9eCcC1965A193B7388713",
|
|
32
|
-
// The identity registry's first event (2026-10-05). Its public RPC takes 10M-block windows.
|
|
33
|
-
identityFrom: 241_557_787n, window: 10_000_000n, scan: "arbitrum-sepolia" },
|
|
34
|
-
// ponytail: identity read from the AppRegistry's deployment, since an app's agent is minted after it.
|
|
35
|
-
// An agent minted before then and rebound with --skip-register is missed; scan earlier if that happens.
|
|
36
|
-
84532: { identity: "0x8004A818BFB912233c491871b3d84c89A494BD9e", reputation: "0x8004B663056A597Dffe9eCcC1965A193B7388713",
|
|
37
|
-
scan: "base-sepolia" },
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
/** What explore reads on one of the SDK's networks (`SupportedNetworks.baseSepolia`, …). */
|
|
41
|
-
export function chainOf(net = BaseSepoliaConfig) {
|
|
42
|
-
const e = ERC8004[net.caip2];
|
|
43
|
-
if (!e) throw new Error(`explore: no ERC-8004 registries known for chain ${net.caip2}`);
|
|
44
|
-
return {
|
|
45
|
-
chainId: net.caip2, appRegistry: net.appRegistryContractAddress, identity: e.identity, reputation: e.reputation,
|
|
46
|
-
// Nothing to read before the registry's deployment; from 0 a scan is mostly empty windows.
|
|
47
|
-
appRegistryFrom: net.appRegistryFromBlock, identityFrom: e.identityFrom ?? net.appRegistryFromBlock,
|
|
48
|
-
window: e.window ?? net.logWindow ?? 1000n,
|
|
49
|
-
scan: (agentId) => `https://8004scan.io/agents/${e.scan}/${agentId}`,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export const CHAIN = chainOf();
|
|
54
|
-
|
|
55
|
-
const APP_AGENT_CHANGED = parseAbiItem("event AppAgentChanged(bytes32 indexed app_id, string agent_uri)");
|
|
56
|
-
const REGISTERED = parseAbiItem("event Registered(uint256 indexed agentId, string agentURI, address indexed owner)");
|
|
57
|
-
const APPS = parseAbi(["function getAppOwner(bytes32) view returns (address)"]);
|
|
58
|
-
const REP = parseAbi([
|
|
59
|
-
"function getClients(uint256) view returns (address[])",
|
|
60
|
-
"function getSummary(uint256, address[], string, string) view returns (uint64, int128, uint8)",
|
|
61
|
-
]);
|
|
62
|
-
|
|
63
|
-
/** A link someone else wrote, shown to a reader: https or nothing. */
|
|
64
|
-
const https = (u) => { try { const x = new URL(String(u)); return x.protocol === "https:" ? x.href : null; } catch { return null; } };
|
|
65
|
-
const slug = (name) => String(name).toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) || "app";
|
|
66
|
-
|
|
67
|
-
/** A card is listed only if it names this chain's AppRegistry and the app that
|
|
68
|
-
* bound it — the checks `discoverApp` makes. The binding itself is the log we
|
|
69
|
-
* read it from: we scanned to `latest`, so the last write per app is current. */
|
|
70
|
-
export function verifyCard(card, appId, chain = CHAIN) {
|
|
71
|
-
const p = card?.capabilities?.extensions?.find((e) => e.uri === APP_EXTENSION)?.params;
|
|
72
|
-
if (!p) return "no fangorn app extension";
|
|
73
|
-
if (String(p.appId).toLowerCase() !== appId.toLowerCase()) return "card names another app";
|
|
74
|
-
if (p.chainId !== chain.chainId || String(p.appRegistry).toLowerCase() !== chain.appRegistry.toLowerCase()) return "card is for another registry";
|
|
75
|
-
if (!/^\d+$/.test(String(p.fromBlock))) return "bad fromBlock";
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* The agent an app registered. `fangorn app agent` mints it and then binds the
|
|
81
|
-
* card, from the owner's wallet, so it is the owner's latest `Registered` at or
|
|
82
|
-
* before the binding.
|
|
83
|
-
*
|
|
84
|
-
* ponytail: paired by owner and block, not by reading the registration file
|
|
85
|
-
* (IPFS gateways are too slow and flaky for a page load). An owner that
|
|
86
|
-
* rebinds with --skip-register after minting another app's agent gets that
|
|
87
|
-
* agent; fetch tokenURI and match its A2A endpoint if that starts happening.
|
|
88
|
-
*/
|
|
89
|
-
export function pairAgent(registered, owner, bindBlock) {
|
|
90
|
-
let best = null;
|
|
91
|
-
for (const r of registered) {
|
|
92
|
-
if (r.owner.toLowerCase() !== owner.toLowerCase() || r.block > bindBlock) continue;
|
|
93
|
-
if (!best || r.block > best.block || (r.block === best.block && r.agentId > best.agentId)) best = r;
|
|
94
|
-
}
|
|
95
|
-
return best?.agentId ?? null;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** Retried: dropping a verified app over a blip hides it from everyone who
|
|
99
|
-
* loads the page in that second. Seen 2026-09-28: headless Chrome in WSL got
|
|
100
|
-
* intermittent net::ERR_SSL_PROTOCOL_ERROR from one pages.dev host (curl never
|
|
101
|
-
* did); three tries do not always get past that one. */
|
|
102
|
-
async function json(url, timeoutMs = 8000, tries = 3) {
|
|
103
|
-
try {
|
|
104
|
-
const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
105
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
106
|
-
return await res.json();
|
|
107
|
-
} catch (e) {
|
|
108
|
-
if (tries <= 1) throw e;
|
|
109
|
-
await new Promise((ok) => setTimeout(ok, 600 * (4 - tries))); // 600ms, then 1.2s
|
|
110
|
-
return json(url, timeoutMs, tries - 1);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async function reputation(client, agentId, chain) {
|
|
115
|
-
try {
|
|
116
|
-
const clients = await client.readContract({ address: chain.reputation, abi: REP, functionName: "getClients", args: [agentId] });
|
|
117
|
-
if (!clients.length) return { feedback: 0, average: null };
|
|
118
|
-
const [count, value, decimals] = await client.readContract({ address: chain.reputation, abi: REP, functionName: "getSummary", args: [agentId, clients, "", ""] });
|
|
119
|
-
return { feedback: Number(count), average: Number(value) / 10 ** decimals, clients: clients.length };
|
|
120
|
-
} catch (e) {
|
|
121
|
-
return { error: e?.shortMessage ?? e?.message ?? String(e) };
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// `window`: the most blocks one getLogs may span on the client's RPC (chainOf says, per chain).
|
|
126
|
-
async function getLogsSince(client, start, filter, window, store) {
|
|
127
|
-
const head = await client.getBlockNumber();
|
|
128
|
-
const read = async (start, head) => {
|
|
129
|
-
const windows = [];
|
|
130
|
-
for (let from = start; from <= head; from += window) {
|
|
131
|
-
const to = from + window - 1n < head ? from + window - 1n : head;
|
|
132
|
-
windows.push(client.getLogs({ ...filter, fromBlock: from, toBlock: to }));
|
|
133
|
-
}
|
|
134
|
-
// In window order: oldest first still holds. Only what readDirectory reads, so a store stays small.
|
|
135
|
-
return (await Promise.all(windows)).flat().map(({ args, blockNumber }) => ({ args, blockNumber }));
|
|
136
|
-
};
|
|
137
|
-
return store ? cachedLogs(store, `${filter.address}:${filter.event.name}:${start}`, start, head, read) : read(start, head);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Every verified app, with its 8004 agent, reputation, and catalog.
|
|
142
|
-
* Unverified apps are dropped, not listed; `dropped` says why, for debugging.
|
|
143
|
-
*
|
|
144
|
-
* `onUpdate({ apps, pending })`, if given, is called once the bindings are read
|
|
145
|
-
* and again as each app lands or drops, so a page can show apps as they arrive.
|
|
146
|
-
* `pending` counts the bound apps not yet settled.
|
|
147
|
-
* `store`, if given, keeps the logs read (apps.js cachedLogs), so the next read
|
|
148
|
-
* scans only the blocks since.
|
|
149
|
-
*/
|
|
150
|
-
export async function readDirectory(client, { chain = CHAIN, onUpdate = () => {}, store } = {}) {
|
|
151
|
-
const [bindLogs, regLogs] = await Promise.all([
|
|
152
|
-
getLogsSince(client, chain.appRegistryFrom ?? 0n, { address: chain.appRegistry, event: APP_AGENT_CHANGED }, chain.window ?? 1000n, store),
|
|
153
|
-
getLogsSince(client, chain.identityFrom ?? 0n, { address: chain.identity, event: REGISTERED }, chain.window ?? 1000n, store),
|
|
154
|
-
]);
|
|
155
|
-
const registered = regLogs.map((l) => ({ agentId: l.args.agentId, owner: l.args.owner, block: l.blockNumber }));
|
|
156
|
-
const latest = new Map(); // logs come oldest first: the last write wins
|
|
157
|
-
for (const l of bindLogs) latest.set(l.args.app_id, { uri: l.args.agent_uri, block: l.blockNumber });
|
|
158
|
-
const bound = [...latest].filter(([, { uri }]) => uri); // an empty uri is unbound on purpose
|
|
159
|
-
|
|
160
|
-
// One pipeline per app, so the quick ones need not wait on Quorum's 1.7 MB
|
|
161
|
-
// catalog. Only a card failure drops an app; an owner or catalog that fails
|
|
162
|
-
// leaves it listed with less to say about it.
|
|
163
|
-
const apps = [], dropped = [];
|
|
164
|
-
let pending = bound.length;
|
|
165
|
-
const settle = () => { pending--; apps.sort((a, b) => a.name.localeCompare(b.name)); onUpdate({ apps: [...apps], pending }); };
|
|
166
|
-
onUpdate({ apps: [], pending });
|
|
167
|
-
await Promise.all(bound.map(async ([appId, { uri, block }]) => {
|
|
168
|
-
let card;
|
|
169
|
-
try {
|
|
170
|
-
if (!/^https:\/\//.test(uri)) throw new Error("card is not https");
|
|
171
|
-
card = await json(uri);
|
|
172
|
-
const why = verifyCard(card, appId, chain);
|
|
173
|
-
if (why) throw new Error(why);
|
|
174
|
-
} catch (e) { dropped.push({ card: uri, why: e?.message ?? String(e) }); return settle(); }
|
|
175
|
-
|
|
176
|
-
const p = card.capabilities.extensions.find((e) => e.uri === APP_EXTENSION).params;
|
|
177
|
-
const [[owner, agentId, rep], { corpora, unreachable }] = await Promise.all([
|
|
178
|
-
client.readContract({ address: chain.appRegistry, abi: APPS, functionName: "getAppOwner", args: [appId] }).catch(() => null)
|
|
179
|
-
.then(async (owner) => {
|
|
180
|
-
const agentId = owner && pairAgent(registered, owner, block);
|
|
181
|
-
return [owner, agentId, agentId == null ? null : await reputation(client, agentId, chain)];
|
|
182
|
-
}),
|
|
183
|
-
survey((p.views ?? []).filter((v) => /^https:\/\//.test(v))),
|
|
184
|
-
]);
|
|
185
|
-
const name = typeof card.name === "string" && card.name.trim() ? card.name.trim() : `App ${appId.slice(0, 10)}`;
|
|
186
|
-
apps.push({
|
|
187
|
-
app: slug(name), name, description: typeof card.description === "string" ? card.description : "",
|
|
188
|
-
site: https(card.url), card: uri, appId, owner,
|
|
189
|
-
boundAt: Number(block), fromBlock: Number(p.fromBlock),
|
|
190
|
-
tools: (card.skills ?? []).map((s) => s.id),
|
|
191
|
-
agent: agentId == null ? null : { id: Number(agentId), scan: chain.scan(agentId) },
|
|
192
|
-
reputation: rep,
|
|
193
|
-
// null, not 0, when no catalog answered: "0 records" would claim it was counted.
|
|
194
|
-
rows: corpora.length ? corpora.reduce((n, c) => n + (c.rows || 0), 0) : null,
|
|
195
|
-
unreachable: unreachable.length,
|
|
196
|
-
domains: corpora.map((c) => ({ name: c.domain, description: c.description, rows: c.rows, coverage: c.coverage, model: c.model })),
|
|
197
|
-
});
|
|
198
|
-
settle();
|
|
199
|
-
}));
|
|
200
|
-
return { apps, dropped };
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/** A calibration knob, not a law: nomic-embed-text-v1.5 at 256d, 5 apps
|
|
204
|
-
* (2026-09-28). Every on-topic top app scored >= 0.545 ("a cozy game" ->
|
|
205
|
-
* Sidequest), every off-topic top <= 0.52 ("bitcoin" -> Audius). Re-measure
|
|
206
|
-
* with the explorer's check when the model or the network changes much. */
|
|
207
|
-
export const MIN_AFFINITY = 0.53;
|
|
208
|
-
|
|
209
|
-
// ponytail: a short English list, enough for questions put to a directory.
|
|
210
|
-
const FILLER = new Set("the and for are was were has have had not but with from that this these those what which where when who whom whose why how can could would should will shall may might must about into onto over under than then there their them they you your our any all some more most much many app apps find show tell learn know want need good best reputable".split(" "));
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Rank a directory against a question. An app scores as its best domain's
|
|
214
|
-
* coverage affinity (what its data is about, not what its blurb says). With no
|
|
215
|
-
* `qv` (no embedder yet), name and description are matched by words.
|
|
216
|
-
*
|
|
217
|
-
* `relevant`: mean + 1σ of this query's scores, and at least MIN_AFFINITY.
|
|
218
|
-
* Unlike findCorpora the top app is NOT always relevant: "which app has stock
|
|
219
|
-
* prices" must be able to answer "none", or the explorer vouches for a
|
|
220
|
-
* government-records app on a finance question.
|
|
221
|
-
*/
|
|
222
|
-
export function rankApps(apps, query, { qv = null, model = null } = {}) {
|
|
223
|
-
const q = String(query ?? "").trim().toLowerCase();
|
|
224
|
-
if (!q) return apps.map((a) => ({ ...a, score: null, relevant: null, ranked_by: null }));
|
|
225
|
-
// Filler dropped, or "where can I learn about X" matches every blurb with "about" in it.
|
|
226
|
-
const content = q.split(/[^\p{L}\p{N}]+/u).filter((w) => w.length > 2 && !FILLER.has(w)).join(" ");
|
|
227
|
-
const words = (a) => (content ? lexScore({ text: `${a.name} ${a.description} ${a.domains.map((d) => d.description ?? "").join(" ")}` }, content) : 0);
|
|
228
|
-
let scored;
|
|
229
|
-
if (qv) {
|
|
230
|
-
scored = apps.map((a) => {
|
|
231
|
-
const doms = rankDomains(a.domains.filter((d) => comparable(d, model)), qv);
|
|
232
|
-
const best = doms.find((d) => d.affinity != null);
|
|
233
|
-
// No coverage (its catalog did not answer, or predates coverage):
|
|
234
|
-
// its own blurb, by words, rather than silently ranking it last.
|
|
235
|
-
if (!best) return { ...a, score: null, matched: null, ranked_by: "words", wordHit: words(a) > 0 };
|
|
236
|
-
return { ...a, score: best.affinity, matched: best.name, ranked_by: "meaning" };
|
|
237
|
-
});
|
|
238
|
-
} else {
|
|
239
|
-
scored = apps.map((a) => ({ ...a, score: words(a), ranked_by: "words" }));
|
|
240
|
-
}
|
|
241
|
-
scored.sort((a, b) => (b.score ?? -Infinity) - (a.score ?? -Infinity));
|
|
242
|
-
const s = scored.filter((a) => a.ranked_by === "meaning").map((a) => a.score);
|
|
243
|
-
const floor = qv ? Math.max(zFloor(s), MIN_AFFINITY) : 1e-9;
|
|
244
|
-
return scored.map(({ wordHit, ...a }) => ({ ...a, relevant: wordHit ?? (a.score != null && a.score >= floor) }));
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/** What a caller sees: the ranking minus the centroids. Quorum alone has 29
|
|
248
|
-
* domains, so an app reports how many, and which one matched. */
|
|
249
|
-
export const brief = ({ domains, ...a }) => ({ ...a, domains: domains.length });
|
|
250
|
-
|
|
251
|
-
// ── self-check: `node src/discover/explore.js` ──────────────────────────────────
|
|
252
|
-
if (typeof process !== "undefined" && import.meta.url === `file://${process.argv[1]}` && process.argv[1].endsWith("/explore.js")) {
|
|
253
|
-
const j = (x) => JSON.stringify(x, (_, v) => (typeof v === "bigint" ? `${v}n` : v));
|
|
254
|
-
const eq = (a, b, m) => { if (j(a) !== j(b)) throw new Error(`${m}: ${j(a)} != ${j(b)}`); };
|
|
255
|
-
const O = "0x00000000000000000000000000000000000000aa", P = "0x00000000000000000000000000000000000000bb";
|
|
256
|
-
const reg = [
|
|
257
|
-
{ agentId: 1n, owner: O, block: 10n }, { agentId: 2n, owner: P, block: 11n },
|
|
258
|
-
{ agentId: 3n, owner: O, block: 20n }, { agentId: 4n, owner: O, block: 99n },
|
|
259
|
-
];
|
|
260
|
-
eq(pairAgent(reg, O, 21n), 3n, "owner's latest agent at or before the binding");
|
|
261
|
-
eq(pairAgent(reg, P.toUpperCase().replace("0X", "0x"), 50n), 2n, "owner compared case-insensitively");
|
|
262
|
-
eq(pairAgent(reg, O, 5n), null, "no agent before the binding");
|
|
263
|
-
|
|
264
|
-
const A = "0x" + "a".repeat(64);
|
|
265
|
-
const card = (params) => ({ capabilities: { extensions: [{ uri: APP_EXTENSION, params }] } });
|
|
266
|
-
const good = { appId: A, chainId: CHAIN.chainId, appRegistry: CHAIN.appRegistry.toUpperCase().replace("0X", "0x"), fromBlock: "7" };
|
|
267
|
-
eq(verifyCard(card(good), A), null, "a good card verifies");
|
|
268
|
-
eq(verifyCard(card({ ...good, appId: "0x" + "b".repeat(64) }), A), "card names another app", "wrong app");
|
|
269
|
-
eq(verifyCard(card({ ...good, chainId: 1 }), A), "card is for another registry", "wrong chain");
|
|
270
|
-
eq(verifyCard({}, A), "no fangorn app extension", "no extension");
|
|
271
|
-
|
|
272
|
-
const cov = (v) => ({ vectors: [v] });
|
|
273
|
-
const apps = [
|
|
274
|
-
{ name: "Tunes", description: "music tracks", domains: [{ name: "tracks", coverage: cov([1, 0, 0]) }] },
|
|
275
|
-
{ name: "Sky", description: "weather alerts", domains: [{ name: "alerts", coverage: cov([0, 1, 0]) }, { name: "old", coverage: null }] },
|
|
276
|
-
{ name: "Law", description: "meetings", domains: [{ name: "minutes", coverage: cov([0, 0, 1]) }] },
|
|
277
|
-
{ name: "Empty", description: "", domains: [] },
|
|
278
|
-
];
|
|
279
|
-
const r = rankApps(apps, "rain", { qv: [0.1, 1, 0] });
|
|
280
|
-
eq(r.map((a) => a.name), ["Sky", "Tunes", "Law", "Empty"], "ranked by best domain affinity, unscored last");
|
|
281
|
-
eq([r[0].relevant, r[0].matched, r[3].relevant], [true, "alerts", false], "top is relevant, unscored is not");
|
|
282
|
-
const blind = rankApps([{ ...apps[1], domains: [] }, apps[0], apps[2]], "weather alerts", { qv: [0.1, 1, 0] });
|
|
283
|
-
eq(blind.map((a) => [a.name, a.relevant, a.ranked_by]).at(-1), ["Sky", true, "words"], "an app with no coverage still matches on its own words");
|
|
284
|
-
eq(rankApps([{ ...apps[1], description: "all about the sky", domains: [] }], "where can I learn about music", { qv: [1, 0, 0] })[0].relevant, false, "filler words never match");
|
|
285
|
-
eq(rankApps(apps, "stock prices", { qv: [-1, -1, -1] }).filter((a) => a.relevant).length, 0, "a question no app covers matches none");
|
|
286
|
-
eq(rankApps(apps, "music").map((a) => [a.name, a.relevant]).slice(0, 2), [["Tunes", true], ["Sky", false]], "word fallback");
|
|
287
|
-
eq(rankApps(apps, "").map((a) => a.score), [null, null, null, null], "no query: listed, not ranked");
|
|
288
|
-
eq([https("javascript:alert(1)"), https("http://x.test"), https("https://x.test/a")], [null, null, "https://x.test/a"], "only https links reach a reader");
|
|
289
|
-
eq(brief({ name: "x", domains: [{ name: "d", coverage: 1 }] }), { name: "x", domains: 1 }, "brief drops centroids");
|
|
290
|
-
console.log("explore.js self-check ok — cards verified, agents paired by owner and block, apps ranked by coverage or words");
|
|
291
|
-
}
|
package/src/market/settle.js
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
// Encrypting a file into the access worker, from Node.
|
|
2
|
-
//
|
|
3
|
-
// This is the publisher's byte path, and it is the half of publishing that no
|
|
4
|
-
// relay can do for you: the DEK is generated here, sealed to the worker's public
|
|
5
|
-
// key here, and the plaintext never leaves the machine that owns it. A relay
|
|
6
|
-
// that offered to do this step would be a relay that had your file.
|
|
7
|
-
//
|
|
8
|
-
// The browser has its own copy of this walk (an app's own encrypt.js, over
|
|
9
|
-
// File.slice instead of fs.read). They must agree byte for byte — they share
|
|
10
|
-
// `pack`, `aadFor` and `chunkKey` from envelope.js precisely so that the only
|
|
11
|
-
// thing that differs between them is how bytes are read off a disk.
|
|
12
|
-
import { open } from "node:fs/promises";
|
|
13
|
-
import { createHash } from "node:crypto";
|
|
14
|
-
import { seal } from "@fangorn-network/sdk";
|
|
15
|
-
import { bytesToHex } from "viem";
|
|
16
|
-
import {
|
|
17
|
-
CHUNK_SIZE, NONCE_LEN, aadFor, chunkKey, deleteResource,
|
|
18
|
-
getWorkerPubkey, pack, putChunk, unpack,
|
|
19
|
-
} from "../publish/envelope.js";
|
|
20
|
-
|
|
21
|
-
export { CHUNK_SIZE, aadFor, chunkKey, deleteResource, getWorkerPubkey };
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Envelope-encrypt the file at `file` chunk by chunk and upload each
|
|
25
|
-
* {ciphertext, sealed DEK} to the access worker's R2. Reads one chunk at a time,
|
|
26
|
-
* so peak memory is ~2x chunkSize no matter how big the file is.
|
|
27
|
-
*
|
|
28
|
-
* @returns { plaintextHash, chunks, size, chunkSize } — the hash to commit
|
|
29
|
-
* on-chain, the chunk count the buyer reassembles, and the plaintext
|
|
30
|
-
* byte geometry a streaming player needs to map a Range request onto a
|
|
31
|
-
* chunk (chunk i starts at i * chunkSize).
|
|
32
|
-
*/
|
|
33
|
-
export async function encryptAndUpload({ file, resourceId, workerUrl, uploadToken, chunkSize = CHUNK_SIZE, onProgress }) {
|
|
34
|
-
const dek = crypto.getRandomValues(new Uint8Array(32));
|
|
35
|
-
const aesKey = await crypto.subtle.importKey("raw", dek, "AES-GCM", false, ["encrypt"]);
|
|
36
|
-
const sealedDek = bytesToHex(seal(dek, await getWorkerPubkey(workerUrl), resourceId));
|
|
37
|
-
|
|
38
|
-
const fh = await open(file, "r");
|
|
39
|
-
try {
|
|
40
|
-
const { size } = await fh.stat();
|
|
41
|
-
const chunks = Math.max(1, Math.ceil(size / chunkSize));
|
|
42
|
-
const hash = createHash("sha256");
|
|
43
|
-
const buf = Buffer.allocUnsafe(Math.min(size, chunkSize) || 1);
|
|
44
|
-
|
|
45
|
-
for (let i = 0; i < chunks; i++) {
|
|
46
|
-
const { bytesRead } = await fh.read(buf, 0, buf.length, i * chunkSize);
|
|
47
|
-
const plain = buf.subarray(0, bytesRead);
|
|
48
|
-
hash.update(plain);
|
|
49
|
-
|
|
50
|
-
const nonce = crypto.getRandomValues(new Uint8Array(NONCE_LEN));
|
|
51
|
-
const aesCt = new Uint8Array(
|
|
52
|
-
await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce, additionalData: aadFor(i) }, aesKey, await pack(plain)),
|
|
53
|
-
);
|
|
54
|
-
const body = new Uint8Array(NONCE_LEN + aesCt.length);
|
|
55
|
-
body.set(nonce, 0);
|
|
56
|
-
body.set(aesCt, NONCE_LEN);
|
|
57
|
-
|
|
58
|
-
await putChunk({ workerUrl, uploadToken, key: chunkKey(resourceId, i), body, sealedDek });
|
|
59
|
-
onProgress?.(i + 1, chunks);
|
|
60
|
-
}
|
|
61
|
-
return { plaintextHash: `0x${hash.digest("hex")}`, chunks, size, chunkSize };
|
|
62
|
-
} finally {
|
|
63
|
-
await fh.close();
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// ── self-check: `node src/market/settle.js` — no network, no worker ─────────────
|
|
68
|
-
//
|
|
69
|
-
// It decrypts with bare AES-GCM rather than importing a buyer, because what is
|
|
70
|
-
// under test here is the ENCRYPTOR: chunk addressing, the AAD index binding, the
|
|
71
|
-
// ragged tail, and that pack/unpack round trip. An app's full publisher→buyer
|
|
72
|
-
// round trip belongs in that app, against its own buyer.
|
|
73
|
-
if (import.meta.url === `file://${process.argv[1]}` && process.argv[1].endsWith("/settle.js")) {
|
|
74
|
-
const { writeFileSync, rmSync } = await import("node:fs");
|
|
75
|
-
const { unseal } = await import("@fangorn-network/sdk");
|
|
76
|
-
const { x25519 } = await import("@noble/curves/ed25519");
|
|
77
|
-
const { hexToBytes, keccak256 } = await import("viem");
|
|
78
|
-
|
|
79
|
-
const CHUNK = 1000;
|
|
80
|
-
const tmp = `/tmp/westmarch-settle-${process.pid}.bin`;
|
|
81
|
-
const workerSecret = crypto.getRandomValues(new Uint8Array(32));
|
|
82
|
-
const workerPubkey = x25519.getPublicKey(workerSecret);
|
|
83
|
-
const r2 = new Map();
|
|
84
|
-
let sealedSeen = null;
|
|
85
|
-
const realFetch = globalThis.fetch;
|
|
86
|
-
globalThis.fetch = async (url, init = {}) => {
|
|
87
|
-
const u = String(url);
|
|
88
|
-
if (u.endsWith("/pubkey")) return { ok: true, json: async () => ({ pubkey: bytesToHex(workerPubkey) }) };
|
|
89
|
-
if (u.includes("/upload/")) {
|
|
90
|
-
const key = u.split("/upload/")[1];
|
|
91
|
-
if (init.method === "DELETE") return r2.delete(key), { ok: true };
|
|
92
|
-
sealedSeen = init.headers["X-Sealed-Dek"];
|
|
93
|
-
r2.set(key, new Uint8Array(init.body));
|
|
94
|
-
return { ok: true };
|
|
95
|
-
}
|
|
96
|
-
return { ok: false, status: 404 };
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const rid = keccak256(new Uint8Array([1]));
|
|
100
|
-
/** Decrypt one stored chunk the way any buyer must. */
|
|
101
|
-
const read = async (i) => {
|
|
102
|
-
const dek = unseal(hexToBytes(sealedSeen), workerSecret, rid);
|
|
103
|
-
const key = await crypto.subtle.importKey("raw", dek, "AES-GCM", false, ["decrypt"]);
|
|
104
|
-
const body = r2.get(chunkKey(rid, i));
|
|
105
|
-
return unpack(new Uint8Array(await crypto.subtle.decrypt(
|
|
106
|
-
{ name: "AES-GCM", iv: body.subarray(0, NONCE_LEN), additionalData: aadFor(i) },
|
|
107
|
-
key, body.subarray(NONCE_LEN),
|
|
108
|
-
)));
|
|
109
|
-
};
|
|
110
|
-
const same = (a, b) => a.length === b.length && a.every((x, i) => x === b[i]);
|
|
111
|
-
|
|
112
|
-
try {
|
|
113
|
-
// Random bytes: 2.5 chunks → a ragged tail, and gzip must LOSE, so these
|
|
114
|
-
// exercise pack()'s store-raw branch.
|
|
115
|
-
const bytes = crypto.getRandomValues(new Uint8Array(2500));
|
|
116
|
-
writeFileSync(tmp, bytes);
|
|
117
|
-
const out = await encryptAndUpload({ file: tmp, resourceId: rid, workerUrl: "http://stub", chunkSize: CHUNK });
|
|
118
|
-
if (out.chunks !== 3) throw new Error(`chunk count: got ${out.chunks}, want 3`);
|
|
119
|
-
if (out.plaintextHash !== `0x${createHash("sha256").update(bytes).digest("hex")}`) throw new Error("streamed hash != whole-file sha256");
|
|
120
|
-
if (!r2.has(rid)) throw new Error("chunk 0 must land on the resourceId — that is where /access looks");
|
|
121
|
-
if (r2.size !== 3) throw new Error(`chunk keys collide: ${r2.size} objects for 3 chunks`);
|
|
122
|
-
// nonce(12) + flag(1) + ct(500) + tag(16)
|
|
123
|
-
if (r2.get(chunkKey(rid, 2)).length !== 12 + 1 + 500 + 16) throw new Error("ragged last chunk is the wrong size");
|
|
124
|
-
|
|
125
|
-
const back = new Uint8Array([...await read(0), ...await read(1), ...await read(2)]);
|
|
126
|
-
if (!same(back, bytes)) throw new Error("round trip corrupted the file");
|
|
127
|
-
|
|
128
|
-
// AAD binds each chunk to its index: a chunk decrypted at the wrong index
|
|
129
|
-
// must FAIL, not silently hand back scrambled bytes.
|
|
130
|
-
let swallowed = false;
|
|
131
|
-
try {
|
|
132
|
-
const dek = unseal(hexToBytes(sealedSeen), workerSecret, rid);
|
|
133
|
-
const key = await crypto.subtle.importKey("raw", dek, "AES-GCM", false, ["decrypt"]);
|
|
134
|
-
const body = r2.get(chunkKey(rid, 0));
|
|
135
|
-
await crypto.subtle.decrypt({ name: "AES-GCM", iv: body.subarray(0, NONCE_LEN), additionalData: aadFor(1) }, key, body.subarray(NONCE_LEN));
|
|
136
|
-
swallowed = true;
|
|
137
|
-
} catch { /* expected */ }
|
|
138
|
-
if (swallowed) throw new Error("a chunk decrypted under the wrong index — AAD binding is broken");
|
|
139
|
-
|
|
140
|
-
// Compressible payload: pack()'s other branch. Stored bytes must come in
|
|
141
|
-
// well under the plaintext and still round trip.
|
|
142
|
-
r2.clear();
|
|
143
|
-
const text = new Uint8Array(3000).fill(65);
|
|
144
|
-
writeFileSync(tmp, text);
|
|
145
|
-
const packed = await encryptAndUpload({ file: tmp, resourceId: rid, workerUrl: "http://stub", chunkSize: CHUNK });
|
|
146
|
-
const stored = [...r2.values()].reduce((n, b) => n + b.length, 0);
|
|
147
|
-
if (stored > text.length / 2) throw new Error(`compressible payload barely shrank: ${stored} of ${text.length}`);
|
|
148
|
-
const gzBack = new Uint8Array([...await read(0), ...await read(1), ...await read(2)]);
|
|
149
|
-
if (!same(gzBack, text)) throw new Error("gzip round trip corrupted the file");
|
|
150
|
-
|
|
151
|
-
// Delete frees every chunk, and a worker that refuses RAISES rather than
|
|
152
|
-
// reporting freed space the operator is still billed for.
|
|
153
|
-
if (await deleteResource({ workerUrl: "http://stub", uploadToken: "t", resourceId: rid, chunks: packed.chunks }) !== packed.chunks) throw new Error("deleteResource miscounted");
|
|
154
|
-
if (r2.size !== 0) throw new Error(`delete left ${r2.size} chunk(s) behind`);
|
|
155
|
-
globalThis.fetch = async () => ({ ok: false, status: 401, statusText: "Unauthorized" });
|
|
156
|
-
let quiet = false;
|
|
157
|
-
try { await deleteResource({ workerUrl: "http://stub", resourceId: rid, chunks: 2 }); quiet = true; } catch { /* expected */ }
|
|
158
|
-
if (quiet) throw new Error("a refused delete was swallowed — the ledger would free bytes still in R2");
|
|
159
|
-
|
|
160
|
-
console.log(`settle.js self-check ok — round trip, hash, ragged tail, AAD index binding, gzip ${stored}/${text.length} bytes, delete`);
|
|
161
|
-
} finally {
|
|
162
|
-
globalThis.fetch = realFetch;
|
|
163
|
-
rmSync(tmp, { force: true });
|
|
164
|
-
}
|
|
165
|
-
}
|