From 39633b5c0533ec1c9955a74922402a7f7a78d8c5 Mon Sep 17 00:00:00 2001 From: chrisli30 Date: Fri, 29 May 2026 13:35:14 -0700 Subject: [PATCH 1/2] chore: initial repo skeleton + 14-protocol catalog seed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bootstraps @avaprotocol/protocols as a standalone npm package. Ships the static-data DeFi catalog (addresses, ABI fragments, event topic hashes) that previously lived inside @avaprotocol/sdk-js@4.0.0-dev.2 at packages/sdk-js/src/v4/protocols/. Extracted unchanged at the data level; doc comments rewritten for standalone context. Protocols covered (14 + shared ERC-20 helper): - aaveV3 Pool/Oracle/wethGateway × 4 chains + ABI + topics - aerodrome Router on Base - chainlink ETH/USD + BTC/USD feeds + AggregatorV3 ABI - compoundV3 USDC Comet on mainnet + Base - ethena sUSDe vault + USDe + custom (cooldown) ABI - fraxEther sfrxETH vault + frxETH + ERC-4626 ABI - lido wstETH × 2 + stETH + L1 wrap/unwrap ABI - morphoBlue Singleton on mainnet + Base + MarketParams ABI - rocketPool rETH × 2 chains + L1 burn/rate/value ABI - sky sDAI vault + ERC-4626 ABI - spark SparkLend Pool (AAVE V3 fork) - superfluid CFAv1Forwarder × 2 + setFlowrate/createFlow ABI - uniswapV3 Router/Quoter/Permit2/Factory/PM/UR × 4 + ABIs - wrapped WETH × 4 chains + WETH9 ABI - erc20 Standard approve fragment Shared ABIs in common.ts: - aggregatorV3Abi Any Chainlink-compatible price feed - erc4626VaultAbi Standard ERC-4626 vault (Frax sfrxETH, Sky sDAI) Package shape: - Dual CJS (.cjs) + ESM (.js) + .d.ts via tsup + tsc - Built tarball: 45 files, 14.7 kB - Node 18+, MIT, public access on npm - Type imports surface: `Chains`, `ChainId`, `Protocols`, `AbiFragment`, `AddressByChain`, `aggregatorV3Abi`, `erc4626VaultAbi` Infra: - tsconfig.json (root) for editor/dev mode, tsconfig.build.json pinning rootDir=src/outDir=dist for declaration emit - vitest @ 1.6 - GitHub Actions CI: typecheck + test + build + tarball verification on Node 18/20/22 Tests (15/15 pass): - Namespace surface (every protocol enumerated + frozen) - Address shape (every 0x[40-hex] across the catalog) - Event-topic shape (32-byte keccak hashes) - AAVE V3 per-chain Pool coverage + Pool method ABI completeness + Borrow event ABI/topic lockstep - Uniswap V3 per-chain SwapRouter02 + exactInputSingle/ exactOutputSingle + Permit2 same-address invariant - Shared ABI references stay object-identical across protocol modules (Frax/Sky share the same erc4626VaultAbi instance) - Cross-chain coverage parity (AAVE Pool/Oracle/Gateway all cover the same chain set; Uniswap Router/Factory match) EOF --- .github/workflows/ci.yml | 47 ++ .gitignore | 32 + LICENSE | 21 + README.md | 165 ++++- package.json | 71 +++ src/chains.ts | 18 + src/index.ts | 15 + src/protocols/aave-v3.ts | 242 +++++++ src/protocols/aerodrome.ts | 13 + src/protocols/chainlink.ts | 30 + src/protocols/common.ts | 80 +++ src/protocols/compound-v3.ts | 19 + src/protocols/erc20.ts | 21 + src/protocols/ethena.ts | 64 ++ src/protocols/frax-ether.ts | 25 + src/protocols/index.ts | 86 +++ src/protocols/lido.ts | 50 ++ src/protocols/morpho.ts | 94 +++ src/protocols/rocket-pool.ts | 41 ++ src/protocols/sky.ts | 17 + src/protocols/spark.ts | 19 + src/protocols/superfluid.ts | 44 ++ src/protocols/types.ts | 29 + src/protocols/uniswap-v3.ts | 209 ++++++ src/protocols/wrapped.ts | 60 ++ tests/catalog.test.ts | 181 ++++++ tsconfig.build.json | 13 + tsconfig.json | 23 + yarn.lock | 1161 ++++++++++++++++++++++++++++++++++ 29 files changed, 2889 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 package.json create mode 100644 src/chains.ts create mode 100644 src/index.ts create mode 100644 src/protocols/aave-v3.ts create mode 100644 src/protocols/aerodrome.ts create mode 100644 src/protocols/chainlink.ts create mode 100644 src/protocols/common.ts create mode 100644 src/protocols/compound-v3.ts create mode 100644 src/protocols/erc20.ts create mode 100644 src/protocols/ethena.ts create mode 100644 src/protocols/frax-ether.ts create mode 100644 src/protocols/index.ts create mode 100644 src/protocols/lido.ts create mode 100644 src/protocols/morpho.ts create mode 100644 src/protocols/rocket-pool.ts create mode 100644 src/protocols/sky.ts create mode 100644 src/protocols/spark.ts create mode 100644 src/protocols/superfluid.ts create mode 100644 src/protocols/types.ts create mode 100644 src/protocols/uniswap-v3.ts create mode 100644 src/protocols/wrapped.ts create mode 100644 tests/catalog.test.ts create mode 100644 tsconfig.build.json create mode 100644 tsconfig.json create mode 100644 yarn.lock diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2dc46d1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,47 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + name: Test on Node ${{ matrix.node }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node: [18, 20, 22] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node ${{ matrix.node }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: yarn + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Typecheck + run: yarn typecheck + + - name: Run tests + run: yarn test:run + + - name: Build + run: yarn build + + - name: Verify tarball contents + # Pack a dry-run tarball and assert the dist surface is intact. + # Catches: missing dist files in `files`, broken exports map. + run: | + npm pack --dry-run + test -f dist/index.js + test -f dist/index.mjs + test -f dist/index.d.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..996926c --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Build output +dist/ +*.tsbuildinfo + +# Dependencies +node_modules/ + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Environment +.env +.env.local +.env.*.local + +# Editor / OS +.DS_Store +.vscode/ +.idea/ +*.swp +*.swo + +# Coverage +coverage/ +.nyc_output/ + +# npm +*.tgz +.npmrc diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6bcd898 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Ava Protocol + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 4d9e64d..6a729f8 100644 --- a/README.md +++ b/README.md @@ -1 +1,164 @@ -# protocols +# @avaprotocol/protocols + +[![npm](https://img.shields.io/npm/v/@avaprotocol/protocols?color=blue)](https://www.npmjs.com/package/@avaprotocol/protocols) +[![CI](https://github.com/AvaProtocol/protocols/actions/workflows/ci.yml/badge.svg)](https://github.com/AvaProtocol/protocols/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) + +Multi-chain catalog of DeFi protocol contract addresses, ABI fragments, and event topic hashes. Curated for callers who need a canonical reference without re-deriving constants or re-vendoring protocol SDKs. + +```ts +import { Protocols, Chains } from "@avaprotocol/protocols"; + +const pool = Protocols.aaveV3.pool[Chains.Sepolia]; +// → "0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951" + +const abi = Protocols.uniswapV3.swapRouter02Abi; +// → readonly AbiFragment[] with exactInputSingle + exactOutputSingle + +const sig = Protocols.aaveV3.eventTopics.Borrow; +// → keccak256("Borrow(address,address,address,uint256,uint8,uint256,uint16)") +``` + +## What's covered + +| Protocol | Contracts | Chains | +|---|---|---| +| **AAVE V3** | Pool, Oracle, WETH Gateway + Pool methods/events ABI + topics | Mainnet, Sepolia, Base, Base Sepolia | +| **Aerodrome** | Router | Base | +| **Chainlink** | ETH/USD + BTC/USD feeds + AggregatorV3 ABI | Mainnet, Sepolia | +| **Compound V3** | USDC Comet market | Mainnet, Base | +| **Ethena** | USDe, sUSDe vault + custom (cooldown-aware) ABI | Mainnet | +| **Frax Ether** | frxETH, sfrxETH vault + standard ERC-4626 ABI | Mainnet | +| **Lido** | stETH, wstETH + L1 wrap/unwrap/rate ABI | Mainnet, Base (wstETH bridged) | +| **Morpho Blue** | Singleton + MarketParams-tuple supply/borrow/position ABI | Mainnet, Base | +| **Rocket Pool** | rETH + L1 burn/rate/value ABI | Mainnet, Base (bridged) | +| **Sky (sDAI)** | sDAI vault + standard ERC-4626 ABI | Mainnet | +| **Spark** | SparkLend Pool (AAVE V3 fork — reuse AAVE Pool ABI) | Mainnet | +| **Superfluid** | CFAv1Forwarder + setFlowrate/createFlow ABI | Mainnet, Base | +| **Uniswap V3** | SwapRouter02, QuoterV2, Permit2, Factory, NFT Position Manager, Universal Router + ABIs | Mainnet, Sepolia, Base, Base Sepolia | +| **Wrapped Ether** | WETH per chain + WETH9 ABI | Mainnet, Sepolia, Base, Base Sepolia | +| **ERC-20** | Standard `approve` ABI fragment | n/a | + +Shared ABIs (consumed by multiple protocol modules): + +- `aggregatorV3Abi` — any Chainlink-compatible price feed +- `erc4626VaultAbi` — standard ERC-4626 vault (used by Frax Ether sfrxETH, Sky sDAI) + +## Install + +```sh +yarn add @avaprotocol/protocols +# or +npm install @avaprotocol/protocols +# or +pnpm add @avaprotocol/protocols +``` + +Works with Node 18+, modern bundlers, and any TypeScript 4.7+ consumer. Ships dual CJS + ESM with full `.d.ts`. + +## Usage patterns + +### Pin an address by chain + +```ts +import { Protocols, Chains } from "@avaprotocol/protocols"; + +const linkOnSepolia = Protocols.aaveV3.tokens.LINK[Chains.Sepolia]!; +// "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5" +``` + +`Partial>` is the catalog's keying convention — every protocol declares which chains it covers. Use the non-null assertion (`!`) only when you're sure the chain is covered, or guard with `if`. + +### Compose a contract write + +```ts +import { Protocols, Chains } from "@avaprotocol/protocols"; + +await wallet.contractWrite({ + contractAddress: Protocols.aaveV3.pool[Chains.Sepolia]!, + contractAbi: Protocols.aaveV3.poolMethodsAbi, + methodCalls: [ + { + methodName: "supply", + methodParams: [ + Protocols.aaveV3.tokens.LINK[Chains.Sepolia]!, + "100000000000000000", // 0.1 LINK + wallet.address, + "0", // referralCode + ], + }, + ], +}); +``` + +### Filter on an event topic + +```ts +import { Protocols } from "@avaprotocol/protocols"; + +const filter = { + address: Protocols.aaveV3.pool[Chains.Sepolia], + topics: [ + Protocols.aaveV3.eventTopics.Borrow, + null, // any reserve + padAddress(eoa), // onBehalfOf = my EOA + ], +}; +``` + +### Address lookups by `(chainId, address)` + +For consumers that need to *recognize* an address rather than look it up by name (e.g. transaction interpreters), iterate the registry directly: + +```ts +import { Protocols, Chains } from "@avaprotocol/protocols"; + +function isAaveV3Pool(chainId: number, address: string): boolean { + const expected = Protocols.aaveV3.pool[chainId]; + return !!expected && expected.toLowerCase() === address.toLowerCase(); +} +``` + +(A first-class reverse-lookup helper may ship later; the data shape already supports it.) + +## Design + +Three principles drive what's in vs. what's out: + +1. **Static, on-chain-public data only.** Addresses, ABI fragments, event topic hashes, well-known token references. No private/embargoed protocol addresses; no RPC URLs, API keys, or credentials. +2. **No UI metadata.** Per-action labels, descriptions, slugs, capability tags belong to each consumer's UX layer. This keeps the package tree-shakeable, language-agnostic, and reusable across web UIs, server-side indexers, partner SDKs, and CLI tooling. +3. **Curated ABI fragments, not full ABIs.** Each protocol module ships only the methods + events callers routinely touch (e.g., AAVE Pool's `supply`/`borrow`/`repay`/`withdraw` + the 5 monitorable events, not the full ~80-method ABI). Keeps the bundle small and the API surface reviewable. Need a method not in the catalog? Open a PR — adding one fragment is a small diff. + +## Comparison with adjacent projects + +| Project | Scope | This catalog's delta | +|---|---|---| +| [`@bgd-labs/aave-address-book`](https://github.com/bgd-labs/aave-address-book) | AAVE-only, exhaustive | Spans 14+ protocols. Borrows the shape + governance model. | +| [`@uniswap/sdk-core`](https://github.com/Uniswap/sdk-core) | Uniswap-only, addresses + math primitives | We ship Uniswap as one entry; don't duplicate the math. | +| [`blockchain-addressbook`](https://github.com/beefyfinance/address-book) | Multi-protocol, Beefy-opinionated | Includes ABI fragments + event topics; not Beefy-vault-shaped. | +| [Uniswap TokenLists](https://tokenlists.org/) | Tokens only, standardized schema | Complementary — we ship protocol contracts; you bring your own token list. | + +There's no equivalent multi-protocol + multi-chain + addresses + ABIs + topics package in the npm ecosystem today, so this fills a gap. See `tests/catalog.test.ts` for shape guarantees. + +## Adding a new protocol + +1. Create `src/protocols/.ts` with the per-chain address maps, ABI fragments, and event topics following the existing modules as templates (`aave-v3.ts` is the most complete example). +2. Wire it through `src/protocols/index.ts` — add the import, the re-export, and the entry in the `Protocols.*` namespace. +3. Add the entry to the supported-protocols table in this README + to the `it("exports every shipped protocol", ...)` test. +4. Open a PR — CI runs typecheck + tests + build + tarball verification across Node 18/20/22. + +Address verification: link to the canonical source (Etherscan-verified deployment, protocol docs, official address book). PRs that don't cite a source for the addresses won't merge. + +## Versioning + +Semver. Until `1.0.0`, breaking changes can land in minor versions (`0.x`), but address corrections are always patches. + +- **Patch (`0.1.x`)** — address corrections, bug fixes, doc-only changes. +- **Minor (`0.x.0`)** — new protocols, new chains, additive ABI fragments. +- **Major (`x.0.0`)** — renames, restructures, breaking removals. + +The `dev` npm tag tracks the latest pre-release; `latest` stays on stable. + +## License + +MIT — see [LICENSE](LICENSE). diff --git a/package.json b/package.json new file mode 100644 index 0000000..e0986bd --- /dev/null +++ b/package.json @@ -0,0 +1,71 @@ +{ + "name": "@avaprotocol/protocols", + "version": "0.1.0", + "description": "Multi-chain catalog of DeFi protocol contract addresses, ABI fragments, and event topic hashes — covers AAVE V3, Uniswap V3, Chainlink, Lido, Morpho, and more.", + "keywords": [ + "defi", + "ethereum", + "smart-contracts", + "abi", + "addresses", + "aave", + "uniswap", + "chainlink", + "lido", + "morpho", + "multi-chain", + "typescript" + ], + "homepage": "https://github.com/AvaProtocol/protocols#readme", + "bugs": { + "url": "https://github.com/AvaProtocol/protocols/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/AvaProtocol/protocols.git" + }, + "license": "MIT", + "author": "Ava Protocol", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + }, + "./package.json": "./package.json" + }, + "files": [ + "dist", + "README.md", + "CHANGELOG.md", + "LICENSE" + ], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build:declarations": "tsc -p tsconfig.build.json", + "build:js": "tsup src/index.ts --format cjs,esm --target es2020", + "build": "yarn clean:dist && yarn build:declarations && yarn build:js", + "clean": "rm -rf node_modules dist tsconfig.tsbuildinfo", + "clean:dist": "rm -rf dist tsconfig.tsbuildinfo", + "test": "vitest", + "test:run": "vitest run", + "typecheck": "tsc --noEmit", + "lint": "tsc --noEmit", + "prepublishOnly": "yarn build" + }, + "devDependencies": { + "tsup": "^8.5.0", + "typescript": "^5.5.4", + "vitest": "^1.6.0" + }, + "engines": { + "node": ">=18" + }, + "packageManager": "yarn@1.22.19" +} diff --git a/src/chains.ts b/src/chains.ts new file mode 100644 index 0000000..ef7d083 --- /dev/null +++ b/src/chains.ts @@ -0,0 +1,18 @@ +// Chain ID constants used as the keying convention across this +// catalog. Every per-protocol address map is keyed by these integer +// constants so callers can write `Protocols.aaveV3.pool[Chains.Sepolia]` +// instead of remembering magic numbers. +// +// IDs follow EIP-155. Add a new entry when extending the catalog to a +// chain — the catalog's per-protocol modules each declare which +// chains they cover with `Partial>`. + +export const Chains = Object.freeze({ + EthereumMainnet: 1 as const, + Sepolia: 11_155_111 as const, + Holesky: 17_000 as const, + BaseMainnet: 8453 as const, + BaseSepolia: 84_532 as const, +}); + +export type ChainId = (typeof Chains)[keyof typeof Chains] | number; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..fecf6b6 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,15 @@ +// @avaprotocol/protocols — multi-chain catalog of DeFi protocol +// contract addresses, ABI fragments, and event topic hashes. +// +// Usage: +// +// import { Protocols, Chains } from "@avaprotocol/protocols"; +// +// const pool = Protocols.aaveV3.pool[Chains.Sepolia]; +// const abi = Protocols.uniswapV3.swapRouter02Abi; +// const sig = Protocols.aaveV3.eventTopics.Borrow; +// +// See README.md for the full list of supported protocols + chains. + +export * from "./protocols"; +export { Chains, type ChainId } from "./chains"; diff --git a/src/protocols/aave-v3.ts b/src/protocols/aave-v3.ts new file mode 100644 index 0000000..6eb7d0b --- /dev/null +++ b/src/protocols/aave-v3.ts @@ -0,0 +1,242 @@ +// AAVE V3 — Pool / Oracle / WETH Gateway addresses per supported +// chain, the Pool ABI fragments (events + the read/write methods +// callers actually touch), and event-topic hashes. +// +// Pool is the single entry point templates target (supply, borrow, +// repay, withdraw, getUserAccountData, setUserUseReserveAsCollateral) +// and the contract whose events templates filter on (`Supply`, +// `Borrow`, etc.). +// +// Address source: AAVE V3 deployment registries +// (https://github.com/bgd-labs/aave-address-book). When AAVE +// redeploys on a new chain, mirror the canonical address book. + +import { Chains } from "../chains"; +import { type AbiFragment, type AddressByChain } from "./types"; + +/** + * AAVE V3 Pool addresses per chain. The Pool is the single entry point + * for supply / borrow / repay / withdraw / liquidationCall and is the + * contract whose events templates filter on (`Supply`, `Borrow`, etc.). + */ +const pool: AddressByChain = { + [Chains.EthereumMainnet]: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", + [Chains.Sepolia]: "0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951", + [Chains.BaseMainnet]: "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5", + [Chains.BaseSepolia]: "0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27", +}; + +/** + * Aave Oracle — the price feed used by Pool to value collateral and + * debt. Templates that derive health-factor-equivalent metrics off + * chain can hit this directly to avoid a Pool round-trip. + */ +const oracle: AddressByChain = { + [Chains.EthereumMainnet]: "0x54586bE62E3c3580375aE3723C145253060Ca0C2", + [Chains.Sepolia]: "0x2da88497588bf89281816106C7259e31AF45a663", + [Chains.BaseMainnet]: "0x2Cc0Fc26eD4563A5ce5e8bdcfe1A2878676Ae156", + [Chains.BaseSepolia]: "0x943b0dE18d4abf4eF02A85912F8fc07684C141dF", +}; + +/** + * WETH gateway — wraps native ETH supplies so Pool can hold WETH as + * the reserve. Templates that supply native ETH (rather than an + * already-wrapped token) go through here instead of Pool directly. + */ +const wethGateway: AddressByChain = { + [Chains.EthereumMainnet]: "0xd01607c3C5eCABa394D8be377a08590149325722", + [Chains.Sepolia]: "0x387d311e47e80b498169e6fb51d3193167d89F7D", + [Chains.BaseMainnet]: "0xa0d9C1E9E48Ca30c8d8C3B5D69FF5dc1f6DFfC24", + [Chains.BaseSepolia]: "0x0568130e794429D2eEBC4dafE18f25Ff1a1ed8b6", +}; + +/** + * Pre-computed keccak256 of the canonical event signatures. Cheaper + * than recomputing per-call and stable across deployments. Match + * topics[0] on `eventTrigger` queries against these. + */ +const eventTopics = Object.freeze({ + Supply: "0x2b627736bca15cd5381dcf80b0bf11fd197d01a037c52b927a881a10fb73ba61", + Withdraw: "0x3115d1449a7b732c986cba18244e897a450f61e1bb8d589cd2e69e6c8924f9f7", + Borrow: "0xb3d084820fb1a9decffb176436bd02558d15fac9b0ddfed8c465bc7359d7dce0", + Repay: "0xa534c8dbe71f871f9f3530e97a74601fea17b426cae02e1c5aee42c96c784051", + LiquidationCall: "0xe413a321e8681d831f4dbccbca790d2952b56f977908e45be37335533e005286", +} as const); + +/** + * Pool event ABI — Supply / Withdraw / Borrow / Repay / LiquidationCall. + * Used by `eventTrigger` queries to decode topic data so downstream + * nodes can reference `reserve`, `amount`, `onBehalfOf`, etc. by name. + */ +const poolEventsAbi: readonly AbiFragment[] = Object.freeze([ + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "reserve", type: "address" }, + { indexed: false, internalType: "address", name: "user", type: "address" }, + { indexed: true, internalType: "address", name: "onBehalfOf", type: "address" }, + { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, + { indexed: true, internalType: "uint16", name: "referralCode", type: "uint16" }, + ], + name: "Supply", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "reserve", type: "address" }, + { indexed: true, internalType: "address", name: "user", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "Withdraw", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "reserve", type: "address" }, + { indexed: false, internalType: "address", name: "user", type: "address" }, + { indexed: true, internalType: "address", name: "onBehalfOf", type: "address" }, + { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, + { indexed: false, internalType: "uint8", name: "interestRateMode", type: "uint8" }, + { indexed: false, internalType: "uint256", name: "borrowRate", type: "uint256" }, + { indexed: true, internalType: "uint16", name: "referralCode", type: "uint16" }, + ], + name: "Borrow", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "reserve", type: "address" }, + { indexed: true, internalType: "address", name: "user", type: "address" }, + { indexed: true, internalType: "address", name: "repayer", type: "address" }, + { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, + { indexed: false, internalType: "bool", name: "useATokens", type: "bool" }, + ], + name: "Repay", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "collateralAsset", type: "address" }, + { indexed: true, internalType: "address", name: "debtAsset", type: "address" }, + { indexed: true, internalType: "address", name: "user", type: "address" }, + { indexed: false, internalType: "uint256", name: "debtToCover", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "liquidatedCollateralAmount", type: "uint256" }, + { indexed: false, internalType: "address", name: "liquidator", type: "address" }, + { indexed: false, internalType: "bool", name: "receiveAToken", type: "bool" }, + ], + name: "LiquidationCall", + type: "event", + }, +]); + +/** + * Pool method ABI — the read + write surface templates routinely call: + * `getUserAccountData` (account health), `supply`, `borrow`, `repay`, + * `withdraw`, and `setUserUseReserveAsCollateral`. Raw ABI so any + * `contractRead`/`contractWrite` consumer can plug it in directly. + */ +const poolMethodsAbi: readonly AbiFragment[] = Object.freeze([ + { + inputs: [{ internalType: "address", name: "user", type: "address" }], + name: "getUserAccountData", + outputs: [ + { internalType: "uint256", name: "totalCollateralBase", type: "uint256" }, + { internalType: "uint256", name: "totalDebtBase", type: "uint256" }, + { internalType: "uint256", name: "availableBorrowsBase", type: "uint256" }, + { internalType: "uint256", name: "currentLiquidationThreshold", type: "uint256" }, + { internalType: "uint256", name: "ltv", type: "uint256" }, + { internalType: "uint256", name: "healthFactor", type: "uint256" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "asset", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "address", name: "onBehalfOf", type: "address" }, + { internalType: "uint16", name: "referralCode", type: "uint16" }, + ], + name: "supply", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "asset", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "uint256", name: "interestRateMode", type: "uint256" }, + { internalType: "uint16", name: "referralCode", type: "uint16" }, + { internalType: "address", name: "onBehalfOf", type: "address" }, + ], + name: "borrow", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "asset", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "uint256", name: "interestRateMode", type: "uint256" }, + { internalType: "address", name: "onBehalfOf", type: "address" }, + ], + name: "repay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "asset", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "address", name: "to", type: "address" }, + ], + name: "withdraw", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "asset", type: "address" }, + { internalType: "bool", name: "useAsCollateral", type: "bool" }, + ], + name: "setUserUseReserveAsCollateral", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +]); + +/** + * Per-chain reserve token addresses for the assets AAVE V3 markets + * keep available across chains. Mainly used by template tests that + * need a known faucet-mintable token to drive supply/borrow flows + * against the live testnet markets. Extend per chain as more reserves + * become test-relevant. + * + * NOTE: the Sepolia LINK here is AAVE's *faucet-mintable test token* + * wired into the Sepolia market, not mainnet ChainLink LINK. + */ +const tokens = Object.freeze({ + LINK: { + [Chains.Sepolia]: "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5", + } satisfies AddressByChain, +}); + +export const aaveV3 = Object.freeze({ + pool, + oracle, + wethGateway, + eventTopics, + poolEventsAbi, + poolMethodsAbi, + tokens, +}); diff --git a/src/protocols/aerodrome.ts b/src/protocols/aerodrome.ts new file mode 100644 index 0000000..bbca66b --- /dev/null +++ b/src/protocols/aerodrome.ts @@ -0,0 +1,13 @@ +// Aerodrome — Base-native AMM (Velodrome V2 fork). Base-only. +// Swaps route through `Route` hops (from, to, stable, factory). + +import { Chains } from "../chains"; +import { type AddressByChain } from "./types"; + +const router: AddressByChain = { + [Chains.BaseMainnet]: "0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43", +}; + +export const aerodrome = Object.freeze({ + router, +}); diff --git a/src/protocols/chainlink.ts b/src/protocols/chainlink.ts new file mode 100644 index 0000000..c9da447 --- /dev/null +++ b/src/protocols/chainlink.ts @@ -0,0 +1,30 @@ +// Chainlink Data Feeds — AggregatorV3Interface price oracles. +// +// The ABI for every Chainlink Data Feed is the same (AggregatorV3 +// Interface), so it lives in `./common.ts` as `aggregatorV3Abi` and +// every feed entry below reuses it. The catalog ships ETH/USD + +// BTC/USD on mainnet plus ETH/USD on Sepolia by default. Extend +// with additional feeds (LINK/USD, EUR/USD, etc.) as needed. +// +// Canonical feed addresses: +// https://docs.chain.link/data-feeds/price-feeds/addresses + +import { Chains } from "../chains"; +import { aggregatorV3Abi } from "./common"; +import { type AddressByChain } from "./types"; + +const ethUsdFeed: AddressByChain = { + [Chains.EthereumMainnet]: "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419", + [Chains.Sepolia]: "0x694AA1769357215DE4FAC081bf1f309aDC325306", +}; + +const btcUsdFeed: AddressByChain = { + [Chains.EthereumMainnet]: "0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c", +}; + +export const chainlink = Object.freeze({ + ethUsdFeed, + btcUsdFeed, + /** Shared AggregatorV3 ABI — works for any Chainlink feed. */ + aggregatorV3Abi, +}); diff --git a/src/protocols/common.ts b/src/protocols/common.ts new file mode 100644 index 0000000..b06e7bd --- /dev/null +++ b/src/protocols/common.ts @@ -0,0 +1,80 @@ +// Shared ABI fragments that more than one protocol routinely reuses: +// - AggregatorV3Interface for any Chainlink-compatible price feed +// - ERC-4626 deposit/redeem for staking vaults (sUSDe, sfrxETH, sDAI, ...) +// - ERC-20 approve already lives in `./erc20.ts` — keep that import path +// stable since it's the most-touched fragment in the catalog. + +import { type AbiFragment } from "./types"; + +/** + * Chainlink AggregatorV3Interface — `latestRoundData` and `decimals`. + * Every Chainlink Data Feed contract implements this, so the same ABI + * works for ETH/USD, BTC/USD, LINK/USD, etc. + */ +export const aggregatorV3Abi: readonly AbiFragment[] = Object.freeze([ + { + inputs: [], + name: "latestRoundData", + outputs: [ + { internalType: "uint80", name: "roundId", type: "uint80" }, + { internalType: "int256", name: "answer", type: "int256" }, + { internalType: "uint256", name: "startedAt", type: "uint256" }, + { internalType: "uint256", name: "updatedAt", type: "uint256" }, + { internalType: "uint80", name: "answeredInRound", type: "uint80" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, +]); + +/** + * Minimal ERC-4626 vault ABI — `deposit`, `redeem`, `previewRedeem`, + * `convertToAssets`. Sufficient for staking vault templates that wrap + * an underlying into a yield-bearing share token (sfrxETH, sDAI, etc.). + * Vaults with non-standard write paths (e.g. sUSDe's cooldown + + * unstake) ship their own ABI in their own protocol module. + */ +export const erc4626VaultAbi: readonly AbiFragment[] = Object.freeze([ + { + inputs: [ + { internalType: "uint256", name: "assets", type: "uint256" }, + { internalType: "address", name: "receiver", type: "address" }, + ], + name: "deposit", + outputs: [{ internalType: "uint256", name: "shares", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "shares", type: "uint256" }, + { internalType: "address", name: "receiver", type: "address" }, + { internalType: "address", name: "owner", type: "address" }, + ], + name: "redeem", + outputs: [{ internalType: "uint256", name: "assets", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "shares", type: "uint256" }], + name: "previewRedeem", + outputs: [{ internalType: "uint256", name: "assets", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "shares", type: "uint256" }], + name: "convertToAssets", + outputs: [{ internalType: "uint256", name: "assets", type: "uint256" }], + stateMutability: "view", + type: "function", + }, +]); diff --git a/src/protocols/compound-v3.ts b/src/protocols/compound-v3.ts new file mode 100644 index 0000000..c11ef84 --- /dev/null +++ b/src/protocols/compound-v3.ts @@ -0,0 +1,19 @@ +// Compound V3 (Comet) — USDC base market. +// +// Comet bundles supply/borrow on a single contract: `supply` / +// `withdraw` move the base asset (USDC, 6 decimals) or collateral; +// `withdraw` past zero opens a borrow. +// +// Canonical addresses: https://docs.compound.finance/#networks + +import { Chains } from "../chains"; +import { type AddressByChain } from "./types"; + +const cometUsdc: AddressByChain = { + [Chains.EthereumMainnet]: "0xc3d688B66703497DAA19211EEdff47f25384cdc3", + [Chains.BaseMainnet]: "0xb125E6687d4313864e53df431d5425969c15Eb2F", +}; + +export const compoundV3 = Object.freeze({ + cometUsdc, +}); diff --git a/src/protocols/erc20.ts b/src/protocols/erc20.ts new file mode 100644 index 0000000..152e71c --- /dev/null +++ b/src/protocols/erc20.ts @@ -0,0 +1,21 @@ +// Minimal ERC-20 ABI fragments that templates routinely need but don't +// belong to any one protocol. `approveAbi` is the standard 2-arg ERC-20 +// approve — used by any DeFi flow that funnels tokens through a protocol's +// pool/router (AAVE.supply, Uniswap.swap, etc.). + +import { type AbiFragment } from "./types"; + +export const erc20 = Object.freeze({ + approveAbi: Object.freeze([ + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "approve", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + ]) as readonly AbiFragment[], +}); diff --git a/src/protocols/ethena.ts b/src/protocols/ethena.ts new file mode 100644 index 0000000..a02045b --- /dev/null +++ b/src/protocols/ethena.ts @@ -0,0 +1,64 @@ +// Ethena — USDe synthetic dollar + sUSDe staking vault. +// +// sUSDe (StakedUSDeV2) is ERC-4626-shaped on the deposit side but +// gates withdrawals behind a cooldown: redemption is a two-step +// `cooldownShares` → `unstake` flow, NOT a direct ERC-4626 redeem. +// So we ship a custom ABI rather than reusing `common.erc4626VaultAbi`. + +import { Chains } from "../chains"; +import { type AbiFragment, type AddressByChain } from "./types"; + +const susde: AddressByChain = { + [Chains.EthereumMainnet]: "0x9D39A5DE30e57443BfF2A8307A4256c8797A3497", +}; + +const usde: AddressByChain = { + [Chains.EthereumMainnet]: "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3", +}; + +const susdeAbi: readonly AbiFragment[] = Object.freeze([ + { + inputs: [ + { internalType: "uint256", name: "assets", type: "uint256" }, + { internalType: "address", name: "receiver", type: "address" }, + ], + name: "deposit", + outputs: [{ internalType: "uint256", name: "shares", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "shares", type: "uint256" }], + name: "cooldownShares", + outputs: [{ internalType: "uint256", name: "assets", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "receiver", type: "address" }], + name: "unstake", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "shares", type: "uint256" }], + name: "previewRedeem", + outputs: [{ internalType: "uint256", name: "assets", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "shares", type: "uint256" }], + name: "convertToAssets", + outputs: [{ internalType: "uint256", name: "assets", type: "uint256" }], + stateMutability: "view", + type: "function", + }, +]); + +export const ethena = Object.freeze({ + susde, + usde, + susdeAbi, +}); diff --git a/src/protocols/frax-ether.ts b/src/protocols/frax-ether.ts new file mode 100644 index 0000000..348af3e --- /dev/null +++ b/src/protocols/frax-ether.ts @@ -0,0 +1,25 @@ +// Frax Ether — frxETH (the L1 liquid token) + sfrxETH (the ERC-4626 +// staking vault that distributes validator yield to depositors). +// +// sfrxETH is a standard ERC-4626 vault — deposit/redeem/previewRedeem/ +// convertToAssets all live in `common.erc4626VaultAbi`. We just need +// to surface the addresses. + +import { Chains } from "../chains"; +import { erc4626VaultAbi } from "./common"; +import { type AddressByChain } from "./types"; + +const sfrxeth: AddressByChain = { + [Chains.EthereumMainnet]: "0xac3E018457B222d93114458476f3E3416Abbe38F", +}; + +const frxeth: AddressByChain = { + [Chains.EthereumMainnet]: "0x5E8422345238F34275888049021821E8E08CAa1f", +}; + +export const fraxEther = Object.freeze({ + sfrxeth, + frxeth, + /** Standard ERC-4626 surface — sfrxETH conforms exactly. */ + vaultAbi: erc4626VaultAbi, +}); diff --git a/src/protocols/index.ts b/src/protocols/index.ts new file mode 100644 index 0000000..352e472 --- /dev/null +++ b/src/protocols/index.ts @@ -0,0 +1,86 @@ +// Protocols — data-only DeFi catalog. Per-protocol per-chain contract +// addresses, ABI fragments, and event-topic hashes that template +// authors, partner SDKs, and on-chain interpreters need without +// re-deriving or duplicating the same constants across consumers. +// +// Each protocol module ships: +// - Per-chain address maps keyed by `Chains.*` integer constants +// - ABI fragments (just the methods + events consumers actually +// touch — not full protocol ABIs) +// - Event-topic hashes (keccak256 of canonical event signatures) +// - Reference token addresses where relevant +// +// Scope: only the static, on-chain-public data. Higher-level UI +// metadata (per-action labels, descriptions, capabilities) belongs to +// each consumer's UX layer, not here. Keeps the package tree-shake- +// able and language-agnostic — the same JSON is reusable from a +// Python or Rust mirror. + +export { aaveV3 } from "./aave-v3"; +export { aerodrome } from "./aerodrome"; +export { chainlink } from "./chainlink"; +export { compoundV3 } from "./compound-v3"; +export { erc20 } from "./erc20"; +export { ethena } from "./ethena"; +export { fraxEther } from "./frax-ether"; +export { lido } from "./lido"; +export { morphoBlue } from "./morpho"; +export { rocketPool } from "./rocket-pool"; +export { sky } from "./sky"; +export { spark } from "./spark"; +export { superfluid } from "./superfluid"; +export { uniswapV3 } from "./uniswap-v3"; +export { wrapped } from "./wrapped"; +export { aggregatorV3Abi, erc4626VaultAbi } from "./common"; +export type { AbiFragment, AddressByChain } from "./types"; + +import { aaveV3 } from "./aave-v3"; +import { aerodrome } from "./aerodrome"; +import { chainlink } from "./chainlink"; +import { compoundV3 } from "./compound-v3"; +import { erc20 } from "./erc20"; +import { ethena } from "./ethena"; +import { fraxEther } from "./frax-ether"; +import { lido } from "./lido"; +import { morphoBlue } from "./morpho"; +import { rocketPool } from "./rocket-pool"; +import { sky } from "./sky"; +import { spark } from "./spark"; +import { superfluid } from "./superfluid"; +import { uniswapV3 } from "./uniswap-v3"; +import { wrapped } from "./wrapped"; + +/** + * Namespaced catalog handle: + * + * import { Protocols, Chains } from "@avaprotocol/protocols"; + * const pool = Protocols.aaveV3.pool[Chains.Sepolia]; + * const abi = Protocols.uniswapV3.swapRouter02Abi; + * + * Protocol property naming maps each protocol's canonical slug to a + * lowerCamelCase property: + * aave-v3 → aaveV3 + * compound-v3 → compoundV3 + * frax-ether → fraxEther + * morpho → morphoBlue (the singleton's product name) + * rocket-pool → rocketPool + * uniswap-v3 → uniswapV3 + * (others) → same as slug, hyphen → camelCase + */ +export const Protocols = Object.freeze({ + aaveV3, + aerodrome, + chainlink, + compoundV3, + erc20, + ethena, + fraxEther, + lido, + morphoBlue, + rocketPool, + sky, + spark, + superfluid, + uniswapV3, + wrapped, +}); diff --git a/src/protocols/lido.ts b/src/protocols/lido.ts new file mode 100644 index 0000000..ac562fc --- /dev/null +++ b/src/protocols/lido.ts @@ -0,0 +1,50 @@ +// Lido — stETH (L1 rebasing) + wstETH (wrapped). Wrap/unwrap only +// exist on the L1 wstETH contract; the Base wstETH entry is a +// bridged ERC-20 and supports standard ERC-20 transfers / approvals +// only. stETH is not bridged to Base. + +import { Chains } from "../chains"; +import { type AbiFragment, type AddressByChain } from "./types"; + +const wsteth: AddressByChain = { + [Chains.EthereumMainnet]: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + [Chains.BaseMainnet]: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452", +}; + +const steth: AddressByChain = { + [Chains.EthereumMainnet]: "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", +}; + +/** + * wstETH wrap/unwrap + getStETHByWstETH read. L1-only — calls against + * the Base bridged token revert. + */ +const wstethAbi: readonly AbiFragment[] = Object.freeze([ + { + inputs: [{ internalType: "uint256", name: "_stETHAmount", type: "uint256" }], + name: "wrap", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_wstETHAmount", type: "uint256" }], + name: "unwrap", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_wstETHAmount", type: "uint256" }], + name: "getStETHByWstETH", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, +]); + +export const lido = Object.freeze({ + wsteth, + steth, + wstethAbi, +}); diff --git a/src/protocols/morpho.ts b/src/protocols/morpho.ts new file mode 100644 index 0000000..57d590e --- /dev/null +++ b/src/protocols/morpho.ts @@ -0,0 +1,94 @@ +// Morpho Blue — permissionless lending singleton. Same address on +// every supported chain. Every market is addressed by a `MarketParams` +// tuple (loanToken, collateralToken, oracle, irm, lltv); lending calls +// pass that struct plus an amount in either `assets` or `shares` +// (one is zero). + +import { Chains } from "../chains"; +import { type AbiFragment, type AddressByChain } from "./types"; + +const morpho: AddressByChain = { + [Chains.EthereumMainnet]: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb", + [Chains.BaseMainnet]: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb", +}; + +/** + * Morpho Blue minimal write+read surface. Each write takes the full + * `MarketParams` tuple as the first argument; the `data` callback + * bytes default to `0x` in template usage. + */ +const morphoAbi: readonly AbiFragment[] = Object.freeze([ + { + inputs: [ + { + components: [ + { internalType: "address", name: "loanToken", type: "address" }, + { internalType: "address", name: "collateralToken", type: "address" }, + { internalType: "address", name: "oracle", type: "address" }, + { internalType: "address", name: "irm", type: "address" }, + { internalType: "uint256", name: "lltv", type: "uint256" }, + ], + internalType: "struct MarketParams", + name: "marketParams", + type: "tuple", + }, + { internalType: "uint256", name: "assets", type: "uint256" }, + { internalType: "uint256", name: "shares", type: "uint256" }, + { internalType: "address", name: "onBehalf", type: "address" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "supply", + outputs: [ + { internalType: "uint256", name: "assetsSupplied", type: "uint256" }, + { internalType: "uint256", name: "sharesSupplied", type: "uint256" }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "loanToken", type: "address" }, + { internalType: "address", name: "collateralToken", type: "address" }, + { internalType: "address", name: "oracle", type: "address" }, + { internalType: "address", name: "irm", type: "address" }, + { internalType: "uint256", name: "lltv", type: "uint256" }, + ], + internalType: "struct MarketParams", + name: "marketParams", + type: "tuple", + }, + { internalType: "uint256", name: "assets", type: "uint256" }, + { internalType: "uint256", name: "shares", type: "uint256" }, + { internalType: "address", name: "onBehalf", type: "address" }, + { internalType: "address", name: "receiver", type: "address" }, + ], + name: "borrow", + outputs: [ + { internalType: "uint256", name: "assetsBorrowed", type: "uint256" }, + { internalType: "uint256", name: "sharesBorrowed", type: "uint256" }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "id", type: "bytes32" }, + { internalType: "address", name: "user", type: "address" }, + ], + name: "position", + outputs: [ + { internalType: "uint256", name: "supplyShares", type: "uint256" }, + { internalType: "uint128", name: "borrowShares", type: "uint128" }, + { internalType: "uint128", name: "collateral", type: "uint128" }, + ], + stateMutability: "view", + type: "function", + }, +]); + +export const morphoBlue = Object.freeze({ + morpho, + morphoAbi, +}); diff --git a/src/protocols/rocket-pool.ts b/src/protocols/rocket-pool.ts new file mode 100644 index 0000000..390c37d --- /dev/null +++ b/src/protocols/rocket-pool.ts @@ -0,0 +1,41 @@ +// Rocket Pool — rETH liquid-staking token. L1 rETH supports burn / +// getExchangeRate / getEthValue; Base rETH is a bridged ERC-20 and +// only exposes the standard ERC-20 surface. + +import { Chains } from "../chains"; +import { type AbiFragment, type AddressByChain } from "./types"; + +const reth: AddressByChain = { + [Chains.EthereumMainnet]: "0xae78736Cd615f374D3085123A210448E74Fc6393", + [Chains.BaseMainnet]: "0xB6fe221Fe9EeF5aBa221c348bA20A1Bf5e73624c", +}; + +/** L1-only `burn` + rate/value reads. */ +const rethAbi: readonly AbiFragment[] = Object.freeze([ + { + inputs: [{ internalType: "uint256", name: "_rethAmount", type: "uint256" }], + name: "burn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "getExchangeRate", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_rethAmount", type: "uint256" }], + name: "getEthValue", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, +]); + +export const rocketPool = Object.freeze({ + reth, + rethAbi, +}); diff --git a/src/protocols/sky.ts b/src/protocols/sky.ts new file mode 100644 index 0000000..f91a7d1 --- /dev/null +++ b/src/protocols/sky.ts @@ -0,0 +1,17 @@ +// Sky Protocol (formerly MakerDAO) — sDAI savings vault. Standard +// ERC-4626 wrapper over the Dai Savings Rate (no cooldown), so the +// shared vault ABI applies cleanly. + +import { Chains } from "../chains"; +import { erc4626VaultAbi } from "./common"; +import { type AddressByChain } from "./types"; + +const sdai: AddressByChain = { + [Chains.EthereumMainnet]: "0x83F20F44975D03b1b09e64809B757c47f942BEeA", +}; + +export const sky = Object.freeze({ + sdai, + /** Standard ERC-4626 surface — sDAI conforms exactly. */ + vaultAbi: erc4626VaultAbi, +}); diff --git a/src/protocols/spark.ts b/src/protocols/spark.ts new file mode 100644 index 0000000..b8cf028 --- /dev/null +++ b/src/protocols/spark.ts @@ -0,0 +1,19 @@ +// Spark Protocol — SparkLend money market, an AAVE V3 fork. +// +// Because Spark forked AAVE V3 unchanged, the Pool contract surface +// is identical: `supply`, `withdraw`, `borrow`, `repay`, +// `setUserUseReserveAsCollateral`, `getUserAccountData` — same +// signatures as `Protocols.aaveV3.poolMethodsAbi`. Templates that +// target Spark can pass `aaveV3.poolMethodsAbi` directly; we don't +// re-vendor a copy. Only the addresses differ. + +import { Chains } from "../chains"; +import { type AddressByChain } from "./types"; + +const pool: AddressByChain = { + [Chains.EthereumMainnet]: "0xC13e21B648A5Ee794902342038FF3aDAB66BE987", +}; + +export const spark = Object.freeze({ + pool, +}); diff --git a/src/protocols/superfluid.ts b/src/protocols/superfluid.ts new file mode 100644 index 0000000..8e19d03 --- /dev/null +++ b/src/protocols/superfluid.ts @@ -0,0 +1,44 @@ +// Superfluid — money streaming via the CFAv1Forwarder. Deployed at +// the same address on every Superfluid network (Ethereum, Base, +// Polygon, Optimism, ...). Flow rates are tokens-per-second as int96. + +import { Chains } from "../chains"; +import { type AbiFragment, type AddressByChain } from "./types"; + +const cfaForwarder: AddressByChain = { + [Chains.EthereumMainnet]: "0xcfA132E353cB4E398080B9700609bb008eceB125", + [Chains.BaseMainnet]: "0xcfA132E353cB4E398080B9700609bb008eceB125", +}; + +/** CFAv1Forwarder minimal write surface — `setFlowrate` + `createFlow`. */ +const cfaForwarderAbi: readonly AbiFragment[] = Object.freeze([ + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "address", name: "receiver", type: "address" }, + { internalType: "int96", name: "flowrate", type: "int96" }, + ], + name: "setFlowrate", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "address", name: "sender", type: "address" }, + { internalType: "address", name: "receiver", type: "address" }, + { internalType: "int96", name: "flowrate", type: "int96" }, + { internalType: "bytes", name: "userData", type: "bytes" }, + ], + name: "createFlow", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, +]); + +export const superfluid = Object.freeze({ + cfaForwarder, + cfaForwarderAbi, +}); diff --git a/src/protocols/types.ts b/src/protocols/types.ts new file mode 100644 index 0000000..87ca7f4 --- /dev/null +++ b/src/protocols/types.ts @@ -0,0 +1,29 @@ +// Loose ABI fragment shape — matches both ethers/viem-style entries +// and the protobuf-flavoured form some consumers (gRPC bindings, +// OpenAPI-generated types) pass through. We intentionally don't +// narrow `inputs`/`outputs` further than `unknown[]`: callers may +// canonicalize the ABI shape differently downstream, so the catalog +// stays permissive. + +export interface AbiFragment { + readonly name?: string; + readonly type: string; + readonly stateMutability?: string; + readonly anonymous?: boolean; + readonly inputs?: readonly unknown[]; + readonly outputs?: readonly unknown[]; + // Permissive tail so `AbiFragment` satisfies the + // `Record` ABI param shape that ethers / viem / + // ABI-coder libraries accept. Real ABI entries carry a handful of + // vendor-specific keys (gas, signature, etc.) we don't enumerate. + readonly [key: string]: unknown; +} + +import { type ChainId } from "../chains"; + +/** + * Per-chain address map. Use `ChainId` constants from `Chains.*` for + * the keys at the call site; `Partial` because not every protocol + * ships on every chain. + */ +export type AddressByChain = Partial>; diff --git a/src/protocols/uniswap-v3.ts b/src/protocols/uniswap-v3.ts new file mode 100644 index 0000000..352eb1a --- /dev/null +++ b/src/protocols/uniswap-v3.ts @@ -0,0 +1,209 @@ +// Uniswap V3 — SwapRouter02 / QuoterV2 / Permit2 / Factory / +// NonfungiblePositionManager / UniversalRouter addresses per chain, +// plus the ABI fragments callers routinely need to compose swaps +// and quotes. +// +// Canonical addresses: +// https://docs.uniswap.org/contracts/v3/reference/deployments +// +// Per-chain pool registries (every USDC/WETH pool at each fee tier, +// etc.) are deliberately NOT shipped here — they're indexable from +// the Uniswap subgraph or `Factory.getPool(tokenA, tokenB, fee)` and +// belong to a discovery layer, not a catalog. Consumers that need a +// specific pool address pass it inline. + +import { Chains } from "../chains"; +import { type AbiFragment, type AddressByChain } from "./types"; + +/** SwapRouter02 — the entry point for exactInput/exactOutput swaps. */ +const swapRouter02: AddressByChain = { + [Chains.EthereumMainnet]: "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", + [Chains.Sepolia]: "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E", + [Chains.BaseMainnet]: "0x2626664c2603336E57B271c5C0b26F421741e481", + [Chains.BaseSepolia]: "0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4", +}; + +/** QuoterV2 — off-chain quote helper for swap previews. */ +const quoterV2: AddressByChain = { + [Chains.EthereumMainnet]: "0x61fFE014bA17989E743c5F6cB21bF9697530B21e", + [Chains.Sepolia]: "0xEd1f6473345F45b75F8179591dd5bA1888cf2FB3", + [Chains.BaseMainnet]: "0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a", + [Chains.BaseSepolia]: "0xC5290058841028F1614F3A6F0F5816cAd0df5E27", +}; + +/** + * Permit2 — Uniswap's universal token-permit contract. Deployed at the + * SAME address across all chains in the catalog. + */ +const permit2: AddressByChain = { + [Chains.EthereumMainnet]: "0x000000000022d473030F116dDEE9F6B43aC78BA3", + [Chains.Sepolia]: "0x000000000022d473030F116dDEE9F6B43aC78BA3", + [Chains.BaseMainnet]: "0x000000000022d473030F116dDEE9F6B43aC78BA3", + [Chains.BaseSepolia]: "0x000000000022d473030F116dDEE9F6B43aC78BA3", +}; + +/** Uniswap V3 Factory — derives the deterministic pool address per token-pair+fee. */ +const factory: AddressByChain = { + [Chains.EthereumMainnet]: "0x1F98431c8aD98523631AE4a59f267346ea31F984", + [Chains.Sepolia]: "0x0227628f3F023bb0B980b67D528571c95c6DaC1c", + [Chains.BaseMainnet]: "0x33128a8fC17869897dcE68Ed026d694621f6FDfD", + [Chains.BaseSepolia]: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24", +}; + +/** NonfungiblePositionManager — LP NFT mint/burn/collect. */ +const nonfungiblePositionManager: AddressByChain = { + [Chains.EthereumMainnet]: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88", + [Chains.Sepolia]: "0x1238536071E1c677A632429e3655c799b22cDA52", + [Chains.BaseMainnet]: "0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1", + [Chains.BaseSepolia]: "0x27F971cb582BF9E50F397e4d29a5C7A34f11faA2", +}; + +/** UniversalRouter — Uniswap's multi-step routing entrypoint (Permit2-aware). */ +const universalRouter: AddressByChain = { + [Chains.EthereumMainnet]: "0x66a9893cc07d91d95644aedd05d03f95e1dba8af", + [Chains.Sepolia]: "0x3A9D48AB9751398BbFa63ad67599Bb04e4BdF98b", + [Chains.BaseMainnet]: "0x6ff5693b99212da76ad316178a184ab56d299b43", + [Chains.BaseSepolia]: "0x492e6456d9528771018deb9e87ef7750ef184104", +}; + +/** + * SwapRouter02 ABI — `exactInputSingle` + `exactOutputSingle`. These + * are the two single-hop swap methods stoploss-style and DCA-style + * templates use; multi-hop variants (`exactInput` / `exactOutput`) + * take a `path` bytes blob and aren't included until a template + * actually needs them. + */ +const swapRouter02Abi: readonly AbiFragment[] = Object.freeze([ + { + inputs: [ + { + components: [ + { internalType: "address", name: "tokenIn", type: "address" }, + { internalType: "address", name: "tokenOut", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "amountIn", type: "uint256" }, + { internalType: "uint256", name: "amountOutMinimum", type: "uint256" }, + { internalType: "uint160", name: "sqrtPriceLimitX96", type: "uint160" }, + ], + internalType: "struct IV3SwapRouter.ExactInputSingleParams", + name: "params", + type: "tuple", + }, + ], + name: "exactInputSingle", + outputs: [{ internalType: "uint256", name: "amountOut", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "tokenIn", type: "address" }, + { internalType: "address", name: "tokenOut", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "amountOut", type: "uint256" }, + { internalType: "uint256", name: "amountInMaximum", type: "uint256" }, + { internalType: "uint160", name: "sqrtPriceLimitX96", type: "uint160" }, + ], + internalType: "struct IV3SwapRouter.ExactOutputSingleParams", + name: "params", + type: "tuple", + }, + ], + name: "exactOutputSingle", + outputs: [{ internalType: "uint256", name: "amountIn", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, +]); + +/** + * QuoterV2 ABI — `quoteExactInputSingle` for off-chain price preview. + * Note: this is a state-changing call in QuoterV2 (the contract uses + * `revert` to return the quote) — `eth_call` against an archive node + * is the standard usage. Despite the `nonpayable` mutability, callers + * should treat it as a read. + */ +const quoterV2Abi: readonly AbiFragment[] = Object.freeze([ + { + inputs: [ + { + components: [ + { internalType: "address", name: "tokenIn", type: "address" }, + { internalType: "address", name: "tokenOut", type: "address" }, + { internalType: "uint256", name: "amountIn", type: "uint256" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + { internalType: "uint160", name: "sqrtPriceLimitX96", type: "uint160" }, + ], + internalType: "struct IQuoterV2.QuoteExactInputSingleParams", + name: "params", + type: "tuple", + }, + ], + name: "quoteExactInputSingle", + outputs: [ + { internalType: "uint256", name: "amountOut", type: "uint256" }, + { internalType: "uint160", name: "sqrtPriceX96After", type: "uint160" }, + { internalType: "uint32", name: "initializedTicksCrossed", type: "uint32" }, + { internalType: "uint256", name: "gasEstimate", type: "uint256" }, + ], + stateMutability: "nonpayable", + type: "function", + }, +]); + +/** + * Factory ABI — `getPool` resolves the canonical pool address for a + * (tokenA, tokenB, fee) triple. Useful when a template starts from a + * pair + fee tier rather than a known pool. + */ +const factoryAbi: readonly AbiFragment[] = Object.freeze([ + { + inputs: [ + { internalType: "address", name: "tokenA", type: "address" }, + { internalType: "address", name: "tokenB", type: "address" }, + { internalType: "uint24", name: "fee", type: "uint24" }, + ], + name: "getPool", + outputs: [{ internalType: "address", name: "pool", type: "address" }], + stateMutability: "view", + type: "function", + }, +]); + +/** + * Reference token addresses on the testnet markets these templates + * routinely target. Mainnet tokens vary per template — pass them + * inline rather than relying on a global registry the catalog + * doesn't yet maintain. + */ +const tokens = Object.freeze({ + WETH: { + [Chains.Sepolia]: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + [Chains.EthereumMainnet]: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + [Chains.BaseMainnet]: "0x4200000000000000000000000000000000000006", + [Chains.BaseSepolia]: "0x4200000000000000000000000000000000000006", + } satisfies AddressByChain, + USDC: { + [Chains.Sepolia]: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + [Chains.EthereumMainnet]: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + [Chains.BaseMainnet]: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + [Chains.BaseSepolia]: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + } satisfies AddressByChain, +}); + +export const uniswapV3 = Object.freeze({ + swapRouter02, + quoterV2, + permit2, + factory, + nonfungiblePositionManager, + universalRouter, + swapRouter02Abi, + quoterV2Abi, + factoryAbi, + tokens, +}); diff --git a/src/protocols/wrapped.ts b/src/protocols/wrapped.ts new file mode 100644 index 0000000..e6bcb62 --- /dev/null +++ b/src/protocols/wrapped.ts @@ -0,0 +1,60 @@ +// Wrapped Ether (WETH) — the canonical native-ETH wrapping contract. +// Mainnet WETH is a one-off; Base (and Base Sepolia) use the OP-stack +// predeploy at 0x4200…0006. Sepolia is the Uniswap-deployed test WETH +// used by AAVE Sepolia and Uniswap Sepolia. + +import { Chains } from "../chains"; +import { type AbiFragment, type AddressByChain } from "./types"; + +const weth: AddressByChain = { + [Chains.EthereumMainnet]: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + [Chains.Sepolia]: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + [Chains.BaseMainnet]: "0x4200000000000000000000000000000000000006", + [Chains.BaseSepolia]: "0x4200000000000000000000000000000000000006", +}; + +/** + * WETH9 ABI — `deposit` (payable wrap) + `withdraw` (unwrap) + the + * standard ERC-20 surface callers rely on. `deposit` is payable with + * no args — the wrap amount comes from `msg.value`, so any wallet UI + * or contract-write builder must surface an editable `value` field. + * The `stateMutability: "payable"` marker is what signals that. + */ +const wethAbi: readonly AbiFragment[] = Object.freeze([ + { + inputs: [], + name: "deposit", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "wad", type: "uint256" }], + name: "withdraw", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "guy", type: "address" }, + { internalType: "uint256", name: "wad", type: "uint256" }, + ], + name: "approve", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, +]); + +export const wrapped = Object.freeze({ + weth, + wethAbi, +}); diff --git a/tests/catalog.test.ts b/tests/catalog.test.ts new file mode 100644 index 0000000..2335ea1 --- /dev/null +++ b/tests/catalog.test.ts @@ -0,0 +1,181 @@ +/** + * Catalog-level integrity tests. The per-protocol data lives in + * `src/protocols/*.ts`; these tests make sure the namespace export + * surfaces every protocol consistently and that every address in the + * catalog has a well-formed shape (lowercased/checksum-form prefix, + * 42 chars), so a typo at extract-time can't silently break callers. + */ +import { describe, it, expect } from "vitest"; +import { Chains, Protocols } from "../src"; + +const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/; +const TOPIC_RE = /^0x[0-9a-fA-F]{64}$/; + +/** + * Walk a protocol's exported object and collect every address-like + * value. Used by the shape tests so we don't have to enumerate every + * known address by hand. + */ +function collectAddresses(value: unknown, acc: string[] = []): string[] { + if (typeof value === "string" && value.startsWith("0x") && value.length === 42) { + acc.push(value); + return acc; + } + if (Array.isArray(value)) { + for (const item of value) collectAddresses(item, acc); + return acc; + } + if (value !== null && typeof value === "object") { + for (const v of Object.values(value as Record)) { + collectAddresses(v, acc); + } + } + return acc; +} + +describe("Protocols namespace", () => { + it("exports every shipped protocol", () => { + // If you add a new protocol module to src/protocols/, add it + // here too — the test is intentionally explicit so the surface + // is reviewable at a glance. + expect(Object.keys(Protocols).sort()).toEqual( + [ + "aaveV3", + "aerodrome", + "chainlink", + "compoundV3", + "erc20", + "ethena", + "fraxEther", + "lido", + "morphoBlue", + "rocketPool", + "sky", + "spark", + "superfluid", + "uniswapV3", + "wrapped", + ].sort(), + ); + }); + + it("freezes the namespace object so consumers can't mutate it", () => { + expect(Object.isFrozen(Protocols)).toBe(true); + }); +}); + +describe("Address shape", () => { + it("every address in the catalog matches the 0x[40-hex] format", () => { + const failures: string[] = []; + for (const [protocolName, protocol] of Object.entries(Protocols)) { + for (const address of collectAddresses(protocol)) { + if (!ADDRESS_RE.test(address)) { + failures.push(`${protocolName}: ${address}`); + } + } + } + expect(failures).toEqual([]); + }); +}); + +describe("Event topic shape", () => { + it("every AAVE V3 event topic is a 32-byte keccak hash", () => { + for (const [name, hash] of Object.entries(Protocols.aaveV3.eventTopics)) { + expect(hash, `aaveV3.eventTopics.${name}`).toMatch(TOPIC_RE); + } + }); +}); + +describe("AAVE V3 catalog", () => { + it("has Pool addresses on mainnet, sepolia, base, base-sepolia", () => { + expect(Protocols.aaveV3.pool[Chains.EthereumMainnet]).toMatch(ADDRESS_RE); + expect(Protocols.aaveV3.pool[Chains.Sepolia]).toMatch(ADDRESS_RE); + expect(Protocols.aaveV3.pool[Chains.BaseMainnet]).toMatch(ADDRESS_RE); + expect(Protocols.aaveV3.pool[Chains.BaseSepolia]).toMatch(ADDRESS_RE); + }); + + it("ships the Pool method ABI with getUserAccountData + supply", () => { + const methods = Protocols.aaveV3.poolMethodsAbi.map((f) => f.name); + expect(methods).toContain("getUserAccountData"); + expect(methods).toContain("supply"); + expect(methods).toContain("borrow"); + expect(methods).toContain("repay"); + expect(methods).toContain("withdraw"); + expect(methods).toContain("setUserUseReserveAsCollateral"); + }); + + it("ships the Borrow event topic + ABI in lockstep", () => { + const borrow = Protocols.aaveV3.poolEventsAbi.find((e) => e.name === "Borrow"); + expect(borrow).toBeDefined(); + expect(Protocols.aaveV3.eventTopics.Borrow).toMatch(TOPIC_RE); + }); +}); + +describe("Uniswap V3 catalog", () => { + it("ships SwapRouter02 on every covered chain", () => { + expect(Protocols.uniswapV3.swapRouter02[Chains.EthereumMainnet]).toMatch(ADDRESS_RE); + expect(Protocols.uniswapV3.swapRouter02[Chains.Sepolia]).toMatch(ADDRESS_RE); + expect(Protocols.uniswapV3.swapRouter02[Chains.BaseMainnet]).toMatch(ADDRESS_RE); + expect(Protocols.uniswapV3.swapRouter02[Chains.BaseSepolia]).toMatch(ADDRESS_RE); + }); + + it("ships exactInputSingle in the SwapRouter02 ABI", () => { + const methods = Protocols.uniswapV3.swapRouter02Abi.map((f) => f.name); + expect(methods).toContain("exactInputSingle"); + expect(methods).toContain("exactOutputSingle"); + }); + + it("Permit2 is at the same address on every covered chain", () => { + const expected = "0x000000000022d473030F116dDEE9F6B43aC78BA3"; + for (const chainId of [ + Chains.EthereumMainnet, + Chains.Sepolia, + Chains.BaseMainnet, + Chains.BaseSepolia, + ]) { + expect(Protocols.uniswapV3.permit2[chainId]?.toLowerCase()).toBe(expected.toLowerCase()); + } + }); +}); + +describe("Shared ABIs", () => { + it("Chainlink AggregatorV3 ABI is reused across protocols", () => { + // The chainlink module re-exports the shared ABI fragment from + // common.ts. Confirm the reference is the same object so updates + // to common stay in lockstep. + expect(Protocols.chainlink.aggregatorV3Abi).toBeDefined(); + const latestRoundData = Protocols.chainlink.aggregatorV3Abi.find( + (f) => f.name === "latestRoundData", + ); + expect(latestRoundData).toBeDefined(); + }); + + it("ERC-4626 vault ABI surfaces deposit + redeem", () => { + // fraxEther + sky share the standard ERC-4626 ABI via common.ts. + const methods = Protocols.fraxEther.vaultAbi.map((f) => f.name); + expect(methods).toContain("deposit"); + expect(methods).toContain("redeem"); + expect(Protocols.sky.vaultAbi).toBe(Protocols.fraxEther.vaultAbi); + }); + + it("ERC-20 approve ABI is single-fragment", () => { + expect(Protocols.erc20.approveAbi).toHaveLength(1); + expect(Protocols.erc20.approveAbi[0].name).toBe("approve"); + }); +}); + +describe("Chain coverage", () => { + it("AAVE V3 covers the same chain set on Pool/Oracle/WETH Gateway", () => { + const poolChains = Object.keys(Protocols.aaveV3.pool).sort(); + const oracleChains = Object.keys(Protocols.aaveV3.oracle).sort(); + const gatewayChains = Object.keys(Protocols.aaveV3.wethGateway).sort(); + expect(oracleChains).toEqual(poolChains); + expect(gatewayChains).toEqual(poolChains); + }); + + it("Uniswap V3 covers the same chain set across its contracts", () => { + const routerChains = Object.keys(Protocols.uniswapV3.swapRouter02).sort(); + const factoryChains = Object.keys(Protocols.uniswapV3.factory).sort(); + expect(factoryChains).toEqual(routerChains); + }); +}); diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..3f40f70 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "noEmit": false, + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true + }, + "include": ["src/**/*"], + "exclude": ["dist", "node_modules", "tests"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..23dae87 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "node", + "lib": ["ES2022"], + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "skipLibCheck": true, + "types": [] + }, + "include": ["src/**/*", "tests/**/*"], + "exclude": ["dist", "node_modules"] +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..2d8163d --- /dev/null +++ b/yarn.lock @@ -0,0 +1,1161 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + +"@esbuild/aix-ppc64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz#82b74f92aa78d720b714162939fb248c90addf53" + integrity sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg== + +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + +"@esbuild/android-arm64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz#f78cb8a3121fc205a53285adb24972db385d185d" + integrity sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ== + +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + +"@esbuild/android-arm@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.27.7.tgz#593e10a1450bbfcac6cb321f61f468453bac209d" + integrity sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ== + +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + +"@esbuild/android-x64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.27.7.tgz#453143d073326033d2d22caf9e48de4bae274b07" + integrity sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg== + +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + +"@esbuild/darwin-arm64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz#6f23000fb9b40b7e04b7d0606c0693bd0632f322" + integrity sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw== + +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + +"@esbuild/darwin-x64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz#27393dd18bb1263c663979c5f1576e00c2d024be" + integrity sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ== + +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + +"@esbuild/freebsd-arm64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz#22e4638fa502d1c0027077324c97640e3adf3a62" + integrity sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w== + +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + +"@esbuild/freebsd-x64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz#9224b8e4fea924ce2194e3efc3e9aebf822192d6" + integrity sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ== + +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + +"@esbuild/linux-arm64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz#4f5d1c27527d817b35684ae21419e57c2bda0966" + integrity sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A== + +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + +"@esbuild/linux-arm@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz#b9e9d070c8c1c0449cf12b20eac37d70a4595921" + integrity sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA== + +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + +"@esbuild/linux-ia32@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz#3f80fb696aa96051a94047f35c85b08b21c36f9e" + integrity sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg== + +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + +"@esbuild/linux-loong64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz#9be1f2c28210b13ebb4156221bba356fe1675205" + integrity sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q== + +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + +"@esbuild/linux-mips64el@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz#4ab5ee67a3dfcbcb5e8fd7883dae6e735b1163b8" + integrity sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw== + +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + +"@esbuild/linux-ppc64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz#dac78c689f6499459c4321e5c15032c12307e7ea" + integrity sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ== + +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + +"@esbuild/linux-riscv64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz#050f7d3b355c3a98308e935bc4d6325da91b0027" + integrity sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ== + +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + +"@esbuild/linux-s390x@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz#d61f715ce61d43fe5844ad0d8f463f88cbe4fef6" + integrity sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw== + +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + +"@esbuild/linux-x64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz#ca8e1aa478fc8209257bf3ac8f79c4dc2982f32a" + integrity sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA== + +"@esbuild/netbsd-arm64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz#1650f2c1b948deeb3ef948f2fc30614723c09690" + integrity sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w== + +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + +"@esbuild/netbsd-x64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz#65772ab342c4b3319bf0705a211050aac1b6e320" + integrity sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw== + +"@esbuild/openbsd-arm64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz#37ed7cfa66549d7955852fce37d0c3de4e715ea1" + integrity sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A== + +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + +"@esbuild/openbsd-x64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz#01bf3d385855ef50cb33db7c4b52f957c34cd179" + integrity sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg== + +"@esbuild/openharmony-arm64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz#6c1f94b34086599aabda4eac8f638294b9877410" + integrity sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw== + +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + +"@esbuild/sunos-x64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz#4b0dd17ae0a6941d2d0fd35a906392517071a90d" + integrity sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA== + +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + +"@esbuild/win32-arm64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz#34193ab5565d6ff68ca928ac04be75102ccb2e77" + integrity sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA== + +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + +"@esbuild/win32-ia32@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz#eb67f0e4482515d8c1894ede631c327a4da9fc4d" + integrity sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw== + +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== + +"@esbuild/win32-x64@0.27.7": + version "0.27.7" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz#8fe30b3088b89b4873c3a6cc87597ae3920c0a8b" + integrity sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg== + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@jridgewell/trace-mapping@^0.3.24": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@rollup/rollup-android-arm-eabi@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz#3a04f01e9f01392bbef5920b94aa3b88794be7ab" + integrity sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ== + +"@rollup/rollup-android-arm64@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz#e371b653ceabc900790ae73f5548a0fd7cd63a70" + integrity sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw== + +"@rollup/rollup-darwin-arm64@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz#2a5aa70432e39816d666d79287a7324cfc3b4e72" + integrity sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA== + +"@rollup/rollup-darwin-x64@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz#c3b5b49629379cd9cdc5d841bf00ed44ebf393dd" + integrity sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg== + +"@rollup/rollup-freebsd-arm64@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz#f929d8e0462fae6602fc960beeabd7287d859283" + integrity sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g== + +"@rollup/rollup-freebsd-x64@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz#c01cb58031226f95d0900b1ec847f4fb32c6e809" + integrity sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw== + +"@rollup/rollup-linux-arm-gnueabihf@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz#f29d890c4858c8e0d3be01677eef4f6a359eed9d" + integrity sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA== + +"@rollup/rollup-linux-arm-musleabihf@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz#1ebfc8eb9f66136ed2faae5f44995add5ca3c964" + integrity sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w== + +"@rollup/rollup-linux-arm64-gnu@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz#c1fa823c2c4ce46ba7f61de1a4c3fdadd4fb4e7b" + integrity sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg== + +"@rollup/rollup-linux-arm64-musl@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz#a7f18854d0471b78bda8ea38f0891a4e059b571d" + integrity sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A== + +"@rollup/rollup-linux-loong64-gnu@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz#83658a9a4576bcce8cef85b2c78b9b649d2200c4" + integrity sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ== + +"@rollup/rollup-linux-loong64-musl@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz#fd2af677ae3417bb58d57ae37dd0d84686e40244" + integrity sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw== + +"@rollup/rollup-linux-ppc64-gnu@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz#6481647181c4cf8f1ddbd99f62c84cfc56c1a94a" + integrity sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg== + +"@rollup/rollup-linux-ppc64-musl@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz#18610a1a1550e28a5042ca916f898419540f17f4" + integrity sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A== + +"@rollup/rollup-linux-riscv64-gnu@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz#597bb80465a2621dbe0de0a41c66394a8a7e9a6e" + integrity sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA== + +"@rollup/rollup-linux-riscv64-musl@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz#a2a919a9f927ef7f24a60af77e3cb55f1ad59e4d" + integrity sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw== + +"@rollup/rollup-linux-s390x-gnu@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz#3166f6ceae7df9bbfddf9f36be1937231e13e3c6" + integrity sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ== + +"@rollup/rollup-linux-x64-gnu@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz#23c9bf79771d804fb87415eb0767569f273261e5" + integrity sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ== + +"@rollup/rollup-linux-x64-musl@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz#97941c6b94d67fe25cde0f027c10a19f2d1fdd39" + integrity sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg== + +"@rollup/rollup-openbsd-x64@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz#7aeb7d92e2cd1d399f56daf75c39040b777b6c77" + integrity sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA== + +"@rollup/rollup-openharmony-arm64@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz#925de61ae83bf99aa636e8acea87432e8c0ffaab" + integrity sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg== + +"@rollup/rollup-win32-arm64-msvc@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz#888ab83842721491044c46a7407e1f38f3235bb4" + integrity sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw== + +"@rollup/rollup-win32-ia32-msvc@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz#fa30ac24e3f0232139d2a47500560a28695764d4" + integrity sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA== + +"@rollup/rollup-win32-x64-gnu@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz#223e2bc93f86e0707568e1fadb5b537e50c976c7" + integrity sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw== + +"@rollup/rollup-win32-x64-msvc@4.60.4": + version "4.60.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz#da4f1676d87e2bdf744291b504b0ab79550c3e61" + integrity sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw== + +"@sinclair/typebox@^0.27.8": + version "0.27.10" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.10.tgz#beefe675f1853f73676aecc915b2bd2ac98c4fc6" + integrity sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA== + +"@types/estree@1.0.8": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + +"@types/estree@^1.0.0": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.9.tgz#cf3f0e876d7bee15a93ab925b82bf570a3904a24" + integrity sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg== + +"@vitest/expect@1.6.1": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.6.1.tgz#b90c213f587514a99ac0bf84f88cff9042b0f14d" + integrity sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog== + dependencies: + "@vitest/spy" "1.6.1" + "@vitest/utils" "1.6.1" + chai "^4.3.10" + +"@vitest/runner@1.6.1": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.6.1.tgz#10f5857c3e376218d58c2bfacfea1161e27e117f" + integrity sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA== + dependencies: + "@vitest/utils" "1.6.1" + p-limit "^5.0.0" + pathe "^1.1.1" + +"@vitest/snapshot@1.6.1": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.6.1.tgz#90414451a634bb36cd539ccb29ae0d048a8c0479" + integrity sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ== + dependencies: + magic-string "^0.30.5" + pathe "^1.1.1" + pretty-format "^29.7.0" + +"@vitest/spy@1.6.1": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.6.1.tgz#33376be38a5ed1ecd829eb986edaecc3e798c95d" + integrity sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw== + dependencies: + tinyspy "^2.2.0" + +"@vitest/utils@1.6.1": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.6.1.tgz#6d2f36cb6d866f2bbf59da854a324d6bf8040f17" + integrity sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g== + dependencies: + diff-sequences "^29.6.3" + estree-walker "^3.0.3" + loupe "^2.3.7" + pretty-format "^29.7.0" + +acorn-walk@^8.3.2: + version "8.3.5" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.5.tgz#8a6b8ca8fc5b34685af15dabb44118663c296496" + integrity sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw== + dependencies: + acorn "^8.11.0" + +acorn@^8.11.0, acorn@^8.16.0: + version "8.16.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.16.0.tgz#4ce79c89be40afe7afe8f3adb902a1f1ce9ac08a" + integrity sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw== + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +bundle-require@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/bundle-require/-/bundle-require-5.1.0.tgz#8db66f41950da3d77af1ef3322f4c3e04009faee" + integrity sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA== + dependencies: + load-tsconfig "^0.2.3" + +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + +chai@^4.3.10: + version "4.5.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" + integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.1.0" + +check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" + +chokidar@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" + integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== + dependencies: + readdirp "^4.0.1" + +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +confbox@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" + integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== + +consola@^3.4.0: + version "3.4.2" + resolved "https://registry.yarnpkg.com/consola/-/consola-3.4.2.tgz#5af110145397bb67afdab77013fdc34cae590ea7" + integrity sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA== + +cross-spawn@^7.0.3: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.3.4, debug@^4.4.0: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +deep-eql@^4.1.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.4.tgz#d0d3912865911bb8fac5afb4e3acfa6a28dc72b7" + integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== + dependencies: + type-detect "^4.0.0" + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +esbuild@^0.21.3: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== + optionalDependencies: + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" + +esbuild@^0.27.0: + version "0.27.7" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.27.7.tgz#bcadce22b2f3fd76f257e3a64f83a64986fea11f" + integrity sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w== + 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" + +estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + +execa@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^8.0.1" + human-signals "^5.0.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^4.1.0" + strip-final-newline "^3.0.0" + +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + +fix-dts-default-cjs-exports@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz#955cb6b3d519691c57828b078adadf2cb92e9549" + integrity sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg== + dependencies: + magic-string "^0.30.17" + mlly "^1.7.4" + rollup "^4.34.8" + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + +get-stream@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" + integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== + +human-signals@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" + integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== + +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +joycon@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" + integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== + +js-tokens@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-9.0.1.tgz#2ec43964658435296f6761b34e10671c2d9527f4" + integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ== + +lilconfig@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4" + integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +load-tsconfig@^0.2.3: + version "0.2.5" + resolved "https://registry.yarnpkg.com/load-tsconfig/-/load-tsconfig-0.2.5.tgz#453b8cd8961bfb912dea77eb6c168fe8cca3d3a1" + integrity sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg== + +local-pkg@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.5.1.tgz#69658638d2a95287534d4c2fff757980100dbb6d" + integrity sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ== + dependencies: + mlly "^1.7.3" + pkg-types "^1.2.1" + +loupe@^2.3.6, loupe@^2.3.7: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + +magic-string@^0.30.17, magic-string@^0.30.5: + version "0.30.21" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91" + integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.5" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + +mlly@^1.7.3, mlly@^1.7.4: + version "1.8.2" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.8.2.tgz#e7f7919a82d13b174405613117249a3f449d78bb" + integrity sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA== + dependencies: + acorn "^8.16.0" + pathe "^2.0.3" + pkg-types "^1.3.1" + ufo "^1.6.3" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nanoid@^3.3.12: + version "3.3.12" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.12.tgz#ab3d912e217a6d0a514f00a72a16543a28982c05" + integrity sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ== + +npm-run-path@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== + dependencies: + path-key "^4.0.0" + +object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + +p-limit@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-5.0.0.tgz#6946d5b7140b649b7a33a027d89b4c625b3a5985" + integrity sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ== + dependencies: + yocto-queue "^1.0.0" + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + +pathe@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" + integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== + +pathe@^2.0.1, pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + +picocolors@^1.0.0, picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.4.tgz#fd6f5e00a143086e074dffe4c924b8fb293b0589" + integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A== + +pirates@^4.0.1: + version "4.0.7" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" + integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== + +pkg-types@^1.2.1, pkg-types@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.3.1.tgz#bd7cc70881192777eef5326c19deb46e890917df" + integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ== + dependencies: + confbox "^0.1.8" + mlly "^1.7.4" + pathe "^2.0.1" + +postcss-load-config@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz#6fd7dcd8ae89badcf1b2d644489cbabf83aa8096" + integrity sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g== + dependencies: + lilconfig "^3.1.1" + +postcss@^8.4.43: + version "8.5.15" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.15.tgz#d1eaf677a324e9ec02196da2d3fecf4a0b9a735c" + integrity sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A== + dependencies: + nanoid "^3.3.12" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +react-is@^18.0.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + +readdirp@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +rollup@^4.20.0, rollup@^4.34.8: + version "4.60.4" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.60.4.tgz#ca3814f5900da3ac3981d2e0c61944b7e6e0cb09" + integrity sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g== + dependencies: + "@types/estree" "1.0.8" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.60.4" + "@rollup/rollup-android-arm64" "4.60.4" + "@rollup/rollup-darwin-arm64" "4.60.4" + "@rollup/rollup-darwin-x64" "4.60.4" + "@rollup/rollup-freebsd-arm64" "4.60.4" + "@rollup/rollup-freebsd-x64" "4.60.4" + "@rollup/rollup-linux-arm-gnueabihf" "4.60.4" + "@rollup/rollup-linux-arm-musleabihf" "4.60.4" + "@rollup/rollup-linux-arm64-gnu" "4.60.4" + "@rollup/rollup-linux-arm64-musl" "4.60.4" + "@rollup/rollup-linux-loong64-gnu" "4.60.4" + "@rollup/rollup-linux-loong64-musl" "4.60.4" + "@rollup/rollup-linux-ppc64-gnu" "4.60.4" + "@rollup/rollup-linux-ppc64-musl" "4.60.4" + "@rollup/rollup-linux-riscv64-gnu" "4.60.4" + "@rollup/rollup-linux-riscv64-musl" "4.60.4" + "@rollup/rollup-linux-s390x-gnu" "4.60.4" + "@rollup/rollup-linux-x64-gnu" "4.60.4" + "@rollup/rollup-linux-x64-musl" "4.60.4" + "@rollup/rollup-openbsd-x64" "4.60.4" + "@rollup/rollup-openharmony-arm64" "4.60.4" + "@rollup/rollup-win32-arm64-msvc" "4.60.4" + "@rollup/rollup-win32-ia32-msvc" "4.60.4" + "@rollup/rollup-win32-x64-gnu" "4.60.4" + "@rollup/rollup-win32-x64-msvc" "4.60.4" + fsevents "~2.3.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +siginfo@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== + +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +source-map@^0.7.6: + version "0.7.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.6.tgz#a3658ab87e5b6429c8a1f3ba0083d4c61ca3ef02" + integrity sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ== + +stackback@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== + +std-env@^3.5.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.10.0.tgz#d810b27e3a073047b2b5e40034881f5ea6f9c83b" + integrity sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg== + +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + +strip-literal@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-2.1.1.tgz#26906e65f606d49f748454a08084e94190c2e5ad" + integrity sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q== + dependencies: + js-tokens "^9.0.1" + +sucrase@^3.35.0: + version "3.35.1" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.1.tgz#4619ea50393fe8bd0ae5071c26abd9b2e346bfe1" + integrity sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.2" + commander "^4.0.0" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + tinyglobby "^0.2.11" + ts-interface-checker "^0.1.9" + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +tinybench@^2.5.1: + version "2.9.0" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" + integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== + +tinyexec@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" + integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== + +tinyglobby@^0.2.11: + version "0.2.16" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.16.tgz#1c3b7eb953fce42b226bc5a1ee06428281aff3d6" + integrity sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg== + dependencies: + fdir "^6.5.0" + picomatch "^4.0.4" + +tinypool@^0.8.3: + version "0.8.4" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.4.tgz#e217fe1270d941b39e98c625dcecebb1408c9aa8" + integrity sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ== + +tinyspy@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.2.1.tgz#117b2342f1f38a0dbdcc73a50a454883adf861d1" + integrity sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A== + +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + +tsup@^8.5.0: + version "8.5.1" + resolved "https://registry.yarnpkg.com/tsup/-/tsup-8.5.1.tgz#a9c7a875b93344bdf70600dedd78e70f88ec9a65" + integrity sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing== + dependencies: + bundle-require "^5.1.0" + cac "^6.7.14" + chokidar "^4.0.3" + consola "^3.4.0" + debug "^4.4.0" + esbuild "^0.27.0" + fix-dts-default-cjs-exports "^1.0.0" + joycon "^3.1.1" + picocolors "^1.1.1" + postcss-load-config "^6.0.1" + resolve-from "^5.0.0" + rollup "^4.34.8" + source-map "^0.7.6" + sucrase "^3.35.0" + tinyexec "^0.3.2" + tinyglobby "^0.2.11" + tree-kill "^1.2.2" + +type-detect@^4.0.0, type-detect@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" + integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== + +typescript@^5.5.4: + version "5.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" + integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== + +ufo@^1.6.3: + version "1.6.4" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.4.tgz#7a8fb875fcc6382d2c7d0b3692738b0500a92467" + integrity sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA== + +vite-node@1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.6.1.tgz#fff3ef309296ea03ceaa6ca4bb660922f5416c57" + integrity sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA== + dependencies: + cac "^6.7.14" + debug "^4.3.4" + pathe "^1.1.1" + picocolors "^1.0.0" + vite "^5.0.0" + +vite@^5.0.0: + version "5.4.21" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.21.tgz#84a4f7c5d860b071676d39ba513c0d598fdc7027" + integrity sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw== + dependencies: + esbuild "^0.21.3" + postcss "^8.4.43" + rollup "^4.20.0" + optionalDependencies: + fsevents "~2.3.3" + +vitest@^1.6.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.6.1.tgz#b4a3097adf8f79ac18bc2e2e0024c534a7a78d2f" + integrity sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag== + dependencies: + "@vitest/expect" "1.6.1" + "@vitest/runner" "1.6.1" + "@vitest/snapshot" "1.6.1" + "@vitest/spy" "1.6.1" + "@vitest/utils" "1.6.1" + acorn-walk "^8.3.2" + chai "^4.3.10" + debug "^4.3.4" + execa "^8.0.1" + local-pkg "^0.5.0" + magic-string "^0.30.5" + pathe "^1.1.1" + picocolors "^1.0.0" + std-env "^3.5.0" + strip-literal "^2.0.0" + tinybench "^2.5.1" + tinypool "^0.8.3" + vite "^5.0.0" + vite-node "1.6.1" + why-is-node-running "^2.2.2" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +why-is-node-running@^2.2.2: + version "2.3.0" + resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" + integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== + dependencies: + siginfo "^2.0.0" + stackback "0.0.2" + +yocto-queue@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.2.2.tgz#3e09c95d3f1aa89a58c114c99223edf639152c00" + integrity sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ== From 7d6d11cbb716ee6151d1bd2c9c42f9525b928769 Mon Sep 17 00:00:00 2001 From: chrisli30 Date: Fri, 29 May 2026 13:39:59 -0700 Subject: [PATCH 2/2] ci: match tsup output filenames in tarball verify step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tsup with package.json "type": "module" emits ESM as index.js and CJS as index.cjs — verify those, not the legacy index.mjs that doesn't exist. The exports map already points at the correct filenames; this just brings the CI check in line. --- .github/workflows/ci.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2dc46d1..44bec87 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,8 +40,12 @@ jobs: - name: Verify tarball contents # Pack a dry-run tarball and assert the dist surface is intact. # Catches: missing dist files in `files`, broken exports map. + # Since package.json declares `"type": "module"`, tsup emits + # ESM as `index.js` and CJS as `index.cjs` — match the actual + # filenames the exports map points at, not the legacy `.mjs` + # convention. run: | npm pack --dry-run test -f dist/index.js - test -f dist/index.mjs + test -f dist/index.cjs test -f dist/index.d.ts