From e1385d6687f13fab03f18cf79926812d7cd07926 Mon Sep 17 00:00:00 2001 From: jxom <7336481+jxom@users.noreply.github.com> Date: Mon, 6 Apr 2026 17:42:39 +1000 Subject: [PATCH 1/8] wip --- package.json | 7 +- pnpm-lock.yaml | 823 +++++++++++++----- pnpm-workspace.yaml | 2 + src/components/guides/AccountsSignIn.tsx | 41 + .../guides/CreatePasskeyAccount.tsx | 90 -- src/components/guides/Demo.tsx | 56 +- src/components/guides/EmbedPasskeys.tsx | 3 +- .../guides/steps/wallet/AddFundsToWallet.tsx | 4 +- .../guides/steps/wallet/AddTokensToWallet.tsx | 4 +- .../guides/steps/wallet/SetFeeToken.tsx | 4 +- src/components/lib/wallets.ts | 15 +- src/pages/accounts/api/adapters.mdx | 28 + src/pages/accounts/api/ceremony.from.mdx | 47 + src/pages/accounts/api/ceremony.local.mdx | 32 + src/pages/accounts/api/ceremony.mdx | 8 + src/pages/accounts/api/ceremony.server.mdx | 25 + src/pages/accounts/api/dialog.iframe.mdx | 20 + src/pages/accounts/api/dialog.mdx | 105 +++ src/pages/accounts/api/dialog.popup.mdx | 27 + src/pages/accounts/api/dialogs.mdx | 23 + src/pages/accounts/api/expiry.mdx | 47 + src/pages/accounts/api/local.mdx | 59 ++ src/pages/accounts/api/provider.mdx | 183 ++++ src/pages/accounts/api/webAuthn.mdx | 63 ++ src/pages/accounts/faq.mdx | 46 + src/pages/accounts/index.mdx | 220 +++++ src/pages/accounts/production.mdx | 24 + .../accounts/rpc/eth_fillTransaction.mdx | 47 + .../accounts/rpc/eth_sendTransaction.mdx | 36 + .../accounts/rpc/eth_sendTransactionSync.mdx | 36 + src/pages/accounts/rpc/personal_sign.mdx | 40 + .../rpc/wallet_authorizeAccessKey.mdx | 53 ++ src/pages/accounts/rpc/wallet_connect.mdx | 54 ++ src/pages/accounts/rpc/wallet_disconnect.mdx | 30 + src/pages/accounts/rpc/wallet_getBalances.mdx | 45 + .../accounts/rpc/wallet_getCallsStatus.mdx | 39 + .../accounts/rpc/wallet_getCapabilities.mdx | 35 + .../accounts/rpc/wallet_revokeAccessKey.mdx | 40 + src/pages/accounts/rpc/wallet_sendCalls.mdx | 48 + src/pages/accounts/server/handler.compose.mdx | 54 ++ .../accounts/server/handler.feePayer.mdx | 69 ++ .../accounts/server/handler.webAuthn.mdx | 95 ++ .../server/index.mdx} | 45 +- src/pages/accounts/server/kv.mdx | 54 ++ src/pages/accounts/wagmi/index.mdx | 23 + src/pages/accounts/wagmi/tempoWallet.mdx | 49 ++ src/pages/accounts/wagmi/webAuthn.mdx | 42 + src/pages/guide/_template.mdx | 12 +- .../guide/issuance/create-a-stablecoin.mdx | 24 +- .../guide/issuance/distribute-rewards.mdx | 18 +- .../guide/issuance/manage-stablecoin.mdx | 42 +- src/pages/guide/issuance/mint-stablecoins.mdx | 18 +- src/pages/guide/issuance/use-for-fees.mdx | 6 +- src/pages/guide/machine-payments/client.mdx | 4 +- .../guide/payments/sponsor-user-fees.mdx | 45 +- .../stablecoin-dex/managing-fee-liquidity.mdx | 48 +- .../guide/use-accounts/embed-passkeys.mdx | 32 +- .../guide/use-accounts/embed-tempo-wallet.mdx | 309 +++++++ src/pages/sdk/typescript/index.mdx | 12 - .../sdk/typescript/server/handler.compose.mdx | 110 --- .../typescript/server/handler.feePayer.mdx | 117 --- .../typescript/server/handler.keyManager.mdx | 168 ---- src/snippets/unformatted/withFeePayer.ts | 12 +- src/snippets/wagmi.config.ts | 16 +- src/wagmi.config.ts | 49 +- vite.config.ts | 3 +- vocs.config.ts | 273 +++++- 67 files changed, 3281 insertions(+), 977 deletions(-) create mode 100644 src/components/guides/AccountsSignIn.tsx delete mode 100644 src/components/guides/CreatePasskeyAccount.tsx create mode 100644 src/pages/accounts/api/adapters.mdx create mode 100644 src/pages/accounts/api/ceremony.from.mdx create mode 100644 src/pages/accounts/api/ceremony.local.mdx create mode 100644 src/pages/accounts/api/ceremony.mdx create mode 100644 src/pages/accounts/api/ceremony.server.mdx create mode 100644 src/pages/accounts/api/dialog.iframe.mdx create mode 100644 src/pages/accounts/api/dialog.mdx create mode 100644 src/pages/accounts/api/dialog.popup.mdx create mode 100644 src/pages/accounts/api/dialogs.mdx create mode 100644 src/pages/accounts/api/expiry.mdx create mode 100644 src/pages/accounts/api/local.mdx create mode 100644 src/pages/accounts/api/provider.mdx create mode 100644 src/pages/accounts/api/webAuthn.mdx create mode 100644 src/pages/accounts/faq.mdx create mode 100644 src/pages/accounts/index.mdx create mode 100644 src/pages/accounts/production.mdx create mode 100644 src/pages/accounts/rpc/eth_fillTransaction.mdx create mode 100644 src/pages/accounts/rpc/eth_sendTransaction.mdx create mode 100644 src/pages/accounts/rpc/eth_sendTransactionSync.mdx create mode 100644 src/pages/accounts/rpc/personal_sign.mdx create mode 100644 src/pages/accounts/rpc/wallet_authorizeAccessKey.mdx create mode 100644 src/pages/accounts/rpc/wallet_connect.mdx create mode 100644 src/pages/accounts/rpc/wallet_disconnect.mdx create mode 100644 src/pages/accounts/rpc/wallet_getBalances.mdx create mode 100644 src/pages/accounts/rpc/wallet_getCallsStatus.mdx create mode 100644 src/pages/accounts/rpc/wallet_getCapabilities.mdx create mode 100644 src/pages/accounts/rpc/wallet_revokeAccessKey.mdx create mode 100644 src/pages/accounts/rpc/wallet_sendCalls.mdx create mode 100644 src/pages/accounts/server/handler.compose.mdx create mode 100644 src/pages/accounts/server/handler.feePayer.mdx create mode 100644 src/pages/accounts/server/handler.webAuthn.mdx rename src/pages/{sdk/typescript/server/handlers.mdx => accounts/server/index.mdx} (56%) create mode 100644 src/pages/accounts/server/kv.mdx create mode 100644 src/pages/accounts/wagmi/index.mdx create mode 100644 src/pages/accounts/wagmi/tempoWallet.mdx create mode 100644 src/pages/accounts/wagmi/webAuthn.mdx create mode 100644 src/pages/guide/use-accounts/embed-tempo-wallet.mdx delete mode 100644 src/pages/sdk/typescript/server/handler.compose.mdx delete mode 100644 src/pages/sdk/typescript/server/handler.feePayer.mdx delete mode 100644 src/pages/sdk/typescript/server/handler.keyManager.mdx diff --git a/package.json b/package.json index c9783e56..b45abda3 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@vercel/analytics": "^1.6.1", "@vercel/speed-insights": "^1.3.1", "abitype": "^1.2.3", + "accounts": "^0.4.20", "cva": "1.0.0-beta.4", "mermaid": "^11.12.2", "monaco-editor": "^0.55.1", @@ -33,10 +34,9 @@ "sql-formatter": "^15.7.0", "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.18", - "tempo.ts": "^0.14.0", "unplugin-auto-import": "^21.0.0", "unplugin-icons": "^23.0.1", - "viem": "^2.47.5", + "viem": "^2.47.10", "vocs": "https://pkg.pr.new/vocs@70a7c8c", "wagmi": "^3.5.0", "waku": "1.0.0-alpha.4", @@ -54,7 +54,8 @@ "tsx": "^4.21.0", "typescript": "^5.9.3", "use-sync-external-store": "^1.6.0", - "vite": "^7.3.1" + "vite": "^7.3.1", + "vite-plugin-mkcert": "^1.17.10" }, "devEngines": { "runtime": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0effa0eb..b38a48dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,6 +37,9 @@ importers: abitype: specifier: ^1.2.3 version: 1.2.3(typescript@5.9.3)(zod@4.3.5) + accounts: + specifier: ^0.4.20 + version: 0.4.20(@modelcontextprotocol/sdk@1.29.0(zod@4.3.5))(@types/react@19.2.9)(@wagmi/core@3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)))(express@5.2.1)(hono@4.11.5)(openapi-types@12.1.3)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)) cva: specifier: 1.0.0-beta.4 version: 1.0.0-beta.4(typescript@5.9.3) @@ -76,9 +79,6 @@ importers: tailwindcss: specifier: ^4.1.18 version: 4.1.18 - tempo.ts: - specifier: ^0.14.0 - version: 0.14.0(@remix-run/headers@0.17.2)(@remix-run/route-pattern@0.15.3)(@remix-run/session@0.4.1)(typescript@5.9.3)(viem@2.47.5(typescript@5.9.3)(zod@4.3.5))(zod@4.3.5) unplugin-auto-import: specifier: ^21.0.0 version: 21.0.0 @@ -86,17 +86,17 @@ importers: specifier: ^23.0.1 version: 23.0.1(@svgr/core@8.1.0(typescript@5.9.3)) viem: - specifier: ^2.47.5 - version: 2.47.5(typescript@5.9.3)(zod@4.3.5) + specifier: ^2.47.10 + version: 2.47.10(typescript@5.9.3)(zod@4.3.5) vocs: specifier: https://pkg.pr.new/vocs@70a7c8c - version: https://pkg.pr.new/vocs@70a7c8c(@types/react@19.2.9)(mermaid@11.12.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(rollup@4.56.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(waku@1.0.0-alpha.4(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + version: https://pkg.pr.new/vocs@70a7c8c(@types/react@19.2.9)(mermaid@11.12.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(rollup@4.56.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(waku@1.0.0-alpha.4(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) wagmi: specifier: ^3.5.0 - version: 3.5.0(@tanstack/query-core@5.90.19)(@tanstack/react-query@5.90.19(react@19.2.3))(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(viem@2.47.5(typescript@5.9.3)(zod@4.3.5)) + version: 3.5.0(@tanstack/query-core@5.90.19)(@tanstack/react-query@5.90.19(react@19.2.3))(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)) waku: specifier: 1.0.0-alpha.4 - version: 1.0.0-alpha.4(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + version: 1.0.0-alpha.4(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) zod: specifier: ^4.3.5 version: 4.3.5 @@ -121,7 +121,7 @@ importers: version: 7.0.0-dev.20260122.3 '@vitejs/plugin-react': specifier: ^5.1.2 - version: 5.1.2(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 5.1.2(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) anser: specifier: ^2.3.5 version: 2.3.5 @@ -139,7 +139,10 @@ importers: version: 1.6.0(react@19.2.3) vite: specifier: ^7.3.1 - version: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + version: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite-plugin-mkcert: + specifier: ^1.17.10 + version: 1.17.10(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) packages: @@ -149,10 +152,20 @@ packages: '@antfu/install-pkg@1.1.0': resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + '@apidevtools/json-schema-ref-parser@14.2.1': + resolution: {integrity: sha512-HmdFw9CDYqM6B25pqGBpNeLCKvGPlIx1EbLrVL0zPvj50CJQUHyBNBw45Muk0kEIkogo1VZvOKHajdMuAzSxRg==} + engines: {node: '>= 20'} + peerDependencies: + '@types/json-schema': ^7.0.15 + '@babel/code-frame@7.28.6': resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.28.6': resolution: {integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==} engines: {node: '>=6.9.0'} @@ -220,8 +233,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} '@babel/template@7.28.6': @@ -542,12 +555,22 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@hono/node-server@1.19.12': + resolution: {integrity: sha512-txsUW4SQ1iilgE0l9/e9VQWmELXifEFvmdA1j6WFh/aFPj99hIntrSsq/if0UWyGVkmrRPKA1wCeP+UCr1B9Uw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@hono/node-server@1.19.9': resolution: {integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==} engines: {node: '>=18.14.1'} peerDependencies: hono: ^4 + '@humanwhocodes/momoa@2.0.4': + resolution: {integrity: sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==} + engines: {node: '>=10.10.0'} + '@iconify-json/lucide@1.2.86': resolution: {integrity: sha512-W/Jz7/gGOkI9u43r+UHmQtZtcyw2YLvMwiHa01WV6V4DYltrPNXiD+bCa+djV8LZB1uwF8CiympOMIbgiQ74nA==} @@ -624,8 +647,8 @@ packages: '@mermaid-js/parser@0.6.3': resolution: {integrity: sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==} - '@modelcontextprotocol/sdk@1.25.3': - resolution: {integrity: sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==} + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -785,21 +808,36 @@ packages: peerDependencies: react: '>=16.8' - '@remix-run/fetch-router@0.12.0': - resolution: {integrity: sha512-BDG/VepZg2ZJ7wav3HDrB9ZJLpzZONHi9ItOkFMcKsrbm5g7jjrxW5Vdijbbebz12pbJQu6VKTwLVXp/LgFusA==} + '@readme/better-ajv-errors@2.4.0': + resolution: {integrity: sha512-9WODaOAKSl/mU+MYNZ2aHCrkoRSvmQ+1YkLj589OEqqjOAhbn8j7Z+ilYoiTu/he6X63/clsxxAB4qny9/dDzg==} + engines: {node: '>=18'} peerDependencies: - '@remix-run/headers': ^0.17.2 - '@remix-run/route-pattern': ^0.15.3 - '@remix-run/session': ^0.4.0 + ajv: 4.11.8 - 8 - '@remix-run/headers@0.17.2': - resolution: {integrity: sha512-IfHVCftsRKfk7kIQUxP9WDCe0OXj9X0lDRfFxk3CPcXJenBUEsYEPeBoW/YCZlKhdRWZjQlrofdk63lMSJmy8w==} + '@readme/openapi-parser@6.0.0': + resolution: {integrity: sha512-PaTnrKlKgEJZzjJ77AAhGe28NiyLBdiKMx95rJ9xlLZ8QLqYitMpPBQAKhsuEGOWQQbsIMfBZEPavbXghACQHA==} + engines: {node: '>=20'} + peerDependencies: + openapi-types: '>=7' + + '@readme/openapi-schemas@3.1.0': + resolution: {integrity: sha512-9FC/6ho8uFa8fV50+FPy/ngWN53jaUu4GRXlAjcxIRrzhltJnpKkBG2Tp0IDraFJeWrOpk84RJ9EMEEYzaI1Bw==} + engines: {node: '>=18'} + + '@remix-run/fetch-proxy@0.7.1': + resolution: {integrity: sha512-rPLfOpAaCXtm1dLI45uIPKERNbXbrh0P9AJc1sliz8pWd/McaFYjdr5KzB4QrFSfPvEt/Wmy6F2521qB1kK0ug==} + + '@remix-run/fetch-router@0.17.0': + resolution: {integrity: sha512-3FeJGrTqrKKCvZdQWijbCXTEHKcdttkLFbI2ogfpZ+iDYSNZ9036wgDXuuoZqg6d+D0E8Unhk5ZwrLKDCd/hOw==} + + '@remix-run/headers@0.19.0': + resolution: {integrity: sha512-+62NbkXuXm9r/NdG6KfH9OCKofCWm8VjkrVPICiHKtRl8Gf2Vi6eFTN4mGgBlZRhd5mmEVRV4hTIn/JUSHDAOw==} '@remix-run/node-fetch-server@0.13.0': resolution: {integrity: sha512-1EsNo0ZpgXu/90AWoRZf/oE3RVTUS80tiTUpt+hv5pjtAkw7icN4WskDwz/KdAw5ARbJLMhZBrO1NqThmy/McA==} - '@remix-run/route-pattern@0.15.3': - resolution: {integrity: sha512-7s4Oy9q6Oz9Vfwg0iZscpmYVASNG9fLqbCa+YY0+SWKksDpvCRiW46xp3S3zEvT7zEP7G55FKA+JdrqqK2AOXw==} + '@remix-run/route-pattern@0.19.0': + resolution: {integrity: sha512-RXKaIJ2Lx01uyZc0iw+yLzowFCa1/NuB8jN7QTo4QUe2CaUGtvPGdhgrTUp75lyNNCSJIrM9SaAJ6c1pjZdmoA==} '@remix-run/session@0.4.1': resolution: {integrity: sha512-Bm6aKYgutb/raHZ3laloz8g/Qu7f3CeK3o4gUVDMxtEiAdWCzJamwHoTpGOc5+g1Kuy7z85v4M6nGrF06MFDSg==} @@ -1246,6 +1284,9 @@ packages: peerDependencies: react: ^18 || ^19 + '@toon-format/toon@2.1.0': + resolution: {integrity: sha512-JwWptdF5eOA0HaQxbKAzkpQtR4wSWTEfDlEy/y3/4okmOAX1qwnpLZMmtEWr+ncAhTTY1raCKH0kteHhSXnQqg==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -1387,6 +1428,9 @@ packages: '@types/node@25.0.10': resolution: {integrity: sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==} + '@types/node@25.5.0': + resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} + '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: @@ -1629,6 +1673,20 @@ packages: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} + accounts@0.4.20: + resolution: {integrity: sha512-mDYAPqOGpsMpqCvorDrXNV4dSQ6DXYzX3V4k9N8bvRMJa2CvukxEcwRNjB5SNqDdQk0xi6rqjjgttrVa21S1mQ==} + peerDependencies: + '@wagmi/core': '>=2' + react: '>=18' + viem: '>=2.43.3' + peerDependenciesMeta: + '@wagmi/core': + optional: true + react: + optional: true + viem: + optional: true + acorn-import-phases@1.0.4: resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} engines: {node: '>=10.13.0'} @@ -1649,6 +1707,19 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -1670,8 +1741,8 @@ packages: peerDependencies: ajv: ^8.8.2 - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} anser@2.3.5: resolution: {integrity: sha512-vcZjxvvVoxTeR5XBNJB38oTu/7eDCZlwdz32N1eNgpyPF7j/Z7Idf+CUwQOkKKpJ7RJyjxgLHCM7vdIK0iCNMQ==} @@ -1686,6 +1757,12 @@ packages: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.14.0: + resolution: {integrity: sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==} + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -1785,6 +1862,10 @@ packages: collapse-white-space@2.1.0: resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -1831,8 +1912,8 @@ packages: core-js@3.48.0: resolution: {integrity: sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==} - cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} cose-base@1.0.3: @@ -2046,6 +2127,10 @@ packages: delaunator@5.0.1: resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -2095,8 +2180,8 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} - enhanced-resolve@5.18.4: - resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} + enhanced-resolve@5.20.1: + resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} entities@4.5.0: @@ -2121,6 +2206,10 @@ packages: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + es5-ext@0.10.64: resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} engines: {node: '>=0.10'} @@ -2236,8 +2325,8 @@ packages: resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} engines: {node: ^18.19.0 || >=20.5.0} - express-rate-limit@7.5.1: - resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} + express-rate-limit@8.3.2: + resolution: {integrity: sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==} engines: {node: '>= 16'} peerDependencies: express: '>= 4.11' @@ -2293,6 +2382,10 @@ packages: debug: optional: true + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + format@0.2.2: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} @@ -2365,6 +2458,10 @@ packages: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -2394,6 +2491,10 @@ packages: resolution: {integrity: sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g==} engines: {node: '>=16.9.0'} + hono@4.12.9: + resolution: {integrity: sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA==} + engines: {node: '>=16.9.0'} + html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} @@ -2417,6 +2518,9 @@ packages: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} + idb-keyval@6.2.2: + resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -2429,6 +2533,10 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} + incur@0.3.13: + resolution: {integrity: sha512-ypjWHtDSS8h6TPz+elg9cmQMe7gZu6YpUSAcv4HGIppdQ47VYHXZdho7P4I08CPSzz9VV4tVsWej2pfzXl8jgg==} + hasBin: true + inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -2446,6 +2554,10 @@ packages: resolution: {integrity: sha512-fn4bQ0Xq8FTej09YC/jqKZwtijpvARlRp6wxL5WTA6yPe2YWSJ5RJh7Nm79rK2qB0wr6iDQzH60XGq5V/7u8YQ==} deprecated: The Intersection Observer polyfill is no longer needed and can safely be removed. Intersection Observer has been Baseline since 2019. + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -2499,8 +2611,8 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - jose@6.1.3: - resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + jose@6.2.2: + resolution: {integrity: sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2531,6 +2643,10 @@ packages: engines: {node: '>=6'} hasBin: true + jsonpointer@5.0.1: + resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} + engines: {node: '>=0.10.0'} + katex@0.16.28: resolution: {integrity: sha512-YHzO7721WbmAL6Ov1uzN/l5mY5WWWhJBSW+jq4tkfZfsxmo1hu6frS0EOswvjBUnWE6NtjEs48SFn5CQESRLZg==} hasBin: true @@ -2548,6 +2664,10 @@ packages: layout-base@2.0.1: resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + lightningcss-android-arm64@1.30.2: resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} engines: {node: '>= 12.0.0'} @@ -2907,6 +3027,25 @@ packages: moo@0.5.2: resolution: {integrity: sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==} + mppx@0.5.5: + resolution: {integrity: sha512-HKGlnnLpRu6zXZCY17rbZNUC786aook9R5Eul5aafePAigpfK8ytlZ68QeRr11J21iR6je6rIztTk46qKcV79Q==} + hasBin: true + peerDependencies: + '@modelcontextprotocol/sdk': '>=1.25.0' + elysia: '>=1' + express: '>=5' + hono: '>=4' + viem: '>=2.47.5' + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + elysia: + optional: true + express: + optional: true + hono: + optional: true + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -3077,6 +3216,9 @@ packages: oniguruma-to-es@4.3.4: resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} + openapi-types@12.1.3: + resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} + outvariant@1.4.0: resolution: {integrity: sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==} @@ -3088,8 +3230,16 @@ packages: typescript: optional: true - ox@0.14.5: - resolution: {integrity: sha512-HgmHmBveYO40H/R3K6TMrwYtHsx/u6TAB+GpZlgJCoW0Sq5Ttpjih0IZZiwGQw7T6vdW4IAyobYrE2mdAvyF8Q==} + ox@0.14.10: + resolution: {integrity: sha512-PYsqEnSP7CrcxISS3uVBtw9yPy2gATAnWNptTI0pMnlrXLTiw0Xw/IIivJVHDFgGvKuRAtBSafhVjs+jis3CVA==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + ox@0.14.7: + resolution: {integrity: sha512-zSQ/cfBdolj7U4++NAvH7sI+VG0T3pEohITCgcQj8KlawvTDY4vGVhDT64Atsm0d6adWfIYHDpu88iUBMMp+AQ==} peerDependencies: typescript: '>=5.4.0' peerDependenciesMeta: @@ -3129,8 +3279,8 @@ packages: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} engines: {node: '>=12'} - path-to-regexp@8.3.0: - resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + path-to-regexp@8.4.1: + resolution: {integrity: sha512-fvU78fIjZ+SBM9YwCknCvKOUKkLVqtWDVctl0s7xIqfmfb38t2TT4ZU2gHm+Z8xGwgW+QWEU3oQSAzIbo89Ggw==} path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} @@ -3220,8 +3370,12 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - qs@6.14.1: - resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + qs@6.15.0: + resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} engines: {node: '>=0.6'} quansync@0.2.11: @@ -3237,9 +3391,6 @@ packages: resolution: {integrity: sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==} engines: {node: '>=0.12'} - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} @@ -3382,9 +3533,6 @@ packages: rw@1.3.3: resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -3406,9 +3554,6 @@ packages: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - serve-static@2.2.1: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} @@ -3544,8 +3689,8 @@ packages: tailwindcss@4.1.18: resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + tapable@2.3.2: + resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} tar@7.2.0: @@ -3553,16 +3698,8 @@ packages: engines: {node: '>=18'} deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me - tempo.ts@0.14.0: - resolution: {integrity: sha512-tyNg6pomYGqXpiRm0PDLwzOcifd//C9J+B+4rvbIHIwvwqxE1jres1YuaVSayo0JE0hzmXi/HZjJOsbSRdu+kg==} - peerDependencies: - viem: '>=2.43.3' - peerDependenciesMeta: - viem: - optional: true - - terser-webpack-plugin@5.3.16: - resolution: {integrity: sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==} + terser-webpack-plugin@5.4.0: + resolution: {integrity: sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==} engines: {node: '>= 10.13.0'} peerDependencies: '@swc/core': '*' @@ -3577,8 +3714,8 @@ packages: uglify-js: optional: true - terser@5.46.0: - resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} + terser@5.46.1: + resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==} engines: {node: '>=10'} hasBin: true @@ -3601,6 +3738,9 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + tokenx@1.3.0: + resolution: {integrity: sha512-NLdXTEZkKiO0gZuLtMoZKjCXTREXeZZt8nnnNeyoXtNZAfG/GKGSbQtLU5STspc0rMSwcA+UJfWZkbNU01iKmQ==} + toml@3.0.0: resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} @@ -3654,6 +3794,9 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + unicorn-magic@0.3.0: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} @@ -3783,8 +3926,8 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - viem@2.47.5: - resolution: {integrity: sha512-nVrJEQ8GL4JoVIrMBF3wwpTUZun0cpojfnOZ+96GtDWhqxZkVdy6vOEgu+jwfXqfTA/+wrR+YsN9TBQmhDUk0g==} + viem@2.47.10: + resolution: {integrity: sha512-D+l6SDDZWB5bh8u9hgICzMX2/egMrgEQ+Pef/QkZgmOl6bOTyCQMSgWAH8jZTWJ/218J9QNv7s/9BH6Wu5oPDg==} peerDependencies: typescript: '>=5.0.4' peerDependenciesMeta: @@ -3794,6 +3937,12 @@ packages: vite-plugin-arraybuffer@0.1.2: resolution: {integrity: sha512-KQLgCTnKJE25blJLvW8smUzhuTQyfcX1+aFqkTRKXpeMeqt6tX/AOGngdBd80oc6o0RX7bEsdaF48EQGXOIPWA==} + vite-plugin-mkcert@1.17.10: + resolution: {integrity: sha512-703hecAoGZYgNrkY76OIbo0M9j0tfGIIM6n7c0sYvhaczQMPwD0nFi+bS44d8kwdbCtV7885FYBWnTzhsaC7QQ==} + engines: {node: '>=v16.7.0'} + peerDependencies: + vite: '>=3' + vite-plugin-wasm@3.5.0: resolution: {integrity: sha512-X5VWgCnqiQEGb+omhlBVsvTfxikKtoOgAzQ95+BZ8gQ+VfMHIjSHr0wyvXFQCa0eKQ0fKyaL0kWcEnYqBac4lQ==} peerDependencies: @@ -3848,7 +3997,7 @@ packages: optional: true vocs@https://pkg.pr.new/vocs@70a7c8c: - resolution: {integrity: sha512-lAJHXJ4gAKQAwwFqpfReXLcEqHTArrOgZwqBga1X3oEOljzzCMXfngLYgOyqlRCKqAQMXiRbxQWMqcaBFKBRVw==, tarball: https://pkg.pr.new/vocs@70a7c8c} + resolution: {tarball: https://pkg.pr.new/vocs@70a7c8c} version: 0.0.0 hasBin: true peerDependencies: @@ -3918,8 +4067,11 @@ packages: web-vitals@4.2.4: resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} - webpack-sources@3.3.3: - resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} + webauthx@0.1.0: + resolution: {integrity: sha512-Z43YHetVeXdV5/4+YqKSz+cAflpbMmxSMz//kXEb2u3ZUqVbPG1zrM+Zp7KaME/QgUFGhGkAE2XHwqCAXnU75g==} + + webpack-sources@3.3.4: + resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} engines: {node: '>=10.13.0'} webpack-virtual-modules@0.6.2: @@ -3962,8 +4114,8 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} - yaml@2.8.2: - resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + yaml@2.8.3: + resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} engines: {node: '>= 14.6'} hasBin: true @@ -3974,14 +4126,17 @@ packages: zimmerframe@1.1.4: resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} - zod-to-json-schema@3.25.1: - resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} peerDependencies: - zod: ^3.25 || ^4 + zod: ^3.25.28 || ^4 zod@4.3.5: resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zustand@5.0.0: resolution: {integrity: sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==} engines: {node: '>=12.20.0'} @@ -4000,6 +4155,24 @@ packages: use-sync-external-store: optional: true + zustand@5.0.12: + resolution: {integrity: sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -4012,12 +4185,23 @@ snapshots: package-manager-detector: 1.6.0 tinyexec: 1.0.2 + '@apidevtools/json-schema-ref-parser@14.2.1(@types/json-schema@7.0.15)': + dependencies: + '@types/json-schema': 7.0.15 + js-yaml: 4.1.1 + '@babel/code-frame@7.28.6': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/compat-data@7.28.6': {} '@babel/core@7.28.6': @@ -4101,7 +4285,7 @@ snapshots: '@babel/core': 7.28.6 '@babel/helper-plugin-utils': 7.28.6 - '@babel/runtime@7.28.6': {} + '@babel/runtime@7.29.2': {} '@babel/template@7.28.6': dependencies: @@ -4128,7 +4312,7 @@ snapshots: '@base-ui/react@1.1.0(@types/react@19.2.9)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 '@base-ui/utils': 0.2.4(@types/react@19.2.9)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@floating-ui/react-dom': 2.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@floating-ui/utils': 0.2.10 @@ -4142,7 +4326,7 @@ snapshots: '@base-ui/utils@0.2.4(@types/react@19.2.9)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 '@floating-ui/utils': 0.2.10 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -4408,10 +4592,16 @@ snapshots: '@floating-ui/utils@0.2.10': {} + '@hono/node-server@1.19.12(hono@4.12.9)': + dependencies: + hono: 4.12.9 + '@hono/node-server@1.19.9(hono@4.11.5)': dependencies: hono: 4.11.5 + '@humanwhocodes/momoa@2.0.4': {} + '@iconify-json/lucide@1.2.86': dependencies: '@iconify/types': 2.0.0 @@ -4496,7 +4686,7 @@ snapshots: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 '@types/mdx': 2.0.13 - acorn: 8.15.0 + acorn: 8.16.0 collapse-white-space: 2.1.0 devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 @@ -4505,7 +4695,7 @@ snapshots: hast-util-to-jsx-runtime: 2.3.6 markdown-extensions: 2.0.0 recma-build-jsx: 1.0.0 - recma-jsx: 1.0.1(acorn@8.15.0) + recma-jsx: 1.0.1(acorn@8.16.0) recma-stringify: 1.0.0 rehype-recma: 1.0.0 remark-mdx: 3.1.1 @@ -4540,26 +4730,49 @@ snapshots: dependencies: langium: 3.3.1 - '@modelcontextprotocol/sdk@1.25.3(hono@4.11.5)(zod@4.3.5)': + '@modelcontextprotocol/sdk@1.29.0(zod@4.3.5)': dependencies: - '@hono/node-server': 1.19.9(hono@4.11.5) - ajv: 8.17.1 - ajv-formats: 3.0.1(ajv@8.17.1) + '@hono/node-server': 1.19.12(hono@4.12.9) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) content-type: 1.0.5 - cors: 2.8.5 + cors: 2.8.6 cross-spawn: 7.0.6 eventsource: 3.0.7 eventsource-parser: 3.0.6 express: 5.2.1 - express-rate-limit: 7.5.1(express@5.2.1) - jose: 6.1.3 + express-rate-limit: 8.3.2(express@5.2.1) + hono: 4.12.9 + jose: 6.2.2 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 zod: 4.3.5 - zod-to-json-schema: 3.25.1(zod@4.3.5) + zod-to-json-schema: 3.25.2(zod@4.3.5) + transitivePeerDependencies: + - supports-color + optional: true + + '@modelcontextprotocol/sdk@1.29.0(zod@4.3.6)': + dependencies: + '@hono/node-server': 1.19.12(hono@4.12.9) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.3.2(express@5.2.1) + hono: 4.12.9 + jose: 6.2.2 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.3.6 + zod-to-json-schema: 3.25.2(zod@4.3.6) transitivePeerDependencies: - - hono - supports-color '@monaco-editor/loader@1.7.0': @@ -4706,17 +4919,42 @@ snapshots: dependencies: react: 19.2.3 - '@remix-run/fetch-router@0.12.0(@remix-run/headers@0.17.2)(@remix-run/route-pattern@0.15.3)(@remix-run/session@0.4.1)': + '@readme/better-ajv-errors@2.4.0(ajv@8.18.0)': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/runtime': 7.29.2 + '@humanwhocodes/momoa': 2.0.4 + ajv: 8.18.0 + jsonpointer: 5.0.1 + leven: 3.1.0 + picocolors: 1.1.1 + + '@readme/openapi-parser@6.0.0(openapi-types@12.1.3)': + dependencies: + '@apidevtools/json-schema-ref-parser': 14.2.1(@types/json-schema@7.0.15) + '@readme/better-ajv-errors': 2.4.0(ajv@8.18.0) + '@readme/openapi-schemas': 3.1.0 + '@types/json-schema': 7.0.15 + ajv: 8.18.0 + ajv-draft-04: 1.0.0(ajv@8.18.0) + openapi-types: 12.1.3 + + '@readme/openapi-schemas@3.1.0': {} + + '@remix-run/fetch-proxy@0.7.1': dependencies: - '@remix-run/headers': 0.17.2 - '@remix-run/route-pattern': 0.15.3 + '@remix-run/headers': 0.19.0 + + '@remix-run/fetch-router@0.17.0': + dependencies: + '@remix-run/route-pattern': 0.19.0 '@remix-run/session': 0.4.1 - '@remix-run/headers@0.17.2': {} + '@remix-run/headers@0.19.0': {} '@remix-run/node-fetch-server@0.13.0': {} - '@remix-run/route-pattern@0.15.3': {} + '@remix-run/route-pattern@0.19.0': {} '@remix-run/session@0.4.1': {} @@ -4957,7 +5195,7 @@ snapshots: '@tailwindcss/node@4.1.18': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.18.4 + enhanced-resolve: 5.20.1 jiti: 2.6.1 lightningcss: 1.30.2 magic-string: 0.30.21 @@ -5015,12 +5253,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 - '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@tailwindcss/node': 4.1.18 '@tailwindcss/oxide': 4.1.18 tailwindcss: 4.1.18 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) '@takumi-rs/core-darwin-arm64@0.62.8': optional: true @@ -5074,6 +5312,8 @@ snapshots: '@tanstack/query-core': 5.90.19 react: 19.2.3 + '@toon-format/toon@2.1.0': {} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.28.6 @@ -5252,6 +5492,10 @@ snapshots: dependencies: undici-types: 7.16.0 + '@types/node@25.5.0': + dependencies: + undici-types: 7.18.2 + '@types/react-dom@19.2.3(@types/react@19.2.9)': dependencies: '@types/react': 19.2.9 @@ -5315,7 +5559,7 @@ snapshots: optionalDependencies: react: 19.2.3 - '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@babel/core': 7.28.6 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.6) @@ -5323,11 +5567,11 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.53 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color - '@vitejs/plugin-rsc@0.5.21(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + '@vitejs/plugin-rsc@0.5.21(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.5 es-module-lexer: 2.0.0 @@ -5339,23 +5583,23 @@ snapshots: srvx: 0.11.12 strip-literal: 3.1.0 turbo-stream: 3.1.0 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - vitefu: 1.1.1(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vitefu: 1.1.1(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) optionalDependencies: react-server-dom-webpack: 19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1) - '@wagmi/connectors@7.2.1(@wagmi/core@3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.47.5(typescript@5.9.3)(zod@4.3.5)))(typescript@5.9.3)(viem@2.47.5(typescript@5.9.3)(zod@4.3.5))': + '@wagmi/connectors@7.2.1(@wagmi/core@3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)))(typescript@5.9.3)(viem@2.47.10(typescript@5.9.3)(zod@4.3.5))': dependencies: - '@wagmi/core': 3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))(viem@2.47.5(typescript@5.9.3)(zod@4.3.5)) - viem: 2.47.5(typescript@5.9.3)(zod@4.3.5) + '@wagmi/core': 3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)) + viem: 2.47.10(typescript@5.9.3)(zod@4.3.5) optionalDependencies: typescript: 5.9.3 - '@wagmi/core@3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))(viem@2.47.5(typescript@5.9.3)(zod@4.3.5))': + '@wagmi/core@3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5))': dependencies: eventemitter3: 5.0.1 mipd: 0.0.7(typescript@5.9.3) - viem: 2.47.5(typescript@5.9.3)(zod@4.3.5) + viem: 2.47.10(typescript@5.9.3)(zod@4.3.5) zustand: 5.0.0(@types/react@19.2.9)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)) optionalDependencies: '@tanstack/query-core': 5.90.19 @@ -5452,39 +5696,78 @@ snapshots: typescript: 5.9.3 zod: 4.3.5 + abitype@1.2.3(typescript@5.9.3)(zod@4.3.6): + optionalDependencies: + typescript: 5.9.3 + zod: 4.3.6 + accepts@2.0.0: dependencies: mime-types: 3.0.2 negotiator: 1.0.0 - acorn-import-phases@1.0.4(acorn@8.15.0): + accounts@0.4.20(@modelcontextprotocol/sdk@1.29.0(zod@4.3.5))(@types/react@19.2.9)(@wagmi/core@3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)))(express@5.2.1)(hono@4.11.5)(openapi-types@12.1.3)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)): dependencies: - acorn: 8.15.0 + '@remix-run/fetch-router': 0.17.0 + idb-keyval: 6.2.2 + mipd: 0.0.7(typescript@5.9.3) + mppx: 0.5.5(@modelcontextprotocol/sdk@1.29.0(zod@4.3.5))(express@5.2.1)(hono@4.11.5)(openapi-types@12.1.3)(typescript@5.9.3)(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)) + ox: 0.14.10(typescript@5.9.3)(zod@4.3.6) + tsx: 4.21.0 + webauthx: 0.1.0(typescript@5.9.3)(zod@4.3.6) + zod: 4.3.6 + zustand: 5.0.12(@types/react@19.2.9)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)) + optionalDependencies: + '@wagmi/core': 3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)) + react: 19.2.3 + viem: 2.47.10(typescript@5.9.3)(zod@4.3.5) + transitivePeerDependencies: + - '@cfworker/json-schema' + - '@modelcontextprotocol/sdk' + - '@types/react' + - elysia + - express + - hono + - immer + - openapi-types + - supports-color + - typescript + - use-sync-external-store - acorn-jsx@5.3.2(acorn@8.15.0): + acorn-import-phases@1.0.4(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 + + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 acorn-loose@8.5.2: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 acorn@8.15.0: {} - ajv-formats@2.1.1(ajv@8.17.1): + acorn@8.16.0: {} + + ajv-draft-04@1.0.0(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv-formats@2.1.1(ajv@8.18.0): optionalDependencies: - ajv: 8.17.1 + ajv: 8.18.0 - ajv-formats@3.0.1(ajv@8.17.1): + ajv-formats@3.0.1(ajv@8.18.0): optionalDependencies: - ajv: 8.17.1 + ajv: 8.18.0 - ajv-keywords@5.1.0(ajv@8.17.1): + ajv-keywords@5.1.0(ajv@8.18.0): dependencies: - ajv: 8.17.1 + ajv: 8.18.0 fast-deep-equal: 3.1.3 - ajv@8.17.1: + ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 fast-uri: 3.1.0 @@ -5499,6 +5782,16 @@ snapshots: astring@1.9.0: {} + asynckit@0.4.0: {} + + axios@1.14.0(debug@4.4.3): + dependencies: + follow-redirects: 1.15.11(debug@4.4.3) + form-data: 4.0.5 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + bail@2.0.2: {} base64-js@1.5.1: {} @@ -5513,7 +5806,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 - qs: 6.14.1 + qs: 6.15.0 raw-body: 3.0.2 type-is: 2.0.1 transitivePeerDependencies: @@ -5594,6 +5887,10 @@ snapshots: collapse-white-space@2.1.0: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} commander@2.20.3: {} @@ -5620,7 +5917,7 @@ snapshots: core-js@3.48.0: {} - cors@2.8.5: + cors@2.8.6: dependencies: object-assign: 4.1.1 vary: 1.1.2 @@ -5861,6 +6158,8 @@ snapshots: dependencies: robust-predicates: 3.0.2 + delayed-stream@1.0.0: {} + depd@2.0.0: {} dequal@2.0.3: {} @@ -5902,10 +6201,10 @@ snapshots: encodeurl@2.0.0: {} - enhanced-resolve@5.18.4: + enhanced-resolve@5.20.1: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.0 + tapable: 2.3.2 entities@4.5.0: {} @@ -5923,6 +6222,13 @@ snapshots: dependencies: es-errors: 1.3.0 + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + es5-ext@0.10.64: dependencies: es6-iterator: 2.0.3 @@ -5951,7 +6257,7 @@ snapshots: esast-util-from-js@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 - acorn: 8.15.0 + acorn: 8.16.0 esast-util-from-estree: 2.0.0 vfile-message: 4.0.3 @@ -6087,9 +6393,10 @@ snapshots: strip-final-newline: 4.0.0 yoctocolors: 2.1.2 - express-rate-limit@7.5.1(express@5.2.1): + express-rate-limit@8.3.2(express@5.2.1): dependencies: express: 5.2.1 + ip-address: 10.1.0 express@5.2.1: dependencies: @@ -6113,7 +6420,7 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.14.1 + qs: 6.15.0 range-parser: 1.2.1 router: 2.2.0 send: 1.2.1 @@ -6161,7 +6468,17 @@ snapshots: transitivePeerDependencies: - supports-color - follow-redirects@1.15.11: {} + follow-redirects@1.15.11(debug@4.4.3): + optionalDependencies: + debug: 4.4.3 + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 format@0.2.2: {} @@ -6222,6 +6539,10 @@ snapshots: has-symbols@1.1.0: {} + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -6299,6 +6620,8 @@ snapshots: hono@4.11.5: {} + hono@4.12.9: {} + html-void-elements@3.0.0: {} http-errors@2.0.1: @@ -6312,7 +6635,7 @@ snapshots: http-proxy@1.18.1: dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.11 + follow-redirects: 1.15.11(debug@4.4.3) requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -6327,6 +6650,8 @@ snapshots: dependencies: safer-buffer: 2.1.2 + idb-keyval@6.2.2: {} + ieee754@1.2.1: {} image-size@2.0.2: {} @@ -6336,6 +6661,19 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 + incur@0.3.13(openapi-types@12.1.3): + dependencies: + '@modelcontextprotocol/sdk': 1.29.0(zod@4.3.6) + '@readme/openapi-parser': 6.0.0(openapi-types@12.1.3) + '@toon-format/toon': 2.1.0 + tokenx: 1.3.0 + yaml: 2.8.3 + zod: 4.3.6 + transitivePeerDependencies: + - '@cfworker/json-schema' + - openapi-types + - supports-color + inherits@2.0.4: {} inline-style-parser@0.2.7: {} @@ -6346,6 +6684,8 @@ snapshots: intersection-observer@0.10.0: {} + ip-address@10.1.0: {} + ipaddr.js@1.9.1: {} is-alphabetical@2.0.1: {} @@ -6381,13 +6721,13 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 25.0.10 + '@types/node': 25.5.0 merge-stream: 2.0.0 supports-color: 8.1.1 jiti@2.6.1: {} - jose@6.1.3: {} + jose@6.2.2: {} js-tokens@4.0.0: {} @@ -6407,6 +6747,8 @@ snapshots: json5@2.2.3: {} + jsonpointer@5.0.1: {} + katex@0.16.28: dependencies: commander: 8.3.0 @@ -6425,6 +6767,8 @@ snapshots: layout-base@2.0.1: {} + leven@3.1.0: {} + lightningcss-android-arm64@1.30.2: optional: true @@ -6869,8 +7213,8 @@ snapshots: micromark-extension-mdxjs@3.0.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) micromark-extension-mdx-expression: 3.0.1 micromark-extension-mdx-jsx: 3.0.2 micromark-extension-mdx-md: 2.0.0 @@ -7042,7 +7386,7 @@ snapshots: mlly@1.8.0: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 pathe: 2.0.3 pkg-types: 1.3.1 ufo: 1.6.3 @@ -7054,6 +7398,24 @@ snapshots: moo@0.5.2: {} + mppx@0.5.5(@modelcontextprotocol/sdk@1.29.0(zod@4.3.5))(express@5.2.1)(hono@4.11.5)(openapi-types@12.1.3)(typescript@5.9.3)(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)): + dependencies: + '@remix-run/fetch-proxy': 0.7.1 + '@remix-run/node-fetch-server': 0.13.0 + incur: 0.3.13(openapi-types@12.1.3) + ox: 0.14.7(typescript@5.9.3)(zod@4.3.6) + viem: 2.47.10(typescript@5.9.3)(zod@4.3.5) + zod: 4.3.6 + optionalDependencies: + '@modelcontextprotocol/sdk': 1.29.0(zod@4.3.5) + express: 5.2.1 + hono: 4.11.5 + transitivePeerDependencies: + - '@cfworker/json-schema' + - openapi-types + - supports-color + - typescript + ms@2.1.3: {} mz@2.7.0: @@ -7118,6 +7480,8 @@ snapshots: regex: 6.1.0 regex-recursion: 6.0.2 + openapi-types@12.1.3: {} + outvariant@1.4.0: {} ox@0.11.3(typescript@5.9.3)(zod@4.3.5): @@ -7135,7 +7499,22 @@ snapshots: transitivePeerDependencies: - zod - ox@0.14.5(typescript@5.9.3)(zod@4.3.5): + ox@0.14.10(typescript@5.9.3)(zod@4.3.6): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@4.3.6) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + + ox@0.14.7(typescript@5.9.3)(zod@4.3.5): dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 @@ -7150,6 +7529,21 @@ snapshots: transitivePeerDependencies: - zod + ox@0.14.7(typescript@5.9.3)(zod@4.3.6): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@4.3.6) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + package-manager-detector@1.6.0: {} parent-module@1.0.1: @@ -7168,7 +7562,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.28.6 + '@babel/code-frame': 7.29.0 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -7183,7 +7577,7 @@ snapshots: path-key@4.0.0: {} - path-to-regexp@8.3.0: {} + path-to-regexp@8.4.1: {} path-type@4.0.0: {} @@ -7295,7 +7689,9 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - qs@6.14.1: + proxy-from-env@2.1.0: {} + + qs@6.15.0: dependencies: side-channel: 1.1.0 @@ -7310,10 +7706,6 @@ snapshots: discontinuous-range: 1.0.0 ret: 0.1.15 - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - range-parser@1.2.1: {} raw-body@3.0.2: @@ -7347,7 +7739,7 @@ snapshots: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) webpack: 5.104.1 - webpack-sources: 3.3.3 + webpack-sources: 3.3.4 react@19.2.3: {} @@ -7357,10 +7749,10 @@ snapshots: estree-util-build-jsx: 3.0.1 vfile: 6.0.3 - recma-jsx@1.0.1(acorn@8.15.0): + recma-jsx@1.0.1(acorn@8.16.0): dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) estree-util-to-js: 2.0.0 recma-parse: 1.0.0 recma-stringify: 1.0.0 @@ -7457,7 +7849,7 @@ snapshots: toml: 3.0.0 unified: 11.0.5 unist-util-mdx-define: 1.1.2 - yaml: 2.8.2 + yaml: 2.8.3 remark-mdx@3.1.1: dependencies: @@ -7547,7 +7939,7 @@ snapshots: depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 - path-to-regexp: 8.3.0 + path-to-regexp: 8.4.1 transitivePeerDependencies: - supports-color @@ -7555,8 +7947,6 @@ snapshots: rw@1.3.3: {} - safe-buffer@5.2.1: {} - safer-buffer@2.1.2: {} scheduler@0.27.0: {} @@ -7564,9 +7954,9 @@ snapshots: schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - ajv-keywords: 5.1.0(ajv@8.17.1) + ajv: 8.18.0 + ajv-formats: 2.1.1(ajv@8.18.0) + ajv-keywords: 5.1.0(ajv@8.18.0) scule@1.3.0: {} @@ -7588,10 +7978,6 @@ snapshots: transitivePeerDependencies: - supports-color - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 - serve-static@2.2.1: dependencies: encodeurl: 2.0.0 @@ -7742,7 +8128,7 @@ snapshots: tailwindcss@4.1.18: {} - tapable@2.3.0: {} + tapable@2.3.2: {} tar@7.2.0: dependencies: @@ -7753,32 +8139,18 @@ snapshots: mkdirp: 3.0.1 yallist: 5.0.0 - tempo.ts@0.14.0(@remix-run/headers@0.17.2)(@remix-run/route-pattern@0.15.3)(@remix-run/session@0.4.1)(typescript@5.9.3)(viem@2.47.5(typescript@5.9.3)(zod@4.3.5))(zod@4.3.5): - dependencies: - '@remix-run/fetch-router': 0.12.0(@remix-run/headers@0.17.2)(@remix-run/route-pattern@0.15.3)(@remix-run/session@0.4.1) - ox: 0.11.3(typescript@5.9.3)(zod@4.3.5) - optionalDependencies: - viem: 2.47.5(typescript@5.9.3)(zod@4.3.5) - transitivePeerDependencies: - - '@remix-run/headers' - - '@remix-run/route-pattern' - - '@remix-run/session' - - typescript - - zod - - terser-webpack-plugin@5.3.16(webpack@5.104.1): + terser-webpack-plugin@5.4.0(webpack@5.104.1): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 - serialize-javascript: 6.0.2 - terser: 5.46.0 + terser: 5.46.1 webpack: 5.104.1 - terser@5.46.0: + terser@5.46.1: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 + acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -7799,6 +8171,8 @@ snapshots: toidentifier@1.0.1: {} + tokenx@1.3.0: {} + toml@3.0.0: {} trim-lines@3.0.1: {} @@ -7844,6 +8218,8 @@ snapshots: undici-types@7.16.0: {} + undici-types@7.18.2: {} + unicorn-magic@0.3.0: {} unified@11.0.5: @@ -7985,7 +8361,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - viem@2.47.5(typescript@5.9.3)(zod@4.3.5): + viem@2.47.10(typescript@5.9.3)(zod@4.3.5): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 @@ -7993,7 +8369,7 @@ snapshots: '@scure/bip39': 1.6.0 abitype: 1.2.3(typescript@5.9.3)(zod@4.3.5) isows: 1.0.7(ws@8.18.3) - ox: 0.14.5(typescript@5.9.3)(zod@4.3.5) + ox: 0.14.7(typescript@5.9.3)(zod@4.3.5) ws: 8.18.3 optionalDependencies: typescript: 5.9.3 @@ -8004,11 +8380,20 @@ snapshots: vite-plugin-arraybuffer@0.1.2: {} - vite-plugin-wasm@3.5.0(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): + vite-plugin-mkcert@1.17.10(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + axios: 1.14.0(debug@4.4.3) + debug: 4.4.3 + picocolors: 1.1.1 + vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + transitivePeerDependencies: + - supports-color + + vite-plugin-wasm@3.5.0(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): + vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.3) @@ -8021,15 +8406,15 @@ snapshots: fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.30.2 - terser: 5.46.0 + terser: 5.46.1 tsx: 4.21.0 - yaml: 2.8.2 + yaml: 2.8.3 - vitefu@1.1.1(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): + vitefu@1.1.1(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): optionalDependencies: - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vocs@https://pkg.pr.new/vocs@70a7c8c(@types/react@19.2.9)(mermaid@11.12.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(rollup@4.56.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(waku@1.0.0-alpha.4(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): + vocs@https://pkg.pr.new/vocs@70a7c8c(@types/react@19.2.9)(mermaid@11.12.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(rollup@4.56.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(waku@1.0.0-alpha.4(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@base-ui/react': 1.1.0(@types/react@19.2.9)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@codesandbox/sandpack-react': 2.20.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -8041,7 +8426,7 @@ snapshots: '@mdx-js/mdx': 3.1.1 '@mdx-js/react': 3.1.1(@types/react@19.2.9)(react@19.2.3) '@mdx-js/rollup': 3.1.1(rollup@4.56.0) - '@modelcontextprotocol/sdk': 1.25.3(hono@4.11.5)(zod@4.3.5) + '@modelcontextprotocol/sdk': 1.29.0(zod@4.3.6) '@remix-run/node-fetch-server': 0.13.0 '@shikijs/rehype': 3.21.0 '@shikijs/transformers': 3.21.0 @@ -8049,11 +8434,11 @@ snapshots: '@shikijs/types': 3.21.0 '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) - '@tailwindcss/vite': 4.1.18(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@tailwindcss/vite': 4.1.18(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@takumi-rs/image-response': 0.62.8 '@takumi-rs/wasm': 0.62.8 - '@vitejs/plugin-react': 5.1.2(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) - '@vitejs/plugin-rsc': 0.5.21(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@vitejs/plugin-react': 5.1.2(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitejs/plugin-rsc': 0.5.21(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) cac: 6.7.14 cva: class-variance-authority@0.7.1 debug: 4.4.3 @@ -8062,7 +8447,7 @@ snapshots: estree-util-visit: 2.0.0 extend: 3.0.2 github-slugger: 2.0.0 - hono: 4.11.5 + hono: 4.12.9 image-size: 2.0.2 mdast-util-from-markdown: 2.0.2 mdast-util-gfm: 3.1.0 @@ -8099,13 +8484,13 @@ snapshots: urlpattern-polyfill: 10.1.0 vfile: 6.0.3 vite-plugin-arraybuffer: 0.1.2 - vite-plugin-wasm: 3.5.0(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) - yaml: 2.8.2 - zod: 4.3.5 + vite-plugin-wasm: 3.5.0(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + yaml: 2.8.3 + zod: 4.3.6 optionalDependencies: mermaid: 11.12.2 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - waku: 1.0.0-alpha.4(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + waku: 1.0.0-alpha.4(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - '@cfworker/json-schema' - '@remix-run/react' @@ -8143,14 +8528,14 @@ snapshots: w3c-keyname@2.2.8: {} - wagmi@3.5.0(@tanstack/query-core@5.90.19)(@tanstack/react-query@5.90.19(react@19.2.3))(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(viem@2.47.5(typescript@5.9.3)(zod@4.3.5)): + wagmi@3.5.0(@tanstack/query-core@5.90.19)(@tanstack/react-query@5.90.19(react@19.2.3))(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)): dependencies: '@tanstack/react-query': 5.90.19(react@19.2.3) - '@wagmi/connectors': 7.2.1(@wagmi/core@3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.47.5(typescript@5.9.3)(zod@4.3.5)))(typescript@5.9.3)(viem@2.47.5(typescript@5.9.3)(zod@4.3.5)) - '@wagmi/core': 3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))(viem@2.47.5(typescript@5.9.3)(zod@4.3.5)) + '@wagmi/connectors': 7.2.1(@wagmi/core@3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)))(typescript@5.9.3)(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)) + '@wagmi/core': 3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)) react: 19.2.3 use-sync-external-store: 1.4.0(react@19.2.3) - viem: 2.47.5(typescript@5.9.3)(zod@4.3.5) + viem: 2.47.10(typescript@5.9.3)(zod@4.3.5) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -8166,11 +8551,11 @@ snapshots: - ox - porto - waku@1.0.0-alpha.4(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): + waku@1.0.0-alpha.4(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: '@hono/node-server': 1.19.9(hono@4.11.5) - '@vitejs/plugin-react': 5.1.2(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) - '@vitejs/plugin-rsc': 0.5.21(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@vitejs/plugin-react': 5.1.2(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitejs/plugin-rsc': 0.5.21(react-dom@19.2.3(react@19.2.3))(react-server-dom-webpack@19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1))(react@19.2.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) dotenv: 17.3.1 hono: 4.11.5 magic-string: 0.30.21 @@ -8179,7 +8564,7 @@ snapshots: react-dom: 19.2.3(react@19.2.3) react-server-dom-webpack: 19.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.104.1) rsc-html-stream: 0.0.7 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - '@types/node' - jiti @@ -8201,7 +8586,14 @@ snapshots: web-vitals@4.2.4: {} - webpack-sources@3.3.3: {} + webauthx@0.1.0(typescript@5.9.3)(zod@4.3.6): + dependencies: + ox: 0.14.10(typescript@5.9.3)(zod@4.3.6) + transitivePeerDependencies: + - typescript + - zod + + webpack-sources@3.3.4: {} webpack-virtual-modules@0.6.2: {} @@ -8213,11 +8605,11 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - acorn-import-phases: 1.0.4(acorn@8.15.0) + acorn: 8.16.0 + acorn-import-phases: 1.0.4(acorn@8.16.0) browserslist: 4.28.1 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.4 + enhanced-resolve: 5.20.1 es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 @@ -8228,10 +8620,10 @@ snapshots: mime-types: 2.1.35 neo-async: 2.6.2 schema-utils: 4.3.3 - tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(webpack@5.104.1) + tapable: 2.3.2 + terser-webpack-plugin: 5.4.0(webpack@5.104.1) watchpack: 2.5.1 - webpack-sources: 3.3.3 + webpack-sources: 3.3.4 transitivePeerDependencies: - '@swc/core' - esbuild @@ -8249,22 +8641,35 @@ snapshots: yallist@5.0.0: {} - yaml@2.8.2: {} + yaml@2.8.3: {} yoctocolors@2.1.2: {} zimmerframe@1.1.4: {} - zod-to-json-schema@3.25.1(zod@4.3.5): + zod-to-json-schema@3.25.2(zod@4.3.5): dependencies: zod: 4.3.5 + optional: true + + zod-to-json-schema@3.25.2(zod@4.3.6): + dependencies: + zod: 4.3.6 zod@4.3.5: {} + zod@4.3.6: {} + zustand@5.0.0(@types/react@19.2.9)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)): optionalDependencies: '@types/react': 19.2.9 react: 19.2.3 use-sync-external-store: 1.6.0(react@19.2.3) + zustand@5.0.12(@types/react@19.2.9)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)): + optionalDependencies: + '@types/react': 19.2.9 + react: 19.2.3 + use-sync-external-store: 1.6.0(react@19.2.3) + zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 90eddccc..f3b4405e 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -3,3 +3,5 @@ patchedDependencies: dayjs@1.11.19: patches/dayjs@1.11.19.patch minimumReleaseAge: 1440 +minimumReleaseAgeExclude: + - accounts diff --git a/src/components/guides/AccountsSignIn.tsx b/src/components/guides/AccountsSignIn.tsx new file mode 100644 index 00000000..5c0e9682 --- /dev/null +++ b/src/components/guides/AccountsSignIn.tsx @@ -0,0 +1,41 @@ +'use client' +import { useConnect, useConnection, useConnectors, useDisconnect } from 'wagmi' +import { Button } from './Demo' + +export function AccountsSignIn() { + const account = useConnection() + const connect = useConnect() + const disconnect = useDisconnect() + const connector = useTempoWalletConnector() + + if (!connector) return null + + if (account.address) + return ( +
+ +
+ ) + + if (connect.isPending) + return ( +
+ +
+ ) + + return ( +
+ +
+ ) +} + +function useTempoWalletConnector() { + const connectors = useConnectors() + return connectors.find((c) => c.id === 'xyz.tempo') +} diff --git a/src/components/guides/CreatePasskeyAccount.tsx b/src/components/guides/CreatePasskeyAccount.tsx deleted file mode 100644 index a5882cc4..00000000 --- a/src/components/guides/CreatePasskeyAccount.tsx +++ /dev/null @@ -1,90 +0,0 @@ -'use client' -import { useAccount, useConnect, useConnectors, useDisconnect } from 'wagmi' - -export function Connect() { - const { connect } = useConnect() - const connectors = useConnectors() - - const handleConnect = - ({ type }: { type: 'sign-in' | 'sign-up' }) => - () => { - const connector = connectors.find((c) => c.id === 'webAuthn') - if (connector) { - connect({ capabilities: { type }, connector }) - } else { - console.error('webauthn connector not found') - } - } - - return ( -
- - -
- ) -} - -export function ConnectAndDisconnect() { - const { isConnected } = useAccount() - const { connect } = useConnect() - const connectors = useConnectors() - const { disconnect } = useDisconnect() - - const handleConnect = - ({ type }: { type: 'sign-in' | 'sign-up' }) => - () => { - const connector = connectors.find((c) => c.id === 'webAuthn') - if (connector) { - connect({ capabilities: { type }, connector }) - } else { - console.error('webauthn connector not found') - } - } - - const handleDisconnect = () => { - disconnect() - } - - if (!isConnected) { - return ( -
- - -
- ) - } - - return ( - - ) -} diff --git a/src/components/guides/Demo.tsx b/src/components/guides/Demo.tsx index ac2ebb2e..7b94b16e 100644 --- a/src/components/guides/Demo.tsx +++ b/src/components/guides/Demo.tsx @@ -5,7 +5,7 @@ import * as React from 'react' import type { Address, BaseError } from 'viem' import { formatUnits } from 'viem' import { tempoModerato } from 'viem/chains' -import { useAccount, useConnect, useConnections, useConnectors, useDisconnect } from 'wagmi' +import { useAccount, useConnect, useConnections, useDisconnect } from 'wagmi' import { Hooks } from 'wagmi/tempo' import LucideCheck from '~icons/lucide/check' import LucideCopy from '~icons/lucide/copy' @@ -15,6 +15,7 @@ import LucideRotateCcw from '~icons/lucide/rotate-ccw' import LucideWalletCards from '~icons/lucide/wallet-cards' import { cva, cx } from '../../../cva.config' import { usePostHogTracking } from '../../lib/posthog' +import { useTempoWalletConnector } from '../../wagmi.config' import { Container as ParentContainer } from '../Container' import { alphaUsd } from './tokens' @@ -23,15 +24,6 @@ export { alphaUsd, betaUsd, pathUsd, thetaUsd } from './tokens' export const FAKE_RECIPIENT = '0xbeefcafe54750903ac1c8909323af7beb21ea2cb' export const FAKE_RECIPIENT_2 = '0xdeadbeef54750903ac1c8909323af7beb21ea2cb' -export function useWebAuthnConnector() { - const connectors = useConnectors() - return React.useMemo( - // biome-ignore lint/style/noNonNullAssertion: webAuthn connector always defined in wagmi.config.ts - () => connectors.find((connector) => connector.id === 'webAuthn')!, - [connectors], - ) -} - function getExplorerHost() { const { VITE_TEMPO_ENV, VITE_EXPLORER_OVERRIDE } = import.meta.env @@ -117,12 +109,16 @@ export function Container( if (!source) return address if (source === 'webAuthn') { - const webAuthnConnection = connections.find((c) => c.connector.id === 'webAuthn') + const webAuthnConnection = connections.find( + (c) => c.connector.id === 'webAuthn' || c.connector.id === 'xyz.tempo', + ) return webAuthnConnection?.accounts[0] } if (source === 'wallet') { - const walletConnection = connections.find((c) => c.connector.id !== 'webAuthn') + const walletConnection = connections.find( + (c) => c.connector.id !== 'webAuthn' && c.connector.id !== 'xyz.tempo', + ) return walletConnection?.accounts[0] } @@ -363,7 +359,7 @@ export namespace StringFormatter { export function Login() { const connect = useConnect() - const connector = useWebAuthnConnector() + const connector = useTempoWalletConnector() return (
@@ -373,32 +369,14 @@ export function Login() { Check prompt ) : ( -
- - -
+ )}
) diff --git a/src/components/guides/EmbedPasskeys.tsx b/src/components/guides/EmbedPasskeys.tsx index a11585b0..ad3b1337 100644 --- a/src/components/guides/EmbedPasskeys.tsx +++ b/src/components/guides/EmbedPasskeys.tsx @@ -1,6 +1,7 @@ 'use client' import { useAccount, useConnect, useDisconnect } from 'wagmi' -import { Button, useWebAuthnConnector } from './Demo' +import { useWebAuthnConnector } from '../../wagmi.config' +import { Button } from './Demo' export function EmbedPasskeys() { const account = useAccount() diff --git a/src/components/guides/steps/wallet/AddFundsToWallet.tsx b/src/components/guides/steps/wallet/AddFundsToWallet.tsx index a8f8bf4a..840497bc 100644 --- a/src/components/guides/steps/wallet/AddFundsToWallet.tsx +++ b/src/components/guides/steps/wallet/AddFundsToWallet.tsx @@ -14,7 +14,9 @@ import type { DemoStepProps } from '../types' export function AddFundsToWallet(props: DemoStepProps) { const { stepNumber = 2, last = false } = props const { address, connector } = useConnection() - const hasNonWebAuthnWallet = Boolean(address && connector?.id !== 'webAuthn') + const hasNonWebAuthnWallet = Boolean( + address && connector?.id !== 'webAuthn' && connector?.id !== 'xyz.tempo', + ) const queryClient = useQueryClient() const { data: balance, refetch: balanceRefetch } = Hooks.token.useGetBalance({ diff --git a/src/components/guides/steps/wallet/AddTokensToWallet.tsx b/src/components/guides/steps/wallet/AddTokensToWallet.tsx index 5a833e21..308b697c 100644 --- a/src/components/guides/steps/wallet/AddTokensToWallet.tsx +++ b/src/components/guides/steps/wallet/AddTokensToWallet.tsx @@ -58,7 +58,9 @@ function AddTokenButton(props: { export function AddTokensToWallet(props: DemoStepProps) { const { stepNumber = 3, last = false } = props const { address, connector } = useConnection() - const hasNonWebAuthnWallet = Boolean(address && connector?.id !== 'webAuthn') + const hasNonWebAuthnWallet = Boolean( + address && connector?.id !== 'webAuthn' && connector?.id !== 'xyz.tempo', + ) const [addedTokens, setAddedTokens] = React.useState>(new Set()) const [expanded, setExpanded] = React.useState(false) diff --git a/src/components/guides/steps/wallet/SetFeeToken.tsx b/src/components/guides/steps/wallet/SetFeeToken.tsx index e7ffa936..59c90f61 100644 --- a/src/components/guides/steps/wallet/SetFeeToken.tsx +++ b/src/components/guides/steps/wallet/SetFeeToken.tsx @@ -27,7 +27,9 @@ const DEFAULT_FEE_TOKEN_OPTION = FEE_TOKEN_OPTIONS[0] export function SetFeeToken(props: DemoStepProps) { const { stepNumber = 1 } = props const { address, connector } = useConnection() - const hasNonWebAuthnWallet = Boolean(address && connector?.id !== 'webAuthn') + const hasNonWebAuthnWallet = Boolean( + address && connector?.id !== 'webAuthn' && connector?.id !== 'xyz.tempo', + ) const chainId = useChainId() const config = useConfig() diff --git a/src/components/lib/wallets.ts b/src/components/lib/wallets.ts index d897aa97..56a4e522 100644 --- a/src/components/lib/wallets.ts +++ b/src/components/lib/wallets.ts @@ -4,10 +4,13 @@ const UNSUPPORTED_WALLET_IDS = new Set(['app.phantom']) const UNSUPPORTED_WALLET_NAMES = new Set(['Phantom']) export function filterSupportedInjectedConnectors(connectors: readonly Connector[]) { - return connectors.filter( - (connector) => - connector.id !== 'webAuthn' && - !UNSUPPORTED_WALLET_IDS.has(connector.id) && - !UNSUPPORTED_WALLET_NAMES.has(connector.name), - ) + const seen = new Set() + return connectors.filter((connector) => { + if (connector.id === 'webAuthn') return false + if (UNSUPPORTED_WALLET_IDS.has(connector.id)) return false + if (UNSUPPORTED_WALLET_NAMES.has(connector.name)) return false + if (seen.has(connector.id)) return false + seen.add(connector.id) + return true + }) } diff --git a/src/pages/accounts/api/adapters.mdx b/src/pages/accounts/api/adapters.mdx new file mode 100644 index 00000000..72e0f063 --- /dev/null +++ b/src/pages/accounts/api/adapters.mdx @@ -0,0 +1,28 @@ +--- +title: Adapters +description: Pluggable adapters for the Tempo Accounts SDK Provider. +--- + +import { Cards, Card } from 'vocs' + +# Adapters + +Adapters control how accounts are created and managed. Pass an adapter to `Provider.create()` to configure the account management strategy. + + + + + + diff --git a/src/pages/accounts/api/ceremony.from.mdx b/src/pages/accounts/api/ceremony.from.mdx new file mode 100644 index 00000000..f8e6b4a2 --- /dev/null +++ b/src/pages/accounts/api/ceremony.from.mdx @@ -0,0 +1,47 @@ +--- +title: WebAuthnCeremony.from +description: Create a WebAuthnCeremony from a custom implementation. +--- + +# `WebAuthnCeremony.from` + +Creates a `WebAuthnCeremony` from a custom implementation. + +## Usage + +```ts +import { WebAuthnCeremony } from 'accounts' + +const ceremony = WebAuthnCeremony.from({ + async getRegistrationOptions(params) { /* ... */ }, + async verifyRegistration(credential) { /* ... */ }, + async getAuthenticationOptions(params) { /* ... */ }, + async verifyAuthentication(response) { /* ... */ }, +}) +``` + +## Properties + +### getRegistrationOptions + +- **Type:** `(params: { name: string; userId?: string; excludeCredentialIds?: readonly string[] }) => Promise<{ options: Registration.Options }>` + +Get credential creation options for `navigator.credentials.create(){:js}`. + +### verifyRegistration + +- **Type:** `(credential: Registration.Credential, options?: { name?: string }) => Promise<{ credentialId: string; publicKey: Hex }>` + +Verify a registration response and extract the public key. + +### getAuthenticationOptions + +- **Type:** `(params?: { allowCredentialIds?: readonly string[]; challenge?: Hex; credentialId?: string; mediation?: 'conditional' | 'optional' | 'required' | 'silent' }) => Promise<{ options: Authentication.Options }>` + +Get credential request options for `navigator.credentials.get(){:js}`. + +### verifyAuthentication + +- **Type:** `(response: Authentication.Response) => Promise<{ credentialId: string; publicKey: Hex; userId?: string }>` + +Verify an authentication response and extract the public key. diff --git a/src/pages/accounts/api/ceremony.local.mdx b/src/pages/accounts/api/ceremony.local.mdx new file mode 100644 index 00000000..5263d04f --- /dev/null +++ b/src/pages/accounts/api/ceremony.local.mdx @@ -0,0 +1,32 @@ +--- +title: WebAuthnCeremony.local +description: Pure client-side WebAuthn ceremony for development and prototyping. +--- + +# `WebAuthnCeremony.local` + +Creates a pure client-side ceremony for development and prototyping. Generates challenges and verifies responses locally. No external server needed. + +## Usage + +```ts +import { WebAuthnCeremony } from 'accounts' + +const ceremony = WebAuthnCeremony.local() +``` + +## Parameters + +### rpId + +- **Type:** `string` +- **Default:** `location.hostname{:js}` + +Relying Party ID (e.g. `"example.com"{:js}`). + +### storage + +- **Type:** `Storage` +- **Default:** `Storage.idb(){:js}` in browser, `Storage.memory(){:js}` otherwise + +Storage adapter for credential persistence. diff --git a/src/pages/accounts/api/ceremony.mdx b/src/pages/accounts/api/ceremony.mdx new file mode 100644 index 00000000..e445855e --- /dev/null +++ b/src/pages/accounts/api/ceremony.mdx @@ -0,0 +1,8 @@ +--- +title: WebAuthnCeremony +description: Pluggable strategy for WebAuthn registration and authentication ceremonies. +--- + +# `WebAuthnCeremony` + +Pluggable strategy for WebAuthn registration and authentication ceremonies. A `WebAuthnCeremony` controls how challenges are generated and responses are verified during passkey registration and login. diff --git a/src/pages/accounts/api/ceremony.server.mdx b/src/pages/accounts/api/ceremony.server.mdx new file mode 100644 index 00000000..9f64317b --- /dev/null +++ b/src/pages/accounts/api/ceremony.server.mdx @@ -0,0 +1,25 @@ +--- +title: WebAuthnCeremony.server +description: Server-backed WebAuthn ceremony that delegates to a remote handler. +--- + +# `WebAuthnCeremony.server` + +Creates a server-backed ceremony that delegates to a remote [WebAuthn server handler](/accounts/server/handler.webAuthn). All challenge generation, verification, and credential storage happen server-side. + +## Usage + +```ts +import { WebAuthnCeremony } from 'accounts' + +const ceremony = WebAuthnCeremony.server({ url: 'https://example.com/webauthn' }) +``` + +## Parameters + +### url + +- **Type:** `string` +- **Required** + +Base URL of the WebAuthn handler (e.g. `"https://example.com/webauthn"{:js}`). diff --git a/src/pages/accounts/api/dialog.iframe.mdx b/src/pages/accounts/api/dialog.iframe.mdx new file mode 100644 index 00000000..d780474f --- /dev/null +++ b/src/pages/accounts/api/dialog.iframe.mdx @@ -0,0 +1,20 @@ +--- +title: Dialog.iframe +description: Embed the Tempo Wallet auth UI in an iframe dialog element. +--- + +# `Dialog.iframe` + +Creates an iframe dialog that embeds the auth app in a `` element. This is the default on most browsers in secure (HTTPS) contexts. + +Falls back to a popup on Safari (which does not support WebAuthn in cross-origin iframes) and insecure (HTTP) origins. + +## Usage + +```ts +import { dialog, Dialog, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: dialog({ dialog: Dialog.iframe() }), +}) +``` diff --git a/src/pages/accounts/api/dialog.mdx b/src/pages/accounts/api/dialog.mdx new file mode 100644 index 00000000..5acd8e79 --- /dev/null +++ b/src/pages/accounts/api/dialog.mdx @@ -0,0 +1,105 @@ +--- +title: dialog +description: Adapter for the Tempo Wallet dialog, an embedded iframe or popup for account management. +--- + +# `dialog` + +Creates an adapter that delegates signing to the Tempo Wallet via an embedded iframe or popup dialog. Also exported as `tempoWallet`. + +## Usage + +```ts twoslash +import { dialog, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: dialog(), +}) +``` + +## Parameters + +### dialog + +- **Type:** `Dialog` +- **Default:** `Dialog.iframe()` (or `Dialog.popup()` in Safari/insecure contexts) + +Dialog to use for the embed app. + +```ts twoslash +import { dialog, Dialog, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: dialog({ + dialog: Dialog.popup(), // [!code focus] + }), +}) +``` + +### host + +- **Type:** `string` +- **Default:** `'https://wallet.tempo.xyz/embed'` + +URL of the embed app. + +```ts twoslash +import { dialog, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: dialog({ + host: 'https://wallet.tempo.xyz/embed', // [!code focus] + }), +}) +``` + +### icon + +- **Type:** `` `data:image/${string}` `` +- **Optional** + +Data URI of the provider icon. + +```ts twoslash +import { dialog, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: dialog({ + icon: 'data:image/svg+xml,...', // [!code focus] + }), +}) +``` + +### name + +- **Type:** `string` +- **Default:** `'Tempo Wallet'` + +Display name of the provider. + +```ts twoslash +import { dialog, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: dialog({ + name: 'My Wallet', // [!code focus] + }), +}) +``` + +### rdns + +- **Type:** `string` +- **Default:** `'xyz.tempo'` + +Reverse DNS identifier for [EIP-6963](https://eips.ethereum.org/EIPS/eip-6963) provider discovery. + +```ts twoslash +import { dialog, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: dialog({ + rdns: 'com.example.wallet', // [!code focus] + }), +}) +``` diff --git a/src/pages/accounts/api/dialog.popup.mdx b/src/pages/accounts/api/dialog.popup.mdx new file mode 100644 index 00000000..5d287442 --- /dev/null +++ b/src/pages/accounts/api/dialog.popup.mdx @@ -0,0 +1,27 @@ +--- +title: Dialog.popup +description: Open the Tempo Wallet auth UI in a popup window. +--- + +# `Dialog.popup` + +Opens the auth app in a new browser window. Used as the default on Safari and insecure (HTTP) origins. + +## Usage + +```ts +import { dialog, Dialog, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: dialog({ dialog: Dialog.popup() }), +}) +``` + +## Parameters + +### size + +- **Type:** `{ width: number; height: number }` +- **Default:** `{ width: 360, height: 440 }` + +Popup window dimensions. diff --git a/src/pages/accounts/api/dialogs.mdx b/src/pages/accounts/api/dialogs.mdx new file mode 100644 index 00000000..a44b586e --- /dev/null +++ b/src/pages/accounts/api/dialogs.mdx @@ -0,0 +1,23 @@ +--- +title: Dialog +description: Dialog modes for embedding the Tempo Wallet. +--- + +import { Cards, Card } from 'vocs' + +# Dialog + +Dialog modes control how the Tempo Wallet is embedded into your app. Pass a dialog to the `dialog()` adapter to configure the embed mode. + + + + + diff --git a/src/pages/accounts/api/expiry.mdx b/src/pages/accounts/api/expiry.mdx new file mode 100644 index 00000000..0c5170d6 --- /dev/null +++ b/src/pages/accounts/api/expiry.mdx @@ -0,0 +1,47 @@ +--- +title: Expiry +description: Utility functions for computing access key expiry timestamps. +--- + +# `Expiry` + +Utility functions that return a Unix timestamp (seconds) offset from the current time. Useful for setting access key expiry. + +## Usage + +```ts +import { Expiry } from 'accounts' + +// Access key that expires in 1 day +const expiry = Expiry.days(1) +``` + +## Functions + +### Expiry.seconds(n) + +Returns a Unix timestamp `n` seconds from now. + +### Expiry.minutes(n) + +Returns a Unix timestamp `n` minutes from now. + +### Expiry.hours(n) + +Returns a Unix timestamp `n` hours from now. + +### Expiry.days(n) + +Returns a Unix timestamp `n` days from now. + +### Expiry.weeks(n) + +Returns a Unix timestamp `n` weeks from now. + +### Expiry.months(n) + +Returns a Unix timestamp `n` months (30 days) from now. + +### Expiry.years(n) + +Returns a Unix timestamp `n` years (365 days) from now. diff --git a/src/pages/accounts/api/local.mdx b/src/pages/accounts/api/local.mdx new file mode 100644 index 00000000..1c492633 --- /dev/null +++ b/src/pages/accounts/api/local.mdx @@ -0,0 +1,59 @@ +--- +title: local +description: Key-agnostic adapter for defining arbitrary account types and signing mechanisms. +--- + +# `local` + +Creates a local adapter where the app manages keys and signing in-process. Use this when you need full control over account creation and transaction signing. + +## Usage + +```ts +import { local, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: local({ + loadAccounts: async () => ({ + accounts: [{ address: '0x...' }], + }), + }), +}) +``` + +## Parameters + +### createAccount + +- **Type:** `(params) => Promise<{ accounts: Account[] }>` +- **Optional** + +Create a new account. Omit for login-only flows. + +### icon + +- **Type:** `` `data:image/${string}` `` +- **Optional** + +Data URI of the provider icon. + +### loadAccounts + +- **Type:** `(params?) => Promise<{ accounts: Account[] }>` +- **Required** + +Discover existing accounts (e.g. via WebAuthn assertion or key lookup). + +### name + +- **Type:** `string` +- **Default:** `'Injected Wallet'` + +Display name of the provider. + +### rdns + +- **Type:** `string` +- **Optional** + +Reverse DNS identifier. diff --git a/src/pages/accounts/api/provider.mdx b/src/pages/accounts/api/provider.mdx new file mode 100644 index 00000000..d42b60b6 --- /dev/null +++ b/src/pages/accounts/api/provider.mdx @@ -0,0 +1,183 @@ +--- +title: Provider +description: Create an EIP-1193 provider for managing accounts on Tempo. +--- + +# `Provider` + +Creates an EIP-1193 provider with a pluggable adapter for managing accounts on Tempo. + +## Usage + +```ts twoslash +import { Provider } from 'accounts' + +const provider = Provider.create() +``` + +### Using JSON-RPC Methods + +You can interact with accounts via the provider's `request` method. + +```ts twoslash +// @noErrors +import { Provider } from 'accounts' + +const provider = Provider.create() + +const { accounts } = await provider.request({ // [!code focus] + method: 'wallet_connect', // [!code focus] +}) // [!code focus] +``` + +### Using Viem Actions + +If you prefer to use Viem actions over raw JSON-RPC calls, the provider exposes a `getClient` accessor. + +```ts twoslash +// @noErrors +import { parseUnits } from 'viem' +import { tempoActions } from 'viem/tempo' +import { Provider } from 'accounts' + +const provider = Provider.create() + +const client = provider.getClient().extend(tempoActions()) // [!code focus] + +const { receipt } = await client.token.transferSync({ // [!code focus] + amount: parseUnits('100', 6), // [!code focus] + to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb', // [!code focus] + token: '0x20c0000000000000000000000000000000000001', // [!code focus] +}) // [!code focus] +``` + +## Parameters + +### adapter + +- **Type:** `Adapter` +- **Default:** `dialog()` + +Adapter to use for account management. + +```ts twoslash +import { Provider, webAuthn } from 'accounts' + +const provider = Provider.create({ + adapter: webAuthn({ authUrl: 'https://myapp.com/auth' }), // [!code focus] +}) +``` + +### authorizeAccessKey + +- **Type:** `() => { expiry: number; limits?: { token: Address; limit: bigint }[] }` +- **Optional** + +Default access key parameters for `wallet_connect`. When set, `wallet_connect` will automatically authorize an access key. + +```ts twoslash +import { parseUnits } from 'viem' +import { Expiry, Provider } from 'accounts' + +const provider = Provider.create({ + authorizeAccessKey: () => ({ // [!code focus] + expiry: Expiry.days(7), // [!code focus] + limits: [ // [!code focus] + { token: '0x20c0000000000000000000000000000000000001', limit: parseUnits('500', 6) }, // [!code focus] + ], // [!code focus] + }), // [!code focus] +}) +``` + +### chains + +- **Type:** `readonly [Chain, ...Chain[]]` +- **Default:** `[tempo, tempoModerato]` + +Supported chains. The first chain is the default. + +```ts twoslash +import { Provider } from 'accounts' +import { tempo } from 'viem/chains' + +const provider = Provider.create({ + chains: [tempo], // [!code focus] +}) +``` + +### feePayerUrl + +- **Type:** `string` +- **Optional** + +Fee payer URL for interacting with a service running [`Handler.feePayer`](/accounts/server/handler.feePayer) from `accounts/server`. + +```ts twoslash +import { Provider } from 'accounts' + +const provider = Provider.create({ + feePayerUrl: 'https://myapp.com/fee-payer', // [!code focus] +}) +``` + +### mpp + +- **Type:** `boolean` +- **Default:** `false` + +Enable [Machine Payment Protocol](https://mpp.dev) support. + +```ts twoslash +import { Provider } from 'accounts' + +const provider = Provider.create({ + mpp: true, // [!code focus] +}) +``` + +### storage + +- **Type:** `Storage` +- **Default:** `Storage.idb()` in browser, `Storage.memory()` otherwise + +Storage adapter for persistence. + +```ts twoslash +import { Provider, Storage } from 'accounts' + +const provider = Provider.create({ + storage: Storage.memory(), // [!code focus] +}) +``` + +### testnet + +- **Type:** `boolean` +- **Default:** `false` + +Use testnet. When `true`, the default chain will be the first testnet chain in `chains`. + +```ts twoslash +import { Provider } from 'accounts' + +const provider = Provider.create({ + testnet: true, // [!code focus] +}) +``` + +## Return Type + +```ts +type ReturnType = { + /** EIP-1193 request method. */ + request(args: RequestArguments): Promise + /** Returns a Viem Client for the current (or specified) chain. */ + getClient(options?: { chainId?: number }): Client + /** Returns a Viem Account for the given address (or active account). */ + getAccount(options?: { address?: Address }): Account + /** Reactive state store with account and chain state. */ + store: Store + /** Configured chains. */ + chains: readonly [Chain, ...Chain[]] +} +``` diff --git a/src/pages/accounts/api/webAuthn.mdx b/src/pages/accounts/api/webAuthn.mdx new file mode 100644 index 00000000..67cf0263 --- /dev/null +++ b/src/pages/accounts/api/webAuthn.mdx @@ -0,0 +1,63 @@ +--- +title: webAuthn +description: Adapter for passkey-based accounts using WebAuthn registration and authentication. +--- + +# `webAuthn` + +Creates a WebAuthn adapter backed by real passkey ceremonies. Wraps the `local` adapter with WebAuthn registration and authentication flows. + +## Usage + +```ts +import { webAuthn, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: webAuthn({ authUrl: 'https://myapp.com/auth' }), +}) +``` + +## Parameters + +### authUrl + +- **Type:** `string` +- **Optional** + +URL of a [WebAuthn server handler](/accounts/server/handler.webAuthn) (shorthand for `WebAuthnCeremony.server({ url }){:js}`) + +:::warning +Cannot be used with `ceremony`. +::: + +### ceremony + +- **Type:** `WebAuthnCeremony` +- **Default:** `WebAuthnCeremony.local(){:js}` + +Ceremony strategy for WebAuthn registration and authentication. [See more](/accounts/api/ceremony). + +:::warning +Cannot be used with `authUrl`. +::: + +### icon + +- **Type:** `` `data:image/${string}` `` +- **Optional** + +Data URI of the provider icon. + +### name + +- **Type:** `string` +- **Default:** `'Injected Wallet'` + +Display name of the provider. + +### rdns + +- **Type:** `string` +- **Optional** + +Reverse DNS identifier. diff --git a/src/pages/accounts/faq.mdx b/src/pages/accounts/faq.mdx new file mode 100644 index 00000000..8fa194d9 --- /dev/null +++ b/src/pages/accounts/faq.mdx @@ -0,0 +1,46 @@ +--- +title: FAQ +description: Frequently asked questions about the Tempo Accounts SDK. +--- + +# Frequently Asked Questions + +## Which browsers are supported? + +The Tempo Accounts SDK supports the following browsers: + +- Safari +- Chrome +- Firefox +- Brave +- Arc + +If a browser is not listed above, it likely works but is not officially supported. + +## Which password managers are supported? + +The Tempo Accounts SDK supports the following password managers: + +- iCloud Keychain +- Google Password Manager +- 1Password +- Bitwarden + +If a password manager is not listed above, it likely works but is not officially supported. + +## Which operating systems are supported? + +The Tempo Accounts SDK supports the following operating systems: + +- iOS +- iPadOS +- macOS +- Android +- Linux +- Windows + +If an operating system is not listed above, it likely works but is not officially supported. + +## How does the Tempo Accounts SDK work with my Content Security Policy? + +If you've deployed a Content Security Policy, see the [Deploying to Production](/accounts/production) page for the full set of required directives. diff --git a/src/pages/accounts/index.mdx b/src/pages/accounts/index.mdx new file mode 100644 index 00000000..8a1740b1 --- /dev/null +++ b/src/pages/accounts/index.mdx @@ -0,0 +1,220 @@ +--- +title: Accounts SDK – Getting Started +description: Set up the Tempo Accounts SDK to create, manage, and interact with accounts on Tempo. +--- + +import { Cards, Card } from 'vocs' +import { AccountsSignIn } from '../../components/guides/AccountsSignIn' + +# Getting Started + +## Overview + +The Tempo Accounts SDK is a TypeScript library for applications and wallets to create, manage, and interact with accounts on Tempo. + + + +## Install + +The Tempo Accounts SDK is available as an [NPM package](https://www.npmjs.com/package/accounts) under `accounts` + +:::code-group +```bash [npm] +npm i accounts +``` +```bash [pnpm] +pnpm i accounts +``` +```bash [bun] +bun i accounts +``` +::: + +## Wagmi Usage + +The Tempo Accounts SDK is best used in conjunction with [Wagmi](https://wagmi.sh/) to provide a seamless experience for developers and end-users. + +::::steps + +### Set up Wagmi + +Get started with Wagmi by following the [official guide](https://wagmi.sh/react/getting-started). + +### Configure + +After you have set up Wagmi, you can set up the Tempo Accounts SDK by using a Connector from `accounts/wagmi`: + + + + + + +:::code-group +```tsx twoslash [Tempo Wallet] +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { tempoWallet } from 'accounts/wagmi' + +export const wagmiConfig = createConfig({ + chains: [tempo], + connectors: [tempoWallet()], + transports: { + [tempo.id]: http(), + }, +}) +``` +```tsx twoslash [WebAuthn] +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { webAuthn } from 'accounts/wagmi' + +export const wagmiConfig = createConfig({ + chains: [tempo], + connectors: [webAuthn({ authUrl: 'https://myapp.com/auth' })], + transports: { + [tempo.id]: http(), + }, +}) +``` +::: + +:::tip +If you are using a wallet connection library and cannot supply a custom connector, +you can use `Provider.create()` to create a new provider instance, and inject itself +into the wallet connection library via [EIP-6963](https://eips.ethereum.org/EIPS/eip-6963). + +```tsx +import { Provider } from 'accounts' +Provider.create() +``` +::: + +### Use Accounts + +You can now use [Wagmi Hooks](https://wagmi.sh/react/api/hooks) like `useConnect`, or [Tempo Hooks](https://wagmi.sh/tempo) like `useTransfer`. + +```tsx twoslash +// @noErrors +import { useConnect, useConnectors } from 'wagmi' + +function Connect() { + const connect = useConnect() + const connectors = useConnectors() + + return connectors?.map((connector) => ( + + )) +} +``` + +### Next Steps + + + + + + + + + +:::: + +## Vanilla Usage + +You can get started with the Tempo Accounts SDK by creating a new `Provider` instance. +Once set up, you can use the `provider` to interact with accounts via JSON-RPC. + +```tsx twoslash +import { Provider } from 'accounts' + +const provider = Provider.create() + +const { accounts } = await provider.request({ + method: 'wallet_connect', +}) + +const client = provider.getClient() +``` + +## Secure Origins (HTTPS) + +The Tempo Accounts SDK is designed to be used on secure origins (HTTPS). If you are using HTTP, +it will fallback to using a popup instead of an iframe. This is because +WebAuthn is not supported on iframes embedded on insecure origins (HTTP). + +Web frameworks typically default to HTTP in development environments. You +will need to ensure to turn on HTTPS in development to leverage the iframe dialog. + +### Portless + +[Portless](https://github.com/vercel-labs/portless) replaces port numbers with stable, named `.localhost` URLs and can enable HTTPS with auto-generated certificates. + +```sh +npm install -g portless +portless run dev +# → https://myapp.localhost +``` + +### Next.js + +HTTPS can be enabled on Next.js' dev server by setting the `--experimental-https` flag on the `next dev` command. + +```bash +next dev --experimental-https +``` + +### Vite + +HTTPS can be enabled on Vite's dev server by installing and configuring the `vite-plugin-mkcert` plugin. + +```bash +npm i vite-plugin-mkcert +``` + +:::code-group +```ts [vite.config.ts] +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import mkcert from 'vite-plugin-mkcert' + +export default defineConfig({ + plugins: [ + mkcert(), + react(), + ], +}) +``` +::: diff --git a/src/pages/accounts/production.mdx b/src/pages/accounts/production.mdx new file mode 100644 index 00000000..52d8d25d --- /dev/null +++ b/src/pages/accounts/production.mdx @@ -0,0 +1,24 @@ +--- +title: Deploying to Production +description: Things to consider before deploying your application with the Tempo Accounts SDK to production. +--- + +# Deploying to Production + +Below are some things to consider before deploying to production. + +## Trusted Hosts + +To enable the `iframe` dialog on all browsers in production, ensure your website hostname is added to the [trusted hosts list](https://github.com/tempoxyz/accounts/blob/main/src/trusted-hosts.json). + +Without this, the `iframe` dialog will fallback to a popup on browsers that do not support the [IntersectionObserver v2 API](https://web.dev/articles/intersectionobserver-v2). + +## Content Security Policy + +If you've deployed a Content Security Policy, ensure that you have the Tempo Accounts SDK configured with your CSPs. + +The full set of directives that the Tempo Accounts SDK requires are: + +| Directive | Value | +| --- | --- | +| `frame-src` | `https://wallet.tempo.xyz` | diff --git a/src/pages/accounts/rpc/eth_fillTransaction.mdx b/src/pages/accounts/rpc/eth_fillTransaction.mdx new file mode 100644 index 00000000..8fb027c4 --- /dev/null +++ b/src/pages/accounts/rpc/eth_fillTransaction.mdx @@ -0,0 +1,47 @@ +--- +title: eth_fillTransaction +description: Fill missing transaction fields like gas and nonce via the node. +--- + +# `eth_fillTransaction` + +Fills in missing transaction fields (gas, nonce, fees) by querying the node. This is a node RPC method, not handled by the accounts provider directly. + +## Request + +```ts +type Request = { + method: 'eth_fillTransaction' + params: [TransactionRequest] +} +``` + +## Response + +```ts +type Response = { + raw: Hex + tx: TransactionRequest +} +``` + +## Example + +```ts +import { createPublicClient, http } from 'viem' +import { tempo } from 'viem/chains' + +const client = createPublicClient({ + chain: tempo, + transport: http(), +}) + +const filled = await client.request({ + method: 'eth_fillTransaction', + params: [{ + from: '0x...', + to: '0x...', + value: '0x0', + }], +}) +``` diff --git a/src/pages/accounts/rpc/eth_sendTransaction.mdx b/src/pages/accounts/rpc/eth_sendTransaction.mdx new file mode 100644 index 00000000..7f1e57d8 --- /dev/null +++ b/src/pages/accounts/rpc/eth_sendTransaction.mdx @@ -0,0 +1,36 @@ +--- +title: eth_sendTransaction +description: Send a transaction from the connected account. +--- + +# `eth_sendTransaction` + +Signs and broadcasts a transaction, returning the transaction hash. + +## Request + +```ts +type Request = { + method: 'eth_sendTransaction' + params: [TransactionRequest] +} +``` + +## Response + +```ts +type Response = Hex // transaction hash +``` + +## Example + +```ts +const hash = await provider.request({ + method: 'eth_sendTransaction', + params: [{ + to: '0x...', + value: '0x0', + data: '0x...', + }], +}) +``` diff --git a/src/pages/accounts/rpc/eth_sendTransactionSync.mdx b/src/pages/accounts/rpc/eth_sendTransactionSync.mdx new file mode 100644 index 00000000..90b902c4 --- /dev/null +++ b/src/pages/accounts/rpc/eth_sendTransactionSync.mdx @@ -0,0 +1,36 @@ +--- +title: eth_sendTransactionSync +description: Send a transaction and wait for the receipt. +--- + +# `eth_sendTransactionSync` + +Signs, broadcasts, and waits for a transaction receipt. Returns the full receipt instead of just the hash. + +## Request + +```ts +type Request = { + method: 'eth_sendTransactionSync' + params: [TransactionRequest] +} +``` + +## Response + +```ts +type Response = TransactionReceipt +``` + +## Example + +```ts +const receipt = await provider.request({ + method: 'eth_sendTransactionSync', + params: [{ + to: '0x...', + value: '0x0', + data: '0x...', + }], +}) +``` diff --git a/src/pages/accounts/rpc/personal_sign.mdx b/src/pages/accounts/rpc/personal_sign.mdx new file mode 100644 index 00000000..3869d335 --- /dev/null +++ b/src/pages/accounts/rpc/personal_sign.mdx @@ -0,0 +1,40 @@ +--- +title: personal_sign +description: Sign a message with the connected account. +--- + +# `personal_sign` + +Signs an arbitrary message with the connected account's key. + +## Request + +```ts +type Request = { + method: 'personal_sign' + params: [ + Hex, // message + Address // signer address + ] +} +``` + +## Response + +```ts +type Response = Hex // signature +``` + +## Example + +```ts +import { Hex } from 'ox' + +const signature = await provider.request({ + method: 'personal_sign', + params: [ + Hex.fromString('Hello, Tempo!'), + '0x...', + ], +}) +``` diff --git a/src/pages/accounts/rpc/wallet_authorizeAccessKey.mdx b/src/pages/accounts/rpc/wallet_authorizeAccessKey.mdx new file mode 100644 index 00000000..58b48471 --- /dev/null +++ b/src/pages/accounts/rpc/wallet_authorizeAccessKey.mdx @@ -0,0 +1,53 @@ +--- +title: wallet_authorizeAccessKey +description: Authorize an access key for delegated transaction signing. +--- + +# `wallet_authorizeAccessKey` + +Authorizes an access key with an expiry and optional spending limits for delegated transaction signing. + +## Request + +```ts +type Request = { + method: 'wallet_authorizeAccessKey' + params: [{ + /** Unix timestamp (seconds) when the key expires. */ + expiry: number + /** TIP-20 spending limits. */ + limits?: { token: Address; limit: Hex }[] + /** Public key to authorize. */ + publicKey?: Hex + /** Key type. */ + keyType?: 'secp256k1' | 'p256' | 'webAuthn' + /** Address of the key (alternative to publicKey). */ + address?: Address + }] +} +``` + +## Response + +```ts +type Response = { + keyAuthorization: KeyAuthorization + rootAddress: Address +} +``` + +## Example + +```ts +import { Expiry } from 'accounts' + +const result = await provider.request({ + method: 'wallet_authorizeAccessKey', + params: [{ + expiry: Expiry.days(1), + limits: [ + { token: '0x20c0000000000000000000000000000000000001', limit: '0x5F5E100' }, + ], + }], +}) +``` diff --git a/src/pages/accounts/rpc/wallet_connect.mdx b/src/pages/accounts/rpc/wallet_connect.mdx new file mode 100644 index 00000000..85c16763 --- /dev/null +++ b/src/pages/accounts/rpc/wallet_connect.mdx @@ -0,0 +1,54 @@ +--- +title: wallet_connect +description: Connect account(s) with optional capabilities like access key authorization. +--- + +# `wallet_connect` + +Requests to connect account(s) with optional capabilities. + +## Request + +```ts +type Request = { + method: 'wallet_connect' + params?: [{ + capabilities?: { + /** Authorize an access key on connect. */ + authorizeAccessKey?: { + expiry: number + limits?: { token: Address; limit: Hex }[] + publicKey?: Hex + } + /** Authentication method. */ + method?: 'register' | 'login' + } + }] +} +``` + +## Response + +```ts +type Response = { + accounts: { + address: Address + capabilities: { + keyAuthorization?: KeyAuthorization + signature?: Hex + } + }[] +} +``` + +## Example + +```ts +import { Provider } from 'accounts' + +const provider = Provider.create() + +const { accounts } = await provider.request({ + method: 'wallet_connect', +}) +``` diff --git a/src/pages/accounts/rpc/wallet_disconnect.mdx b/src/pages/accounts/rpc/wallet_disconnect.mdx new file mode 100644 index 00000000..4dcc8b0d --- /dev/null +++ b/src/pages/accounts/rpc/wallet_disconnect.mdx @@ -0,0 +1,30 @@ +--- +title: wallet_disconnect +description: Disconnect the connected account(s). +--- + +# `wallet_disconnect` + +Disconnects the connected account(s) and clears session state. + +## Request + +```ts +type Request = { + method: 'wallet_disconnect' +} +``` + +## Response + +```ts +type Response = undefined +``` + +## Example + +```ts +await provider.request({ + method: 'wallet_disconnect', +}) +``` diff --git a/src/pages/accounts/rpc/wallet_getBalances.mdx b/src/pages/accounts/rpc/wallet_getBalances.mdx new file mode 100644 index 00000000..ad2c5557 --- /dev/null +++ b/src/pages/accounts/rpc/wallet_getBalances.mdx @@ -0,0 +1,45 @@ +--- +title: wallet_getBalances +description: Get token balances for an account. +--- + +# `wallet_getBalances` + +Returns token balances for the connected account. + +## Request + +```ts +type Request = { + method: 'wallet_getBalances' + params?: [{ + /** Account address. Defaults to connected account. */ + account?: Address + /** Chain ID. */ + chainId?: number + /** Filter to specific token addresses. */ + tokens?: Address[] + }] +} +``` + +## Response + +```ts +type Response = { + address: Address + balance: bigint + decimals: number + display: string + name: string + symbol: string +}[] +``` + +## Example + +```ts +const balances = await provider.request({ + method: 'wallet_getBalances', +}) +``` diff --git a/src/pages/accounts/rpc/wallet_getCallsStatus.mdx b/src/pages/accounts/rpc/wallet_getCallsStatus.mdx new file mode 100644 index 00000000..0a537ba9 --- /dev/null +++ b/src/pages/accounts/rpc/wallet_getCallsStatus.mdx @@ -0,0 +1,39 @@ +--- +title: wallet_getCallsStatus +description: Get the status of a batch of calls sent via wallet_sendCalls. +--- + +# `wallet_getCallsStatus` + +Returns the status and receipts of a previously submitted batch of calls. + +## Request + +```ts +type Request = { + method: 'wallet_getCallsStatus' + params?: [string] +} +``` + +## Response + +```ts +type Response = { + atomic: boolean + chainId: number + id: string + receipts?: TransactionReceipt[] + status: number + version: string +} +``` + +## Example + +```ts +const status = await provider.request({ + method: 'wallet_getCallsStatus', + params: ['0x...'], +}) +``` diff --git a/src/pages/accounts/rpc/wallet_getCapabilities.mdx b/src/pages/accounts/rpc/wallet_getCapabilities.mdx new file mode 100644 index 00000000..8a2f8f2f --- /dev/null +++ b/src/pages/accounts/rpc/wallet_getCapabilities.mdx @@ -0,0 +1,35 @@ +--- +title: wallet_getCapabilities +description: Get account capabilities for specified chains. +--- + +# `wallet_getCapabilities` + +Returns capabilities for the connected account across chains. + +## Request + +```ts +type Request = { + method: 'wallet_getCapabilities' + params?: [Address] | [Address, Hex[]] +} +``` + +## Response + +```ts +type Response = Record +``` + +## Example + +```ts +const capabilities = await provider.request({ + method: 'wallet_getCapabilities', + params: ['0x...'], +}) +``` diff --git a/src/pages/accounts/rpc/wallet_revokeAccessKey.mdx b/src/pages/accounts/rpc/wallet_revokeAccessKey.mdx new file mode 100644 index 00000000..a62cc6c6 --- /dev/null +++ b/src/pages/accounts/rpc/wallet_revokeAccessKey.mdx @@ -0,0 +1,40 @@ +--- +title: wallet_revokeAccessKey +description: Revoke a previously authorized access key. +--- + +# `wallet_revokeAccessKey` + +Revokes a previously authorized access key. + +## Request + +```ts +type Request = { + method: 'wallet_revokeAccessKey' + params: [{ + /** Address of the account. */ + address: Address + /** Address of the access key to revoke. */ + accessKeyAddress: Address + }] +} +``` + +## Response + +```ts +type Response = undefined +``` + +## Example + +```ts +await provider.request({ + method: 'wallet_revokeAccessKey', + params: [{ + address: '0x...', + accessKeyAddress: '0x...', + }], +}) +``` diff --git a/src/pages/accounts/rpc/wallet_sendCalls.mdx b/src/pages/accounts/rpc/wallet_sendCalls.mdx new file mode 100644 index 00000000..dc907327 --- /dev/null +++ b/src/pages/accounts/rpc/wallet_sendCalls.mdx @@ -0,0 +1,48 @@ +--- +title: wallet_sendCalls +description: Send a batch of calls from the connected account. +--- + +# `wallet_sendCalls` + +Sends a batch of calls from the connected account. Supports atomic execution. + +## Request + +```ts +type Request = { + method: 'wallet_sendCalls' + params?: [{ + calls: { to: Address; data?: Hex; value?: Hex }[] + from?: Address + chainId?: number + capabilities?: { sync?: boolean } + atomicRequired?: boolean + }] +} +``` + +## Response + +```ts +type Response = { + id: string + status?: number + receipts?: TransactionReceipt[] + chainId?: number + atomic?: boolean +} +``` + +## Example + +```ts +const result = await provider.request({ + method: 'wallet_sendCalls', + params: [{ + calls: [ + { to: '0x...', data: '0x...' }, + ], + }], +}) +``` diff --git a/src/pages/accounts/server/handler.compose.mdx b/src/pages/accounts/server/handler.compose.mdx new file mode 100644 index 00000000..161a983f --- /dev/null +++ b/src/pages/accounts/server/handler.compose.mdx @@ -0,0 +1,54 @@ +--- +title: Handler.compose +description: Compose multiple server handlers into a single handler. +--- + +# `Handler.compose` + +Composes multiple handlers into a single handler, routing requests to the handler that matches the request path. + +## Usage + +```ts +import { Handler } from 'accounts/server' + +const handler = Handler.compose([ + Handler.feePayer({ + account: privateKeyToAccount('0x...') + }), + Handler.webAuthn({ + kv: Kv.memory(), + origin: 'https://example.com', + rpId: 'example.com' + }), +]) +``` + +Then plug `handler` into your server framework of choice: + +```ts +createServer(handler.listener) // Node.js +Bun.serve(handler) // Bun +Deno.serve(handler) // Deno +app.all('*', c => handler.fetch(c.request)) // Elysia +app.use(handler.listener) // Express +app.use(c => handler.fetch(c.req.raw)) // Hono +export const GET = handler.fetch // Next.js +export const POST = handler.fetch // Next.js +``` + +## Parameters + +### handlers + +- **Type:** `Handler[]` +- **Required** + +Array of handlers to compose. Requests are routed to each handler in order. + +### path + +- **Type:** `string` +- **Default:** `'/'` + +Base path prefix for all composed handlers. diff --git a/src/pages/accounts/server/handler.feePayer.mdx b/src/pages/accounts/server/handler.feePayer.mdx new file mode 100644 index 00000000..2c54ba25 --- /dev/null +++ b/src/pages/accounts/server/handler.feePayer.mdx @@ -0,0 +1,69 @@ +--- +title: Handler.feePayer +description: Server handler that sponsors transaction fees for users. +--- + +# `Handler.feePayer` + +Creates a server handler that acts as a fee payer for transactions, enabling you to subsidize gas costs for users by signing transactions with a dedicated fee payer account on your backend. + +## Usage + +```ts +import { privateKeyToAccount } from 'viem/accounts' +import { Handler } from 'accounts/server' + +const handler = Handler.feePayer({ + account: privateKeyToAccount('0x...'), +}) +``` + +Then plug `handler` into your server framework of choice: + +```ts +createServer(handler.listener) // Node.js +Bun.serve(handler) // Bun +Deno.serve(handler) // Deno +app.all('*', c => handler.fetch(c.request)) // Elysia +app.use(handler.listener) // Express +app.use(c => handler.fetch(c.req.raw)) // Hono +export const GET = handler.fetch // Next.js +export const POST = handler.fetch // Next.js +``` + +## Parameters + +### account + +- **Type:** `LocalAccount` +- **Required** + +The account to use as the fee payer. This account will sign all transactions and pay the gas fees. + +### chains + +- **Type:** `readonly [Chain, ...Chain[]]` +- **Default:** `[tempo, tempoModerato]` + +Supported chains. The handler resolves the client based on the `chainId` in the incoming transaction. + +### onRequest + +- **Type:** `(request: RpcRequest) => Promise` +- **Optional** + +Callback called before processing each request. Useful for logging, rate limiting, or custom validation. + +### path + +- **Type:** `string` +- **Default:** `'/'` + +Path where the handler listens for requests. + +### transports + +- **Type:** `Record` +- **Default:** `http()` for each chain + +Transports keyed by chain ID. diff --git a/src/pages/accounts/server/handler.webAuthn.mdx b/src/pages/accounts/server/handler.webAuthn.mdx new file mode 100644 index 00000000..13b9b12e --- /dev/null +++ b/src/pages/accounts/server/handler.webAuthn.mdx @@ -0,0 +1,95 @@ +--- +title: Handler.webAuthn +description: Server-side WebAuthn ceremony handler for registration and authentication. +--- + +# `Handler.webAuthn` + +Creates a WebAuthn ceremony handler that manages registration and authentication flows server-side. + +Exposes 4 POST endpoints: + +- `POST /register/options` — Generate credential creation options +- `POST /register` — Verify registration and store credential +- `POST /login/options` — Generate credential request options +- `POST /login` — Verify authentication + +## Usage + +```ts +import { Handler, Kv } from 'accounts/server' + +const handler = Handler.webAuthn({ + kv: Kv.memory(), + origin: 'https://example.com', + rpId: 'example.com', +}) +``` + +Then plug `handler` into your server framework of choice: + +```ts +createServer(handler.listener) // Node.js +Bun.serve(handler) // Bun +Deno.serve(handler) // Deno +app.all('*', c => handler.fetch(c.request)) // Elysia +app.use(handler.listener) // Express +app.use(c => handler.fetch(c.req.raw)) // Hono +export const GET = handler.fetch // Next.js +export const POST = handler.fetch // Next.js +``` + +:::warning +`Kv.memory()` is not recommended for production use. Instead, use a persistent store like Cloudflare or Vercel KV, or a Redis instance. See [`Kv`](/accounts/server/kv) for available adapters. +::: + +## Parameters + +### challengeTtl + +- **Type:** `number` +- **Default:** `300` (5 minutes) + +Maximum age of a challenge in seconds before it expires. + +### kv + +- **Type:** `Kv` +- **Required** + +Key-value store for challenges and credentials. + +### onAuthenticate + +- **Type:** `(params: { credentialId, publicKey, userId?, request }) => Response | void` +- **Optional** + +Called after a successful authentication. + +### onRegister + +- **Type:** `(params: { credentialId, publicKey, request }) => Response | void` +- **Optional** + +Called after a successful registration. The returned response is merged onto the default JSON response. + +### origin + +- **Type:** `string | readonly string[]` +- **Required** + +Expected origin(s) for WebAuthn verification (e.g. `'https://example.com'`). + +### path + +- **Type:** `string` +- **Default:** `''` + +Path prefix for the WebAuthn endpoints. + +### rpId + +- **Type:** `string` +- **Required** + +Relying Party ID (e.g. `'example.com'`). diff --git a/src/pages/sdk/typescript/server/handlers.mdx b/src/pages/accounts/server/index.mdx similarity index 56% rename from src/pages/sdk/typescript/server/handlers.mdx rename to src/pages/accounts/server/index.mdx index 98e80414..9be6cfba 100644 --- a/src/pages/sdk/typescript/server/handlers.mdx +++ b/src/pages/accounts/server/index.mdx @@ -1,10 +1,11 @@ --- -description: Framework-agnostic server handlers for Tempo protocol operations. Works with Node.js, Bun, Deno, Express, Hono, and Next.js. +title: Handlers +description: Server-side handlers for the Tempo Accounts SDK. --- import { Cards, Card } from 'vocs' -# Overview +# Handlers Server handlers are framework-agnostic handlers that run on your backend to manage protocol operations that require server-side logic. @@ -13,51 +14,37 @@ Handlers are compatible with any server framework that supports the: - [Node.js `RequestListener` API](https://nodejs.org/api/http.html#http_class_http_serverrequestlistener), and is exposed via the `Handler#listener` function ```ts -import { Handler } from 'tempo.ts/server' -import { account, client } from './config' +import { Handler } from 'accounts/server' +import { privateKeyToAccount } from 'viem/accounts' const handler = Handler.feePayer({ - account, - client, - feeToken: '0x20c0…0001' - path: '/fee-payer', + account: privateKeyToAccount('0x...'), }) createServer(handler.listener) // Node.js - Bun.serve(handler) // Bun - Deno.serve(handler) // Deno - app.all('*', c => handler.fetch(c.request)) // Elysia - app.use(handler.listener) // Express - app.use(c => handler.fetch(c.req.raw)) // Hono - export const GET = handler.fetch // Next.js export const POST = handler.fetch // Next.js ``` -## Handlers - - \ No newline at end of file + diff --git a/src/pages/accounts/server/kv.mdx b/src/pages/accounts/server/kv.mdx new file mode 100644 index 00000000..efa1252f --- /dev/null +++ b/src/pages/accounts/server/kv.mdx @@ -0,0 +1,54 @@ +--- +title: Kv +description: Key-value store adapters for server-side persistence. +--- + +# `Kv` + +Key-value store interface used by server handlers for persistence (challenges, credentials, device codes). + +## Usage + +```ts +import { Kv } from 'accounts/server' + +// In-memory (for development/testing) +const kv = Kv.memory() + +// Cloudflare Workers KV +const kv = Kv.cloudflare(env.MY_KV_NAMESPACE) +``` + +## Adapters + +### Kv.memory() + +Creates an in-memory key-value store. Useful for development and testing. + +### Kv.cloudflare(namespace) + +Creates a key-value store backed by Cloudflare Workers KV. + +- **namespace** — Cloudflare KV namespace binding. + +### Kv.from(kv) + +Creates a key-value store from a custom implementation. + +```ts +const kv = Kv.from({ + async get(key) { /* ... */ }, + async set(key, value) { /* ... */ }, + async delete(key) { /* ... */ }, +}) +``` + +## Interface + +```ts +type Kv = { + get: (key: string) => Promise + set: (key: string, value: unknown) => Promise + delete: (key: string) => Promise +} +``` diff --git a/src/pages/accounts/wagmi/index.mdx b/src/pages/accounts/wagmi/index.mdx new file mode 100644 index 00000000..9feda548 --- /dev/null +++ b/src/pages/accounts/wagmi/index.mdx @@ -0,0 +1,23 @@ +--- +title: Connectors +description: Wagmi connectors for integrating Tempo accounts into your app. +--- + +import { Cards, Card } from 'vocs' + +# Connectors + +Wagmi connectors for integrating Tempo accounts into your app. + + + + + diff --git a/src/pages/accounts/wagmi/tempoWallet.mdx b/src/pages/accounts/wagmi/tempoWallet.mdx new file mode 100644 index 00000000..f541c36a --- /dev/null +++ b/src/pages/accounts/wagmi/tempoWallet.mdx @@ -0,0 +1,49 @@ +--- +title: tempoWallet +description: Wagmi connector for the Tempo Wallet dialog. +--- + +# `tempoWallet` + +Creates a Wagmi connector backed by the Tempo Wallet dialog adapter. + +## Usage + +```ts +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { tempoWallet } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [tempoWallet()], + transports: { + [tempo.id]: http(), + }, +}) +``` + +## Parameters + +Accepts all [`dialog`](/accounts/api/dialog) adapter options, plus all [`Provider`](/accounts/api/provider) options except `adapter`. + +### authorizeAccessKey + +- **Type:** `() => { expiry: number; limits?: { token: Address; limit: bigint }[] }` +- **Optional** + +Default access key parameters for `wallet_connect`. + +### chains + +- **Type:** `readonly [Chain, ...Chain[]]` +- **Default:** `[tempo, tempoModerato]` + +Supported chains. + +### host + +- **Type:** `string` +- **Default:** `'https://wallet.tempo.xyz/embed'` + +URL of the embed app. diff --git a/src/pages/accounts/wagmi/webAuthn.mdx b/src/pages/accounts/wagmi/webAuthn.mdx new file mode 100644 index 00000000..c967dcce --- /dev/null +++ b/src/pages/accounts/wagmi/webAuthn.mdx @@ -0,0 +1,42 @@ +--- +title: webAuthn +description: Wagmi connector for passkey-based WebAuthn accounts. +--- + +# `webAuthn` + +Creates a Wagmi connector backed by the WebAuthn adapter. + +## Usage + +```ts +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { webAuthn } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [webAuthn({ authUrl: 'https://myapp.com/auth' })], + transports: { + [tempo.id]: http(), + }, +}) +``` + +## Parameters + +Accepts all [`webAuthn`](/accounts/api/webauthn) adapter options, plus all [`Provider`](/accounts/api/provider) options except `adapter`. + +### authUrl + +- **Type:** `string` +- **Optional** + +URL of a WebAuthn handler. + +### ceremony + +- **Type:** `WebAuthnCeremony` +- **Default:** `WebAuthnCeremony.local()` + +Ceremony strategy for WebAuthn flows. diff --git a/src/pages/guide/_template.mdx b/src/pages/guide/_template.mdx index 516907a4..a5ee7e4c 100644 --- a/src/pages/guide/_template.mdx +++ b/src/pages/guide/_template.mdx @@ -43,13 +43,11 @@ export function Component() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -75,13 +73,11 @@ export function Component() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, diff --git a/src/pages/guide/issuance/create-a-stablecoin.mdx b/src/pages/guide/issuance/create-a-stablecoin.mdx index cfe25a5c..a1a8dab4 100644 --- a/src/pages/guide/issuance/create-a-stablecoin.mdx +++ b/src/pages/guide/issuance/create-a-stablecoin.mdx @@ -69,13 +69,11 @@ export function AddFunds() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -130,13 +128,11 @@ export function CreateStablecoin() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -198,13 +194,11 @@ export function CreateStablecoin() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -266,13 +260,11 @@ export function CreateStablecoin() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, diff --git a/src/pages/guide/issuance/distribute-rewards.mdx b/src/pages/guide/issuance/distribute-rewards.mdx index dd9c43af..f6b5e5fb 100644 --- a/src/pages/guide/issuance/distribute-rewards.mdx +++ b/src/pages/guide/issuance/distribute-rewards.mdx @@ -77,13 +77,11 @@ export function OptInToRewards() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -137,13 +135,11 @@ export function StartReward() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -190,13 +186,11 @@ export function ClaimReward() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, diff --git a/src/pages/guide/issuance/manage-stablecoin.mdx b/src/pages/guide/issuance/manage-stablecoin.mdx index 4cd91cb0..abbba2e3 100644 --- a/src/pages/guide/issuance/manage-stablecoin.mdx +++ b/src/pages/guide/issuance/manage-stablecoin.mdx @@ -74,13 +74,11 @@ export function GrantRoles() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -153,13 +151,11 @@ export function GrantRoles() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -266,13 +262,11 @@ export function RevokeRoles() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -337,13 +331,11 @@ export function SetSupplyCap() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -446,13 +438,11 @@ export function LinkTokenPolicy() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -526,13 +516,11 @@ export function PauseUnpauseTransfers() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -600,13 +588,11 @@ export function BurnBlocked() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, diff --git a/src/pages/guide/issuance/mint-stablecoins.mdx b/src/pages/guide/issuance/mint-stablecoins.mdx index b4b8caca..96b9e482 100644 --- a/src/pages/guide/issuance/mint-stablecoins.mdx +++ b/src/pages/guide/issuance/mint-stablecoins.mdx @@ -77,13 +77,11 @@ export function GrantIssuerRole() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -180,13 +178,11 @@ export function MintToken() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, @@ -339,13 +335,11 @@ export function BurnToken() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, diff --git a/src/pages/guide/issuance/use-for-fees.mdx b/src/pages/guide/issuance/use-for-fees.mdx index 4ad675c4..b0248b9a 100644 --- a/src/pages/guide/issuance/use-for-fees.mdx +++ b/src/pages/guide/issuance/use-for-fees.mdx @@ -201,13 +201,11 @@ export function PayWithIssuedToken() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ - keyManager: KeyManager.localStorage(), - })], + connectors: [tempoWallet()], transports: { [tempo.id]: http(), }, diff --git a/src/pages/guide/machine-payments/client.mdx b/src/pages/guide/machine-payments/client.mdx index 4ae816d8..add1b853 100644 --- a/src/pages/guide/machine-payments/client.mdx +++ b/src/pages/guide/machine-payments/client.mdx @@ -97,11 +97,11 @@ Mppx.create({ ```ts [config.ts] import { createConfig, http } from 'wagmi' -import { webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' import { tempoModerato } from 'viem/chains' export const config = createConfig({ - connectors: [webAuthn()], + connectors: [tempoWallet()], chains: [tempoModerato], transports: { [tempoModerato.id]: http(), diff --git a/src/pages/guide/payments/sponsor-user-fees.mdx b/src/pages/guide/payments/sponsor-user-fees.mdx index dcdfe8f8..6b66e27c 100644 --- a/src/pages/guide/payments/sponsor-user-fees.mdx +++ b/src/pages/guide/payments/sponsor-user-fees.mdx @@ -29,7 +29,7 @@ Enable gasless transactions by sponsoring transaction fees for your users. Tempo Tempo provides a public testnet fee payer service at `https://sponsor.moderato.tempo.xyz` that you can use for development and testing. If you want to run your own, follow the instructions below. ::: -You can stand up a minimal fee payer service using the `Handler.feePayer` handler provided by the Tempo TypeScript SDK ([link](/sdk/typescript/server/handler.feePayer)). To sponsor transactions, you need a funded account that will act as the fee payer. +You can stand up a minimal fee payer service using the [`Handler.feePayer`](/accounts/server/handler.feePayer) handler provided by the [Tempo Accounts SDK](/accounts). To sponsor transactions, you need a funded account that will act as the fee payer. ```ts twoslash [server.ts] // @noErrors @@ -38,15 +38,50 @@ You can stand up a minimal fee payer service using the `Handler.feePayer` handle ### Configure your client to use the fee payer service -Use the `withFeePayer` transport provided by Viem ([link](https://viem.sh/tempo/transports/withFeePayer)). It routes transactions to the configured fee payer service for sponsorship when `feePayer: true` is requested on a transaction. - -```ts twoslash [wagmi.config.ts] +:::code-group + +```ts twoslash [Tempo Wallet] // @noErrors -// [!include ~/snippets/wagmi.config.ts:withFeePayer] +import { tempoWallet } from 'accounts/wagmi' +import { tempo } from 'viem/chains' +import { createConfig, http } from 'wagmi' + +export const config = createConfig({ + connectors: [tempoWallet({ + feePayerUrl: 'https://sponsor.moderato.tempo.xyz', // [!code hl] + })], + chains: [tempo], + multiInjectedProviderDiscovery: false, + transports: { + [tempo.id]: http(), + }, +}) ``` +```ts twoslash [Other] +// @noErrors +import { tempoWallet } from 'accounts/wagmi' +import { tempo } from 'viem/chains' +import { withFeePayer } from 'viem/tempo' +import { createConfig, http } from 'wagmi' + +export const config = createConfig({ + connectors: [tempoWallet()], + chains: [tempo], + multiInjectedProviderDiscovery: false, + transports: { + [tempo.id]: withFeePayer( // [!code hl] + http(), // [!code hl] + http('https://sponsor.moderato.tempo.xyz'), // [!code hl] + ), // [!code hl] + }, +}) +``` + +::: + ### Sponsor your user's transactions Now you can sponsor transactions by passing `feePayer: true` in the transaction parameters. For more details on how to send a transaction, see the [Send a payment](/guide/payments/send-a-payment) guide. diff --git a/src/pages/guide/stablecoin-dex/managing-fee-liquidity.mdx b/src/pages/guide/stablecoin-dex/managing-fee-liquidity.mdx index 70fa56f2..f4511fde 100644 --- a/src/pages/guide/stablecoin-dex/managing-fee-liquidity.mdx +++ b/src/pages/guide/stablecoin-dex/managing-fee-liquidity.mdx @@ -55,15 +55,11 @@ function ManageFeeLiquidity() { ```ts twoslash [wagmi.config.ts] // @noErrors import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' import { createConfig, http } from 'wagmi' export const config = createConfig({ - connectors: [ - webAuthn({ - keyManager: KeyManager.localStorage(), - }), - ], + connectors: [tempoWallet()], chains: [tempo], multiInjectedProviderDiscovery: false, transports: { @@ -123,15 +119,11 @@ function ManageFeeLiquidity() { ```ts twoslash [wagmi.config.ts] // @noErrors import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' import { createConfig, http } from 'wagmi' export const config = createConfig({ - connectors: [ - webAuthn({ - keyManager: KeyManager.localStorage(), - }), - ], + connectors: [tempoWallet()], chains: [tempo], multiInjectedProviderDiscovery: false, transports: { @@ -198,15 +190,11 @@ function ManageFeeLiquidity() { ```ts twoslash [wagmi.config.ts] // @noErrors import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' import { createConfig, http } from 'wagmi' export const config = createConfig({ - connectors: [ - webAuthn({ - keyManager: KeyManager.localStorage(), - }), - ], + connectors: [tempoWallet()], chains: [tempo], multiInjectedProviderDiscovery: false, transports: { @@ -285,15 +273,11 @@ function ManageFeeLiquidity() { ```ts twoslash [wagmi.config.ts] // @noErrors import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' import { createConfig, http } from 'wagmi' export const config = createConfig({ - connectors: [ - webAuthn({ - keyManager: KeyManager.localStorage(), - }), - ], + connectors: [tempoWallet()], chains: [tempo], multiInjectedProviderDiscovery: false, transports: { @@ -355,15 +339,11 @@ function MonitorSwaps() { ```ts twoslash [wagmi.config.ts] // @noErrors import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' import { createConfig, http } from 'wagmi' export const config = createConfig({ - connectors: [ - webAuthn({ - keyManager: KeyManager.localStorage(), - }), - ], + connectors: [tempoWallet()], chains: [tempo], multiInjectedProviderDiscovery: false, transports: { @@ -423,15 +403,11 @@ function RebalancePool() { ```ts twoslash [wagmi.config.ts] // @noErrors import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' +import { tempoWallet } from 'accounts/wagmi' import { createConfig, http } from 'wagmi' export const config = createConfig({ - connectors: [ - webAuthn({ - keyManager: KeyManager.localStorage(), - }), - ], + connectors: [tempoWallet()], chains: [tempo], multiInjectedProviderDiscovery: false, transports: { diff --git a/src/pages/guide/use-accounts/embed-passkeys.mdx b/src/pages/guide/use-accounts/embed-passkeys.mdx index c5266c9c..862f32bb 100644 --- a/src/pages/guide/use-accounts/embed-passkeys.mdx +++ b/src/pages/guide/use-accounts/embed-passkeys.mdx @@ -8,9 +8,9 @@ import { EmbedPasskeys, SignInButtons } from '../../../components/guides/EmbedPa # Embed Passkey Accounts -Create a domain-bound passkey account on Tempo using WebAuthn signatures for secure, passwordless authentication with [Tempo transactions](/protocol/transactions/spec-tempo-transaction). +Create a domain-bound passkey account on Tempo using the [Tempo Accounts SDK](/accounts) and WebAuthn signatures for secure, passwordless authentication with [Tempo transactions](/protocol/transactions/spec-tempo-transaction). -Passkeys enable users to authenticate with biometrics (fingerprint, Face ID, Touch ID) they already use for other apps. Keys are stored in the device's secure enclave and sync across devices via iCloud Keychain or Google Password Manager. +The [`webAuthn`](/accounts/wagmi/webAuthn) Wagmi connector is the easiest way to get started. Passkeys enable users to authenticate with biometrics (fingerprint, Face ID, Touch ID) they already use for other apps. Keys are stored in the device's secure enclave and sync across devices via iCloud Keychain or Google Password Manager. :::info @@ -49,13 +49,11 @@ Next, we will need to configure the `webAuthn` connector in our Wagmi config. // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' // [!code ++] +import { webAuthn } from 'accounts/wagmi' // [!code ++] export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ // [!code ++] - keyManager: KeyManager.localStorage(), // [!code ++] - })], // [!code ++] + connectors: [webAuthn()], // [!code ++] multiInjectedProviderDiscovery: false, transports: { [tempo.id]: http(), @@ -65,9 +63,15 @@ export const config = createConfig({ :::warning -The `KeyManager.localStorage()` implementation is not recommended for production use as it stores public keys on the client device, meaning it cannot be re-extracted when the user's storage is cleared or if the user is on another device. +Without an `authUrl`, credentials are stored locally on the client device. This means users will lose access to their passkey account if their storage is cleared or if they sign in from another device. -For production, you should opt for a remote key manager such as [`KeyManager.http`](https://wagmi.sh/tempo/keyManagers/http). +For production, you should set up a [`Handler.webAuthn`](/accounts/server/handler.webAuthn) server and pass the `authUrl` to the connector: + +```tsx +connectors: [webAuthn({ authUrl: 'https://myapp.com/auth' })] +``` + +See [Deploying to Production](/accounts/production) for more details. ::: @@ -131,13 +135,11 @@ export function Example() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' // [!code ++] +import { webAuthn } from 'accounts/wagmi' // [!code ++] export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ // [!code ++] - keyManager: KeyManager.localStorage(), // [!code ++] - })], // [!code ++] + connectors: [webAuthn()], // [!code ++] multiInjectedProviderDiscovery: false, transports: { [tempo.id]: http(), @@ -209,13 +211,11 @@ export function Example() { // @noErrors import { createConfig, http } from 'wagmi' import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' // [!code ++] +import { webAuthn } from 'accounts/wagmi' // [!code ++] export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ // [!code ++] - keyManager: KeyManager.localStorage(), // [!code ++] - })], // [!code ++] + connectors: [webAuthn()], // [!code ++] multiInjectedProviderDiscovery: false, transports: { [tempo.id]: http(), diff --git a/src/pages/guide/use-accounts/embed-tempo-wallet.mdx b/src/pages/guide/use-accounts/embed-tempo-wallet.mdx new file mode 100644 index 00000000..eaed4750 --- /dev/null +++ b/src/pages/guide/use-accounts/embed-tempo-wallet.mdx @@ -0,0 +1,309 @@ +--- +description: Embed the Tempo Wallet dialog into your application for a universal wallet experience with account management, passkeys, and fee sponsorship. +--- + +import { Cards, Card } from 'vocs' +import * as Demo from '../../../components/guides/Demo.tsx' +import { AccountsSignIn } from '../../../components/guides/AccountsSignIn.tsx' + +# Embed Tempo Wallet + +Embed the [Tempo Wallet](https://wallet.tempo.xyz) dialog into your application using the [Tempo Accounts SDK](/accounts) for a universal wallet experience. + +The [`tempoWallet`](/accounts/wagmi/tempoWallet) Wagmi connector is the easiest way to get started. It wraps the Accounts SDK and provides a complete account management experience for your users, including sign-up, sign-in, balance management, and transaction signing, all within an embedded dialog. + +:::info + +**When should I use the Tempo Wallet vs Passkey accounts?** + +The **Tempo Wallet** provides a universal wallet experience – users manage their account through the Tempo Wallet interface, and their account is portable across all applications that embed it. + +**Passkey accounts** are domain-bound – credentials are tied to your specific domain and cannot be used on other applications. This gives you full control over the authentication experience but requires more setup. + +If you want a quick integration with a full-featured wallet, use the Tempo Wallet. If you want a fully custom, domain-bound authentication experience, use [Passkey accounts](/guide/use-accounts/embed-passkeys). + +::: + +## Demo + +By the end of this guide, you will be able to embed the Tempo Wallet into your application. + + + + + +## Steps + +::::steps + +### Set up Wagmi + +Ensure that you have set up your project with Wagmi by following the [guide](/sdk/typescript#wagmi-setup). + +### Configure the Tempo Wallet Connector + +Next, we will configure the `tempoWallet` connector in our Wagmi config. + +```tsx twoslash [config.ts] +// @noErrors +import { createConfig, http } from 'wagmi' +import { tempo } from 'viem/chains' +import { tempoWallet } from 'accounts/wagmi' // [!code ++] + +export const config = createConfig({ + chains: [tempo], + connectors: [tempoWallet()], // [!code ++] + multiInjectedProviderDiscovery: false, + transports: { + [tempo.id]: http(), + }, +}) +``` + +:::tip + +This Wagmi configuration sets `multiInjectedProviderDiscovery` to `false` to +prevent injected browser wallets from being detected, and to prefer the `tempoWallet` connector. +If you would like to allow connection to other wallets, set this property to `true`. + +::: + +### Display Sign In Button + +After that, we will set up a "Sign in" button that opens the Tempo Wallet dialog for the user. + +We will create a new `Example.tsx` component to work in. + +:::code-group + +```tsx twoslash [Example.tsx] +// @noErrors +import { useConnect, useConnectors } from 'wagmi' + +export function Example() { + const connect = useConnect() + const connectors = useConnectors() + const connector = connectors.find((c) => c.id === 'xyz.tempo') + + return ( +
+ +
+ ) +} +``` + +```tsx twoslash [config.ts] filename="config.ts" +// @noErrors +import { createConfig, http } from 'wagmi' +import { tempo } from 'viem/chains' +import { tempoWallet } from 'accounts/wagmi' // [!code ++] + +export const config = createConfig({ + chains: [tempo], + connectors: [tempoWallet()], // [!code ++] + multiInjectedProviderDiscovery: false, + transports: { + [tempo.id]: http(), + }, +}) +``` + +::: + +### Display Account & Sign Out + +After the user has signed in, we can display the account information and a sign out button. + +:::code-group + +
+ +
+ +
+
+
+ +::: + +:::code-group + +```tsx twoslash [Example.tsx] +// @noErrors +import { useConnection, useConnect, useConnectors, useDisconnect } from 'wagmi' + +export function Example() { + const account = useConnection() // [!code ++] + const connect = useConnect() + const connectors = useConnectors() + const connector = connectors.find((c) => c.id === 'xyz.tempo') + const disconnect = useDisconnect() // [!code ++] + + if (account.address) // [!code ++] + return ( // [!code ++] +
{/* [!code ++] */} +
{account.address.slice(0, 6)}...{account.address.slice(-4)}
{/* [!code ++] */} + {/* [!code ++] */} +
{/* [!code ++] */} + ) // [!code ++] + + return ( +
+ +
+ ) +} + +``` + +```tsx twoslash [config.ts] filename="config.ts" +// @noErrors +import { createConfig, http } from 'wagmi' +import { tempo } from 'viem/chains' +import { tempoWallet } from 'accounts/wagmi' // [!code ++] + +export const config = createConfig({ + chains: [tempo], + connectors: [tempoWallet()], // [!code ++] + multiInjectedProviderDiscovery: false, + transports: { + [tempo.id]: http(), + }, +}) +``` + +::: + +### Deploy to Production + +When you're ready to go live, follow the [Deploying to Production](/accounts/production) guide to configure your application for production use. + +### Next Steps + +Now that you have embedded the Tempo Wallet, you can now: +- learn the [Best Practices](#best-practices) below +- follow a guide on how to [make a payment](/guide/payments), [create a stablecoin](/guide/issuance), or [exchange stablecoins](/guide/stablecoin-dex). + +:::: + +## Best Practices + +### Loading State + +When the user is logging in or signing out, we should show loading state to indicate that the process is happening. + +We can use the `isPending` property from the `useConnect` hook to show pending state to the user. + +```tsx twoslash [Example.tsx] +// @noErrors +import { useConnection, useConnect, useConnectors, useDisconnect } from 'wagmi' + +export function Example() { + const account = useConnection() + const connect = useConnect() + const connectors = useConnectors() + const connector = connectors.find((c) => c.id === 'xyz.tempo') + const disconnect = useDisconnect() + + if (connect.isPending) // [!code ++] + return
Check prompt...
{/* [!code ++] */} + return (/* ... */) +} +``` + +### Error Handling + +If an error unexpectedly occurs, we should display an error message to the user. + +We can use the `error` property from the `useConnect` hook to show error state to the user. + +```tsx twoslash [Example.tsx] +// @noErrors +import { useConnection, useConnect, useConnectors, useDisconnect } from 'wagmi' + +export function Example() { + const account = useConnection() + const connect = useConnect() + const connectors = useConnectors() + const connector = connectors.find((c) => c.id === 'xyz.tempo') + const disconnect = useDisconnect() + + if (connect.error) // [!code ++] + return
Error: {connect.error.message}
{/* [!code ++] */} + return (/* ... */) +} +``` + +### Fee Sponsorship + +The `tempoWallet` connector supports fee sponsorship via a `feePayerUrl`. This allows you to sponsor transaction fees for your users. + +```tsx twoslash [config.ts] +// @noErrors +import { createConfig, http } from 'wagmi' +import { tempo } from 'viem/chains' +import { tempoWallet } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [tempoWallet({ + feePayerUrl: 'https://sponsor.example.com', // [!code ++] + })], + transports: { + [tempo.id]: http(), + }, +}) +``` + +See the [Sponsor user fees](/guide/payments/sponsor-user-fees) guide for more details on setting up a fee payer server. + +### Access Key Limits + +You can configure default access key parameters to restrict the tokens and amounts a session key can spend: + +```tsx twoslash [config.ts] +// @noErrors +import { parseUnits } from 'viem' +import { createConfig, http } from 'wagmi' +import { tempo } from 'viem/chains' +import { Expiry } from 'accounts' +import { tempoWallet } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [tempoWallet({ + authorizeAccessKey: () => ({ // [!code ++] + expiry: Expiry.days(1), // [!code ++] + limits: [{ // [!code ++] + token: '0x...', // [!code ++] + limit: parseUnits('100', 6), // [!code ++] + }], // [!code ++] + }), // [!code ++] + })], + transports: { + [tempo.id]: http(), + }, +}) +``` + +## Learning Resources + + + + + diff --git a/src/pages/sdk/typescript/index.mdx b/src/pages/sdk/typescript/index.mdx index bb9c435a..8fdf9a16 100644 --- a/src/pages/sdk/typescript/index.mdx +++ b/src/pages/sdk/typescript/index.mdx @@ -6,18 +6,6 @@ import { Cards, Card } from 'vocs' # TypeScript SDKs -:::note -**Note:** `tempo.ts/chains` & `tempo.ts/viem` have been upstreamed into [Viem](https://viem.sh/tempo) as of `viem@2.43.0`. If you are using either entrypoint, please update to use `viem/chains` or `viem/tempo` instead. - -[Migration Guide](https://github.com/tempoxyz/tempo-ts/releases/tag/tempo.ts%400.12.0) -::: - -:::note -**Note:** `tempo.ts/wagmi` has been upstreamed into [Wagmi](https://wagmi.sh/tempo) as of `wagmi@3.2.0` and `@wagmi/core@3.1.0`. Please update to use `wagmi/tempo` or `@wagmi/core/tempo` instead. - -[Migration Guide](https://github.com/tempoxyz/tempo-ts/releases/tag/tempo.ts%400.13.0) -::: - Tempo distributes TypeScript SDKs for: - [Viem](https://viem.sh): TypeScript interface for EVM blockchains diff --git a/src/pages/sdk/typescript/server/handler.compose.mdx b/src/pages/sdk/typescript/server/handler.compose.mdx deleted file mode 100644 index 2f6b2798..00000000 --- a/src/pages/sdk/typescript/server/handler.compose.mdx +++ /dev/null @@ -1,110 +0,0 @@ ---- -description: Combine multiple Tempo server handlers into a single endpoint. Run fee payer and key manager services together from one server. ---- - -# `Handler.compose` - -Composes multiple handlers into a single handler. This is useful when you want to run multiple services (like fee payer and key manager) from a single endpoint. - -## Usage - -```ts twoslash [server.ts] -// @noErrors -import { Handler, Kv } from 'tempo.ts/server' -import { tempo } from 'viem/chains' -import { http } from 'viem' -import { privateKeyToAccount } from 'viem/accounts' - -const handler = Handler.compose([ - // Create a fee payer handler - Handler.feePayer({ - account: privateKeyToAccount('0x...'), - chain: tempo.extend({ - feeToken: '0x20c0...0001' - }), - transport: http(), - path: '/fee-payer', - }) - - // Create a key manager handler - Handler.keyManager({ - kv: Kv.memory(), - path: '/keys', - rp: 'example.com', - }) -]) -``` - -Then plug `handler` into your server framework of choice. For example: - -```ts -createServer(handler.listener) // Node.js -Bun.serve(handler) // Bun -Deno.serve(handler) // Deno -app.all('*', c => handler.fetch(c.request)) // Elysia -app.use(handler.listener) // Express -app.use(c => handler.fetch(c.req.raw)) // Hono -export const GET = handler.fetch // Next.js -export const POST = handler.fetch // Next.js -``` -### Base Path - -You can configure the base path for the composed handler. - -```ts -const handler = Handler.compose([ - Handler.feePayer({ path: '/fee-payer', ... }), - Handler.keyManager({ path: '/keys', ... }), -], { path: '/api' }) -``` - -Requests are routed as follows: -- `POST /api/fee-payer` → Fee payer handler -- `GET /api/keys/challenge` → Key manager handler -- `GET /api/keys/:credentialId` → Key manager handler -- `POST /api/keys/:credentialId` → Key manager handler - -## Parameters - -### handlers - -- **Type:** `Handler[]` - -An array of handlers to compose. Handlers are tried in order, and the first one that doesn't return a 404 wins. - -```ts twoslash -// @noErrors -import { Handler } from 'tempo.ts/server' - -const handler = Handler.compose([ - Handler.feePayer({ /* ... */ }), - Handler.keyManager({ /* ... */ }), - // Add more handlers as needed -]) -``` - -### options.path - -- **Type:** `string` -- **Default:** `'/'` - -The base path where all composed handlers will be mounted. This path is stripped from incoming requests before forwarding to individual handlers. - -```ts twoslash -// @noErrors -import { Handler } from 'tempo.ts/server' - -const handler = Handler.compose( - [ - Handler.feePayer({ path: '/fee-payer', /* ... */ }), - Handler.keyManager({ path: '/keys', /* ... */ }), - ], - { path: '/api' }, // [!code focus] -) - -// Endpoints will be: -// POST /api/fee-payer -// GET /api/keys/challenge -// GET /api/keys/:credentialId -// POST /api/keys/:credentialId -``` diff --git a/src/pages/sdk/typescript/server/handler.feePayer.mdx b/src/pages/sdk/typescript/server/handler.feePayer.mdx deleted file mode 100644 index aa897add..00000000 --- a/src/pages/sdk/typescript/server/handler.feePayer.mdx +++ /dev/null @@ -1,117 +0,0 @@ ---- -description: Create a server handler to subsidize gas costs for users. Sign transactions with a dedicated fee payer account on your backend. ---- - -# `Handler.feePayer` - -Creates a server handler that acts as a fee payer for transactions. -This enables you to subsidize gas costs for your users by signing transactions with a dedicated fee payer account on your backend. - -## Usage - -:::code-group - -```ts twoslash [server.ts] -// @noErrors -import { Handler } from 'tempo.ts/server' -import { tempo } from 'viem/chains' -import { http } from 'viem' -import { privateKeyToAccount } from 'viem/accounts' - -const handler = Handler.feePayer({ - account: privateKeyToAccount('0x...'), - chain: tempo.extend({ feeToken: '0x20c0...0001' }), - path: '/fee-payer', - transport: http(), -}) -``` - -```ts twoslash [example.client.ts] -// @noErrors -import { createClient, http, walletActions } from 'viem' -import { tempo } from 'viem/chains' -import { tempoActions, withFeePayer } from 'viem/tempo' - -const client = createClient({ - chain: tempo, - transport: withFeePayer( - http(), // Default transport - http('http://localhost:3000/fee-payer'), // Fee payer transport (your server) - ), -}).extend(tempoActions()) - -// Send a fee-sponsored payment -const receipt = await client.token.transferSync({ - amount: parseUnits('10', 6), - feePayer: true, - to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb', - token: '0x20c0000000000000000000000000000000000001', -}) -``` - -::: - -Then plug `handler` into your server framework of choice. For example: - -```ts -createServer(handler.listener) // Node.js -Bun.serve(handler) // Bun -Deno.serve(handler) // Deno -app.all('*', c => handler.fetch(c.request)) // Elysia -app.use(handler.listener) // Express -app.use(c => handler.fetch(c.req.raw)) // Hono -export const GET = handler.fetch // Next.js -export const POST = handler.fetch // Next.js -``` - - -## How It Works - -The fee payer handler intercepts RPC requests and handles the following methods: - -- **`eth_signTransaction`** - Signs a transaction with the fee payer account -- **`eth_signRawTransaction`** - Signs a pre-serialized transaction with the fee payer account -- **`eth_sendRawTransaction`** - Signs and broadcasts a transaction with the fee payer account -- **`eth_sendRawTransactionSync`** - Signs, broadcasts, and waits for confirmation - -For each of these methods, the handler: -1. Deserializes the transaction (if necessary) -2. Signs the transaction with your fee payer account -3. Returns the signed transaction or transaction hash - -## Parameters - -### account - -- **Type:** `LocalAccount` -- **Required:** Yes - -The account to use as the fee payer. This account will sign all transactions and pay the gas fees. - -### chain - -- **Type:** `Chain` - -Chain (and fee token) to use. - -### transport - -- **Type:** `Transport` - -Transport to use. - -### path - -- **Type:** `string` -- **Default:** `'/'` -- **Optional** - -The path where the handler will listen for requests. - -### onRequest - -- **Type:** `(request: RpcRequest) => Promise` -- **Optional** - -A callback function that's called before processing each request. Useful for logging, rate limiting, or custom validation. - diff --git a/src/pages/sdk/typescript/server/handler.keyManager.mdx b/src/pages/sdk/typescript/server/handler.keyManager.mdx deleted file mode 100644 index c5f04c6c..00000000 --- a/src/pages/sdk/typescript/server/handler.keyManager.mdx +++ /dev/null @@ -1,168 +0,0 @@ ---- -description: Create a server handler to manage WebAuthn credential public keys. Enable passkey authentication for users across multiple devices. ---- - -# `Handler.keyManager` - -Creates a server handler that manages WebAuthn credential public keys. This handler stores and retrieves the public keys associated with passkey credentials, enabling users to access their accounts from any device. - -## Usage - -:::code-group - -```ts twoslash [server.ts] -// @noErrors -import { Handler, Kv } from 'tempo.ts/server' - -const handler = Handler.keyManager({ - kv: Kv.memory(), - path: '/keys', - rp: 'example.com', -}) -``` - -```ts twoslash [wagmi.config.ts] -// @noErrors -import { tempo } from 'viem/chains' -import { KeyManager, webAuthn } from 'wagmi/tempo' -import { createConfig, http } from 'wagmi' - -export const config = createConfig({ - connectors: [ - webAuthn({ - keyManager: KeyManager.http('http://localhost:3000/keys'), - rpId: 'example.com', - }), - ], - chains: [tempo], - transports: { - [tempo.id]: http(), - }, -}) -``` - -::: - -Then plug `handler` into your server framework of choice. For example: - -```ts -createServer(handler.listener) // Node.js -Bun.serve(handler) // Bun -Deno.serve(handler) // Deno -app.all('*', c => handler.fetch(c.request)) // Elysia -app.use(handler.listener) // Express -app.use(c => handler.fetch(c.req.raw)) // Hono -export const GET = handler.fetch // Next.js -export const POST = handler.fetch // Next.js -``` - -:::warning - -It is not recommended to use `Kv.memory()` in production. Instead, use a persistent store like Cloudflare or Vercel KV, or a Redis instance. - -::: - -## How It Works - -The key manager handler exposes three endpoints: - -### `GET /{path}/challenge` - -Generates a random challenge for WebAuthn credential creation. The challenge is stored temporarily (with a 5-minute expiration) to be verified later during credential registration. - -### `GET /{path}/:credentialId` - -Retrieves the public key for a given credential ID. This is used when a user authenticates with an existing passkey. - -### `POST /{path}/:credentialId` - -Stores a public key for a new credential. This endpoint: -1. Verifies the challenge was previously issued and is still valid -2. Validates the credential's `clientDataJSON.type` is `'webauthn.create'` -3. Verifies the origin matches the configured RP ID (if set) -4. Extracts and stores the public key from the authenticator data - -## Parameters - -### kv - -- **Type:** `Kv` -- **Required:** Yes - -The key-value store to use for persisting challenges and public keys. tempo.ts provides adapters for common KV stores: - -```ts twoslash -// @noErrors -import { Kv } from 'tempo.ts/server' - -// In-memory store (for development/testing) -const kv = Kv.memory() - -// Cloudflare KV -import { env } from 'cloudflare:workers' -const kv = Kv.cloudflare(env.KEY_STORE) -``` - -:::warning -`Kv.memory()` stores data only in memory and will be lost when the server restarts. Use a persistent store like Cloudflare or Vercel KV, or a Redis instance in production. -::: - -### path - -- **Type:** `string` - -The base path where the handler will listen for requests. All three endpoints (`/challenge`, `/:credentialId`) will be mounted under this path. - -```ts twoslash -// @noErrors -import { Handler } from 'tempo.ts/server' - -const handler = Handler.keyManager({ - // ... other options - path: '/api/keys', // [!code focus] -}) - -// Endpoints will be: -// GET /api/keys/challenge -// GET /api/keys/:credentialId -// POST /api/keys/:credentialId -``` - -### rp - -- **Type:** `string | { id: string, name?: string }` - -The Relying Party (RP) identifier and name. This is used to: -- Include RP information in the challenge response -- Verify the origin of credential registration requests - -```ts twoslash -// @noErrors -import { Handler } from 'tempo.ts/server' - -// Simple string (uses as both id and name) -const handler = Handler.keyManager({ - // ... other options - rp: 'example.com', // [!code focus] -}) - -// Object with custom name -const handler2 = Handler.keyManager({ - // ... other options - rp: { // [!code focus] - id: 'example.com', // [!code focus] - name: 'Example App', // [!code focus] - }, // [!code focus] -}) -``` - -:::info -The RP ID must match the domain where your application is hosted. For localhost, the origin verification is automatically skipped. -::: - -## Storage Schema - -The handler uses the following key patterns in the KV store: - -- **`challenge:{hex}`** - Stores issued challenges -- **`credential:{credentialId}`** - Stores public keys diff --git a/src/snippets/unformatted/withFeePayer.ts b/src/snippets/unformatted/withFeePayer.ts index 2ec49c4e..91299c37 100644 --- a/src/snippets/unformatted/withFeePayer.ts +++ b/src/snippets/unformatted/withFeePayer.ts @@ -30,23 +30,13 @@ const _receipt2 = await client.sendTransactionSync({ // [!endregion usage] -import { Handler } from 'tempo.ts/server' // [!region server] -import { createClient, http } from 'viem' +import { Handler } from 'accounts/server' import { privateKeyToAccount } from 'viem/accounts' -import { tempo } from 'viem/chains' - -const client = createClient({ - chain: tempo.extend({ - feeToken: '0x20c0000000000000000000000000000000000001', - }), - transport: http(), -}) const handler = Handler.feePayer({ // [!code hl] account: privateKeyToAccount('0x...'), // [!code hl] - client, // [!code hl] }) // [!code hl] const server = createServer(handler.listener) diff --git a/src/snippets/wagmi.config.ts b/src/snippets/wagmi.config.ts index 0fce1d1f..d0706f92 100644 --- a/src/snippets/wagmi.config.ts +++ b/src/snippets/wagmi.config.ts @@ -2,18 +2,14 @@ // biome-ignore-all lint: snippet // biome-ignore-all format: snippet -import { KeyManager, webAuthn } from 'tempo.ts/wagmi' // [!region setup] +import { tempoWallet } from 'accounts/wagmi' import { tempo } from 'viem/chains' import { createConfig, http } from 'wagmi' import { KeyManager, webAuthn } from 'wagmi/tempo' export const config = createConfig({ - connectors: [ - webAuthn({ - keyManager: KeyManager.http('https://keys.tempo.xyz'), - }), - ], + connectors: [tempoWallet()], chains: [tempo], multiInjectedProviderDiscovery: false, transports: { @@ -23,8 +19,8 @@ export const config = createConfig({ // [!endregion setup] -import { KeyManager, webAuthn } from 'tempo.ts/wagmi' // [!region withFeePayer] +import { tempoWallet } from 'accounts/wagmi' import { tempo } from 'viem/chains' import { withFeePayer } from 'viem/tempo' import { createConfig, http } from 'wagmi' @@ -32,14 +28,14 @@ import { KeyManager, webAuthn } from 'wagmi/tempo' export const config = createConfig({ connectors: [ - webAuthn({ - keyManager: KeyManager.http('https://keys.tempo.xyz'), + tempoWallet({ + feePayerUrl: 'https://sponsor.moderato.tempo.xyz', }), ], chains: [tempo], multiInjectedProviderDiscovery: false, transports: { - [tempo.id]: withFeePayer(http(), http('https://sponsor.moderato.tempo.xyz')), + [tempo.id]: http(), }, }) // [!endregion withFeePayer] diff --git a/src/wagmi.config.ts b/src/wagmi.config.ts index 02c77c1a..d36b8906 100644 --- a/src/wagmi.config.ts +++ b/src/wagmi.config.ts @@ -1,8 +1,20 @@ import { QueryClient } from '@tanstack/react-query' +import { Expiry } from 'accounts' +import { tempoWallet } from 'accounts/wagmi' +import * as React from 'react' +import { parseUnits } from 'viem' import { tempoDevnet, tempoLocalnet, tempoModerato } from 'viem/chains' import { withFeePayer } from 'viem/tempo' -import { type CreateConfigParameters, createConfig, createStorage, http, webSocket } from 'wagmi' +import { + type CreateConfigParameters, + createConfig, + createStorage, + http, + useConnectors, + webSocket, +} from 'wagmi' import { KeyManager, webAuthn } from 'wagmi/tempo' +import { alphaUsd, betaUsd, pathUsd, thetaUsd } from './components/guides/tokens' const feeToken = '0x20c0000000000000000000000000000000000001' @@ -28,8 +40,23 @@ export function getConfig(options: getConfig.Options = {}) { }, chains: [chain], connectors: [ + tempoWallet({ + authorizeAccessKey: () => ({ + expiry: Expiry.days(1), + limits: [ + { token: pathUsd, limit: parseUnits('500', 6) }, + { token: alphaUsd, limit: parseUnits('500', 6) }, + { token: betaUsd, limit: parseUnits('500', 6) }, + { token: thetaUsd, limit: parseUnits('500', 6) }, + ], + }), + feePayerUrl: 'https://sponsor.moderato.tempo.xyz', + }), webAuthn({ - grantAccessKey: { chainId: BigInt(chain.id) } as any, + grantAccessKey: { + // @ts-expect-error - TODO: migrate to webAuthn on Accounts SDK + chainId: BigInt(chain.id), + }, keyManager: KeyManager.http('https://keys.tempo.xyz'), rpId, }), @@ -67,6 +94,24 @@ export const config = getConfig() export const queryClient = new QueryClient() +export function useTempoWalletConnector() { + const connectors = useConnectors() + return React.useMemo( + // biome-ignore lint/style/noNonNullAssertion: _ + () => connectors.find((connector) => connector.id === 'xyz.tempo')!, + [connectors], + ) +} + +export function useWebAuthnConnector() { + const connectors = useConnectors() + return React.useMemo( + // biome-ignore lint/style/noNonNullAssertion: _ + () => connectors.find((connector) => connector.id === 'webAuthn')!, + [connectors], + ) +} + declare module 'wagmi' { interface Register { config: typeof config diff --git a/vite.config.ts b/vite.config.ts index 5fb213cb..ddbda55a 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,6 +3,7 @@ import * as path from 'node:path' import react from '@vitejs/plugin-react' import { Instance } from 'prool' import { defineConfig, loadEnv, type Plugin } from 'vite' +import mkcert from 'vite-plugin-mkcert' import { vocs } from 'vocs/vite' // https://vite.dev/config/ @@ -12,7 +13,7 @@ export default defineConfig(({ mode }) => { if (!(key in process.env)) process.env[key] = env[key] } return { - plugins: [syncTips(), vocs(), react(), tempoNode()], + plugins: [syncTips(), vocs(), react(), mkcert(), tempoNode()], } }) diff --git a/vocs.config.ts b/vocs.config.ts index 5d486188..c8b1ac08 100644 --- a/vocs.config.ts +++ b/vocs.config.ts @@ -92,6 +92,10 @@ export default defineConfig({ text: 'Overview', link: '/guide/use-accounts', }, + { + text: 'Embed Tempo Wallet', + link: '/guide/use-accounts/embed-tempo-wallet', + }, { text: 'Embed Passkey accounts', link: '/guide/use-accounts/embed-passkeys', @@ -549,6 +553,10 @@ export default defineConfig({ { text: 'Tempo Developer Tools', items: [ + { + text: 'Accounts', + link: '/accounts', + }, { text: 'CLI', collapsed: true, @@ -599,32 +607,6 @@ export default defineConfig({ text: 'Wagmi Reference', link: 'https://wagmi.sh/tempo', }, - { - text: 'Server Reference', - items: [ - { - text: 'Handlers', - items: [ - { - text: 'Overview', - link: '/sdk/typescript/server/handlers', - }, - { - text: 'compose', - link: '/sdk/typescript/server/handler.compose', - }, - { - text: 'feePayer', - link: '/sdk/typescript/server/handler.feePayer', - }, - { - text: 'keyManager', - link: '/sdk/typescript/server/handler.keyManager', - }, - ], - }, - ], - }, { text: 'Prool Reference', items: [ @@ -730,6 +712,222 @@ export default defineConfig({ // ], // }, ], + '/accounts': { + backLink: true, + items: [ + { + text: 'Accounts SDK', + items: [ + { + text: 'Getting Started', + link: '/accounts', + }, + { + text: 'Deploying to Production', + link: '/accounts/production', + }, + { + text: 'FAQ', + link: '/accounts/faq', + }, + ], + }, + { + text: 'Core', + items: [ + { + text: 'Provider', + link: '/accounts/api/provider', + }, + { + text: 'Adapters', + collapsed: true, + items: [ + { + text: 'Overview', + link: '/accounts/api/adapters', + }, + { + text: 'dialog', + link: '/accounts/api/dialog', + }, + { + text: 'webAuthn', + link: '/accounts/api/webAuthn', + }, + { + text: 'local', + link: '/accounts/api/local', + }, + ], + }, + { + text: 'Dialog', + collapsed: true, + items: [ + { + text: 'Overview', + link: '/accounts/api/dialogs', + }, + { + text: '.iframe', + link: '/accounts/api/dialog.iframe', + }, + { + text: '.popup', + link: '/accounts/api/dialog.popup', + }, + ], + }, + { + text: 'Expiry', + link: '/accounts/api/expiry', + }, + { + text: 'WebAuthnCeremony', + collapsed: true, + items: [ + { + text: 'Overview', + link: '/accounts/api/ceremony', + }, + { + text: '.from', + link: '/accounts/api/ceremony.from', + }, + { + text: '.local', + link: '/accounts/api/ceremony.local', + }, + { + text: '.server', + link: '/accounts/api/ceremony.server', + }, + ], + }, + ], + }, + { + text: 'Wagmi', + items: [ + { + text: 'Connectors', + collapsed: true, + items: [ + { + text: 'Overview', + link: '/accounts/wagmi', + }, + { + text: 'tempoWallet', + link: '/accounts/wagmi/tempoWallet', + }, + { + text: 'webAuthn', + link: '/accounts/wagmi/webAuthn', + }, + ], + }, + ], + }, + { + text: 'Server', + items: [ + { + text: 'Handlers', + collapsed: true, + items: [ + { + text: 'Overview', + link: '/accounts/server', + }, + { + text: '.compose', + link: '/accounts/server/handler.compose', + }, + { + text: '.feePayer', + link: '/accounts/server/handler.feePayer', + }, + { + text: '.webAuthn', + link: '/accounts/server/handler.webAuthn', + }, + ], + }, + { + text: 'Kv', + link: '/accounts/server/kv', + }, + ], + }, + { + text: 'JSON-RPC', + items: [ + { + text: 'wallet_connect 🚧', + disabled: true, + link: '/accounts/rpc/wallet_connect', + }, + { + text: 'wallet_disconnect 🚧', + disabled: true, + link: '/accounts/rpc/wallet_disconnect', + }, + { + text: 'wallet_authorizeAccessKey 🚧', + disabled: true, + link: '/accounts/rpc/wallet_authorizeAccessKey', + }, + { + text: 'wallet_revokeAccessKey 🚧', + disabled: true, + link: '/accounts/rpc/wallet_revokeAccessKey', + }, + { + text: 'wallet_getBalances 🚧', + disabled: true, + link: '/accounts/rpc/wallet_getBalances', + }, + { + text: 'wallet_getCapabilities 🚧', + disabled: true, + link: '/accounts/rpc/wallet_getCapabilities', + }, + { + text: 'wallet_getCallsStatus 🚧', + disabled: true, + link: '/accounts/rpc/wallet_getCallsStatus', + }, + { + text: 'wallet_sendCalls 🚧', + disabled: true, + link: '/accounts/rpc/wallet_sendCalls', + }, + { + text: 'eth_sendTransaction 🚧', + disabled: true, + link: '/accounts/rpc/eth_sendTransaction', + }, + { + text: 'eth_sendTransactionSync 🚧', + disabled: true, + link: '/accounts/rpc/eth_sendTransactionSync', + }, + { + text: 'eth_fillTransaction 🚧', + disabled: true, + link: '/accounts/rpc/eth_fillTransaction', + }, + { + text: 'personal_sign 🚧', + disabled: true, + link: '/accounts/rpc/personal_sign', + }, + ], + }, + ], + }, '/learn': [ { text: 'Home', @@ -879,7 +1077,28 @@ export default defineConfig({ }, { source: '/sdk/typescript/server', - destination: '/sdk/typescript/server/handlers', + destination: '/accounts/server', + status: 301, + }, + { + source: '/sdk/typescript/server/handlers', + destination: '/accounts/server', + status: 301, + }, + { + source: '/sdk/typescript/server/handler.compose', + destination: '/accounts/server/handler.compose', + status: 301, + }, + { + source: '/sdk/typescript/server/handler.feePayer', + destination: '/accounts/server/handler.feePayer', + status: 301, + }, + { + source: '/sdk/typescript/server/handler.keyManager', + destination: '/accounts/server/handler.webAuthn', + status: 301, }, { source: '/sdk/typescript/prool', From b6c5a07b81326e1a848229a34bdd5ca2319a7cbc Mon Sep 17 00:00:00 2001 From: jxom <7336481+jxom@users.noreply.github.com> Date: Mon, 6 Apr 2026 18:12:44 +1000 Subject: [PATCH 2/8] accounts docs: guides sidebar, update deps, vocs Amp-Thread-ID: https://ampcode.com/threads/T-019d6176-f3a7-71b8-a7e9-3fc5fbf3911a --- package.json | 2 +- pnpm-lock.yaml | 12 ++++++------ vocs.config.ts | 25 +++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index b45abda3..8ddc628e 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "@vercel/analytics": "^1.6.1", "@vercel/speed-insights": "^1.3.1", "abitype": "^1.2.3", - "accounts": "^0.4.20", + "accounts": "^0.4.23", "cva": "1.0.0-beta.4", "mermaid": "^11.12.2", "monaco-editor": "^0.55.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b38a48dd..6e659898 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,8 +38,8 @@ importers: specifier: ^1.2.3 version: 1.2.3(typescript@5.9.3)(zod@4.3.5) accounts: - specifier: ^0.4.20 - version: 0.4.20(@modelcontextprotocol/sdk@1.29.0(zod@4.3.5))(@types/react@19.2.9)(@wagmi/core@3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)))(express@5.2.1)(hono@4.11.5)(openapi-types@12.1.3)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)) + specifier: ^0.4.23 + version: 0.4.23(@modelcontextprotocol/sdk@1.29.0(zod@4.3.5))(@types/react@19.2.9)(@wagmi/core@3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)))(express@5.2.1)(hono@4.11.5)(openapi-types@12.1.3)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)) cva: specifier: 1.0.0-beta.4 version: 1.0.0-beta.4(typescript@5.9.3) @@ -1673,8 +1673,8 @@ packages: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} - accounts@0.4.20: - resolution: {integrity: sha512-mDYAPqOGpsMpqCvorDrXNV4dSQ6DXYzX3V4k9N8bvRMJa2CvukxEcwRNjB5SNqDdQk0xi6rqjjgttrVa21S1mQ==} + accounts@0.4.23: + resolution: {integrity: sha512-P/lv8ymHx/+8IfdFSNjJSTHsNEtlFDWOwbQb3OBqQ95yKjpl9q83kZFeyIGQl1iLBMuxgRkEsMKf8vnJa6pfBw==} peerDependencies: '@wagmi/core': '>=2' react: '>=18' @@ -5706,7 +5706,7 @@ snapshots: mime-types: 3.0.2 negotiator: 1.0.0 - accounts@0.4.20(@modelcontextprotocol/sdk@1.29.0(zod@4.3.5))(@types/react@19.2.9)(@wagmi/core@3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)))(express@5.2.1)(hono@4.11.5)(openapi-types@12.1.3)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)): + accounts@0.4.23(@modelcontextprotocol/sdk@1.29.0(zod@4.3.5))(@types/react@19.2.9)(@wagmi/core@3.4.0(@tanstack/query-core@5.90.19)(@types/react@19.2.9)(ox@0.11.3(typescript@5.9.3)(zod@4.3.5))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)))(express@5.2.1)(hono@4.11.5)(openapi-types@12.1.3)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))(viem@2.47.10(typescript@5.9.3)(zod@4.3.5)): dependencies: '@remix-run/fetch-router': 0.17.0 idb-keyval: 6.2.2 @@ -7386,7 +7386,7 @@ snapshots: mlly@1.8.0: dependencies: - acorn: 8.16.0 + acorn: 8.15.0 pathe: 2.0.3 pkg-types: 1.3.1 ufo: 1.6.3 diff --git a/vocs.config.ts b/vocs.config.ts index c8b1ac08..7c2ca5c9 100644 --- a/vocs.config.ts +++ b/vocs.config.ts @@ -732,6 +732,31 @@ export default defineConfig({ }, ], }, + { + text: 'Guides', + items: [ + { + text: 'Embed Tempo Wallet', + link: '/guide/use-accounts/embed-tempo-wallet', + external: true, + }, + { + text: 'Make Payments', + link: '/guide/payments', + external: true, + }, + { + text: 'Issue Stablecoins', + link: '/guide/issuance', + external: true, + }, + { + text: 'Exchange Stablecoins', + link: '/guide/stablecoin-dex', + external: true, + }, + ], + }, { text: 'Core', items: [ From 9b3654b85a46c7778d0df12a59e1a5561c69696e Mon Sep 17 00:00:00 2001 From: jxom <7336481+jxom@users.noreply.github.com> Date: Tue, 7 Apr 2026 09:13:43 +1000 Subject: [PATCH 3/8] wip Amp-Thread-ID: https://ampcode.com/threads/T-019d6478-0703-7239-b479-27de573344e6 --- src/pages/accounts/api/adapters.mdx | 3 + src/pages/accounts/api/ceremony.mdx | 8 - src/pages/accounts/api/dialog.mdx | 2 +- src/pages/accounts/api/dialogs.mdx | 2 + src/pages/accounts/api/local.mdx | 58 +++++++ src/pages/accounts/api/provider.mdx | 7 +- src/pages/accounts/api/webAuthn.mdx | 57 +++++- ...ony.from.mdx => webauthnceremony.from.mdx} | 0 ...y.local.mdx => webauthnceremony.local.mdx} | 0 src/pages/accounts/api/webauthnceremony.mdx | 31 ++++ ...server.mdx => webauthnceremony.server.mdx} | 0 src/pages/accounts/faq.mdx | 8 + .../guides/create-and-use-accounts.mdx | 45 +++++ src/pages/accounts/index.mdx | 50 +++--- .../accounts/server/handler.feePayer.mdx | 60 +++++++ .../accounts/server/handler.webAuthn.mdx | 86 ++++++++- src/pages/accounts/server/index.mdx | 3 + src/pages/accounts/wagmi/index.mdx | 2 + src/pages/accounts/wagmi/tempoWallet.mdx | 136 ++++++++++++++- src/pages/accounts/wagmi/webAuthn.mdx | 163 +++++++++++++++++- .../guide/payments/sponsor-user-fees.mdx | 29 +++- .../guide/use-accounts/embed-passkeys.mdx | 79 ++++++--- .../guide/use-accounts/embed-tempo-wallet.mdx | 53 ++---- src/pages/guide/use-accounts/index.mdx | 43 +++-- vocs.config.ts | 25 +-- 25 files changed, 805 insertions(+), 145 deletions(-) delete mode 100644 src/pages/accounts/api/ceremony.mdx rename src/pages/accounts/api/{ceremony.from.mdx => webauthnceremony.from.mdx} (100%) rename src/pages/accounts/api/{ceremony.local.mdx => webauthnceremony.local.mdx} (100%) create mode 100644 src/pages/accounts/api/webauthnceremony.mdx rename src/pages/accounts/api/{ceremony.server.mdx => webauthnceremony.server.mdx} (100%) create mode 100644 src/pages/accounts/guides/create-and-use-accounts.mdx diff --git a/src/pages/accounts/api/adapters.mdx b/src/pages/accounts/api/adapters.mdx index 72e0f063..37b74b90 100644 --- a/src/pages/accounts/api/adapters.mdx +++ b/src/pages/accounts/api/adapters.mdx @@ -12,16 +12,19 @@ Adapters control how accounts are created and managed. Pass an adapter to `Provi diff --git a/src/pages/accounts/api/ceremony.mdx b/src/pages/accounts/api/ceremony.mdx deleted file mode 100644 index e445855e..00000000 --- a/src/pages/accounts/api/ceremony.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: WebAuthnCeremony -description: Pluggable strategy for WebAuthn registration and authentication ceremonies. ---- - -# `WebAuthnCeremony` - -Pluggable strategy for WebAuthn registration and authentication ceremonies. A `WebAuthnCeremony` controls how challenges are generated and responses are verified during passkey registration and login. diff --git a/src/pages/accounts/api/dialog.mdx b/src/pages/accounts/api/dialog.mdx index 5acd8e79..2b2ace93 100644 --- a/src/pages/accounts/api/dialog.mdx +++ b/src/pages/accounts/api/dialog.mdx @@ -5,7 +5,7 @@ description: Adapter for the Tempo Wallet dialog, an embedded iframe or popup fo # `dialog` -Creates an adapter that delegates signing to the Tempo Wallet via an embedded iframe or popup dialog. Also exported as `tempoWallet`. +Enables universal wallet experiences by delegating signing to an external origin dialog. Also exported as `tempoWallet`. ## Usage diff --git a/src/pages/accounts/api/dialogs.mdx b/src/pages/accounts/api/dialogs.mdx index a44b586e..8eb95ff5 100644 --- a/src/pages/accounts/api/dialogs.mdx +++ b/src/pages/accounts/api/dialogs.mdx @@ -12,11 +12,13 @@ Dialog modes control how the Tempo Wallet is embedded into your app. Pass a dial diff --git a/src/pages/accounts/api/local.mdx b/src/pages/accounts/api/local.mdx index 1c492633..48c76dde 100644 --- a/src/pages/accounts/api/local.mdx +++ b/src/pages/accounts/api/local.mdx @@ -30,6 +30,19 @@ const provider = Provider.create({ Create a new account. Omit for login-only flows. +```ts twoslash +import { local, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: local({ + loadAccounts: async () => ({ accounts: [{ address: '0x...' }] }), + createAccount: async () => ({ // [!code focus] + accounts: [{ address: '0x...' }], // [!code focus] + }), // [!code focus] + }), +}) +``` + ### icon - **Type:** `` `data:image/${string}` `` @@ -37,6 +50,17 @@ Create a new account. Omit for login-only flows. Data URI of the provider icon. +```ts twoslash +import { local, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: local({ + loadAccounts: async () => ({ accounts: [{ address: '0x...' }] }), + icon: 'data:image/svg+xml,...', // [!code focus] + }), +}) +``` + ### loadAccounts - **Type:** `(params?) => Promise<{ accounts: Account[] }>` @@ -44,6 +68,18 @@ Data URI of the provider icon. Discover existing accounts (e.g. via WebAuthn assertion or key lookup). +```ts twoslash +import { local, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: local({ + loadAccounts: async () => ({ // [!code focus] + accounts: [{ address: '0x...' }], // [!code focus] + }), // [!code focus] + }), +}) +``` + ### name - **Type:** `string` @@ -51,9 +87,31 @@ Discover existing accounts (e.g. via WebAuthn assertion or key lookup). Display name of the provider. +```ts twoslash +import { local, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: local({ + loadAccounts: async () => ({ accounts: [{ address: '0x...' }] }), + name: 'My Wallet', // [!code focus] + }), +}) +``` + ### rdns - **Type:** `string` - **Optional** Reverse DNS identifier. + +```ts twoslash +import { local, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: local({ + loadAccounts: async () => ({ accounts: [{ address: '0x...' }] }), + rdns: 'com.example.wallet', // [!code focus] + }), +}) +``` diff --git a/src/pages/accounts/api/provider.mdx b/src/pages/accounts/api/provider.mdx index d42b60b6..011d6009 100644 --- a/src/pages/accounts/api/provider.mdx +++ b/src/pages/accounts/api/provider.mdx @@ -82,9 +82,10 @@ import { Expiry, Provider } from 'accounts' const provider = Provider.create({ authorizeAccessKey: () => ({ // [!code focus] expiry: Expiry.days(7), // [!code focus] - limits: [ // [!code focus] - { token: '0x20c0000000000000000000000000000000000001', limit: parseUnits('500', 6) }, // [!code focus] - ], // [!code focus] + limits: [{ // [!code focus] + token: '0x20c0000000000000000000000000000000000001', // [!code focus] + limit: parseUnits('500', 6), // [!code focus] + }], // [!code focus] }), // [!code focus] }) ``` diff --git a/src/pages/accounts/api/webAuthn.mdx b/src/pages/accounts/api/webAuthn.mdx index 67cf0263..2bc83ce8 100644 --- a/src/pages/accounts/api/webAuthn.mdx +++ b/src/pages/accounts/api/webAuthn.mdx @@ -5,7 +5,7 @@ description: Adapter for passkey-based accounts using WebAuthn registration and # `webAuthn` -Creates a WebAuthn adapter backed by real passkey ceremonies. Wraps the `local` adapter with WebAuthn registration and authentication flows. +Enables domain-bound passkey experiences by wrapping the `local` adapter with WebAuthn registration and authentication flows. ## Usage @@ -30,17 +30,37 @@ URL of a [WebAuthn server handler](/accounts/server/handler.webAuthn) (shorthand Cannot be used with `ceremony`. ::: +```ts twoslash +import { webAuthn, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: webAuthn({ + authUrl: 'https://myapp.com/auth', // [!code focus] + }), +}) +``` + ### ceremony - **Type:** `WebAuthnCeremony` - **Default:** `WebAuthnCeremony.local(){:js}` -Ceremony strategy for WebAuthn registration and authentication. [See more](/accounts/api/ceremony). +Ceremony strategy for WebAuthn registration and authentication. [See more](/accounts/api/webauthnceremony). :::warning Cannot be used with `authUrl`. ::: +```ts twoslash +import { webAuthn, WebAuthnCeremony, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: webAuthn({ + ceremony: WebAuthnCeremony.server({ url: 'https://myapp.com/auth' }), // [!code focus] + }), +}) +``` + ### icon - **Type:** `` `data:image/${string}` `` @@ -48,6 +68,17 @@ Cannot be used with `authUrl`. Data URI of the provider icon. +```ts twoslash +import { webAuthn, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: webAuthn({ + authUrl: 'https://myapp.com/auth', + icon: 'data:image/svg+xml,...', // [!code focus] + }), +}) +``` + ### name - **Type:** `string` @@ -55,9 +86,31 @@ Data URI of the provider icon. Display name of the provider. +```ts twoslash +import { webAuthn, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: webAuthn({ + authUrl: 'https://myapp.com/auth', + name: 'My Wallet', // [!code focus] + }), +}) +``` + ### rdns - **Type:** `string` - **Optional** Reverse DNS identifier. + +```ts twoslash +import { webAuthn, Provider } from 'accounts' + +const provider = Provider.create({ + adapter: webAuthn({ + authUrl: 'https://myapp.com/auth', + rdns: 'com.example.wallet', // [!code focus] + }), +}) +``` diff --git a/src/pages/accounts/api/ceremony.from.mdx b/src/pages/accounts/api/webauthnceremony.from.mdx similarity index 100% rename from src/pages/accounts/api/ceremony.from.mdx rename to src/pages/accounts/api/webauthnceremony.from.mdx diff --git a/src/pages/accounts/api/ceremony.local.mdx b/src/pages/accounts/api/webauthnceremony.local.mdx similarity index 100% rename from src/pages/accounts/api/ceremony.local.mdx rename to src/pages/accounts/api/webauthnceremony.local.mdx diff --git a/src/pages/accounts/api/webauthnceremony.mdx b/src/pages/accounts/api/webauthnceremony.mdx new file mode 100644 index 00000000..c2ed3f75 --- /dev/null +++ b/src/pages/accounts/api/webauthnceremony.mdx @@ -0,0 +1,31 @@ +--- +title: WebAuthnCeremony +description: Pluggable strategy for WebAuthn registration and authentication ceremonies. +--- + +import { Cards, Card } from 'vocs' + +# `WebAuthnCeremony` + +Pluggable strategy for WebAuthn registration and authentication ceremonies. A `WebAuthnCeremony` controls how challenges are generated and responses are verified during passkey registration and login. + + + + + + diff --git a/src/pages/accounts/api/ceremony.server.mdx b/src/pages/accounts/api/webauthnceremony.server.mdx similarity index 100% rename from src/pages/accounts/api/ceremony.server.mdx rename to src/pages/accounts/api/webauthnceremony.server.mdx diff --git a/src/pages/accounts/faq.mdx b/src/pages/accounts/faq.mdx index 8fa194d9..c9038293 100644 --- a/src/pages/accounts/faq.mdx +++ b/src/pages/accounts/faq.mdx @@ -5,6 +5,14 @@ description: Frequently asked questions about the Tempo Accounts SDK. # Frequently Asked Questions +## What adapter should I use? + +Most apps should use [Tempo Wallet](/accounts/api/dialog) - it provides a universal account experience with a central account for users that includes embedded onramp, access keys, and transaction orchestration out of the box. + +Use [domain-bound passkeys](/accounts/api/webAuthn) when you want to build your own wallet experience or when your app needs to manage and own the WebAuthn ceremony directly. + +[Learn more](/accounts/guides/create-and-use-accounts). + ## Which browsers are supported? The Tempo Accounts SDK supports the following browsers: diff --git a/src/pages/accounts/guides/create-and-use-accounts.mdx b/src/pages/accounts/guides/create-and-use-accounts.mdx new file mode 100644 index 00000000..00ee504a --- /dev/null +++ b/src/pages/accounts/guides/create-and-use-accounts.mdx @@ -0,0 +1,45 @@ +--- +title: Create & Use Accounts +description: Choose between universal wallet experiences or domain-bound passkey accounts for your app. +--- + +import { Cards, Card } from 'vocs' + +# Create & Use Accounts + +Create and integrate Tempo accounts into your product with the universal Tempo Wallet or domain-bound passkeys. + +## What should I use? + +### Tempo Wallet + +Most apps should use [Tempo Wallet](/accounts/api/dialog) - it provides a universal account experience with a central account for users that includes embedded onramp, access keys, and transaction orchestration out of the box. + +### Domain-bound Passkeys + +Use [domain-bound passkeys](/accounts/api/webAuthn) when you want to build your own wallet experience or when your app needs to manage and own the WebAuthn ceremony directly. + +:::info +Tempo Wallet uses domain-bound passkeys (on `tempo.xyz`) under the hood. +::: + +### Other Wallets + +Offer users a range of existing wallets to connect from, such as MetaMask, Coinbase Wallet, and others. [See the guide](/guide/use-accounts/connect-to-wallets). + +--- + + + + + diff --git a/src/pages/accounts/index.mdx b/src/pages/accounts/index.mdx index 8a1740b1..93dd4f33 100644 --- a/src/pages/accounts/index.mdx +++ b/src/pages/accounts/index.mdx @@ -42,20 +42,7 @@ Get started with Wagmi by following the [official guide](https://wagmi.sh/react/ ### Configure -After you have set up Wagmi, you can set up the Tempo Accounts SDK by using a Connector from `accounts/wagmi`: - - - - - +After you have set up Wagmi, you can set up the Tempo Accounts SDK by using a Connector from `accounts/wagmi`. :::code-group ```tsx twoslash [Tempo Wallet] @@ -86,6 +73,10 @@ export const wagmiConfig = createConfig({ ``` ::: +:::info[What adapter should I use?] +Most apps should use **Tempo Wallet** - it provides a universal account experience with embedded onramp, access keys, and transaction orchestration. **Domain-bound Passkeys** is for apps that want to manage domain-bound passkey accounts directly. [Learn more](/accounts/faq#what-adapter-should-i-use). +::: + :::tip If you are using a wallet connection library and cannot supply a custom connector, you can use `Provider.create()` to create a new provider instance, and inject itself @@ -124,30 +115,41 @@ function Connect() { - + + :::: diff --git a/src/pages/accounts/server/handler.feePayer.mdx b/src/pages/accounts/server/handler.feePayer.mdx index 2c54ba25..f1c3ebcb 100644 --- a/src/pages/accounts/server/handler.feePayer.mdx +++ b/src/pages/accounts/server/handler.feePayer.mdx @@ -7,6 +7,10 @@ description: Server handler that sponsors transaction fees for users. Creates a server handler that acts as a fee payer for transactions, enabling you to subsidize gas costs for users by signing transactions with a dedicated fee payer account on your backend. +:::info +[See the guide](#TODO) +::: + ## Usage ```ts @@ -40,6 +44,15 @@ export const POST = handler.fetch // Next.js The account to use as the fee payer. This account will sign all transactions and pay the gas fees. +```ts twoslash +import { privateKeyToAccount } from 'viem/accounts' +import { Handler } from 'accounts/server' + +const handler = Handler.feePayer({ + account: privateKeyToAccount('0x...'), // [!code focus] +}) +``` + ### chains - **Type:** `readonly [Chain, ...Chain[]]` @@ -47,6 +60,17 @@ The account to use as the fee payer. This account will sign all transactions and Supported chains. The handler resolves the client based on the `chainId` in the incoming transaction. +```ts twoslash +import { privateKeyToAccount } from 'viem/accounts' +import { tempo } from 'viem/chains' +import { Handler } from 'accounts/server' + +const handler = Handler.feePayer({ + account: privateKeyToAccount('0x...'), + chains: [tempo], // [!code focus] +}) +``` + ### onRequest - **Type:** `(request: RpcRequest) => Promise` @@ -54,6 +78,18 @@ Supported chains. The handler resolves the client based on the `chainId` in the Callback called before processing each request. Useful for logging, rate limiting, or custom validation. +```ts twoslash +import { privateKeyToAccount } from 'viem/accounts' +import { Handler } from 'accounts/server' + +const handler = Handler.feePayer({ + account: privateKeyToAccount('0x...'), + onRequest: async (request) => { // [!code focus] + console.log('Processing request:', request.method) // [!code focus] + }, // [!code focus] +}) +``` + ### path - **Type:** `string` @@ -61,9 +97,33 @@ Callback called before processing each request. Useful for logging, rate limitin Path where the handler listens for requests. +```ts twoslash +import { privateKeyToAccount } from 'viem/accounts' +import { Handler } from 'accounts/server' + +const handler = Handler.feePayer({ + account: privateKeyToAccount('0x...'), + path: '/fee-payer', // [!code focus] +}) +``` + ### transports - **Type:** `Record` - **Default:** `http()` for each chain Transports keyed by chain ID. + +```ts twoslash +import { http } from 'viem' +import { privateKeyToAccount } from 'viem/accounts' +import { tempo } from 'viem/chains' +import { Handler } from 'accounts/server' + +const handler = Handler.feePayer({ + account: privateKeyToAccount('0x...'), + transports: { // [!code focus] + [tempo.id]: http('https://rpc.tempo.xyz'), // [!code focus] + }, // [!code focus] +}) +``` diff --git a/src/pages/accounts/server/handler.webAuthn.mdx b/src/pages/accounts/server/handler.webAuthn.mdx index 13b9b12e..e602d9fc 100644 --- a/src/pages/accounts/server/handler.webAuthn.mdx +++ b/src/pages/accounts/server/handler.webAuthn.mdx @@ -7,6 +7,10 @@ description: Server-side WebAuthn ceremony handler for registration and authenti Creates a WebAuthn ceremony handler that manages registration and authentication flows server-side. +:::info +[See the guide](#TODO) +::: + Exposes 4 POST endpoints: - `POST /register/options` — Generate credential creation options @@ -52,12 +56,33 @@ export const POST = handler.fetch // Next.js Maximum age of a challenge in seconds before it expires. +```ts twoslash +import { Handler, Kv } from 'accounts/server' + +const handler = Handler.webAuthn({ + kv: Kv.memory(), + origin: 'https://example.com', + rpId: 'example.com', + challengeTtl: 600, // [!code focus] +}) +``` + ### kv -- **Type:** `Kv` +- **Type:** [`Kv`](/accounts/server/kv) - **Required** -Key-value store for challenges and credentials. +Key-value store for challenges and credentials. [See `Kv`](/accounts/server/kv) for available adapters. + +```ts twoslash +import { Handler, Kv } from 'accounts/server' + +const handler = Handler.webAuthn({ + kv: Kv.memory(), // [!code focus] + origin: 'https://example.com', + rpId: 'example.com', +}) +``` ### onAuthenticate @@ -66,6 +91,19 @@ Key-value store for challenges and credentials. Called after a successful authentication. +```ts twoslash +import { Handler, Kv } from 'accounts/server' + +const handler = Handler.webAuthn({ + kv: Kv.memory(), + origin: 'https://example.com', + rpId: 'example.com', + onAuthenticate: ({ credentialId, publicKey }) => { // [!code focus] + console.log('Authenticated:', credentialId) // [!code focus] + }, // [!code focus] +}) +``` + ### onRegister - **Type:** `(params: { credentialId, publicKey, request }) => Response | void` @@ -73,6 +111,19 @@ Called after a successful authentication. Called after a successful registration. The returned response is merged onto the default JSON response. +```ts twoslash +import { Handler, Kv } from 'accounts/server' + +const handler = Handler.webAuthn({ + kv: Kv.memory(), + origin: 'https://example.com', + rpId: 'example.com', + onRegister: ({ credentialId, publicKey }) => { // [!code focus] + console.log('Registered:', credentialId) // [!code focus] + }, // [!code focus] +}) +``` + ### origin - **Type:** `string | readonly string[]` @@ -80,6 +131,16 @@ Called after a successful registration. The returned response is merged onto the Expected origin(s) for WebAuthn verification (e.g. `'https://example.com'`). +```ts twoslash +import { Handler, Kv } from 'accounts/server' + +const handler = Handler.webAuthn({ + kv: Kv.memory(), + origin: 'https://example.com', // [!code focus] + rpId: 'example.com', +}) +``` + ### path - **Type:** `string` @@ -87,9 +148,30 @@ Expected origin(s) for WebAuthn verification (e.g. `'https://example.com'`). Path prefix for the WebAuthn endpoints. +```ts twoslash +import { Handler, Kv } from 'accounts/server' + +const handler = Handler.webAuthn({ + kv: Kv.memory(), + origin: 'https://example.com', + rpId: 'example.com', + path: '/webauthn', // [!code focus] +}) +``` + ### rpId - **Type:** `string` - **Required** Relying Party ID (e.g. `'example.com'`). + +```ts twoslash +import { Handler, Kv } from 'accounts/server' + +const handler = Handler.webAuthn({ + kv: Kv.memory(), + origin: 'https://example.com', + rpId: 'example.com', // [!code focus] +}) +``` diff --git a/src/pages/accounts/server/index.mdx b/src/pages/accounts/server/index.mdx index 9be6cfba..ee469483 100644 --- a/src/pages/accounts/server/index.mdx +++ b/src/pages/accounts/server/index.mdx @@ -34,16 +34,19 @@ export const POST = handler.fetch // Next.js diff --git a/src/pages/accounts/wagmi/index.mdx b/src/pages/accounts/wagmi/index.mdx index 9feda548..90662ec9 100644 --- a/src/pages/accounts/wagmi/index.mdx +++ b/src/pages/accounts/wagmi/index.mdx @@ -12,11 +12,13 @@ Wagmi connectors for integrating Tempo accounts into your app. diff --git a/src/pages/accounts/wagmi/tempoWallet.mdx b/src/pages/accounts/wagmi/tempoWallet.mdx index f541c36a..e7487444 100644 --- a/src/pages/accounts/wagmi/tempoWallet.mdx +++ b/src/pages/accounts/wagmi/tempoWallet.mdx @@ -34,12 +34,78 @@ Accepts all [`dialog`](/accounts/api/dialog) adapter options, plus all [`Provide Default access key parameters for `wallet_connect`. -### chains +```ts twoslash +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { parseUnits } from 'viem' +import { Expiry, tempoWallet } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [ + tempoWallet({ + authorizeAccessKey: () => ({ // [!code focus] + expiry: Expiry.days(7), // [!code focus] + limits: [{ // [!code focus] + token: '0x20c0000000000000000000000000000000000001', // [!code focus] + limit: parseUnits('500', 6), // [!code focus] + }], // [!code focus] + }), // [!code focus] + }), + ], + transports: { [tempo.id]: http() }, +}) +``` + +### dialog + +- **Type:** `Dialog` +- **Default:** `Dialog.iframe()` (or `Dialog.popup()` in Safari/insecure contexts) + +Dialog to use for the embed app. + +```ts twoslash +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { Dialog, tempoWallet } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [ + tempoWallet({ + dialog: Dialog.popup(), // [!code focus] + }), + ], + transports: { [tempo.id]: http() }, +}) +``` + +### feePayerUrl + +- **Type:** `string` +- **Optional** + +Fee payer URL for interacting with a service running [`Handler.feePayer`](/accounts/server/handler.feePayer) from `accounts/server`. + +:::info +[See the guide](#TODO) +::: -- **Type:** `readonly [Chain, ...Chain[]]` -- **Default:** `[tempo, tempoModerato]` +```ts twoslash +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { tempoWallet } from 'accounts/wagmi' -Supported chains. +export const config = createConfig({ + chains: [tempo], + connectors: [ + tempoWallet({ + feePayerUrl: 'https://myapp.com/fee-payer', // [!code focus] + }), + ], + transports: { [tempo.id]: http() }, +}) +``` ### host @@ -47,3 +113,65 @@ Supported chains. - **Default:** `'https://wallet.tempo.xyz/embed'` URL of the embed app. + +```ts twoslash +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { tempoWallet } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [ + tempoWallet({ + host: 'https://wallet.tempo.xyz/embed', // [!code focus] + }), + ], + transports: { [tempo.id]: http() }, +}) +``` + +### mpp + +- **Type:** `boolean` +- **Default:** `false` + +Enable [Machine Payment Protocol](https://mpp.dev) support. + +```ts twoslash +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { tempoWallet } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [ + tempoWallet({ + mpp: true, // [!code focus] + }), + ], + transports: { [tempo.id]: http() }, +}) +``` + +### testnet + +- **Type:** `boolean` +- **Default:** `false` + +Use testnet. When `true`, the default chain will be the first testnet chain in `chains`. + +```ts twoslash +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { tempoWallet } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [ + tempoWallet({ + testnet: true, // [!code focus] + }), + ], + transports: { [tempo.id]: http() }, +}) +``` diff --git a/src/pages/accounts/wagmi/webAuthn.mdx b/src/pages/accounts/wagmi/webAuthn.mdx index c967dcce..2806e223 100644 --- a/src/pages/accounts/wagmi/webAuthn.mdx +++ b/src/pages/accounts/wagmi/webAuthn.mdx @@ -25,18 +25,173 @@ export const config = createConfig({ ## Parameters -Accepts all [`webAuthn`](/accounts/api/webauthn) adapter options, plus all [`Provider`](/accounts/api/provider) options except `adapter`. +Accepts all [`webAuthn`](/accounts/api/webAuthn) adapter options, plus all [`Provider`](/accounts/api/provider) options except `adapter`. ### authUrl - **Type:** `string` - **Optional** -URL of a WebAuthn handler. +URL of a [WebAuthn server handler](/accounts/server/handler.webAuthn). + +:::info +[See the guide](#TODO) +::: + +:::warning +Cannot be used with `ceremony`. +::: + +```ts twoslash +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { webAuthn } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [ + webAuthn({ + authUrl: 'https://myapp.com/auth', // [!code focus] + }), + ], + transports: { [tempo.id]: http() }, +}) +``` + +### authorizeAccessKey + +- **Type:** `() => { expiry: number; limits?: { token: Address; limit: bigint }[] }` +- **Optional** + +Default access key parameters for `wallet_connect`. + +```ts twoslash +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { parseUnits } from 'viem' +import { Expiry, webAuthn } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [ + webAuthn({ + authUrl: 'https://myapp.com/auth', + authorizeAccessKey: () => ({ // [!code focus] + expiry: Expiry.days(7), // [!code focus] + limits: [{ // [!code focus] + token: '0x20c0000000000000000000000000000000000001', // [!code focus] + limit: parseUnits('500', 6), // [!code focus] + }], // [!code focus] + }), // [!code focus] + }), + ], + transports: { [tempo.id]: http() }, +}) +``` ### ceremony - **Type:** `WebAuthnCeremony` -- **Default:** `WebAuthnCeremony.local()` +- **Default:** `WebAuthnCeremony.local(){:js}` + +Ceremony strategy for WebAuthn registration and authentication. [See more](/accounts/api/webauthnceremony). + +:::info +[See the guide](#TODO) +::: + +:::warning +Cannot be used with `authUrl`. +::: + +```ts twoslash +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { WebAuthnCeremony, webAuthn } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [ + webAuthn({ + ceremony: WebAuthnCeremony.server({ url: 'https://myapp.com/auth' }), // [!code focus] + }), + ], + transports: { [tempo.id]: http() }, +}) +``` + +### feePayerUrl + +- **Type:** `string` +- **Optional** + +Fee payer URL for interacting with a service running [`Handler.feePayer`](/accounts/server/handler.feePayer) from `accounts/server`. + +:::info +[See the guide](#TODO) +::: + +```ts twoslash +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { webAuthn } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [ + webAuthn({ + authUrl: 'https://myapp.com/auth', + feePayerUrl: 'https://myapp.com/fee-payer', // [!code focus] + }), + ], + transports: { [tempo.id]: http() }, +}) +``` + +### mpp + +- **Type:** `boolean` +- **Default:** `false` + +Enable [Machine Payment Protocol](https://mpp.dev) support. + +```ts twoslash +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { webAuthn } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [ + webAuthn({ + authUrl: 'https://myapp.com/auth', + mpp: true, // [!code focus] + }), + ], + transports: { [tempo.id]: http() }, +}) +``` + +### testnet + +- **Type:** `boolean` +- **Default:** `false` -Ceremony strategy for WebAuthn flows. +Use testnet. When `true`, the default chain will be the first testnet chain in `chains`. + +```ts twoslash +import { createConfig, http } from 'wagmi' +import { tempo } from 'wagmi/chains' +import { webAuthn } from 'accounts/wagmi' + +export const config = createConfig({ + chains: [tempo], + connectors: [ + webAuthn({ + authUrl: 'https://myapp.com/auth', + testnet: true, // [!code focus] + }), + ], + transports: { [tempo.id]: http() }, +}) +``` diff --git a/src/pages/guide/payments/sponsor-user-fees.mdx b/src/pages/guide/payments/sponsor-user-fees.mdx index 6b66e27c..70771cd1 100644 --- a/src/pages/guide/payments/sponsor-user-fees.mdx +++ b/src/pages/guide/payments/sponsor-user-fees.mdx @@ -36,6 +36,19 @@ You can stand up a minimal fee payer service using the [`Handler.feePayer`](/acc // [!include ~/snippets/unformatted/withFeePayer.ts:server] ``` +Then plug `handler` into your server framework of choice: + +```ts +createServer(handler.listener) // Node.js +Bun.serve(handler) // Bun +Deno.serve(handler) // Deno +app.all('*', c => handler.fetch(c.request)) // Elysia +app.use(handler.listener) // Express +app.use(c => handler.fetch(c.req.raw)) // Hono +export const GET = handler.fetch // Next.js +export const POST = handler.fetch // Next.js +``` + ### Configure your client to use the fee payer service @@ -50,7 +63,7 @@ import { createConfig, http } from 'wagmi' export const config = createConfig({ connectors: [tempoWallet({ - feePayerUrl: 'https://sponsor.moderato.tempo.xyz', // [!code hl] + feePayerUrl: 'https://sponsor.moderato.tempo.xyz', // [!code focus] })], chains: [tempo], multiInjectedProviderDiscovery: false, @@ -60,22 +73,22 @@ export const config = createConfig({ }) ``` -```ts twoslash [Other] +```ts twoslash [WebAuthn] // @noErrors -import { tempoWallet } from 'accounts/wagmi' +import { webAuthn } from 'accounts/wagmi' import { tempo } from 'viem/chains' import { withFeePayer } from 'viem/tempo' import { createConfig, http } from 'wagmi' export const config = createConfig({ - connectors: [tempoWallet()], + connectors: [webAuthn({ authUrl: 'https://myapp.com/auth' })], chains: [tempo], multiInjectedProviderDiscovery: false, transports: { - [tempo.id]: withFeePayer( // [!code hl] - http(), // [!code hl] - http('https://sponsor.moderato.tempo.xyz'), // [!code hl] - ), // [!code hl] + [tempo.id]: withFeePayer( // [!code focus] + http(), // [!code focus] + http('https://sponsor.moderato.tempo.xyz'), // [!code focus] + ), // [!code focus] }, }) ``` diff --git a/src/pages/guide/use-accounts/embed-passkeys.mdx b/src/pages/guide/use-accounts/embed-passkeys.mdx index 862f32bb..aad30483 100644 --- a/src/pages/guide/use-accounts/embed-passkeys.mdx +++ b/src/pages/guide/use-accounts/embed-passkeys.mdx @@ -20,8 +20,7 @@ WebAuthn credentials are bound to a specific domain (the [Relying Party](https:/ This means that credentials created for one domain (e.g., `example.com`) will only work on that domain (and its subdomains) and cannot be used to authenticate on other domains. -This means your users won't be able to use the same passkey account on other applications. If this is not what you want, head to the [Connect to wallets](/guide/use-accounts/connect-to-wallets) -guide that walks you through on how to connect your application to a universal wallet like MetaMask. +This means your users won't be able to use the same passkey account on other applications. If this is not what you want, head to the [Embed Tempo Wallet](/guide/use-accounts/embed-tempo-wallet) guide for a universal account experience. ::: @@ -41,9 +40,41 @@ By the end of this guide, you will be able to embed passkey accounts into your a Ensure that you have set up your project with Wagmi by following the [guide](/sdk/typescript#wagmi-setup). +### Set up the WebAuthn server + +Set up a [`Handler.webAuthn`](/accounts/server/handler.webAuthn) server to handle passkey registration and authentication ceremonies. + +```ts twoslash [server.ts] +// @noErrors +import { Handler, Kv } from 'accounts/server' + +const handler = Handler.webAuthn({ + kv: Kv.memory(), + origin: 'https://example.com', + rpId: 'example.com', +}) +``` + +Then plug `handler` into your server framework of choice: + +```ts +createServer(handler.listener) // Node.js +Bun.serve(handler) // Bun +Deno.serve(handler) // Deno +app.all('*', c => handler.fetch(c.request)) // Elysia +app.use(handler.listener) // Express +app.use(c => handler.fetch(c.req.raw)) // Hono +export const GET = handler.fetch // Next.js +export const POST = handler.fetch // Next.js +``` + +:::warning +`Kv.memory()` is not recommended for production use. Instead, use a persistent store like Cloudflare or Vercel KV, or a Redis instance. See [`Kv`](/accounts/server/kv) for available adapters. +::: + ### Configure the WebAuthn Connector -Next, we will need to configure the `webAuthn` connector in our Wagmi config. +Next, we will need to configure the `webAuthn` connector in our Wagmi config, passing the (relative or absolute) url of your WebAuthn server to `authUrl`. ```tsx twoslash [config.ts] // @noErrors @@ -53,7 +84,7 @@ import { webAuthn } from 'accounts/wagmi' // [!code ++] export const config = createConfig({ chains: [tempo], - connectors: [webAuthn()], // [!code ++] + connectors: [webAuthn({ authUrl: '/auth' })], // [!code ++] multiInjectedProviderDiscovery: false, transports: { [tempo.id]: http(), @@ -61,20 +92,6 @@ export const config = createConfig({ }) ``` -:::warning - -Without an `authUrl`, credentials are stored locally on the client device. This means users will lose access to their passkey account if their storage is cleared or if they sign in from another device. - -For production, you should set up a [`Handler.webAuthn`](/accounts/server/handler.webAuthn) server and pass the `authUrl` to the connector: - -```tsx -connectors: [webAuthn({ authUrl: 'https://myapp.com/auth' })] -``` - -See [Deploying to Production](/accounts/production) for more details. - -::: - :::tip This Wagmi configuration sets `multiInjectedProviderDiscovery` to `false` to @@ -139,7 +156,7 @@ import { webAuthn } from 'accounts/wagmi' // [!code ++] export const config = createConfig({ chains: [tempo], - connectors: [webAuthn()], // [!code ++] + connectors: [webAuthn({ authUrl: '/auth' })], // [!code ++] multiInjectedProviderDiscovery: false, transports: { [tempo.id]: http(), @@ -215,7 +232,7 @@ import { webAuthn } from 'accounts/wagmi' // [!code ++] export const config = createConfig({ chains: [tempo], - connectors: [webAuthn()], // [!code ++] + connectors: [webAuthn({ authUrl: '/auth' })], // [!code ++] multiInjectedProviderDiscovery: false, transports: { [tempo.id]: http(), @@ -299,15 +316,21 @@ export function Example() { + diff --git a/src/pages/guide/use-accounts/embed-tempo-wallet.mdx b/src/pages/guide/use-accounts/embed-tempo-wallet.mdx index eaed4750..66c44228 100644 --- a/src/pages/guide/use-accounts/embed-tempo-wallet.mdx +++ b/src/pages/guide/use-accounts/embed-tempo-wallet.mdx @@ -14,13 +14,13 @@ The [`tempoWallet`](/accounts/wagmi/tempoWallet) Wagmi connector is the easiest :::info -**When should I use the Tempo Wallet vs Passkey accounts?** +**When should I use Tempo Wallet vs. domain-bound Passkeys?** The **Tempo Wallet** provides a universal wallet experience – users manage their account through the Tempo Wallet interface, and their account is portable across all applications that embed it. -**Passkey accounts** are domain-bound – credentials are tied to your specific domain and cannot be used on other applications. This gives you full control over the authentication experience but requires more setup. +**Domain-bound Passkeys** are tied to your specific domain and cannot be used on other applications. This gives you full control over the authentication experience but requires more setup. -If you want a quick integration with a full-featured wallet, use the Tempo Wallet. If you want a fully custom, domain-bound authentication experience, use [Passkey accounts](/guide/use-accounts/embed-passkeys). +If you want a quick integration with a full-featured wallet, use the [Tempo Wallet](/accounts/api/dialog). If you want a fully custom, domain-bound authentication experience, use [domain-bound Passkeys](/guide/use-accounts/embed-passkeys). ::: @@ -262,48 +262,25 @@ export const config = createConfig({ See the [Sponsor user fees](/guide/payments/sponsor-user-fees) guide for more details on setting up a fee payer server. -### Access Key Limits - -You can configure default access key parameters to restrict the tokens and amounts a session key can spend: - -```tsx twoslash [config.ts] -// @noErrors -import { parseUnits } from 'viem' -import { createConfig, http } from 'wagmi' -import { tempo } from 'viem/chains' -import { Expiry } from 'accounts' -import { tempoWallet } from 'accounts/wagmi' - -export const config = createConfig({ - chains: [tempo], - connectors: [tempoWallet({ - authorizeAccessKey: () => ({ // [!code ++] - expiry: Expiry.days(1), // [!code ++] - limits: [{ // [!code ++] - token: '0x...', // [!code ++] - limit: parseUnits('100', 6), // [!code ++] - }], // [!code ++] - }), // [!code ++] - })], - transports: { - [tempo.id]: http(), - }, -}) -``` - ## Learning Resources + + - diff --git a/src/pages/guide/use-accounts/index.mdx b/src/pages/guide/use-accounts/index.mdx index 0a044acd..bbd749ac 100644 --- a/src/pages/guide/use-accounts/index.mdx +++ b/src/pages/guide/use-accounts/index.mdx @@ -1,39 +1,56 @@ --- -description: Create and integrate Tempo accounts with domain-bound passkeys or connect to EVM-compatible wallets. Choose embedded or universal account experiences. +description: Create and integrate Tempo accounts with the universal Tempo Wallet or domain-bound passkeys. --- import { Cards, Card } from 'vocs' # Create & Use Accounts -Create and integrate Tempo accounts into your product with domain-bound passkeys or connecting your app to EVM-compatible wallets. +Create and integrate Tempo accounts into your product with the universal Tempo Wallet or domain-bound passkeys. -:::tip -**Should I use a Passkey account or a wallet?** +## What should I use? -- If you need a **domain-bound account** experience, you can embed a Passkey account. -- If you need a **universal account** experience, you can integrate your app with wallets. +### Tempo Wallet -You can even use both if you would like to offer both experiences. +Most apps should use [Tempo Wallet](/accounts/api/dialog) - it provides a universal account experience with a central account for users that includes embedded onramp, access keys, and transaction orchestration out of the box. + +### Domain-bound Passkeys + +Use [domain-bound passkeys](/accounts/api/webAuthn) when you want to build your own wallet experience or when your app needs to manage and own the WebAuthn ceremony directly. + +:::info +Tempo Wallet uses domain-bound passkeys (on `tempo.xyz`) under the hood. ::: +### Other Wallets + +Offer users a range of existing wallets to connect from, such as MetaMask, Coinbase Wallet, and others. + +--- + + diff --git a/vocs.config.ts b/vocs.config.ts index 7c2ca5c9..56361722 100644 --- a/vocs.config.ts +++ b/vocs.config.ts @@ -97,11 +97,11 @@ export default defineConfig({ link: '/guide/use-accounts/embed-tempo-wallet', }, { - text: 'Embed Passkey accounts', + text: 'Embed domain-bound Passkeys', link: '/guide/use-accounts/embed-passkeys', }, { - text: 'Connect to wallets', + text: 'Connect to other wallets', link: '/guide/use-accounts/connect-to-wallets', }, { @@ -554,7 +554,7 @@ export default defineConfig({ text: 'Tempo Developer Tools', items: [ { - text: 'Accounts', + text: 'Accounts SDK', link: '/accounts', }, { @@ -736,8 +736,8 @@ export default defineConfig({ text: 'Guides', items: [ { - text: 'Embed Tempo Wallet', - link: '/guide/use-accounts/embed-tempo-wallet', + text: 'Create & Use Accounts', + link: '/guide/use-accounts', external: true, }, { @@ -745,6 +745,11 @@ export default defineConfig({ link: '/guide/payments', external: true, }, + { + text: 'Sponsor Fees', + link: '/guide/payments/sponsor-user-fees', + external: true, + }, { text: 'Issue Stablecoins', link: '/guide/issuance', @@ -773,7 +778,7 @@ export default defineConfig({ link: '/accounts/api/adapters', }, { - text: 'dialog', + text: 'dialog / tempoWallet', link: '/accounts/api/dialog', }, { @@ -814,19 +819,19 @@ export default defineConfig({ items: [ { text: 'Overview', - link: '/accounts/api/ceremony', + link: '/accounts/api/webauthnceremony', }, { text: '.from', - link: '/accounts/api/ceremony.from', + link: '/accounts/api/webauthnceremony.from', }, { text: '.local', - link: '/accounts/api/ceremony.local', + link: '/accounts/api/webauthnceremony.local', }, { text: '.server', - link: '/accounts/api/ceremony.server', + link: '/accounts/api/webauthnceremony.server', }, ], }, From 18581231092ce2001425a777e04362abad1c3ebe Mon Sep 17 00:00:00 2001 From: jxom <7336481+jxom@users.noreply.github.com> Date: Tue, 7 Apr 2026 09:46:46 +1000 Subject: [PATCH 4/8] accounts: remove WebAuthnCeremony.local, fix guide links, rename adapter to connector Amp-Thread-ID: https://ampcode.com/threads/T-019d652c-8d5d-723f-9b1a-41076bcc23ba --- src/pages/accounts/api/adapters.mdx | 8 +++++ src/pages/accounts/api/webAuthn.mdx | 2 +- .../accounts/api/webauthnceremony.local.mdx | 32 ------------------- src/pages/accounts/api/webauthnceremony.mdx | 6 ---- src/pages/accounts/index.mdx | 6 ++-- .../accounts/server/handler.feePayer.mdx | 2 +- .../accounts/server/handler.webAuthn.mdx | 2 +- src/pages/accounts/wagmi/tempoWallet.mdx | 2 +- src/pages/accounts/wagmi/webAuthn.mdx | 8 ++--- vocs.config.ts | 4 --- 10 files changed, 19 insertions(+), 53 deletions(-) delete mode 100644 src/pages/accounts/api/webauthnceremony.local.mdx diff --git a/src/pages/accounts/api/adapters.mdx b/src/pages/accounts/api/adapters.mdx index 37b74b90..4195d908 100644 --- a/src/pages/accounts/api/adapters.mdx +++ b/src/pages/accounts/api/adapters.mdx @@ -9,6 +9,14 @@ import { Cards, Card } from 'vocs' Adapters control how accounts are created and managed. Pass an adapter to `Provider.create()` to configure the account management strategy. +| Adapter | Uses | Best for | +| --- | --- | --- | +| [`dialog`](/accounts/api/dialog) (default) | Hosted dialog | Apps wanting a universal account experience | +| [`webAuthn`](/accounts/api/webAuthn) | Domain-bound passkeys | Wallets integrating Passkey accounts, or Apps wanting to host and manage their own Passkey accounts | +| [`local`](/accounts/api/local) | Arbitrary keys | Custom signing and key management | + +--- + - Date: Tue, 7 Apr 2026 10:12:35 +1000 Subject: [PATCH 5/8] fix: import Expiry, Dialog, WebAuthnCeremony from accounts instead of accounts/wagmi Amp-Thread-ID: https://ampcode.com/threads/T-019d652c-8d5d-723f-9b1a-41076bcc23ba --- src/pages/accounts/wagmi/tempoWallet.mdx | 6 ++++-- src/pages/accounts/wagmi/webAuthn.mdx | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/pages/accounts/wagmi/tempoWallet.mdx b/src/pages/accounts/wagmi/tempoWallet.mdx index 4a85dfe9..fcb0d7c1 100644 --- a/src/pages/accounts/wagmi/tempoWallet.mdx +++ b/src/pages/accounts/wagmi/tempoWallet.mdx @@ -38,7 +38,8 @@ Default access key parameters for `wallet_connect`. import { createConfig, http } from 'wagmi' import { tempo } from 'wagmi/chains' import { parseUnits } from 'viem' -import { Expiry, tempoWallet } from 'accounts/wagmi' +import { Expiry } from 'accounts' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], @@ -67,7 +68,8 @@ Dialog to use for the embed app. ```ts twoslash import { createConfig, http } from 'wagmi' import { tempo } from 'wagmi/chains' -import { Dialog, tempoWallet } from 'accounts/wagmi' +import { Dialog } from 'accounts' +import { tempoWallet } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], diff --git a/src/pages/accounts/wagmi/webAuthn.mdx b/src/pages/accounts/wagmi/webAuthn.mdx index c240804b..758d8ca8 100644 --- a/src/pages/accounts/wagmi/webAuthn.mdx +++ b/src/pages/accounts/wagmi/webAuthn.mdx @@ -69,7 +69,8 @@ Default access key parameters for `wallet_connect`. import { createConfig, http } from 'wagmi' import { tempo } from 'wagmi/chains' import { parseUnits } from 'viem' -import { Expiry, webAuthn } from 'accounts/wagmi' +import { Expiry } from 'accounts' +import { webAuthn } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], @@ -107,7 +108,8 @@ Cannot be used with `authUrl`. ```ts twoslash import { createConfig, http } from 'wagmi' import { tempo } from 'wagmi/chains' -import { WebAuthnCeremony, webAuthn } from 'accounts/wagmi' +import { WebAuthnCeremony } from 'accounts' +import { webAuthn } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], From f11871156ef0c6741734e2578e9323c45419add3 Mon Sep 17 00:00:00 2001 From: jxom <7336481+jxom@users.noreply.github.com> Date: Tue, 7 Apr 2026 14:41:12 +1000 Subject: [PATCH 6/8] fix: update gitpick examples to tempoxyz/accounts repo Amp-Thread-ID: https://ampcode.com/threads/T-019d652c-8d5d-723f-9b1a-41076bcc23ba --- src/pages/guide/payments/sponsor-user-fees.mdx | 2 +- src/pages/guide/use-accounts/embed-passkeys.mdx | 2 +- src/pages/guide/use-accounts/embed-tempo-wallet.mdx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/guide/payments/sponsor-user-fees.mdx b/src/pages/guide/payments/sponsor-user-fees.mdx index 70771cd1..9f8187f1 100644 --- a/src/pages/guide/payments/sponsor-user-fees.mdx +++ b/src/pages/guide/payments/sponsor-user-fees.mdx @@ -13,7 +13,7 @@ Enable gasless transactions by sponsoring transaction fees for your users. Tempo ## Demo - + diff --git a/src/pages/guide/use-accounts/embed-passkeys.mdx b/src/pages/guide/use-accounts/embed-passkeys.mdx index aad30483..59024b85 100644 --- a/src/pages/guide/use-accounts/embed-passkeys.mdx +++ b/src/pages/guide/use-accounts/embed-passkeys.mdx @@ -28,7 +28,7 @@ This means your users won't be able to use the same passkey account on other app By the end of this guide, you will be able to embed passkey accounts into your application. - + diff --git a/src/pages/guide/use-accounts/embed-tempo-wallet.mdx b/src/pages/guide/use-accounts/embed-tempo-wallet.mdx index 66c44228..35021a35 100644 --- a/src/pages/guide/use-accounts/embed-tempo-wallet.mdx +++ b/src/pages/guide/use-accounts/embed-tempo-wallet.mdx @@ -28,7 +28,7 @@ If you want a quick integration with a full-featured wallet, use the [Tempo Wall By the end of this guide, you will be able to embed the Tempo Wallet into your application. - + From 96354a9c9bb8626cbd3cfbb31977bdc1aaa5b04a Mon Sep 17 00:00:00 2001 From: jxom <7336481+jxom@users.noreply.github.com> Date: Tue, 7 Apr 2026 16:54:15 +1000 Subject: [PATCH 7/8] accounts: polish getting started, examples table, remove connectors overview, use /auth Amp-Thread-ID: https://ampcode.com/threads/T-019d652c-8d5d-723f-9b1a-41076bcc23ba --- src/pages/accounts/api/provider.mdx | 2 +- src/pages/accounts/api/webAuthn.mdx | 12 ++--- src/pages/accounts/index.mdx | 45 ++++++++++++++++--- src/pages/accounts/wagmi/index.mdx | 25 ----------- src/pages/accounts/wagmi/webAuthn.mdx | 14 +++--- .../guide/payments/sponsor-user-fees.mdx | 2 +- vocs.config.ts | 4 -- 7 files changed, 53 insertions(+), 51 deletions(-) delete mode 100644 src/pages/accounts/wagmi/index.mdx diff --git a/src/pages/accounts/api/provider.mdx b/src/pages/accounts/api/provider.mdx index 011d6009..6e880841 100644 --- a/src/pages/accounts/api/provider.mdx +++ b/src/pages/accounts/api/provider.mdx @@ -64,7 +64,7 @@ Adapter to use for account management. import { Provider, webAuthn } from 'accounts' const provider = Provider.create({ - adapter: webAuthn({ authUrl: 'https://myapp.com/auth' }), // [!code focus] + adapter: webAuthn({ authUrl: '/auth' }), // [!code focus] }) ``` diff --git a/src/pages/accounts/api/webAuthn.mdx b/src/pages/accounts/api/webAuthn.mdx index 0bbe0a5e..b475acba 100644 --- a/src/pages/accounts/api/webAuthn.mdx +++ b/src/pages/accounts/api/webAuthn.mdx @@ -13,7 +13,7 @@ Enables domain-bound passkey experiences by wrapping the `local` adapter with We import { webAuthn, Provider } from 'accounts' const provider = Provider.create({ - adapter: webAuthn({ authUrl: 'https://myapp.com/auth' }), + adapter: webAuthn({ authUrl: '/auth' }), }) ``` @@ -35,7 +35,7 @@ import { webAuthn, Provider } from 'accounts' const provider = Provider.create({ adapter: webAuthn({ - authUrl: 'https://myapp.com/auth', // [!code focus] + authUrl: '/auth', // [!code focus] }), }) ``` @@ -56,7 +56,7 @@ import { webAuthn, WebAuthnCeremony, Provider } from 'accounts' const provider = Provider.create({ adapter: webAuthn({ - ceremony: WebAuthnCeremony.server({ url: 'https://myapp.com/auth' }), // [!code focus] + ceremony: WebAuthnCeremony.server({ url: '/auth' }), // [!code focus] }), }) ``` @@ -73,7 +73,7 @@ import { webAuthn, Provider } from 'accounts' const provider = Provider.create({ adapter: webAuthn({ - authUrl: 'https://myapp.com/auth', + authUrl: '/auth', icon: 'data:image/svg+xml,...', // [!code focus] }), }) @@ -91,7 +91,7 @@ import { webAuthn, Provider } from 'accounts' const provider = Provider.create({ adapter: webAuthn({ - authUrl: 'https://myapp.com/auth', + authUrl: '/auth', name: 'My Wallet', // [!code focus] }), }) @@ -109,7 +109,7 @@ import { webAuthn, Provider } from 'accounts' const provider = Provider.create({ adapter: webAuthn({ - authUrl: 'https://myapp.com/auth', + authUrl: '/auth', rdns: 'com.example.wallet', // [!code focus] }), }) diff --git a/src/pages/accounts/index.mdx b/src/pages/accounts/index.mdx index b583bafd..c29dfd6a 100644 --- a/src/pages/accounts/index.mdx +++ b/src/pages/accounts/index.mdx @@ -12,6 +12,8 @@ import { AccountsSignIn } from '../../components/guides/AccountsSignIn' The Tempo Accounts SDK is a TypeScript library for applications and wallets to create, manage, and interact with accounts on Tempo. +Try it out by logging into Tempo Wallet below: + ## Install @@ -48,11 +50,11 @@ After you have set up Wagmi, you can set up the Tempo Accounts SDK by using a Co ```tsx twoslash [Tempo Wallet] import { createConfig, http } from 'wagmi' import { tempo } from 'wagmi/chains' -import { tempoWallet } from 'accounts/wagmi' +import { tempoWallet } from 'accounts/wagmi' // [!code hl] export const wagmiConfig = createConfig({ chains: [tempo], - connectors: [tempoWallet()], + connectors: [tempoWallet()], // [!code hl] transports: { [tempo.id]: http(), }, @@ -61,11 +63,11 @@ export const wagmiConfig = createConfig({ ```tsx twoslash [Domain-bound Passkeys] import { createConfig, http } from 'wagmi' import { tempo } from 'wagmi/chains' -import { webAuthn } from 'accounts/wagmi' +import { webAuthn } from 'accounts/wagmi' // [!code hl] export const wagmiConfig = createConfig({ chains: [tempo], - connectors: [webAuthn({ authUrl: 'https://myapp.com/auth' })], + connectors: [webAuthn({ authUrl: '/auth' })], // [!code hl] transports: { [tempo.id]: http(), }, @@ -154,13 +156,16 @@ function Connect() { :::: -## Vanilla Usage +## Vanilla + Viem Usage You can get started with the Tempo Accounts SDK by creating a new `Provider` instance. -Once set up, you can use the `provider` to interact with accounts via JSON-RPC. +Once set up, you can use the provider to interact with accounts via JSON-RPC, or use [Viem Actions](https://viem.sh/tempo) with `.getClient(){:js}`. ```tsx twoslash +// @noErrors import { Provider } from 'accounts' +import { parseUnits } from 'viem' +import { tempoActions } from 'viem/tempo' const provider = Provider.create() @@ -168,9 +173,29 @@ const { accounts } = await provider.request({ method: 'wallet_connect', }) -const client = provider.getClient() +const client = provider.getClient().extend(tempoActions()) + +const { receipt } = await client.token.transferSync({ + token: '0x20c0000000000000000000000000000000000001', + to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb', + amount: parseUnits('10', 6), +}) ``` +## Examples + +Check out these examples to get started with the Tempo Accounts SDK. + +| Example | Description | | +| --- | --- | --- | +| [Embed Tempo Wallet](https://github.com/tempoxyz/accounts/tree/main/examples/basic) | Wagmi-based setup using the `tempoWallet` connector to connect to Tempo Wallets. | [Guide](/guide/use-accounts/embed-tempo-wallet) | +| [Embed Domain-bound Passkeys](https://github.com/tempoxyz/accounts/tree/main/examples/domain-bound-webauthn) | Domain-bound passkey example using Wagmi and the `webAuthn` connector. | [Guide](/guide/use-accounts/embed-passkeys) | +| [CLI + Tempo Wallets](https://github.com/tempoxyz/accounts/tree/main/examples/cli) | Minimal CLI setup to connect and authorize local keys using Tempo Wallets. | | +| [Access Keys + Tempo Wallets](https://github.com/tempoxyz/accounts/tree/main/examples/with-access-key) | Authorize access keys using Tempo Wallets to submit transactions without prompts. | | +| [Access Keys + Domain-bound Passkeys](https://github.com/tempoxyz/accounts/tree/main/examples/with-access-key-and-webauthn) | Authorize access keys using domain-bound Passkeys. | | +| [Sponsor Fees + Tempo Wallets](https://github.com/tempoxyz/accounts/tree/main/examples/with-fee-payer) | Sponsor transactions via Tempo Wallets. | [Guide](/guide/payments/sponsor-user-fees) | +| [Sponsor Fees + Domain-bound Passkeys](https://github.com/tempoxyz/accounts/tree/main/examples/with-fee-payer-and-webauthn) | Sponsor transactions via domain-bound Passkeys. | [Guide](/guide/payments/sponsor-user-fees) | + ## Secure Origins (HTTPS) The Tempo Accounts SDK is designed to be used on secure origins (HTTPS). If you are using HTTP, @@ -220,3 +245,9 @@ export default defineConfig({ }) ``` ::: + +## Getting Help + +Have questions or building something cool with the Accounts SDK? + +Join the Telegram group to chat with the team and other devs: [@mpp_devs](https://t.me/mpp_devs) diff --git a/src/pages/accounts/wagmi/index.mdx b/src/pages/accounts/wagmi/index.mdx deleted file mode 100644 index 90662ec9..00000000 --- a/src/pages/accounts/wagmi/index.mdx +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: Connectors -description: Wagmi connectors for integrating Tempo accounts into your app. ---- - -import { Cards, Card } from 'vocs' - -# Connectors - -Wagmi connectors for integrating Tempo accounts into your app. - - - - - diff --git a/src/pages/accounts/wagmi/webAuthn.mdx b/src/pages/accounts/wagmi/webAuthn.mdx index 758d8ca8..bbe5970f 100644 --- a/src/pages/accounts/wagmi/webAuthn.mdx +++ b/src/pages/accounts/wagmi/webAuthn.mdx @@ -16,7 +16,7 @@ import { webAuthn } from 'accounts/wagmi' export const config = createConfig({ chains: [tempo], - connectors: [webAuthn({ authUrl: 'https://myapp.com/auth' })], + connectors: [webAuthn({ authUrl: '/auth' })], transports: { [tempo.id]: http(), }, @@ -51,7 +51,7 @@ export const config = createConfig({ chains: [tempo], connectors: [ webAuthn({ - authUrl: 'https://myapp.com/auth', // [!code focus] + authUrl: '/auth', // [!code focus] }), ], transports: { [tempo.id]: http() }, @@ -76,7 +76,7 @@ export const config = createConfig({ chains: [tempo], connectors: [ webAuthn({ - authUrl: 'https://myapp.com/auth', + authUrl: '/auth', authorizeAccessKey: () => ({ // [!code focus] expiry: Expiry.days(7), // [!code focus] limits: [{ // [!code focus] @@ -115,7 +115,7 @@ export const config = createConfig({ chains: [tempo], connectors: [ webAuthn({ - ceremony: WebAuthnCeremony.server({ url: 'https://myapp.com/auth' }), // [!code focus] + ceremony: WebAuthnCeremony.server({ url: '/auth' }), // [!code focus] }), ], transports: { [tempo.id]: http() }, @@ -142,7 +142,7 @@ export const config = createConfig({ chains: [tempo], connectors: [ webAuthn({ - authUrl: 'https://myapp.com/auth', + authUrl: '/auth', feePayerUrl: 'https://myapp.com/fee-payer', // [!code focus] }), ], @@ -166,7 +166,7 @@ export const config = createConfig({ chains: [tempo], connectors: [ webAuthn({ - authUrl: 'https://myapp.com/auth', + authUrl: '/auth', mpp: true, // [!code focus] }), ], @@ -190,7 +190,7 @@ export const config = createConfig({ chains: [tempo], connectors: [ webAuthn({ - authUrl: 'https://myapp.com/auth', + authUrl: '/auth', testnet: true, // [!code focus] }), ], diff --git a/src/pages/guide/payments/sponsor-user-fees.mdx b/src/pages/guide/payments/sponsor-user-fees.mdx index 9f8187f1..ea4f377d 100644 --- a/src/pages/guide/payments/sponsor-user-fees.mdx +++ b/src/pages/guide/payments/sponsor-user-fees.mdx @@ -81,7 +81,7 @@ import { withFeePayer } from 'viem/tempo' import { createConfig, http } from 'wagmi' export const config = createConfig({ - connectors: [webAuthn({ authUrl: 'https://myapp.com/auth' })], + connectors: [webAuthn({ authUrl: '/auth' })], chains: [tempo], multiInjectedProviderDiscovery: false, transports: { diff --git a/vocs.config.ts b/vocs.config.ts index c2c66b8c..68233621 100644 --- a/vocs.config.ts +++ b/vocs.config.ts @@ -840,10 +840,6 @@ export default defineConfig({ text: 'Connectors', collapsed: true, items: [ - { - text: 'Overview', - link: '/accounts/wagmi', - }, { text: 'tempoWallet', link: '/accounts/wagmi/tempoWallet', From 7bebf44c9b6097137e93e21be4abe1c1015a5d5b Mon Sep 17 00:00:00 2001 From: jxom <7336481+jxom@users.noreply.github.com> Date: Tue, 7 Apr 2026 17:09:05 +1000 Subject: [PATCH 8/8] accounts: add quick prompt, examples table, getting help section Amp-Thread-ID: https://ampcode.com/threads/T-019d652c-8d5d-723f-9b1a-41076bcc23ba --- src/pages/accounts/index.mdx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/pages/accounts/index.mdx b/src/pages/accounts/index.mdx index c29dfd6a..ab782166 100644 --- a/src/pages/accounts/index.mdx +++ b/src/pages/accounts/index.mdx @@ -16,6 +16,14 @@ Try it out by logging into Tempo Wallet below: +## Quick Prompt + +Prompt your agent: + +``` +Read docs.tempo.xyz/accounts and integrate Tempo Wallet into my application +``` + ## Install The Tempo Accounts SDK is available as an [NPM package](https://www.npmjs.com/package/accounts) under `accounts`