From c7493df20d44cb357d590cf0aff7f04fa404aa42 Mon Sep 17 00:00:00 2001 From: ioannischtz Date: Fri, 12 Jun 2026 12:19:34 +0300 Subject: [PATCH 1/9] feat(chat-app): migrate to @mysten/dapp-kit-react - Replace deprecated @mysten/dapp-kit (JSON-RPC) with @mysten/dapp-kit-react + @mysten/dapp-kit-core (gRPC-native); bump @mysten/sui to ^2.17.0 and drop the now-unused @tanstack/react-query. - New src/lib/dapp-kit.ts: createDAppKit instance (testnet + devstack localnet networks, SuiGrpcClient factory) and a signAndExecute helper that throws on FailedTransaction, since the new kit returns a $kind union instead of throwing. - Swap the provider stack to DAppKitProvider and the removed hooks to their replacements (useCurrentClient, useDAppKit, imperative sign methods); delete network-config.ts. - Register the devstack dev-wallet through devWalletInitializer / walletInitializers instead of the manual DevWallet + register + mountDevWallet shim, pinning the panel's active network to localnet. - Keep the queued-sign serialization: dApp Kit does not queue wallet requests and the dev-wallet rejects concurrent signs. Verified on devstack localnet (connect, create group, send, fresh-session decrypt via Playwright) and on testnet (create, send, fresh-client decrypt over the same gRPC client config, plus browser gRPC-Web CORS probe). Co-Authored-By: Claude Fable 5 --- chat-app/.env.example | 1 + chat-app/devstack.config.ts | 5 +- chat-app/package.json | 6 +- chat-app/pnpm-lock.yaml | 1162 ++++------------- chat-app/src/App.tsx | 3 +- chat-app/src/components/AdminPanel.tsx | 3 +- chat-app/src/components/ChatArea.tsx | 9 +- chat-app/src/components/CreateGroupModal.tsx | 3 +- chat-app/src/components/admin/MemberList.tsx | 2 +- .../src/contexts/MessagingClientContext.tsx | 25 +- chat-app/src/hooks/usePermissions.ts | 2 +- chat-app/src/lib/dapp-kit.ts | 51 + chat-app/src/lib/network-config.ts | 24 - chat-app/src/main.tsx | 26 +- chat-app/src/vite-env.d.ts | 2 + chat-app/vite.config.ts | 27 +- 16 files changed, 338 insertions(+), 1013 deletions(-) create mode 100644 chat-app/src/lib/dapp-kit.ts delete mode 100644 chat-app/src/lib/network-config.ts diff --git a/chat-app/.env.example b/chat-app/.env.example index fda4458..704cd1d 100644 --- a/chat-app/.env.example +++ b/chat-app/.env.example @@ -1,5 +1,6 @@ # Sui Network VITE_SUI_NETWORK=testnet +# gRPC-Web endpoint (the public fullnodes serve gRPC and JSON-RPC on the same host) VITE_SUI_RPC_URL=https://fullnode.testnet.sui.io:443 VITE_SUI_GRAPHQL_URL=https://sui-testnet.mystenlabs.com/graphql diff --git a/chat-app/devstack.config.ts b/chat-app/devstack.config.ts index 47644eb..9bbf92c 100644 --- a/chat-app/devstack.config.ts +++ b/chat-app/devstack.config.ts @@ -210,8 +210,9 @@ export default defineDevstack({ // @generated/packages (packages.sui_stack_messaging.packageId) -> packageConfig.messaging // @generated/sui/network (suiNetwork.{rpcUrl,graphqlUrl}) -> base gRPC client + GraphQL // @generated/dapp-kit/config (walletUrl,pairUrl,chain) -> dev-wallet registration + network -// The shim also REGISTERS the dev-wallet (DevstackSignerAdapter + DevWallet + mountDevWallet) — -// devstack runs the wallet server, but the app must register it. MessagingNamespace + Version + +// The shim also builds the dev-wallet `walletInitializers` entry (DevstackSignerAdapter wrapped in +// devWalletInitializer) — devstack runs the wallet server, but the app hands the initializer to +// createDAppKit (src/lib/dapp-kit.ts), which registers the wallet. MessagingNamespace + Version + // the merged sui_groups id are recovered from the publish tx at bootstrap (not surfaced by codegen); // mvr overrides `@local-pkg/sui-stack-messaging` / `@local-pkg/sui-groups` are set on the base client. // diff --git a/chat-app/package.json b/chat-app/package.json index 3efde9e..ae28fc2 100644 --- a/chat-app/package.json +++ b/chat-app/package.json @@ -12,13 +12,13 @@ }, "dependencies": { "@mysten/bcs": "^2.0.3", - "@mysten/dapp-kit": "^1.0.4", + "@mysten/dapp-kit-core": "^1.3.2", + "@mysten/dapp-kit-react": "^2.0.3", "@mysten/sui-stack-messaging": "0.0.2", "@mysten/sui-groups": "^0.0.1", "@mysten/seal": "^1.1.1", - "@mysten/sui": "^2.13.2", + "@mysten/sui": "^2.17.0", "@tailwindcss/vite": "^4.2.1", - "@tanstack/react-query": "^5.90.21", "react": "^19.1.0", "react-dom": "^19.1.0", "tailwindcss": "^4.2.1" diff --git a/chat-app/pnpm-lock.yaml b/chat-app/pnpm-lock.yaml index 5480a3e..f2437ef 100644 --- a/chat-app/pnpm-lock.yaml +++ b/chat-app/pnpm-lock.yaml @@ -14,27 +14,27 @@ importers: '@mysten/bcs': specifier: ^2.0.3 version: 2.0.3 - '@mysten/dapp-kit': - specifier: ^1.0.4 - version: 1.0.4(@mysten/sui@2.13.2(typescript@5.8.3))(@tanstack/react-query@5.90.21(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.8.3) + '@mysten/dapp-kit-core': + specifier: ^1.3.2 + version: 1.3.2(@mysten/sui@2.17.0(typescript@5.8.3))(typescript@5.8.3) + '@mysten/dapp-kit-react': + specifier: ^2.0.3 + version: 2.0.3(@mysten/sui@2.17.0(typescript@5.8.3))(@types/react@19.2.14)(react@19.2.4)(typescript@5.8.3) '@mysten/seal': specifier: ^1.1.1 - version: 1.1.1(@mysten/sui@2.13.2(typescript@5.8.3)) + version: 1.1.1(@mysten/sui@2.17.0(typescript@5.8.3)) '@mysten/sui': - specifier: ^2.13.2 - version: 2.13.2(typescript@5.8.3) + specifier: ^2.17.0 + version: 2.17.0(typescript@5.8.3) '@mysten/sui-groups': specifier: ^0.0.1 - version: 0.0.1(@mysten/bcs@2.0.3)(@mysten/sui@2.13.2(typescript@5.8.3)) + version: 0.0.1(@mysten/bcs@2.0.3)(@mysten/sui@2.17.0(typescript@5.8.3)) '@mysten/sui-stack-messaging': specifier: 0.0.2 - version: 0.0.2(@mysten/bcs@2.0.3)(@mysten/seal@1.1.1(@mysten/sui@2.13.2(typescript@5.8.3)))(@mysten/sui-groups@0.0.1(@mysten/bcs@2.0.3)(@mysten/sui@2.13.2(typescript@5.8.3)))(@mysten/sui@2.13.2(typescript@5.8.3)) + version: 0.0.2(@mysten/bcs@2.0.3)(@mysten/seal@1.1.1(@mysten/sui@2.17.0(typescript@5.8.3)))(@mysten/sui-groups@0.0.1(@mysten/bcs@2.0.3)(@mysten/sui@2.17.0(typescript@5.8.3)))(@mysten/sui@2.17.0(typescript@5.8.3)) '@tailwindcss/vite': specifier: ^4.2.1 version: 4.2.1(vite@6.4.1(@types/node@25.9.2)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.9.0)) - '@tanstack/react-query': - specifier: ^5.90.21 - version: 5.90.21(react@19.2.4) react: specifier: ^19.1.0 version: 19.2.4 @@ -47,13 +47,13 @@ importers: devDependencies: '@mysten-incubation/dev-wallet': specifier: 0.3.0 - version: 0.3.0(@mysten/signers@1.0.5(@mysten/sui@2.13.2(typescript@5.8.3)))(@mysten/sui@2.13.2(typescript@5.8.3))(@types/react@19.2.14)(react@19.2.4)(typescript@5.8.3) + version: 0.3.0(@lit/react@1.0.8(@types/react@19.2.14))(@mysten/signers@1.0.5(@mysten/sui@2.17.0(typescript@5.8.3)))(@mysten/sui@2.17.0(typescript@5.8.3))(@types/react@19.2.14)(react@19.2.4)(typescript@5.8.3) '@mysten-incubation/devstack': specifier: 0.1.1 version: 0.1.1(@types/react@19.2.14)(ioredis@5.11.1)(typescript@5.8.3) '@mysten/signers': specifier: 1.0.5 - version: 1.0.5(@mysten/sui@2.13.2(typescript@5.8.3)) + version: 1.0.5(@mysten/sui@2.17.0(typescript@5.8.3)) '@types/react': specifier: ^19.1.0 version: 19.2.14 @@ -161,10 +161,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} - engines: {node: '>=6.9.0'} - '@babel/template@7.28.6': resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} @@ -190,9 +186,6 @@ packages: effect: ^4.0.0-beta.65 ioredis: ^5.7.0 - '@emotion/hash@0.9.2': - resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} - '@envelop/core@5.5.1': resolution: {integrity: sha512-3DQg8sFskDo386TkL5j12jyRAdip/8yzK3x7YGbZBgobZ4aKXrvDU0GppU0SnmrpQnNaiTUsxBs9LKkwQ/eyvw==} engines: {node: '>=18.0.0'} @@ -370,12 +363,6 @@ packages: '@floating-ui/dom@1.7.6': resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} - '@floating-ui/react-dom@2.1.8': - resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} @@ -518,12 +505,23 @@ packages: '@ledgerhq/logs@6.17.0': resolution: {integrity: sha512-yra33g5q/AU7+PwAws+GaVpQGUuxnDREjVBnviJjcaJLVKuLzI4pnj8Bd3nY3fypM5k1yZEYKEXfUuGFUjP2+w==} + '@lit-labs/scoped-registry-mixin@1.0.4': + resolution: {integrity: sha512-gYeotwRwluD7RsFgU0eP48WgBMg6fIF5RXzbrjs/gwsPiJiFtal90s+x/LHIHqQ2VkubsyP+m+QAfgmOnsNhUg==} + '@lit-labs/ssr-dom-shim@1.6.0': resolution: {integrity: sha512-VHb0ALPMTlgKjM6yIxxoQNnpKyUKLD04VzeQdsiXkMqkvYlAHxq9glGLmgbb889/1GsohSOAjvQYoiBppXFqrQ==} + '@lit/react@1.0.8': + resolution: {integrity: sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==} + peerDependencies: + '@types/react': 17 || 18 || 19 + '@lit/reactive-element@2.1.2': resolution: {integrity: sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==} + '@lit/task@1.0.3': + resolution: {integrity: sha512-1gJGJl8WON+2j0y9xfcD+XsS1rvcy3XDgsIhcdUW++yTR8ESjZW6o7dn8M8a4SZM8NnJe6ynS2cKWwsbfLOurg==} + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4': resolution: {integrity: sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==} cpu: [arm64] @@ -599,12 +597,16 @@ packages: resolution: {integrity: sha512-4t1/V/vQLNoZ4XvGP/Aab5dk6zD63uhk2b9/5aMTZl5njswAEm2q57+eTNoq2fn2WKn9HnEK1DqAsSyr8NDn7w==} hasBin: true - '@mysten/dapp-kit@1.0.4': - resolution: {integrity: sha512-RybvMIT3R+GNWNH7tOWXnsLk0gKLtpY/GOefp/Mzsqb78JD3QzKzlQmrm/Bc5bEisI/SuykU3qYzKDLQivZy0Q==} + '@mysten/dapp-kit-core@1.3.2': + resolution: {integrity: sha512-0IaIDydmJBEVpXSBeR6As3Tx0PzNyKfp4jXlUHkLFiagn3ln+16ai7rsCrgzLna4XCB3EaO+pM6uzClUDTrLng==} peerDependencies: - '@mysten/sui': ^2.8.0 - '@tanstack/react-query': ^5.0.0 - react: '*' + '@mysten/sui': ^2.16.2 + + '@mysten/dapp-kit-react@2.0.3': + resolution: {integrity: sha512-HxRDG6vWDPCg9gmRhXh0gdzU9DVco07eNaL9psHIH23I5ggRo5dPcTtjdSSGTSo/ouYqr9W+JZf4Ao9R+5/q4g==} + peerDependencies: + '@types/react': '>=17.0.0' + react: '>=17.0.0' '@mysten/deepbook-v3@1.4.1': resolution: {integrity: sha512-OLJ9jYNIetg+aXOR2QpIL5eBHeyF8hm3zbv5s6s/jqmDbzqhpGmxvwOodG1X82cML7kKh4IgyQX193+fvndQYA==} @@ -638,10 +640,10 @@ packages: peerDependencies: '@mysten/sui': ^2.16.2 - '@mysten/slush-wallet@1.0.3': - resolution: {integrity: sha512-TF1CXXug5VPaV4KImKxZ7nyR0XY//KJVzOFxFXaajBHewLBinCO7s6GS9EYbtQMaNvnjrYQn1cpGhYfwGkzvtQ==} + '@mysten/slush-wallet@1.0.5': + resolution: {integrity: sha512-soP0eZW4uP2S2z5YH7eg0dZQZ7hZyY6F7D2H0Wv93wjFz9DSHlOf1b9mY+2kzH1oO7nSnpdRdL15v8+X3X7f6w==} peerDependencies: - '@mysten/sui': ^2.8.0 + '@mysten/sui': ^2.16.2 '@mysten/sui-groups@0.0.1': resolution: {integrity: sha512-6yck5UQjAtApWUXvgPc0WaMNatTTUxINBU92XrgawYTWZry/PAxGLvU1XjFFW+DAKbQWpkOMqu8yiuwcBybXfA==} @@ -657,10 +659,6 @@ packages: '@mysten/sui': ^2.13.2 '@mysten/sui-groups': ^0.0.1 - '@mysten/sui@2.13.2': - resolution: {integrity: sha512-M/H2CZJQyLyi0vvCJZ6rRzItJCsnh66v1OTI2VoBad2lau/BTuUKOEPjRpfU4YlVJcGR4h+RLCjDXV4ACuRKSA==} - engines: {node: '>=22'} - '@mysten/sui@2.17.0': resolution: {integrity: sha512-TrS1BCPm4V6rC69MBejmcqnKIyJ5t1iksax4XA9jWarZxAAp9LMmdxEBebejyDT/yAJxYIf3fNm5WBkHE2qnIw==} engines: {node: '>=22'} @@ -681,6 +679,11 @@ packages: peerDependencies: '@mysten/sui': '*' + '@mysten/wallet-standard@0.20.3': + resolution: {integrity: sha512-Kp1EpWaQAwANuMoTCJKVdZnEOaE9aJ5PPvIC7qg+J3u6Uf20VsVsQngZllyaS2OQHm+iLlJzcLXHff7ttvQJYw==} + peerDependencies: + '@mysten/sui': '*' + '@mysten/webcrypto-signer@0.1.2': resolution: {integrity: sha512-MFI64BrUoyI05zZ1GXskZc8ohqCS9fM6StS/RO71YtX9pi7ZLTLdhUM7FEfgCYoSNsJHahG23JxvG0cfgiX/DQ==} engines: {node: '>=22'} @@ -690,6 +693,22 @@ packages: '@mysten/window-wallet-core@0.1.4': resolution: {integrity: sha512-LK1t5dJQZUJv0fF/Cj8HS8N9HHaa7cAOcdWfPAFuYvgVJMEr9K/p33ldqiflcn6p1d53uTtUH9kA5/lQlTmZ2A==} + '@mysten/window-wallet-core@0.1.6': + resolution: {integrity: sha512-vKx4RVn+6sfMHnoFIK3hJ3pxYcy88FdW+BjaFp8GpcGCXC0ImK0HTLNPC0JxeQWmjgDe1eXIMPpY9/eAMU9Azw==} + + '@nanostores/lit@0.2.3': + resolution: {integrity: sha512-hIUKzdNrgKXkXCsppzQxmYYYMTn96cncijWhzcYZKn3Yimqj7B6YK94qN/KObjBNEe0xR3JLgMo96ew5fVtW2w==} + peerDependencies: + lit: ^2.6.0 || ^3.0.0 + nanostores: '>=0.7 < 1.0.0 || ^1.0.0' + + '@nanostores/react@1.1.0': + resolution: {integrity: sha512-MbH35fjhcf7LAubYX5vhOChYUfTLzNLqH/mBGLVsHkcvjy0F8crO1WQwdmQ2xKbAmtpalDa2zBt3Hlg5kqr8iw==} + engines: {node: ^20.0.0 || >=22.0.0} + peerDependencies: + nanostores: ^1.2.0 + react: '>=18.0.0' + '@noble/curves@2.0.1': resolution: {integrity: sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==} engines: {node: '>= 20.19.0'} @@ -764,294 +783,6 @@ packages: '@protobufjs/utf8@1.1.1': resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==} - '@radix-ui/primitive@1.1.3': - resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} - - '@radix-ui/react-arrow@1.1.7': - resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-collection@1.1.7': - resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context@1.1.2': - resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dialog@1.1.15': - resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-direction@1.1.1': - resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dismissable-layer@1.1.11': - resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-dropdown-menu@2.1.16': - resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-focus-guards@1.1.3': - resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-focus-scope@1.1.7': - resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-id@1.1.1': - resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-menu@2.1.16': - resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-popper@1.2.8': - resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-portal@1.1.9': - resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-presence@1.1.5': - resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-primitive@2.1.3': - resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-roving-focus@1.1.11': - resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-slot@1.2.4': - resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-callback-ref@1.1.1': - resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-escape-keydown@1.1.1': - resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-rect@1.1.1': - resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-size@1.1.1': - resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/rect@1.1.1': - resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - '@repeaterjs/repeater@3.0.6': resolution: {integrity: sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==} @@ -1309,14 +1040,6 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 - '@tanstack/query-core@5.90.20': - resolution: {integrity: sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==} - - '@tanstack/react-query@5.90.21': - resolution: {integrity: sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==} - peerDependencies: - react: ^18 || ^19 - '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -1349,20 +1072,6 @@ packages: '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@vanilla-extract/css@1.18.0': - resolution: {integrity: sha512-/p0dwOjr0o8gE5BRQ5O9P0u/2DjUd6Zfga2JGmE4KaY7ZITWMszTzk4x4CPlM5cKkRr2ZGzbE6XkuPNfp9shSQ==} - - '@vanilla-extract/dynamic@2.1.5': - resolution: {integrity: sha512-QGIFGb1qyXQkbzx6X6i3+3LMc/iv/ZMBttMBL+Wm/DetQd36KsKsFg5CtH3qy+1hCA/5w93mEIIAiL4fkM8ycw==} - - '@vanilla-extract/private@1.0.9': - resolution: {integrity: sha512-gT2jbfZuaaCLrAxwXbRgIhGhcXbRZCG3v4TTUnjw0EJ7ArdBRxkq4msNJkbuRkCgfIK5ATmprB5t9ljvLeFDEA==} - - '@vanilla-extract/recipes@0.5.7': - resolution: {integrity: sha512-Fvr+htdyb6LVUu+PhH61UFPhwkjgDEk8L4Zq9oIdte42sntpKrgFy90MyTRtGwjVALmrJ0pwRUVr8UoByYeW8A==} - peerDependencies: - '@vanilla-extract/css': ^1.0.0 - '@vitejs/plugin-react@4.7.0': resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} engines: {node: ^14.18.0 || >=16.0.0} @@ -1377,6 +1086,10 @@ packages: resolution: {integrity: sha512-DJDQhjKmSNVLKWItoKThJS+CsJQjR9AOBOirBVT1F9YpRyC9oYHE+ZnSf8y8bxUphtKqdQMPVQ2mHohYdRvDVQ==} engines: {node: '>=16'} + '@wallet-standard/base@1.1.1': + resolution: {integrity: sha512-gggIHTtxicF9XFMQ12DkfS6NAG92Ak795JeSA7f2whAQ6Y3AkMWWuCMxSZXG2NIPN42kEaZSNVjqMsJRaJRxMQ==} + engines: {node: '>=22'} + '@wallet-standard/core@1.1.1': resolution: {integrity: sha512-5Xmjc6+Oe0hcPfVc5n8F77NVLwx1JVAoCVgQpLyv/43/bhtIif+Gx3WUrDlaSDoM8i2kA2xd6YoFbHCxs+e0zA==} engines: {node: '>=16'} @@ -1386,14 +1099,42 @@ packages: engines: {node: '>=16'} hasBin: true + '@wallet-standard/errors@0.1.2': + resolution: {integrity: sha512-oEzKUqJefKby6wcIvaJgrSEe/uNn/rnqkJ0P/85K+h0i5Tdo9E3L22VWq/j5K1e8hHMnZd6LgaIr8m/Wn7X/Ng==} + engines: {node: '>=22'} + hasBin: true + '@wallet-standard/features@1.1.0': resolution: {integrity: sha512-hiEivWNztx73s+7iLxsuD1sOJ28xtRix58W7Xnz4XzzA/pF0+aicnWgjOdA10doVDEDZdUuZCIIqG96SFNlDUg==} engines: {node: '>=16'} + '@wallet-standard/ui-compare@1.0.3': + resolution: {integrity: sha512-AXst7auT0+5eIaj8MyUXZLopKWN2HwqiQNTVgcF80u9X9a/fsiiHi8tlY0dc/y/AIOM654cMpvpJqsJEZNV9pg==} + engines: {node: '>=22'} + + '@wallet-standard/ui-core@1.0.1': + resolution: {integrity: sha512-LFmsSjMw3wXfZgZ5eAFGdIJ1512dGTWIEeoPDKsc6mHf7cMU18tvtpe4bOL76lT9Qh1Gc+4+kdtwSkTuJ9L+jw==} + engines: {node: '>=22'} + + '@wallet-standard/ui-features@1.0.3': + resolution: {integrity: sha512-3YgxBoDXZCsaSyCNMph7i7G57ap+C6Y+l3HmTEQKigzTGxPUJ2mvqpTPwdj8D2cVkTKBzu8/78wweV7I9eG1rA==} + engines: {node: '>=22'} + + '@wallet-standard/ui-registry@1.1.1': + resolution: {integrity: sha512-vJDZ/K2xwIqkxiyWUhPb6s62bTMRbYPj0MCJa9lYsqHGZgMbKBI3ZjLJK5MzWow2VxoOfuR77HuJng+HDWt1hA==} + engines: {node: '>=22'} + + '@wallet-standard/ui@1.0.3': + resolution: {integrity: sha512-H2QJTR5m3PeHi06q8kj4TiRf3U+fEe6W+jw+hztPkjTRBVDeCIrwRhbdgAyI8yaGc7dBhzGYqhUQ9ecYj7x0rQ==} + engines: {node: '>=22'} + '@wallet-standard/wallet@1.1.0': resolution: {integrity: sha512-Gt8TnSlDZpAl+RWOOAB/kuvC7RpcdWAlFbHNoi4gsXsfaWa1QCT6LBcfIYTPdOZC9OVZUDwqGuGAcqZejDmHjg==} engines: {node: '>=16'} + '@webcomponents/scoped-custom-element-registry@0.0.10': + resolution: {integrity: sha512-wP4LF28aysE2Pq3NQRNQxko7Q0vOOwcoOSMg8FFI4S6z76UuXkYIc5ndC31dJMwso1/vSteL75LW2CEKedAJbA==} + '@whatwg-node/disposablestack@0.0.6': resolution: {integrity: sha512-LOtTn+JgJvX8WfBVJtF08TGrdjuFzGJc4mkP8EdDI8ADbvO7kiexYep1o8dwnt0okb0jYclCDXF13xU7Ge4zSw==} engines: {node: '>=18.0.0'} @@ -1449,10 +1190,6 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - aria-hidden@1.2.6: - resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} - engines: {node: '>=10'} - asn1-ts@11.1.0: resolution: {integrity: sha512-CpmMTBhSn3c9uCyT7GAui+VhplZLLvVAPWwcHgZKaeGDqx8R4OJfJGTenJZ0ZpGg70Q/OTd9TWUT8zDuBzb78w==} @@ -1530,10 +1267,6 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} - clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} - cluster-key-slot@1.1.1: resolution: {integrity: sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==} engines: {node: '>=0.10.0'} @@ -1581,15 +1314,6 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - css-what@6.2.2: - resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} - engines: {node: '>= 6'} - - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -1606,21 +1330,6 @@ packages: supports-color: optional: true - dedent@1.7.2: - resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true - - deep-object-diff@1.1.9: - resolution: {integrity: sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==} - - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -1633,9 +1342,6 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - detect-node-es@1.1.0: - resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -1798,10 +1504,6 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} - get-nonce@1.0.1: - resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} - engines: {node: '>=6'} - get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -2084,9 +1786,6 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - media-query-parser@2.0.2: - resolution: {integrity: sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==} - mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -2112,9 +1811,6 @@ packages: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} - modern-ahocorasick@1.1.0: - resolution: {integrity: sha512-sEKPVl2rM+MNVkGQt3ChdmD8YsigmXdn5NifZn6jiwn9LRJpWm8F3guhaqrJT/JOat6pwpbXEk6kv+b9DMIjsQ==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2133,6 +1829,10 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanostores@1.3.0: + resolution: {integrity: sha512-XPUa/jz+P1oJvN9VBxw4L9MtdFfaH3DAryqPssqhb2kXjmb9npz0dly6rCsgFWOPr4Yg9mTfM3MDZgZZ+7A3lA==} + engines: {node: ^20.0.0 || >=22.0.0} + node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} @@ -2235,36 +1935,6 @@ packages: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} - react-remove-scroll-bar@2.3.8: - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - react-remove-scroll@2.7.2: - resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react-style-singleton@2.2.3: - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - react@19.2.4: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} @@ -2458,28 +2128,8 @@ packages: urlpattern-polyfill@10.1.0: resolution: {integrity: sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==} - use-callback-ref@1.3.3: - resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - use-sidecar@1.1.3: - resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} utility-types@3.11.0: resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==} @@ -2603,24 +2253,6 @@ packages: zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} - zustand@5.0.11: - resolution: {integrity: sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==} - 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 - snapshots: '@0no-co/graphql.web@1.2.0(graphql@16.13.1)': @@ -2733,8 +2365,6 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/runtime@7.28.6': {} - '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.29.0 @@ -2778,8 +2408,6 @@ snapshots: - bufferutil - utf-8-validate - '@emotion/hash@0.9.2': {} - '@envelop/core@5.5.1': dependencies: '@envelop/instrumentation': 1.0.0 @@ -2886,12 +2514,6 @@ snapshots: '@floating-ui/core': 1.7.5 '@floating-ui/utils': 0.2.11 - '@floating-ui/react-dom@2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@floating-ui/dom': 1.7.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - '@floating-ui/utils@0.2.11': {} '@google-cloud/kms@5.5.1': @@ -3082,12 +2704,25 @@ snapshots: '@ledgerhq/logs@6.17.0': {} + '@lit-labs/scoped-registry-mixin@1.0.4': + dependencies: + '@lit/reactive-element': 2.1.2 + lit: 3.3.3 + '@lit-labs/ssr-dom-shim@1.6.0': {} + '@lit/react@1.0.8(@types/react@19.2.14)': + dependencies: + '@types/react': 19.2.14 + '@lit/reactive-element@2.1.2': dependencies: '@lit-labs/ssr-dom-shim': 1.6.0 + '@lit/task@1.0.3': + dependencies: + '@lit/reactive-element': 2.1.2 + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4': optional: true @@ -3106,18 +2741,19 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4': optional: true - '@mysten-incubation/dev-wallet@0.3.0(@mysten/signers@1.0.5(@mysten/sui@2.13.2(typescript@5.8.3)))(@mysten/sui@2.13.2(typescript@5.8.3))(@types/react@19.2.14)(react@19.2.4)(typescript@5.8.3)': + '@mysten-incubation/dev-wallet@0.3.0(@lit/react@1.0.8(@types/react@19.2.14))(@mysten/signers@1.0.5(@mysten/sui@2.17.0(typescript@5.8.3)))(@mysten/sui@2.17.0(typescript@5.8.3))(@types/react@19.2.14)(react@19.2.4)(typescript@5.8.3)': dependencies: '@hono/node-server': 1.19.14(hono@4.12.24) - '@mysten/sui': 2.13.2(typescript@5.8.3) + '@mysten/sui': 2.17.0(typescript@5.8.3) '@mysten/utils': 0.3.1 - '@mysten/wallet-sdk': 0.1.1(@mysten/sui@2.13.2(typescript@5.8.3))(typescript@5.8.3) - '@mysten/wallet-standard': 0.20.1(@mysten/sui@2.13.2(typescript@5.8.3)) + '@mysten/wallet-sdk': 0.1.1(@mysten/sui@2.17.0(typescript@5.8.3))(typescript@5.8.3) + '@mysten/wallet-standard': 0.20.1(@mysten/sui@2.17.0(typescript@5.8.3)) '@mysten/window-wallet-core': 0.1.4(typescript@5.8.3) hono: 4.12.24 lit: 3.3.3 optionalDependencies: - '@mysten/signers': 1.0.5(@mysten/sui@2.13.2(typescript@5.8.3)) + '@lit/react': 1.0.8(@types/react@19.2.14) + '@mysten/signers': 1.0.5(@mysten/sui@2.17.0(typescript@5.8.3)) '@types/react': 19.2.14 react: 19.2.4 transitivePeerDependencies: @@ -3151,9 +2787,9 @@ snapshots: - typescript - utf-8-validate - '@mysten/aws-kms-signer@0.1.2(@mysten/sui@2.13.2(typescript@5.8.3))': + '@mysten/aws-kms-signer@0.1.2(@mysten/sui@2.17.0(typescript@5.8.3))': dependencies: - '@mysten/sui': 2.13.2(typescript@5.8.3) + '@mysten/sui': 2.17.0(typescript@5.8.3) '@noble/curves': 2.0.1 asn1-ts: 11.1.0 @@ -3183,30 +2819,35 @@ snapshots: - '@gql.tada/svelte-support' - '@gql.tada/vue-support' - '@mysten/dapp-kit@1.0.4(@mysten/sui@2.13.2(typescript@5.8.3))(@tanstack/react-query@5.90.21(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.8.3)': + '@mysten/dapp-kit-core@1.3.2(@mysten/sui@2.17.0(typescript@5.8.3))(typescript@5.8.3)': dependencies: - '@mysten/slush-wallet': 1.0.3(@mysten/sui@2.13.2(typescript@5.8.3))(typescript@5.8.3) - '@mysten/sui': 2.13.2(typescript@5.8.3) - '@mysten/utils': 0.3.1 - '@mysten/wallet-standard': 0.20.1(@mysten/sui@2.13.2(typescript@5.8.3)) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.4) - '@tanstack/react-query': 5.90.21(react@19.2.4) - '@vanilla-extract/css': 1.18.0 - '@vanilla-extract/dynamic': 2.1.5 - '@vanilla-extract/recipes': 0.5.7(@vanilla-extract/css@1.18.0) - clsx: 2.1.1 + '@floating-ui/dom': 1.7.6 + '@lit-labs/scoped-registry-mixin': 1.0.4 + '@lit/task': 1.0.3 + '@mysten/slush-wallet': 1.0.5(@mysten/sui@2.17.0(typescript@5.8.3))(typescript@5.8.3) + '@mysten/sui': 2.17.0(typescript@5.8.3) + '@mysten/utils': 0.3.3 + '@mysten/wallet-standard': 0.20.3(@mysten/sui@2.17.0(typescript@5.8.3)) + '@nanostores/lit': 0.2.3(lit@3.3.3)(nanostores@1.3.0) + '@wallet-standard/ui': 1.0.3 + '@wallet-standard/ui-registry': 1.1.1 + '@webcomponents/scoped-custom-element-registry': 0.0.10 + lit: 3.3.3 + nanostores: 1.3.0 + transitivePeerDependencies: + - typescript + + '@mysten/dapp-kit-react@2.0.3(@mysten/sui@2.17.0(typescript@5.8.3))(@types/react@19.2.14)(react@19.2.4)(typescript@5.8.3)': + dependencies: + '@lit/react': 1.0.8(@types/react@19.2.14) + '@mysten/dapp-kit-core': 1.3.2(@mysten/sui@2.17.0(typescript@5.8.3))(typescript@5.8.3) + '@nanostores/react': 1.1.0(nanostores@1.3.0)(react@19.2.4) + '@types/react': 19.2.14 + nanostores: 1.3.0 react: 19.2.4 - zustand: 5.0.11(@types/react@19.2.14)(react@19.2.4) transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - - babel-plugin-macros - - immer - - react-dom + - '@mysten/sui' - typescript - - use-sync-external-store '@mysten/deepbook-v3@1.4.1(@mysten/sui@2.17.0(typescript@5.8.3))': dependencies: @@ -3219,19 +2860,19 @@ snapshots: - debug - supports-color - '@mysten/gcp-kms-signer@0.1.2(@mysten/sui@2.13.2(typescript@5.8.3))': + '@mysten/gcp-kms-signer@0.1.2(@mysten/sui@2.17.0(typescript@5.8.3))': dependencies: '@google-cloud/kms': 5.5.1 - '@mysten/sui': 2.13.2(typescript@5.8.3) + '@mysten/sui': 2.17.0(typescript@5.8.3) '@noble/curves': 2.0.1 asn1-ts: 11.1.0 transitivePeerDependencies: - supports-color - '@mysten/ledger-signer@0.1.2(@mysten/sui@2.13.2(typescript@5.8.3))': + '@mysten/ledger-signer@0.1.2(@mysten/sui@2.17.0(typescript@5.8.3))': dependencies: '@mysten/ledgerjs-hw-app-sui': 0.8.3 - '@mysten/sui': 2.13.2(typescript@5.8.3) + '@mysten/sui': 2.17.0(typescript@5.8.3) transitivePeerDependencies: - debug @@ -3247,67 +2888,45 @@ snapshots: transitivePeerDependencies: - debug - '@mysten/seal@1.1.1(@mysten/sui@2.13.2(typescript@5.8.3))': + '@mysten/seal@1.1.1(@mysten/sui@2.17.0(typescript@5.8.3))': dependencies: '@mysten/bcs': 2.0.3 - '@mysten/sui': 2.13.2(typescript@5.8.3) + '@mysten/sui': 2.17.0(typescript@5.8.3) '@noble/curves': 2.0.1 '@noble/hashes': 2.0.1 - '@mysten/signers@1.0.5(@mysten/sui@2.13.2(typescript@5.8.3))': + '@mysten/signers@1.0.5(@mysten/sui@2.17.0(typescript@5.8.3))': dependencies: - '@mysten/aws-kms-signer': 0.1.2(@mysten/sui@2.13.2(typescript@5.8.3)) - '@mysten/gcp-kms-signer': 0.1.2(@mysten/sui@2.13.2(typescript@5.8.3)) - '@mysten/ledger-signer': 0.1.2(@mysten/sui@2.13.2(typescript@5.8.3)) - '@mysten/sui': 2.13.2(typescript@5.8.3) - '@mysten/webcrypto-signer': 0.1.2(@mysten/sui@2.13.2(typescript@5.8.3)) + '@mysten/aws-kms-signer': 0.1.2(@mysten/sui@2.17.0(typescript@5.8.3)) + '@mysten/gcp-kms-signer': 0.1.2(@mysten/sui@2.17.0(typescript@5.8.3)) + '@mysten/ledger-signer': 0.1.2(@mysten/sui@2.17.0(typescript@5.8.3)) + '@mysten/sui': 2.17.0(typescript@5.8.3) + '@mysten/webcrypto-signer': 0.1.2(@mysten/sui@2.17.0(typescript@5.8.3)) transitivePeerDependencies: - debug - supports-color - '@mysten/slush-wallet@1.0.3(@mysten/sui@2.13.2(typescript@5.8.3))(typescript@5.8.3)': + '@mysten/slush-wallet@1.0.5(@mysten/sui@2.17.0(typescript@5.8.3))(typescript@5.8.3)': dependencies: - '@mysten/sui': 2.13.2(typescript@5.8.3) - '@mysten/utils': 0.3.1 - '@mysten/wallet-standard': 0.20.1(@mysten/sui@2.13.2(typescript@5.8.3)) - '@mysten/window-wallet-core': 0.1.4(typescript@5.8.3) + '@mysten/sui': 2.17.0(typescript@5.8.3) + '@mysten/utils': 0.3.3 + '@mysten/wallet-standard': 0.20.3(@mysten/sui@2.17.0(typescript@5.8.3)) + '@mysten/window-wallet-core': 0.1.6(typescript@5.8.3) valibot: 1.2.0(typescript@5.8.3) transitivePeerDependencies: - typescript - '@mysten/sui-groups@0.0.1(@mysten/bcs@2.0.3)(@mysten/sui@2.13.2(typescript@5.8.3))': - dependencies: - '@mysten/bcs': 2.0.3 - '@mysten/sui': 2.13.2(typescript@5.8.3) - - '@mysten/sui-stack-messaging@0.0.2(@mysten/bcs@2.0.3)(@mysten/seal@1.1.1(@mysten/sui@2.13.2(typescript@5.8.3)))(@mysten/sui-groups@0.0.1(@mysten/bcs@2.0.3)(@mysten/sui@2.13.2(typescript@5.8.3)))(@mysten/sui@2.13.2(typescript@5.8.3))': + '@mysten/sui-groups@0.0.1(@mysten/bcs@2.0.3)(@mysten/sui@2.17.0(typescript@5.8.3))': dependencies: '@mysten/bcs': 2.0.3 - '@mysten/seal': 1.1.1(@mysten/sui@2.13.2(typescript@5.8.3)) - '@mysten/sui': 2.13.2(typescript@5.8.3) - '@mysten/sui-groups': 0.0.1(@mysten/bcs@2.0.3)(@mysten/sui@2.13.2(typescript@5.8.3)) + '@mysten/sui': 2.17.0(typescript@5.8.3) - '@mysten/sui@2.13.2(typescript@5.8.3)': + '@mysten/sui-stack-messaging@0.0.2(@mysten/bcs@2.0.3)(@mysten/seal@1.1.1(@mysten/sui@2.17.0(typescript@5.8.3)))(@mysten/sui-groups@0.0.1(@mysten/bcs@2.0.3)(@mysten/sui@2.17.0(typescript@5.8.3)))(@mysten/sui@2.17.0(typescript@5.8.3))': dependencies: - '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.1) '@mysten/bcs': 2.0.3 - '@mysten/utils': 0.3.1 - '@noble/curves': 2.0.1 - '@noble/hashes': 2.0.1 - '@protobuf-ts/grpcweb-transport': 2.11.1 - '@protobuf-ts/runtime': 2.11.1 - '@protobuf-ts/runtime-rpc': 2.11.1 - '@scure/base': 2.0.0 - '@scure/bip32': 2.0.1 - '@scure/bip39': 2.0.1 - gql.tada: 1.9.0(graphql@16.13.1)(typescript@5.8.3) - graphql: 16.13.1 - poseidon-lite: 0.2.1 - valibot: 1.2.0(typescript@5.8.3) - transitivePeerDependencies: - - '@gql.tada/svelte-support' - - '@gql.tada/vue-support' - - typescript + '@mysten/seal': 1.1.1(@mysten/sui@2.17.0(typescript@5.8.3)) + '@mysten/sui': 2.17.0(typescript@5.8.3) + '@mysten/sui-groups': 0.0.1(@mysten/bcs@2.0.3)(@mysten/sui@2.17.0(typescript@5.8.3)) '@mysten/sui@2.17.0(typescript@5.8.3)': dependencies: @@ -3361,23 +2980,28 @@ snapshots: dependencies: '@scure/base': 2.0.0 - '@mysten/wallet-sdk@0.1.1(@mysten/sui@2.13.2(typescript@5.8.3))(typescript@5.8.3)': + '@mysten/wallet-sdk@0.1.1(@mysten/sui@2.17.0(typescript@5.8.3))(typescript@5.8.3)': dependencies: '@mysten/bcs': 2.0.3 - '@mysten/sui': 2.13.2(typescript@5.8.3) - '@mysten/wallet-standard': 0.20.1(@mysten/sui@2.13.2(typescript@5.8.3)) + '@mysten/sui': 2.17.0(typescript@5.8.3) + '@mysten/wallet-standard': 0.20.1(@mysten/sui@2.17.0(typescript@5.8.3)) valibot: 1.2.0(typescript@5.8.3) transitivePeerDependencies: - typescript - '@mysten/wallet-standard@0.20.1(@mysten/sui@2.13.2(typescript@5.8.3))': + '@mysten/wallet-standard@0.20.1(@mysten/sui@2.17.0(typescript@5.8.3))': + dependencies: + '@mysten/sui': 2.17.0(typescript@5.8.3) + '@wallet-standard/core': 1.1.1 + + '@mysten/wallet-standard@0.20.3(@mysten/sui@2.17.0(typescript@5.8.3))': dependencies: - '@mysten/sui': 2.13.2(typescript@5.8.3) + '@mysten/sui': 2.17.0(typescript@5.8.3) '@wallet-standard/core': 1.1.1 - '@mysten/webcrypto-signer@0.1.2(@mysten/sui@2.13.2(typescript@5.8.3))': + '@mysten/webcrypto-signer@0.1.2(@mysten/sui@2.17.0(typescript@5.8.3))': dependencies: - '@mysten/sui': 2.13.2(typescript@5.8.3) + '@mysten/sui': 2.17.0(typescript@5.8.3) '@noble/curves': 2.0.1 '@mysten/window-wallet-core@0.1.4(typescript@5.8.3)': @@ -3388,6 +3012,24 @@ snapshots: transitivePeerDependencies: - typescript + '@mysten/window-wallet-core@0.1.6(typescript@5.8.3)': + dependencies: + '@mysten/utils': 0.3.3 + jose: 6.2.1 + valibot: 1.2.0(typescript@5.8.3) + transitivePeerDependencies: + - typescript + + '@nanostores/lit@0.2.3(lit@3.3.3)(nanostores@1.3.0)': + dependencies: + lit: 3.3.3 + nanostores: 1.3.0 + + '@nanostores/react@1.1.0(nanostores@1.3.0)(react@19.2.4)': + dependencies: + nanostores: 1.3.0 + react: 19.2.4 + '@noble/curves@2.0.1': dependencies: '@noble/hashes': 2.0.1 @@ -3449,275 +3091,6 @@ snapshots: '@protobufjs/utf8@1.1.1': {} - '@radix-ui/primitive@1.1.3': {} - - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - aria-hidden: 1.2.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - aria-hidden: 1.2.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/rect': 1.1.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/rect': 1.1.1 - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/rect@1.1.1': {} - '@repeaterjs/repeater@3.0.6': {} '@rolldown/pluginutils@1.0.0-beta.27': {} @@ -3886,13 +3259,6 @@ snapshots: tailwindcss: 4.2.1 vite: 6.4.1(@types/node@25.9.2)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.9.0) - '@tanstack/query-core@5.90.20': {} - - '@tanstack/react-query@5.90.21(react@19.2.4)': - dependencies: - '@tanstack/query-core': 5.90.20 - react: 19.2.4 - '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.29.0 @@ -3934,33 +3300,6 @@ snapshots: dependencies: '@types/node': 25.9.2 - '@vanilla-extract/css@1.18.0': - dependencies: - '@emotion/hash': 0.9.2 - '@vanilla-extract/private': 1.0.9 - css-what: 6.2.2 - cssesc: 3.0.0 - csstype: 3.2.3 - dedent: 1.7.2 - deep-object-diff: 1.1.9 - deepmerge: 4.3.1 - lru-cache: 10.4.3 - media-query-parser: 2.0.2 - modern-ahocorasick: 1.1.0 - picocolors: 1.1.1 - transitivePeerDependencies: - - babel-plugin-macros - - '@vanilla-extract/dynamic@2.1.5': - dependencies: - '@vanilla-extract/private': 1.0.9 - - '@vanilla-extract/private@1.0.9': {} - - '@vanilla-extract/recipes@0.5.7(@vanilla-extract/css@1.18.0)': - dependencies: - '@vanilla-extract/css': 1.18.0 - '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@25.9.2)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.0 @@ -3979,6 +3318,8 @@ snapshots: '@wallet-standard/base@1.1.0': {} + '@wallet-standard/base@1.1.1': {} + '@wallet-standard/core@1.1.1': dependencies: '@wallet-standard/app': 1.1.0 @@ -3992,14 +3333,50 @@ snapshots: chalk: 5.6.2 commander: 13.1.0 + '@wallet-standard/errors@0.1.2': + dependencies: + chalk: 5.6.2 + commander: 13.1.0 + '@wallet-standard/features@1.1.0': dependencies: '@wallet-standard/base': 1.1.0 + '@wallet-standard/ui-compare@1.0.3': + dependencies: + '@wallet-standard/base': 1.1.1 + '@wallet-standard/ui-core': 1.0.1 + '@wallet-standard/ui-registry': 1.1.1 + + '@wallet-standard/ui-core@1.0.1': + dependencies: + '@wallet-standard/base': 1.1.1 + + '@wallet-standard/ui-features@1.0.3': + dependencies: + '@wallet-standard/base': 1.1.1 + '@wallet-standard/errors': 0.1.2 + '@wallet-standard/ui-core': 1.0.1 + '@wallet-standard/ui-registry': 1.1.1 + + '@wallet-standard/ui-registry@1.1.1': + dependencies: + '@wallet-standard/base': 1.1.1 + '@wallet-standard/errors': 0.1.2 + '@wallet-standard/ui-core': 1.0.1 + + '@wallet-standard/ui@1.0.3': + dependencies: + '@wallet-standard/ui-compare': 1.0.3 + '@wallet-standard/ui-core': 1.0.1 + '@wallet-standard/ui-features': 1.0.3 + '@wallet-standard/wallet@1.1.0': dependencies: '@wallet-standard/base': 1.1.0 + '@webcomponents/scoped-custom-element-registry@0.0.10': {} + '@whatwg-node/disposablestack@0.0.6': dependencies: '@whatwg-node/promise-helpers': 1.3.2 @@ -4057,10 +3434,6 @@ snapshots: argparse@2.0.1: {} - aria-hidden@1.2.6: - dependencies: - tslib: 2.8.1 - asn1-ts@11.1.0: {} asynckit@0.4.0: {} @@ -4140,8 +3513,6 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - clsx@2.1.1: {} - cluster-key-slot@1.1.1: {} code-excerpt@4.0.0: @@ -4183,10 +3554,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-what@6.2.2: {} - - cssesc@3.0.0: {} - csstype@3.2.3: {} data-uri-to-buffer@4.0.1: {} @@ -4195,20 +3562,12 @@ snapshots: dependencies: ms: 2.1.3 - dedent@1.7.2: {} - - deep-object-diff@1.1.9: {} - - deepmerge@4.3.1: {} - delayed-stream@1.0.0: {} denque@2.1.0: {} detect-libc@2.1.2: {} - detect-node-es@1.1.0: {} - dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -4403,8 +3762,6 @@ snapshots: hasown: 2.0.4 math-intrinsics: 1.1.0 - get-nonce@1.0.1: {} - get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -4730,10 +4087,6 @@ snapshots: math-intrinsics@1.1.0: {} - media-query-parser@2.0.2: - dependencies: - '@babel/runtime': 7.28.6 - mime-db@1.52.0: {} mime-types@2.1.35: @@ -4750,8 +4103,6 @@ snapshots: minipass@7.1.3: {} - modern-ahocorasick@1.1.0: {} - ms@2.1.3: {} msgpackr-extract@3.0.4: @@ -4774,6 +4125,8 @@ snapshots: nanoid@3.3.11: {} + nanostores@1.3.0: {} + node-domexception@1.0.0: {} node-fetch@3.3.2: @@ -4872,33 +4225,6 @@ snapshots: react-refresh@0.17.0: {} - react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.4): - dependencies: - react: 19.2.4 - react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.14 - - react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.4): - dependencies: - react: 19.2.4 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.4) - react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) - tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.4) - use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - - react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.4): - dependencies: - get-nonce: 1.0.1 - react: 19.2.4 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.14 - react@19.2.4: {} react@19.2.7: {} @@ -5088,21 +4414,6 @@ snapshots: urlpattern-polyfill@10.1.0: {} - use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.4): - dependencies: - react: 19.2.4 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.14 - - use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.4): - dependencies: - detect-node-es: 1.1.0 - react: 19.2.4 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.14 - util-deprecate@1.0.2: {} utility-types@3.11.0: {} @@ -5185,8 +4496,3 @@ snapshots: yoga-layout@3.2.1: {} zod@4.4.3: {} - - zustand@5.0.11(@types/react@19.2.14)(react@19.2.4): - optionalDependencies: - '@types/react': 19.2.14 - react: 19.2.4 diff --git a/chat-app/src/App.tsx b/chat-app/src/App.tsx index 0fe93ce..59e6aa8 100644 --- a/chat-app/src/App.tsx +++ b/chat-app/src/App.tsx @@ -1,5 +1,6 @@ import { useState, useCallback } from 'react'; -import { ConnectButton, useCurrentAccount } from '@mysten/dapp-kit'; +import { useCurrentAccount } from '@mysten/dapp-kit-react'; +import { ConnectButton } from '@mysten/dapp-kit-react/ui'; import { Sidebar } from './components/Sidebar'; import { ChatArea } from './components/ChatArea'; import { CreateGroupModal } from './components/CreateGroupModal'; diff --git a/chat-app/src/components/AdminPanel.tsx b/chat-app/src/components/AdminPanel.tsx index c6e8d29..0edef6a 100644 --- a/chat-app/src/components/AdminPanel.tsx +++ b/chat-app/src/components/AdminPanel.tsx @@ -2,7 +2,7 @@ * Slide-out admin panel for group management. */ import { useState, useEffect, useCallback } from 'react'; -import { useSignAndExecuteTransaction } from '@mysten/dapp-kit'; +import { signAndExecute } from '../lib/dapp-kit'; import { useRequiredMessagingClient } from '../contexts/MessagingClientContext'; import { updateStoredGroupName } from '../lib/group-store'; import type { Permissions } from '../hooks/usePermissions'; @@ -40,7 +40,6 @@ export function AdminPanel({ onGroupArchived, }: Readonly) { const { client } = useRequiredMessagingClient(); - const { mutateAsync: signAndExecute } = useSignAndExecuteTransaction(); const [members, setMembers] = useState([]); const [loadingMembers, setLoadingMembers] = useState(false); diff --git a/chat-app/src/components/ChatArea.tsx b/chat-app/src/components/ChatArea.tsx index 9644f45..0dcf3e2 100644 --- a/chat-app/src/components/ChatArea.tsx +++ b/chat-app/src/components/ChatArea.tsx @@ -1,8 +1,6 @@ import { useState, useRef, useEffect, useCallback } from 'react'; -import { - useCurrentAccount, - useSignAndExecuteTransaction, -} from '@mysten/dapp-kit'; +import { useCurrentAccount } from '@mysten/dapp-kit-react'; +import { signAndExecute } from '../lib/dapp-kit'; import type { StoredGroup } from '../lib/group-store'; import { removeStoredGroup } from '../lib/group-store'; import { useRequiredMessagingClient } from '../contexts/MessagingClientContext'; @@ -103,7 +101,6 @@ function ChatView({ }>) { const account = useCurrentAccount(); const { client } = useRequiredMessagingClient(); - const { mutateAsync: signAndExecute } = useSignAndExecuteTransaction(); const { permissions, refresh: refreshPermissions } = usePermissions(group.groupId); const [adminPanelOpen, setAdminPanelOpen] = useState(false); const { @@ -146,7 +143,7 @@ function ChatView({ } finally { setLeaving(false); } - }, [client, group, signAndExecute, onLeaveGroup]); + }, [client, group, onLeaveGroup]); const scrollRef = useRef(null); const bottomRef = useRef(null); diff --git a/chat-app/src/components/CreateGroupModal.tsx b/chat-app/src/components/CreateGroupModal.tsx index 374355e..a48aa47 100644 --- a/chat-app/src/components/CreateGroupModal.tsx +++ b/chat-app/src/components/CreateGroupModal.tsx @@ -1,5 +1,5 @@ import {type SyntheticEvent, useState} from 'react'; -import { useSignAndExecuteTransaction } from '@mysten/dapp-kit'; +import { signAndExecute } from '../lib/dapp-kit'; import { useRequiredMessagingClient } from '../contexts/MessagingClientContext'; import { addStoredGroup } from '../lib/group-store'; @@ -15,7 +15,6 @@ export function CreateGroupModal({ onGroupCreated, }: Readonly) { const { client } = useRequiredMessagingClient(); - const { mutateAsync: signAndExecute } = useSignAndExecuteTransaction(); const [name, setName] = useState(''); const [members, setMembers] = useState(''); diff --git a/chat-app/src/components/admin/MemberList.tsx b/chat-app/src/components/admin/MemberList.tsx index 34ab402..1f4c861 100644 --- a/chat-app/src/components/admin/MemberList.tsx +++ b/chat-app/src/components/admin/MemberList.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { useCurrentAccount } from '@mysten/dapp-kit'; +import { useCurrentAccount } from '@mysten/dapp-kit-react'; import { MemberItem } from './MemberItem'; interface MemberWithPermissions { diff --git a/chat-app/src/contexts/MessagingClientContext.tsx b/chat-app/src/contexts/MessagingClientContext.tsx index 06cac55..f052857 100644 --- a/chat-app/src/contexts/MessagingClientContext.tsx +++ b/chat-app/src/contexts/MessagingClientContext.tsx @@ -1,9 +1,9 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'; import { useCurrentAccount, - useSignPersonalMessage, - useSuiClient, -} from '@mysten/dapp-kit'; + useCurrentClient, + useDAppKit, +} from '@mysten/dapp-kit-react'; import { createSuiStackMessagingClient, WalrusHttpStorageAdapter } from '@mysten/sui-stack-messaging'; import { SuiGraphQLClient } from '@mysten/sui/graphql'; import { DappKitSigner } from '../lib/dapp-kit-signer'; @@ -90,25 +90,20 @@ export function MessagingClientProvider({ children: ReactNode; }>) { const account = useCurrentAccount(); - const suiClient = useSuiClient(); - const { mutateAsync: signPersonalMessage } = useSignPersonalMessage(); - - // Stabilize signPersonalMessage so it doesn't cause client recreation on every render - const signRef = useRef(signPersonalMessage); - useEffect(() => { - signRef.current = signPersonalMessage; - }, [signPersonalMessage]); + const suiClient = useCurrentClient(); + const dAppKit = useDAppKit(); // Serialize wallet sign requests. The Seal session-key flow and tx signing can each // trigger a personal-message sign, and they can overlap (more so under React StrictMode). - // The devstack dev-wallet — and some real wallets — reject a second concurrent sign with - // "a signing request is already pending"; queueing keeps at most one in flight. + // dApp Kit does not queue wallet requests, and the devstack dev-wallet — like some real + // wallets — rejects a second concurrent sign with "a signing request is already pending"; + // queueing keeps at most one in flight. const signChain = useRef>(Promise.resolve()); const queuedSign = useCallback((args: { message: Uint8Array }): Promise<{ signature: string }> => { - const run = signChain.current.then(() => signRef.current(args)); + const run = signChain.current.then(() => dAppKit.signPersonalMessage(args)); signChain.current = run.catch(() => undefined); return run; - }, []); + }, [dAppKit]); // Local devstack: resolve the generated config (local RPC + seal + package ids) // and recover the bundled sui_groups id once, independent of the wallet. diff --git a/chat-app/src/hooks/usePermissions.ts b/chat-app/src/hooks/usePermissions.ts index 67f254f..c609bd3 100644 --- a/chat-app/src/hooks/usePermissions.ts +++ b/chat-app/src/hooks/usePermissions.ts @@ -7,7 +7,7 @@ * - EncryptionKeyRotator, MetadataAdmin */ import { useState, useEffect, useCallback, useRef } from 'react'; -import { useCurrentAccount } from '@mysten/dapp-kit'; +import { useCurrentAccount } from '@mysten/dapp-kit-react'; import { useRequiredMessagingClient } from '../contexts/MessagingClientContext'; export interface Permissions { diff --git a/chat-app/src/lib/dapp-kit.ts b/chat-app/src/lib/dapp-kit.ts new file mode 100644 index 0000000..237f069 --- /dev/null +++ b/chat-app/src/lib/dapp-kit.ts @@ -0,0 +1,51 @@ +import { createDAppKit } from '@mysten/dapp-kit-react'; +import { SuiGrpcClient } from '@mysten/sui/grpc'; +import { devstack } from 'virtual:devstack-app-config'; +import type { Transaction } from '@mysten/sui/transactions'; +import { devstackNetwork, isDevstack } from './devstack-config'; + +// gRPC-Web endpoint (the public fullnodes serve gRPC and JSON-RPC on the same host). +const TESTNET_GRPC_URL = + import.meta.env.VITE_SUI_RPC_URL || 'https://fullnode.testnet.sui.io:443'; + +// `localnet` is registered up front but only constructible under `devstack up` — +// outside devstack the default network is `testnet` and nothing switches to it. +// Under devstack, the dev wallet reports `sui:localnet` chains, so dApp Kit must +// default to `localnet` to connect on the same chain. +export const dAppKit = createDAppKit({ + networks: ['testnet', 'localnet'] as const, + defaultNetwork: isDevstack && devstackNetwork ? 'localnet' : 'testnet', + createClient(network) { + if (network === 'localnet') { + if (!devstackNetwork) { + throw new Error('The localnet network is only available under a devstack run'); + } + return new SuiGrpcClient({ network: 'localnet', baseUrl: devstackNetwork.rpcUrl }); + } + return new SuiGrpcClient({ network: 'testnet', baseUrl: TESTNET_GRPC_URL }); + }, + // Under devstack, the shim provides a dev-wallet initializer (server-backed + // accounts + floating approval UI); outside devstack, no extra wallets. + walletInitializers: devstack?.walletInitializers ?? [], +}); + +declare module '@mysten/dapp-kit-react' { + interface Register { + dAppKit: typeof dAppKit; + } +} + +/** + * Sign and execute a transaction via the connected wallet, throwing on failure. + * dApp Kit returns a `$kind` union instead of throwing when the transaction + * fails on-chain, so call sites that treat resolution as success go through this. + */ +export async function signAndExecute({ transaction }: { transaction: Transaction }) { + const result = await dAppKit.signAndExecuteTransaction({ transaction }); + if (result.$kind === 'FailedTransaction') { + throw new Error( + result.FailedTransaction.status.error?.message ?? 'Transaction failed on-chain', + ); + } + return result; +} diff --git a/chat-app/src/lib/network-config.ts b/chat-app/src/lib/network-config.ts deleted file mode 100644 index b122360..0000000 --- a/chat-app/src/lib/network-config.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { createNetworkConfig } from '@mysten/dapp-kit'; -import { getJsonRpcFullnodeUrl } from '@mysten/sui/jsonRpc'; -import { devstackNetwork, isDevstack } from './devstack-config'; - -const rpcUrl = import.meta.env.VITE_SUI_RPC_URL; - -const testnet = { - url: rpcUrl || getJsonRpcFullnodeUrl('testnet'), - network: 'testnet' as const, -}; - -// Under `devstack up`, add a local network keyed by the devstack chain id and make -// it the default — this is the chain the injected dev wallet reports, so dapp-kit -// connects on the same chain. Outside devstack, testnet-only (unchanged). -const networks = - isDevstack && devstackNetwork - ? { [devstackNetwork.key]: { url: devstackNetwork.rpcUrl, network: 'localnet' as const }, testnet } - : { testnet }; - -export const defaultNetwork = isDevstack && devstackNetwork ? devstackNetwork.key : 'testnet'; - -const { networkConfig, useNetworkVariable } = createNetworkConfig(networks); - -export { networkConfig, useNetworkVariable }; diff --git a/chat-app/src/main.tsx b/chat-app/src/main.tsx index 36b7cf7..2ed87cc 100644 --- a/chat-app/src/main.tsx +++ b/chat-app/src/main.tsx @@ -1,28 +1,20 @@ import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { SuiClientProvider, WalletProvider } from '@mysten/dapp-kit'; -import { defaultNetwork, networkConfig } from './lib/network-config'; +import { DAppKitProvider } from '@mysten/dapp-kit-react'; +import { dAppKit } from './lib/dapp-kit'; import { MessagingClientProvider } from './contexts/MessagingClientContext'; import { ErrorBoundary } from './components/ErrorBoundary'; import App from './App'; -import '@mysten/dapp-kit/dist/index.css'; import './index.css'; -const queryClient = new QueryClient(); - createRoot(document.getElementById('root')!).render( - - - - - - - - - - - + + + + + + + , ); diff --git a/chat-app/src/vite-env.d.ts b/chat-app/src/vite-env.d.ts index 8c8a226..4c825aa 100644 --- a/chat-app/src/vite-env.d.ts +++ b/chat-app/src/vite-env.d.ts @@ -37,6 +37,8 @@ declare module 'virtual:devstack-app-config' { packages: Record; network: DevstackSuiNetwork; dappKit: DevstackDappKitConfig; + /** Dev-wallet initializer for `createDAppKit({ walletInitializers })`. */ + walletInitializers: import('@mysten/dapp-kit-core').WalletInitializer[]; } export const devstack: DevstackGenerated | null; } diff --git a/chat-app/vite.config.ts b/chat-app/vite.config.ts index fdb6060..82807fb 100644 --- a/chat-app/vite.config.ts +++ b/chat-app/vite.config.ts @@ -12,23 +12,28 @@ const DEVSTACK_ACTIVE = !!process.env.DEVSTACK_RUNTIME_ROOT || !!process.env.DEV // committed app code can import it unconditionally without ever statically referencing // `@generated` (which only exists when `devstackVitePlugin()` is active). const SHIM_ACTIVE_SOURCE = [ - `import { DevWallet } from '@mysten-incubation/dev-wallet';`, + `import { devWalletInitializer } from '@mysten-incubation/dev-wallet';`, `import { DevstackSignerAdapter, parseDevstackToken } from '@mysten-incubation/dev-wallet/adapters';`, - `import { mountDevWallet } from '@mysten-incubation/dev-wallet/ui';`, `import { sealBindings as s1 } from '@generated/seal/local';`, `import { packages } from '@generated/packages';`, `import { suiNetwork } from '@generated/sui/network';`, `import { dappKitConfig } from '@generated/dapp-kit/config';`, // devstack runs the dev-wallet server (funded accounts; keys stay server-side, signing - // goes through /api/v1/devstack/*). Build the server-delegating adapter, load its accounts, - // register the wallet (so the existing /ConnectButton lists it), and mount - // the floating panel (so connect/sign approvals have a UI). Side effect on shim load. - `const __adapter = new DevstackSignerAdapter({ serverOrigin: dappKitConfig.walletUrl, token: parseDevstackToken(dappKitConfig.pairUrl) });`, - `try { await __adapter.initialize(); } catch (e) { console.error('[devstack] dev-wallet adapter init failed', e); }`, - `const __wallet = new DevWallet({ adapters: [__adapter], networks: { localnet: suiNetwork.rpcUrl } });`, - `__wallet.register();`, - `mountDevWallet(__wallet);`, - `export const devstack = { seal: [s1], packages, network: suiNetwork, dappKit: dappKitConfig };`, + // goes through /api/v1/devstack/*). The initializer goes into dApp Kit's + // `walletInitializers` (see src/lib/dapp-kit.ts), which registers the wallet (so + // ConnectButton lists it), initializes the adapter, and mounts the floating approval UI. + `const walletInitializers = [`, + ` devWalletInitializer({`, + ` adapters: [new DevstackSignerAdapter({ serverOrigin: dappKitConfig.walletUrl, token: parseDevstackToken(dappKitConfig.pairUrl) })],`, + // Accounts come from the devstack wallet server; never create a local one. + ` createInitialAccount: false,`, + ` mountUI: true,`, + // The initializer inherits dApp Kit's networks list in declaration order (testnet + // first); pin the panel to localnet so its balances/faucet target the in-stack node. + ` onWalletCreated: (wallet) => wallet.setActiveNetwork('localnet'),`, + ` }),`, + `];`, + `export const devstack = { seal: [s1], packages, network: suiNetwork, dappKit: dappKitConfig, walletInitializers };`, ].join('\n'); function devstackAppConfigShim(active: boolean): Plugin { From 0715580207a1c17761869107cd8d06e8fc5dca81 Mon Sep 17 00:00:00 2001 From: ioannischtz Date: Fri, 12 Jun 2026 12:19:49 +0300 Subject: [PATCH 2/9] docs(chat-app): update docs for the dapp-kit-react migration - README: new package names, dependency table, gRPC endpoint note for VITE_SUI_RPC_URL. - DEVSTACK.md: shim now hands a walletInitializers entry to createDAppKit; drop the completed migration follow-up note. - SYSTEM_DESIGN.md: provider stack, client-init flow, and session-key ADR updated to the createDAppKit/DAppKitProvider architecture. Co-Authored-By: Claude Fable 5 --- chat-app/README.md | 19 ++++++++++--------- chat-app/docs/DEVSTACK.md | 18 +++++++++--------- chat-app/docs/SYSTEM_DESIGN.md | 28 ++++++++++++---------------- 3 files changed, 31 insertions(+), 34 deletions(-) diff --git a/chat-app/README.md b/chat-app/README.md index 1f4f424..114c528 100644 --- a/chat-app/README.md +++ b/chat-app/README.md @@ -18,10 +18,10 @@ A fully functional chat application built on the Sui Groups SDK ecosystem, showc - **On-chain permission management** — Group membership and fine-grained permissions (send, read, edit, delete, admin) are enforced on-chain via `@mysten/sui-groups`, with the relayer and Seal key servers independently verifying permissions. - **Atomic multi-step transactions** — The SDK's `call` layer composes multiple on-chain operations (e.g., remove member + rotate encryption key) into a single Programmable Transaction Block (PTB), guaranteeing atomicity. - **Encrypted file attachments via Walrus** — Files are encrypted with the group's DEK and stored on [Walrus](https://docs.wal.app) decentralized storage. Metadata (filename, MIME type, size) is encrypted separately. -- **Wallet-based authentication** — No usernames or passwords. Users authenticate with their Sui wallet via `@mysten/dapp-kit`. +- **Wallet-based authentication** — No usernames or passwords. Users authenticate with their Sui wallet via `@mysten/dapp-kit-react`. - **Real-time message delivery** — New messages appear automatically via HTTP polling with the SDK's `subscribe()` API. -**Tech stack:** React 19 · Vite · Tailwind CSS · @mysten/dapp-kit +**Tech stack:** React 19 · Vite · Tailwind CSS · @mysten/dapp-kit-react --- @@ -45,7 +45,7 @@ The app provides working code for common integration patterns: wallet setup, ses | Feature | Description | SDK Method | |---------------------------|-------------------------------------------------------|---------------------------------| -| Wallet connection | Connect/disconnect via @mysten/dapp-kit ConnectButton | `useCurrentAccount()` | +| Wallet connection | Connect/disconnect via @mysten/dapp-kit-react ConnectButton | `useCurrentAccount()` | | SDK client initialization | Create SuiStackMessagingClient from wallet signer | `createSuiStackMessagingClient()` | ### Group Management @@ -117,7 +117,8 @@ The app follows a 3-layer architecture: ### Layer 1 — Browser (React SPA) - React 19 UI with Tailwind CSS styling -- @mysten/dapp-kit for Sui wallet integration (ConnectButton, useCurrentAccount, useSignPersonalMessage) +- @mysten/dapp-kit-react for Sui wallet integration (ConnectButton, useCurrentAccount, `dAppKit.signPersonalMessage`) +- Sui access is gRPC: `VITE_SUI_RPC_URL` must point at a gRPC-Web-capable endpoint (the public fullnodes serve gRPC and JSON-RPC on the same host) - Custom `MessagingClientProvider` context that creates and memoizes the SDK client ### Layer 2 — SDK (in-browser, client-side) @@ -139,7 +140,7 @@ The app follows a 3-layer architecture: ### Key Architectural Decisions - **Group discovery via Sui GraphQL** — query `MemberAdded`/`MemberRemoved` events from the indexer, cached in localStorage for instant sidebar rendering -- **Tier 2 session keys** — dapp-kit's `signPersonalMessage` feeds the SDK callback config +- **Tier 2 session keys** — dApp Kit's `signPersonalMessage` feeds the SDK callback config - **Atomic PTBs via SDK `call` layer** — composed admin operations in single transactions - **Distributed state** — React component state + localStorage caching (no centralized store needed) @@ -153,8 +154,9 @@ The app follows a 3-layer architecture: |-------------------------------|-----------|-------------------------| | `@mysten/sui-stack-messaging` | workspace | E2E encrypted messaging | | `@mysten/sui-groups` | workspace | Permission management | -| `@mysten/dapp-kit` | ^0.x | Wallet adapter | -| `@mysten/sui` | ^2.6 | Sui RPC client | +| `@mysten/dapp-kit-react` | ^2.0 | Wallet adapter (React) | +| `@mysten/dapp-kit-core` | ^1.3 | Wallet adapter core | +| `@mysten/sui` | ^2.17 | Sui gRPC client | | `@mysten/seal` | ^1.1 | Threshold encryption | ### Application Dependencies @@ -164,7 +166,6 @@ The app follows a 3-layer architecture: | React | ^19 | UI framework | | Vite | ^6 | Build tool | | Tailwind CSS | ^4 | Styling | -| TanStack Query | ^5 | Server state management | ### Infrastructure @@ -183,7 +184,7 @@ The app follows a 3-layer architecture: |----------------------|---------------------------------------------------------------------------------------------------------------------------| | Groups SDK source | [permissioned-groups](../ts-sdks/packages/permissioned-groups), [messaging-groups](../ts-sdks/packages/messaging-groups/) | | System Design doc | [SYSTEM_DESIGN.md](./docs/SYSTEM_DESIGN.md) | -| @mysten/dapp-kit | https://sdk.mystenlabs.com/dapp-kit | +| @mysten/dapp-kit-react | https://sdk.mystenlabs.com/dapp-kit | | Sui TypeScript SDK | https://sdk.mystenlabs.com/typescript | | Walrus Documentation | https://docs.wal.app | | Seal Documentation | https://docs.seal.mystenlabs.com | diff --git a/chat-app/docs/DEVSTACK.md b/chat-app/docs/DEVSTACK.md index 1330872..2dbdd38 100644 --- a/chat-app/docs/DEVSTACK.md +++ b/chat-app/docs/DEVSTACK.md @@ -38,10 +38,10 @@ this Vite app. It writes typed config to `src/generated/` (gitignored). | File | What it does | |---|---| | `devstack.config.ts` | The stack definition. Also **materializes patched build sources** under `.devstack/` (see "Publishing" below) — the canonical Move package is never touched. | -| `vite.config.ts` | Adds `devstackVitePlugin()` (dev-only; aliases `@generated`) and a `virtual:devstack-app-config` **shim**. The shim composes the generated config into one `devstack` object AND registers the dev-wallet — both only in the active branch, so committed code never statically imports `@generated` or the incubation packages. | +| `vite.config.ts` | Adds `devstackVitePlugin()` (dev-only; aliases `@generated`) and a `virtual:devstack-app-config` **shim**. The shim composes the generated config into one `devstack` object, including a dev-wallet `walletInitializers` entry — all only in the active branch, so committed code never statically imports `@generated` or the incubation packages. | | `src/lib/devstack-config.ts` | The loader. Reads the shim, derives the local network, builds a **gRPC base client** with MVR overrides, and recovers on-chain ids (see "Recovery"). `isDevstack` is the on/off switch the rest of the app branches on. | | `src/contexts/MessagingClientContext.tsx` | In devstack mode, builds the messaging client from the loader (local RPC + seal serverConfigs + package ids) instead of env; sets `sealThreshold: 1`; **serializes wallet signs**. | -| `src/lib/network-config.ts`, `src/main.tsx` | Add a `localnet` dapp-kit network (so the dev-wallet's `sui:localnet` chain matches) and default to it under devstack. | +| `src/lib/dapp-kit.ts`, `src/main.tsx` | The `createDAppKit` instance. Registers a `localnet` network (so the dev-wallet's `sui:localnet` chain matches), defaults to it under devstack, and passes the shim's `walletInitializers` through. | | `.gitignore` | Ignores `.devstack/` (patched Move sources) and `src/generated/` (regenerated every `up`). | ## Publishing the Move package (the tricky bit) @@ -69,11 +69,13 @@ recovers them from the publish tx at bootstrap via the local GraphQL (newer sche ## Dev-wallet devstack runs the wallet **server** (funded accounts; keys stay server-side) but does **not** register -a wallet in the app. The shim builds a `DevstackSignerAdapter` from the generated `dappKitConfig`, -wraps it in a `DevWallet`, `register()`s it (wallet-standard → dapp-kit's `ConnectButton` lists it), -and `mountDevWallet()`s the approval panel. Because the DevWallet allows only one pending sign, the -context **serializes** sign requests (session-key + tx signing can otherwise overlap, especially under -React StrictMode) to avoid "a signing request is already pending". +a wallet in the app. The shim builds a `DevstackSignerAdapter` from the generated `dappKitConfig` and +wraps it in dev-wallet's `devWalletInitializer({ mountUI: true })`, which `src/lib/dapp-kit.ts` passes +to `createDAppKit({ walletInitializers })` — dApp Kit then registers the wallet (so `ConnectButton` +lists it), initializes the adapter, and mounts the approval panel. Because the DevWallet allows only +one pending sign (and dApp Kit doesn't queue wallet requests), the context still **serializes** sign +requests (session-key + tx signing can otherwise overlap, especially under React StrictMode) to avoid +"a signing request is already pending". ## Seal — one key server @@ -109,5 +111,3 @@ triggers pnpm's deps-purge in its non-TTY child. - Friction log + upstream doc links: [`.claude/skills/spin-up-local-devstack/reference/NOTES.md`](../../.claude/skills/spin-up-local-devstack/reference/NOTES.md) - Runbook: the `spin-up-local-devstack` skill. -- Follow-up: migrating off the deprecated `@mysten/dapp-kit` to `@mysten/dapp-kit-react` (gRPC-native) — - tracked as a separate PR. diff --git a/chat-app/docs/SYSTEM_DESIGN.md b/chat-app/docs/SYSTEM_DESIGN.md index 0b0be00..5932016 100644 --- a/chat-app/docs/SYSTEM_DESIGN.md +++ b/chat-app/docs/SYSTEM_DESIGN.md @@ -33,7 +33,7 @@ The chat application is a React SPA that runs entirely in the browser. It delega graph TB subgraph Browser["Browser (React SPA)"] UI[React UI
Components] - DK["@mysten/dapp-kit
Wallet Provider"] + DK["@mysten/dapp-kit-react
dApp Kit instance"] HOOK[useMessagingClient
Hook] end @@ -115,14 +115,14 @@ The SDK client is initialized once when the wallet connects. The `createSuiStack ```mermaid sequenceDiagram participant User - participant DK as dapp-kit + participant DK as dApp Kit participant Hook as useMessagingClient participant Factory as createSuiStackMessagingClient - participant SUI as SuiClient + participant SUI as SuiGrpcClient User->>DK: Connect Wallet - DK-->>Hook: account.address + signPersonalMessage - Hook->>SUI: new SuiClient({ url: testnetRpc }) + DK-->>Hook: account.address + dAppKit.signPersonalMessage + Hook->>SUI: useCurrentClient() (created by dApp Kit's createClient) Hook->>Factory: createSuiStackMessagingClient(suiClient, config) Note over Factory: config = {
seal: { serverConfigs },
encryption: {
sessionKey: {
address,
onSign: signPersonalMessage
}
},
relayer: { relayerUrl, signer },
attachments: {
storageAdapter: WalrusHttpStorageAdapter
}
} Factory->>Factory: baseClient.$extend(suiGroups, seal) @@ -137,7 +137,7 @@ The factory performs two `$extend` calls, not three. The first call registers bo ```mermaid graph LR - BASE[SuiClient
core RPC] -->|"$extend()"| EXT1[+ groups
+ seal] + BASE[SuiGrpcClient
core gRPC] -->|"$extend()"| EXT1[+ groups
+ seal] EXT1 -->|"$extend()"| EXT2[+ messaging] EXT2 -->|returns| FULL["Extended Client
.core .groups .seal .messaging"] ``` @@ -541,22 +541,18 @@ graph TB subgraph Providers["Provider Stack (top-down, outermost first)"] direction TB P0["StrictMode (React)"] - P1["QueryClientProvider (TanStack Query)
Server state caching"] - P1B["SuiClientProvider (dapp-kit)
Network config: testnet"] - P2["WalletProvider (dapp-kit)
Wallet connection state + autoConnect"] + P2["DAppKitProvider (dapp-kit-react)
createDAppKit instance: networks, clients,
wallet connection state + autoConnect"] P3["MessagingClientProvider (custom)
Extended SDK client + GraphQL client"] P4["ErrorBoundary
Global error catch"] end - P0 --> P1 - P1 --> P1B - P1B --> P2 + P0 --> P2 P2 --> P3 P3 --> P4 subgraph Hooks["Available Hooks"] H1["useCurrentAccount()
Wallet address + publicKey"] - H2["useSignAndExecuteTransaction()
On-chain TX execution"] + H2["useDAppKit()
signAndExecuteTransaction, signPersonalMessage"] H3["useMessagingClient()
client.messaging, client.groups, client.seal"] H4["useGraphQLClient()
SuiGraphQLClient for event queries"] end @@ -745,9 +741,9 @@ type MessagingGroupsPackageConfig = { ```typescript type SessionKeyConfig = - // Tier 1: Signer-based (dapp-kit-next, Keypair, Enoki) -- fully automatic + // Tier 1: Signer-based (Keypair, Enoki, dapp-kit-core CurrentAccountSigner) -- fully automatic | { signer: Signer; ttlMin?: number; refreshBufferMs?: number } - // Tier 2: Callback-based (current dapp-kit) -- SDK creates, consumer signs + // Tier 2: Callback-based (used by this app) -- SDK creates, consumer signs | { address: string; onSign: (message: Uint8Array) => Promise; ttlMin?: number; refreshBufferMs?: number } // Tier 3: Full manual control -- consumer manages entire lifecycle @@ -766,7 +762,7 @@ type SessionKeyConfig = ### ADR-2: Tier 2 session keys (callback-based) -- **Context**: Current `@mysten/dapp-kit` provides `account.address` and `signPersonalMessage()` but does not expose a full `Signer` object. The Tier 1 (signer-based) path requires a `Signer`. +- **Context**: The Tier 1 (signer-based) path requires a `Signer`. `@mysten/dapp-kit-core` exposes a `CurrentAccountSigner`, but the app must serialize wallet sign requests (the devstack dev-wallet and some real wallets reject concurrent signs), and the Tier 2 callback is the natural place to route every sign through that queue. - **Decision**: Use the SDK's Tier 2 session key config: ```typescript { From 119f67a80a06014d6c0ef79bcc71fa0607577e4b Mon Sep 17 00:00:00 2001 From: ioannischtz Date: Fri, 12 Jun 2026 12:19:49 +0300 Subject: [PATCH 3/9] docs(skills): update skills for the dapp-kit-react migration - spin-up-local-devstack: dev-wallet wiring now goes through devWalletInitializer / walletInitializers; refresh the mountDevWallet troubleshooting entries and mark the migration follow-up done. - configure-session-keys / integrate-sui-stack-messaging: fix stale dapp-kit-next / CurrentAccountSigner package references. Co-Authored-By: Claude Fable 5 --- .../skills/configure-session-keys/SKILL.md | 2 +- .../integrate-sui-stack-messaging/SKILL.md | 4 +- .../skills/spin-up-local-devstack/SKILL.md | 8 ++-- .../spin-up-local-devstack/reference/NOTES.md | 45 ++++++++++++------- 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/.claude/skills/configure-session-keys/SKILL.md b/.claude/skills/configure-session-keys/SKILL.md index 1bf095d..593a7db 100644 --- a/.claude/skills/configure-session-keys/SKILL.md +++ b/.claude/skills/configure-session-keys/SKILL.md @@ -22,7 +22,7 @@ encryption: { sessionKey: { signer: keypair } } The SDK derives the address from `signer.toSuiAddress()`, creates a `SessionKey`, and certifies it automatically. Works with: - `Keypair` directly (Node/server-side, scripts). -- `@mysten/dapp-kit`'s `CurrentAccountSigner`. +- `@mysten/dapp-kit-core`'s `CurrentAccountSigner`. - Enoki's `EnokiSigner`. **Use this whenever you have a `Signer` instance.** Zero ceremony. diff --git a/.claude/skills/integrate-sui-stack-messaging/SKILL.md b/.claude/skills/integrate-sui-stack-messaging/SKILL.md index 481c151..8574853 100644 --- a/.claude/skills/integrate-sui-stack-messaging/SKILL.md +++ b/.claude/skills/integrate-sui-stack-messaging/SKILL.md @@ -97,8 +97,8 @@ Three tiers, pick by your auth situation: | Tier | When | What you pass | |---|---|---| -| **1 — signer-based** | dapp-kit-next, Keypair, Enoki, server-side Node with a key | `encryption: { sessionKey: { signer: keypair } }` | -| **2 — callback-based** | current dapp-kit without the Signer abstraction | `encryption: { sessionKey: { address, onSign: async (msg) => signPersonalMessage(msg) } }` | +| **1 — signer-based** | Keypair, Enoki, dapp-kit-core's `CurrentAccountSigner`, server-side Node with a key | `encryption: { sessionKey: { signer: keypair } }` | +| **2 — callback-based** | wallet integrations without a `Signer`, or when you wrap signs (e.g. to serialize them) | `encryption: { sessionKey: { address, onSign: async (msg) => signPersonalMessage(msg) } }` | | **3 — manual** | you already manage `SessionKey` lifecycle externally | `encryption: { sessionKey: { getSessionKey: () => myManaged } }` | Tier-1 is the default. Tier-2 is what most current React-wallet integrations end up needing. Tier-3 is rare — only choose if you have a strong reason to manage the key elsewhere. diff --git a/.claude/skills/spin-up-local-devstack/SKILL.md b/.claude/skills/spin-up-local-devstack/SKILL.md index 67c7045..06bdd03 100644 --- a/.claude/skills/spin-up-local-devstack/SKILL.md +++ b/.claude/skills/spin-up-local-devstack/SKILL.md @@ -58,8 +58,9 @@ The load-bearing, non-obvious bits (all handled in `chat-app/devstack.config.ts` - **Seal: one server, `sealThreshold: 1`.** Two local-keygen servers collide in codegen in 0.1.1. - **Dev-wallet: register it yourself.** `devstackVitePlugin()` only aliases `@generated` — it does NOT inject a wallet. devstack runs the wallet *server* (funded accounts); the app builds a - `DevstackSignerAdapter` from `@generated/dapp-kit/config`, `register()`s a `DevWallet`, and - `mountDevWallet()`s the panel. Serialize sign calls (the DevWallet allows one pending sign). + `DevstackSignerAdapter` from `@generated/dapp-kit/config` and hands it to dApp Kit via + `devWalletInitializer({ mountUI: true })` in `createDAppKit({ walletInitializers })`. + Serialize sign calls (the DevWallet allows one pending sign; dApp Kit doesn't queue). ## Relayer @@ -93,7 +94,8 @@ experiment now, add `walrus({ local })` + `walCoin` to `devstack.config.ts` and - **Reset:** `devstack wipe --yes`; hard Docker reset `docker rm -f $(docker ps -aq --filter name=devstack)` (`devstack prune` only removes idle groups). Re-emit codegen: `devstack apply`. - **"A signing request is already pending"** = concurrent signs vs the DevWallet's one-pending model → serialize app-side. -- **Connect hangs at "Confirm connection in the wallet"** = no `mountDevWallet()`. +- **Connect hangs at "Confirm connection in the wallet"** = no approval UI — `mountUI: true` missing + in `devWalletInitializer(...)`, or `walletInitializers` not passed to `createDAppKit`. - **Relayer "grpc-status header missing, HTTP 400"** = gRPC through Traefik → use the host-published port. ## Cross-links diff --git a/.claude/skills/spin-up-local-devstack/reference/NOTES.md b/.claude/skills/spin-up-local-devstack/reference/NOTES.md index ae834fc..75f2391 100644 --- a/.claude/skills/spin-up-local-devstack/reference/NOTES.md +++ b/.claude/skills/spin-up-local-devstack/reference/NOTES.md @@ -76,25 +76,36 @@ two-server topology). `serverConfigs` comes from `@generated/seal/local.ts`. (`devstack/dist/build-integrations/vite/index.mjs`). It does **not** inject a wallet. devstack's `wallet({ accounts })` runs a server (`http://…:6173`, funded accounts, keys stay server-side; signs over `/api/v1/devstack/*`) and emits `@generated/dapp-kit/config.ts` (`walletUrl`, `pairUrl#token`, -`chain: sui:local` — sensitive, gitignored). The browser app wires it up itself: +`chain: sui:local` — sensitive, gitignored). The browser app wires it up itself — with +`@mysten/dapp-kit-react`, via dev-wallet's first-class initializer: ```ts -import { DevWallet } from '@mysten-incubation/dev-wallet'; +import { devWalletInitializer } from '@mysten-incubation/dev-wallet'; import { DevstackSignerAdapter, parseDevstackToken } from '@mysten-incubation/dev-wallet/adapters'; -import { mountDevWallet } from '@mysten-incubation/dev-wallet/ui'; -const a = new DevstackSignerAdapter({ serverOrigin: dappKitConfig.walletUrl, token: parseDevstackToken(dappKitConfig.pairUrl) }); -await a.initialize(); // fetch the funded accounts from the server -const w = new DevWallet({ adapters: [a], networks: { localnet: suiNetwork.rpcUrl } }); -w.register(); // wallet-standard -> dapp-kit's ConnectButton lists it -mountDevWallet(w); // floating panel = where connect/sign approvals happen +const dAppKit = createDAppKit({ + networks: ['localnet'], + createClient: (network) => new SuiGrpcClient({ network, baseUrl: suiNetwork.rpcUrl }), + walletInitializers: [ + devWalletInitializer({ + adapters: [new DevstackSignerAdapter({ serverOrigin: dappKitConfig.walletUrl, token: parseDevstackToken(dappKitConfig.pairUrl) })], + createInitialAccount: false, // accounts come from the devstack wallet server + mountUI: true, // floating panel = where connect/sign approvals happen + }), + ], +}); +// dApp Kit registers the wallet (ConnectButton lists it) and initializes the adapter. ``` +(Pre-migration, on the deprecated `@mysten/dapp-kit`, this was manual: `new DevWallet({ adapters })` + +`wallet.register()` + `mountDevWallet(wallet)` — the initializer replaces all three.) + Gotchas hit: - **`DevWalletClient` (popup) is the wrong client** — that's for a standalone served wallet UI; the devstack server is an HTTP signing API, consumed via `DevstackSignerAdapter`. - **`createDevstackAdapterFromManifest` wants the nested runtime `Manifest`**, not the flat generated `dappKitConfig` — use `DevstackSignerAdapter` + `parseDevstackToken` directly. -- **Without `mountDevWallet`, connect hangs** at "Confirm connection in the wallet" — no UI to confirm in. +- **Without `mountUI: true` (in `devWalletInitializer`), connect hangs** at "Confirm connection in the + wallet" — no UI to confirm in. - **The DevWallet allows only one pending sign** → concurrent session-key + tx signs throw "a signing request is already pending" (`dev-wallet/dist/wallet/dev-wallet.mjs`). Real wallets queue; the DevWallet doesn't. Fix: serialize sign calls app-side (a promise chain around `signPersonalMessage` @@ -130,7 +141,7 @@ queries) may need the same schema port if exercised on localnet. | `SealError`/`register` "object … unavailable" | two seal servers on one signer | one server, dedicated signer (§2) | | `CodegenEmitterCollision` | two Seal package bindings | one Seal server (§2) | | `HostServiceAcquireError`/`exit` (`ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY`) | `pnpm exec vite` hit pnpm-v11 deps-purge in a non-TTY child | run vite via `node_modules/.bin/vite` in the host-service `script` | -| connect hangs "Confirm connection in the wallet" | no wallet UI mounted | `mountDevWallet(wallet)` (§3) | +| connect hangs "Confirm connection in the wallet" | no wallet UI mounted | `devWalletInitializer({ mountUI: true })` in `walletInitializers` (§3) | | "A signing request is already pending" | DevWallet one-pending-sign + concurrent signs | serialize signs app-side (§3) | | relayer "grpc-status header missing, HTTP 400" | gRPC through Traefik | point at the host-published validator port (§4) | @@ -145,11 +156,11 @@ queries) may need the same schema port if exercised on localnet. - Logs: `devstack up --renderer plain`. Reset: `devstack wipe --yes`. `devstack prune --yes` only removes *idle* groups (a live validator isn't idle). Re-emit codegen: `devstack apply`. -## 8. Follow-up: migrate the chat-app to `@mysten/dapp-kit-react` +## 8. dapp-kit migration (done) -The chat-app is on the **deprecated** `@mysten/dapp-kit` (JSON-RPC-only, never gets gRPC/GraphQL). -`@mysten/dapp-kit-react` (sui-2.0) is the path forward and is gRPC-native. Browser-gRPC-on-localnet is -**proven working** here (the messaging base client is already `SuiGrpcClient`), so the migration's main -unknown is retired. The dev-wallet wiring is identical on both stacks (same `DevstackSignerAdapter`), -so migration is a separate, deliberate PR — see the cost-benefit (workaround-now / migrate-next). -Guide: . +The chat-app now runs on `@mysten/dapp-kit-react` (sui-2.0, gRPC-native): `createDAppKit` + +`DAppKitProvider`, `useCurrentClient()` as the base client source, imperative +`dAppKit.signAndExecuteTransaction` / `signPersonalMessage` (no mutation hooks), and the dev-wallet +registered through `walletInitializers` (section 3). The sign-request serialization stays — dApp Kit +does not queue wallet requests and the DevWallet still allows only one pending sign. +Guide used: . From 4c04e45489f814b7d0b2301ed155896aabbc8922 Mon Sep 17 00:00:00 2001 From: ioannischtz Date: Fri, 12 Jun 2026 12:47:31 +0300 Subject: [PATCH 4/9] refactor(chat-app): Tier-1 session keys via queued CurrentAccountSigner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace the hand-rolled DappKitSigner + onSign callback with dApp Kit's CurrentAccountSigner, subclassed as QueuedCurrentAccountSigner to serialize personal-message signs (dApp Kit doesn't queue wallet requests; the devstack dev-wallet rejects concurrent signs). - Switch the SDK session-key config from Tier 2 (address + onSign) to Tier 1 ({ signer }) — Seal certifies the session key through the queued signer, so the ceremony and relayer request signing share one queue. - Drop the queuedSign promise-chain plumbing from MessagingClientContext. Verified on devstack localnet (send + fresh-session decrypt) and testnet (Tier-1 create -> send -> fresh-client decrypt, digest 32fGQrMpszmSHVM9...). Co-Authored-By: Claude Fable 5 --- .../src/contexts/MessagingClientContext.tsx | 52 ++++------- chat-app/src/lib/dapp-kit-signer.ts | 86 ------------------- chat-app/src/lib/queued-signer.ts | 31 +++++++ 3 files changed, 47 insertions(+), 122 deletions(-) delete mode 100644 chat-app/src/lib/dapp-kit-signer.ts create mode 100644 chat-app/src/lib/queued-signer.ts diff --git a/chat-app/src/contexts/MessagingClientContext.tsx b/chat-app/src/contexts/MessagingClientContext.tsx index f052857..f4e9336 100644 --- a/chat-app/src/contexts/MessagingClientContext.tsx +++ b/chat-app/src/contexts/MessagingClientContext.tsx @@ -1,4 +1,4 @@ -import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'; +import { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from 'react'; import { useCurrentAccount, useCurrentClient, @@ -6,7 +6,7 @@ import { } from '@mysten/dapp-kit-react'; import { createSuiStackMessagingClient, WalrusHttpStorageAdapter } from '@mysten/sui-stack-messaging'; import { SuiGraphQLClient } from '@mysten/sui/graphql'; -import { DappKitSigner } from '../lib/dapp-kit-signer'; +import { QueuedCurrentAccountSigner } from '../lib/queued-signer'; import { devstackNetwork, isDevstack, @@ -93,17 +93,11 @@ export function MessagingClientProvider({ const suiClient = useCurrentClient(); const dAppKit = useDAppKit(); - // Serialize wallet sign requests. The Seal session-key flow and tx signing can each - // trigger a personal-message sign, and they can overlap (more so under React StrictMode). - // dApp Kit does not queue wallet requests, and the devstack dev-wallet — like some real - // wallets — rejects a second concurrent sign with "a signing request is already pending"; - // queueing keeps at most one in flight. - const signChain = useRef>(Promise.resolve()); - const queuedSign = useCallback((args: { message: Uint8Array }): Promise<{ signature: string }> => { - const run = signChain.current.then(() => dAppKit.signPersonalMessage(args)); - signChain.current = run.catch(() => undefined); - return run; - }, [dAppKit]); + // Signer over the connected account. The queued subclass serializes + // personal-message signs — the Seal session-key ceremony and relayer request + // signing can overlap (more so under React StrictMode), and the devstack + // dev-wallet rejects a second concurrent sign. + const signer = useMemo(() => new QueuedCurrentAccountSigner(dAppKit), [dAppKit]); // Local devstack: resolve the generated config (local RPC + seal + package ids) // and recover the bundled sui_groups id once, independent of the wallet. @@ -121,18 +115,10 @@ export function MessagingClientProvider({ }; }, []); - const { client, signer } = useMemo(() => { - if (!account) return { client: null, signer: null }; + const client = useMemo(() => { + if (!account) return null; // In devstack mode, wait for the local config before building the client. - if (isDevstack && !devstackCfg) return { client: null, signer: null }; - - const signer = new DappKitSigner({ - address: account.address, - publicKeyBytes: account.publicKey - ? new Uint8Array(account.publicKey) - : undefined, - signPersonalMessage: (args) => queuedSign({ message: args.message }), - }); + if (isDevstack && !devstackCfg) return null; // devstack mode sources the base client (local RPC + MVR overrides), seal // server configs and package ids from the generated config; otherwise env. @@ -155,18 +141,14 @@ export function MessagingClientProvider({ } : undefined; - const client = createSuiStackMessagingClient(baseClient, { + return createSuiStackMessagingClient(baseClient, { seal: { serverConfigs: sealServerConfigs, }, encryption: { - sessionKey: { - address: account.address, - onSign: async (message: Uint8Array) => { - const { signature } = await queuedSign({ message }); - return signature; - }, - }, + // Tier 1 (signer-based): the SDK creates and certifies session keys via + // signer.signPersonalMessage — serialized by QueuedCurrentAccountSigner. + sessionKey: { signer }, // Local devstack runs a single Seal key server; match the threshold to it // (the default of 2 assumes the testnet two-server topology). sealThreshold: devstackCfg ? devstackCfg.sealServerConfigs.length : undefined, @@ -178,12 +160,10 @@ export function MessagingClientProvider({ }, attachments, }); - - return { client, signer }; - }, [account, suiClient, devstackCfg, queuedSign]); + }, [account, suiClient, devstackCfg, signer]); const value = useMemo( - () => ({ client, signer, graphqlClient }), + () => ({ client, signer: client ? signer : null, graphqlClient }), [client, signer], ); diff --git a/chat-app/src/lib/dapp-kit-signer.ts b/chat-app/src/lib/dapp-kit-signer.ts deleted file mode 100644 index 3bffc6f..0000000 --- a/chat-app/src/lib/dapp-kit-signer.ts +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Adapter that wraps dapp-kit's signPersonalMessage into a Signer-compatible object - * for use with the messaging SDK's relayer transport. - * - * Supports all Sui wallet types (Ed25519, Secp256k1, Secp256r1, zkLogin, multisig) - * by lazily extracting the public key from the first signature when the wallet - * doesn't expose publicKey upfront. - */ -import { Signer, parseSerializedSignature } from '@mysten/sui/cryptography'; -import type { PublicKey, SignatureScheme } from '@mysten/sui/cryptography'; -import { publicKeyFromRawBytes, publicKeyFromSuiBytes } from '@mysten/sui/verify'; -import { toBase64 } from '@mysten/sui/utils'; - -export type SignPersonalMessageFn = (args: { - message: Uint8Array; -}) => Promise<{ signature: string }>; - -export class DappKitSigner extends Signer { - readonly #address: string; - #publicKey: PublicKey | null; - readonly #signPersonalMessage: SignPersonalMessageFn; - - constructor(opts: { - address: string; - publicKeyBytes?: Uint8Array; - signPersonalMessage: SignPersonalMessageFn; - }) { - super(); - this.#address = opts.address; - this.#publicKey = - opts.publicKeyBytes?.length - ? publicKeyFromSuiBytes(opts.publicKeyBytes) - : null; - this.#signPersonalMessage = opts.signPersonalMessage; - } - - async sign(_bytes: Uint8Array): Promise> { - throw new Error( - 'DappKitSigner.sign() is not supported. Use signPersonalMessage() instead.', - ); - } - - override async signPersonalMessage( - bytes: Uint8Array, - ): Promise<{ bytes: string; signature: string }> { - const { signature } = await this.#signPersonalMessage({ - message: bytes, - }); - - // Extract public key from the signature if not already known - if (!this.#publicKey) { - const parsed = parseSerializedSignature(signature); - if ('publicKey' in parsed && parsed.publicKey) { - this.#publicKey = publicKeyFromRawBytes( - parsed.signatureScheme, - parsed.publicKey, - ); - } - } - - return { bytes: toBase64(bytes), signature }; - } - - getKeyScheme(): SignatureScheme { - if (!this.#publicKey) { - return 'ED25519'; // default until first signature resolves it - } - const flag = this.#publicKey.flag(); - if (flag === 0x00) return 'ED25519'; - if (flag === 0x01) return 'Secp256k1'; - return 'Secp256r1'; - } - - getPublicKey(): PublicKey { - if (!this.#publicKey) { - throw new Error( - 'Public key not yet available. It will be resolved after the first signPersonalMessage call.', - ); - } - return this.#publicKey; - } - - override toSuiAddress(): string { - return this.#address; - } -} diff --git a/chat-app/src/lib/queued-signer.ts b/chat-app/src/lib/queued-signer.ts new file mode 100644 index 0000000..dd6829d --- /dev/null +++ b/chat-app/src/lib/queued-signer.ts @@ -0,0 +1,31 @@ +import { + CurrentAccountSigner, + type DAppKit, + type RegisteredDAppKit, +} from '@mysten/dapp-kit-core'; + +/** + * CurrentAccountSigner that serializes personal-message signs. dApp Kit does not + * queue wallet requests, and the devstack dev-wallet — like some real wallets — + * rejects a second concurrent sign with "a signing request is already pending". + * Both the Seal session-key ceremony (SessionKey.getCertificate) and relayer + * request signing go through this signer, so chaining here keeps at most one + * sign in flight. + */ +export class QueuedCurrentAccountSigner extends CurrentAccountSigner { + #chain: Promise = Promise.resolve(); + + // Upstream types the parameter as bare `DAppKit`, whose default generics fix + // `networks` to `[]` — accept the app's registered instance type instead. + constructor(dAppKit: RegisteredDAppKit) { + super(dAppKit as unknown as DAppKit); + } + + override signPersonalMessage( + bytes: Uint8Array, + ): ReturnType { + const run = this.#chain.then(() => super.signPersonalMessage(bytes)); + this.#chain = run.catch(() => undefined); + return run; + } +} From f1708dc668ea9e6bd1ad49873e82d5aa2a2e81f3 Mon Sep 17 00:00:00 2001 From: ioannischtz Date: Fri, 12 Jun 2026 12:47:51 +0300 Subject: [PATCH 5/9] docs: describe the queued CurrentAccountSigner session-key setup - chat-app README / DEVSTACK / SYSTEM_DESIGN: Tier-1 signer-based session keys, queued-signer file map entry, ADR-2 rewritten for the queued CurrentAccountSigner decision. - Skills: point the sign-serialization guidance at the queued-signer pattern and the worked example in chat-app/src/lib/queued-signer.ts. Co-Authored-By: Claude Fable 5 --- .../skills/configure-session-keys/SKILL.md | 4 ++++ .../integrate-sui-stack-messaging/SKILL.md | 2 +- .../spin-up-local-devstack/reference/NOTES.md | 7 +++--- chat-app/README.md | 2 +- chat-app/docs/DEVSTACK.md | 10 ++++---- chat-app/docs/SYSTEM_DESIGN.md | 23 ++++++++----------- 6 files changed, 26 insertions(+), 22 deletions(-) diff --git a/.claude/skills/configure-session-keys/SKILL.md b/.claude/skills/configure-session-keys/SKILL.md index 593a7db..1799630 100644 --- a/.claude/skills/configure-session-keys/SKILL.md +++ b/.claude/skills/configure-session-keys/SKILL.md @@ -27,6 +27,10 @@ The SDK derives the address from `signer.toSuiAddress()`, creates a `SessionKey` **Use this whenever you have a `Signer` instance.** Zero ceremony. +If the wallet rejects concurrent sign requests (the dev-wallet does; dApp Kit does not queue), +subclass `CurrentAccountSigner` and serialize `signPersonalMessage` with a promise chain — worked +example: `chat-app/src/lib/queued-signer.ts`. + ### Tier 2 — callback-based ```ts diff --git a/.claude/skills/integrate-sui-stack-messaging/SKILL.md b/.claude/skills/integrate-sui-stack-messaging/SKILL.md index 8574853..c2dd482 100644 --- a/.claude/skills/integrate-sui-stack-messaging/SKILL.md +++ b/.claude/skills/integrate-sui-stack-messaging/SKILL.md @@ -98,7 +98,7 @@ Three tiers, pick by your auth situation: | Tier | When | What you pass | |---|---|---| | **1 — signer-based** | Keypair, Enoki, dapp-kit-core's `CurrentAccountSigner`, server-side Node with a key | `encryption: { sessionKey: { signer: keypair } }` | -| **2 — callback-based** | wallet integrations without a `Signer`, or when you wrap signs (e.g. to serialize them) | `encryption: { sessionKey: { address, onSign: async (msg) => signPersonalMessage(msg) } }` | +| **2 — callback-based** | wallet integrations without a `Signer` abstraction | `encryption: { sessionKey: { address, onSign: async (msg) => signPersonalMessage(msg) } }` | | **3 — manual** | you already manage `SessionKey` lifecycle externally | `encryption: { sessionKey: { getSessionKey: () => myManaged } }` | Tier-1 is the default. Tier-2 is what most current React-wallet integrations end up needing. Tier-3 is rare — only choose if you have a strong reason to manage the key elsewhere. diff --git a/.claude/skills/spin-up-local-devstack/reference/NOTES.md b/.claude/skills/spin-up-local-devstack/reference/NOTES.md index 75f2391..80945ea 100644 --- a/.claude/skills/spin-up-local-devstack/reference/NOTES.md +++ b/.claude/skills/spin-up-local-devstack/reference/NOTES.md @@ -108,8 +108,9 @@ Gotchas hit: wallet" — no UI to confirm in. - **The DevWallet allows only one pending sign** → concurrent session-key + tx signs throw "a signing request is already pending" (`dev-wallet/dist/wallet/dev-wallet.mjs`). Real wallets queue; the - DevWallet doesn't. Fix: serialize sign calls app-side (a promise chain around `signPersonalMessage` - in `MessagingClientContext.tsx`). React StrictMode double-render makes the race more likely. + DevWallet doesn't. dApp Kit doesn't queue either. Fix: serialize sign calls app-side — the chat-app + subclasses `CurrentAccountSigner` with a promise chain around `signPersonalMessage` + (`src/lib/queued-signer.ts`). React StrictMode double-render makes the race more likely. ## 4. Relayer on devstack — use the host-published port, not the routed one @@ -142,7 +143,7 @@ queries) may need the same schema port if exercised on localnet. | `CodegenEmitterCollision` | two Seal package bindings | one Seal server (§2) | | `HostServiceAcquireError`/`exit` (`ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY`) | `pnpm exec vite` hit pnpm-v11 deps-purge in a non-TTY child | run vite via `node_modules/.bin/vite` in the host-service `script` | | connect hangs "Confirm connection in the wallet" | no wallet UI mounted | `devWalletInitializer({ mountUI: true })` in `walletInitializers` (§3) | -| "A signing request is already pending" | DevWallet one-pending-sign + concurrent signs | serialize signs app-side (§3) | +| "A signing request is already pending" | DevWallet one-pending-sign + concurrent signs | queued `CurrentAccountSigner` subclass (§3) | | relayer "grpc-status header missing, HTTP 400" | gRPC through Traefik | point at the host-published validator port (§4) | ## 7. Operational diff --git a/chat-app/README.md b/chat-app/README.md index 114c528..94ab039 100644 --- a/chat-app/README.md +++ b/chat-app/README.md @@ -140,7 +140,7 @@ The app follows a 3-layer architecture: ### Key Architectural Decisions - **Group discovery via Sui GraphQL** — query `MemberAdded`/`MemberRemoved` events from the indexer, cached in localStorage for instant sidebar rendering -- **Tier 2 session keys** — dApp Kit's `signPersonalMessage` feeds the SDK callback config +- **Tier 1 session keys** — a queued `CurrentAccountSigner` subclass feeds the SDK's signer-based config - **Atomic PTBs via SDK `call` layer** — composed admin operations in single transactions - **Distributed state** — React component state + localStorage caching (no centralized store needed) diff --git a/chat-app/docs/DEVSTACK.md b/chat-app/docs/DEVSTACK.md index 2dbdd38..cd83031 100644 --- a/chat-app/docs/DEVSTACK.md +++ b/chat-app/docs/DEVSTACK.md @@ -40,7 +40,8 @@ this Vite app. It writes typed config to `src/generated/` (gitignored). | `devstack.config.ts` | The stack definition. Also **materializes patched build sources** under `.devstack/` (see "Publishing" below) — the canonical Move package is never touched. | | `vite.config.ts` | Adds `devstackVitePlugin()` (dev-only; aliases `@generated`) and a `virtual:devstack-app-config` **shim**. The shim composes the generated config into one `devstack` object, including a dev-wallet `walletInitializers` entry — all only in the active branch, so committed code never statically imports `@generated` or the incubation packages. | | `src/lib/devstack-config.ts` | The loader. Reads the shim, derives the local network, builds a **gRPC base client** with MVR overrides, and recovers on-chain ids (see "Recovery"). `isDevstack` is the on/off switch the rest of the app branches on. | -| `src/contexts/MessagingClientContext.tsx` | In devstack mode, builds the messaging client from the loader (local RPC + seal serverConfigs + package ids) instead of env; sets `sealThreshold: 1`; **serializes wallet signs**. | +| `src/contexts/MessagingClientContext.tsx` | In devstack mode, builds the messaging client from the loader (local RPC + seal serverConfigs + package ids) instead of env; sets `sealThreshold: 1`. | +| `src/lib/queued-signer.ts` | `QueuedCurrentAccountSigner` — dApp Kit's `CurrentAccountSigner` with **serialized personal-message signs** (the DevWallet allows one pending sign). | | `src/lib/dapp-kit.ts`, `src/main.tsx` | The `createDAppKit` instance. Registers a `localnet` network (so the dev-wallet's `sui:localnet` chain matches), defaults to it under devstack, and passes the shim's `walletInitializers` through. | | `.gitignore` | Ignores `.devstack/` (patched Move sources) and `src/generated/` (regenerated every `up`). | @@ -73,9 +74,10 @@ a wallet in the app. The shim builds a `DevstackSignerAdapter` from the generate wraps it in dev-wallet's `devWalletInitializer({ mountUI: true })`, which `src/lib/dapp-kit.ts` passes to `createDAppKit({ walletInitializers })` — dApp Kit then registers the wallet (so `ConnectButton` lists it), initializes the adapter, and mounts the approval panel. Because the DevWallet allows only -one pending sign (and dApp Kit doesn't queue wallet requests), the context still **serializes** sign -requests (session-key + tx signing can otherwise overlap, especially under React StrictMode) to avoid -"a signing request is already pending". +one pending sign (and dApp Kit doesn't queue wallet requests), the app's signer +(`QueuedCurrentAccountSigner`, `src/lib/queued-signer.ts`) **serializes** personal-message signs — +the Seal session-key ceremony and relayer request signing can otherwise overlap, especially under +React StrictMode, throwing "a signing request is already pending". ## Seal — one key server diff --git a/chat-app/docs/SYSTEM_DESIGN.md b/chat-app/docs/SYSTEM_DESIGN.md index 5932016..0a3dfa7 100644 --- a/chat-app/docs/SYSTEM_DESIGN.md +++ b/chat-app/docs/SYSTEM_DESIGN.md @@ -124,11 +124,11 @@ sequenceDiagram DK-->>Hook: account.address + dAppKit.signPersonalMessage Hook->>SUI: useCurrentClient() (created by dApp Kit's createClient) Hook->>Factory: createSuiStackMessagingClient(suiClient, config) - Note over Factory: config = {
seal: { serverConfigs },
encryption: {
sessionKey: {
address,
onSign: signPersonalMessage
}
},
relayer: { relayerUrl, signer },
attachments: {
storageAdapter: WalrusHttpStorageAdapter
}
} + Note over Factory: config = {
seal: { serverConfigs },
encryption: {
sessionKey: { signer }
},
relayer: { relayerUrl, signer },
attachments: {
storageAdapter: WalrusHttpStorageAdapter
}
} Factory->>Factory: baseClient.$extend(suiGroups, seal) Factory->>Factory: result.$extend(suiStackMessaging) Factory-->>Hook: Extended client (with .groups, .seal, .messaging) - Note over Hook: Client ready. First operation
triggers SessionKey.create()
via Tier 2 callback flow + Note over Hook: Client ready. First operation
triggers SessionKey.create()
via Tier 1 signer flow ``` **Extension composition detail:** @@ -741,9 +741,9 @@ type MessagingGroupsPackageConfig = { ```typescript type SessionKeyConfig = - // Tier 1: Signer-based (Keypair, Enoki, dapp-kit-core CurrentAccountSigner) -- fully automatic + // Tier 1: Signer-based (used by this app via a queued CurrentAccountSigner) -- fully automatic | { signer: Signer; ttlMin?: number; refreshBufferMs?: number } - // Tier 2: Callback-based (used by this app) -- SDK creates, consumer signs + // Tier 2: Callback-based -- SDK creates, consumer signs | { address: string; onSign: (message: Uint8Array) => Promise; ttlMin?: number; refreshBufferMs?: number } // Tier 3: Full manual control -- consumer manages entire lifecycle @@ -760,18 +760,15 @@ type SessionKeyConfig = - **Decision**: Use `SuiGraphQLClient` to query `MemberAdded` and `MemberRemoved` events filtered by the messaging package's event type. Extract `member` and `group_id` fields from each event, filter client-side for the connected address, and compute net membership (added minus removed). Cache results in localStorage for instant sidebar rendering on subsequent loads. Supplement with immediate cache updates on group creation and join-link flows. - **Consequences**: Group discovery works across devices (any client can query the indexer). Client-side filtering is required since `EventFilter` doesn't support payload field filtering — acceptable at testnet scale. localStorage serves as a performance cache, not the source of truth. Background refresh keeps the list current when external admins add the user to new groups. -### ADR-2: Tier 2 session keys (callback-based) +### ADR-2: Tier 1 session keys via a queued `CurrentAccountSigner` -- **Context**: The Tier 1 (signer-based) path requires a `Signer`. `@mysten/dapp-kit-core` exposes a `CurrentAccountSigner`, but the app must serialize wallet sign requests (the devstack dev-wallet and some real wallets reject concurrent signs), and the Tier 2 callback is the natural place to route every sign through that queue. -- **Decision**: Use the SDK's Tier 2 session key config: +- **Context**: The Tier 1 (signer-based) path requires a `Signer`. `@mysten/dapp-kit-core` exposes `CurrentAccountSigner`, a `Signer` over the connected wallet account. The app must still serialize wallet sign requests — dApp Kit does not queue them and the devstack dev-wallet (like some real wallets) rejects a second concurrent sign. Both the Seal session-key ceremony (`SessionKey.getCertificate()` → `signer.signPersonalMessage()`) and relayer request signing run through the same signer instance, so the signer itself is the natural place for the queue. +- **Decision**: Subclass `CurrentAccountSigner` as `QueuedCurrentAccountSigner` (`src/lib/queued-signer.ts`), overriding `signPersonalMessage` with a promise chain that keeps at most one sign in flight, and pass it as the SDK's Tier 1 config: ```typescript - { - address: account.address, - onSign: (msg) => signPersonalMessage({ message: msg }) - } + encryption: { sessionKey: { signer: queuedCurrentAccountSigner } } ``` - The SDK calls `SessionKey.create()`, obtains the personal message via `getPersonalMessage()`, invokes the callback, and completes the ceremony via `setPersonalMessageSignature()`. -- **Consequences**: Wallet popup appears on the first encrypt/decrypt operation (session key signing). The default TTL of 10 minutes (configurable via `ttlMin`) and refresh buffer of 60 seconds means the popup reappears infrequently during active use. + The SDK calls `SessionKey.create({ signer })` and the Seal SDK certifies the key by calling `signer.signPersonalMessage()` internally — which routes through the queue. +- **Consequences**: Wallet popup appears on the first encrypt/decrypt operation (session key signing). The default TTL of 10 minutes (configurable via `ttlMin`) and refresh buffer of 60 seconds means the popup reappears infrequently during active use. The same signer serves the relayer transport, so its signs are serialized too. Transaction signing (`dAppKit.signAndExecuteTransaction` in components) is not routed through the queue — same coverage as the previous callback-based queue. ### ADR-3: Atomic PTB for admin actions From 790cce39f64ddc9fb718fde0cf002c6862ff6776 Mon Sep 17 00:00:00 2001 From: ioannischtz Date: Fri, 12 Jun 2026 12:47:52 +0300 Subject: [PATCH 6/9] docs(sdk): migrate examples off the deprecated @mysten/dapp-kit - Examples.md: tx.* wallet integration now uses useDAppKit() + signAndExecuteTransaction, with a note on the $kind result union. - Setup.md / Encryption.md: CurrentAccountSigner is @mysten/dapp-kit-core's (was attributed to dapp-kit / dapp-kit-next). - APIRef.md / Setup.md: neutral "dApp Kit" wording for tx.* signing. Co-Authored-By: Claude Fable 5 --- docs/sui-stack-messaging/APIRef.md | 2 +- docs/sui-stack-messaging/Encryption.md | 4 ++-- docs/sui-stack-messaging/Examples.md | 23 ++++++++++++++--------- docs/sui-stack-messaging/Setup.md | 4 ++-- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/docs/sui-stack-messaging/APIRef.md b/docs/sui-stack-messaging/APIRef.md index 0a0aac3..1c5dc0f 100644 --- a/docs/sui-stack-messaging/APIRef.md +++ b/docs/sui-stack-messaging/APIRef.md @@ -508,7 +508,7 @@ const humanMembers = allMembers.filter(m => !system.has(m.address)); ## Transaction builders (`tx.*`) -Return `Transaction` objects ready for signing. Same parameters as imperative methods (minus `signer`). Use these when you need to inspect or modify the transaction before signing (for example, with dapp-kit's `signAndExecuteTransaction`). +Return `Transaction` objects ready for signing. Same parameters as imperative methods (minus `signer`). Use these when you need to inspect or modify the transaction before signing (for example, with dApp Kit's `signAndExecuteTransaction`). ```typescript const tx = client.messaging.tx.createAndShareGroup({ diff --git a/docs/sui-stack-messaging/Encryption.md b/docs/sui-stack-messaging/Encryption.md index 8f9368b..f93c99a 100644 --- a/docs/sui-stack-messaging/Encryption.md +++ b/docs/sui-stack-messaging/Encryption.md @@ -82,7 +82,7 @@ Seal operations require a **session key**, a short-lived key that authorizes dec encryption: { sessionKey: { signer: keypair } } ``` -The SDK calls `SessionKey.create()` with the signer and handles certification automatically. Works with dapp-kit-next `CurrentAccountSigner`, `Keypair`, and Enoki. +The SDK calls `SessionKey.create()` with the signer and handles certification automatically. Works with `@mysten/dapp-kit-core`'s `CurrentAccountSigner`, `Keypair`, and Enoki. **Tier 2: Callback-based:** @@ -95,7 +95,7 @@ encryption: { } ``` -The SDK creates a session key, then calls `onSign()` with the personal message bytes for wallet signing. For current dapp-kit without the Signer abstraction. +The SDK creates a session key, then calls `onSign()` with the personal message bytes for wallet signing. For wallet integrations without a `Signer` abstraction, or when you want to wrap every sign in custom logic. **Tier 3: Manual:** diff --git a/docs/sui-stack-messaging/Examples.md b/docs/sui-stack-messaging/Examples.md index 373f1ee..a2a5c1b 100644 --- a/docs/sui-stack-messaging/Examples.md +++ b/docs/sui-stack-messaging/Examples.md @@ -162,13 +162,15 @@ See [Security](./Security.md) for why `removeMembersAndRotateKey()` is recommend ## Using `tx.*` with dApp Kit -When integrating with `@mysten/dapp-kit`, use `tx.*` methods to get a `Transaction` object for the wallet to sign: +When integrating with `@mysten/dapp-kit-react`, use `tx.*` methods to get a `Transaction` object for the wallet to sign: ```typescript -// In a React component using dapp-kit -const { mutate: signAndExecute } = useSignAndExecuteTransaction(); +// In a React component using dapp-kit-react +import { useDAppKit } from '@mysten/dapp-kit-react'; -const handleCreateGroup = () => { +const dAppKit = useDAppKit(); + +const handleCreateGroup = async () => { const uuid = crypto.randomUUID(); const tx = client.messaging.tx.createAndShareGroup({ @@ -177,27 +179,30 @@ const handleCreateGroup = () => { initialMembers: selectedMembers, }); - signAndExecute({ transaction: tx }); + await dAppKit.signAndExecuteTransaction({ transaction: tx }); }; -const handleRotateKey = () => { +const handleRotateKey = async () => { const tx = client.messaging.tx.rotateEncryptionKey({ uuid: groupUuid, }); - signAndExecute({ transaction: tx }); + await dAppKit.signAndExecuteTransaction({ transaction: tx }); }; -const handleRemoveMember = (memberAddress: string) => { +const handleRemoveMember = async (memberAddress: string) => { const tx = client.messaging.tx.removeMembersAndRotateKey({ uuid: groupUuid, members: [memberAddress], }); - signAndExecute({ transaction: tx }); + await dAppKit.signAndExecuteTransaction({ transaction: tx }); }; ``` +`signAndExecuteTransaction` resolves with a `$kind` discriminated union rather than throwing on +on-chain failure — check `result.$kind === 'FailedTransaction'` before treating it as a success. + ## Composing with `call.*` thunks Use `call.*` with `tx.add()` to compose operations into a single PTB. This follows the [MystenLabs SDK transaction thunks pattern](https://sdk.mystenlabs.com/sui/sdk-building#transaction-thunks). diff --git a/docs/sui-stack-messaging/Setup.md b/docs/sui-stack-messaging/Setup.md index e4acf69..08783d9 100644 --- a/docs/sui-stack-messaging/Setup.md +++ b/docs/sui-stack-messaging/Setup.md @@ -114,7 +114,7 @@ Controls how the SDK obtains Seal session keys and encrypts/decrypts messages. ##### Tier 1: Signer-based (recommended) -Works with `@mysten/dapp-kit`'s `CurrentAccountSigner`, a `Keypair`, or Enoki. +Works with `@mysten/dapp-kit-core`'s `CurrentAccountSigner`, a `Keypair`, or Enoki. ```typescript encryption: { @@ -275,7 +275,7 @@ The `client.messaging` object exposes several sub-modules: ### When to use which - Top-level imperative methods (for example, `client.messaging.sendMessage()`): simplest path, sign, encrypt, and send in one call. -- `tx.*`: when you need a `Transaction` object to inspect or modify before signing (for example, with dapp-kit's `signAndExecuteTransaction`). +- `tx.*`: when you need a `Transaction` object to inspect or modify before signing (for example, with dApp Kit's `signAndExecuteTransaction`). - `call.*`: when composing multiple operations into a single PTB. - `view.*`: for read-only queries that don't require a signer. From caa48caf1520eb5442d13b3a59d28ecf493a325d Mon Sep 17 00:00:00 2001 From: ioannischtz Date: Fri, 12 Jun 2026 13:27:36 +0300 Subject: [PATCH 7/9] fix(chat-app): gate the UI on messaging-client readiness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a reload, dApp Kit's autoConnect restores the account before the messaging client finishes initializing (in devstack mode it waits on the generated-config load). CreateGroupModal mounted on `account` alone and calls useRequiredMessagingClient before its `open` check, so the init window threw "Wallet must be connected to use messaging client" into the ErrorBoundary — unrecoverable across reloads since the race reproduces every time. Render the body and modal only once the client exists, with an interim "Setting up the messaging client" state while an account is connected. Co-Authored-By: Claude Fable 5 --- chat-app/src/App.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/chat-app/src/App.tsx b/chat-app/src/App.tsx index 59e6aa8..d643fc8 100644 --- a/chat-app/src/App.tsx +++ b/chat-app/src/App.tsx @@ -5,9 +5,15 @@ import { Sidebar } from './components/Sidebar'; import { ChatArea } from './components/ChatArea'; import { CreateGroupModal } from './components/CreateGroupModal'; import { useGroupDiscovery } from './hooks/useGroupDiscovery'; +import { useMessagingClient } from './contexts/MessagingClientContext'; function App() { const account = useCurrentAccount(); + // Null while disconnected, but also while the client is still initializing + // after an auto-reconnect (in devstack mode it waits on the generated-config + // load). Components using useRequiredMessagingClient must not mount before + // it resolves. + const messagingClient = useMessagingClient(); const { groups, @@ -47,7 +53,7 @@ function App() { {/* Body */} - {account ? ( + {account && messagingClient ? (

- Connect your wallet to get started. + {account + ? 'Setting up the messaging client…' + : 'Connect your wallet to get started.'}

)} {/* Create group modal */} - {account && ( + {account && messagingClient && ( setShowCreateModal(false)} From 7397f70dedb4792f641610a63a25409343400895 Mon Sep 17 00:00:00 2001 From: ioannischtz Date: Fri, 12 Jun 2026 13:27:38 +0300 Subject: [PATCH 8/9] fix(chat-app): wait for transaction indexing in signAndExecute Callers read back the state they just changed (permissions after group creation, member lists after admin actions), but fullnode reads lag execution until the transaction is indexed. The most visible symptom: right after creating a group, the auto-selected chat showed "You don't have permission to send messages" until the group was re-selected. Wait on dAppKit.getClient().waitForTransaction(digest) before resolving, so every call site gets read-your-writes ordering. Co-Authored-By: Claude Fable 5 --- chat-app/src/lib/dapp-kit.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/chat-app/src/lib/dapp-kit.ts b/chat-app/src/lib/dapp-kit.ts index 237f069..6d16335 100644 --- a/chat-app/src/lib/dapp-kit.ts +++ b/chat-app/src/lib/dapp-kit.ts @@ -39,6 +39,10 @@ declare module '@mysten/dapp-kit-react' { * Sign and execute a transaction via the connected wallet, throwing on failure. * dApp Kit returns a `$kind` union instead of throwing when the transaction * fails on-chain, so call sites that treat resolution as success go through this. + * + * Also waits for the fullnode to index the transaction before resolving — + * callers read back the state they just changed (permissions, members, group + * objects), and reads lag execution until indexing completes. */ export async function signAndExecute({ transaction }: { transaction: Transaction }) { const result = await dAppKit.signAndExecuteTransaction({ transaction }); @@ -47,5 +51,6 @@ export async function signAndExecute({ transaction }: { transaction: Transaction result.FailedTransaction.status.error?.message ?? 'Transaction failed on-chain', ); } + await dAppKit.getClient().waitForTransaction({ digest: result.Transaction.digest }); return result; } From 12ebd801bf9144e78ba3c601b9bf6112b51228bb Mon Sep 17 00:00:00 2001 From: ioannischtz Date: Tue, 16 Jun 2026 17:43:08 +0300 Subject: [PATCH 9/9] docs: address review feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Examples.md: remove em dash and use "onchain" per the Sui docs style guide. - vite.config.ts: fix an inaccurate comment — devstackVitePlugin() aliases @generated only; the dev wallet is registered via the shim's walletInitializers entry (SHIM_ACTIVE_SOURCE), not the plugin. Co-Authored-By: Claude Fable 5 --- chat-app/vite.config.ts | 3 ++- docs/sui-stack-messaging/Examples.md | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/chat-app/vite.config.ts b/chat-app/vite.config.ts index 82807fb..cc8cc30 100644 --- a/chat-app/vite.config.ts +++ b/chat-app/vite.config.ts @@ -58,7 +58,8 @@ export default defineConfig(async ({ mode }) => { const plugins: PluginOption[] = [tailwindcss(), react()]; if (DEVSTACK_ACTIVE) { - // Aliases `@generated` / `@devstack-dev` and auto-injects the dev wallet. + // Aliases `@generated` / `@devstack-dev`. It does NOT register the dev wallet — that is the + // shim's `walletInitializers` entry (SHIM_ACTIVE_SOURCE), passed to createDAppKit. const { devstackVitePlugin } = await import('@mysten-incubation/devstack/vite'); plugins.push(devstackVitePlugin()); } diff --git a/docs/sui-stack-messaging/Examples.md b/docs/sui-stack-messaging/Examples.md index a2a5c1b..590387a 100644 --- a/docs/sui-stack-messaging/Examples.md +++ b/docs/sui-stack-messaging/Examples.md @@ -200,8 +200,8 @@ const handleRemoveMember = async (memberAddress: string) => { }; ``` -`signAndExecuteTransaction` resolves with a `$kind` discriminated union rather than throwing on -on-chain failure — check `result.$kind === 'FailedTransaction'` before treating it as a success. +`signAndExecuteTransaction` resolves with a `$kind` discriminated union rather than throwing when a +transaction fails onchain. Check `result.$kind === 'FailedTransaction'` before treating it as a success. ## Composing with `call.*` thunks