diff --git a/package.json b/package.json index 4b5bcf4..d0361fa 100644 --- a/package.json +++ b/package.json @@ -2,5 +2,8 @@ "name": "ripguard", "private": true, "packageManager": "pnpm@10.29.3", - "workspaces": ["packages/*"] + "workspaces": ["packages/*"], + "scripts": { + "balances": "pnpm --filter app balances" + } } diff --git a/packages/app/package.json b/packages/app/package.json index 2f68018..872257f 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -8,7 +8,8 @@ "start": "next start", "lint": "eslint", "test": "vitest run", - "test:watch": "vitest" + "test:watch": "vitest", + "balances": "tsx scripts/treasury-balances.ts" }, "dependencies": { "@rainbow-me/rainbowkit": "^2.2.10", @@ -31,6 +32,7 @@ "eslint": "^9", "eslint-config-next": "16.1.6", "tailwindcss": "^4", + "tsx": "^4.21.0", "typescript": "^5", "vitest": "^4.1.2" } diff --git a/packages/app/scripts/treasury-balances.ts b/packages/app/scripts/treasury-balances.ts new file mode 100644 index 0000000..21293c8 --- /dev/null +++ b/packages/app/scripts/treasury-balances.ts @@ -0,0 +1,132 @@ +/** + * Treasury balance check — read-only across every mainnet chain in the registry. + * + * pnpm balances → checks the default treasury (per chains.ts) + * pnpm balances 0xAddr... → checks any address (e.g. cold-storage sweep target) + * + * Uses each chain's default public RPC (no API key, no env config). One read + * per chain via viem. Non-zero balances render in cyan; zeros are dim. + * + * Adding a chain to chains.ts auto-includes it here — there's no separate + * list to maintain. Testnets are filtered out (they don't earn revenue). + */ + +import { createPublicClient, formatUnits, getAddress, http, isAddress, type Address } from "viem"; +import * as wagmiChains from "viem/chains"; +import { CHAINS, type ChainConfig } from "../src/config/chains"; + +const ERC20_BALANCE_OF_ABI = [ + { + type: "function", + name: "balanceOf", + inputs: [{ name: "account", type: "address" }], + outputs: [{ type: "uint256" }], + stateMutability: "view", + }, +] as const; + +const chainIdToWagmiChain: Record = { + [wagmiChains.mainnet.id]: wagmiChains.mainnet, + [wagmiChains.base.id]: wagmiChains.base, + [wagmiChains.arbitrum.id]: wagmiChains.arbitrum, + [wagmiChains.optimism.id]: wagmiChains.optimism, + [wagmiChains.polygon.id]: wagmiChains.polygon, + [wagmiChains.avalanche.id]: wagmiChains.avalanche, + [wagmiChains.bsc.id]: wagmiChains.bsc, +}; + +const useColor = process.stdout.isTTY && !process.env.NO_COLOR; +const c = { + cyan: useColor ? "\x1b[36m" : "", + bold: useColor ? "\x1b[1m" : "", + dim: useColor ? "\x1b[2m" : "", + reset: useColor ? "\x1b[0m" : "", +}; + +type Result = { + chain: ChainConfig; + balance: bigint; + error: string | null; +}; + +async function fetchBalance(chain: ChainConfig, address: Address): Promise { + const wagmiChain = chainIdToWagmiChain[chain.chainId]; + if (!wagmiChain) { + return { chain, balance: BigInt(0), error: "no RPC mapping" }; + } + try { + // Short timeout + no retries so a single slow public RPC (looking at you, + // Ethereum) doesn't block the whole script. The user can re-run if needed. + const client = createPublicClient({ + chain: wagmiChain, + transport: http(undefined, { timeout: 8_000, retryCount: 0 }), + }); + const balance = await client.readContract({ + address: chain.usdc, + abi: ERC20_BALANCE_OF_ABI, + functionName: "balanceOf", + args: [address], + }); + return { chain, balance, error: null }; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + // Collapse to single line and trim — error messages can carry URLs and + // multi-line stack traces that wreck the table layout. + const oneLine = msg.replace(/\s+/g, " ").trim(); + return { chain, balance: BigInt(0), error: oneLine.slice(0, 60) }; + } +} + +function resolveTargetAddress(): Address { + const arg = process.argv[2]; + if (!arg) { + // Default: the treasury currently set on the deployment's default chain. + // (Same EOA across mainnet chains.) + const defaultChain = Object.values(CHAINS).find((c) => !c.isTestnet); + if (!defaultChain) { + console.error("No mainnet chain in registry. Aborting."); + process.exit(1); + } + return defaultChain.treasury; + } + if (!isAddress(arg)) { + console.error(`"${arg}" isn't a valid EVM address.`); + process.exit(1); + } + return getAddress(arg); +} + +async function main() { + const target = resolveTargetAddress(); + const mainnetChains = Object.values(CHAINS).filter((c) => !c.isTestnet); + + process.stdout.write(`\n ${c.dim}Address${c.reset} ${target}\n\n`); + + const results = await Promise.all(mainnetChains.map((chain) => fetchBalance(chain, target))); + + let totalDisplay = 0; + for (const r of results) { + const display = formatUnits(r.balance, r.chain.usdcDecimals); + const num = Number(display); + totalDisplay += num; + + const color = r.error ? c.dim : num > 0 ? c.cyan + c.bold : c.dim; + const formatted = num > 0 ? num.toFixed(6) : "0.000000"; + const note = r.error ? ` ${c.dim}(${r.error})${c.reset}` : ""; + + console.log( + ` ${color}${r.chain.name.padEnd(14)}${c.reset} ${color}${formatted.padStart(14)} USDC${c.reset}${note}` + ); + } + + const totalColor = totalDisplay > 0 ? c.cyan + c.bold : c.dim; + console.log(` ${c.dim}${"─".repeat(34)}${c.reset}`); + console.log( + ` ${totalColor}${"Total".padEnd(14)} ${totalDisplay.toFixed(6).padStart(14)} USDC${c.reset}\n` + ); +} + +main().catch((err) => { + console.error("Fatal:", err); + process.exit(1); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3efc87f..22809ba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -55,7 +55,7 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(vite@8.0.3(@types/node@20.19.37)(jiti@2.6.1)) + version: 6.0.1(vite@8.0.3(@types/node@20.19.37)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) eslint: specifier: ^9 version: 9.39.4(jiti@2.6.1) @@ -65,12 +65,15 @@ importers: tailwindcss: specifier: ^4 version: 4.2.1 + tsx: + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5 version: 5.9.3 vitest: specifier: ^4.1.2 - version: 4.1.2(@types/node@20.19.37)(vite@8.0.3(@types/node@20.19.37)(jiti@2.6.1)) + version: 4.1.2(@types/node@20.19.37)(vite@8.0.3(@types/node@20.19.37)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) packages: @@ -182,6 +185,162 @@ packages: '@emotion/hash@0.9.2': resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2299,6 +2458,11 @@ packages: es6-promisify@5.0.0: resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -3879,6 +4043,11 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -4583,6 +4752,84 @@ snapshots: '@emotion/hash@0.9.2': {} + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.6.1))': dependencies: eslint: 9.39.4(jiti@2.6.1) @@ -6268,10 +6515,10 @@ snapshots: next: 16.1.6(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 - '@vitejs/plugin-react@6.0.1(vite@8.0.3(@types/node@20.19.37)(jiti@2.6.1))': + '@vitejs/plugin-react@6.0.1(vite@8.0.3(@types/node@20.19.37)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.7 - vite: 8.0.3(@types/node@20.19.37)(jiti@2.6.1) + vite: 8.0.3(@types/node@20.19.37)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) '@vitest/expect@4.1.2': dependencies: @@ -6282,13 +6529,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.2(vite@8.0.3(@types/node@20.19.37)(jiti@2.6.1))': + '@vitest/mocker@4.1.2(vite@8.0.3(@types/node@20.19.37)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))': dependencies: '@vitest/spy': 4.1.2 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.3(@types/node@20.19.37)(jiti@2.6.1) + vite: 8.0.3(@types/node@20.19.37)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) '@vitest/pretty-format@4.1.2': dependencies: @@ -7504,6 +7751,35 @@ snapshots: dependencies: es6-promise: 4.2.8 + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + escalade@3.2.0: {} escape-string-regexp@4.0.0: {} @@ -9235,6 +9511,13 @@ snapshots: tslib@2.8.1: {} + tsx@4.21.0: + dependencies: + esbuild: 0.27.7 + get-tsconfig: 4.13.6 + optionalDependencies: + fsevents: 2.3.3 + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -9478,7 +9761,7 @@ snapshots: - utf-8-validate - zod - vite@8.0.3(@types/node@20.19.37)(jiti@2.6.1): + vite@8.0.3(@types/node@20.19.37)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -9487,13 +9770,15 @@ snapshots: tinyglobby: 0.2.15 optionalDependencies: '@types/node': 20.19.37 + esbuild: 0.27.7 fsevents: 2.3.3 jiti: 2.6.1 + tsx: 4.21.0 - vitest@4.1.2(@types/node@20.19.37)(vite@8.0.3(@types/node@20.19.37)(jiti@2.6.1)): + vitest@4.1.2(@types/node@20.19.37)(vite@8.0.3(@types/node@20.19.37)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)): dependencies: '@vitest/expect': 4.1.2 - '@vitest/mocker': 4.1.2(vite@8.0.3(@types/node@20.19.37)(jiti@2.6.1)) + '@vitest/mocker': 4.1.2(vite@8.0.3(@types/node@20.19.37)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) '@vitest/pretty-format': 4.1.2 '@vitest/runner': 4.1.2 '@vitest/snapshot': 4.1.2 @@ -9510,7 +9795,7 @@ snapshots: tinyexec: 1.0.4 tinyglobby: 0.2.15 tinyrainbow: 3.1.0 - vite: 8.0.3(@types/node@20.19.37)(jiti@2.6.1) + vite: 8.0.3(@types/node@20.19.37)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.19.37