@fangorn-network/westmarch 0.0.19-dev → 2026.10.2-0.0-dev
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -3
- package/docs/app-to-agent.md +100 -27
- package/package.json +9 -5
- package/plugin/scripts/fx.mjs +7 -9
- package/site/dist/assets/AccountNotFoundScreen-C4njXc69-RUyAWRzV.js +1 -0
- package/site/dist/assets/AddFundsSelectionScreen-RAoCn7ej-ZV-LlYBe.js +31 -0
- package/site/dist/assets/Address-H8kD1d9O-CGQnt7Pu.js +17 -0
- package/site/dist/assets/AffirmativeConsentScreen-BG0MJxku-CKn2JLwq.js +6 -0
- package/site/dist/assets/AllowlistRejectionScreen-Cae6e1Od-9oIP9fma.js +1 -0
- package/site/dist/assets/ArrowsRightLeftIcon-BEhBD_6N.js +1 -0
- package/site/dist/assets/AuthenticateWithWalletScreen-CU6hIcFT-D1wLlSJs.js +1 -0
- package/site/dist/assets/AwaitingEvmToSolBridgingScreen-D0e_sZMS-CSBbHTyz.js +1 -0
- package/site/dist/assets/AwaitingExternalEthereumTransferScreen-ur5HL4R7-BsRq-xBt.js +1 -0
- package/site/dist/assets/AwaitingPasswordlessCodeScreen-DRHz76mM-BPdhsKvN.js +103 -0
- package/site/dist/assets/AwaitingSolToEvmBridgingScreen-CdLRrGD2-CEGNdrkr.js +1 -0
- package/site/dist/assets/BridgeNetworkSelectionView-CFGjB2nO-Da9P7eSx.js +68 -0
- package/site/dist/assets/CaptchaScreen-DbpvkIGx-BecgMnD_.js +1 -0
- package/site/dist/assets/CheckCircleIcon-DBiWFjO6.js +1 -0
- package/site/dist/assets/CheckCircleIcon-DzG2ROJZ.js +1 -0
- package/site/dist/assets/Checkbox-D1EDeo41-DMHcj9o_.js +52 -0
- package/site/dist/assets/ChevronDownIcon-2Os56gUt.js +1 -0
- package/site/dist/assets/Chip-CZKIKt9K-BWzs9fj5.js +26 -0
- package/site/dist/assets/CoinbaseOnrampStatusScreen-BbyCJDXL-CFvcSiDs.js +16 -0
- package/site/dist/assets/ConnectEmailForm-B-VRE0MN-BozkCg8q.js +3 -0
- package/site/dist/assets/ConnectLedgerScreen-DWHABGot-DaCnbBzh.js +10 -0
- package/site/dist/assets/ConnectOnlyLandingScreen-CZYx9Bmp-DUkCLkxD.js +1 -0
- package/site/dist/assets/ConnectOnlyStatusScreen-DCRzjxHx-Dv_5nMkZ.js +1 -0
- package/site/dist/assets/ConnectOrCreateScreen-CUUYUO07-DSGEeB3Y.js +1 -0
- package/site/dist/assets/ConnectPhoneForm-Dek5xn4C-C-s4s_Lq.js +95 -0
- package/site/dist/assets/ConnectWalletView-DqI-PTvX-BKX7fdYr.js +74 -0
- package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-DSoAuMFZ.js +7 -0
- package/site/dist/assets/CopyToClipboard-i_OQSBJr-CZTXyfV0.js +39 -0
- package/site/dist/assets/CopyableText-CQapvaMr-DHO818I0.js +28 -0
- package/site/dist/assets/CrossAppAuthScreen-CLw7ymZq-DW4nRGfz.js +1 -0
- package/site/dist/assets/CustomLandingScreenView-Cm_MBSyX-DH8Nnb4Y.js +22 -0
- package/site/dist/assets/DelegatedActionsConsentScreen-DYF2U4y5-gfUS_uV5.js +1 -0
- package/site/dist/assets/DelegatedActionsRevokeScreen-bPp6Uwyh-DZj9HTHc.js +1 -0
- package/site/dist/assets/DepositAddressAddressStepView-4vdkb55L-eHYsDK9W.js +187 -0
- package/site/dist/assets/DepositAddressScreen-DBLRs7aI-DK_XVgVk.js +8 -0
- package/site/dist/assets/DepositAddressV3Screen-CDqIEMQw-6gRZzhLe.js +1 -0
- package/site/dist/assets/{EmailInputForm-Cqo1mda8-B2NG3K5V.js → EmailInputForm-Cqo1mda8-CZD4r5LM.js} +11 -11
- package/site/dist/assets/EmbeddedWalletConnectingScreen-D4T7DUzs-BZu2ae0k.js +1 -0
- package/site/dist/assets/EmbeddedWalletCreatedScreen-D7WhW5ve-86pviemJ.js +1 -0
- package/site/dist/assets/EmbeddedWalletKeyExportScreen-CqV4NYQ3-vDcvT53Y.js +23 -0
- package/site/dist/assets/EmbeddedWalletOnAccountCreateScreen-BoKb3Q2S-rNJAtSJc.js +1 -0
- package/site/dist/assets/EmbeddedWalletPasswordUpdateScreen-D3rMlqS7-I8Q95280.js +1 -0
- package/site/dist/assets/EmbeddedWalletPasswordUpdateSplashScreen-BPFkWJeE-Coi7OxoI.js +1 -0
- package/site/dist/assets/EnrollTotp-Dibew4dp-DC7FrDgo.js +66 -0
- package/site/dist/assets/EnvelopeIcon-DY6ERnW7.js +1 -0
- package/site/dist/assets/ErrorBanner-BcpGRt0h-BvESwN99.js +21 -0
- package/site/dist/assets/{ErrorMessage-D8VaAP5m-CrZOnUyg.js → ErrorMessage-D8VaAP5m-oSruKN8L.js} +2 -2
- package/site/dist/assets/ErrorScreen-DipdTWzE-DnKGxH1Z.js +4 -0
- package/site/dist/assets/ExclamationCircleIcon-BZhlqH0r.js +1 -0
- package/site/dist/assets/ExclamationTriangleIcon-CkAOJIYV.js +1 -0
- package/site/dist/assets/FarcasterConnectStatusScreen-51tjUxqq-4pi7jooW.js +75 -0
- package/site/dist/assets/FarcasterSignerStatusScreen-6x-Uh95G-z2XCMaLL.js +28 -0
- package/site/dist/assets/FiatOnrampScreen-BAhYeiTI-CBVA9v1-.js +491 -0
- package/site/dist/assets/FingerPrintIcon-ra2dqmJO.js +1 -0
- package/site/dist/assets/FundSolWalletWithExternalSolanaWallet-WtLwYaOl-DwAwc6Ny.js +1 -0
- package/site/dist/assets/FundWalletMethodHeader-BWNkokCT-CZszQsZf.js +1 -0
- package/site/dist/assets/FundWithBankDepositScreen-DajkHxBD-DfX6nvFQ.js +58 -0
- package/site/dist/assets/FundingEditAmountScreen-CpvpiO4M-CDS_sk_t.js +1 -0
- package/site/dist/assets/FundingMethodSelectionScreen-Db7vhRlE-CPfNQemT.js +1 -0
- package/site/dist/assets/GlobeAltIcon-SEUEIe_E.js +1 -0
- package/site/dist/assets/GooglePay-B53WnudL-aap7zwag.js +1 -0
- package/site/dist/assets/HCaptchaWrapper-CUi9LJsp-DgSjCjQI.js +4 -0
- package/site/dist/assets/InAppBrowserLoginNotPossible-BMR9br1T-DO4wICml.js +1 -0
- package/site/dist/assets/InfoBanner-Cb3p1z12-CDWt2ADo.js +22 -0
- package/site/dist/assets/InjectedWalletIcon-DLcYOGDj-Ba19XoBr.js +1 -0
- package/site/dist/assets/InstallWalletScreen-DTA8dwLv-DGpewEch.js +1 -0
- package/site/dist/assets/{JsonTree-BHzNC-ic-DcNcbSoM.js → JsonTree-BHzNC-ic-pAEq1bl9.js} +3 -3
- package/site/dist/assets/{LabelXs-oqZNqbm_-iafrj25N.js → LabelXs-oqZNqbm_-D09YjVR4.js} +2 -2
- package/site/dist/assets/LandingScreen-CGWUoSUG-CUOCWUXd.js +1 -0
- package/site/dist/assets/{Layouts-BMRfo5hw-CeCOyCLK.js → Layouts-BMRfo5hw-D2u1-w8g.js} +16 -16
- package/site/dist/assets/Link-BdDilT2T-BYiP1zvW.js +40 -0
- package/site/dist/assets/LinkConflictScreen-C3ZEPsgl-Tb6cAepT.js +77 -0
- package/site/dist/assets/LinkEmailScreen-dKo9frwc-pq0NF2JO.js +1 -0
- package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-D9MOmDqg.js +117 -0
- package/site/dist/assets/LinkPhoneScreen-oIUpfj0w-B80UJqAZ.js +1 -0
- package/site/dist/assets/{LoadingSkeleton-BMsgO5PV-CiEyS5PZ.js → LoadingSkeleton-BMsgO5PV-BRMh4Fv4.js} +6 -6
- package/site/dist/assets/LockClosedIcon-BqkoEL9J.js +1 -0
- package/site/dist/assets/LoginFailedScreen-CN0dJV6U-DlnOM-Kh.js +1 -0
- package/site/dist/assets/ManualTransferScreen-CHqcuqbs-DSShupq9.js +1 -0
- package/site/dist/assets/MfaAuthEnrollmentFlowScreen-Dj7gPTRC-DUPV_SLA.js +1 -0
- package/site/dist/assets/MfaAuthVerifyFlowScreen-DbFpyWMy-D96GpzXX.js +1 -0
- package/site/dist/assets/MfaEnrollmentFlowScreen-DhLnGgnr-CYQDa4ND.js +1 -0
- package/site/dist/assets/MfaVerifyFlowScreen-C_XPjMRP-CJtSAXGN.js +1 -0
- package/site/dist/assets/ModalFooter-BCuEK_nz-D2I8KWtk.js +403 -0
- package/site/dist/assets/MoonpayStatusScreen-CzTUtokc-Bx5aHy-z.js +16 -0
- package/site/dist/assets/OAuthStatusScreen-ufbOa-da-CS6988X2.js +1 -0
- package/site/dist/assets/OpenLink-CUpJ1mOr-EZWVSX2r.js +39 -0
- package/site/dist/assets/PasskeySelectSignupOrLogin-xh2ScC_l-BY4eK5Jh.js +1 -0
- package/site/dist/assets/PasskeyStatusScreen-Bla8MaOk-LXys76u9.js +6 -0
- package/site/dist/assets/PasswordRecoveryScreen-awGXZkQk-RczvLvmo.js +20 -0
- package/site/dist/assets/{PhArrowCircleDown-D97G-BOA.js → PhArrowCircleDown-BtlNV0TZ.js} +5 -5
- package/site/dist/assets/PhArrowClockwise-mOiWYLMV.js +14 -0
- package/site/dist/assets/PhArrowDown-CkoOD89h.js +14 -0
- package/site/dist/assets/PhArrowLeft-C0jlxVhM.js +14 -0
- package/site/dist/assets/PhArrowRight-BI-V03Xf.js +14 -0
- package/site/dist/assets/{PhArrowSquareOut-Bk2CMG3I.js → PhArrowSquareOut-DnQ7n_B4.js} +5 -5
- package/site/dist/assets/PhArrowUp-izKvURUW.js +14 -0
- package/site/dist/assets/PhArrowUpRight-Bn-JhHsY.js +14 -0
- package/site/dist/assets/{PhArrowsClockwise-BXRn1GEl.js → PhArrowsClockwise-Brtx2Re-.js} +5 -5
- package/site/dist/assets/{PhArrowsDownUp-DM09Jo_3.js → PhArrowsDownUp-PZosTqZG.js} +5 -5
- package/site/dist/assets/PhArrowsLeftRight-CYsRQ2qh.js +14 -0
- package/site/dist/assets/{PhBank-fHbgCqqZ.js → PhBank-hhPAIPVb.js} +5 -5
- package/site/dist/assets/PhBrowser-BjzAmrHO.js +14 -0
- package/site/dist/assets/PhCaretDown-ddSjwcwm.js +14 -0
- package/site/dist/assets/PhCaretLeft-B7YLoNEF.js +14 -0
- package/site/dist/assets/PhCaretRight-BY8D5MIg.js +14 -0
- package/site/dist/assets/PhCaretUp-BG10nSut.js +14 -0
- package/site/dist/assets/PhCheck-DrKd7pBC.js +14 -0
- package/site/dist/assets/{PhCircleHalf-MJZeRBGF.js → PhCircleHalf-Bk9C4DvT.js} +5 -5
- package/site/dist/assets/PhClock-Sj17weCB.js +14 -0
- package/site/dist/assets/{PhCompass-hYn3HhGN.js → PhCompass-Df1ugFO-.js} +5 -5
- package/site/dist/assets/PhCopy-rgttky8E.js +14 -0
- package/site/dist/assets/{PhCreditCard-Fy4pzwtt.js → PhCreditCard-CZpdid2n.js} +5 -5
- package/site/dist/assets/{PhCurrencyDollar-BgiaenCi.js → PhCurrencyDollar-B6IKKjue.js} +5 -5
- package/site/dist/assets/{PhDesktop-CxrzCSv5.js → PhDesktop-BuCDXYJj.js} +5 -5
- package/site/dist/assets/PhDeviceMobile-CnybhXY-.js +14 -0
- package/site/dist/assets/PhDotsThree-CSAEcba1.js +14 -0
- package/site/dist/assets/PhEnvelope-SmaNeXoQ.js +14 -0
- package/site/dist/assets/PhFunnelSimple-DKx35ITq.js +14 -0
- package/site/dist/assets/{PhGlobe-DvmSc9_A.js → PhGlobe-q1mqj65V.js} +5 -5
- package/site/dist/assets/{PhIdentificationCard-CfkZm-5K.js → PhIdentificationCard-BeLXJpfZ.js} +5 -5
- package/site/dist/assets/{PhImage-Cf0J2ZfJ.js → PhImage-BYrKfN9k.js} +5 -5
- package/site/dist/assets/{PhInfo-Bwi51-2X.js → PhInfo-X33f06Ej.js} +5 -5
- package/site/dist/assets/{PhLightbulb-C4FZV7Es.js → PhLightbulb-DMZJsowR.js} +5 -5
- package/site/dist/assets/PhMagnifyingGlass-B6D0sWFL.js +14 -0
- package/site/dist/assets/{PhPaperPlaneRight-zxQVvPLX.js → PhPaperPlaneRight-Dvo-nXr9.js} +5 -5
- package/site/dist/assets/PhPlus-CBvZvLax.js +14 -0
- package/site/dist/assets/{PhPower-CFyWDmgD.js → PhPower-D8-AcNM6.js} +5 -5
- package/site/dist/assets/{PhPuzzlePiece-BjoNVfST.js → PhPuzzlePiece-C-7mYqGO.js} +5 -5
- package/site/dist/assets/{PhQrCode-CP3tFauY.js → PhQrCode-uIXlI5ER.js} +5 -5
- package/site/dist/assets/{PhQuestion-wOWJBd3G.js → PhQuestion-rUoqC2sC.js} +5 -5
- package/site/dist/assets/{PhQuestionMark-CV0k9C0Y.js → PhQuestionMark-W55Txvvb.js} +5 -5
- package/site/dist/assets/{PhSealCheck-vIKzREuN.js → PhSealCheck-BeVLq9PH.js} +5 -5
- package/site/dist/assets/{PhSignOut-CxELV-i0.js → PhSignOut-Cq2PivQ6.js} +5 -5
- package/site/dist/assets/{PhSpinner-CGDmbzUd.js → PhSpinner-CZMtAFdX.js} +5 -5
- package/site/dist/assets/{PhTrash-C9PD0SAt.js → PhTrash-BamrmMsN.js} +5 -5
- package/site/dist/assets/{PhUser-0sWNXQeZ.js → PhUser-A2fxqIV0.js} +5 -5
- package/site/dist/assets/{PhVault-6JTskUcC.js → PhVault-B8m1usHw.js} +5 -5
- package/site/dist/assets/{PhWarning-CoKs3gz6.js → PhWarning-CpkID9oi.js} +5 -5
- package/site/dist/assets/PhWarningCircle-Cm58gXb9.js +14 -0
- package/site/dist/assets/PhX-C3b4cCEy.js +14 -0
- package/site/dist/assets/PhoneIcon-CzbssTb8.js +1 -0
- package/site/dist/assets/PinInput-DbZ0b1i1-1DtLWL81.js +247 -0
- package/site/dist/assets/QrCode-DbnZwlkH-ChwcUk_h.js +22 -0
- package/site/dist/assets/RecoveryOAuthStatusScreen-CsgtTI2x-C79jd345.js +1 -0
- package/site/dist/assets/RecoveryPasswordCreateScreen-Be-qJ-LU-C9c0x-yq.js +1 -0
- package/site/dist/assets/RecoverySelectionScreen-D1iGtpmi-PNqHb6CI.js +7 -0
- package/site/dist/assets/{Screen-D30meWsY-CCeVNuWs.js → Screen-D30meWsY-DDum2qlY.js} +22 -22
- package/site/dist/assets/{ScreenHeader-CHmc4-Lu-DjyrH7IK.js → ScreenHeader-CHmc4-Lu-BqrAEXbV.js} +4 -4
- package/site/dist/assets/ScreenLayout-OwaQQcxH-B4Z8FjFp.js +1 -0
- package/site/dist/assets/{SelectSourceAsset-CWFog6gm-RKjBsB6m.js → SelectSourceAsset-CWFog6gm-8iXuqbAs.js} +18 -18
- package/site/dist/assets/SetAutomaticRecoveryScreen-BO_OEqAZ-CUpQZ9wq.js +14 -0
- package/site/dist/assets/SetWalletPasswordForm-DwCTVtAh-ZzvPLj2s.js +15 -0
- package/site/dist/assets/ShieldCheckIcon-Bjwe_-PV.js +1 -0
- package/site/dist/assets/SignRequestScreen-BHKv32KR-0qGeNipB.js +26 -0
- package/site/dist/assets/{StackedContainer-B2vaEl56-eQCM2cmv.js → StackedContainer-B2vaEl56-C-ojzCoQ.js} +2 -2
- package/site/dist/assets/StandardSignAndSendTransactionScreen-CfhIXVtd-C3lgJb68.js +20 -0
- package/site/dist/assets/{Subtitle-CV-2yKE4-zxWw2m1Q.js → Subtitle-CV-2yKE4-o-1FQLlX.js} +2 -2
- package/site/dist/assets/TelegramAuthScreen-UL9zLfO8-l35_C2DG.js +1 -0
- package/site/dist/assets/{Title-BnzYV3Is-B_JpTatT.js → Title-BnzYV3Is-RX1f0RV-.js} +2 -2
- package/site/dist/assets/TodoList-DnyULl18-JxWWU9KA.js +36 -0
- package/site/dist/assets/TransactionDetails-e9nesl30-C91nJPM9.js +109 -0
- package/site/dist/assets/TransactionErrorView-BDBNqA_f-Cpm-4xzm.js +178 -0
- package/site/dist/assets/TransferFromWalletScreen-Qvn1Yuno-BWCH7-Si.js +31 -0
- package/site/dist/assets/TransferOrBridgeLoadingScreen-Dl1I_iIz-BWMeJabk.js +6 -0
- package/site/dist/assets/TurnstileWrapper-B7sNddys-Dgr80Gih.js +1 -0
- package/site/dist/assets/UpdateEmailScreen-DVOhPV0H-Clk4zk-8.js +1 -0
- package/site/dist/assets/UpdatePhoneScreen-CXRswTNZ-BgRsoR3B.js +1 -0
- package/site/dist/assets/UserLimitReachedScreen-5we2DHn8-D-SU-vAz.js +1 -0
- package/site/dist/assets/{Value-DTgR824E-BRuIGiec.js → Value-DTgR824E-DZpvBCWi.js} +7 -7
- package/site/dist/assets/WalletCards-DH1rqayz-UuZ4i_Ze.js +1 -0
- package/site/dist/assets/WalletIcon-B1i03Vqc.js +1 -0
- package/site/dist/assets/WalletInfoCard-sq_2wgFg-TXTxmb8L.js +29 -0
- package/site/dist/assets/WalletInterstitialScreen-Sh7LfsAh-CbrFb0ON.js +1 -0
- package/site/dist/assets/WalletLink-DK5LB5Ha-BYQZV7UV.js +20 -0
- package/site/dist/assets/WalletOverflowButton-bfCnp-9T-CNgSPnTS.js +1 -0
- package/site/dist/assets/WarningBanner-ZZqCEtZK-DNZUUOph.js +21 -0
- package/site/dist/assets/__vite-browser-external-BIHI7g3E.js +1 -0
- package/site/dist/assets/analytics-mkkvFRju-DOXuftJB.js +1 -0
- package/site/dist/assets/basic-C9wn6QoQ.js +1575 -0
- package/site/dist/assets/bytes-CjWw8TJh.js +1 -0
- package/site/dist/assets/capitalizeFirstLetter-DmLYqXsO-tV1Idewc.js +1 -0
- package/site/dist/assets/ccip-BhHEqVIW.js +1 -0
- package/site/dist/assets/check-C_DTyjLS.js +1 -0
- package/site/dist/assets/chevron-down-iklXXH-z.js +1 -0
- package/site/dist/assets/circle-alert-KEOUF48T.js +1 -0
- package/site/dist/assets/circle-check-big-BJ_ADwB4.js +1 -0
- package/site/dist/assets/circle-x-BSfWmhYk.js +1 -0
- package/site/dist/assets/client-BnDcP42J.js +9 -0
- package/site/dist/assets/client-DH86IrJA.js +125 -0
- package/site/dist/assets/coinbase-DCPC2L_R-2ivYfoMv.js +3 -0
- package/site/dist/assets/copy-sK00DOfH.js +1 -0
- package/site/dist/assets/core-CRE213RM.js +211 -0
- package/site/dist/assets/createLucideIcon-D9OK_uxG.js +1 -0
- package/site/dist/assets/custom-V1wex-Di.js +1 -0
- package/site/dist/assets/dijkstra-COg3n3zL.js +1 -0
- package/site/dist/assets/embed.worker-BRIYO7m8.js +1 -0
- package/site/dist/assets/encodePacked-DyXYq3Cc.js +1 -0
- package/site/dist/assets/ethers-zTjbodk5-DSYOi6tU.js +1 -0
- package/site/dist/assets/external-link-Cdp8NBio.js +1 -0
- package/site/dist/assets/fallback-DiFue5Zm.js +1 -0
- package/site/dist/assets/farcaster-DPlSjvF5-DP2DLoHZ.js +1 -0
- package/site/dist/assets/features-B6BTj_BL.js +5 -0
- package/site/dist/assets/fingerprint-pattern-gFJTz5e4.js +1 -0
- package/site/dist/assets/floating-ui.react-D9ndYqYK.js +1 -0
- package/site/dist/assets/floating-ui.react-dom-CNbOgOFt.js +1 -0
- package/site/dist/assets/formatErc20TokenAmount-BuPk9xcy-CkAr4Oc0.js +1 -0
- package/site/dist/assets/getChainName-DjpPdUSc-c2urPd0g.js +1 -0
- package/site/dist/assets/getErc20Balance-jXNpFf0N-mFQ9Iqk-.js +1 -0
- package/site/dist/assets/getErc20TokenInfo-BNTrzLMP-Dx5he_uG.js +1 -0
- package/site/dist/assets/getFormattedUsdFromLamports-De3U9GlO-C446pzMl.js +1 -0
- package/site/dist/assets/getTransactionCount-80UHlwAV.js +1 -0
- package/site/dist/assets/getUsdcMintAddress-BVgm9GRo-FDalV59C.js +1 -0
- package/site/dist/assets/hashTypedData-Beq57Ogb.js +22 -0
- package/site/dist/assets/hooks.module-ClpaQ1Tg.js +1 -0
- package/site/dist/assets/hourglass-CB7z_I9H.js +1 -0
- package/site/dist/assets/http-BocEfKYb.js +19 -0
- package/site/dist/assets/index-0knDOgU9.js +1 -0
- package/site/dist/assets/index-9jNeS_nC.js +1 -0
- package/site/dist/assets/index-B--T-Fmt.js +16 -0
- package/site/dist/assets/index-BDkarAkX.js +2 -0
- package/site/dist/assets/index-BMfMy017.js +679 -0
- package/site/dist/assets/index-BOd8jv8-.js +1 -0
- package/site/dist/assets/index-BdEw5wyl-2VGMzHIs.js +1 -0
- package/site/dist/assets/index-C8ThRelw.js +9 -0
- package/site/dist/assets/{index-CWARkn2w-Cezl_uBr.js → index-CWARkn2w-D6ikWJWj.js} +7 -7
- package/site/dist/assets/{wui-ux-by-reown-fVu0QkI4.js → index-CztIxJB6.js} +296 -296
- package/site/dist/assets/index-D4LdLFDC.js +1 -0
- package/site/dist/assets/index-D6T-s6sR.js +1 -0
- package/site/dist/assets/index-D7396TWe.js +1 -0
- package/site/dist/assets/index-DdxtHe81.js +2 -0
- package/site/dist/assets/index-DvMddJcd-D7AEQrzj.js +12 -0
- package/site/dist/assets/index-nibyPLVP.js +1 -0
- package/site/dist/assets/index.browser-B6Bt5URJ.js +1 -0
- package/site/dist/assets/isPaymentRequestAvailable-Bq1cemEn-D7xtzRqA.js +1 -0
- package/site/dist/assets/landmark-CMLKifhk.js +1 -0
- package/site/dist/assets/lock-BkyjNE8h.js +1 -0
- package/site/dist/assets/mail-B6-Tq9Ld.js +1 -0
- package/site/dist/assets/native-CJ5et6AR.js +1 -0
- package/site/dist/assets/nonceManager-zkW7cM66.js +1 -0
- package/site/dist/assets/parseEther-C7aOvuze.js +1 -0
- package/site/dist/assets/parseSignature-BIjcuWdB.js +1 -0
- package/site/dist/assets/preload-helper-PPVm8Dsz.js +1 -0
- package/site/dist/assets/privateKeyToAccount-CRvvpHWf.js +1 -0
- package/site/dist/assets/property-CnFDNXw5.js +3 -0
- package/site/dist/assets/react-auth_false-DedQs79w.js +1 -0
- package/site/dist/assets/reservoir-x-nGuZkT-DFxAFt2v.js +1 -0
- package/site/dist/assets/roles-DV_6FRBZ.js +1 -0
- package/site/dist/assets/safe-url-D7SRPu33-A8zMgOTd.js +1 -0
- package/site/dist/assets/serializeErc6492Signature-CeJeL3h6.js +1 -0
- package/site/dist/assets/serializeTransaction-L-_Ej-jW.js +8 -0
- package/site/dist/assets/{shared-DRZUmnL5-xqAUARWo.js → shared-DRZUmnL5-MWD-C-pp.js} +33 -33
- package/site/dist/assets/{shared-FM0rljBt--Avg6q2R.js → shared-FM0rljBt-c4eSjzGj.js} +6 -6
- package/site/dist/assets/shouldProceedtoEmbeddedWalletCreationFlow-B3vyavrh-CF2QteTJ.js +1 -0
- package/site/dist/assets/simulateTransaction-CfuOrae4-BHUMPf6Q.js +1 -0
- package/site/dist/assets/smartphone-DAN5rY0T.js +1 -0
- package/site/dist/assets/stripe.esm-Dv8C3q95.js +2 -0
- package/site/dist/assets/styles-BsotlekN-Cjuu2SDV.js +9 -0
- package/site/dist/assets/{styles-Cm9H63WO-D90SsXOs.js → styles-Cm9H63WO-Cv1TbqYi.js} +17 -17
- package/site/dist/assets/{styles-DVyDvTdj-BTABn2K8.js → styles-DVyDvTdj-CI4xZNHp.js} +8 -8
- package/site/dist/assets/{styles-hslXy6xG-D-49b1rk.js → styles-hslXy6xG-DeVcFoDD.js} +23 -23
- package/site/dist/assets/telegram-B-JqnkqZ-DTjJLkIF.js +1 -0
- package/site/dist/assets/to-ui-error-DWe-qwS3-Dx3yzcV0.js +4 -0
- package/site/dist/assets/toAccount-Bq6rbpbI.js +1 -0
- package/site/dist/assets/transaction-BNTP-bFm-CrebgH-D.js +1 -0
- package/site/dist/assets/transactionReceipt-BwJl-gjg.js +1 -0
- package/site/dist/assets/transfer-6YztDh-t-DU6hH7CZ.js +1 -0
- package/site/dist/assets/transformers.web-BEKVh7pD.js +40 -0
- package/site/dist/assets/transformers.web-aWa49tv1.js +40 -0
- package/site/dist/assets/triangle-alert-ndoiBs4y.js +1 -0
- package/site/dist/assets/twitch-5IOe4sIQ-BXviIywg.js +1 -0
- package/site/dist/assets/useGetSolPrice-x7gfUIHJ-C7axYJ--.js +1 -0
- package/site/dist/assets/useGetTokenPrice-CaoUkb79-CR4CrguU.js +1 -0
- package/site/dist/assets/useI18n-C-5n_noF-C_t8QqBJ.js +1 -0
- package/site/dist/assets/useWalletBalance-CZnP5f_f-BnSHLVI_.js +1 -0
- package/site/dist/assets/w3m-modal-Bz5KWTQ-.js +1174 -0
- package/site/dist/assets/wallet-DTM31trz.js +2 -0
- package/site/dist/assets/wallet-UESEqPei.js +1 -0
- package/site/dist/assets/wallet-connect-BvJtUsDt-CnvUnFbz.js +1 -0
- package/site/dist/assets/walletconnect-v2-3frQFwbg-CzQk99gS.js +15 -0
- package/site/dist/assets/x-B2_XdOVQ.js +1 -0
- package/site/dist/index.html +120 -8
- package/site/feed.js +16 -1
- package/site/no-model.js +4 -0
- package/site/worker.js +597 -58
- package/src/agent/agent-card.js +20 -11
- package/src/agent/mcp.js +150 -316
- package/src/agent/view-tools.js +53 -12
- package/src/agent/x402.js +379 -44
- package/src/core/embed.js +51 -52
- package/src/core/embed.worker.js +1 -1
- package/src/core/shard.js +7 -3
- package/src/discover/apps.js +4 -3
- package/src/discover/explore.js +36 -22
- package/src/market/reactions.js +2 -2
- package/src/publish/devnet.js +95 -0
- package/src/publish/lint.js +2 -1
- package/src/publish/ship.js +517 -236
- package/src/publish/view-cli.js +11 -10
- package/src/publish/view.js +359 -206
- package/src/taste/taste-doc.js +3 -2
- package/src/taste/taste.js +2 -2
- package/src/taste/vault.js +3 -1
- package/site/dist/assets/AccountNotFoundScreen-C4njXc69-BOfmiSH1.js +0 -1
- package/site/dist/assets/AddFundsSelectionScreen-RAoCn7ej-B6uvYyqa.js +0 -31
- package/site/dist/assets/Address-H8kD1d9O-DcHv7A8C.js +0 -17
- package/site/dist/assets/AffirmativeConsentScreen-BG0MJxku-v2wz-N-s.js +0 -6
- package/site/dist/assets/AllowlistRejectionScreen-Cae6e1Od-DhVy9iGN.js +0 -1
- package/site/dist/assets/ApiController-BbhXeqTV.js +0 -5
- package/site/dist/assets/ArrowsRightLeftIcon-cp60yobq.js +0 -1
- package/site/dist/assets/AuthenticateWithWalletScreen-CU6hIcFT-B0eT1zE6.js +0 -1
- package/site/dist/assets/AwaitingEvmToSolBridgingScreen-D0e_sZMS-DL5PH-v_.js +0 -1
- package/site/dist/assets/AwaitingExternalEthereumTransferScreen-ur5HL4R7-n1BsRPqc.js +0 -1
- package/site/dist/assets/AwaitingPasswordlessCodeScreen-DRHz76mM-BVl2BJDY.js +0 -103
- package/site/dist/assets/AwaitingSolToEvmBridgingScreen-CdLRrGD2-BD-OZUQb.js +0 -1
- package/site/dist/assets/BridgeNetworkSelectionView-CFGjB2nO-CaYrzRje.js +0 -68
- package/site/dist/assets/CaptchaScreen-DbpvkIGx-BQJ7inx1.js +0 -1
- package/site/dist/assets/CheckCircleIcon-BM409mGI.js +0 -1
- package/site/dist/assets/CheckCircleIcon-NCOQc0Gs.js +0 -1
- package/site/dist/assets/Checkbox-D1EDeo41-rHlvsZzP.js +0 -52
- package/site/dist/assets/ChevronDownIcon-CW-4MSpE.js +0 -1
- package/site/dist/assets/Chip-CZKIKt9K-CutJG010.js +0 -26
- package/site/dist/assets/CoinbaseOnrampStatusScreen-BbyCJDXL-DDaMC7cl.js +0 -16
- package/site/dist/assets/ConnectEmailForm-B-VRE0MN-DVSf4tFJ.js +0 -3
- package/site/dist/assets/ConnectLedgerScreen-DWHABGot-h0uYIUi6.js +0 -10
- package/site/dist/assets/ConnectOnlyLandingScreen-CZYx9Bmp-DP19hJq5.js +0 -1
- package/site/dist/assets/ConnectOnlyStatusScreen-DCRzjxHx-DHvijlTx.js +0 -1
- package/site/dist/assets/ConnectOrCreateScreen-CUUYUO07-ewmXYPTQ.js +0 -1
- package/site/dist/assets/ConnectPhoneForm-Dek5xn4C-DUYdmVtr.js +0 -95
- package/site/dist/assets/ConnectWalletView-DqI-PTvX-RobGErVW.js +0 -74
- package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-Bbiq3hY6.js +0 -1
- package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-DPkOGNWl.js +0 -7
- package/site/dist/assets/ConnectorUtil-BO1L6VvV.js +0 -21
- package/site/dist/assets/ConstantsUtil-DmLsRHAl.js +0 -198
- package/site/dist/assets/CopyToClipboard-i_OQSBJr-DujUHNzW.js +0 -39
- package/site/dist/assets/CopyableText-CQapvaMr-DMIdpDaU.js +0 -28
- package/site/dist/assets/CrossAppAuthScreen-CLw7ymZq-DbGy4QyA.js +0 -1
- package/site/dist/assets/CustomLandingScreenView-Cm_MBSyX-B3WqJZBh.js +0 -22
- package/site/dist/assets/DelegatedActionsConsentScreen-DYF2U4y5-CmUDoS0C.js +0 -1
- package/site/dist/assets/DelegatedActionsRevokeScreen-bPp6Uwyh-fcO51q5H.js +0 -1
- package/site/dist/assets/DepositAddressAddressStepView-4vdkb55L-ClAb_j1B.js +0 -187
- package/site/dist/assets/DepositAddressScreen-DBLRs7aI-CN1P_KY9.js +0 -8
- package/site/dist/assets/DepositAddressV3Screen-CDqIEMQw-BtDZmuEN.js +0 -1
- package/site/dist/assets/EmbeddedWalletConnectingScreen-D4T7DUzs-D3pExuaW.js +0 -1
- package/site/dist/assets/EmbeddedWalletCreatedScreen-D7WhW5ve-CLsJbPYQ.js +0 -1
- package/site/dist/assets/EmbeddedWalletKeyExportScreen-CqV4NYQ3-DI6bu-oi.js +0 -23
- package/site/dist/assets/EmbeddedWalletOnAccountCreateScreen-BoKb3Q2S-BQ9Ygr0P.js +0 -1
- package/site/dist/assets/EmbeddedWalletPasswordUpdateScreen-D3rMlqS7-CxrfLr5q.js +0 -1
- package/site/dist/assets/EmbeddedWalletPasswordUpdateSplashScreen-BPFkWJeE-DHZRGoTN.js +0 -1
- package/site/dist/assets/EnrollTotp-Dibew4dp-7gVtJ1Jt.js +0 -66
- package/site/dist/assets/EnvelopeIcon-Dh2vSVj4.js +0 -1
- package/site/dist/assets/ErrorBanner-BcpGRt0h-BKOYTyCi.js +0 -21
- package/site/dist/assets/ErrorScreen-DipdTWzE-BT8TtRTx.js +0 -4
- package/site/dist/assets/ErrorScreen-DipdTWzE-DAam41Xl.js +0 -1
- package/site/dist/assets/ExclamationCircleIcon-DUA2wMfO.js +0 -1
- package/site/dist/assets/ExclamationTriangleIcon-eZfaqcFq.js +0 -1
- package/site/dist/assets/FarcasterConnectStatusScreen-51tjUxqq-BPCBi37Q.js +0 -75
- package/site/dist/assets/FarcasterSignerStatusScreen-6x-Uh95G-XCmWpnUd.js +0 -28
- package/site/dist/assets/FiatOnrampScreen-BAhYeiTI-DJRcUh2N.js +0 -491
- package/site/dist/assets/FingerPrintIcon-Dm6kxmg7.js +0 -1
- package/site/dist/assets/FundSolWalletWithExternalSolanaWallet-WtLwYaOl-BfNVSTb1.js +0 -1
- package/site/dist/assets/FundWalletMethodHeader-BWNkokCT-BQdbJ5Bb.js +0 -1
- package/site/dist/assets/FundWithBankDepositScreen-DajkHxBD-BfvMcHb6.js +0 -58
- package/site/dist/assets/FundingEditAmountScreen-CpvpiO4M-VBfbahnA.js +0 -1
- package/site/dist/assets/FundingMethodSelectionScreen-Db7vhRlE-CMuBYf64.js +0 -1
- package/site/dist/assets/GlobeAltIcon-vqrVV5ho.js +0 -1
- package/site/dist/assets/GooglePay-B53WnudL-BX5_WtCx.js +0 -1
- package/site/dist/assets/HCaptchaWrapper-CUi9LJsp-D-I8j7NO.js +0 -4
- package/site/dist/assets/InAppBrowserLoginNotPossible-BMR9br1T-BY3j50El.js +0 -1
- package/site/dist/assets/InfoBanner-Cb3p1z12-DLBl_Ywy.js +0 -22
- package/site/dist/assets/InjectedWalletIcon-DLcYOGDj-DLSV_NjP.js +0 -1
- package/site/dist/assets/InstallWalletScreen-DTA8dwLv-CxreyXoD.js +0 -1
- package/site/dist/assets/LandingScreen-CGWUoSUG-Q7hgXKvM.js +0 -1
- package/site/dist/assets/Link-BdDilT2T-BEDEdHuS.js +0 -40
- package/site/dist/assets/LinkConflictScreen-C3ZEPsgl-DK1z_v7y.js +0 -77
- package/site/dist/assets/LinkEmailScreen-dKo9frwc-BYYpJ5-6.js +0 -1
- package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-uhub9C26.js +0 -1
- package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-uid22VTN.js +0 -117
- package/site/dist/assets/LinkPhoneScreen-oIUpfj0w-CVQibNi9.js +0 -1
- package/site/dist/assets/Loader-UAZqxsnw-Cy7hEE2f.js +0 -62
- package/site/dist/assets/LockClosedIcon-BgY_5v_Z.js +0 -1
- package/site/dist/assets/LoginFailedScreen-CN0dJV6U-DhUMiJZJ.js +0 -1
- package/site/dist/assets/ManualTransferScreen-CHqcuqbs-DMygAXMU.js +0 -1
- package/site/dist/assets/MfaAuthEnrollmentFlowScreen-Dj7gPTRC-_1GFUSIg.js +0 -1
- package/site/dist/assets/MfaAuthVerifyFlowScreen-DbFpyWMy-DLnBJ5b8.js +0 -1
- package/site/dist/assets/MfaEnrollmentFlowScreen-DhLnGgnr-BUJY1lzs.js +0 -1
- package/site/dist/assets/MfaVerifyFlowScreen-C_XPjMRP-25l5fVun.js +0 -1
- package/site/dist/assets/ModalFooter-BCuEK_nz-c-khvG4Y.js +0 -403
- package/site/dist/assets/MoonpayStatusScreen-CzTUtokc-BRFN2eXr.js +0 -16
- package/site/dist/assets/OAuthStatusScreen-ufbOa-da-DL30vu07.js +0 -1
- package/site/dist/assets/OpenLink-CUpJ1mOr-DfAvJRyK.js +0 -39
- package/site/dist/assets/PasskeySelectSignupOrLogin-xh2ScC_l-DtxhRQyw.js +0 -1
- package/site/dist/assets/PasskeyStatusScreen-Bla8MaOk-CNfu8ujT.js +0 -6
- package/site/dist/assets/PasswordRecoveryScreen-awGXZkQk-BR6z6xE8.js +0 -20
- 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/PhArrowUp-4sgyKPGx.js +0 -14
- package/site/dist/assets/PhArrowUpRight-BNghD2zq.js +0 -14
- package/site/dist/assets/PhArrowsLeftRight-MuKBLUoF.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/PhClock-x3MS3Mwi.js +0 -14
- package/site/dist/assets/PhCopy-CWNYcABI.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/PhMagnifyingGlass-C9u8jSCJ.js +0 -14
- package/site/dist/assets/PhPlus-C4UoW-2n.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-CvIiPwYQ.js +0 -1
- package/site/dist/assets/PinInput-DbZ0b1i1-CDXZBdQx.js +0 -247
- package/site/dist/assets/PrivyPluginContext-DA-yS5vO-CtQWBiV2.js +0 -1
- package/site/dist/assets/QrCode-DbnZwlkH-BymHrKY7.js +0 -22
- package/site/dist/assets/RecoveryOAuthStatusScreen-CsgtTI2x-Dro1btv5.js +0 -1
- package/site/dist/assets/RecoveryPasswordCreateScreen-Be-qJ-LU-C1q1hiaN.js +0 -1
- package/site/dist/assets/RecoverySelectionScreen-D1iGtpmi-C21D20gD.js +0 -7
- package/site/dist/assets/SIWXUtil-CHZVugix.js +0 -1
- package/site/dist/assets/ScreenLayout-OwaQQcxH-CrQM6kvA.js +0 -1
- package/site/dist/assets/SetAutomaticRecoveryScreen-BO_OEqAZ-BcWHJoEG.js +0 -14
- package/site/dist/assets/SetWalletPasswordForm-DwCTVtAh-kq1zvA7d.js +0 -11
- package/site/dist/assets/ShieldCheckIcon-o6RHYev1.js +0 -1
- package/site/dist/assets/SignRequestScreen-BHKv32KR-iQCaBkcz.js +0 -26
- package/site/dist/assets/SolanaWalletConnector-C7Lqk-Wz-BUdJJ0ep.js +0 -1
- package/site/dist/assets/StandardSignAndSendTransactionScreen-CfhIXVtd-nART-xUU.js +0 -20
- package/site/dist/assets/TelegramAuthScreen-UL9zLfO8-Dw9geyK3.js +0 -1
- package/site/dist/assets/TodoList-DnyULl18-C8Eyy28X.js +0 -36
- package/site/dist/assets/TransactionDetails-e9nesl30-DeEL1JQS.js +0 -109
- package/site/dist/assets/TransactionErrorView-BDBNqA_f-Dffuo7I4.js +0 -178
- package/site/dist/assets/TransferFromWalletScreen-Qvn1Yuno-CWLWUiHy.js +0 -31
- package/site/dist/assets/TransferOrBridgeLoadingScreen-Dl1I_iIz-Bo-tm6wr.js +0 -6
- package/site/dist/assets/TurnstileWrapper-B7sNddys-Jwy1tJtm.js +0 -1
- package/site/dist/assets/UpdateEmailScreen-DVOhPV0H-gFbSIUhh.js +0 -1
- package/site/dist/assets/UpdatePhoneScreen-CXRswTNZ-Coy4E1NQ.js +0 -1
- package/site/dist/assets/UserLimitReachedScreen-5we2DHn8-D7m70C4b.js +0 -1
- package/site/dist/assets/WalletCards-DH1rqayz-Bgp9Fsgs.js +0 -1
- package/site/dist/assets/WalletIcon-gKf0gTw6.js +0 -1
- package/site/dist/assets/WalletInfoCard-sq_2wgFg-ISBsQt8p.js +0 -29
- package/site/dist/assets/WalletInterstitialScreen-Sh7LfsAh-DG-RuO-F.js +0 -1
- package/site/dist/assets/WalletLink-DK5LB5Ha-CXBqCHf3.js +0 -20
- package/site/dist/assets/WalletOverflowButton-bfCnp-9T-DP0-PoZL.js +0 -1
- package/site/dist/assets/WarningBanner-ZZqCEtZK-2eU4Qo74.js +0 -21
- package/site/dist/assets/__vite-browser-external-CitKSmYk.js +0 -1
- package/site/dist/assets/_esm-CJe2F7LL.js +0 -7
- package/site/dist/assets/_esm-zhBBffjV.js +0 -1
- package/site/dist/assets/accounts-Bq8t1wAD.js +0 -1
- package/site/dist/assets/accounts-D96UKWkC.js +0 -1
- package/site/dist/assets/analytics-mkkvFRju-BRBcadka.js +0 -1
- package/site/dist/assets/baseSepolia-DX-qGsik.js +0 -1
- package/site/dist/assets/basic-MlZ7f4s9.js +0 -1575
- package/site/dist/assets/capitalizeFirstLetter-DmLYqXsO-DtOXx-2n.js +0 -1
- package/site/dist/assets/ccip-BI9LWBBg.js +0 -1
- package/site/dist/assets/ccip-C-59SNEF.js +0 -7
- package/site/dist/assets/ccip-y08wK9du.js +0 -1
- package/site/dist/assets/chain-DM3oH6Px.js +0 -8
- package/site/dist/assets/check-BPgcwEPP.js +0 -1
- package/site/dist/assets/chevron-down-BSsbXkK-.js +0 -1
- package/site/dist/assets/circle-alert-DWaeLZNj.js +0 -1
- package/site/dist/assets/circle-check-big-Chb1ivw9.js +0 -1
- package/site/dist/assets/circle-x-AV9Cet0R.js +0 -1
- package/site/dist/assets/client-D0IV9lV9.js +0 -2
- package/site/dist/assets/client-Dsa7_3V3.js +0 -9
- package/site/dist/assets/coinbase-DCPC2L_R-Rs9nVCfm.js +0 -3
- package/site/dist/assets/copy-Ckr0AkL6.js +0 -1
- package/site/dist/assets/core-zQ1tZtVZ.js +0 -12
- package/site/dist/assets/createLucideIcon-IPW50ckY.js +0 -1
- package/site/dist/assets/defineChain-CiuCXUZW.js +0 -1
- package/site/dist/assets/dijkstra-Drfl93V4.js +0 -1
- package/site/dist/assets/dist-BxQqwnue.js +0 -16
- package/site/dist/assets/dist-Cm7pNAtL.js +0 -1
- package/site/dist/assets/dist-CoS6E-3x.js +0 -1
- package/site/dist/assets/dist-Dl07uGq1.js +0 -1
- package/site/dist/assets/embed.worker-ugGhEqCV.js +0 -1
- package/site/dist/assets/errors-BQ3N-RVt-BLqjTPNR.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-DXsETz3H.js +0 -1
- package/site/dist/assets/esm-n2lWo7kz.js +0 -1
- package/site/dist/assets/esm-vs5jNx_Y.js +0 -37
- package/site/dist/assets/ethers-zTjbodk5-B7BBFFKf.js +0 -1
- package/site/dist/assets/eventemitter3-CL76jPsW.js +0 -1
- package/site/dist/assets/external-link-D-uehwM2.js +0 -1
- package/site/dist/assets/farcaster-DPlSjvF5-BqTvDXBR.js +0 -1
- package/site/dist/assets/features-CYXRa3_m.js +0 -2
- package/site/dist/assets/fingerprint-pattern-D8ytA16Q.js +0 -1
- package/site/dist/assets/floating-ui.react-dom-DKWOL9UG.js +0 -1
- package/site/dist/assets/floating-ui.react-xRkl9O3u.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-Dukf7_kJ.js +0 -1
- package/site/dist/assets/getChainName-DjpPdUSc-DUyKDrnp.js +0 -1
- package/site/dist/assets/getErc20Balance-jXNpFf0N-V2btxzrJ.js +0 -1
- package/site/dist/assets/getErc20TokenInfo-BNTrzLMP-CtCwQuGA.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-CHfXo8XI.js +0 -1
- package/site/dist/assets/hooks.module-BYZGfwDl.js +0 -1
- package/site/dist/assets/hourglass-CPG1HZmf.js +0 -1
- package/site/dist/assets/id-UqEwL2BI-CdKXapd-.js +0 -1
- package/site/dist/assets/index-BdEw5wyl-ChSJvPZk.js +0 -1
- package/site/dist/assets/index-CKdAF_dK.js +0 -8
- package/site/dist/assets/index-DvMddJcd-D-4mRLKK.js +0 -12
- package/site/dist/assets/index-YiCw0Y_x-BX1zsiqG.js +0 -437
- 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-BmqyoBEM.js +0 -2
- package/site/dist/assets/index.es-C1v1or--.js +0 -3
- package/site/dist/assets/isPaymentRequestAvailable-Bq1cemEn-By6r0dVB.js +0 -1
- package/site/dist/assets/jsx-runtime-BbDfbRii.js +0 -1
- package/site/dist/assets/landmark-CH6LV6F0.js +0 -1
- package/site/dist/assets/lib-BsS8z8Lj.js +0 -1
- package/site/dist/assets/localBatchGatewayRequest-5YxrERBj.js +0 -32
- package/site/dist/assets/lock-DcskI4Bb.js +0 -1
- package/site/dist/assets/logger-CsXm3oIv-B0UYpNFI.js +0 -1
- package/site/dist/assets/mail-Bs0r5yOi.js +0 -1
- package/site/dist/assets/modal-context-CwmSeFcv-DruX9J1E.js +0 -1
- package/site/dist/assets/native-BKj27wfc.js +0 -1
- package/site/dist/assets/ofetch.CWycOUEr-CHp-crOQ.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-CGP3gnf2.js +0 -1
- package/site/dist/assets/pkce-DXF0yKjP-Bqz4wAsq.js +0 -1
- package/site/dist/assets/preload-helper-BaNbYf_w.js +0 -1
- package/site/dist/assets/privy-context-81KmsBw2-CjWGzyg7.js +0 -2
- package/site/dist/assets/property-DuZ9DLP4.js +0 -3
- package/site/dist/assets/react-DCXkXSrv.js +0 -1
- package/site/dist/assets/react-DQnMl2Xv.js +0 -1
- package/site/dist/assets/react-DrJ0MmMO.js +0 -1
- package/site/dist/assets/react-auth-sHnipzbS.js +0 -1
- package/site/dist/assets/react-dom-5dW7aKoP.js +0 -1
- package/site/dist/assets/reservoir-x-nGuZkT-BMX127i6.js +0 -1
- package/site/dist/assets/roles-32M1l9jI.js +0 -1
- package/site/dist/assets/roles-DKPW79Ca.js +0 -1
- package/site/dist/assets/rolldown-runtime-BcKkbAw3.js +0 -1
- package/site/dist/assets/safe-url-D7SRPu33-CkMedGro.js +0 -1
- package/site/dist/assets/secp256k1-C4nzcPo-.js +0 -1
- package/site/dist/assets/secp256k1-D92aGNnU.js +0 -1
- package/site/dist/assets/secp256k1-DmbwyFau.js +0 -1
- package/site/dist/assets/secp256k1-_MleGpqL.js +0 -1
- package/site/dist/assets/secp256k1-xl2og-wO.js +0 -1
- package/site/dist/assets/serializeAuthorizationList-CX8hGL56.js +0 -1
- package/site/dist/assets/serializeSignature-DfxkPnu-.js +0 -2
- package/site/dist/assets/sha2-BU_QyRTx.js +0 -1
- package/site/dist/assets/shouldProceedtoEmbeddedWalletCreationFlow-B3vyavrh-ByFOTrQK.js +0 -1
- package/site/dist/assets/simulateTransaction-CfuOrae4-CMFGDgT_.js +0 -1
- package/site/dist/assets/smartphone-CcEZ-XAy.js +0 -1
- package/site/dist/assets/src-BBjkfi-Q.js +0 -1
- package/site/dist/assets/storage-Ufl800Ne-EalZTH9q.js +0 -9
- package/site/dist/assets/stringify-BlDm7tuc.js +0 -21
- package/site/dist/assets/stripe.esm-CZRDpc-N.js +0 -2
- package/site/dist/assets/styles-BsotlekN-CXEB4Ud9.js +0 -9
- package/site/dist/assets/telegram-B-JqnkqZ-RBoY3PLx.js +0 -1
- package/site/dist/assets/to-ui-error-DWe-qwS3-DgCO-Y70.js +0 -4
- package/site/dist/assets/toViemAccount-B5iDGq1b-DZ1MBqUW.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/transformers.web-D4RvOP4-.js +0 -40
- package/site/dist/assets/transformers.web-D8W1u_I2.js +0 -49
- package/site/dist/assets/triangle-alert-CWjYH75H.js +0 -1
- package/site/dist/assets/twitch-5IOe4sIQ-lDtgk0os.js +0 -1
- package/site/dist/assets/types-4CuOD23i.js +0 -1
- package/site/dist/assets/use-headless-crypto-deposit-Yn-QRLB3-Dn6_8w-Y.js +0 -1
- package/site/dist/assets/use-unlink-wallet-BKK4_5Ur-DgsQ75lh.js +0 -1
- package/site/dist/assets/useActiveWallet-B-yZYGc6-B6JWREbk.js +0 -123
- package/site/dist/assets/useGetSolPrice-x7gfUIHJ-D1hmQfpA.js +0 -1
- package/site/dist/assets/useGetTokenPrice-CaoUkb79-ZnbuJ-vP.js +0 -1
- package/site/dist/assets/useI18n-C-5n_noF-BcqC76yj.js +0 -1
- package/site/dist/assets/useWalletBalance-CZnP5f_f-L3V0jDjL.js +0 -1
- package/site/dist/assets/useWallets-X1ndvJ_U-CLwUcevw.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-BMubXAoG.js +0 -1174
- package/site/dist/assets/wallet-Bn85Sg2W.js +0 -1
- package/site/dist/assets/wallet-connect-BvJtUsDt-Y03hhqFN.js +0 -1
- package/site/dist/assets/wallet-uSKqQsgP.js +0 -2
- package/site/dist/assets/walletconnect-registry-xxG8XLCb-D1SSFvMp.js +0 -1
- package/site/dist/assets/walletconnect-v2-3frQFwbg-Dv6JY_ko.js +0 -12
- package/site/dist/assets/x-rlSp9U7W.js +0 -1
package/src/publish/view.js
CHANGED
|
@@ -1,43 +1,50 @@
|
|
|
1
|
-
// An app's
|
|
1
|
+
// An app's presented data → a view any Fangorn reader loads: the embedding lens
|
|
2
|
+
// (WHITEPAPER_1 §3.4), computed by whoever runs this.
|
|
2
3
|
//
|
|
3
|
-
// westmarch-view --app my-app --
|
|
4
|
+
// westmarch-view --app my-app [--repo catalog …] --out site/view (a laptop, CI)
|
|
5
|
+
// site/worker.js, on a cron (the free tier)
|
|
4
6
|
//
|
|
5
|
-
// Reads the
|
|
6
|
-
//
|
|
7
|
-
//
|
|
7
|
+
// Reads the registry and storage and nothing else: every repo the app presents (its
|
|
8
|
+
// members' repos, less its exclusions, `appRepos`), at their latest heads, and the app
|
|
9
|
+
// owner's schema (`fangorn.schema`, see below). Embeds only records the view does not hold
|
|
10
|
+
// yet, drops removed ones, and writes, through a store (a directory or an R2 bucket):
|
|
8
11
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
+
// cdn/catalog
|
|
13
|
+
// cdn/domains/<domain>/manifest
|
|
14
|
+
// cdn/domains/<domain>/shards/shard-NNNN-<sha12>.ndjson.gz
|
|
12
15
|
//
|
|
13
|
-
// Stateless: the view's own files are its state,
|
|
14
|
-
//
|
|
16
|
+
// Stateless: the view's own files are its state, and each domain's manifest names the head
|
|
17
|
+
// it was built from, so a run where no head moved reads one manifest per repo and nothing
|
|
18
|
+
// else. A repo the app stops presenting (an exclusion) loses its domain on the next run.
|
|
15
19
|
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
// - URL layout, domain names (`domainFor`, byte-identical to quickbeam's
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
// - a record is a vertex: track_id = its CID, fields = payload + entityType (its tag);
|
|
20
|
+
// The layout is quickbeam's (the hosted tier), so an app moves between the two by changing
|
|
21
|
+
// one URL in its card:
|
|
22
|
+
// - URL layout, domain names (`domainFor`, byte-identical to quickbeam's `_domain_for`),
|
|
23
|
+
// row shape {track_id, fields, v}, manifest and catalog keys;
|
|
24
|
+
// - a record is a row: track_id = its CID, fields = payload + entityType (its type);
|
|
22
25
|
// - the schema: a declared type is embedded and shipped with exactly its role map;
|
|
23
26
|
// - the embedded text (`composeText` mirrors quickbeam's `compose_document_text`).
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
+
// The encoder is EmbeddingGemma (embed.js). Two runtimes of it agree closely but not bit for
|
|
28
|
+
// bit, so the manifest names its `embedder` and this refuses to append to a view another
|
|
29
|
+
// encoder built.
|
|
27
30
|
//
|
|
28
|
-
// ponytail: flat records. quickbeam folds a record's
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
31
|
+
// ponytail: flat records. quickbeam folds a record's neighbours into its text and can fuse
|
|
32
|
+
// publishers by shared identity; that is the hosted tier's job. A reference the schema
|
|
33
|
+
// declares is written onto its source row instead (`linkRelations`), which is all a
|
|
34
|
+
// serverless reader needs.
|
|
32
35
|
|
|
33
36
|
import { gunzipSync, gzipSync } from "node:zlib";
|
|
34
37
|
import { createHash } from "node:crypto";
|
|
35
38
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
39
|
+
import { dirname } from "node:path";
|
|
36
40
|
import { EMBED_DIM, EMBED_DTYPE, EMBED_MODEL, embedDocumentDirect, packVec, unpackVec } from "../core/embed.js";
|
|
37
41
|
import { coverage as fitCoverage } from "../market/reactions.js";
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
/** The app owner's repo that declares the app's types: one TYPE_TAG record per type, one
|
|
44
|
+
* RELATION_TAG record per allowed reference between two of them. */
|
|
45
|
+
export const SCHEMA_REPO = "fangorn.schema";
|
|
40
46
|
export const TYPE_TAG = "fangorn.type.v1";
|
|
47
|
+
export const RELATION_TAG = "fangorn.relation.v1";
|
|
41
48
|
export const EMBEDDER = { runtime: "transformers.js", model: EMBED_MODEL, dtype: EMBED_DTYPE };
|
|
42
49
|
const SINGULAR = ["identity", "title", "subtitle", "temporal", "spatial", "media", "thread"];
|
|
43
50
|
const MULTI = ["tags", "measures", "relations", "text"];
|
|
@@ -68,17 +75,16 @@ export function composeText(fields, rm) {
|
|
|
68
75
|
return s.slice(0, 1000 - "search_document: ".length);
|
|
69
76
|
}
|
|
70
77
|
|
|
71
|
-
/** `fangorn.schema`
|
|
78
|
+
/** `fangorn.schema` records → { types: {tag: {description, role_map, presentation}}, relations }. */
|
|
72
79
|
export function parseSchema(contents) {
|
|
73
|
-
const types = {},
|
|
74
|
-
for (const
|
|
75
|
-
const p =
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
const types = {}, relations = [];
|
|
81
|
+
for (const r of contents?.records ?? []) {
|
|
82
|
+
const p = r.payload ?? {};
|
|
83
|
+
if (r.type === TYPE_TAG && typeof p.tag === "string")
|
|
84
|
+
types[p.tag] = { description: String(p.description ?? ""), role_map: p.role_map ?? {}, presentation: p.presentation ?? {} };
|
|
85
|
+
else if (r.type === RELATION_TAG && p.rel && p.from && p.to)
|
|
86
|
+
relations.push({ rel: String(p.rel), from: String(p.from), to: String(p.to) });
|
|
79
87
|
}
|
|
80
|
-
const relations = (contents?.edges ?? []).filter((e) => tagOf[e.sourceCid] && tagOf[e.targetCid])
|
|
81
|
-
.map((e) => ({ rel: e.relation, from: tagOf[e.sourceCid], to: tagOf[e.targetCid] }));
|
|
82
88
|
return { types, relations };
|
|
83
89
|
}
|
|
84
90
|
|
|
@@ -122,49 +128,62 @@ export function domainSpec(schema, tags) {
|
|
|
122
128
|
}
|
|
123
129
|
|
|
124
130
|
/**
|
|
125
|
-
* Each declared relation, onto the row it starts from: an agenda item
|
|
126
|
-
* to a matter carries `part_of: <the matter's identity>`,
|
|
127
|
-
*
|
|
128
|
-
* `
|
|
129
|
-
*
|
|
130
|
-
* needs many.
|
|
131
|
+
* Each declared relation, onto the row it starts from: an agenda item whose `part_of` is a
|
|
132
|
+
* reference ({local: <record id>}) to a matter carries `part_of: <the matter's identity>`,
|
|
133
|
+
* so a reader groups rows by it without resolving references. References the schema does not
|
|
134
|
+
* declare are left as they are (the schema is the contract). `rows` maps CID → {id, fields}
|
|
135
|
+
* and is changed in place.
|
|
131
136
|
*/
|
|
132
|
-
export function linkRelations(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
137
|
+
export function linkRelations(rows, schema) {
|
|
138
|
+
const byId = new Map([...rows.values()].map((r) => [r.id, r.fields]));
|
|
139
|
+
for (const { fields } of rows.values()) for (const rel of schema.relations) {
|
|
140
|
+
const ref = fields[rel.rel];
|
|
141
|
+
if (rel.from !== fields.entityType || typeof ref?.local !== "string") continue;
|
|
142
|
+
const to = byId.get(ref.local);
|
|
143
|
+
if (!to || to.entityType !== rel.to) continue;
|
|
144
|
+
const id = schema.types[rel.to]?.role_map?.identity;
|
|
145
|
+
fields[rel.rel] = String((id && to[id]) ?? ref.local);
|
|
138
146
|
}
|
|
139
147
|
}
|
|
140
148
|
|
|
141
149
|
// ── a client that only reads ──────────────────────────────────────────────────
|
|
142
150
|
|
|
143
|
-
/**
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
/** The SDK's deployment for a network name ("baseSepolia"): FANGORN_NETWORK, else its default. */
|
|
152
|
+
export async function network(name = process.env.FANGORN_NETWORK || "baseSepolia") {
|
|
153
|
+
const { SupportedNetworks } = await import("@fangorn-network/sdk");
|
|
154
|
+
if (!SupportedNetworks[name]) throw new Error(`network ${name}: the SDK knows ${Object.keys(SupportedNetworks).join(", ")}`);
|
|
155
|
+
return SupportedNetworks[name];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** The IPFS gateway to read contents through: FANGORN_IPFS_GATEWAY, else the one in
|
|
159
|
+
* ~/.fangorn/config.json (what the fangorn CLI reads through), else none (the SDK default). */
|
|
160
|
+
export function ipfsGateway() {
|
|
151
161
|
let gateway = process.env.FANGORN_IPFS_GATEWAY ?? process.env.IPFS_GATEWAY;
|
|
152
|
-
try { gateway ??= JSON.parse(readFileSync(`${
|
|
153
|
-
|
|
162
|
+
try { gateway ??= JSON.parse(readFileSync(`${process.env.HOME}/.fangorn/config.json`, "utf8")).pinataGateway || undefined; } catch { /* no CLI config */ }
|
|
163
|
+
return gateway && !/^https?:\/\//.test(gateway) ? `https://${gateway}` : gateway;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** An SDK client for reading: a throwaway key (nothing signs) and no upload credentials,
|
|
167
|
+
* reading contents through `ipfsGateway()`. */
|
|
168
|
+
export async function readOnlyFangorn() {
|
|
169
|
+
const [{ Fangorn }, { generatePrivateKey }] = await Promise.all([import("@fangorn-network/sdk"), import("viem/accounts")]);
|
|
170
|
+
const FangornConfig = await network();
|
|
171
|
+
const gateway = ipfsGateway();
|
|
154
172
|
return Fangorn.create({ privateKey: generatePrivateKey(), config: FangornConfig,
|
|
155
173
|
storage: { signedUrl: gateway ? { gateway } : {} } });
|
|
156
174
|
}
|
|
157
175
|
|
|
158
176
|
/** What publishView reads, served from memory instead of the chain: `chain` maps
|
|
159
|
-
* `<owner>/<
|
|
160
|
-
*
|
|
161
|
-
*
|
|
177
|
+
* `<owner>/<repo>` to `{ records: [{id, cid, type, payload}] }`, every one presented.
|
|
178
|
+
* A build that must not touch the chain — a candidate recipe graded before it ships —
|
|
179
|
+
* runs the exact code a real one does. */
|
|
162
180
|
export function localFangorn(chain, { appId, owner }) {
|
|
181
|
+
const root = (k) => `0x${createHash("sha256").update(JSON.stringify(chain[k])).digest("hex")}`;
|
|
163
182
|
return {
|
|
164
183
|
setAppId() {}, getAppId: () => appId,
|
|
165
184
|
getAppRegistry: () => ({ getAppOwner: async () => owner }),
|
|
166
|
-
|
|
167
|
-
|
|
185
|
+
appRepos: async () => Object.keys(chain).map((k) => ({ owner: k.split("/")[0], repo: k.split("/").slice(1).join("/"), root: root(k) })),
|
|
186
|
+
readRepo: async (o, repo) => { const c = chain[`${o}/${repo}`]; return { tip: c ? root(`${o}/${repo}`) : null, contents: { records: c?.records ?? [] } }; },
|
|
168
187
|
};
|
|
169
188
|
}
|
|
170
189
|
|
|
@@ -187,83 +206,141 @@ export function cachedEmbed(path, embed = embedDocumentDirect) {
|
|
|
187
206
|
return fn;
|
|
188
207
|
}
|
|
189
208
|
|
|
190
|
-
// ── the view
|
|
209
|
+
// ── where the view lives ──────────────────────────────────────────────────────
|
|
210
|
+
//
|
|
211
|
+
// A store is four calls on paths relative to the view's root: get → bytes or null, put,
|
|
212
|
+
// del (a file, or everything under a folder), and list (a folder's immediate children).
|
|
191
213
|
|
|
192
|
-
|
|
193
|
-
|
|
214
|
+
/** A directory on disk. */
|
|
215
|
+
export function fsStore(out) {
|
|
216
|
+
const at = (p) => `${out}/${p}`;
|
|
217
|
+
return {
|
|
218
|
+
get: async (p) => (existsSync(at(p)) ? readFileSync(at(p)) : null),
|
|
219
|
+
put: async (p, b) => { mkdirSync(dirname(at(p)), { recursive: true }); writeFileSync(`${at(p)}.tmp`, b); renameSync(`${at(p)}.tmp`, at(p)); },
|
|
220
|
+
del: async (p) => rmSync(at(p), { recursive: true, force: true }),
|
|
221
|
+
list: async (p) => (existsSync(at(p)) ? readdirSync(at(p)) : []),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** An R2 bucket (a Worker's binding), under `prefix`. */
|
|
226
|
+
export function r2Store(bucket, prefix = "view/") {
|
|
227
|
+
const keys = async (p, delimiter) => {
|
|
228
|
+
const out = { objects: [], prefixes: [] };
|
|
229
|
+
let cursor;
|
|
230
|
+
do {
|
|
231
|
+
const l = await bucket.list({ prefix: prefix + p, delimiter, cursor });
|
|
232
|
+
out.objects.push(...l.objects.map((o) => o.key));
|
|
233
|
+
out.prefixes.push(...(l.delimitedPrefixes ?? []));
|
|
234
|
+
cursor = l.truncated ? l.cursor : undefined;
|
|
235
|
+
} while (cursor);
|
|
236
|
+
return out;
|
|
237
|
+
};
|
|
238
|
+
return {
|
|
239
|
+
get: async (p) => { const o = await bucket.get(prefix + p); return o ? new Uint8Array(await o.arrayBuffer()) : null; },
|
|
240
|
+
put: async (p, b) => { await bucket.put(prefix + p, b); },
|
|
241
|
+
del: async (p) => {
|
|
242
|
+
const all = [...(await keys(`${p}/`)).objects, ...((await bucket.head(prefix + p)) ? [prefix + p] : [])];
|
|
243
|
+
for (let i = 0; i < all.length; i += 1000) await bucket.delete(all.slice(i, i + 1000));
|
|
244
|
+
},
|
|
245
|
+
list: async (p) => {
|
|
246
|
+
const { objects, prefixes } = await keys(`${p}/`, "/");
|
|
247
|
+
const base = prefix.length + p.length + 1;
|
|
248
|
+
return [...objects.map((k) => k.slice(base)), ...prefixes.map((k) => k.slice(base, -1))];
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const readJson = async (store, p, dflt) => { const b = await store.get(p); return b ? JSON.parse(new TextDecoder().decode(b)) : dflt; };
|
|
254
|
+
const writeJson = (store, p, o) => store.put(p, JSON.stringify(o, null, 1));
|
|
194
255
|
|
|
195
256
|
/** What a domain already serves: its manifest and every row (for tombstones and coverage). */
|
|
196
|
-
function loadDomain(dir) {
|
|
197
|
-
const manifest = readJson(`${dir}/manifest`, null);
|
|
257
|
+
async function loadDomain(store, dir) {
|
|
258
|
+
const manifest = await readJson(store, `${dir}/manifest`, null);
|
|
198
259
|
const rows = new Map();
|
|
199
260
|
for (const s of manifest?.shards ?? []) {
|
|
200
|
-
const
|
|
201
|
-
|
|
261
|
+
const b = await store.get(`${dir}/shards/${s.file}`);
|
|
262
|
+
if (!b) throw new Error(`${dir}: shard ${s.file} is named by its manifest and missing`);
|
|
263
|
+
for (const line of gunzipSync(b).toString("utf8").split("\n")) if (line.trim()) { const r = JSON.parse(line); rows.set(r.track_id, r); }
|
|
202
264
|
}
|
|
203
265
|
return { manifest, rows };
|
|
204
266
|
}
|
|
205
267
|
|
|
206
|
-
/** Every live row's fields, across the view
|
|
207
|
-
export function liveFields(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
const { manifest, rows } = loadDomain(
|
|
268
|
+
/** Every live row's fields, across the view in `store` (or the directory `out`). */
|
|
269
|
+
export async function liveFields(store) {
|
|
270
|
+
if (typeof store === "string") store = fsStore(store);
|
|
271
|
+
const out = [];
|
|
272
|
+
for (const d of await store.list("cdn/domains")) {
|
|
273
|
+
const { manifest, rows } = await loadDomain(store, `cdn/domains/${d}`);
|
|
212
274
|
const dead = new Set(manifest?.tombstones ?? []);
|
|
213
|
-
|
|
214
|
-
}
|
|
275
|
+
for (const r of rows.values()) if (!dead.has(r.track_id)) out.push(r.fields ?? {});
|
|
276
|
+
}
|
|
277
|
+
return out;
|
|
215
278
|
}
|
|
216
279
|
|
|
280
|
+
const sha256 = (s) => createHash("sha256").update(s).digest("hex");
|
|
281
|
+
|
|
217
282
|
/**
|
|
218
|
-
* Bring
|
|
283
|
+
* Bring the view up to date with what the app presents. `fangorn` is an SDK client (reads
|
|
284
|
+
* only); the view goes to `store`, or the directory `out`. `repos` narrows it to those repo
|
|
285
|
+
* names (every publisher's); without it, every repo the app presents. `fromBlock` must be
|
|
286
|
+
* at or before the first update to a repo the app presents, or a repo the scan misses is left out;
|
|
287
|
+
* left out, the SDK's deployment start. `embedBatch(texts)` embeds many at once where the
|
|
288
|
+
* encoder batches (a Worker's AI binding); `embedder` is what the manifest records.
|
|
289
|
+
* `presented` replaces the `appRepos` scan with a list the caller keeps itself
|
|
290
|
+
* ([{owner, repo, root}], exclusions already applied), as a Worker does across runs.
|
|
219
291
|
* Returns per-domain counts of what changed.
|
|
220
292
|
*/
|
|
221
|
-
export async function publishView({ fangorn, app,
|
|
222
|
-
embed = embedDocumentDirect,
|
|
223
|
-
|
|
293
|
+
export async function publishView({ fangorn, app, repos, out, store = fsStore(out), fromBlock, presented, rebake = false,
|
|
294
|
+
embed = embedDocumentDirect, embedBatch = (ts) => Promise.all(ts.map(embed)),
|
|
295
|
+
embedder = EMBEDDER, log = console.log, shardRows = 20000, concurrency = 4, open = (p) => p }) {
|
|
224
296
|
fangorn.setAppId(app);
|
|
225
297
|
const appId = fangorn.getAppId();
|
|
226
298
|
const owner = (await fangorn.getAppRegistry().getAppOwner()).toLowerCase();
|
|
227
299
|
let schema = { types: {}, relations: [] };
|
|
228
300
|
if (owner === ZERO) log(`app ${app} is unclaimed, so it has no schema; every type will be guessed`);
|
|
229
301
|
else {
|
|
230
|
-
try { schema = parseSchema((await fangorn.
|
|
302
|
+
try { schema = parseSchema((await retry(() => fangorn.readRepo(owner, SCHEMA_REPO))).contents); }
|
|
231
303
|
catch (e) { log(`schema: none read (${e.message}); every type will be guessed`); }
|
|
232
304
|
}
|
|
233
305
|
const declared = Object.keys(schema.types);
|
|
234
306
|
log(`schema: ${declared.length ? declared.join(", ") : "no declared types"}`);
|
|
307
|
+
const schemaHash = sha256(JSON.stringify(schema));
|
|
308
|
+
|
|
309
|
+
// Every repo the app presents, at its accepted head: one log scan, exclusions applied.
|
|
310
|
+
const listed = (presented ?? await retry(() => fangorn.appRepos(fromBlock == null ? {} : { fromBlock: BigInt(fromBlock) })))
|
|
311
|
+
.filter((t) => t.repo !== SCHEMA_REPO && (!repos?.length || repos.includes(t.repo)));
|
|
312
|
+
log(`${listed.length} repo(s) presented${repos?.length ? ` of ${repos.join(", ")}` : ""}`);
|
|
235
313
|
|
|
236
314
|
const report = {};
|
|
237
|
-
|
|
238
|
-
//
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
// them by app only, so a scan per namespace re-reads every log of the app each time: 376 s a
|
|
242
|
-
// namespace through a public RPC, against 3 s to read the namespace itself.
|
|
243
|
-
const reg = fangorn.getDataRegistry?.();
|
|
244
|
-
let committed = null;
|
|
245
|
-
if (reg?.getStateCommittedLogs && reg.namespaceKey) {
|
|
246
|
-
const logs = await retry(() => reg.getStateCommittedLogs({}, BigInt(fromBlock)));
|
|
247
|
-
committed = { keys: new Set(logs.map((l) => l.namespaceKey)), publishers: [...new Set(logs.map((l) => l.publisher))] };
|
|
248
|
-
log(`commit logs since block ${fromBlock}: ${logs.length} from ${committed.publishers.length} publisher(s)`);
|
|
249
|
-
}
|
|
250
|
-
const publishersOf = (ns) => (committed
|
|
251
|
-
? committed.publishers.filter((p) => committed.keys.has(reg.namespaceKey(p, ns))).map((owner) => ({ owner }))
|
|
252
|
-
: retry(() => fangorn.appNamespaces({ namespace: ns, fromBlock: BigInt(fromBlock) })));
|
|
315
|
+
const live = new Set();
|
|
316
|
+
// Several repos at once: reading one through an IPFS gateway is block by block and takes
|
|
317
|
+
// far longer than embedding it. Each domain writes only its own folder.
|
|
318
|
+
const queue = [...listed];
|
|
253
319
|
const worker = async () => {
|
|
254
|
-
for (let
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
});
|
|
262
|
-
|
|
320
|
+
for (let t; (t = queue.shift()) !== undefined;) {
|
|
321
|
+
const domain = domainFor(appId, t.owner, t.repo);
|
|
322
|
+
live.add(domain);
|
|
323
|
+
// One repo failing (unreadable, the encoder out for the day) keeps its last view and
|
|
324
|
+
// does not stop the others; the next run tries it again.
|
|
325
|
+
const r = await publishDomain({ fangorn, store, schema, schemaHash, publisher: t.owner, repo: t.repo, head: t.root, domain,
|
|
326
|
+
dir: `cdn/domains/${domain}`, rebake, embedBatch, embedder, log, shardRows, open })
|
|
327
|
+
.catch((e) => { log(`${domain}: ✗ ${e.message}; left as it was`); return { added: 0, removed: 0, error: e.message }; });
|
|
328
|
+
if (r) report[domain] = r;
|
|
263
329
|
}
|
|
264
330
|
};
|
|
265
331
|
await Promise.all(Array.from({ length: concurrency }, worker));
|
|
266
|
-
|
|
332
|
+
|
|
333
|
+
// What the app no longer presents (excluded, or its publisher banned) is not served.
|
|
334
|
+
for (const d of await store.list("cdn/domains")) {
|
|
335
|
+
if (live.has(d)) continue;
|
|
336
|
+
const m = await readJson(store, `cdn/domains/${d}/manifest`, null);
|
|
337
|
+
const repo = m?.filter?.repo?.[0] ?? m?.filter?.namespace?.[0];
|
|
338
|
+
if (repos?.length && !repos.includes(repo)) continue;
|
|
339
|
+
await store.del(`cdn/domains/${d}`);
|
|
340
|
+
report[d] = { added: 0, removed: m?.count ?? 0, dropped: true };
|
|
341
|
+
log(`${d}: no longer presented by the app; dropped`);
|
|
342
|
+
}
|
|
343
|
+
await writeCatalog(store);
|
|
267
344
|
return report;
|
|
268
345
|
}
|
|
269
346
|
|
|
@@ -277,19 +354,26 @@ async function retry(f, tries = 6) {
|
|
|
277
354
|
}
|
|
278
355
|
}
|
|
279
356
|
|
|
280
|
-
async function publishDomain({ fangorn, schema, publisher,
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
357
|
+
async function publishDomain({ fangorn, store, schema, schemaHash, publisher, repo, head, domain, dir, rebake, embedBatch, embedder, log, shardRows, open }) {
|
|
358
|
+
// The head the domain was built from, and the schema it was built under: neither moved,
|
|
359
|
+
// nothing to read. This is what keeps a cron run with nothing new to one read per repo.
|
|
360
|
+
const was = rebake ? null : await readJson(store, `${dir}/manifest`, null);
|
|
361
|
+
if (was && was.head === head && was.schema_hash === schemaHash) return null;
|
|
362
|
+
|
|
363
|
+
const { contents } = await retry(() => fangorn.readRepo(publisher, repo));
|
|
364
|
+
// `open`: a private app's rows are sealed on chain (x402.js's sealRow); the Worker opens them here.
|
|
365
|
+
const records = new Map(await Promise.all(contents.records.filter((r) => r.payload && typeof r.payload === "object")
|
|
366
|
+
.map(async (r) => [r.cid, { id: r.id, fields: { ...(await open(r.payload)), entityType: r.type } }])));
|
|
367
|
+
linkRelations(records, schema);
|
|
368
|
+
const fieldsOf = (cid) => records.get(cid).fields;
|
|
369
|
+
|
|
370
|
+
if (rebake) await store.del(dir); // old shards would stay reachable
|
|
371
|
+
const had = await loadDomain(store, dir);
|
|
288
372
|
const made = had.manifest?.embedder ?? (had.manifest ? { runtime: "fastembed", dtype: "fp32" } : null);
|
|
289
373
|
// Same model and dtype is the same encoder, whatever ran it: q8 on CPU, CUDA and WASM agree to
|
|
290
|
-
// ~0.98-0.99 cosine, fp32 against q8
|
|
291
|
-
if (made && (made.model ??
|
|
292
|
-
throw new Error(`${domain} was embedded by ${made.runtime} ${made.dtype}, not ${
|
|
374
|
+
// ~0.98-0.99 cosine, fp32 against q8 noticeably less.
|
|
375
|
+
if (made && (made.model ?? "") + made.dtype !== embedder.model + embedder.dtype)
|
|
376
|
+
throw new Error(`${domain} was embedded by ${made.runtime} ${made.model ?? ""} ${made.dtype}, not ${embedder.runtime} ${embedder.model} ${embedder.dtype}; ` +
|
|
293
377
|
"vectors from two encoders are not comparable. Rebake it with --rebake, or keep publishing it with the tool that made it.");
|
|
294
378
|
|
|
295
379
|
const dead = new Set(had.manifest?.tombstones ?? []);
|
|
@@ -299,53 +383,70 @@ async function publishDomain({ fangorn, schema, publisher, ns, domain, dir, reba
|
|
|
299
383
|
// A row already served whose links changed (its matter came later, or moved): new fields,
|
|
300
384
|
// the same vector, so no embedding, only a rewrite.
|
|
301
385
|
const relinked = [...had.rows.keys()].filter((id) => live(id) && records.has(id)
|
|
302
|
-
&& JSON.stringify(had.rows.get(id).fields) !== JSON.stringify(
|
|
303
|
-
for (const id of relinked) had.rows.get(id).fields =
|
|
386
|
+
&& JSON.stringify(had.rows.get(id).fields) !== JSON.stringify(fieldsOf(id)));
|
|
387
|
+
for (const id of relinked) had.rows.get(id).fields = fieldsOf(id);
|
|
304
388
|
|
|
305
389
|
// Roles per type: declared exactly, else guessed (and said so).
|
|
306
390
|
const byType = new Map();
|
|
307
|
-
for (const id of fresh) { const t =
|
|
391
|
+
for (const id of fresh) { const t = fieldsOf(id).entityType; byType.set(t, [...(byType.get(t) ?? []), id]); }
|
|
308
392
|
const rolesOf = new Map();
|
|
309
393
|
for (const [t, ids] of byType) {
|
|
310
394
|
if (schema.types[t]) rolesOf.set(t, completeRoles(schema.types[t].role_map));
|
|
311
395
|
else {
|
|
312
|
-
rolesOf.set(t, guessRoles(ids.slice(0, 200).map(
|
|
396
|
+
rolesOf.set(t, guessRoles(ids.slice(0, 200).map(fieldsOf)));
|
|
313
397
|
log(`${domain}: type ${t} is not in the schema; guessed title=${rolesOf.get(t).title} text=${rolesOf.get(t).text}`);
|
|
314
398
|
}
|
|
315
399
|
}
|
|
316
400
|
|
|
317
|
-
let n = 0;
|
|
401
|
+
let n = 0, stopped = null;
|
|
318
402
|
const lines = [];
|
|
319
|
-
// 32 at a time:
|
|
403
|
+
// 32 at a time: what an encoder batches (embed.js, a GPU, the Worker's AI binding).
|
|
320
404
|
for (let i = 0; i < fresh.length; i += 32) {
|
|
321
405
|
const ids = fresh.slice(i, i + 32);
|
|
322
|
-
|
|
323
|
-
|
|
406
|
+
try {
|
|
407
|
+
const vs = await embedBatch(ids.map((id) => composeText(fieldsOf(id), rolesOf.get(fieldsOf(id).entityType))));
|
|
408
|
+
ids.forEach((id, j) => lines.push(JSON.stringify({ track_id: id, fields: fieldsOf(id), v: packVec(vs[j]) })));
|
|
409
|
+
} catch (e) {
|
|
410
|
+
// The encoder gave out (Workers AI's free daily allowance, say): keep what is embedded
|
|
411
|
+
// and come back for the rest. Nothing served yet, nothing to save: fail as before.
|
|
412
|
+
if (!lines.length) throw e;
|
|
413
|
+
stopped = e;
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
324
416
|
if (Math.floor((n + ids.length) / 1000) > Math.floor(n / 1000)) log(`${domain}: embedded ${n + ids.length}/${fresh.length}`);
|
|
325
417
|
n += ids.length;
|
|
326
418
|
}
|
|
419
|
+
const manifest = had.manifest ?? { name: domain, description: "", count: 0, dim: EMBED_DIM, model: EMBED_MODEL,
|
|
420
|
+
distance: "Cosine", embedder, filter: { owner: [publisher], repo: [repo] }, shards: [], tombstones: [] };
|
|
421
|
+
// Unfinished: the old head stays, so the next run sees a head to catch up to and embeds only what is missing.
|
|
422
|
+
manifest.head = stopped ? (had.manifest?.head ?? null) : head;
|
|
423
|
+
manifest.schema_hash = schemaHash;
|
|
327
424
|
if (!fresh.length && !gone.length && !relinked.length && had.manifest && !rebake) {
|
|
328
|
-
applySpec(dir,
|
|
425
|
+
await applySpec(store, dir, manifest, schema, had.rows, dead); // a schema change alone still lands
|
|
329
426
|
return { added: 0, removed: 0 };
|
|
330
427
|
}
|
|
331
428
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
// Pages serves files up to 25 MiB; 52k Steam games gzipped to 28 MiB in one shard.
|
|
336
|
-
// ponytail: split by row count (~550 B a row gzipped); split by bytes if rows get much fatter.
|
|
337
|
-
const writeShard = (all) => {
|
|
429
|
+
// Pages and R2 serve files of any size, but a reader holds a shard whole; 52k Steam games
|
|
430
|
+
// gzipped to 28 MiB in one. ponytail: split by row count (~550 B a row gzipped).
|
|
431
|
+
const writeShard = async (all) => {
|
|
338
432
|
for (let i = 0; i < all.length; i += shardRows) {
|
|
339
433
|
const ls = all.slice(i, i + shardRows);
|
|
340
434
|
const gz = gzipSync(`${ls.join("\n")}\n`, { level: 9 });
|
|
341
|
-
const
|
|
342
|
-
const file = `shard-${String(manifest.shards.length).padStart(4, "0")}-${
|
|
343
|
-
|
|
344
|
-
manifest.shards.push({ file, count: ls.length, bytes: gz.length, sha256 });
|
|
435
|
+
const digest = sha256(gz);
|
|
436
|
+
const file = `shard-${String(manifest.shards.length).padStart(4, "0")}-${digest.slice(0, 12)}.ndjson.gz`;
|
|
437
|
+
await store.put(`${dir}/shards/${file}`, gz);
|
|
438
|
+
manifest.shards.push({ file, count: ls.length, bytes: gz.length, sha256: digest });
|
|
345
439
|
}
|
|
346
440
|
};
|
|
441
|
+
if (stopped) {
|
|
442
|
+
await writeShard(lines);
|
|
443
|
+
for (const l of lines) { const r = JSON.parse(l); had.rows.set(r.track_id, r); dead.delete(r.track_id); }
|
|
444
|
+
await applySpec(store, dir, manifest, schema, had.rows, dead, rolesOf);
|
|
445
|
+
log(`${domain}: stopped at ${n}/${fresh.length} (${stopped.message}); the rest on the next run`);
|
|
446
|
+
return { added: n, removed: 0, partial: true };
|
|
447
|
+
}
|
|
347
448
|
if (lines.length) {
|
|
348
|
-
writeShard(lines);
|
|
449
|
+
await writeShard(lines);
|
|
349
450
|
for (const l of lines) { const r = JSON.parse(l); had.rows.set(r.track_id, r); dead.delete(r.track_id); }
|
|
350
451
|
}
|
|
351
452
|
for (const id of gone) dead.add(id);
|
|
@@ -355,29 +456,30 @@ async function publishDomain({ fangorn, schema, publisher, ns, domain, dir, reba
|
|
|
355
456
|
// files are deleted. No re-embedding: the vectors are already in the rows.
|
|
356
457
|
// ponytail: rewrites the whole domain on every removal; compact past a threshold if domains get big.
|
|
357
458
|
if (dead.size || relinked.length) {
|
|
358
|
-
for (const s of manifest.shards)
|
|
459
|
+
for (const s of manifest.shards) await store.del(`${dir}/shards/${s.file}`);
|
|
359
460
|
manifest.shards = [];
|
|
360
461
|
for (const id of dead) had.rows.delete(id);
|
|
361
462
|
dead.clear();
|
|
362
|
-
writeShard([...had.rows.values()].map((r) => JSON.stringify(r)));
|
|
463
|
+
await writeShard([...had.rows.values()].map((r) => JSON.stringify(r)));
|
|
363
464
|
}
|
|
364
465
|
manifest.tombstones = [...dead].sort();
|
|
365
466
|
manifest.created_at = Math.floor(Date.now() / 1000);
|
|
366
|
-
applySpec(dir, manifest, schema, had.rows, dead, rolesOf);
|
|
467
|
+
await applySpec(store, dir, manifest, schema, had.rows, dead, rolesOf);
|
|
367
468
|
log(`${domain}: +${fresh.length} embedded, -${gone.length} removed, ${relinked.length} relinked, ${manifest.count} live`);
|
|
368
469
|
return { added: fresh.length, removed: gone.length, ...(relinked.length ? { relinked: relinked.length } : {}) };
|
|
369
470
|
}
|
|
370
471
|
|
|
371
|
-
/** Counts, types, roles, description, presentation
|
|
372
|
-
|
|
472
|
+
/** Counts, types, roles, description, presentation, coverage and the hosts its media role
|
|
473
|
+
* links to (what a Worker may show inline, see site/worker.js) from what the domain holds. */
|
|
474
|
+
async function applySpec(store, dir, manifest, schema, rows, dead, guessed = new Map()) {
|
|
373
475
|
const liveRows = [...rows.values()].filter((r) => !dead.has(r.track_id));
|
|
374
476
|
const types = {};
|
|
375
477
|
for (const r of liveRows) types[r.fields?.entityType] = (types[r.fields?.entityType] ?? 0) + 1;
|
|
376
478
|
const tags = Object.entries(types).sort((a, b) => b[1] - a[1]).map(([t]) => t);
|
|
377
|
-
// Compare with what is
|
|
479
|
+
// Compare with what is stored, not with the manifest as it arrived: publishDomain has already
|
|
378
480
|
// swapped shards and tombstones, and a one-for-one replacement changes nothing here, which left
|
|
379
481
|
// the old manifest naming deleted shards.
|
|
380
|
-
const before = JSON.stringify(readJson(`${dir}/manifest`, null));
|
|
482
|
+
const before = JSON.stringify(await readJson(store, `${dir}/manifest`, null));
|
|
381
483
|
|
|
382
484
|
manifest.count = liveRows.length;
|
|
383
485
|
manifest.entity_types = tags.map((t) => ({ type: t, count: types[t] }));
|
|
@@ -386,27 +488,30 @@ function applySpec(dir, manifest, schema, rows, dead, guessed = new Map()) {
|
|
|
386
488
|
manifest.role_map = { ...(spec?.role_map ?? manifest.role_map ?? guessed.values().next().value ?? completeRoles()), fields };
|
|
387
489
|
if (spec?.description) manifest.description = spec.description;
|
|
388
490
|
if (spec && Object.keys(spec.presentation).length) manifest.presentation = spec.presentation;
|
|
491
|
+
const media = [manifest.role_map.media ?? []].flat();
|
|
492
|
+
manifest.link_hosts = [...new Set(liveRows.flatMap((r) => media.map((m) => r.fields?.[m]))
|
|
493
|
+
.filter((u) => typeof u === "string" && u.startsWith("https://"))
|
|
494
|
+
.map((u) => { try { return new URL(u).hostname; } catch { return null; } }).filter(Boolean))].sort();
|
|
389
495
|
|
|
390
496
|
const cov = manifest.coverage;
|
|
391
497
|
if (liveRows.length && (!cov || liveRows.length >= COVERAGE_REFIT * (cov.fit_at ?? 0))) {
|
|
392
498
|
manifest.coverage = { ...fitCoverage(liveRows.map((r) => unpackVec(r.v))), fit_at: liveRows.length };
|
|
393
499
|
}
|
|
394
|
-
if (JSON.stringify(manifest) !== before) {
|
|
395
|
-
mkdirSync(dir, { recursive: true });
|
|
396
|
-
writeJson(`${dir}/manifest`, manifest);
|
|
397
|
-
}
|
|
500
|
+
if (JSON.stringify(manifest) !== before) await writeJson(store, `${dir}/manifest`, manifest);
|
|
398
501
|
}
|
|
399
502
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
const domains =
|
|
404
|
-
|
|
503
|
+
/** The catalog: every domain's summary and coverage, the one file a reader routes on. */
|
|
504
|
+
export async function writeCatalog(store) {
|
|
505
|
+
if (typeof store === "string") store = fsStore(store);
|
|
506
|
+
const domains = (await Promise.all((await store.list("cdn/domains")).sort()
|
|
507
|
+
.map((d) => readJson(store, `cdn/domains/${d}/manifest`, null)))).filter(Boolean);
|
|
508
|
+
await writeJson(store, "cdn/catalog", {
|
|
405
509
|
generated_at: Math.floor(Date.now() / 1000), embedding_model: EMBED_MODEL,
|
|
406
510
|
domains: domains.map((m) => ({
|
|
407
511
|
name: m.name, description: m.description, count: m.count, dim: m.dim,
|
|
408
512
|
bytes: m.shards.reduce((s, x) => s + x.bytes, 0), shard_count: m.shards.length,
|
|
409
513
|
entity_types: m.entity_types.map((e) => e.type), manifest: `${m.name}/manifest.json`,
|
|
514
|
+
...(m.link_hosts?.length ? { link_hosts: m.link_hosts } : {}),
|
|
410
515
|
...(m.coverage ? { coverage: m.coverage } : {}),
|
|
411
516
|
})),
|
|
412
517
|
});
|
|
@@ -419,7 +524,8 @@ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv
|
|
|
419
524
|
const { tmpdir } = await import("node:os");
|
|
420
525
|
const { loadShard, configure } = await import("../core/shard.js");
|
|
421
526
|
const eq = (a, b, m) => { if (JSON.stringify(a) !== JSON.stringify(b)) throw new Error(`${m}: ${JSON.stringify(a)} != ${JSON.stringify(b)}`); };
|
|
422
|
-
const
|
|
527
|
+
const manifestOf = (dir, d) => JSON.parse(readFileSync(`${dir}/cdn/domains/${d}/manifest`, "utf8"));
|
|
528
|
+
const rec = (cid, type, payload, id = cid) => ({ id, cid, type, payload });
|
|
423
529
|
|
|
424
530
|
// quickbeam's own outputs, pinned: the contract, not an approximation of it.
|
|
425
531
|
eq(domainFor(`0x${"7e1497af".padEnd(64, "0")}`, "0x55cf6bd2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "media"), "7e1497af-55cf6bd2-media", "domain name = quickbeam's");
|
|
@@ -430,14 +536,14 @@ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv
|
|
|
430
536
|
const APP = `0x${"ab".repeat(32)}`, OWNER = `0x${"11".repeat(20)}`, PUB = `0x${"22".repeat(20)}`;
|
|
431
537
|
const TAG = "shop.item.v1";
|
|
432
538
|
const chain = {
|
|
433
|
-
[`${OWNER}/${
|
|
539
|
+
[`${OWNER}/${SCHEMA_REPO}`]: { records: [rec("t1", TYPE_TAG, {
|
|
434
540
|
tag: TAG, description: "Things for a room.", role_map: { identity: "sku", title: "name", text: "about" },
|
|
435
|
-
presentation: { externalUrl: { [TAG]: "https://shop.example/{sku}" } } }
|
|
436
|
-
[`${PUB}/shop`]: {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
]
|
|
541
|
+
presentation: { externalUrl: { [TAG]: "https://shop.example/{sku}" } } })] },
|
|
542
|
+
[`${PUB}/shop`]: { records: [
|
|
543
|
+
rec("c1", TAG, { sku: "a1", name: "Oak table", about: "a solid oak dining table", price: 3 }),
|
|
544
|
+
rec("c2", TAG, { sku: "b2", name: "Lamp", about: "brass reading lamp", price: 1 }),
|
|
545
|
+
rec("c3", "shop.note.v1", { title: "Note", body: "an undeclared type, with a body long enough to count as its text field" }),
|
|
546
|
+
] },
|
|
441
547
|
};
|
|
442
548
|
const fangorn = localFangorn(chain, { appId: APP, owner: OWNER });
|
|
443
549
|
const embedded = [];
|
|
@@ -451,45 +557,42 @@ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv
|
|
|
451
557
|
appendFileSync(`${out}/vectors.ndjson`, '["cut sho');
|
|
452
558
|
eq(packVec(await cachedEmbed(`${out}/vectors.ndjson`, embed)("Title: Oak")), packVec(v1), "a line cut short by a kill is skipped, not fatal");
|
|
453
559
|
embedded.length = 0; rmSync(`${out}/vectors.ndjson`);
|
|
454
|
-
const run = () => publishView({ fangorn, app: APP,
|
|
560
|
+
const run = () => publishView({ fangorn, app: APP, out, embed, log: () => {} });
|
|
455
561
|
|
|
456
562
|
const d = domainFor(APP, PUB, "shop");
|
|
457
563
|
const split = mkdtempSync(`${tmpdir()}/view-`);
|
|
458
|
-
await publishView({ fangorn, app: APP,
|
|
459
|
-
|
|
460
|
-
eq([m.count, m.shards.map((s) => s.count)], [3, [2, 1]], "rows past shardRows go to the next shard (Pages caps a file at 25 MiB)"); }
|
|
564
|
+
await publishView({ fangorn, app: APP, out: split, embed, log: () => {}, shardRows: 2 });
|
|
565
|
+
eq(manifestOf(split, d).shards.map((s) => s.count), [2, 1], "rows past shardRows go to the next shard");
|
|
461
566
|
embedded.length = 0;
|
|
462
567
|
eq((await run())[d], { added: 3, removed: 0 }, "first run embeds everything");
|
|
463
568
|
if (!embedded.includes("Title: Oak table. Tags: . a solid oak dining table")) throw new Error(`declared roles compose the text: ${embedded}`);
|
|
464
|
-
let m =
|
|
569
|
+
let m = manifestOf(out, d);
|
|
465
570
|
eq([m.role_map.identity, m.role_map.title, m.role_map.text, m.description], ["sku", "name", ["about"], "Things for a room."], "the schema is applied");
|
|
466
|
-
eq(m.embedder, EMBEDDER, "the manifest names its encoder");
|
|
571
|
+
eq([m.embedder, m.filter], [EMBEDDER, { owner: [PUB], repo: ["shop"] }], "the manifest names its encoder and its repo");
|
|
467
572
|
|
|
468
|
-
eq(
|
|
573
|
+
eq(await run(), {}, "no head moved → nothing read, nothing embedded");
|
|
469
574
|
eq(embedded.length, 3, "and the embedder was not called");
|
|
470
575
|
|
|
471
|
-
chain[`${PUB}/shop`].
|
|
472
|
-
|
|
576
|
+
chain[`${PUB}/shop`].records = [chain[`${PUB}/shop`].records[0],
|
|
577
|
+
rec("c2b", TAG, { sku: "b2", name: "Lamp", about: "brass reading lamp", price: 2 }, "c2")];
|
|
473
578
|
eq((await run())[d], { added: 1, removed: 2 }, "a changed record is a new CID; removed ones are dropped");
|
|
474
|
-
m =
|
|
579
|
+
m = manifestOf(out, d);
|
|
475
580
|
eq([m.count, m.shards.length, m.tombstones, readdirSync(`${out}/cdn/domains/${d}/shards`).length], [2, 1, [], 1],
|
|
476
581
|
"a removal compacts: the retracted rows' bytes are no longer served anywhere");
|
|
477
582
|
if (embedded.length !== 4) throw new Error("compaction must not re-embed");
|
|
478
|
-
chain[`${PUB}/shop`].
|
|
583
|
+
chain[`${PUB}/shop`].records[1] = rec("c2c", TAG, { sku: "b3", name: "Lamp", about: "steel reading lamp", price: 2 }, "c2");
|
|
479
584
|
eq((await run())[d], { added: 1, removed: 1 }, "a one-for-one replacement: same count, same types");
|
|
480
|
-
m =
|
|
585
|
+
m = manifestOf(out, d);
|
|
481
586
|
eq(m.shards.map((x) => x.file).sort(), readdirSync(`${out}/cdn/domains/${d}/shards`).sort(),
|
|
482
|
-
"and the manifest names the shards
|
|
483
|
-
chain[`${PUB}/shop`].
|
|
587
|
+
"and the manifest names the shards stored, not the ones compaction deleted");
|
|
588
|
+
chain[`${PUB}/shop`].records[1] = rec("c2b", TAG, { sku: "b2", name: "Lamp", about: "brass reading lamp", price: 2 }, "c2");
|
|
484
589
|
await run(); // back to the state the checks below expect
|
|
485
|
-
|
|
486
|
-
chain[`${PUB}/shop`].vertices.push({ cid: "c4", schemaId: TAG, payload: { sku: "d4", name: "Rug", about: "wool rug" } });
|
|
590
|
+
chain[`${PUB}/shop`].records.push(rec("c4", TAG, { sku: "d4", name: "Rug", about: "wool rug" }));
|
|
487
591
|
await run();
|
|
488
|
-
chain[`${PUB}/shop`].
|
|
489
|
-
|
|
490
|
-
eq([m.count, m.shards.length], [3, 2], "an addition alone is a delta shard");
|
|
592
|
+
chain[`${PUB}/shop`].records.pop();
|
|
593
|
+
eq([manifestOf(out, d).count, manifestOf(out, d).shards.length], [3, 2], "an addition alone is a delta shard");
|
|
491
594
|
await run();
|
|
492
|
-
m =
|
|
595
|
+
m = manifestOf(out, d);
|
|
493
596
|
|
|
494
597
|
// The real reader over HTTP: digests checked, tombstones honoured, the publisher's id resolves.
|
|
495
598
|
const srv = createServer((q, s) => { try { s.end(readFileSync(`${out}${decodeURIComponent(q.url)}`)); } catch { s.statusCode = 404; s.end(); } });
|
|
@@ -502,39 +605,89 @@ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv
|
|
|
502
605
|
const { rolesFrom } = await import("../core/roles.js");
|
|
503
606
|
eq(getRow(got, "b2", rolesFrom([m]))?.id, "c2b", "get by the publisher's own id, not the CID");
|
|
504
607
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
await
|
|
509
|
-
eq((
|
|
608
|
+
// An exclusion: the app stops presenting the repo, and its domain stops being served.
|
|
609
|
+
const shop = chain[`${PUB}/shop`];
|
|
610
|
+
delete chain[`${PUB}/shop`];
|
|
611
|
+
eq((await run())[d], { added: 0, removed: 2, dropped: true }, "a repo the app no longer presents is dropped");
|
|
612
|
+
eq([existsSync(`${out}/cdn/domains/${d}`), JSON.parse(readFileSync(`${out}/cdn/catalog`, "utf8")).domains], [false, []], "with its files and its catalog entry");
|
|
613
|
+
chain[`${PUB}/shop`] = shop;
|
|
614
|
+
eq((await run())[d], { added: 2, removed: 0 }, "and a restore brings it back");
|
|
615
|
+
|
|
616
|
+
const setEmbedder = (e) => { const x = manifestOf(out, d); x.embedder = e; x.head = "moved"; writeFileSync(`${out}/cdn/domains/${d}/manifest`, JSON.stringify(x)); };
|
|
617
|
+
setEmbedder({ ...EMBEDDER, runtime: "transformers.js cuda" });
|
|
618
|
+
if ((await run())[d]?.error) throw new Error("another runtime of the same q8 model must be accepted");
|
|
619
|
+
setEmbedder({ runtime: "fastembed", dtype: "fp32" });
|
|
620
|
+
if (!/not comparable/.test((await run())[d]?.error)) throw new Error("appending to another encoder's view must be refused");
|
|
621
|
+
|
|
622
|
+
// The encoder gives out partway (a free daily allowance): what it embedded is served, and
|
|
623
|
+
// the next run embeds only the rest, then takes the head.
|
|
624
|
+
const big = mkdtempSync(`${tmpdir()}/view-`), BIG = `${PUB}/big`;
|
|
625
|
+
chain[BIG] = { records: Array.from({ length: 80 }, (_, i) => ({ id: `r${i}`, cid: `big${i}`, type: "shop.item.v1", payload: { sku: `r${i}`, name: `Thing ${i}` } })) };
|
|
626
|
+
let budget = 40;
|
|
627
|
+
const capped = (ts) => (budget -= ts.length) < 0 ? Promise.reject(new Error("daily allowance used")) : Promise.all(ts.map(embed));
|
|
628
|
+
const bd = domainFor(APP, PUB, "big");
|
|
629
|
+
eq((await publishView({ fangorn, app: APP, out: big, repos: ["big"], embedBatch: capped, log: () => {} }))[bd],
|
|
630
|
+
{ added: 32, removed: 0, partial: true }, "an encoder that gives out keeps what it embedded");
|
|
631
|
+
eq([manifestOf(big, bd).count, manifestOf(big, bd).head], [32, null], "served, and the head not taken");
|
|
632
|
+
budget = 1e9;
|
|
633
|
+
eq((await publishView({ fangorn, app: APP, out: big, repos: ["big"], embedBatch: capped, log: () => {} }))[bd],
|
|
634
|
+
{ added: 48, removed: 0 }, "the next run embeds only the rest");
|
|
635
|
+
eq(manifestOf(big, bd).count, 80, "and serves all of it");
|
|
636
|
+
delete chain[BIG];
|
|
637
|
+
rmSync(big, { recursive: true, force: true });
|
|
638
|
+
eq((await publishView({ fangorn, app: APP, out, embed, rebake: true, log: () => {} }))[d],
|
|
510
639
|
{ added: 2, removed: 0 }, "--rebake starts the domain over");
|
|
511
640
|
eq(readdirSync(`${out}/cdn/domains/${d}/shards`).length, 1, "and leaves no orphaned shards");
|
|
512
641
|
rmSync(out, { recursive: true, force: true });
|
|
513
642
|
|
|
514
|
-
// Relations: a declared
|
|
515
|
-
// undeclared one
|
|
643
|
+
// Relations: a declared reference lands on its source row as the target's identity; an
|
|
644
|
+
// undeclared one is left alone; a target whose identity moves relinks the row without embedding it.
|
|
516
645
|
{
|
|
517
|
-
const T =
|
|
518
|
-
const rel = { [`${OWNER}/${
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
[`${PUB}/civic`]: {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
edges: [{ relation: "part_of", sourceCid: "i1", targetCid: "m1" }, { relation: "cites", sourceCid: "i2", targetCid: "m1" }] } };
|
|
646
|
+
const T = "civic.item.v1", M = "civic.matter.v1";
|
|
647
|
+
const rel = { [`${OWNER}/${SCHEMA_REPO}`]: { records: [
|
|
648
|
+
rec("ti", TYPE_TAG, { tag: T, role_map: { identity: "item_id", title: "heading", thread: "part_of" } }),
|
|
649
|
+
rec("tm", TYPE_TAG, { tag: M, role_map: { identity: "matter_id", title: "title" } }),
|
|
650
|
+
rec("tr", RELATION_TAG, { rel: "part_of", from: T, to: M })] },
|
|
651
|
+
[`${PUB}/civic`]: { records: [
|
|
652
|
+
rec("i1", T, { item_id: "a#1", heading: "Rezone, committee", part_of: { local: "m" } }),
|
|
653
|
+
rec("i2", T, { item_id: "b#4", heading: "Rezone, council", cites: { local: "m" } }),
|
|
654
|
+
rec("m1", M, { matter_id: "plover:7", title: "Rezone" }, "m")] } };
|
|
527
655
|
const o = mkdtempSync(`${tmpdir()}/view-`), dr = domainFor(APP, PUB, "civic");
|
|
528
|
-
const go = () => publishView({ fangorn: localFangorn(rel, { appId: APP, owner: OWNER }), app: APP,
|
|
529
|
-
const
|
|
656
|
+
const go = () => publishView({ fangorn: localFangorn(rel, { appId: APP, owner: OWNER }), app: APP, out: o, embed, log: () => {} });
|
|
657
|
+
const rows = async () => Object.fromEntries([...(await loadDomain(fsStore(o), `cdn/domains/${dr}`)).rows.values()]
|
|
658
|
+
.map((r) => [r.fields.heading ?? r.fields.title, r.fields.part_of ?? r.fields.cites ?? null]));
|
|
530
659
|
await go();
|
|
531
|
-
eq(
|
|
532
|
-
eq(
|
|
533
|
-
rel[`${PUB}/civic`].
|
|
660
|
+
eq(await rows(), { "Rezone, committee": "plover:7", "Rezone, council": { local: "m" }, Rezone: null }, "a declared reference carries the target's identity; an undeclared one is left alone");
|
|
661
|
+
eq(manifestOf(o, dr).role_map.thread, "part_of", "the thread role reaches the manifest");
|
|
662
|
+
rel[`${PUB}/civic`].records[2] = rec("m1b", M, { matter_id: "plover:8", title: "Rezone" }, "m");
|
|
534
663
|
const before = embedded.length;
|
|
535
|
-
eq((await go())[dr], { added:
|
|
536
|
-
eq([
|
|
664
|
+
eq((await go())[dr], { added: 1, removed: 1, relinked: 1 }, "a target whose identity moves relinks the row that points at it");
|
|
665
|
+
eq([(await rows())["Rezone, committee"], embedded.length - before], ["plover:8", 1], "without embedding it again");
|
|
537
666
|
rmSync(o, { recursive: true, force: true });
|
|
538
667
|
}
|
|
539
|
-
|
|
668
|
+
|
|
669
|
+
// The R2 store: the same four calls over a bucket's flat keys.
|
|
670
|
+
{
|
|
671
|
+
const objs = new Map();
|
|
672
|
+
const bucket = {
|
|
673
|
+
get: async (k) => objs.has(k) ? { arrayBuffer: async () => objs.get(k) } : null,
|
|
674
|
+
head: async (k) => objs.has(k) ? {} : null,
|
|
675
|
+
put: async (k, b) => { objs.set(k, typeof b === "string" ? new TextEncoder().encode(b) : b); },
|
|
676
|
+
delete: async (ks) => { for (const k of [ks].flat()) objs.delete(k); },
|
|
677
|
+
list: async ({ prefix, delimiter }) => {
|
|
678
|
+
const ks = [...objs.keys()].filter((k) => k.startsWith(prefix)).sort();
|
|
679
|
+
if (!delimiter) return { objects: ks.map((key) => ({ key })), truncated: false };
|
|
680
|
+
const deep = new Set(ks.filter((k) => k.slice(prefix.length).includes("/")).map((k) => prefix + k.slice(prefix.length).split("/")[0] + "/"));
|
|
681
|
+
return { objects: ks.filter((k) => !k.slice(prefix.length).includes("/")).map((key) => ({ key })), delimitedPrefixes: [...deep], truncated: false };
|
|
682
|
+
},
|
|
683
|
+
};
|
|
684
|
+
const r2 = r2Store(bucket);
|
|
685
|
+
const via = await publishView({ fangorn, app: APP, store: r2, embed, log: () => {} });
|
|
686
|
+
eq(Object.keys(via), [d], "a view builds into a bucket");
|
|
687
|
+
eq(await r2.list("cdn/domains"), [d], "list names a folder's children");
|
|
688
|
+
eq((await liveFields(r2)).length, 2, "and reads back");
|
|
689
|
+
await r2.del(`cdn/domains/${d}`);
|
|
690
|
+
eq([...objs.keys()].filter((k) => k.includes(d)), [], "del removes a folder and everything under it");
|
|
691
|
+
}
|
|
692
|
+
console.log("view.js self-check ok — domain names and embedded text match quickbeam's, the schema is applied, an unmoved head reads nothing, additions ship as delta shards, removals compact the domain, an excluded repo is dropped and a restored one returns, the real reader sees exactly the live records by the publisher's id, another encoder's view is refused, declared references land on their source rows, and the view builds the same into R2");
|
|
540
693
|
}
|