From 4b4dee3c32d437ed2f34ec162e6014adf66e0538 Mon Sep 17 00:00:00 2001 From: sirpy Date: Wed, 12 Aug 2026 19:47:20 +0300 Subject: [PATCH 1/9] Add viem fallback client helper --- packages/core/README.md | 96 +++++++ packages/core/package.json | 8 +- packages/core/src/index.ts | 10 + packages/core/src/viemFallbackClient.ts | 311 ++++++++++++++++++++++ packages/core/tsup.config.ts | 14 +- pnpm-lock.yaml | 340 +++++------------------- 6 files changed, 504 insertions(+), 275 deletions(-) create mode 100644 packages/core/README.md create mode 100644 packages/core/src/viemFallbackClient.ts diff --git a/packages/core/README.md b/packages/core/README.md new file mode 100644 index 00000000..e7ed2fdd --- /dev/null +++ b/packages/core/README.md @@ -0,0 +1,96 @@ +# @goodwidget/core + +Runtime helpers for GoodWidget providers, host detection, wallet context, and viem client setup. + +## viem fallback clients + +`createViemFallbackClient` wraps viem `createPublicClient` and `createWalletClient` so callers get a fallback HTTP transport built from cached Chainlist RPC URLs for the requested chain. + +The helper accepts a small key-value storage adapter. On initialization it reads cached RPC metadata from storage. If the cache is missing or older than 1 day, it starts a background refresh from Chainlist. Client creation waits for that first refresh only when no cached RPCs are available for the requested chain. + +```ts +import { createViemFallbackClient } from '@goodwidget/core/viemFallbackClient' +import { celo } from 'viem/chains' + +const viemClient = createViemFallbackClient(localStorage, { + onError(error) { + console.warn('RPC refresh failed', error) + }, +}) + +const publicClient = await viemClient.createPublicClient({ + chain: celo, + fallbackRpcs: ['https://forno.celo.org'], +}) +``` + +The same helper can create wallet clients. Any viem wallet client option, such as `account`, can be passed through. + +```ts +import { privateKeyToAccount } from 'viem/accounts' +import { celo } from 'viem/chains' + +const account = privateKeyToAccount('0x...') + +const walletClient = await viemClient.createWalletClient({ + account, + chain: celo, + fallbackRpcs: ['https://forno.celo.org'], +}) +``` + +If you pass `transport`, the wrapper leaves it unchanged and does not create a fallback transport for that client. + +```ts +import { http } from 'viem' +import { celo } from 'viem/chains' + +const client = await viemClient.createPublicClient({ + chain: celo, + transport: http('https://forno.celo.org'), +}) +``` + +## Storage adapters + +The adapter supports browser-style storage and Worker-style KV storage. + +```ts +createViemFallbackClient(localStorage) +``` + +```ts +createViemFallbackClient({ + get: (key) => env.KV.get(key, 'json'), + put: (key, value) => env.KV.put(key, value), +}) +``` + +Cached values use this shape: + +```ts +type ViemRpcCacheEntry = { + fetchedAt: string + rpcs: Array<{ + chainId: number + rpcs: string[] + }> +} +``` + +Only HTTPS RPC URLs are used. URLs containing Chainlist template placeholders are ignored. + +## Options + +```ts +createViemFallbackClient(storage, { + cacheKey: 'goodwidget:viem-rpcs', + chainlistRpcsUrl: 'https://chainlist.org/rpcs.json', + refreshIntervalMs: 24 * 60 * 60 * 1000, + fetchTimeoutMs: 10_000, + fetch: globalThis.fetch, + onError: console.warn, +}) +``` + +`chainlistRpcsUrl` is intended for Chainlist's HTTPS RPC JSON endpoint. The helper blocks non-HTTPS URLs and hosts outside the expected Chainlist domain. \ No newline at end of file diff --git a/packages/core/package.json b/packages/core/package.json index 7d540585..c93e930d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -15,6 +15,11 @@ "types": "./dist/wagmi.d.ts", "import": "./dist/wagmi.js", "require": "./dist/wagmi.cjs" + }, + "./viemFallbackClient": { + "types": "./dist/viemFallbackClient.d.ts", + "import": "./dist/viemFallbackClient.js", + "require": "./dist/viemFallbackClient.cjs" } }, "scripts": { @@ -35,7 +40,8 @@ }, "dependencies": { "@goodwidget/ui": "workspace:*", - "tamagui": "1.121.0" + "tamagui": "1.121.0", + "viem": "^2.0.0" }, "devDependencies": { "react": "^18.3.0", diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index db0331d3..b9f0fa47 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -2,6 +2,16 @@ export { GoodWidgetProvider } from './provider' export type { WalletContextValue, HostContextValue, GoodWidgetContextValue } from './provider' export { useWallet, useHost, useGoodWidget } from './hooks' export { detectHost } from './detect' +export { createViemFallbackClient } from './viemFallbackClient' +export type { + CachedChainRpcs, + ViemFallbackClient, + ViemFallbackClientOptions, + ViemFallbackPublicClientParameters, + ViemFallbackStorage, + ViemFallbackWalletClientParameters, + ViemRpcCacheEntry, +} from './viemFallbackClient' export type { EIP1193Provider, diff --git a/packages/core/src/viemFallbackClient.ts b/packages/core/src/viemFallbackClient.ts new file mode 100644 index 00000000..9606b2f7 --- /dev/null +++ b/packages/core/src/viemFallbackClient.ts @@ -0,0 +1,311 @@ +import { + createPublicClient as createViemPublicClient, + createWalletClient as createViemWalletClient, + fallback, + http, + type Account, + type Address, + type Chain, + type PublicClient, + type PublicClientConfig, + type RpcSchema, + type Transport, + type WalletClient, + type WalletClientConfig, +} from 'viem' + +const DEFAULT_CHAINLIST_RPCS_URL = 'https://chainlist.org/rpcs.json' +const DEFAULT_CACHE_KEY = 'goodwidget:viem-rpcs' +const DEFAULT_REFRESH_INTERVAL_MS = 24 * 60 * 60 * 1000 +const DEFAULT_FETCH_TIMEOUT_MS = 10_000 + +type MaybePromise = T | Promise + +export interface ViemFallbackStorage { + get?: (key: string) => MaybePromise + put?: (key: string, value: string) => MaybePromise + getItem?: (key: string) => MaybePromise + setItem?: (key: string, value: string) => MaybePromise +} + +export interface ViemFallbackClientOptions { + cacheKey?: string + chainlistRpcsUrl?: string + refreshIntervalMs?: number + fetchTimeoutMs?: number + fetch?: typeof fetch + onError?: (error: unknown) => void +} + +export interface CachedChainRpcs { + chainId: number + rpcs: string[] +} + +export interface ViemRpcCacheEntry { + rpcs: CachedChainRpcs[] + fetchedAt: string +} + +export type ViemFallbackPublicClientParameters = Omit< + PublicClientConfig, + 'chain' | 'transport' +> & { + chain: Chain + transport?: Transport + fallbackRpcs?: string[] +} + +export type ViemFallbackWalletClientParameters = Omit< + WalletClientConfig, + 'chain' | 'transport' +> & { + chain: Chain + transport?: Transport + fallbackRpcs?: string[] +} + +export interface ViemFallbackClient { + ready: Promise + refreshRpcs: () => Promise + getRpcUrls: (chain: Chain, fallbackRpcs?: string[]) => Promise + createPublicClient: (parameters: ViemFallbackPublicClientParameters) => Promise + createWalletClient: (parameters: ViemFallbackWalletClientParameters) => Promise +} + +/** + * Creates viem client wrappers backed by a cached Chainlist RPC list. + */ +export function createViemFallbackClient( + storage: ViemFallbackStorage, + options: ViemFallbackClientOptions = {}, +): ViemFallbackClient { + const cacheKey = options.cacheKey ?? DEFAULT_CACHE_KEY + const chainlistRpcsUrl = options.chainlistRpcsUrl ?? DEFAULT_CHAINLIST_RPCS_URL + const refreshIntervalMs = options.refreshIntervalMs ?? DEFAULT_REFRESH_INTERVAL_MS + const fetchTimeoutMs = options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS + const fetchImpl = options.fetch ?? globalThis.fetch + + let cache: ViemRpcCacheEntry | null = null + let refreshPromise: Promise | null = null + + const refreshRpcs = async (): Promise => { + if (!fetchImpl) throw new Error('fetch is not available') + + const chainlistUrl = new URL(chainlistRpcsUrl) + + const abortController = new AbortController() + const timeout = setTimeout(() => abortController.abort(), fetchTimeoutMs) + + try { + const response = await fetchImpl(chainlistUrl.href, { + redirect: 'error', + signal: abortController.signal, + }) + if (!response.ok) { + throw new Error(`Chainlist HTTP ${response.status}`) + } + + const payload = await response.json() + const nextCache: ViemRpcCacheEntry = { + rpcs: normalizeChainlistPayload(payload), + fetchedAt: new Date().toISOString(), + } + + if (nextCache.rpcs.length === 0) return + + cache = nextCache + await writeCache(storage, cacheKey, nextCache) + } finally { + clearTimeout(timeout) + } + } + + const startRefresh = (): Promise => { + if (!refreshPromise) { + refreshPromise = refreshRpcs() + .catch((error) => { + options.onError?.(error) + }) + .finally(() => { + refreshPromise = null + }) + } + + return refreshPromise + } + + const ready = readCache(storage, cacheKey) + .then((cached) => { + cache = cached + if (!cached || isStale(cached, refreshIntervalMs)) { + void startRefresh() + } + }) + .catch((error) => { + options.onError?.(error) + void startRefresh() + }) + + const getRpcUrls = async (chain: Chain, fallbackRpcs: string[] = []): Promise => { + await ready + + const cachedUrls = getCachedRpcUrls(cache, chain.id) + if (cachedUrls.length === 0 && refreshPromise) { + await refreshPromise + } + + return sanitizeRpcUrls([ + ...getCachedRpcUrls(cache, chain.id), + ...fallbackRpcs, + ...(chain.rpcUrls.default.http ?? []), + ]) + } + + const createFallbackTransport = async ( + chain: Chain, + fallbackRpcs?: string[], + ): Promise => { + const rpcUrls = await getRpcUrls(chain, fallbackRpcs) + const transports = rpcUrls.length > 0 ? rpcUrls.map((rpcUrl) => http(rpcUrl)) : [http()] + return fallback(transports) + } + + return { + ready, + refreshRpcs, + getRpcUrls, + async createPublicClient(parameters) { + const { fallbackRpcs, ...clientParameters } = parameters + const transport = + clientParameters.transport ?? + (await createFallbackTransport(clientParameters.chain, fallbackRpcs)) + + return createViemPublicClient({ + ...clientParameters, + transport, + } as PublicClientConfig< + Transport, + Chain, + Account | Address | undefined, + RpcSchema | undefined + >) + }, + async createWalletClient(parameters) { + const { fallbackRpcs, ...clientParameters } = parameters + const transport = + clientParameters.transport ?? + (await createFallbackTransport(clientParameters.chain, fallbackRpcs)) + + return createViemWalletClient({ + ...clientParameters, + transport, + } as WalletClientConfig< + Transport, + Chain, + Account | Address | undefined, + RpcSchema | undefined + >) + }, + } +} + +async function readCache( + storage: ViemFallbackStorage, + key: string, +): Promise { + const value = storage.get ? await storage.get(key) : await storage.getItem?.(key) + return parseCacheEntry(value) +} + +async function writeCache( + storage: ViemFallbackStorage, + key: string, + value: ViemRpcCacheEntry, +): Promise { + const serialized = JSON.stringify(value) + if (storage.put) { + await storage.put(key, serialized) + return + } + + await storage.setItem?.(key, serialized) +} + +function parseCacheEntry(value: unknown): ViemRpcCacheEntry | null { + if (!value) return null + + if (typeof value === 'string') { + try { + return parseCacheEntry(JSON.parse(value)) + } catch { + return null + } + } + + if (typeof value !== 'object') return null + + const candidate = value as Partial + if (typeof candidate.fetchedAt !== 'string' || !Array.isArray(candidate.rpcs)) return null + + const rpcs = candidate.rpcs + .map((entry) => ({ + chainId: typeof entry.chainId === 'number' ? entry.chainId : Number.NaN, + rpcs: Array.isArray(entry.rpcs) + ? sanitizeRpcUrls( + entry.rpcs.filter((rpcUrl): rpcUrl is string => typeof rpcUrl === 'string'), + ) + : [], + })) + .filter((entry) => Number.isInteger(entry.chainId) && entry.rpcs.length > 0) + + return { + fetchedAt: candidate.fetchedAt, + rpcs, + } +} + +function normalizeChainlistPayload(payload: unknown): CachedChainRpcs[] { + if (!Array.isArray(payload)) return [] + + return payload + .map((entry) => { + const candidate = entry as { chainId?: unknown; rpc?: unknown } + const rpcEntries = Array.isArray(candidate.rpc) ? candidate.rpc : [] + const urls = rpcEntries + .map((rpcEntry) => { + if (typeof rpcEntry === 'string') return rpcEntry + if (typeof rpcEntry === 'object' && rpcEntry && 'url' in rpcEntry) { + const url = (rpcEntry as { url?: unknown }).url + return typeof url === 'string' ? url : '' + } + return '' + }) + .filter((url) => url.length > 0) + + return { + chainId: typeof candidate.chainId === 'number' ? candidate.chainId : Number.NaN, + rpcs: sanitizeRpcUrls(urls), + } + }) + .filter((entry) => Number.isInteger(entry.chainId) && entry.rpcs.length > 0) +} + +function getCachedRpcUrls(cache: ViemRpcCacheEntry | null, chainId: number): string[] { + return cache?.rpcs.find((entry) => entry.chainId === chainId)?.rpcs ?? [] +} + +function isStale(cache: ViemRpcCacheEntry, refreshIntervalMs: number): boolean { + const fetchedAtMs = Date.parse(cache.fetchedAt) + return Number.isNaN(fetchedAtMs) || Date.now() - fetchedAtMs >= refreshIntervalMs +} + +function sanitizeRpcUrls(urls: string[]): string[] { + const deduped = new Set() + for (const url of urls) { + if (!url.startsWith('https://')) continue + if (url.includes('${')) continue + deduped.add(url) + } + return [...deduped] +} diff --git a/packages/core/tsup.config.ts b/packages/core/tsup.config.ts index b0c20dc1..60d7407b 100644 --- a/packages/core/tsup.config.ts +++ b/packages/core/tsup.config.ts @@ -4,11 +4,23 @@ export default defineConfig({ entry: { index: 'src/index.ts', wagmi: 'src/wagmi.ts', + viemFallbackClient: 'src/viemFallbackClient.ts', }, format: ['esm', 'cjs'], dts: true, sourcemap: true, clean: true, tsconfig: 'tsconfig.build.json', - external: ['react', 'react-dom', 'react-native', 'react-native-web', 'wagmi', 'viem', '@wagmi/core', 'tamagui', '@tamagui/core', '@goodwidget/ui'], + external: [ + 'react', + 'react-dom', + 'react-native', + 'react-native-web', + 'wagmi', + 'viem', + '@wagmi/core', + 'tamagui', + '@tamagui/core', + '@goodwidget/ui', + ], }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3111a2bf..9331f862 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,7 +49,7 @@ importers: version: link:../../packages/ui '@reown/appkit': specifier: ^1.8.22 - version: 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) + version: 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@4.1.11) '@tamagui/core': specifier: 1.121.0 version: 1.121.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -461,6 +461,9 @@ importers: tamagui: specifier: 1.121.0 version: 1.121.0(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.9(@babel/core@7.29.0)(@babel/preset-env@7.29.2(@babel/core@7.29.0))(@types/react@18.3.28)(react@18.3.1))(react@18.3.1) + viem: + specifier: ^2.0.0 + version: 2.48.4(typescript@5.9.3)(zod@4.1.11) devDependencies: '@types/react': specifier: ^18.3.0 @@ -491,19 +494,19 @@ importers: version: 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@reown/appkit': specifier: ^1.8.22 - version: 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) + version: 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) '@reown/appkit-adapter-wagmi': specifier: ^1.8.22 - version: 1.8.22(v6adbyiuvbtrgqm65ozlnb246m) + version: 1.8.22(isknxadknpp2cdfgti7v5vosu4) '@tanstack/react-query': specifier: ^5.101.2 version: 5.101.2(react@18.3.1) viem: specifier: ^2.0.0 - version: 2.48.4(typescript@5.9.3)(zod@4.1.11) + version: 2.48.4(typescript@5.9.3)(zod@3.25.76) wagmi: specifier: ^3.7.1 - version: 3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) + version: 3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) devDependencies: '@types/react': specifier: ^18.3.0 @@ -2051,7 +2054,7 @@ packages: '@expo/bunyan@4.0.1': resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} - engines: {'0': node >=0.10.0} + engines: {node: '>=0.10.0'} '@expo/cli@0.22.28': resolution: {integrity: sha512-lvt72KNitGuixYD2l3SZmRKVu2G4zJpmg5V7WfUBNpmUU5oODBw/6qmiJ6kSLAlfDozscUk+BBGknBBzxUrwrA==} @@ -10731,31 +10734,7 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@base-org/account@2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11)': - dependencies: - '@coinbase/cdp-sdk': 1.52.0(typescript@5.9.3) - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.3)(zod@4.1.11) - preact: 10.24.2 - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) - zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - debug - - fastestsmallesttextencoderdecoder - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod - optional: true - - '@base-org/account@2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76)': + '@base-org/account@2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76)': dependencies: '@coinbase/cdp-sdk': 1.52.0(typescript@5.9.3) '@noble/hashes': 1.4.0 @@ -10765,7 +10744,7 @@ snapshots: ox: 0.6.9(typescript@5.9.3)(zod@3.25.76) preact: 10.24.2 viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) - zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) transitivePeerDependencies: - '@types/react' - bufferutil @@ -10829,28 +10808,7 @@ snapshots: - utf-8-validate optional: true - '@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11)': - dependencies: - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.3)(zod@4.1.11) - preact: 10.24.2 - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) - zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod - optional: true - - '@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76)': + '@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76)': dependencies: '@noble/hashes': 1.4.0 clsx: 1.2.1 @@ -10859,7 +10817,7 @@ snapshots: ox: 0.6.9(typescript@5.9.3)(zod@3.25.76) preact: 10.24.2 viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) - zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) transitivePeerDependencies: - '@types/react' - bufferutil @@ -12407,22 +12365,22 @@ snapshots: '@renovatebot/pep440@4.2.1': {} - '@reown/appkit-adapter-wagmi@1.8.22(v6adbyiuvbtrgqm65ozlnb246m)': + '@reown/appkit-adapter-wagmi@1.8.22(isknxadknpp2cdfgti7v5vosu4)': dependencies: - '@reown/appkit': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) + '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-polyfills': 1.8.22 - '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) + '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) - '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) - '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@4.1.11) + '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) + '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@3.25.76) valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) - wagmi: 3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) + viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) + wagmi: 3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) optionalDependencies: - '@wagmi/connectors': 8.0.8(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) + '@wagmi/connectors': 8.0.8(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -12566,52 +12524,12 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-pay@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11)': - dependencies: - '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) - lit: 3.3.0 - valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - typescript - - uploadthing - - use-sync-external-store - - utf-8-validate - - zod - - '@reown/appkit-pay@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76)': + '@reown/appkit-pay@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) lit: 3.3.0 valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) transitivePeerDependencies: @@ -12690,55 +12608,13 @@ snapshots: dependencies: buffer: 6.0.3 - '@reown/appkit-scaffold-ui@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11)': - dependencies: - '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) - '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) - lit: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - typescript - - uploadthing - - use-sync-external-store - - utf-8-validate - - valtio - - zod - - '@reown/appkit-scaffold-ui@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76)': + '@reown/appkit-scaffold-ui@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) + '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) lit: 3.3.0 transitivePeerDependencies: @@ -12888,55 +12764,7 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-utils@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11)': - dependencies: - '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-polyfills': 1.8.22 - '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) - '@wallet-standard/wallet': 1.1.0 - '@walletconnect/logger': 3.0.2 - '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@4.1.11) - valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) - optionalDependencies: - '@base-org/account': 2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@4.1.11) - '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@4.1.11) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - typescript - - uploadthing - - use-sync-external-store - - utf-8-validate - - zod - - '@reown/appkit-utils@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76)': + '@reown/appkit-utils@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) @@ -12948,8 +12776,8 @@ snapshots: valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) optionalDependencies: - '@base-org/account': 2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) - '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) + '@base-org/account': 2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) + '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@3.25.76) '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@3.25.76) transitivePeerDependencies: @@ -13043,64 +12871,15 @@ snapshots: - typescript - utf-8-validate - '@reown/appkit@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11)': - dependencies: - '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@reown/appkit-polyfills': 1.8.22 - '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) - '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) - '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) - '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@4.1.11) - bs58: 6.0.0 - semver: 7.7.2 - valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) - optionalDependencies: - '@lit/react': 1.0.8(@types/react@18.3.28) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - typescript - - uploadthing - - use-sync-external-store - - utf-8-validate - - zod - - '@reown/appkit@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76)': + '@reown/appkit@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) + '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) '@reown/appkit-polyfills': 1.8.22 - '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@3.25.76) bs58: 6.0.0 @@ -16220,14 +15999,14 @@ snapshots: loupe: 3.2.1 tinyrainbow: 1.2.0 - '@wagmi/connectors@8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11))': + '@wagmi/connectors@8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76))': dependencies: - '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) + '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) + viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) optionalDependencies: - '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@4.1.11) - '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@4.1.11) + '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) + '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@3.25.76) + '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@3.25.76) typescript: 5.9.3 '@wagmi/connectors@8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11))': @@ -16240,17 +16019,32 @@ snapshots: '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@4.1.11) typescript: 5.9.3 - '@wagmi/connectors@8.0.8(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11))': + '@wagmi/connectors@8.0.8(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76))': dependencies: - '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) + '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) + viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) optionalDependencies: - '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@4.1.11) - '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@4.1.11) + '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) + '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@3.25.76) + '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@3.25.76) typescript: 5.9.3 optional: true + '@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76))': + dependencies: + eventemitter3: 5.0.1 + mipd: 0.0.7(typescript@5.9.3) + viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) + zustand: 5.0.0(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) + optionalDependencies: + '@tanstack/query-core': 5.101.2 + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/react' + - immer + - react + - use-sync-external-store + '@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11))': dependencies: eventemitter3: 5.0.1 @@ -22133,14 +21927,14 @@ snapshots: w-json@1.3.11: {} - wagmi@3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)): + wagmi@3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)): dependencies: '@tanstack/react-query': 5.101.2(react@18.3.1) - '@wagmi/connectors': 8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) - '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) + '@wagmi/connectors': 8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) + '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) react: 18.3.1 use-sync-external-store: 1.4.0(react@18.3.1) - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) + viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: From 0f38cc108acfde605fb9fbb502bcc000d8950669 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Aug 2026 09:57:32 +0000 Subject: [PATCH 2/9] fix: address viem fallback review feedback Co-authored-by: sirpy <671095+sirpy@users.noreply.github.com> --- packages/core/README.md | 2 + packages/core/package.json | 1 + packages/core/src/viemFallbackClient.test.ts | 156 +++++++++++++++++++ packages/core/src/viemFallbackClient.ts | 25 ++- 4 files changed, 181 insertions(+), 3 deletions(-) create mode 100644 packages/core/src/viemFallbackClient.test.ts diff --git a/packages/core/README.md b/packages/core/README.md index e7ed2fdd..d8f9828b 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -8,6 +8,8 @@ Runtime helpers for GoodWidget providers, host detection, wallet context, and vi The helper accepts a small key-value storage adapter. On initialization it reads cached RPC metadata from storage. If the cache is missing or older than 1 day, it starts a background refresh from Chainlist. Client creation waits for that first refresh only when no cached RPCs are available for the requested chain. +Caller-provided `fallbackRpcs` are always tried first, then the chain's own default RPC URLs, and finally any cached Chainlist URLs. The generated viem fallback transport enables ranking and a single retry so unhealthy discovered RPCs can be deprioritized during use instead of being trusted purely by cache order. + ```ts import { createViemFallbackClient } from '@goodwidget/core/viemFallbackClient' import { celo } from 'viem/chains' diff --git a/packages/core/package.json b/packages/core/package.json index c93e930d..f4f72c10 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -26,6 +26,7 @@ "build": "tsup", "dev": "tsup --watch", "lint": "eslint src/", + "test": "node --test --experimental-strip-types --test-force-exit src/**/*.test.ts", "clean": "rm -rf dist .turbo", "bump-version": "pnpm version patch --no-git-tag-version && git add package.json && git commit -m \"chore(release): bump @goodwidget/core to $(node -p 'JSON.parse(require(\"fs\").readFileSync(\"package.json\")).version')\"" }, diff --git a/packages/core/src/viemFallbackClient.test.ts b/packages/core/src/viemFallbackClient.test.ts new file mode 100644 index 00000000..52bf13a2 --- /dev/null +++ b/packages/core/src/viemFallbackClient.test.ts @@ -0,0 +1,156 @@ +import assert from 'node:assert/strict' +import test from 'node:test' + +import { celo } from 'viem/chains' + +import { createViemFallbackClient, type ViemFallbackStorage } from './viemFallbackClient.ts' + +function createStorage(initialValue?: string): ViemFallbackStorage { + let value = initialValue ?? null + + return { + async getItem() { + return value + }, + async setItem(_key, nextValue) { + value = nextValue + }, + } +} + +function createChainlistResponse(rpcs: string[]) { + return new Response( + JSON.stringify([ + { + chainId: celo.id, + rpc: rpcs, + }, + ]), + { + status: 200, + headers: { 'content-type': 'application/json' }, + }, + ) +} + +function createChain(defaultRpcs: string[]) { + return { + ...celo, + rpcUrls: { + ...celo.rpcUrls, + default: { + ...celo.rpcUrls.default, + http: defaultRpcs, + }, + }, + } +} + +test( + 'getRpcUrls prefers caller and chain defaults before cached Chainlist URLs', + { concurrency: false }, + async () => { + const client = createViemFallbackClient(createStorage(), { + fetch: async () => + createChainlistResponse(['https://cached.example', 'https://default.example']), + }) + + await client.ready + + const urls = await client.getRpcUrls( + createChain(['https://default.example']), + ['https://caller.example'], + ) + + assert.deepEqual(urls, [ + 'https://caller.example', + 'https://default.example', + 'https://cached.example', + ]) + }, +) + +test('refreshRpcs rejects non-HTTPS and non-Chainlist refresh URLs', { concurrency: false }, async () => { + const mockFetch = async () => createChainlistResponse([]) + + const insecureClient = createViemFallbackClient(createStorage(), { + chainlistRpcsUrl: 'http://chainlist.org/rpcs.json', + fetch: mockFetch, + }) + + await assert.rejects( + () => insecureClient.refreshRpcs(), + /chainlistRpcsUrl must use HTTPS/, + ) + + const unexpectedHostClient = createViemFallbackClient(createStorage(), { + chainlistRpcsUrl: 'https://example.com/rpcs.json', + fetch: mockFetch, + }) + + await assert.rejects( + () => unexpectedHostClient.refreshRpcs(), + /chainlistRpcsUrl must use chainlist\.org/, + ) +}) + +test( + 'createPublicClient falls back to a working discovered RPC when the first one fails', + { concurrency: false }, + async () => { + const originalFetch = globalThis.fetch + const badRpcCalls: string[] = [] + const goodRpcCalls: string[] = [] + + const mockFetch: typeof fetch = async (input, init) => { + const url = input instanceof Request ? input.url : String(input) + + if (url === 'https://chainlist.org/rpcs.json') { + return createChainlistResponse(['https://bad.example', 'https://good.example']) + } + + if (url === 'https://bad.example/' || url === 'https://bad.example') { + badRpcCalls.push(url) + return new Response('rate limited', { status: 429 }) + } + + if (url === 'https://good.example/' || url === 'https://good.example') { + goodRpcCalls.push(url) + const payload = JSON.parse(String(init?.body)) + + return new Response( + JSON.stringify({ + jsonrpc: '2.0', + id: payload.id, + result: '0xa4ec', + }), + { + status: 200, + headers: { 'content-type': 'application/json' }, + }, + ) + } + + throw new Error(`Unexpected fetch URL: ${url}`) + } + + globalThis.fetch = mockFetch + + try { + const client = createViemFallbackClient(createStorage(), { + fetch: mockFetch, + }) + const publicClient = await client.createPublicClient({ + chain: createChain([]), + }) + + const chainId = await publicClient.request({ method: 'eth_chainId' }) + + assert.equal(chainId, '0xa4ec') + assert.ok(badRpcCalls.length >= 1) + assert.ok(goodRpcCalls.length >= 1) + } finally { + globalThis.fetch = originalFetch + } + }, +) diff --git a/packages/core/src/viemFallbackClient.ts b/packages/core/src/viemFallbackClient.ts index 9606b2f7..d3a1f74c 100644 --- a/packages/core/src/viemFallbackClient.ts +++ b/packages/core/src/viemFallbackClient.ts @@ -18,6 +18,7 @@ const DEFAULT_CHAINLIST_RPCS_URL = 'https://chainlist.org/rpcs.json' const DEFAULT_CACHE_KEY = 'goodwidget:viem-rpcs' const DEFAULT_REFRESH_INTERVAL_MS = 24 * 60 * 60 * 1000 const DEFAULT_FETCH_TIMEOUT_MS = 10_000 +const CHAINLIST_HOST = 'chainlist.org' type MaybePromise = T | Promise @@ -92,7 +93,7 @@ export function createViemFallbackClient( const refreshRpcs = async (): Promise => { if (!fetchImpl) throw new Error('fetch is not available') - const chainlistUrl = new URL(chainlistRpcsUrl) + const chainlistUrl = parseChainlistUrl(chainlistRpcsUrl) const abortController = new AbortController() const timeout = setTimeout(() => abortController.abort(), fetchTimeoutMs) @@ -155,10 +156,12 @@ export function createViemFallbackClient( await refreshPromise } + // Prefer integrator-supplied RPCs and chain defaults before discovered Chainlist + // endpoints so callers control the primary transport order. return sanitizeRpcUrls([ - ...getCachedRpcUrls(cache, chain.id), ...fallbackRpcs, ...(chain.rpcUrls.default.http ?? []), + ...getCachedRpcUrls(cache, chain.id), ]) } @@ -168,7 +171,12 @@ export function createViemFallbackClient( ): Promise => { const rpcUrls = await getRpcUrls(chain, fallbackRpcs) const transports = rpcUrls.length > 0 ? rpcUrls.map((rpcUrl) => http(rpcUrl)) : [http()] - return fallback(transports) + // Let viem re-rank transports during use so stale cached endpoints do not remain + // the preferred RPCs after they start failing or slowing down. + return fallback(transports, { + rank: true, + retryCount: 1, + }) } return { @@ -291,6 +299,17 @@ function normalizeChainlistPayload(payload: unknown): CachedChainRpcs[] { .filter((entry) => Number.isInteger(entry.chainId) && entry.rpcs.length > 0) } +function parseChainlistUrl(value: string): URL { + const url = new URL(value) + if (url.protocol !== 'https:') { + throw new Error('chainlistRpcsUrl must use HTTPS') + } + if (url.hostname !== CHAINLIST_HOST) { + throw new Error(`chainlistRpcsUrl must use ${CHAINLIST_HOST}`) + } + return url +} + function getCachedRpcUrls(cache: ViemRpcCacheEntry | null, chainId: number): string[] { return cache?.rpcs.find((entry) => entry.chainId === chainId)?.rpcs ?? [] } From d9f364eb126c6378083d9faf67571f96951e6048 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Aug 2026 09:58:27 +0000 Subject: [PATCH 3/9] test: align viem fallback tests with review feedback Co-authored-by: sirpy <671095+sirpy@users.noreply.github.com> --- packages/core/src/viemFallbackClient.test.ts | 5 ++++- packages/core/src/viemFallbackClient.ts | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/core/src/viemFallbackClient.test.ts b/packages/core/src/viemFallbackClient.test.ts index 52bf13a2..5f687ee7 100644 --- a/packages/core/src/viemFallbackClient.test.ts +++ b/packages/core/src/viemFallbackClient.test.ts @@ -5,6 +5,8 @@ import { celo } from 'viem/chains' import { createViemFallbackClient, type ViemFallbackStorage } from './viemFallbackClient.ts' +const chainlistUrl = 'https://chainlist.org/rpcs.json' + function createStorage(initialValue?: string): ViemFallbackStorage { let value = initialValue ?? null @@ -105,7 +107,7 @@ test( const mockFetch: typeof fetch = async (input, init) => { const url = input instanceof Request ? input.url : String(input) - if (url === 'https://chainlist.org/rpcs.json') { + if (url === chainlistUrl) { return createChainlistResponse(['https://bad.example', 'https://good.example']) } @@ -138,6 +140,7 @@ test( try { const client = createViemFallbackClient(createStorage(), { + chainlistRpcsUrl: chainlistUrl, fetch: mockFetch, }) const publicClient = await client.createPublicClient({ diff --git a/packages/core/src/viemFallbackClient.ts b/packages/core/src/viemFallbackClient.ts index d3a1f74c..f1f7f402 100644 --- a/packages/core/src/viemFallbackClient.ts +++ b/packages/core/src/viemFallbackClient.ts @@ -304,6 +304,8 @@ function parseChainlistUrl(value: string): URL { if (url.protocol !== 'https:') { throw new Error('chainlistRpcsUrl must use HTTPS') } + // Keep the refresh source pinned to Chainlist's canonical host so cached RPC + // metadata cannot be replaced by another origin. if (url.hostname !== CHAINLIST_HOST) { throw new Error(`chainlistRpcsUrl must use ${CHAINLIST_HOST}`) } From ea5e69115656128a774d444743629ee9b4d6c5eb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Aug 2026 10:14:12 +0000 Subject: [PATCH 4/9] fix: remove chainlist URL validation Co-authored-by: sirpy <671095+sirpy@users.noreply.github.com> --- packages/core/README.md | 2 +- packages/core/src/viemFallbackClient.test.ts | 32 ++++++++------------ packages/core/src/viemFallbackClient.ts | 16 +--------- 3 files changed, 15 insertions(+), 35 deletions(-) diff --git a/packages/core/README.md b/packages/core/README.md index d8f9828b..de8d5b86 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -95,4 +95,4 @@ createViemFallbackClient(storage, { }) ``` -`chainlistRpcsUrl` is intended for Chainlist's HTTPS RPC JSON endpoint. The helper blocks non-HTTPS URLs and hosts outside the expected Chainlist domain. \ No newline at end of file +`chainlistRpcsUrl` defaults to Chainlist's RPC JSON endpoint, but can be overridden. Refresh requests still use a timeout and `redirect: 'error'`. \ No newline at end of file diff --git a/packages/core/src/viemFallbackClient.test.ts b/packages/core/src/viemFallbackClient.test.ts index 5f687ee7..b860bbcf 100644 --- a/packages/core/src/viemFallbackClient.test.ts +++ b/packages/core/src/viemFallbackClient.test.ts @@ -72,28 +72,22 @@ test( }, ) -test('refreshRpcs rejects non-HTTPS and non-Chainlist refresh URLs', { concurrency: false }, async () => { - const mockFetch = async () => createChainlistResponse([]) - - const insecureClient = createViemFallbackClient(createStorage(), { - chainlistRpcsUrl: 'http://chainlist.org/rpcs.json', - fetch: mockFetch, +test('refreshRpcs accepts a custom RPC list URL', { concurrency: false }, async () => { + const customUrl = 'http://example.com/rpcs.json' + const fetchCalls: string[] = [] + const client = createViemFallbackClient(createStorage(), { + chainlistRpcsUrl: customUrl, + fetch: async (input) => { + fetchCalls.push(input instanceof Request ? input.url : String(input)) + return createChainlistResponse(['https://cached.example']) + }, }) - await assert.rejects( - () => insecureClient.refreshRpcs(), - /chainlistRpcsUrl must use HTTPS/, - ) - - const unexpectedHostClient = createViemFallbackClient(createStorage(), { - chainlistRpcsUrl: 'https://example.com/rpcs.json', - fetch: mockFetch, - }) + await client.ready - await assert.rejects( - () => unexpectedHostClient.refreshRpcs(), - /chainlistRpcsUrl must use chainlist\.org/, - ) + assert.ok(fetchCalls.length >= 1) + assert.ok(fetchCalls.every((url) => url === customUrl)) + assert.deepEqual(await client.getRpcUrls(createChain([])), ['https://cached.example']) }) test( diff --git a/packages/core/src/viemFallbackClient.ts b/packages/core/src/viemFallbackClient.ts index f1f7f402..91f7d5c8 100644 --- a/packages/core/src/viemFallbackClient.ts +++ b/packages/core/src/viemFallbackClient.ts @@ -18,7 +18,6 @@ const DEFAULT_CHAINLIST_RPCS_URL = 'https://chainlist.org/rpcs.json' const DEFAULT_CACHE_KEY = 'goodwidget:viem-rpcs' const DEFAULT_REFRESH_INTERVAL_MS = 24 * 60 * 60 * 1000 const DEFAULT_FETCH_TIMEOUT_MS = 10_000 -const CHAINLIST_HOST = 'chainlist.org' type MaybePromise = T | Promise @@ -93,7 +92,7 @@ export function createViemFallbackClient( const refreshRpcs = async (): Promise => { if (!fetchImpl) throw new Error('fetch is not available') - const chainlistUrl = parseChainlistUrl(chainlistRpcsUrl) + const chainlistUrl = new URL(chainlistRpcsUrl) const abortController = new AbortController() const timeout = setTimeout(() => abortController.abort(), fetchTimeoutMs) @@ -299,19 +298,6 @@ function normalizeChainlistPayload(payload: unknown): CachedChainRpcs[] { .filter((entry) => Number.isInteger(entry.chainId) && entry.rpcs.length > 0) } -function parseChainlistUrl(value: string): URL { - const url = new URL(value) - if (url.protocol !== 'https:') { - throw new Error('chainlistRpcsUrl must use HTTPS') - } - // Keep the refresh source pinned to Chainlist's canonical host so cached RPC - // metadata cannot be replaced by another origin. - if (url.hostname !== CHAINLIST_HOST) { - throw new Error(`chainlistRpcsUrl must use ${CHAINLIST_HOST}`) - } - return url -} - function getCachedRpcUrls(cache: ViemRpcCacheEntry | null, chainId: number): string[] { return cache?.rpcs.find((entry) => entry.chainId === chainId)?.rpcs ?? [] } From ead4a3e8fb6e665a6c3389326d891e5041236c91 Mon Sep 17 00:00:00 2001 From: sirpy Date: Mon, 31 Aug 2026 17:44:30 +0300 Subject: [PATCH 5/9] fix: lockfile --- pnpm-lock.yaml | 347 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 266 insertions(+), 81 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 91bbe506..b6aff91e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,7 +49,7 @@ importers: version: link:../../packages/ui '@reown/appkit': specifier: ^1.8.22 - version: 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@4.1.11) + version: 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) '@tamagui/core': specifier: 1.121.0 version: 1.121.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -509,7 +509,7 @@ importers: version: link:../ui tamagui: specifier: 1.121.0 - version: 1.121.0(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.9(@babel/core@7.29.0)(@babel/preset-env@7.29.2(@babel/core@7.29.0))(@types/react@18.3.28)(react@18.3.1))(react@18.3.1) + version: 1.121.0(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.9(@babel/core@7.29.7)(@babel/preset-env@7.29.2(@babel/core@7.29.7))(@types/react@18.3.28)(react@18.3.1))(react@18.3.1) viem: specifier: ^2.0.0 version: 2.48.4(typescript@5.9.3)(zod@4.1.11) @@ -543,19 +543,19 @@ importers: version: 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@reown/appkit': specifier: ^1.8.22 - version: 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) + version: 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) '@reown/appkit-adapter-wagmi': specifier: ^1.8.22 - version: 1.8.22(isknxadknpp2cdfgti7v5vosu4) + version: 1.8.22(v6adbyiuvbtrgqm65ozlnb246m) '@tanstack/react-query': specifier: ^5.101.2 version: 5.101.2(react@18.3.1) viem: specifier: ^2.0.0 - version: 2.48.4(typescript@5.9.3)(zod@3.25.76) + version: 2.48.4(typescript@5.9.3)(zod@4.1.11) wagmi: specifier: ^3.7.1 - version: 3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) + version: 3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) devDependencies: '@types/react': specifier: ^18.3.0 @@ -2667,7 +2667,7 @@ packages: '@expo/bunyan@4.0.1': resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} - engines: {node: '>=0.10.0'} + engines: {'0': node >=0.10.0} '@expo/cli@0.22.28': resolution: {integrity: sha512-lvt72KNitGuixYD2l3SZmRKVu2G4zJpmg5V7WfUBNpmUU5oODBw/6qmiJ6kSLAlfDozscUk+BBGknBBzxUrwrA==} @@ -10815,7 +10815,7 @@ snapshots: '@babel/helper-module-imports@7.28.6': dependencies: '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -11000,7 +11000,7 @@ snapshots: '@babel/highlight@7.25.9': dependencies: - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.1.1 @@ -12327,7 +12327,7 @@ snapshots: '@babel/helper-module-imports': 7.28.6 '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/types': 7.29.0 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -12338,7 +12338,7 @@ snapshots: '@babel/helper-module-imports': 7.28.6 '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.7) - '@babel/types': 7.29.0 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -12920,7 +12920,7 @@ snapshots: ox: 0.6.9(typescript@5.9.3)(zod@3.25.76) preact: 10.24.2 viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) - zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) + zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) transitivePeerDependencies: - '@types/react' - bufferutil @@ -12984,7 +12984,28 @@ snapshots: - utf-8-validate optional: true - '@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76)': + '@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11)': + dependencies: + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.9.3)(zod@4.1.11) + preact: 10.24.2 + viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) + zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + optional: true + + '@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76)': dependencies: '@noble/hashes': 1.4.0 clsx: 1.2.1 @@ -12993,7 +13014,7 @@ snapshots: ox: 0.6.9(typescript@5.9.3)(zod@3.25.76) preact: 10.24.2 viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) - zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) + zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) transitivePeerDependencies: - '@types/react' - bufferutil @@ -14755,22 +14776,22 @@ snapshots: '@renovatebot/pep440@4.2.1': {} - '@reown/appkit-adapter-wagmi@1.8.22(isknxadknpp2cdfgti7v5vosu4)': + '@reown/appkit-adapter-wagmi@1.8.22(v6adbyiuvbtrgqm65ozlnb246m)': dependencies: - '@reown/appkit': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) - '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) + '@reown/appkit': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) + '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) '@reown/appkit-polyfills': 1.8.22 - '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) - '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) - '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@3.25.76) + '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) + '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@4.1.11) valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) - viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) - wagmi: 3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) + viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) + wagmi: 3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) optionalDependencies: - '@wagmi/connectors': 8.0.8(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) + '@wagmi/connectors': 8.0.8(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -14914,12 +14935,52 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-pay@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76)': + '@reown/appkit-pay@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11)': + dependencies: + '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) + lit: 3.3.0 + valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - zod + + '@reown/appkit-pay@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) lit: 3.3.0 valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) transitivePeerDependencies: @@ -14998,13 +15059,55 @@ snapshots: dependencies: buffer: 6.0.3 - '@reown/appkit-scaffold-ui@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76)': + '@reown/appkit-scaffold-ui@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11)': + dependencies: + '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) + '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) + '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) + lit: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - valtio + - zod + + '@reown/appkit-scaffold-ui@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) + '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) lit: 3.3.0 transitivePeerDependencies: @@ -15154,7 +15257,55 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-utils@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76)': + '@reown/appkit-utils@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11)': + dependencies: + '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit-polyfills': 1.8.22 + '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) + '@wallet-standard/wallet': 1.1.0 + '@walletconnect/logger': 3.0.2 + '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@4.1.11) + valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) + viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) + optionalDependencies: + '@base-org/account': 2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) + '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) + '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@4.1.11) + '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@4.1.11) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - zod + + '@reown/appkit-utils@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) @@ -15166,8 +15317,8 @@ snapshots: valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) optionalDependencies: - '@base-org/account': 2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) - '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) + '@base-org/account': 2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) + '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@3.25.76) '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@3.25.76) transitivePeerDependencies: @@ -15261,15 +15412,64 @@ snapshots: - typescript - utf-8-validate - '@reown/appkit@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76)': + '@reown/appkit@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11)': + dependencies: + '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) + '@reown/appkit-polyfills': 1.8.22 + '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) + '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) + '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) + '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@4.1.11) + bs58: 6.0.0 + semver: 7.7.2 + valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) + viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) + optionalDependencies: + '@lit/react': 1.0.8(@types/react@18.3.28) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - zod + + '@reown/appkit@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) + '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) '@reown/appkit-polyfills': 1.8.22 - '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@3.25.76) bs58: 6.0.0 @@ -18705,14 +18905,14 @@ snapshots: loupe: 3.2.1 tinyrainbow: 1.2.0 - '@wagmi/connectors@8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76))': + '@wagmi/connectors@8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11))': dependencies: - '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) - viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) + '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) + viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) optionalDependencies: - '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) - '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@3.25.76) - '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@3.25.76) + '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) + '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@4.1.11) + '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@4.1.11) typescript: 5.9.3 '@wagmi/connectors@8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11))': @@ -18725,32 +18925,17 @@ snapshots: '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@4.1.11) typescript: 5.9.3 - '@wagmi/connectors@8.0.8(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76))': + '@wagmi/connectors@8.0.8(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11))': dependencies: - '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) - viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) + '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) + viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) optionalDependencies: - '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) - '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@3.25.76) - '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@3.25.76) + '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) + '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@4.1.11) + '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@4.1.11) typescript: 5.9.3 optional: true - '@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76))': - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.9.3) - viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) - zustand: 5.0.0(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - optionalDependencies: - '@tanstack/query-core': 5.101.2 - typescript: 5.9.3 - transitivePeerDependencies: - - '@types/react' - - immer - - react - - use-sync-external-store - '@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11))': dependencies: eventemitter3: 5.0.1 @@ -19499,9 +19684,9 @@ snapshots: babel-literal-to-ast@2.1.0(@babel/core@7.29.0): dependencies: '@babel/core': 7.29.0 - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.8 '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -19517,8 +19702,8 @@ snapshots: babel-plugin-jest-hoist@29.6.3: dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.28.0 @@ -21535,7 +21720,7 @@ snapshots: istanbul-lib-instrument@5.2.1: dependencies: '@babel/core': 7.29.0 - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.8 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -21736,7 +21921,7 @@ snapshots: jest-message-util@29.7.0: dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@jest/types': 29.6.3 '@types/stack-utils': 2.0.3 chalk: 4.1.2 @@ -21871,10 +22056,10 @@ snapshots: jest-snapshot@29.7.0: dependencies: '@babel/core': 7.29.0 - '@babel/generator': 7.29.1 + '@babel/generator': 7.29.8 '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) - '@babel/types': 7.29.0 + '@babel/types': 7.29.8 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 @@ -22483,8 +22668,8 @@ snapshots: metro-transform-plugins@0.81.5: dependencies: '@babel/core': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/template': 7.28.6 + '@babel/generator': 7.29.8 + '@babel/template': 7.29.7 '@babel/traverse': 7.29.0 flow-enums-runtime: 0.0.6 nullthrows: 1.1.1 @@ -22505,9 +22690,9 @@ snapshots: metro-transform-worker@0.81.5: dependencies: '@babel/core': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 + '@babel/generator': 7.29.8 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 flow-enums-runtime: 0.0.6 metro: 0.81.5 metro-babel-transformer: 0.81.5 @@ -24981,14 +25166,14 @@ snapshots: w-json@1.3.11: {} - wagmi@3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)): + wagmi@3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)): dependencies: '@tanstack/react-query': 5.101.2(react@18.3.1) - '@wagmi/connectors': 8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) - '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) + '@wagmi/connectors': 8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) + '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) react: 18.3.1 use-sync-external-store: 1.4.0(react@18.3.1) - viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) + viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: From 81018cb80911ae8cdde4078b1a6ceb658a4f04e8 Mon Sep 17 00:00:00 2001 From: blueogin Date: Tue, 1 Sep 2026 08:25:37 -0400 Subject: [PATCH 6/9] Add test task dependency on build in turbo.json --- package.json | 1 + packages/core/README.md | 7 +- packages/core/package.json | 6 +- packages/core/src/viemFallbackClient.ts | 29 +- packages/core/tsconfig.build.json | 3 +- pnpm-lock.yaml | 494 ++++++++---------------- turbo.json | 3 + 7 files changed, 199 insertions(+), 344 deletions(-) diff --git a/package.json b/package.json index 129a9631..bbf83037 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "build": "turbo run build", "dev": "turbo run dev", "lint": "turbo run lint", + "test": "turbo run test", "clean": "turbo run clean", "storybook": "pnpm --filter @goodwidget/storybook storybook", "build-storybook": "pnpm --filter @goodwidget/storybook build-storybook", diff --git a/packages/core/README.md b/packages/core/README.md index de8d5b86..e4ffcd6b 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -8,7 +8,7 @@ Runtime helpers for GoodWidget providers, host detection, wallet context, and vi The helper accepts a small key-value storage adapter. On initialization it reads cached RPC metadata from storage. If the cache is missing or older than 1 day, it starts a background refresh from Chainlist. Client creation waits for that first refresh only when no cached RPCs are available for the requested chain. -Caller-provided `fallbackRpcs` are always tried first, then the chain's own default RPC URLs, and finally any cached Chainlist URLs. The generated viem fallback transport enables ranking and a single retry so unhealthy discovered RPCs can be deprioritized during use instead of being trusted purely by cache order. +Caller-provided `fallbackRpcs` are always tried first, then the chain's own default RPC URLs, and finally any cached Chainlist URLs. The generated viem fallback transport keeps that order and retries once, moving on to the next endpoint whenever one fails. ```ts import { createViemFallbackClient } from '@goodwidget/core/viemFallbackClient' @@ -92,7 +92,10 @@ createViemFallbackClient(storage, { fetchTimeoutMs: 10_000, fetch: globalThis.fetch, onError: console.warn, + rank: false, }) ``` -`chainlistRpcsUrl` defaults to Chainlist's RPC JSON endpoint, but can be overridden. Refresh requests still use a timeout and `redirect: 'error'`. \ No newline at end of file +`chainlistRpcsUrl` defaults to Chainlist's RPC JSON endpoint, but can be overridden. Refresh requests still use a timeout and `redirect: 'error'`. + +`rank` is off by default. Setting it to `true` (or `{ intervalMs }`) turns on viem's latency ranking, which reorders transports by measured health — but it starts a background ping against every discovered RPC that runs for the lifetime of the client and cannot be stopped, and it overrides the caller-first ordering described above. \ No newline at end of file diff --git a/packages/core/package.json b/packages/core/package.json index d4981151..aaeb96c4 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -7,6 +7,9 @@ "directory": "packages/core" }, "type": "module", + "engines": { + "node": ">=22.6" + }, "main": "./dist/index.cjs", "module": "./dist/index.js", "types": "./dist/index.d.ts", @@ -31,7 +34,7 @@ "build": "tsup", "dev": "tsup --watch", "lint": "eslint src/", - "test": "node --test --experimental-strip-types --test-force-exit src/**/*.test.ts", + "test": "node --test --experimental-strip-types src/*.test.ts", "clean": "rm -rf dist .turbo", "bump-version": "pnpm version patch --no-git-tag-version && git add package.json && git commit -m \"chore(release): bump @goodwidget/core to $(node -p 'JSON.parse(require(\"fs\").readFileSync(\"package.json\")).version')\"" }, @@ -53,6 +56,7 @@ "react": "^18.3.0", "react-native": "0.76.9", "@types/react": "^18.3.0", + "@types/node": "^22.10.0", "tsup": "^8.4.0", "typescript": "^5.7.0" } diff --git a/packages/core/src/viemFallbackClient.ts b/packages/core/src/viemFallbackClient.ts index 91f7d5c8..a2423f41 100644 --- a/packages/core/src/viemFallbackClient.ts +++ b/packages/core/src/viemFallbackClient.ts @@ -35,6 +35,13 @@ export interface ViemFallbackClientOptions { fetchTimeoutMs?: number fetch?: typeof fetch onError?: (error: unknown) => void + /** + * Enables viem's latency ranking for the generated fallback transport. Ranking runs a + * repeating background ping against every discovered RPC for the lifetime of the client + * and cannot be stopped, so it is opt-in. Defaults to `false`, which keeps the transports + * in the caller-controlled order and simply skips endpoints that fail a request. + */ + rank?: boolean | { intervalMs?: number } } export interface CachedChainRpcs { @@ -84,7 +91,17 @@ export function createViemFallbackClient( const chainlistRpcsUrl = options.chainlistRpcsUrl ?? DEFAULT_CHAINLIST_RPCS_URL const refreshIntervalMs = options.refreshIntervalMs ?? DEFAULT_REFRESH_INTERVAL_MS const fetchTimeoutMs = options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS - const fetchImpl = options.fetch ?? globalThis.fetch + const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis) + + // Many managed RPC providers reject viem's default `net_listening` ping, which would score + // them as permanently unhealthy, so rank against a method every provider implements. + const rankOptions = options.rank + ? { + interval: typeof options.rank === 'object' ? (options.rank.intervalMs ?? 30_000) : 30_000, + ping: ({ transport }: { transport: { request: (args: { method: string }) => Promise } }) => + transport.request({ method: 'eth_chainId' }), + } + : false let cache: ViemRpcCacheEntry | null = null let refreshPromise: Promise | null = null @@ -170,10 +187,10 @@ export function createViemFallbackClient( ): Promise => { const rpcUrls = await getRpcUrls(chain, fallbackRpcs) const transports = rpcUrls.length > 0 ? rpcUrls.map((rpcUrl) => http(rpcUrl)) : [http()] - // Let viem re-rank transports during use so stale cached endpoints do not remain - // the preferred RPCs after they start failing or slowing down. + // Without ranking viem walks the transports in order and skips the ones that fail, which + // preserves the caller-controlled ordering built in `getRpcUrls`. return fallback(transports, { - rank: true, + rank: rankOptions, retryCount: 1, }) } @@ -256,6 +273,7 @@ function parseCacheEntry(value: unknown): ViemRpcCacheEntry | null { if (typeof candidate.fetchedAt !== 'string' || !Array.isArray(candidate.rpcs)) return null const rpcs = candidate.rpcs + .filter((entry): entry is CachedChainRpcs => Boolean(entry) && typeof entry === 'object') .map((entry) => ({ chainId: typeof entry.chainId === 'number' ? entry.chainId : Number.NaN, rpcs: Array.isArray(entry.rpcs) @@ -276,13 +294,14 @@ function normalizeChainlistPayload(payload: unknown): CachedChainRpcs[] { if (!Array.isArray(payload)) return [] return payload + .filter((entry) => Boolean(entry) && typeof entry === 'object') .map((entry) => { const candidate = entry as { chainId?: unknown; rpc?: unknown } const rpcEntries = Array.isArray(candidate.rpc) ? candidate.rpc : [] const urls = rpcEntries .map((rpcEntry) => { if (typeof rpcEntry === 'string') return rpcEntry - if (typeof rpcEntry === 'object' && rpcEntry && 'url' in rpcEntry) { + if (rpcEntry && typeof rpcEntry === 'object' && 'url' in rpcEntry) { const url = (rpcEntry as { url?: unknown }).url return typeof url === 'string' ? url : '' } diff --git a/packages/core/tsconfig.build.json b/packages/core/tsconfig.build.json index 792172fb..b96c2e6f 100644 --- a/packages/core/tsconfig.build.json +++ b/packages/core/tsconfig.build.json @@ -4,5 +4,6 @@ "outDir": "./dist", "rootDir": "./src" }, - "include": ["src"] + "include": ["src"], + "exclude": ["src/**/*.test.ts"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b6aff91e..0860ce60 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,7 +49,7 @@ importers: version: link:../../packages/ui '@reown/appkit': specifier: ^1.8.22 - version: 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) + version: 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@4.1.11) '@tamagui/core': specifier: 1.121.0 version: 1.121.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -374,13 +374,13 @@ importers: version: 8.6.18(@storybook/test@8.6.18(storybook@8.6.18(prettier@3.8.1)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.18(prettier@3.8.1))(typescript@5.9.3) '@storybook/react-vite': specifier: ^8.6.17 - version: 8.6.18(@storybook/test@8.6.18(storybook@8.6.18(prettier@3.8.1)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.60.0)(storybook@8.6.18(prettier@3.8.1))(typescript@5.9.3)(vite@6.4.1(@types/node@26.2.0)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0)) + version: 8.6.18(@storybook/test@8.6.18(storybook@8.6.18(prettier@3.8.1)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.60.0)(storybook@8.6.18(prettier@3.8.1))(typescript@5.9.3)(vite@6.4.1(@types/node@22.20.1)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0)) '@storybook/test': specifier: ^8.6.17 version: 8.6.18(storybook@8.6.18(prettier@3.8.1)) '@storybook/test-runner': specifier: ^0.21.0 - version: 0.21.3(@types/node@26.2.0)(storybook@8.6.18(prettier@3.8.1)) + version: 0.21.3(@types/node@22.20.1)(storybook@8.6.18(prettier@3.8.1)) '@types/react': specifier: ^18.3.0 version: 18.3.28 @@ -389,7 +389,7 @@ importers: version: 18.3.7(@types/react@18.3.28) '@vitejs/plugin-react': specifier: ^4.3.0 - version: 4.7.0(vite@6.4.1(@types/node@26.2.0)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0)) + version: 4.7.0(vite@6.4.1(@types/node@22.20.1)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0)) storybook: specifier: ^8.6.17 version: 8.6.18(prettier@3.8.1) @@ -509,11 +509,14 @@ importers: version: link:../ui tamagui: specifier: 1.121.0 - version: 1.121.0(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.9(@babel/core@7.29.7)(@babel/preset-env@7.29.2(@babel/core@7.29.7))(@types/react@18.3.28)(react@18.3.1))(react@18.3.1) + version: 1.121.0(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.9(@babel/core@7.29.0)(@babel/preset-env@7.29.2(@babel/core@7.29.0))(@types/react@18.3.28)(react@18.3.1))(react@18.3.1) viem: specifier: ^2.0.0 version: 2.48.4(typescript@5.9.3)(zod@4.1.11) devDependencies: + '@types/node': + specifier: ^22.10.0 + version: 22.20.1 '@types/react': specifier: ^18.3.0 version: 18.3.28 @@ -522,7 +525,7 @@ importers: version: 18.3.1 react-native: specifier: 0.76.9 - version: 0.76.9(@babel/core@7.29.7)(@babel/preset-env@7.29.2(@babel/core@7.29.7))(@types/react@18.3.28)(react@18.3.1) + version: 0.76.9(@babel/core@7.29.0)(@babel/preset-env@7.29.2(@babel/core@7.29.0))(@types/react@18.3.28)(react@18.3.1) tsup: specifier: ^8.4.0 version: 8.5.1(@swc/core@1.15.30)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0) @@ -543,19 +546,19 @@ importers: version: 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@reown/appkit': specifier: ^1.8.22 - version: 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) + version: 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) '@reown/appkit-adapter-wagmi': specifier: ^1.8.22 - version: 1.8.22(v6adbyiuvbtrgqm65ozlnb246m) + version: 1.8.22(isknxadknpp2cdfgti7v5vosu4) '@tanstack/react-query': specifier: ^5.101.2 version: 5.101.2(react@18.3.1) viem: specifier: ^2.0.0 - version: 2.48.4(typescript@5.9.3)(zod@4.1.11) + version: 2.48.4(typescript@5.9.3)(zod@3.25.76) wagmi: specifier: ^3.7.1 - version: 3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) + version: 3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) devDependencies: '@types/react': specifier: ^18.3.0 @@ -2667,7 +2670,7 @@ packages: '@expo/bunyan@4.0.1': resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} - engines: {'0': node >=0.10.0} + engines: {node: '>=0.10.0'} '@expo/cli@0.22.28': resolution: {integrity: sha512-lvt72KNitGuixYD2l3SZmRKVu2G4zJpmg5V7WfUBNpmUU5oODBw/6qmiJ6kSLAlfDozscUk+BBGknBBzxUrwrA==} @@ -5175,8 +5178,8 @@ packages: '@types/node@20.11.0': resolution: {integrity: sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==} - '@types/node@25.5.0': - resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} + '@types/node@22.20.1': + resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==} '@types/node@26.2.0': resolution: {integrity: sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==} @@ -5582,7 +5585,7 @@ packages: '@xmldom/xmldom@0.7.13': resolution: {integrity: sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==} engines: {node: '>=10.0.0'} - deprecated: this version is no longer supported, please update to at least 0.8.* + deprecated: this version has critical issues, please update to the latest version '@xmldom/xmldom@0.8.11': resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} @@ -9973,8 +9976,8 @@ packages: undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} undici-types@7.29.0: resolution: {integrity: sha512-vamA8dGlzMwhpyYpQp9d8vka3o4D/yn5I7ez7Or+msDA4bZ8Uh+Zy91WvWf3I73gDAkFha9JcYRqm2li0Npfgg==} @@ -12886,31 +12889,7 @@ snapshots: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@base-org/account@2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11)': - dependencies: - '@coinbase/cdp-sdk': 1.52.0(typescript@5.9.3) - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.3)(zod@4.1.11) - preact: 10.24.2 - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) - zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - debug - - fastestsmallesttextencoderdecoder - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod - optional: true - - '@base-org/account@2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76)': + '@base-org/account@2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76)': dependencies: '@coinbase/cdp-sdk': 1.52.0(typescript@5.9.3) '@noble/hashes': 1.4.0 @@ -12920,7 +12899,7 @@ snapshots: ox: 0.6.9(typescript@5.9.3)(zod@3.25.76) preact: 10.24.2 viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) - zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) transitivePeerDependencies: - '@types/react' - bufferutil @@ -12984,28 +12963,7 @@ snapshots: - utf-8-validate optional: true - '@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11)': - dependencies: - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.3)(zod@4.1.11) - preact: 10.24.2 - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) - zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod - optional: true - - '@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76)': + '@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76)': dependencies: '@noble/hashes': 1.4.0 clsx: 1.2.1 @@ -13014,7 +12972,7 @@ snapshots: ox: 0.6.9(typescript@5.9.3)(zod@3.25.76) preact: 10.24.2 viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) - zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + zustand: 5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) transitivePeerDependencies: - '@types/react' - bufferutil @@ -13888,7 +13846,7 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 25.5.0 + '@types/node': 22.20.1 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -13901,14 +13859,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 26.2.0 + '@types/node': 22.20.1 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@26.2.0) + jest-config: 29.7.0(@types/node@22.20.1) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -13941,7 +13899,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.5.0 + '@types/node': 22.20.1 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -13959,7 +13917,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 25.5.0 + '@types/node': 22.20.1 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -13975,7 +13933,7 @@ snapshots: '@jest/pattern@30.0.1': dependencies: - '@types/node': 26.2.0 + '@types/node': 22.20.1 jest-regex-util: 30.0.1 '@jest/reporters@29.7.0': @@ -13986,7 +13944,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.31 - '@types/node': 26.2.0 + '@types/node': 22.20.1 chalk: 4.1.2 collect-v8-coverage: 1.0.3 exit: 0.1.2 @@ -14060,7 +14018,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 25.5.0 + '@types/node': 22.20.1 '@types/yargs': 17.0.35 chalk: 4.1.2 @@ -14070,16 +14028,16 @@ snapshots: '@jest/schemas': 30.0.5 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 26.2.0 + '@types/node': 22.20.1 '@types/yargs': 17.0.35 chalk: 4.1.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.9.3)(vite@6.4.1(@types/node@26.2.0)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.9.3)(vite@6.4.1(@types/node@22.20.1)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0))': dependencies: glob: 10.5.0 magic-string: 0.27.0 react-docgen-typescript: 2.4.0(typescript@5.9.3) - vite: 6.4.1(@types/node@26.2.0)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0) + vite: 6.4.1(@types/node@22.20.1)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0) optionalDependencies: typescript: 5.9.3 @@ -14776,22 +14734,22 @@ snapshots: '@renovatebot/pep440@4.2.1': {} - '@reown/appkit-adapter-wagmi@1.8.22(v6adbyiuvbtrgqm65ozlnb246m)': + '@reown/appkit-adapter-wagmi@1.8.22(isknxadknpp2cdfgti7v5vosu4)': dependencies: - '@reown/appkit': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) + '@reown/appkit': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) + '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-polyfills': 1.8.22 - '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) + '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) - '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) - '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@4.1.11) + '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) + '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@3.25.76) valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) - wagmi: 3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) + viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) + wagmi: 3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) optionalDependencies: - '@wagmi/connectors': 8.0.8(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) + '@wagmi/connectors': 8.0.8(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -14935,52 +14893,12 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-pay@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11)': - dependencies: - '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) - lit: 3.3.0 - valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - typescript - - uploadthing - - use-sync-external-store - - utf-8-validate - - zod - - '@reown/appkit-pay@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76)': + '@reown/appkit-pay@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) lit: 3.3.0 valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) transitivePeerDependencies: @@ -15059,55 +14977,13 @@ snapshots: dependencies: buffer: 6.0.3 - '@reown/appkit-scaffold-ui@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11)': - dependencies: - '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) - '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) - lit: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - typescript - - uploadthing - - use-sync-external-store - - utf-8-validate - - valtio - - zod - - '@reown/appkit-scaffold-ui@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76)': + '@reown/appkit-scaffold-ui@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) + '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) lit: 3.3.0 transitivePeerDependencies: @@ -15257,55 +15133,7 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-utils@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11)': - dependencies: - '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-polyfills': 1.8.22 - '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) - '@wallet-standard/wallet': 1.1.0 - '@walletconnect/logger': 3.0.2 - '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@4.1.11) - valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) - optionalDependencies: - '@base-org/account': 2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@4.1.11) - '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@4.1.11) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - typescript - - uploadthing - - use-sync-external-store - - utf-8-validate - - zod - - '@reown/appkit-utils@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76)': + '@reown/appkit-utils@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) @@ -15317,8 +15145,8 @@ snapshots: valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) optionalDependencies: - '@base-org/account': 2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) - '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) + '@base-org/account': 2.4.0(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) + '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@3.25.76) '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@3.25.76) transitivePeerDependencies: @@ -15412,64 +15240,15 @@ snapshots: - typescript - utf-8-validate - '@reown/appkit@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11)': - dependencies: - '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@reown/appkit-polyfills': 1.8.22 - '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) - '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@4.1.11) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@4.1.11) - '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) - '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@4.1.11) - bs58: 6.0.0 - semver: 7.7.2 - valtio: 2.1.7(@types/react@18.3.28)(react@18.3.1) - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) - optionalDependencies: - '@lit/react': 1.0.8(@types/react@18.3.28) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - typescript - - uploadthing - - use-sync-external-store - - utf-8-validate - - zod - - '@reown/appkit@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76)': + '@reown/appkit@1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.22(typescript@5.9.3)(zod@3.25.76) '@reown/appkit-controllers': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@3.25.76) + '@reown/appkit-pay': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) '@reown/appkit-polyfills': 1.8.22 - '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-scaffold-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) '@reown/appkit-ui': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76) - '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-utils': 1.8.22(@types/react@18.3.28)(@vercel/blob@2.4.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(valtio@2.1.7(@types/react@18.3.28)(react@18.3.1))(zod@3.25.76) '@reown/appkit-wallet': 1.8.22(typescript@5.9.3) '@walletconnect/universal-provider': 2.23.7(@vercel/blob@2.4.0)(typescript@5.9.3)(zod@3.25.76) bs58: 6.0.0 @@ -16359,13 +16138,13 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/builder-vite@8.6.18(storybook@8.6.18(prettier@3.8.1))(vite@6.4.1(@types/node@26.2.0)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0))': + '@storybook/builder-vite@8.6.18(storybook@8.6.18(prettier@3.8.1))(vite@6.4.1(@types/node@22.20.1)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0))': dependencies: '@storybook/csf-plugin': 8.6.18(storybook@8.6.18(prettier@3.8.1)) browser-assert: 1.2.1 storybook: 8.6.18(prettier@3.8.1) ts-dedent: 2.2.0 - vite: 6.4.1(@types/node@26.2.0)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0) + vite: 6.4.1(@types/node@22.20.1)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0) '@storybook/components@8.6.18(storybook@8.6.18(prettier@3.8.1))': dependencies: @@ -16428,11 +16207,11 @@ snapshots: react-dom: 18.3.1(react@18.3.1) storybook: 8.6.18(prettier@3.8.1) - '@storybook/react-vite@8.6.18(@storybook/test@8.6.18(storybook@8.6.18(prettier@3.8.1)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.60.0)(storybook@8.6.18(prettier@3.8.1))(typescript@5.9.3)(vite@6.4.1(@types/node@26.2.0)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0))': + '@storybook/react-vite@8.6.18(@storybook/test@8.6.18(storybook@8.6.18(prettier@3.8.1)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.60.0)(storybook@8.6.18(prettier@3.8.1))(typescript@5.9.3)(vite@6.4.1(@types/node@22.20.1)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@5.9.3)(vite@6.4.1(@types/node@26.2.0)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@5.9.3)(vite@6.4.1(@types/node@22.20.1)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0)) '@rollup/pluginutils': 5.3.0(rollup@4.60.0) - '@storybook/builder-vite': 8.6.18(storybook@8.6.18(prettier@3.8.1))(vite@6.4.1(@types/node@26.2.0)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0)) + '@storybook/builder-vite': 8.6.18(storybook@8.6.18(prettier@3.8.1))(vite@6.4.1(@types/node@22.20.1)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0)) '@storybook/react': 8.6.18(@storybook/test@8.6.18(storybook@8.6.18(prettier@3.8.1)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.18(prettier@3.8.1))(typescript@5.9.3) find-up: 5.0.0 magic-string: 0.30.21 @@ -16442,7 +16221,7 @@ snapshots: resolve: 1.22.11 storybook: 8.6.18(prettier@3.8.1) tsconfig-paths: 4.2.0 - vite: 6.4.1(@types/node@26.2.0)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0) + vite: 6.4.1(@types/node@22.20.1)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0) optionalDependencies: '@storybook/test': 8.6.18(storybook@8.6.18(prettier@3.8.1)) transitivePeerDependencies: @@ -16465,7 +16244,7 @@ snapshots: '@storybook/test': 8.6.18(storybook@8.6.18(prettier@3.8.1)) typescript: 5.9.3 - '@storybook/test-runner@0.21.3(@types/node@26.2.0)(storybook@8.6.18(prettier@3.8.1))': + '@storybook/test-runner@0.21.3(@types/node@22.20.1)(storybook@8.6.18(prettier@3.8.1))': dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.1 @@ -16476,14 +16255,14 @@ snapshots: '@swc/core': 1.15.30 '@swc/jest': 0.2.39(@swc/core@1.15.30) expect-playwright: 0.8.0 - jest: 29.7.0(@types/node@26.2.0) + jest: 29.7.0(@types/node@22.20.1) jest-circus: 29.7.0 jest-environment-node: 29.7.0 jest-junit: 16.0.0 - jest-playwright-preset: 4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0(@types/node@26.2.0)) + jest-playwright-preset: 4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0(@types/node@22.20.1)) jest-runner: 29.7.0 jest-serializer-html: 7.1.0 - jest-watch-typeahead: 2.2.2(jest@29.7.0(@types/node@26.2.0)) + jest-watch-typeahead: 2.2.2(jest@29.7.0(@types/node@22.20.1)) nyc: 15.1.0 playwright: 1.59.1 storybook: 8.6.18(prettier@3.8.1) @@ -18372,7 +18151,7 @@ snapshots: '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 25.5.0 + '@types/node': 22.20.1 '@types/hammerjs@2.0.46': {} @@ -18394,19 +18173,20 @@ snapshots: '@types/node-forge@1.3.14': dependencies: - '@types/node': 26.2.0 + '@types/node': 22.20.1 '@types/node@20.11.0': dependencies: undici-types: 5.26.5 - '@types/node@25.5.0': + '@types/node@22.20.1': dependencies: - undici-types: 7.18.2 + undici-types: 6.21.0 '@types/node@26.2.0': dependencies: undici-types: 8.3.0 + optional: true '@types/prop-types@15.7.15': {} @@ -18429,7 +18209,7 @@ snapshots: '@types/wait-on@5.3.4': dependencies: - '@types/node': 26.2.0 + '@types/node': 22.20.1 '@types/yargs-parser@21.0.3': {} @@ -18861,6 +18641,18 @@ snapshots: json-schema-to-ts: 1.6.4 ts-morph: 12.0.0 + '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@22.20.1)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-beta.27 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 6.4.1(@types/node@22.20.1)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0) + transitivePeerDependencies: + - supports-color + '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@26.2.0)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.0 @@ -18905,14 +18697,14 @@ snapshots: loupe: 3.2.1 tinyrainbow: 1.2.0 - '@wagmi/connectors@8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11))': + '@wagmi/connectors@8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76))': dependencies: - '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) + '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) + viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) optionalDependencies: - '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@4.1.11) - '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@4.1.11) + '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) + '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@3.25.76) + '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@3.25.76) typescript: 5.9.3 '@wagmi/connectors@8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11))': @@ -18925,17 +18717,32 @@ snapshots: '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@4.1.11) typescript: 5.9.3 - '@wagmi/connectors@8.0.8(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11))': + '@wagmi/connectors@8.0.8(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76))': dependencies: - '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) + '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) + viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) optionalDependencies: - '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11) - '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@4.1.11) - '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@4.1.11) + '@coinbase/wallet-sdk': 4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76) + '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@3.25.76) + '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@3.25.76) typescript: 5.9.3 optional: true + '@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76))': + dependencies: + eventemitter3: 5.0.1 + mipd: 0.0.7(typescript@5.9.3) + viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) + zustand: 5.0.0(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) + optionalDependencies: + '@tanstack/query-core': 5.101.2 + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/react' + - immer + - react + - use-sync-external-store + '@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11))': dependencies: eventemitter3: 5.0.1 @@ -20115,7 +19922,7 @@ snapshots: chrome-launcher@0.15.2: dependencies: - '@types/node': 26.2.0 + '@types/node': 22.20.1 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -20124,7 +19931,7 @@ snapshots: chromium-edge-launcher@0.2.0: dependencies: - '@types/node': 26.2.0 + '@types/node': 22.20.1 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -20283,13 +20090,13 @@ snapshots: js-yaml: 3.15.1 parse-json: 4.0.0 - create-jest@29.7.0(@types/node@26.2.0): + create-jest@29.7.0(@types/node@22.20.1): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@26.2.0) + jest-config: 29.7.0(@types/node@22.20.1) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -21785,7 +21592,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.5.0 + '@types/node': 22.20.1 chalk: 4.1.2 co: 4.6.0 dedent: 1.7.2 @@ -21805,16 +21612,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@26.2.0): + jest-cli@29.7.0(@types/node@22.20.1): dependencies: '@jest/core': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@26.2.0) + create-jest: 29.7.0(@types/node@22.20.1) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@26.2.0) + jest-config: 29.7.0(@types/node@22.20.1) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -21824,7 +21631,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@26.2.0): + jest-config@29.7.0(@types/node@22.20.1): dependencies: '@babel/core': 7.29.0 '@jest/test-sequencer': 29.7.0 @@ -21849,7 +21656,7 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 26.2.0 + '@types/node': 22.20.1 transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -21878,7 +21685,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.5.0 + '@types/node': 22.20.1 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -21888,7 +21695,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 25.5.0 + '@types/node': 22.20.1 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -21934,13 +21741,13 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 25.5.0 + '@types/node': 22.20.1 jest-util: 29.7.0 - jest-playwright-preset@4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0(@types/node@26.2.0)): + jest-playwright-preset@4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0(@types/node@22.20.1)): dependencies: expect-playwright: 0.8.0 - jest: 29.7.0(@types/node@26.2.0) + jest: 29.7.0(@types/node@22.20.1) jest-circus: 29.7.0 jest-environment-node: 29.7.0 jest-process-manager: 0.4.0 @@ -22003,7 +21810,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.5.0 + '@types/node': 22.20.1 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -22031,7 +21838,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.5.0 + '@types/node': 22.20.1 chalk: 4.1.2 cjs-module-lexer: 1.4.3 collect-v8-coverage: 1.0.3 @@ -22081,7 +21888,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 25.5.0 + '@types/node': 22.20.1 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -22096,11 +21903,11 @@ snapshots: leven: 3.1.0 pretty-format: 29.7.0 - jest-watch-typeahead@2.2.2(jest@29.7.0(@types/node@26.2.0)): + jest-watch-typeahead@2.2.2(jest@29.7.0(@types/node@22.20.1)): dependencies: ansi-escapes: 6.2.1 chalk: 5.6.2 - jest: 29.7.0(@types/node@26.2.0) + jest: 29.7.0(@types/node@22.20.1) jest-regex-util: 29.6.3 jest-watcher: 29.7.0 slash: 5.1.0 @@ -22111,7 +21918,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.5.0 + '@types/node': 22.20.1 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -22120,17 +21927,17 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 25.5.0 + '@types/node': 22.20.1 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@26.2.0): + jest@29.7.0(@types/node@22.20.1): dependencies: '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@26.2.0) + jest-cli: 29.7.0(@types/node@22.20.1) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -24898,12 +24705,13 @@ snapshots: undici-types@5.26.5: {} - undici-types@7.18.2: {} + undici-types@6.21.0: {} undici-types@7.29.0: optional: true - undici-types@8.3.0: {} + undici-types@8.3.0: + optional: true undici@5.28.4: dependencies: @@ -25144,6 +24952,22 @@ snapshots: - utf-8-validate - zod + vite@6.4.1(@types/node@22.20.1)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + postcss: 8.5.8 + rollup: 4.60.0 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 22.20.1 + fsevents: 2.3.3 + lightningcss: 1.27.0 + terser: 5.50.0 + tsx: 4.21.0 + yaml: 2.9.0 + vite@6.4.1(@types/node@26.2.0)(lightningcss@1.27.0)(terser@5.50.0)(tsx@4.21.0)(yaml@2.9.0): dependencies: esbuild: 0.25.12 @@ -25166,14 +24990,14 @@ snapshots: w-json@1.3.11: {} - wagmi@3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)): + wagmi@3.7.1(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@tanstack/query-core@5.101.2)(@tanstack/react-query@5.101.2(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)): dependencies: '@tanstack/react-query': 5.101.2(react@18.3.1) - '@wagmi/connectors': 8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@4.1.11))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@4.1.11))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@4.1.11))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) - '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@4.1.11)) + '@wagmi/connectors': 8.0.22(@coinbase/wallet-sdk@4.3.6(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(zod@3.25.76))(@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76))(@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76))(@wagmi/core@3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)))(typescript@5.9.3)(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) + '@wagmi/core': 3.6.1(@tanstack/query-core@5.101.2)(@types/react@18.3.28)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.48.4(typescript@5.9.3)(zod@3.25.76)) react: 18.3.1 use-sync-external-store: 1.4.0(react@18.3.1) - viem: 2.48.4(typescript@5.9.3)(zod@4.1.11) + viem: 2.48.4(typescript@5.9.3)(zod@3.25.76) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: diff --git a/turbo.json b/turbo.json index f9205c33..b351cefd 100644 --- a/turbo.json +++ b/turbo.json @@ -12,6 +12,9 @@ "lint": { "dependsOn": ["^build"] }, + "test": { + "dependsOn": ["^build"] + }, "clean": { "cache": false } From 432af53c2fd1aeb007ed1f21d8ab7858dbfde1e9 Mon Sep 17 00:00:00 2001 From: blueogin Date: Tue, 1 Sep 2026 08:29:26 -0400 Subject: [PATCH 7/9] feat(viem-fallback-client): enhance client with chain tracking and refresh retry logic --- packages/core/README.md | 8 +- packages/core/src/viemFallbackClient.test.ts | 70 ++++++++++++++ packages/core/src/viemFallbackClient.ts | 99 +++++++++++++++++--- packages/core/tsconfig.json | 3 + 4 files changed, 165 insertions(+), 15 deletions(-) diff --git a/packages/core/README.md b/packages/core/README.md index e4ffcd6b..b87b881b 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -6,7 +6,9 @@ Runtime helpers for GoodWidget providers, host detection, wallet context, and vi `createViemFallbackClient` wraps viem `createPublicClient` and `createWalletClient` so callers get a fallback HTTP transport built from cached Chainlist RPC URLs for the requested chain. -The helper accepts a small key-value storage adapter. On initialization it reads cached RPC metadata from storage. If the cache is missing or older than 1 day, it starts a background refresh from Chainlist. Client creation waits for that first refresh only when no cached RPCs are available for the requested chain. +The helper accepts a small key-value storage adapter. On initialization it reads cached RPC metadata from storage. If the cache is missing or older than 1 day, it starts a background refresh from Chainlist. Client creation waits for that first refresh only when no cached RPCs are available for the requested chain; a stale cache is served immediately while the refresh runs behind it, and a refresh that fails is retried on a later call rather than disabling discovery for the session. + +Chainlist returns every known chain, which is far too large to put in `localStorage`. Only the chains you list in `chainIds`, the chains the client is actually asked about, and the chains already in the cache are written back to storage. Caller-provided `fallbackRpcs` are always tried first, then the chain's own default RPC URLs, and finally any cached Chainlist URLs. The generated viem fallback transport keeps that order and retries once, moving on to the next endpoint whenever one fails. @@ -89,6 +91,8 @@ createViemFallbackClient(storage, { cacheKey: 'goodwidget:viem-rpcs', chainlistRpcsUrl: 'https://chainlist.org/rpcs.json', refreshIntervalMs: 24 * 60 * 60 * 1000, + refreshRetryMs: 60_000, + chainIds: [42220], fetchTimeoutMs: 10_000, fetch: globalThis.fetch, onError: console.warn, @@ -98,4 +102,6 @@ createViemFallbackClient(storage, { `chainlistRpcsUrl` defaults to Chainlist's RPC JSON endpoint, but can be overridden. Refresh requests still use a timeout and `redirect: 'error'`. +`chainIds` seeds the set of chains persisted to storage; it is optional, since any chain passed to `getRpcUrls`, `createPublicClient`, or `createWalletClient` is added automatically. `refreshRetryMs` bounds how often a failed Chainlist fetch is retried. + `rank` is off by default. Setting it to `true` (or `{ intervalMs }`) turns on viem's latency ranking, which reorders transports by measured health — but it starts a background ping against every discovered RPC that runs for the lifetime of the client and cannot be stopped, and it overrides the caller-first ordering described above. \ No newline at end of file diff --git a/packages/core/src/viemFallbackClient.test.ts b/packages/core/src/viemFallbackClient.test.ts index b860bbcf..a432987b 100644 --- a/packages/core/src/viemFallbackClient.test.ts +++ b/packages/core/src/viemFallbackClient.test.ts @@ -151,3 +151,73 @@ test( } }, ) + +test('persists only tracked chains instead of the whole Chainlist payload', async () => { + let stored: string | null = null + const storage: ViemFallbackStorage = { + async getItem() { + return stored + }, + async setItem(_key, value) { + stored = value + }, + } + + const client = createViemFallbackClient(storage, { + fetch: async () => + new Response( + JSON.stringify([ + { chainId: celo.id, rpc: ['https://celo.example'] }, + { chainId: 999_001, rpc: ['https://other.example'] }, + { chainId: 999_002, rpc: ['https://other2.example'] }, + ]), + { status: 200, headers: { 'content-type': 'application/json' } }, + ), + }) + + await client.getRpcUrls(createChain([])) + + assert.ok(stored, 'expected the cache to be written') + const parsed = JSON.parse(stored) as { rpcs: { chainId: number }[] } + assert.deepEqual( + parsed.rpcs.map((entry) => entry.chainId), + [celo.id], + ) +}) + +test('retries a failed refresh instead of giving up for the session', async () => { + let attempts = 0 + const errors: unknown[] = [] + + const client = createViemFallbackClient(createStorage(), { + refreshRetryMs: 0, + onError: (error) => errors.push(error), + fetch: async () => { + attempts += 1 + if (attempts === 1) throw new Error('offline') + return createChainlistResponse(['https://recovered.example']) + }, + }) + + await client.ready + + assert.deepEqual(await client.getRpcUrls(createChain([])), ['https://recovered.example']) + assert.equal(attempts, 2) + assert.equal(errors.length, 1) +}) + +test('does not refetch for a chain Chainlist does not know about', async () => { + let attempts = 0 + const client = createViemFallbackClient(createStorage(), { + fetch: async () => { + attempts += 1 + return createChainlistResponse(['https://celo.example']) + }, + }) + + const unknownChain = { ...createChain([]), id: 999_999 } + + assert.deepEqual(await client.getRpcUrls(unknownChain), []) + assert.deepEqual(await client.getRpcUrls(unknownChain), []) + assert.equal(attempts, 1) +}) diff --git a/packages/core/src/viemFallbackClient.ts b/packages/core/src/viemFallbackClient.ts index a2423f41..b15e0cdf 100644 --- a/packages/core/src/viemFallbackClient.ts +++ b/packages/core/src/viemFallbackClient.ts @@ -18,6 +18,7 @@ const DEFAULT_CHAINLIST_RPCS_URL = 'https://chainlist.org/rpcs.json' const DEFAULT_CACHE_KEY = 'goodwidget:viem-rpcs' const DEFAULT_REFRESH_INTERVAL_MS = 24 * 60 * 60 * 1000 const DEFAULT_FETCH_TIMEOUT_MS = 10_000 +const DEFAULT_REFRESH_RETRY_MS = 60_000 type MaybePromise = T | Promise @@ -32,6 +33,17 @@ export interface ViemFallbackClientOptions { cacheKey?: string chainlistRpcsUrl?: string refreshIntervalMs?: number + /** + * How long to wait before retrying after a failed Chainlist refresh. Defaults to 1 minute. + */ + refreshRetryMs?: number + /** + * Chain IDs to persist RPC URLs for. Chainlist returns every known chain, which is far too + * large for storage backends like `localStorage`, so only the chains listed here — plus any + * chain the client is actually asked about, and any chain already present in the cache — are + * written back to storage. + */ + chainIds?: number[] fetchTimeoutMs?: number fetch?: typeof fetch onError?: (error: unknown) => void @@ -90,6 +102,7 @@ export function createViemFallbackClient( const cacheKey = options.cacheKey ?? DEFAULT_CACHE_KEY const chainlistRpcsUrl = options.chainlistRpcsUrl ?? DEFAULT_CHAINLIST_RPCS_URL const refreshIntervalMs = options.refreshIntervalMs ?? DEFAULT_REFRESH_INTERVAL_MS + const refreshRetryMs = options.refreshRetryMs ?? DEFAULT_REFRESH_RETRY_MS const fetchTimeoutMs = options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis) @@ -103,8 +116,16 @@ export function createViemFallbackClient( } : false + // Chains whose RPC URLs are worth persisting. Seeded from `options.chainIds`, then grown by + // whatever the caller asks for and by whatever the existing cache already holds. + const trackedChainIds = new Set(options.chainIds ?? []) + let cache: ViemRpcCacheEntry | null = null let refreshPromise: Promise | null = null + let lastFailureAt = 0 + // The payload covers every chain, so one successful refresh answers for all of them: a chain + // still missing afterwards is a chain Chainlist does not know about, not a stale cache. + let hasRefreshed = false const refreshRpcs = async (): Promise => { if (!fetchImpl) throw new Error('fetch is not available') @@ -129,25 +150,61 @@ export function createViemFallbackClient( fetchedAt: new Date().toISOString(), } - if (nextCache.rpcs.length === 0) return + if (nextCache.rpcs.length === 0) { + throw new Error('Chainlist returned no usable RPC URLs') + } cache = nextCache - await writeCache(storage, cacheKey, nextCache) + hasRefreshed = true + await persistCache() } finally { clearTimeout(timeout) } } - const startRefresh = (): Promise => { - if (!refreshPromise) { - refreshPromise = refreshRpcs() - .catch((error) => { - options.onError?.(error) - }) - .finally(() => { - refreshPromise = null - }) + /** + * Writes the tracked subset of the in-memory cache. Storage failures (quota, private mode) + * are reported but never reject, so a full disk cannot break RPC resolution. + */ + const persistCache = async (): Promise => { + if (!cache || trackedChainIds.size === 0) return + + const rpcs = cache.rpcs.filter((entry) => trackedChainIds.has(entry.chainId)) + if (rpcs.length === 0) return + + try { + await writeCache(storage, cacheKey, { fetchedAt: cache.fetchedAt, rpcs }) + } catch (error) { + options.onError?.(error) } + } + + const trackChain = (chainId: number): void => { + if (trackedChainIds.has(chainId)) return + + trackedChainIds.add(chainId) + void persistCache() + } + + const canRetryRefresh = (): boolean => + lastFailureAt === 0 || Date.now() - lastFailureAt >= refreshRetryMs + + const startRefresh = (): Promise => { + if (refreshPromise) return refreshPromise + // A failed refresh must stay retryable, but not on every single call. + if (!canRetryRefresh()) return Promise.resolve() + + refreshPromise = refreshRpcs() + .then(() => { + lastFailureAt = 0 + }) + .catch((error) => { + lastFailureAt = Date.now() + options.onError?.(error) + }) + .finally(() => { + refreshPromise = null + }) return refreshPromise } @@ -155,6 +212,9 @@ export function createViemFallbackClient( const ready = readCache(storage, cacheKey) .then((cached) => { cache = cached + // Keep persisting the chains an earlier session cared about, not just this session's. + for (const entry of cached?.rpcs ?? []) trackedChainIds.add(entry.chainId) + if (!cached || isStale(cached, refreshIntervalMs)) { void startRefresh() } @@ -167,9 +227,20 @@ export function createViemFallbackClient( const getRpcUrls = async (chain: Chain, fallbackRpcs: string[] = []): Promise => { await ready - const cachedUrls = getCachedRpcUrls(cache, chain.id) - if (cachedUrls.length === 0 && refreshPromise) { - await refreshPromise + trackChain(chain.id) + + if (getCachedRpcUrls(cache, chain.id).length === 0) { + // Nothing cached for this chain: wait on any in-flight refresh, and start one if no + // refresh has ever succeeded — which covers a first run as well as a boot-time failure + // that would otherwise leave the client with no Chainlist URLs for the whole session. + if (refreshPromise) await refreshPromise + if (!hasRefreshed && getCachedRpcUrls(cache, chain.id).length === 0) { + await startRefresh() + } + } else if (!cache || isStale(cache, refreshIntervalMs)) { + // Serve the cached URLs immediately and refresh behind them, so a long-lived client does + // not keep using a cache that went stale after construction. + void startRefresh() } // Prefer integrator-supplied RPCs and chain defaults before discovered Chainlist diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index e4a4cd43..b14b6481 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -3,6 +3,9 @@ "compilerOptions": { "outDir": "./dist", "rootDir": "./src", + // Editor/typecheck config only; emitting is tsup's job via tsconfig.build.json. + "noEmit": true, + "allowImportingTsExtensions": true, "paths": { "@goodwidget/ui": ["../ui/src/index.ts"] } From 8a26c2a18bed32bd789936ecb3da7674c4a4a765 Mon Sep 17 00:00:00 2001 From: blueogin Date: Tue, 1 Sep 2026 08:39:17 -0400 Subject: [PATCH 8/9] feat(viem-fallback-client): enable ranking by default for improved endpoint health management --- packages/core/README.md | 6 ++-- packages/core/src/viemFallbackClient.test.ts | 3 ++ packages/core/src/viemFallbackClient.ts | 30 +++++++++++++------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/packages/core/README.md b/packages/core/README.md index b87b881b..b29c3343 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -10,7 +10,7 @@ The helper accepts a small key-value storage adapter. On initialization it reads Chainlist returns every known chain, which is far too large to put in `localStorage`. Only the chains you list in `chainIds`, the chains the client is actually asked about, and the chains already in the cache are written back to storage. -Caller-provided `fallbackRpcs` are always tried first, then the chain's own default RPC URLs, and finally any cached Chainlist URLs. The generated viem fallback transport keeps that order and retries once, moving on to the next endpoint whenever one fails. +Caller-provided `fallbackRpcs` are always tried first, then the chain's own default RPC URLs, and finally any cached Chainlist URLs. The generated viem fallback transport retries once and moves on to the next endpoint whenever one fails, and ranks endpoints by measured health so a cached RPC that starts rate-limiting or erroring is deprioritized instead of being trusted for the rest of the cache cycle. ```ts import { createViemFallbackClient } from '@goodwidget/core/viemFallbackClient' @@ -96,7 +96,7 @@ createViemFallbackClient(storage, { fetchTimeoutMs: 10_000, fetch: globalThis.fetch, onError: console.warn, - rank: false, + rank: true, }) ``` @@ -104,4 +104,4 @@ createViemFallbackClient(storage, { `chainIds` seeds the set of chains persisted to storage; it is optional, since any chain passed to `getRpcUrls`, `createPublicClient`, or `createWalletClient` is added automatically. `refreshRetryMs` bounds how often a failed Chainlist fetch is retried. -`rank` is off by default. Setting it to `true` (or `{ intervalMs }`) turns on viem's latency ranking, which reorders transports by measured health — but it starts a background ping against every discovered RPC that runs for the lifetime of the client and cannot be stopped, and it overrides the caller-first ordering described above. \ No newline at end of file +`rank` is on by default and reorders transports by measured health, pinging with `eth_chainId` (rather than viem's default `net_listening`, which many managed providers reject) every 30 seconds. Pass `{ intervalMs }` to change the interval. Be aware that ranking starts a background ping against every discovered RPC that runs for the lifetime of the client and cannot be stopped, and that once it has samples it supersedes the caller-first ordering described above. Pass `rank: false` to disable it. \ No newline at end of file diff --git a/packages/core/src/viemFallbackClient.test.ts b/packages/core/src/viemFallbackClient.test.ts index a432987b..f6ef7dfa 100644 --- a/packages/core/src/viemFallbackClient.test.ts +++ b/packages/core/src/viemFallbackClient.test.ts @@ -136,6 +136,9 @@ test( const client = createViemFallbackClient(createStorage(), { chainlistRpcsUrl: chainlistUrl, fetch: mockFetch, + // Ranking is on by default and its background ping loop cannot be stopped, which would + // keep the test process alive. This test only cares about failover ordering. + rank: false, }) const publicClient = await client.createPublicClient({ chain: createChain([]), diff --git a/packages/core/src/viemFallbackClient.ts b/packages/core/src/viemFallbackClient.ts index b15e0cdf..aa615603 100644 --- a/packages/core/src/viemFallbackClient.ts +++ b/packages/core/src/viemFallbackClient.ts @@ -19,6 +19,7 @@ const DEFAULT_CACHE_KEY = 'goodwidget:viem-rpcs' const DEFAULT_REFRESH_INTERVAL_MS = 24 * 60 * 60 * 1000 const DEFAULT_FETCH_TIMEOUT_MS = 10_000 const DEFAULT_REFRESH_RETRY_MS = 60_000 +const DEFAULT_RANK_INTERVAL_MS = 30_000 type MaybePromise = T | Promise @@ -48,10 +49,11 @@ export interface ViemFallbackClientOptions { fetch?: typeof fetch onError?: (error: unknown) => void /** - * Enables viem's latency ranking for the generated fallback transport. Ranking runs a - * repeating background ping against every discovered RPC for the lifetime of the client - * and cannot be stopped, so it is opt-in. Defaults to `false`, which keeps the transports - * in the caller-controlled order and simply skips endpoints that fail a request. + * viem's latency ranking for the generated fallback transport, which reorders endpoints by + * measured health so a chronically rate-limited RPC stops being preferred. Enabled by + * default. Note that ranking starts a repeating background ping against every discovered + * RPC that runs for the lifetime of the client and cannot be stopped — pass `false` to keep + * the caller-controlled order and only skip endpoints that fail an actual request. */ rank?: boolean | { intervalMs?: number } } @@ -107,12 +109,18 @@ export function createViemFallbackClient( const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis) // Many managed RPC providers reject viem's default `net_listening` ping, which would score - // them as permanently unhealthy, so rank against a method every provider implements. - const rankOptions = options.rank + // them as permanently unhealthy and demote the integrator's own endpoints, so rank against a + // method every provider implements. viem's default 4s interval is also far too aggressive for + // a list this size. + const rank = options.rank ?? true + const rankOptions = rank ? { - interval: typeof options.rank === 'object' ? (options.rank.intervalMs ?? 30_000) : 30_000, - ping: ({ transport }: { transport: { request: (args: { method: string }) => Promise } }) => - transport.request({ method: 'eth_chainId' }), + interval: typeof rank === 'object' ? (rank.intervalMs ?? DEFAULT_RANK_INTERVAL_MS) : DEFAULT_RANK_INTERVAL_MS, + ping: ({ + transport, + }: { + transport: { request: (args: { method: string }) => Promise } + }) => transport.request({ method: 'eth_chainId' }), } : false @@ -258,8 +266,8 @@ export function createViemFallbackClient( ): Promise => { const rpcUrls = await getRpcUrls(chain, fallbackRpcs) const transports = rpcUrls.length > 0 ? rpcUrls.map((rpcUrl) => http(rpcUrl)) : [http()] - // Without ranking viem walks the transports in order and skips the ones that fail, which - // preserves the caller-controlled ordering built in `getRpcUrls`. + // Ranking reorders these by measured health during use; with `rank: false` viem instead + // walks them in the caller-controlled order built by `getRpcUrls`, skipping failures. return fallback(transports, { rank: rankOptions, retryCount: 1, From 1ae7bf2b06908cf76a5c5102f157520faf17d50a Mon Sep 17 00:00:00 2001 From: blueogin Date: Tue, 1 Sep 2026 08:48:51 -0400 Subject: [PATCH 9/9] feat(viem-fallback-client): improve cache entry parsing and handle malformed Chainlist rows --- packages/core/src/viemFallbackClient.test.ts | 32 +++++++++ packages/core/src/viemFallbackClient.ts | 75 +++++++++----------- 2 files changed, 67 insertions(+), 40 deletions(-) diff --git a/packages/core/src/viemFallbackClient.test.ts b/packages/core/src/viemFallbackClient.test.ts index f6ef7dfa..bf4f8ca3 100644 --- a/packages/core/src/viemFallbackClient.test.ts +++ b/packages/core/src/viemFallbackClient.test.ts @@ -224,3 +224,35 @@ test('does not refetch for a chain Chainlist does not know about', async () => { assert.deepEqual(await client.getRpcUrls(unknownChain), []) assert.equal(attempts, 1) }) + +test('skips malformed Chainlist rows instead of discarding the payload', async () => { + const client = createViemFallbackClient(createStorage(), { + rank: false, + fetch: async () => + new Response( + JSON.stringify([ + null, + 'not-a-chain', + { chainId: 'nope', rpc: ['https://bad-id.example'] }, + { chainId: celo.id, rpc: null }, + { + chainId: celo.id, + rpc: [ + null, + 42, + 'http://insecure.example', + 'https://templated.example/${KEY}', + { url: 'https://object-form.example' }, + 'https://string-form.example', + ], + }, + ]), + { status: 200, headers: { 'content-type': 'application/json' } }, + ), + }) + + assert.deepEqual(await client.getRpcUrls(createChain([])), [ + 'https://object-form.example', + 'https://string-form.example', + ]) +}) diff --git a/packages/core/src/viemFallbackClient.ts b/packages/core/src/viemFallbackClient.ts index aa615603..a72ff1b6 100644 --- a/packages/core/src/viemFallbackClient.ts +++ b/packages/core/src/viemFallbackClient.ts @@ -335,9 +335,31 @@ async function writeCache( await storage.setItem?.(key, serialized) } -function parseCacheEntry(value: unknown): ViemRpcCacheEntry | null { - if (!value) return null +function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null +} + +function isPresent(value: T | null): value is T { + return value !== null +} + +/** Chainlist lists an RPC as either a bare URL or a `{ url }` object; the cache only ever + * holds bare URLs. Anything else collapses to '', which `sanitizeRpcUrls` drops. */ +function toRpcUrl(entry: unknown): string { + if (typeof entry === 'string') return entry + if (isRecord(entry) && typeof entry.url === 'string') return entry.url + return '' +} + +/** Builds one cache row, or null when the chain id or its RPC list is unusable. */ +function toChainRpcs(chainId: unknown, urls: unknown): CachedChainRpcs | null { + if (typeof chainId !== 'number' || !Number.isInteger(chainId)) return null + const rpcs = sanitizeRpcUrls(Array.isArray(urls) ? urls.map(toRpcUrl) : []) + return rpcs.length > 0 ? { chainId, rpcs } : null +} + +function parseCacheEntry(value: unknown): ViemRpcCacheEntry | null { if (typeof value === 'string') { try { return parseCacheEntry(JSON.parse(value)) @@ -346,26 +368,17 @@ function parseCacheEntry(value: unknown): ViemRpcCacheEntry | null { } } - if (typeof value !== 'object') return null + if (!isRecord(value)) return null - const candidate = value as Partial - if (typeof candidate.fetchedAt !== 'string' || !Array.isArray(candidate.rpcs)) return null - - const rpcs = candidate.rpcs - .filter((entry): entry is CachedChainRpcs => Boolean(entry) && typeof entry === 'object') - .map((entry) => ({ - chainId: typeof entry.chainId === 'number' ? entry.chainId : Number.NaN, - rpcs: Array.isArray(entry.rpcs) - ? sanitizeRpcUrls( - entry.rpcs.filter((rpcUrl): rpcUrl is string => typeof rpcUrl === 'string'), - ) - : [], - })) - .filter((entry) => Number.isInteger(entry.chainId) && entry.rpcs.length > 0) + const { fetchedAt, rpcs } = value + if (typeof fetchedAt !== 'string' || !Array.isArray(rpcs)) return null return { - fetchedAt: candidate.fetchedAt, - rpcs, + fetchedAt, + rpcs: rpcs + .filter(isRecord) + .map((entry) => toChainRpcs(entry.chainId, entry.rpcs)) + .filter(isPresent), } } @@ -373,27 +386,9 @@ function normalizeChainlistPayload(payload: unknown): CachedChainRpcs[] { if (!Array.isArray(payload)) return [] return payload - .filter((entry) => Boolean(entry) && typeof entry === 'object') - .map((entry) => { - const candidate = entry as { chainId?: unknown; rpc?: unknown } - const rpcEntries = Array.isArray(candidate.rpc) ? candidate.rpc : [] - const urls = rpcEntries - .map((rpcEntry) => { - if (typeof rpcEntry === 'string') return rpcEntry - if (rpcEntry && typeof rpcEntry === 'object' && 'url' in rpcEntry) { - const url = (rpcEntry as { url?: unknown }).url - return typeof url === 'string' ? url : '' - } - return '' - }) - .filter((url) => url.length > 0) - - return { - chainId: typeof candidate.chainId === 'number' ? candidate.chainId : Number.NaN, - rpcs: sanitizeRpcUrls(urls), - } - }) - .filter((entry) => Number.isInteger(entry.chainId) && entry.rpcs.length > 0) + .filter(isRecord) + .map((entry) => toChainRpcs(entry.chainId, entry.rpc)) + .filter(isPresent) } function getCachedRpcUrls(cache: ViemRpcCacheEntry | null, chainId: number): string[] {