diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index aff2b4e..6f01729 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -24,7 +24,7 @@ jobs: - uses: pnpm/action-setup@v4 - name: Install dependencies - run: pnpm build:prepare + run: pnpm install - name: Build run: pnpm build diff --git a/.planning/PROJECT.md b/.planning/PROJECT.md new file mode 100644 index 0000000..0e1db24 --- /dev/null +++ b/.planning/PROJECT.md @@ -0,0 +1,82 @@ +# iCKB Stack v2 + +## What This Is + +A CCC-based TypeScript library suite and reference apps for interacting with the on-chain iCKB protocol (NervosDAO liquidity via pooled deposits and iCKB xUDT tokens). The library packages (`@ickb/utils`, `@ickb/dao`, `@ickb/order`, `@ickb/core`, `@ickb/sdk`) provide the building blocks; the apps (`bot`, `interface`, `faucet`, `sampler`, `tester`) demonstrate usage and run protocol operations. + +## Core Value + +Clean, CCC-aligned library packages published to npm that frontends can depend on to interact with iCKB contracts — no Lumos, no abandoned abstractions, no duplicated functionality with CCC. + +## Requirements + +### Validated + + + +- ✓ CCC-based package structure (`@ickb/utils`, `@ickb/dao`, `@ickb/order`, `@ickb/core`, `@ickb/sdk`) — existing +- ✓ Manager pattern with `ScriptDeps` interface for composability — existing +- ✓ Async generator cell discovery with lazy evaluation — existing +- ✓ Molecule codec integration with CCC's `mol.union`, `ccc.Entity.Base`, `@ccc.codec` — existing +- ✓ Epoch class adopted from CCC (local Epoch deleted) — existing +- ✓ Faucet and sampler apps migrated to CCC — existing + +### Active + +- [ ] Remove SmartTransaction — replace with `ccc.Transaction` + utility functions +- [ ] Adopt CCC UDT handling — investigate subclassing `Udt` for iCKB's multi-representation value (xUDT + receipts + deposits) +- [ ] Systematic CCC alignment audit — replace local utilities with CCC equivalents from merged upstream PRs +- [ ] Migrate bot app from Lumos to CCC + new packages +- [ ] Migrate interface app from Lumos to CCC + new packages (straight swap, same UI) +- [ ] Migrate tester app from Lumos to CCC + new packages +- [ ] Remove all Lumos dependencies (`@ckb-lumos/*`, `@ickb/lumos-utils`, `@ickb/v1-core`) +- [ ] Clean APIs suitable for npm publication +- [ ] Identify reusable patterns that could become CCC upstream PRs +- [ ] Track CCC PR #328 (FeePayer) — potential CCC-native replacement for SmartTransaction's fee/balancing role + +### Out of Scope + +- UI/UX redesign for interface app — straight migration only +- New reference/example apps — existing apps serve as reference +- On-chain contract changes — contracts are immutable and non-upgradable +- Mobile app — web-first +- CCC framework changes — we adopt CCC, not fork it (PRs go upstream) + +## Context + +**Protocol:** iCKB tokenizes NervosDAO deposits. CKB deposited into NervosDAO is locked for ~30 days. iCKB represents that locked value as a liquid xUDT token. Key invariant: `Input UDT + Input Receipts = Output UDT + Input Deposits`. All contracts are deployed with zero-args locks (immutable, trustless). + +**iCKB UDT particularity:** iCKB value has three on-chain representations: (1) xUDT tokens (standard UDT), (2) receipt cells (pending conversion), (3) DAO deposit cells (locked CKB). CCC's `Udt` class only understands form (1). The relationship between all three forms is governed by the conservation law enforced by the `ickb_logic` type script. This makes CCC UDT adoption non-trivial — subclassing `Udt` to account for all three representations is a key design investigation. + +**SmartTransaction history:** `SmartTransaction` extends `ccc.Transaction` with UDT handler management and fee/change completion. The concept was proposed as an ecosystem-wide pattern but abandoned due to no adoption from CCC maintainers or other projects. The class itself still works and is used by all 5 library packages. Replacement: utility functions operating on plain `ccc.Transaction`. + +**CCC upstream contributions:** 12 PRs authored by this project's maintainer have been merged into CCC, covering: `shouldAddInputs` for completeFee (#225), `findCellsOnChain` (#258), auto capacity completion (#259), optimized completeFee (#260), UDT balance utilities (#228), multiple scripts for SignerCkbScriptReadonly (#265), `CellAny` type (#262), `reduce`/`reduceAsync` (#267), fixed-size mol union (#174), Epoch class (#314), UDT info querying (#261), `bytesLen`/`bytesLenUnsafe` (#353). PR #328 (FeePayer abstraction) is still open. + +**Local utility overlap with CCC core:** Several local utilities now have CCC equivalents that should be adopted: `gcd()`, `isHex()`, `hexFrom()`, `max()`/`min()` (use `numMax`/`numMin`). Utilities unique to iCKB (no CCC equivalent): `binarySearch()`, `asyncBinarySearch()`, `shuffle()`, `unique()`, `collect()`, `BufferedGenerator`, `MinHeap`. + +**Migration status:** Library packages are on CCC. Apps split: faucet/sampler already migrated; bot/interface/tester still on legacy Lumos (`@ckb-lumos/*`, `@ickb/lumos-utils@1.4.2`, `@ickb/v1-core@1.4.2`). + +**Local CCC dev build:** `ccc-dev/` supports using local CCC builds for testing. `.pnpmfile.cjs` transparently rewires `@ckb-ccc/*` to local packages. `ccc-dev/patch.sh` rewrites exports to `.ts` source. This enables testing upstream changes before they're published. + +## Constraints + +- **On-chain contracts**: Immutable — library must match existing contract behavior exactly +- **CCC compatibility**: Must work with `@ckb-ccc/core ^1.12.2` (catalog-pinned) +- **Node.js**: >= 24 (enforced via engines) +- **Package manager**: pnpm 10.30.1 (pinned with SHA-512) +- **TypeScript**: Strict mode with `noUncheckedIndexedAccess`, `verbatimModuleSyntax`, `noImplicitOverride` +- **Versioning**: All packages use `1001.0.0` (Epoch Semantic Versioning), managed by changesets +- **Publishing**: npm with `access: public` and `provenance: true` + +## Key Decisions + +| Decision | Rationale | Outcome | +|----------|-----------|---------| +| Remove SmartTransaction, use ccc.Transaction directly | SmartTransaction concept abandoned by ecosystem, no adoption from CCC maintainers | — Pending | +| Investigate CCC Udt subclassing for iCKB | iCKB value is multi-representation (xUDT + receipts + deposits); need to determine if CCC's Udt can be extended | — Pending | +| Library refactor before app migration | Clean packages first, then migrate apps on stable foundation | — Pending | +| Interface app: straight migration only | No UI/UX redesign — swap Lumos internals for CCC packages | — Pending | +| Track CCC PR #328 (FeePayer) | Could become CCC-native solution for what SmartTransaction does for fee completion | — Pending | + +--- +*Last updated: 2026-02-20 after initialization* diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md new file mode 100644 index 0000000..3f8f494 --- /dev/null +++ b/.planning/REQUIREMENTS.md @@ -0,0 +1,112 @@ +# Requirements: iCKB Stack v2 + +**Defined:** 2026-02-21 +**Core Value:** Clean, CCC-aligned library packages published to npm that frontends can depend on to interact with iCKB contracts -- no Lumos, no abandoned abstractions, no duplicated functionality with CCC. + +## v1 Requirements + +Requirements for initial milestone. Each maps to roadmap phases. + +### SmartTransaction Removal + +- [ ] **SMTX-01**: All manager methods (`DaoManager`, `OrderManager`, `LogicManager`, `OwnedOwnerManager`, `CapacityManager`, `UdtManager`, `IckbUdtManager`) accept `ccc.Transaction` instead of `SmartTransaction` +- [ ] **SMTX-02**: `SmartTransaction` class and its `completeFee()` override are deleted from `@ickb/utils` +- [ ] **SMTX-03**: Fee completion uses CCC-native `ccc.Transaction.completeFeeBy()` or `completeFeeChangeToLock()` with DAO-aware capacity calculation +- [ ] **SMTX-04**: Header caching delegates to `ccc.Client.cache` instead of `SmartTransaction.headers` map +- [ ] **SMTX-05**: UDT handler registration (`addUdtHandlers()`) is replaced by direct `Udt` instance usage or standalone utility functions +- [ ] **SMTX-06**: 64-output NervosDAO limit check is consolidated into a single utility function (currently scattered across 6 locations) +- [ ] **SMTX-07**: `IckbUdtManager` multi-representation UDT balance logic (xUDT + receipts + deposits) survives removal intact -- conservation law `Input UDT + Input Receipts = Output UDT + Input Deposits` is preserved +- [ ] **SMTX-08**: `IckbSdk.estimate()` and `IckbSdk.maturity()` continue working after SmartTransaction removal +- [ ] **SMTX-09**: All 5 library packages (`@ickb/utils`, `@ickb/dao`, `@ickb/order`, `@ickb/core`, `@ickb/sdk`) compile and pass type checking after removal +- [ ] **SMTX-10**: Deprecated CCC API calls (`udtBalanceFrom`, `getInputsUdtBalance`, `getOutputsUdtBalance`, `completeInputsByUdt`) are replaced with `@ckb-ccc/udt` equivalents + +### CCC Utility Deduplication + +- [ ] **DEDUP-01**: Local `max()` / `min()` replaced with `ccc.numMax()` / `ccc.numMin()` across all packages +- [ ] **DEDUP-02**: Local `gcd()` replaced with `ccc.gcd()` across all packages +- [ ] **DEDUP-03**: Local `isHex()` replaced with `ccc.isHex()` in `@ickb/utils` +- [ ] **DEDUP-04**: Local `hexFrom()` refactored to explicit calls -- CCC's `hexFrom()` only handles `HexLike` (not `bigint | Entity`), so call sites should use `ccc.numToHex()` for bigint and `ccc.hexFrom(entity.toBytes())` for entities (per STACK.md evaluation) +- [ ] **DEDUP-05**: iCKB-unique utilities (`binarySearch`, `asyncBinarySearch`, `shuffle`, `unique`, `collect`, `BufferedGenerator`, `MinHeap`) are preserved unchanged + +### CCC Udt Integration + +- [ ] **UDT-01**: Feasibility assessment completed: can `IckbUdt extends udt.Udt` override `infoFrom()` or `getInputsInfo()`/`getOutputsInfo()` to account for receipt cells and deposit cells alongside xUDT cells +- [ ] **UDT-02**: Header access pattern for receipt value calculation is designed -- determine whether `client.getCellWithHeader()`, `client.getHeaderByTxHash()`, or the existing `getHeader()` pattern is used within the Udt override +- [ ] **UDT-03**: Decision documented: subclass CCC `Udt` vs. keep custom `UdtHandler` interface vs. hybrid approach +- [ ] **UDT-04**: If subclassing is viable, `IckbUdt` class is implemented in `@ickb/core` with multi-representation balance calculation +- [ ] **UDT-05**: If subclassing is not viable, `IckbUdtManager` is refactored to work with plain `ccc.Transaction` (no SmartTransaction dependency) while maintaining a compatible interface + +## v2 Requirements + +Deferred to next milestone. Tracked but not in current roadmap. + +### API & Publication + +- **API-01**: Clean public API surface -- audit all `export *` barrel files, mark internal symbols with `@internal` +- **API-02**: npm publication with provenance -- publish updated packages after API audit +- **API-03**: Type export audit -- ensure `.d.ts` correctness, no `any` leaks in public API + +### App Migration + +- **APP-01**: Bot app migrated from Lumos to CCC + new library packages +- **APP-02**: Interface app migrated from Lumos to CCC + new library packages (straight swap, same UI) +- **APP-03**: Tester app migrated from Lumos to CCC + new library packages + +### Ecosystem Cleanup + +- **CLEAN-01**: Complete Lumos removal -- remove all `@ckb-lumos/*`, `@ickb/lumos-utils`, `@ickb/v1-core` dependencies +- **CLEAN-02**: Upstream CCC contribution -- identify reusable patterns for CCC PRs + +## Out of Scope + +Explicitly excluded. Documented to prevent scope creep. + +| Feature | Reason | +|---------|--------| +| UI/UX redesign for interface app | Straight migration only -- conflates concerns, delays migration | +| New reference/example apps | Existing 5 apps already demonstrate all library capabilities | +| On-chain contract changes | All contracts deployed with zero-args locks (immutable, non-upgradable) | +| Mobile app | Web-first, web-only for now | +| CCC framework fork | We adopt CCC, not fork it -- PRs go upstream | +| Custom Molecule codec library | CCC already provides `mol.*` -- custom codecs duplicate effort | +| Custom blockchain indexer | CCC's `findCells`/`findCellsOnChain` covers all current needs | +| Multi-chain / L2 token bridging | Separate concern requiring different architecture | +| Embedded wallet/signer management | CCC provides comprehensive signer abstraction | +| Database/state persistence layer | All state is on-chain -- database creates stale-state problems | +| SmartTransaction as ecosystem standard | Abandoned by CCC maintainers and broader ecosystem | + +## Traceability + +Which phases cover which requirements. Updated during roadmap creation. + +| Requirement | Phase | Status | +|-------------|-------|--------| +| SMTX-01 | Phase 5 | Pending | +| SMTX-02 | Phase 1 | Pending | +| SMTX-03 | Phase 6 | Pending | +| SMTX-04 | Phase 1 | Pending | +| SMTX-05 | Phase 4 | Pending | +| SMTX-06 | Phase 1 | Pending | +| SMTX-07 | Phase 5 | Pending | +| SMTX-08 | Phase 6 | Pending | +| SMTX-09 | Phase 7 | Pending | +| SMTX-10 | Phase 4 | Pending | +| DEDUP-01 | Phase 2 | Pending | +| DEDUP-02 | Phase 2 | Pending | +| DEDUP-03 | Phase 2 | Pending | +| DEDUP-04 | Phase 2 | Pending | +| DEDUP-05 | Phase 2 | Pending | +| UDT-01 | Phase 3 | Pending | +| UDT-02 | Phase 3 | Pending | +| UDT-03 | Phase 3 | Pending | +| UDT-04 | Phase 5 | Pending | +| UDT-05 | Phase 5 | Pending | + +**Coverage:** +- v1 requirements: 20 total +- Mapped to phases: 20 +- Unmapped: 0 + +--- +*Requirements defined: 2026-02-21* +*Last updated: 2026-02-21 after roadmap creation* diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md new file mode 100644 index 0000000..c8dfcae --- /dev/null +++ b/.planning/ROADMAP.md @@ -0,0 +1,146 @@ +# Roadmap: iCKB Stack v2 + +## Overview + +This roadmap delivers the v1 milestone: removing the abandoned SmartTransaction abstraction, adopting CCC-native utilities and UDT patterns, and verifying the entire 5-package library suite compiles and functions against plain `ccc.Transaction`. The work follows the package dependency graph bottom-up (`@ickb/utils` -> `@ickb/dao` + `@ickb/order` -> `@ickb/core` -> `@ickb/sdk`), with a parallel design investigation for CCC Udt integration that feeds into the `@ickb/core` refactor. + +## Phases + +**Phase Numbering:** +- Integer phases (1, 2, 3): Planned milestone work +- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED) + +Decimal phases appear between their surrounding integers in numeric order. + +- [ ] **Phase 1: @ickb/utils SmartTransaction Removal** - Delete SmartTransaction class and its infrastructure; extract standalone utilities for header caching and DAO output limits +- [ ] **Phase 2: CCC Utility Adoption** - Replace local utility functions that duplicate CCC equivalents across all packages; preserve iCKB-unique utilities +- [ ] **Phase 3: CCC Udt Integration Investigation** - Assess feasibility of subclassing CCC's Udt class for iCKB's multi-representation value; design header access pattern; document decision +- [ ] **Phase 4: @ickb/dao and @ickb/order Migration** - Update DaoManager and OrderManager to accept plain ccc.Transaction; replace UDT handler registration pattern; replace deprecated CCC API calls +- [ ] **Phase 5: @ickb/core Refactor** - Update all remaining managers to plain ccc.Transaction; implement IckbUdt class or refactor IckbUdtManager based on Phase 3 findings; preserve conservation law +- [ ] **Phase 6: SDK Completion Pipeline** - Wire IckbSdk facade to CCC-native fee completion; verify estimate() and maturity() work end-to-end +- [ ] **Phase 7: Full Stack Verification** - Verify all 5 library packages compile clean with no SmartTransaction remnants and no type errors + +## Phase Details + +### Phase 1: @ickb/utils SmartTransaction Removal +**Goal**: SmartTransaction class and its dependent types (UdtHandler, UdtManager, CapacityManager) are removed from @ickb/utils; header caching and 64-output DAO limit check are consolidated into standalone utility functions +**Depends on**: Nothing (first phase) +**Requirements**: SMTX-02, SMTX-04, SMTX-06 +**Success Criteria** (what must be TRUE): + 1. `SmartTransaction` class, `UdtHandler` interface, `UdtManager` class, and `CapacityManager` class no longer exist in `@ickb/utils` source or exports + 2. A standalone `getHeader()` utility function exists that delegates to `ccc.Client.cache` for header lookups instead of maintaining its own `Map` + 3. A single `assertDaoOutputLimit(tx)` utility function exists that checks the 64-output NervosDAO limit, replacing the check currently scattered across 6 locations + 4. `@ickb/utils` compiles successfully with the SmartTransaction-related code removed (downstream packages will have expected compilation errors until they are updated) +**Plans**: TBD + +Plans: +- [ ] 01-01: TBD +- [ ] 01-02: TBD +- [ ] 01-03: TBD + +### Phase 2: CCC Utility Adoption +**Goal**: Local utility functions that duplicate CCC core functionality are replaced with CCC equivalents across all packages; iCKB-unique utilities are explicitly preserved +**Depends on**: Phase 1 +**Requirements**: DEDUP-01, DEDUP-02, DEDUP-03, DEDUP-04, DEDUP-05 +**Success Criteria** (what must be TRUE): + 1. All call sites using local `max()`/`min()` now use `ccc.numMax()`/`ccc.numMin()` and the local implementations are deleted + 2. All call sites using local `gcd()` now use `ccc.gcd()` and the local implementation is deleted + 3. Local `isHex()` in `@ickb/utils` is replaced with `ccc.isHex()` + 4. Local `hexFrom()` call sites are refactored to explicit calls: `ccc.numToHex()` for bigint and `ccc.hexFrom(entity.toBytes())` for entities (CCC's `hexFrom()` only handles `HexLike`, not `bigint | Entity`) + 5. iCKB-unique utilities (`binarySearch`, `asyncBinarySearch`, `shuffle`, `unique`, `collect`, `BufferedGenerator`, `MinHeap`) remain in `@ickb/utils` unchanged +**Plans**: TBD + +Plans: +- [ ] 02-01: TBD +- [ ] 02-02: TBD + +### Phase 3: CCC Udt Integration Investigation +**Goal**: Clear, documented decision on whether IckbUdt should extend CCC's `udt.Udt` class for iCKB's multi-representation value (xUDT + receipts + deposits), with the header access pattern designed +**Depends on**: Nothing (can proceed in parallel with Phases 1-2; design investigation, not code changes) +**Requirements**: UDT-01, UDT-02, UDT-03 +**Success Criteria** (what must be TRUE): + 1. A written feasibility assessment exists answering: can `IckbUdt extends udt.Udt` override `getInputsInfo()`/`getOutputsInfo()` to account for receipt cells and deposit cells alongside xUDT cells, without breaking CCC's internal method chains + 2. The header access pattern for receipt value calculation is designed and documented -- specifying whether `client.getCellWithHeader()`, `client.getHeaderByTxHash()`, or the existing `getHeader()` utility is used within the Udt override + 3. A decision document exists with one of three outcomes: (a) subclass CCC Udt, (b) keep custom interface, (c) hybrid approach -- with rationale for the chosen path +**Plans**: TBD + +Plans: +- [ ] 03-01: TBD +- [ ] 03-02: TBD + +### Phase 4: @ickb/dao and @ickb/order Migration +**Goal**: DaoManager and OrderManager accept plain `ccc.Transaction`; the UDT handler registration pattern (`addUdtHandlers()`) is replaced in these packages; deprecated CCC API calls are replaced with `@ckb-ccc/udt` equivalents +**Depends on**: Phase 1 (SmartTransaction removed from utils) +**Requirements**: SMTX-05, SMTX-10 +**Success Criteria** (what must be TRUE): + 1. `DaoManager` methods in `@ickb/dao` accept `ccc.Transaction` as their transaction parameter (not `SmartTransaction`) + 2. `OrderManager` methods in `@ickb/order` accept `ccc.Transaction` as their transaction parameter (not `SmartTransaction`) + 3. No calls to `addUdtHandlers()` exist in `@ickb/dao` or `@ickb/order`; UDT-related operations use direct `Udt` instance methods or standalone utility functions + 4. No calls to deprecated CCC APIs (`udtBalanceFrom`, `getInputsUdtBalance`, `getOutputsUdtBalance`, `completeInputsByUdt`) exist in `@ickb/dao` or `@ickb/order` + 5. Both `@ickb/dao` and `@ickb/order` compile successfully +**Plans**: TBD + +Plans: +- [ ] 04-01: TBD +- [ ] 04-02: TBD + +### Phase 5: @ickb/core Refactor +**Goal**: All remaining managers (LogicManager, OwnedOwnerManager, IckbUdtManager) accept plain `ccc.Transaction`; IckbUdt class is implemented or IckbUdtManager is refactored based on Phase 3 findings; the iCKB conservation law is preserved through the refactor +**Depends on**: Phase 3 (UDT decision), Phase 4 (dao+order done) +**Requirements**: SMTX-01, SMTX-07, UDT-04, UDT-05 +**Success Criteria** (what must be TRUE): + 1. ALL manager methods across ALL 5 library packages accept `ccc.Transaction` instead of `SmartTransaction` (this is the completion gate for SMTX-01 -- utils managers removed in Phase 1, dao+order managers updated in Phase 4, core managers updated here) + 2. The iCKB conservation law (`Input UDT + Input Receipts = Output UDT + Input Deposits`) is enforced correctly in the refactored code -- multi-representation UDT balance logic survives intact + 3. If Phase 3 concluded subclassing is viable: `IckbUdt extends udt.Udt` exists in `@ickb/core` with overridden `getInputsInfo()`/`getOutputsInfo()` that account for xUDT cells, receipt cells, and deposit cells + 4. If Phase 3 concluded subclassing is not viable: `IckbUdtManager` is refactored to work with plain `ccc.Transaction` while maintaining a compatible interface for balance calculation + 5. `@ickb/core` compiles successfully with no SmartTransaction imports +**Plans**: TBD + +Plans: +- [ ] 05-01: TBD +- [ ] 05-02: TBD +- [ ] 05-03: TBD + +### Phase 6: SDK Completion Pipeline +**Goal**: IckbSdk facade uses CCC-native fee completion pipeline; estimate() and maturity() continue working after SmartTransaction removal +**Depends on**: Phase 5 (core refactored) +**Requirements**: SMTX-03, SMTX-08 +**Success Criteria** (what must be TRUE): + 1. `IckbSdk` transaction building uses `ccc.Transaction.completeFeeBy()` or `completeFeeChangeToLock()` for fee completion, with DAO-aware capacity calculation (no SmartTransaction.completeFee override) + 2. `IckbSdk.estimate()` returns correct iCKB exchange rate estimates when called against the refactored library + 3. `IckbSdk.maturity()` returns correct deposit maturity information when called against the refactored library + 4. The explicit completion pipeline ordering is correct: UDT completion before CKB capacity completion before fee completion +**Plans**: TBD + +Plans: +- [ ] 06-01: TBD +- [ ] 06-02: TBD + +### Phase 7: Full Stack Verification +**Goal**: All 5 library packages compile clean with strict TypeScript settings, no SmartTransaction remnants, and no deprecated CCC API calls anywhere in the codebase +**Depends on**: Phase 6 (SDK done -- all packages now updated) +**Requirements**: SMTX-09 +**Success Criteria** (what must be TRUE): + 1. `pnpm check:full` passes -- all 5 library packages (`@ickb/utils`, `@ickb/dao`, `@ickb/order`, `@ickb/core`, `@ickb/sdk`) compile with zero type errors under strict TypeScript settings (`noUncheckedIndexedAccess`, `verbatimModuleSyntax`, `noImplicitOverride`) + 2. No imports of `SmartTransaction` exist anywhere in the codebase (library packages or apps) + 3. No calls to deprecated CCC APIs (`udtBalanceFrom`, `getInputsUdtBalance`, `getOutputsUdtBalance`, `completeInputsByUdt`) exist anywhere in the 5 library packages +**Plans**: TBD + +Plans: +- [ ] 07-01: TBD + +## Progress + +**Execution Order:** +Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 +(Note: Phase 3 could theoretically start in parallel with Phases 1-2, but sequential execution is configured) + +| Phase | Plans Complete | Status | Completed | +|-------|----------------|--------|-----------| +| 1. @ickb/utils SmartTransaction Removal | 0/3 | Not started | - | +| 2. CCC Utility Adoption | 0/2 | Not started | - | +| 3. CCC Udt Integration Investigation | 0/2 | Not started | - | +| 4. @ickb/dao and @ickb/order Migration | 0/2 | Not started | - | +| 5. @ickb/core Refactor | 0/3 | Not started | - | +| 6. SDK Completion Pipeline | 0/2 | Not started | - | +| 7. Full Stack Verification | 0/1 | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md new file mode 100644 index 0000000..218ac61 --- /dev/null +++ b/.planning/STATE.md @@ -0,0 +1,62 @@ +# Project State + +## Project Reference + +See: .planning/PROJECT.md (updated 2026-02-20) + +**Core value:** Clean, CCC-aligned library packages published to npm that frontends can depend on to interact with iCKB contracts -- no Lumos, no abandoned abstractions, no duplicated functionality with CCC. +**Current focus:** Phase 1: @ickb/utils SmartTransaction Removal + +## Current Position + +Phase: 1 of 7 (@ickb/utils SmartTransaction Removal) +Plan: 0 of 3 in current phase +Status: Ready to plan +Last activity: 2026-02-21 -- Roadmap created + +Progress: [░░░░░░░░░░] 0% + +## Performance Metrics + +**Velocity:** +- Total plans completed: 0 +- Average duration: - +- Total execution time: 0 hours + +**By Phase:** + +| Phase | Plans | Total | Avg/Plan | +|-------|-------|-------|----------| +| - | - | - | - | + +**Recent Trend:** +- Last 5 plans: - +- Trend: - + +*Updated after each plan completion* + +## Accumulated Context + +### Decisions + +Decisions are logged in PROJECT.md Key Decisions table. +Recent decisions affecting current work: + +- [Roadmap]: Bottom-up refactor order follows package dependency graph: utils -> dao+order -> core -> sdk +- [Roadmap]: UDT investigation (Phase 3) is a design phase that produces a decision document before core implementation (Phase 5) +- [Roadmap]: SMTX-01 (all managers accept ccc.Transaction) is verified at Phase 5 completion, after utils managers removed (Phase 1), dao+order managers updated (Phase 4), and core managers updated (Phase 5) + +### Pending Todos + +None yet. + +### Blockers/Concerns + +- Resolved: CCC's `Transaction.getInputsCapacity()` handles DAO profit natively via `getInputsCapacityExtra()` -> `CellInput.getExtraCapacity()` -> `Cell.getDaoProfit()` (verified in STACK.md from CCC source). No standalone utility needed. +- Research gap: CCC Udt `getInputsInfo()` signature needs verification for header fetching context -- must confirm during Phase 3 investigation. + +## Session Continuity + +Last session: 2026-02-21 +Stopped at: Roadmap created, ready for Phase 1 planning +Resume file: None diff --git a/.planning/codebase/ARCHITECTURE.md b/.planning/codebase/ARCHITECTURE.md index 9e2c76b..205f74d 100644 --- a/.planning/codebase/ARCHITECTURE.md +++ b/.planning/codebase/ARCHITECTURE.md @@ -77,7 +77,7 @@ Receipts convert to UDT; deposits stay as deposits or convert to UDT. No iCKB ca **Utilities Layer (`packages/utils/src/`)** - Purpose: Reusable blockchain primitives and transaction helpers -- Key exports: `SmartTransaction`, `CapacityManager`, codec/heap/epoch utilities, UDT handlers +- Key exports: `SmartTransaction`, `CapacityManager`, codec/heap utilities, UDT handlers - Key files: - `transaction.ts` (517 lines): SmartTransaction builder with fee completion and UDT balancing - `capacity.ts` (221 lines): CapacityManager for cell discovery and collection @@ -151,7 +151,7 @@ Receipts convert to UDT; deposits stay as deposits or convert to UDT. No iCKB ca - Purpose: Domain-specific operational services **Faucet (Migrated to CCC + New Packages):** - - Location: `apps/faucet/src/main.ts` (86 lines) + - Location: `apps/faucet/src/main.ts` (88 lines), entry via `apps/faucet/src/index.ts` - Entry: `main()` async function - Pattern: Infinite loop with 2-minute poll interval - Uses: CCC client, CapacityManager, SmartTransaction diff --git a/.planning/codebase/CONCERNS.md b/.planning/codebase/CONCERNS.md index 186ca06..721e122 100644 --- a/.planning/codebase/CONCERNS.md +++ b/.planning/codebase/CONCERNS.md @@ -64,20 +64,13 @@ ## Known Bugs -### Self-Comparison Bug in Pool Snapshot Maturity Calculation +### ~~Faucet `main()` Runs Diagnostic Code Instead of Faucet Logic~~ (RESOLVED) -- Symptoms: In `IckbSdk.getCkb()`, the maturity estimation for pool snapshot bins always takes the wrong branch. The condition `tipEpoch.compare(tipEpoch) < 0` compares `tipEpoch` to itself, which always returns `0` (equal), so the condition is always `false`. The comment says "If the bin has already started, assume worst-case timing" but this branch is never taken. -- Files: `packages/sdk/src/sdk.ts`, line 444 -- Trigger: Any call to `IckbSdk.getL1State()` when a pool snapshot exists (when `poolSnapshotHex !== "0x"`). The maturity calculation for bins always uses `end.toUnix(tip)` instead of `end.add(oneCycle).toUnix(tip)` for bins that have already started. -- Workaround: The code path still produces a maturity value, just potentially an incorrect one (underestimating maturity for already-started bins, since it does not add the extra cycle). -- Fix: The comparison should likely be `start.compare(tipEpoch) < 0` (checking if the bin start is before the current tip epoch) or similar, not `tipEpoch.compare(tipEpoch)`. +- **Resolved:** Faucet was restructured. `apps/faucet/src/index.ts` now imports and calls `main()` from `apps/faucet/src/main.ts` which contains the actual faucet transfer logic (88 lines). -### Faucet `main()` Runs Diagnostic Code Instead of Faucet Logic +### ~~Self-Comparison Bug in Pool Snapshot Maturity Calculation~~ (INVALID) -- Symptoms: `apps/faucet/src/index.ts` exports two functions named `main` (lines 6-13) and `main0` (lines 16-90). The file calls `await main()` at the bottom (line 92), but `main()` is a diagnostic function that queries DAO claim epochs from testnet and logs them. The actual faucet transfer logic is in `main0()`. -- Files: `apps/faucet/src/index.ts`, lines 6-13 (diagnostic `main`), lines 16-90 (actual faucet `main0`), line 92 (`await main()`) -- Trigger: Running the faucet app always executes the diagnostic instead of the fund transfer. -- Workaround: Manually change `await main()` to `await main0()`. +- **Invalid:** The original analysis incorrectly stated the condition was `tipEpoch.compare(tipEpoch) < 0` (self-comparison). The actual code at `packages/sdk/src/sdk.ts` line 443 is `start.compare(tipEpoch) < 0`, which correctly checks whether the bin start epoch precedes the current tip epoch. No bug exists. ## Security Considerations @@ -92,9 +85,9 @@ ### Faucet Logs Ephemeral Private Key to Console -- Risk: `apps/faucet/src/index.ts` generates a temporary private key using `crypto.getRandomValues()` at line 30 and logs the key to console at line 31 (`console.log(key)`). -- Files: `apps/faucet/src/index.ts`, lines 30-31 -- Current mitigation: The key is ephemeral and only used for testnet faucet transfers. This code is currently in `main0()` which is not the active entry point (see faucet bug above). +- Risk: `apps/faucet/src/main.ts` generates a temporary private key using `crypto.getRandomValues()` at line 26 and logs the key to console at line 27 (`console.log(key)`). +- Files: `apps/faucet/src/main.ts`, lines 26-27 +- Current mitigation: The key is ephemeral and only used for testnet faucet transfers. - Recommendations: Avoid logging private keys even in development/testnet contexts. Keep the key in memory only. ### Hardcoded Script Constants @@ -137,7 +130,7 @@ ### SmartTransaction Class Extending ccc.Transaction -- Files: `packages/utils/src/transaction.ts` (478 lines) +- Files: `packages/utils/src/transaction.ts` (517 lines) - Why fragile: `SmartTransaction` extends `ccc.Transaction` and overrides 8 methods: `completeFee`, `getInputsUdtBalance`, `getOutputsUdtBalance`, `getInputsCapacity`, `clone`, `copy`, `from`, `default`, and `fromLumosSkeleton`. Changes to `ccc.Transaction`'s interface or behavior upstream can silently break `SmartTransaction`. - Safe modification: When updating CCC dependency, review `ccc.Transaction` changelog for breaking changes to overridden methods. The `completeFee` override (lines 63-98) is particularly fragile as it calls `super.completeFee()` and also queries the client for the NervosDAO script to check the 64-output limit. - Test coverage: No tests for `SmartTransaction`. @@ -193,20 +186,20 @@ ### No Automated Tests -- Problem: Zero test files exist in the project source code (all `*.test.*` and `*.spec.*` files are in `node_modules/`). The CI pipeline (`.github/workflows/check.yaml`) has the test step commented out (lines 22-23: `# - name: Test` / `# run: pnpm test:ci`). +- Problem: Zero test files exist in the project source code (all `*.test.*` and `*.spec.*` files are in `node_modules/`). The CI pipeline (`.github/workflows/check.yaml`) runs `pnpm check` which includes `pnpm test:ci`, but with no test files, `vitest run` passes vacuously. - Blocks: Confident refactoring, library migration, and CCC upstream updates. Any code change is a regression risk. -- Files: `.github/workflows/check.yaml`, lines 22-23 +- Files: `.github/workflows/check.yaml` ### No Published Package Versions -- Problem: All packages in `packages/` have version `0.0.1` in their `package.json` files. None have been published to npm. +- Problem: All packages in `packages/` have version `1001.0.0` (Epoch Semantic Versioning placeholder) in their `package.json` files. None have been published to npm yet. - Blocks: External consumers cannot depend on the new libraries. External projects still must use the deprecated `@ickb/lumos-utils@1.4.2` and `@ickb/v1-core@1.4.2`. - Files: - - `packages/utils/package.json` - version `0.0.1` - - `packages/core/package.json` - version `0.0.1` - - `packages/dao/package.json` - version `0.0.1` - - `packages/order/package.json` - version `0.0.1` - - `packages/sdk/package.json` - version `0.0.1` + - `packages/utils/package.json` - version `1001.0.0` + - `packages/core/package.json` - version `1001.0.0` + - `packages/dao/package.json` - version `1001.0.0` + - `packages/order/package.json` - version `1001.0.0` + - `packages/sdk/package.json` - version `1001.0.0` ## Test Coverage Gaps @@ -249,13 +242,6 @@ ## Dead Code -### Faucet Diagnostic `main()` Function - -- Issue: `apps/faucet/src/index.ts` contains a `main()` function (lines 6-13) that queries DAO claim epochs from testnet. This is leftover diagnostic code. The actual faucet logic is in `main0()` (lines 16-90). The file calls the diagnostic `main()` at line 92. -- Files: `apps/faucet/src/index.ts`, lines 6-13 -- Impact: The faucet app does not perform its intended function when run. -- Fix approach: Remove diagnostic `main()`, rename `main0()` to `main()`. - ### `fromLumosSkeleton` in SmartTransaction - Issue: `SmartTransaction.fromLumosSkeleton()` at `packages/utils/src/transaction.ts` line 432 provides Lumos interoperability. Since the new packages do not use Lumos, this method is only needed if external code passes Lumos skeletons to the new packages. @@ -266,7 +252,7 @@ ### SmartTransaction Name is Misleading (Not Dead) - Issue: Despite the original "SmartTransaction" concept being abandoned ecosystem-wide, the `SmartTransaction` class in `packages/utils/src/transaction.ts` is actively used throughout the new packages. It extends `ccc.Transaction` with UDT handler management and header caching (which is what replaced the abandoned SmartTransaction headers concept). The name is a vestige but the code is alive and critical. -- Files: `packages/utils/src/transaction.ts` - definition (478 lines). Used in: `packages/sdk/src/sdk.ts`, `packages/order/src/order.ts`, `packages/dao/src/dao.ts`, `packages/core/src/owned_owner.ts`, `packages/core/src/logic.ts`, `apps/faucet/src/index.ts` +- Files: `packages/utils/src/transaction.ts` - definition (517 lines). Used in: `packages/sdk/src/sdk.ts`, `packages/order/src/order.ts`, `packages/dao/src/dao.ts`, `packages/core/src/owned_owner.ts`, `packages/core/src/logic.ts`, `apps/faucet/src/main.ts` - Impact: The name `SmartTransaction` may confuse developers familiar with the abandoned ecosystem concept. - Fix approach: Consider renaming to `IckbTransaction` or `EnhancedTransaction`. Low priority since the class is internal to the monorepo. diff --git a/.planning/codebase/CONVENTIONS.md b/.planning/codebase/CONVENTIONS.md index c88a5a9..160d0b6 100644 --- a/.planning/codebase/CONVENTIONS.md +++ b/.planning/codebase/CONVENTIONS.md @@ -158,7 +158,7 @@ if (!isChain(CHAIN)) { 5. **Async error handling in app loops** -- catch, log structured JSON, continue: ```typescript -// apps/bot/src/index.ts, apps/tester/src/index.ts, apps/faucet/src/index.ts +// apps/bot/src/index.ts, apps/tester/src/index.ts, apps/faucet/src/main.ts try { // ... main logic } catch (e) { @@ -257,7 +257,6 @@ async *findDeposits( ```typescript export * from "./codec.js"; export * from "./capacity.js"; -export * from "./epoch.js"; export * from "./heap.js"; export * from "./transaction.js"; export * from "./udt.js"; diff --git a/.planning/codebase/INTEGRATIONS.md b/.planning/codebase/INTEGRATIONS.md index 51e492f..f5e2795 100644 --- a/.planning/codebase/INTEGRATIONS.md +++ b/.planning/codebase/INTEGRATIONS.md @@ -10,7 +10,7 @@ All interaction with the Nervos CKB Layer 1 blockchain happens via JSON-RPC 2.0. **New CCC-based clients:** - `ccc.ClientPublicTestnet()` - Public CKB testnet RPC endpoint - - Used in: `apps/faucet/src/index.ts`, `apps/interface/src/main.tsx` + - Used in: `apps/faucet/src/main.ts`, `apps/interface/src/main.tsx` - `ccc.ClientPublicMainnet()` - Public CKB mainnet RPC endpoint - Used in: `apps/sampler/src/index.ts`, `apps/interface/src/main.tsx` - Custom RPC URL supported via env var in bot @@ -30,7 +30,7 @@ All interaction with the Nervos CKB Layer 1 blockchain happens via JSON-RPC 2.0. - `client.getHeaderByNumber()` / `client.getHeaderByHash()` - Get block headers - Used in: `packages/utils/src/utils.ts`, `apps/sampler/src/index.ts` - `client.getHeaderByNumberNoCache()` - Uncached header fetch - - Used in: `apps/faucet/src/index.ts` + - Used in: `apps/faucet/src/main.ts` - `client.getTransactionWithHeader()` - Get transaction with its block header - Used in: `packages/utils/src/utils.ts` - `client.getCell()` - Get individual cell by outpoint @@ -40,7 +40,7 @@ All interaction with the Nervos CKB Layer 1 blockchain happens via JSON-RPC 2.0. - `client.getFeeRate()` - Get current fee rate - Used in: `packages/sdk/src/sdk.ts` - `signer.sendTransaction()` - Submit signed transactions - - Used in: `apps/faucet/src/index.ts`, `apps/interface/src/Connector.tsx` + - Used in: `apps/faucet/src/main.ts`, `apps/interface/src/Connector.tsx` ### CKB Public RPC Endpoints @@ -82,7 +82,7 @@ All interaction with the Nervos CKB Layer 1 blockchain happens via JSON-RPC 2.0. **Wallet Signing (CCC-based):** - `ccc.SignerCkbPrivateKey` - Private key signer for programmatic signing - - Used in: `apps/faucet/src/index.ts` (generates random ephemeral keys) + - Used in: `apps/faucet/src/main.ts` (generates random ephemeral keys) - JoyId Signer - Browser wallet integration - Used in: `apps/interface/src/main.tsx` via `JoyId.getJoyIdSigners()` - CCC's `@ckb-ccc/ccc` package provides wallet connector framework @@ -213,7 +213,7 @@ union PartialOrderData { MintOrderData, MatchOrderData } **Logging:** - JSON structured logs to stdout - `apps/bot/src/index.ts`: Logs `{ startTime, balance, ratio, actions, txFee, txHash, error, ElapsedSeconds }` each iteration - - `apps/faucet/src/index.ts`: Logs `{ startTime, balance, error, txHash, elapsedSeconds }` each iteration + - `apps/faucet/src/main.ts`: Logs `{ startTime, balance, error, txHash, elapsedSeconds }` each iteration - `apps/sampler/src/index.ts`: Outputs CSV rows `BlockNumber, Date, Value, Note` - No log aggregation service diff --git a/.planning/codebase/STACK.md b/.planning/codebase/STACK.md index 70647b0..b54fed8 100644 --- a/.planning/codebase/STACK.md +++ b/.planning/codebase/STACK.md @@ -21,7 +21,7 @@ - Current environment: v24.13.0 **Package Manager:** -- pnpm 10.29.3 (pinned via `packageManager` field with SHA-512 hash in root `package.json`) +- pnpm 10.30.1 (pinned via `packageManager` field with SHA-512 hash in root `package.json`) - Lockfile: `pnpm-lock.yaml` present - Workspace protocol: `workspace:*` for internal deps, `catalog:` for shared version pins @@ -153,7 +153,7 @@ The repo supports using a local development build of CCC for testing unpublished ## Versioning -**Packages use version `1001.0.0`** - Placeholder version indicating pre-release / under active development. All publishable packages (`@ickb/utils`, `@ickb/dao`, `@ickb/order`, `@ickb/core`, `@ickb/sdk`) and apps use this. +**Packages use version `1001.0.0`** (Epoch Semantic Versioning) - All publishable packages (`@ickb/utils`, `@ickb/dao`, `@ickb/order`, `@ickb/core`, `@ickb/sdk`) use this version, managed by changesets. **Changesets** (`.changeset/config.json`): - Public access @@ -167,7 +167,7 @@ The repo supports using a local development build of CCC for testing unpublished **Development:** - Node.js >= 24 -- pnpm 10.29.3 +- pnpm 10.30.1 - Git (for CCC setup script) - DevContainer configuration at `.devcontainer/devcontainer.json` diff --git a/.planning/codebase/STRUCTURE.md b/.planning/codebase/STRUCTURE.md index 333ad79..1d7ac8d 100644 --- a/.planning/codebase/STRUCTURE.md +++ b/.planning/codebase/STRUCTURE.md @@ -34,7 +34,8 @@ │ │ └── codec.ts # PoolSnapshot codec (138 lines) │ └── utils/ # Shared blockchain utilities │ └── src/ -│ ├── index.ts # Barrel export: codec, capacity, heap, transaction, udt, utils│ ├── transaction.ts # SmartTransaction class (517 lines) +│ ├── index.ts # Barrel export: codec, capacity, heap, transaction, udt, utils +│ ├── transaction.ts # SmartTransaction class (517 lines) │ ├── capacity.ts # CapacityManager class (221 lines) │ ├── udt.ts # UDT calculations and handlers (393 lines) │ ├── utils.ts # Binary search, collectors, etc. (458 lines) @@ -46,8 +47,8 @@ │ │ └── index.ts # main() entry with order matching loop (897 lines) │ ├── faucet/ # Testnet CKB distribution (MIGRATED to CCC) │ │ └── src/ -│ │ ├── index.ts # Export main() -│ │ └── main.ts # main() entry with distribution loop (86 lines) +│ │ ├── index.ts # Entry: imports and calls main() from main.ts +│ │ └── main.ts # main() entry with distribution loop (88 lines) │ ├── sampler/ # Blockchain state sampling (MIGRATED to CCC) │ │ └── src/ │ │ └── index.ts # Direct execution entry (192 lines) diff --git a/.planning/codebase/TESTING.md b/.planning/codebase/TESTING.md index daf5e42..23da58b 100644 --- a/.planning/codebase/TESTING.md +++ b/.planning/codebase/TESTING.md @@ -11,7 +11,7 @@ - CCC PRs for UDT and Epochs have been **MERGED** upstream. - `SmartTransaction` was **ABANDONED** -- do not expand its test coverage; it exists in `packages/utils/src/transaction.ts` but header caching now uses CCC's client cache. -**Current test status:** No `.test.ts` files exist yet in the `packages/` or `apps/` source directories. Vitest is fully configured and ready. The CI pipeline has the test step **commented out** (see `.github/workflows/check.yaml`). Writing tests is a greenfield effort. +**Current test status:** No `.test.ts` files exist yet in the `packages/` or `apps/` source directories. Vitest is fully configured and ready. The CI pipeline runs `pnpm check` which includes `pnpm test:ci`, but with no test files `vitest run` passes vacuously. Writing tests is a greenfield effort. ## Test Framework @@ -111,32 +111,39 @@ Use `describe` for grouping by class or function, `it` or `test` for individual ```typescript import { describe, expect, it } from "vitest"; -import { Epoch } from "./epoch.js"; +import { Ratio } from "./entities.js"; -describe("Epoch", () => { +describe("Ratio", () => { describe("from", () => { - it("creates from tuple representation", () => { - const epoch = Epoch.from([5n, 2n, 4n]); - expect(epoch.number).toBe(5n); - expect(epoch.index).toBe(1n); // normalized: 2/4 -> 1/2 - expect(epoch.length).toBe(2n); + it("creates from plain object", () => { + const ratio = Ratio.from({ ckbScale: 3n, udtScale: 4n }); + expect(ratio.ckbScale).toBe(3n); + expect(ratio.udtScale).toBe(4n); }); - it("short-circuits on Epoch instance", () => { - const epoch = Epoch.from([5n, 0n, 1n]); - expect(Epoch.from(epoch)).toBe(epoch); + it("short-circuits on Ratio instance", () => { + const ratio = new Ratio(10n, 20n); + expect(Ratio.from(ratio)).toBe(ratio); }); + }); - it("throws on non-positive length", () => { - expect(() => Epoch.from([0n, 0n, 0n])).toThrow("Non positive Epoch length"); + describe("validate", () => { + it("accepts populated ratio", () => { + const r = new Ratio(100n, 200n); + expect(() => r.validate()).not.toThrow(); + expect(r.isValid()).toBe(true); }); - }); - describe("compare", () => { - it("returns 0 for equal epochs", () => { - const a = Epoch.from([5n, 1n, 2n]); - const b = Epoch.from([5n, 2n, 4n]); - expect(a.compare(b)).toBe(0); + it("accepts empty ratio", () => { + const r = Ratio.empty(); + expect(() => r.validate()).not.toThrow(); + expect(r.isValid()).toBe(true); + }); + + it("rejects half-populated ratio", () => { + const r = new Ratio(100n, 0n); + expect(() => r.validate()).toThrow("not empty, not populated"); + expect(r.isValid()).toBe(false); }); }); }); @@ -359,19 +366,11 @@ describe("Ratio.compare", () => { **Current state in `.github/workflows/check.yaml`:** ```yaml -- name: Build - run: pnpm build:all -- name: Lint - run: pnpm lint -# - name: Test -# run: pnpm test:ci +- name: Check (lint, build and test) + run: pnpm check ``` -The test step is **commented out**. Once tests are written, uncomment to enable: -```yaml -- name: Test - run: pnpm test:ci -``` +The `pnpm check` script runs: `pnpm clean:deep && pnpm install && pnpm lint && pnpm build:all && pnpm test:ci`. Tests are included but with no test files, `vitest run` passes vacuously. **CI runs on:** `[pull_request, push]` events, `ubuntu-latest`, Node.js 24, pnpm. diff --git a/.planning/config.json b/.planning/config.json new file mode 100644 index 0000000..a066169 --- /dev/null +++ b/.planning/config.json @@ -0,0 +1,12 @@ +{ + "mode": "interactive", + "depth": "comprehensive", + "parallelization": false, + "commit_docs": true, + "model_profile": "quality", + "workflow": { + "research": true, + "plan_check": true, + "verifier": true + } +} diff --git a/.planning/research/ARCHITECTURE.md b/.planning/research/ARCHITECTURE.md new file mode 100644 index 0000000..b444de2 --- /dev/null +++ b/.planning/research/ARCHITECTURE.md @@ -0,0 +1,603 @@ +# Architecture Research + +**Domain:** CCC-based blockchain library suite refactoring (iCKB protocol) +**Researched:** 2026-02-21 +**Confidence:** HIGH + +## Standard Architecture + +### System Overview + +``` ++-------------------------------------------------------------------+ +| Application Layer | +| +----------+ +----------+ +----------+ +---------+ +--------+ | +| | bot | | interface | | tester | | faucet | | sampler| | +| | (Lumos) | | (Lumos) | | (Lumos) | | (CCC) | | (CCC) | | +| +----+-----+ +----+-----+ +----+-----+ +----+----+ +---+----+ | +| | | | | | | ++-------+--------------+--------------+-------------+------------+----+ + | ++-------------------------------------------------------------------+ +| SDK Composition Layer | +| +---------------------------------------------------------------+ | +| | @ickb/sdk (IckbSdk) | | +| | estimate() | maturity() | request() | collect() | getL1State | | +| +---------------------------------------------------------------+ | +| | | | | | ++-------+--------------+--------------+-------------+-----------------+ +| Domain Layer | +| +-----------+ +---------------+ +--------------------+ | +| | @ickb/dao | | @ickb/order | | @ickb/core | | +| | DaoManager| | OrderManager | | LogicManager | | +| | | | OrderMatcher | | OwnedOwnerManager | | +| | | | | | IckbUdtManager | | +| +-----------+ +---------------+ +--------------------+ | +| | | | | | ++-------+--------------+--------------+-------------+-----------------+ +| Utilities Layer | +| +---------------------------------------------------------------+ | +| | @ickb/utils | | +| | SmartTransaction | CapacityManager | UdtManager | UdtHandler | | +| | collect() | unique() | binarySearch() | MinHeap | | +| +---------------------------------------------------------------+ | +| | | ++------------------------------+--------------------------------------+ +| Foundation Layer | +| +---------------------------------------------------------------+ | +| | @ckb-ccc/core | | +| | Transaction | Client | Signer | Script | Epoch | Molecule | | +| +---------------------------------------------------------------+ | +| +---------------------------------------------------------------+ | +| | @ckb-ccc/udt (CCC's Udt class) | | +| | Udt | UdtInfo | completeInputsByBalance | completeBy | | +| +---------------------------------------------------------------+ | ++-------------------------------------------------------------------+ +``` + +### Component Responsibilities + +| Component | Responsibility | Communicates With | +|-----------|---------------|-------------------| +| `@ickb/utils` | Transaction building, capacity management, generic UDT handling, shared utilities | `@ckb-ccc/core` | +| `@ickb/dao` | NervosDAO deposit/withdrawal/request operations, DaoCell wrapping | `@ickb/utils`, `@ckb-ccc/core` | +| `@ickb/order` | Limit order minting/matching/melting, order cell management, exchange ratio math | `@ickb/utils`, `@ckb-ccc/core` | +| `@ickb/core` | iCKB protocol logic: deposits, receipts, owned-owner pairing, iCKB UDT calculations | `@ickb/dao`, `@ickb/utils`, `@ckb-ccc/core` | +| `@ickb/sdk` | Composes all domain managers into a high-level facade. System state fetching, conversion estimates, order lifecycle | All `@ickb/*` packages | +| Apps | User-facing applications consuming the SDK | `@ickb/sdk` (or individual packages) | + +## Recommended Architecture After Refactoring + +### Target: Remove SmartTransaction, Adopt CCC Udt + +The refactored architecture replaces `SmartTransaction` (a subclass of `ccc.Transaction`) with plain `ccc.Transaction` plus utility functions, and replaces the local `UdtHandler`/`UdtManager` with CCC's `Udt` class (possibly subclassed for iCKB). + +``` ++-------------------------------------------------------------------+ +| Application Layer | +| +----------+ +----------+ +----------+ +---------+ +--------+ | +| | bot | | interface | | tester | | faucet | | sampler| | +| | (CCC) | | (CCC) | | (CCC) | | (CCC) | | (CCC) | | +| +----+-----+ +----+-----+ +----+-----+ +----+----+ +---+----+ | +| | | | | | | ++-------+--------------+--------------+-------------+------------+----+ + | ++-------------------------------------------------------------------+ +| SDK Composition Layer | +| +---------------------------------------------------------------+ | +| | @ickb/sdk (IckbSdk) | | +| | estimate() | maturity() | request() | collect() | getL1State | | +| | Uses: ccc.Transaction (plain) + utility functions | | +| +---------------------------------------------------------------+ | +| | | | | | ++-------+--------------+--------------+-------------+-----------------+ +| Domain Layer | +| +-----------+ +---------------+ +--------------------+ | +| | @ickb/dao | | @ickb/order | | @ickb/core | | +| | DaoManager| | OrderManager | | LogicManager | | +| | | | OrderMatcher | | OwnedOwnerManager | | +| | | | | | IckbUdt (extends | | +| | | | | | ccc Udt) | | +| +-----------+ +---------------+ +--------------------+ | +| | | | | | ++-------+--------------+--------------+-------------+-----------------+ +| Utilities Layer | +| +---------------------------------------------------------------+ | +| | @ickb/utils | | +| | addCellDeps() | getHeader() utilities | | +| | collect() | unique() | binarySearch() | MinHeap | | +| | (NO SmartTransaction, NO UdtHandler, NO UdtManager, | | +| | NO CapacityManager -- replaced by CCC completeInputs*) | | +| +---------------------------------------------------------------+ | +| | | ++------------------------------+--------------------------------------+ +| Foundation Layer | +| +---------------------------------------------------------------+ | +| | @ckb-ccc/core + @ckb-ccc/udt | | +| | Transaction (with completeFee, completeInputsByCapacity) | | +| | Udt (with completeInputsByBalance, completeBy, infoFrom) | | +| | Client | Signer | Script | Epoch | Molecule | | +| +---------------------------------------------------------------+ | ++-------------------------------------------------------------------+ +``` + +### Key Architectural Changes + +**1. SmartTransaction Removal** + +Current state: `SmartTransaction extends ccc.Transaction` adding: +- `udtHandlers: Map` for tracking UDT balancing +- `headers: Map` for header caching +- Overrides `completeFee()` to call UDT handlers first +- Overrides `getInputsUdtBalance()`/`getOutputsUdtBalance()` to delegate to handlers +- Overrides `getInputsCapacity()` to account for DAO withdrawal profit + +Target: All manager methods accept `ccc.Transaction` instead of `SmartTransaction`. Each concern migrates to a different place: + +| SmartTransaction feature | Replacement | +|---|---| +| `udtHandlers` map + `addUdtHandlers()` | CCC `Udt.completeBy()` / `Udt.completeInputsByBalance()` called at transaction completion time | +| `completeFee()` override that calls UDT handlers | App-level orchestration: call `ickbUdt.completeBy(tx, signer)` then `tx.completeFeeBy(signer)` | +| `getInputsUdtBalance()`/`getOutputsUdtBalance()` overrides | `IckbUdt.getInputsInfo(client, tx)` / `IckbUdt.getOutputsInfo(client, tx)` | +| `getInputsCapacity()` DAO profit override | Not needed -- CCC's `Transaction.getInputsCapacity()` handles DAO profit natively via `getInputsCapacityExtra()` -> `Cell.getDaoProfit()` | +| `headers` map + `addHeaders()` + `getHeader()` | CCC's Client Cache (already caches headers). For header-dependent operations, pass headers explicitly or use client.getHeader() | +| `addCellDeps()` deduplication | Utility function `addCellDeps(tx, deps)` (simple, no class needed) | +| `SmartTransaction.default()` | `ccc.Transaction.default()` | + +**2. CCC Udt Adoption for iCKB** + +CCC's `Udt` class (from `@ckb-ccc/udt`) provides: +- `isUdt(cell)` -- checks type script match + data length >= 16 +- `getInputsInfo(client, tx)` / `getOutputsInfo(client, tx)` -- returns `UdtInfo { balance, capacity, count }` +- `completeInputsByBalance(tx, signer)` -- adds UDT inputs to cover outputs +- `completeBy(tx, signer)` -- complete with change to signer's recommended address +- `completeChangeToLock(tx, signer, lock)` -- complete with change to specific lock +- `balanceFrom(client, cells)` -- extract balance from cells +- `infoFrom(client, cells, acc)` -- extract and accumulate UDT info from cells + +iCKB's triple-representation value requires custom balance calculation to account for: +1. Standard xUDT cells (balance from first 16 bytes of output data) -- standard Udt behavior +2. Receipt cells (valued as `depositQuantity * ickbValue(depositAmount, header)`) +3. iCKB deposit cells consumed as inputs (negative iCKB value: `-ickbValue(cell.capacityFree, header)`) + +**Recommended approach: Subclass `Udt` as `IckbUdt`, overriding `getInputsInfo()` and `getOutputsInfo()`.** + +The natural override point would be `infoFrom()` (called by all balance/info methods), but `infoFrom()` receives `CellAnyLike` which lacks `outPoint` -- needed to fetch the deposit header via transaction hash for receipt and deposit value calculation. Instead, `getInputsInfo()` and `getOutputsInfo()` receive the full transaction, so input outpoints are available for header lookups. + +```typescript +// packages/core/src/udt.ts -- refactored +import { udt } from "@ckb-ccc/udt"; + +export class IckbUdt extends udt.Udt { + constructor( + code: ccc.OutPointLike, + script: ccc.ScriptLike, + public readonly logicScript: ccc.Script, + public readonly daoManager: DaoManager, + config?: udt.UdtConfigLike | null, + ) { + super(code, script, config); + } + + /** + * Override getInputsInfo to account for iCKB's three value representations: + * 1. xUDT cells (standard 16-byte balance) + * 2. Receipt cells (type = logicScript, balance = depositQuantity * ickbValue) + * 3. Deposit cells being withdrawn (lock = logicScript + DAO deposit, + * negative balance = -ickbValue) + * + * Uses getInputsInfo (not infoFrom) because receipt/deposit value calculation + * requires the cell's outPoint for header fetching, which CellAnyLike lacks. + */ + override async getInputsInfo( + client: ccc.Client, + txLike: ccc.TransactionLike, + ): Promise { + const tx = ccc.Transaction.from(txLike); + const info = udt.UdtInfo.default(); + + for (const input of tx.inputs) { + const cell = await input.getCell(client); + if (!cell) continue; + + // Standard xUDT + if (this.isUdt(cell)) { + info.addAssign({ + balance: udt.Udt.balanceFromUnsafe(cell.outputData), + capacity: cell.cellOutput.capacity, + count: 1, + }); + continue; + } + + // iCKB Receipt + if (cell.cellOutput.type?.eq(this.logicScript)) { + const header = await client.getHeaderByTxHash(input.previousOutput.txHash); + const { depositQuantity, depositAmount } = ReceiptData.decode(cell.outputData); + info.addAssign({ + balance: ickbValue(depositAmount, header) * BigInt(depositQuantity), + capacity: cell.cellOutput.capacity, + count: 1, + }); + continue; + } + + // iCKB Deposit being withdrawn (negative UDT balance) + if (cell.cellOutput.lock.eq(this.logicScript) && this.daoManager.isDeposit(cell)) { + const header = await client.getHeaderByTxHash(input.previousOutput.txHash); + info.addAssign({ + balance: -ickbValue(cell.capacityFree, header), + capacity: cell.cellOutput.capacity, + count: 1, + }); + continue; + } + } + + return info; + } +} +``` + +This approach works because: +- CCC's `Udt.completeInputsByBalance()` calls `this.getInputsInfo()` -- overriding it changes balancing behavior +- CCC's `Udt.getBalanceBurned()` delegates to `getInputsBalance()` - `getOutputsBalance()` which call `getInputsInfo()`/`getOutputsInfo()` -- so the conservation law check naturally accounts for all three representations +- The `completeBy()` and `completeChangeToLock()` methods automatically work with the overridden balance calculation +- Input outpoints are available in `tx.inputs`, enabling header fetching for receipt/deposit value calculation + +**Note:** This is a preliminary design. The viability of subclassing CCC's `Udt` is an open question to be resolved during Phase 3 (UDT Investigation). See Pitfall 2 in PITFALLS.md for the risks involved. + +**3. DAO Capacity Calculation** + +`SmartTransaction.getInputsCapacity()` is currently overridden to add DAO withdrawal profit. **This override is no longer needed** — CCC's `Transaction.getInputsCapacity()` already handles DAO profit natively via `getInputsCapacityExtra()` -> `CellInput.getExtraCapacity()` -> `Cell.getDaoProfit()` (verified from CCC source, see STACK.md lines 116-132). No standalone utility function is required; simply removing the override and using the base `ccc.Transaction.getInputsCapacity()` is sufficient. + +### Component Boundaries After Refactoring + +| Component | Owns | Does NOT Own | +|-----------|------|-------------| +| `@ickb/utils` | `addCellDeps()` utility, `getHeader()` utility, `collect()`, `unique()`, `binarySearch()`, `MinHeap`, `BufferedGenerator`, codec utilities | No SmartTransaction, no UdtHandler, no UdtManager, no CapacityManager (replaced by CCC's `completeInputsByCapacity`), no header caching | +| `@ickb/dao` | `DaoManager` (deposit/withdraw/requestWithdrawal/find operations), `DaoCell` wrapping | No UDT concerns, no DAO capacity utility (CCC handles natively) | +| `@ickb/order` | `OrderManager` (convert/mint/match/melt/find), `OrderMatcher`, `OrderCell`/`MasterCell`/`OrderGroup`, `Info`/`Ratio`/`OrderData` entities | No direct UDT balancing (delegates to UDT handler) | +| `@ickb/core` | `LogicManager` (deposit/completeDeposit/findReceipts/findDeposits), `OwnedOwnerManager`, `IckbUdt extends udt.Udt` (triple-representation balancing), iCKB exchange rate math | No generic UDT handling | +| `@ickb/sdk` | `IckbSdk` facade, `SystemState`, config/constants, pool snapshot codec. Orchestrates all managers. | No direct cell operations | + +## Data Flow + +### Transaction Building Flow (Post-Refactoring) + +``` +App creates: tx = ccc.Transaction.default() + | + v +Manager operations (domain layer): + orderManager.mint(tx, lock, info, amounts) // Adds outputs, cellDeps + logicManager.deposit(tx, qty, amount, lock) // Adds DAO outputs, receipt + daoManager.requestWithdrawal(tx, deposits, lock) // Adds inputs/outputs + | + v +UDT completion (IckbUdt): + ickbUdt.completeBy(tx, signer) // Adds UDT inputs + change + | + v +Fee completion (ccc.Transaction): + tx.completeFeeBy(signer) // Adds capacity inputs + change + | + v +Sign and send: + signer.sendTransaction(tx) +``` + +### iCKB Value Conservation Flow + +``` +Input UDT + Input Receipts = Output UDT + Input Deposits + +getInputsInfo(): + For each input cell: + if xUDT cell -> balance += UDT amount (16 bytes LE) + if receipt cell -> balance += qty * ickbValue(amount, depositHeader) + if deposit cell -> balance -= ickbValue(capacityFree, depositHeader) + (deposits consumed as inputs reduce UDT balance) + +getOutputsInfo(): + For each output cell: + if xUDT cell -> balance += UDT amount (16 bytes LE) + (receipts and deposits are NOT counted in outputs because + they are tracked by the contract's conservation law) +``` + +### State Discovery Flow + +``` +IckbSdk.getL1State(client, locks): + | + +-> client.getTipHeader() -> tip header + +-> ickbExchangeRatio(tip) -> exchange ratio + | + +-> Parallel: + | +-> getCkb(client, tip) -> ckbAvailable, ckbMaturing + | +-> order.findOrders(client) -> all order groups + | +-> client.getFeeRate() -> fee rate + | + +-> Filter orders into user/system + +-> Estimate maturity for user orders + | + v + SystemState { feeRate, tip, exchangeRatio, orderPool, ckbAvailable, ckbMaturing } +``` + +### Manager Method Signatures (Before vs After) + +**Before (SmartTransaction):** +```typescript +// All managers require SmartTransaction +daoManager.deposit(tx: SmartTransaction, capacities, lock): void +orderManager.mint(tx: SmartTransaction, lock, info, amounts): void +logicManager.deposit(tx: SmartTransaction, qty, amount, lock): void +``` + +**After (plain ccc.Transaction):** +```typescript +// All managers accept plain ccc.Transaction +daoManager.deposit(tx: ccc.Transaction, capacities, lock): void +orderManager.mint(tx: ccc.Transaction, lock, info, amounts): void +logicManager.deposit(tx: ccc.Transaction, qty, amount, lock): void +``` + +The key difference: managers no longer call `tx.addUdtHandlers()` or `tx.addHeaders()`. Instead: +- CellDeps are added via `tx.addCellDeps()` (already exists on `ccc.Transaction`) +- UDT completion is handled by the caller at transaction completion time +- Headers are fetched from the client cache or passed explicitly when needed + +## Architectural Patterns + +### Pattern 1: Manager + Utility Functions (replacing Manager + SmartTransaction) + +**What:** Stateless manager classes with methods that operate on plain `ccc.Transaction`. Side concerns (UDT balancing, fee completion) handled by caller using CCC-native methods. + +**When to use:** All domain operations that modify transactions. + +**Trade-offs:** +- Pro: Managers are simpler, no coupling to custom transaction subclass +- Pro: Callers can use any completion strategy (CCC's completeFeeBy, completeFeeChangeToOutput, etc.) +- Con: Caller must remember to call UDT completion and fee completion separately +- Con: Slightly more boilerplate at call sites + +**Example:** +```typescript +// Application code (e.g., bot) +const tx = ccc.Transaction.default(); + +// Domain operations +orderManager.addMatch(tx, bestMatch); + +// UDT completion (new pattern using CCC Udt) +const completedTx = await ickbUdt.completeBy(tx, signer); + +// Fee completion (CCC native) +await completedTx.completeFeeBy(signer); + +// Send +await signer.sendTransaction(completedTx); +``` + +### Pattern 2: IckbUdt Subclass with Overridden Balance Calculation + +**What:** `IckbUdt extends udt.Udt` overriding `getInputsInfo()` and `getOutputsInfo()` to account for the triple-representation value model. + +**When to use:** Whenever iCKB UDT balancing is needed (order creation, deposit completion, any tx involving iCKB tokens). + +**Trade-offs:** +- Pro: All CCC Udt methods (completeBy, completeInputsByBalance, getBalanceBurned) automatically work with iCKB's special value model +- Pro: Consistent with CCC ecosystem patterns -- other projects can adopt the same pattern +- Con: Requires header fetching inside getInputsInfo(), which adds async complexity +- Con: `IckbUdt` needs references to `logicScript` and `daoManager` for cell type detection + +**Example:** +```typescript +export class IckbUdt extends udt.Udt { + constructor( + code: ccc.OutPointLike, + script: ccc.ScriptLike, + public readonly logicScript: ccc.Script, + public readonly daoManager: DaoManager, + ) { + super(code, script); + } + + override async getInputsInfo( + client: ccc.Client, + txLike: ccc.TransactionLike, + ): Promise { + const tx = ccc.Transaction.from(txLike); + const info = udt.UdtInfo.default(); + + for (const input of tx.inputs) { + const cell = await input.getCell(client); + if (!cell) continue; + + // Standard xUDT + if (this.isUdt(cell)) { + info.addAssign({ + balance: udt.Udt.balanceFromUnsafe(cell.outputData), + capacity: cell.cellOutput.capacity, + count: 1, + }); + continue; + } + + // iCKB Receipt + if (cell.cellOutput.type?.eq(this.logicScript)) { + const header = await client.getHeaderByTxHash(input.previousOutput.txHash); + const { depositQuantity, depositAmount } = ReceiptData.decode(cell.outputData); + info.addAssign({ + balance: ickbValue(depositAmount, header) * BigInt(depositQuantity), + capacity: cell.cellOutput.capacity, + count: 1, + }); + continue; + } + + // iCKB Deposit being withdrawn (negative UDT balance) + if (cell.cellOutput.lock.eq(this.logicScript) && this.daoManager.isDeposit(cell)) { + const header = await client.getHeaderByTxHash(input.previousOutput.txHash); + info.addAssign({ + balance: -ickbValue(cell.capacityFree, header), + capacity: cell.cellOutput.capacity, + count: 1, + }); + continue; + } + } + + return info; + } +} +``` + +### Pattern 3: Explicit Transaction Completion Pipeline + +**What:** Instead of SmartTransaction's "magic" `completeFee()` that internally handles UDT balancing, make the completion pipeline explicit at the call site. + +**When to use:** All application-level transaction building. + +**Trade-offs:** +- Pro: Transparent -- every step is visible +- Pro: Composable -- easy to add/remove steps +- Pro: No hidden state (no udtHandlers map, no headers map) +- Con: Every call site must follow the same pattern (consider a helper function) + +**Example:** +```typescript +// Helper function to standardize the completion pipeline +export async function completeIckbTransaction( + tx: ccc.Transaction, + signer: ccc.Signer, + ickbUdt: IckbUdt, +): Promise { + // Step 1: Complete iCKB UDT inputs and change + const completedTx = await ickbUdt.completeBy(tx, signer); + + // Step 2: Complete CKB fee (with DAO profit awareness if needed) + await completedTx.completeFeeBy(signer); + + return completedTx; +} +``` + +## Anti-Patterns + +### Anti-Pattern 1: Extending ccc.Transaction with Custom Subclass + +**What people do:** Create `SmartTransaction extends ccc.Transaction` to add domain-specific state. + +**Why it's wrong:** +- CCC's methods (`completeFee`, `completeInputsByCapacity`) return `ccc.Transaction`, not the subclass -- leading to type coercion issues +- The subclass couples UDT concerns (balancing) with transaction concerns (inputs/outputs) into one God object +- CCC's `Udt` class already provides the UDT completion features that SmartTransaction implemented +- The ecosystem rejected this pattern (no adoption) +- Makes it impossible to use CCC's newer completion methods directly + +**Do this instead:** Use plain `ccc.Transaction` and compose domain operations through utility functions and CCC's `Udt` class. + +### Anti-Pattern 2: Storing Headers in the Transaction Object + +**What people do:** Keep a `headers: Map` on SmartTransaction for lookups during balance calculation. + +**Why it's wrong:** +- CCC's Client Cache already caches headers fetched via the client +- The headers map creates shared mutable state between cloned transactions +- Header dependencies (`headerDeps`) are already tracked by `ccc.Transaction` + +**Do this instead:** Use `client.getHeaderByTxHash()` or `client.getHeaderByNumber()` and rely on CCC's client-side caching. For transaction-specific header operations (like DAO profit calculation), pass headers explicitly. + +### Anti-Pattern 3: Generic UdtHandler Interface in Utils + +**What people do:** Define a `UdtHandler` interface in `@ickb/utils` that all UDT types implement. + +**Why it's wrong:** +- CCC's `Udt` class already provides this abstraction with a richer API +- The custom `UdtHandler` interface creates a parallel type system that doesn't interop with CCC ecosystem tools +- Forces `SmartTransaction` dependency (methods take `SmartTransaction` parameter) + +**Do this instead:** Use CCC's `Udt` class directly. For iCKB-specific behavior, subclass `Udt`. + +## Build Order (Dependency-Driven) + +The refactoring must proceed bottom-up through the dependency graph: + +``` +Phase 1: @ickb/utils (foundation -- remove SmartTransaction, UdtHandler, UdtManager) + | + v +Phase 2: @ickb/dao (update DaoManager to use ccc.Transaction) + | + v +Phase 3: @ickb/order (update OrderManager to use ccc.Transaction) + | \ + v v +Phase 4: @ickb/core (update LogicManager, OwnedOwnerManager; create IckbUdt) + | + v +Phase 5: @ickb/sdk (update IckbSdk to use new completion pipeline) + | + v +Phase 6: Apps (migrate bot, interface, tester from Lumos to CCC + new packages) +``` + +**Rationale for this order:** + +1. **@ickb/utils first** because every other package imports it. SmartTransaction removal here unlocks all downstream changes. + +2. **@ickb/dao before @ickb/order and @ickb/core** because `@ickb/core` depends on `@ickb/dao` (LogicManager has a DaoManager). Order and core can be done in parallel since neither depends on the other directly. + +3. **@ickb/core before @ickb/sdk** because IckbUdt (in core) must exist before SDK can use it for the completion pipeline. + +4. **@ickb/sdk before apps** because apps consume the SDK. + +5. **Apps last** because they are the consumers and the most work. The migrated faucet/sampler apps will also need updating if their SmartTransaction usage changes. + +**Critical dependency:** The `IckbUdt` subclass design in Phase 4 is the riskiest and most uncertain part. If CCC's `Udt` class cannot be subclassed effectively for the triple-representation model, the architecture may need to fall back to a wrapper pattern rather than inheritance. Phase-specific research recommended. + +## Integration Points + +### External Services + +| Service | Integration Pattern | Notes | +|---------|---------------------|-------| +| CKB RPC (via CCC Client) | `ccc.ClientPublicTestnet` / `ccc.ClientPublicMainnet` | All chain queries, cell discovery, transaction submission | +| CCC Client Cache | Transparent caching of headers, cells | Replaces SmartTransaction's `headers` map | +| JoyId Wallet (interface app) | CCC Signer abstraction | No direct API calls, uses CCC's wallet connector pattern | + +### Internal Boundaries + +| Boundary | Communication | Notes | +|----------|---------------|-------| +| Utils <-> Domain | Domain managers call utility functions, use CapacityManager | Direction: domain calls utils, never reverse | +| Domain <-> SDK | SDK instantiates and orchestrates domain managers | SDK owns manager lifecycle via `getConfig()` | +| SDK <-> Apps | Apps call SDK methods, receive immutable snapshots | `SystemState` is a plain readonly object, no circular dependency | +| Domain <-> CCC Udt | `IckbUdt extends udt.Udt` in `@ickb/core` | CCC Udt is the extension point; iCKB does NOT modify CCC code | +| All packages <-> CCC | Import `{ ccc } from "@ckb-ccc/core"` | One-way dependency: iCKB depends on CCC, never reverse. PRs go upstream | + +## Scaling Considerations + +| Scale | Architecture Adjustments | +|-------|--------------------------| +| Current (few users, single bot) | Monolith is fine. Single process bot, single RPC endpoint | +| Multiple bots | Bot lock script array in SDK already supports this. No architecture change needed | +| High-frequency order matching | OrderManager.bestMatch() is O(n^2) over order pool. If order count grows beyond ~1000, consider pre-indexing by ratio range | +| Multiple UDT types | CCC's Udt class is per-token instance. Each additional token requires a new Udt instance with its own script. The IckbUdt subclass is specific to iCKB -- other tokens use base Udt | + +## Sources + +- CCC `@ckb-ccc/udt` source code: `/workspaces/stack/ccc-dev/ccc/packages/udt/src/udt/index.ts` (HIGH confidence -- direct code examination) +- CCC `@ckb-ccc/core` Transaction class: `/workspaces/stack/ccc-dev/ccc/packages/core/src/ckb/transaction.ts` (HIGH confidence -- direct code examination) +- Current SmartTransaction: `/workspaces/stack/packages/utils/src/transaction.ts` (HIGH confidence -- direct code examination) +- Current IckbUdtManager: `/workspaces/stack/packages/core/src/udt.ts` (HIGH confidence -- direct code examination) +- Current UdtManager/UdtHandler: `/workspaces/stack/packages/utils/src/udt.ts` (HIGH confidence -- direct code examination) +- PROJECT.md decisions and context (HIGH confidence -- project documentation) +- Current codebase architecture analysis: `.planning/codebase/ARCHITECTURE.md` (HIGH confidence) + +--- +*Architecture research for: iCKB library suite CCC refactoring* +*Researched: 2026-02-21* diff --git a/.planning/research/FEATURES.md b/.planning/research/FEATURES.md new file mode 100644 index 0000000..6f42507 --- /dev/null +++ b/.planning/research/FEATURES.md @@ -0,0 +1,223 @@ +# Feature Research + +**Domain:** CCC-based CKB protocol library suite (NervosDAO liquidity / iCKB) +**Researched:** 2026-02-21 +**Confidence:** HIGH (based on codebase analysis, CCC docs, existing protocol architecture, npm ecosystem survey) + +## Feature Landscape + +### Table Stakes (Users Expect These) + +Features that library consumers (app developers, frontends, the bot) expect to exist. Missing any of these means the library suite is not production-ready for npm publication. + +| Feature | Why Expected | Complexity | Notes | +|---------|--------------|------------|-------| +| **TS-1: SmartTransaction removal** | SmartTransaction extends `ccc.Transaction` with abandoned ecosystem semantics; consumers expect to work with plain `ccc.Transaction` | HIGH | Core refactor touching all 5 packages and all managers. Replace with utility functions that operate on `ccc.Transaction` directly. UDT handler map and header cache must be externalized or passed as parameters. | +| **TS-2: CCC utility deduplication** | Library consumers expect no redundant code when CCC already provides equivalents | LOW | Adopt `ccc.numMax`/`ccc.numMin` for `max`/`min`, CCC's `gcd()`, `isHex()`, `hexFrom()`. Keep iCKB-unique utilities (`binarySearch`, `shuffle`, `unique`, `collect`, `BufferedGenerator`, `MinHeap`). | +| **TS-3: Clean public API surface** | npm packages must export only intentional public API, not internal implementation details | MEDIUM | Audit all `export *` barrel files. Mark internal symbols with `@internal` or move to non-exported files. Ensure each package's entry point (`index.ts`) is curated. | +| **TS-4: Complete Lumos removal** | Consumers expect zero `@ckb-lumos/*` dependencies in the published library packages | MEDIUM | Library packages (`packages/*`) already use CCC. Lumos remains only in legacy apps (`bot`, `interface`, `tester`). App migration is the gate. Legacy packages `@ickb/lumos-utils` and `@ickb/v1-core` should not be dependencies of any new package. | +| **TS-5: Bot app migration to CCC** | Bot is the primary protocol operator; it must use the new library packages to validate they work end-to-end | HIGH | 897-line file using `@ickb/v1-core` + `@ckb-lumos/*`. Needs full rewrite to use `@ickb/sdk` + `@ickb/core` + CCC signers. Validates the entire library stack under real production load. | +| **TS-6: Interface app migration to CCC** | The user-facing DApp must use the new packages; shipping two implementations is unsustainable | MEDIUM | Straight migration (same UI). Swap `@ickb/v1-core` + `@ckb-lumos/*` for `@ickb/sdk` + CCC. React + TanStack Query architecture stays. ~1,158 lines across 8 files. Already uses CCC for wallet connection. | +| **TS-7: Tester app migration to CCC** | Tester validates protocol behavior; must exercise the new packages | MEDIUM | 469-line simulation file. Similar migration pattern to bot. | +| **TS-8: Correct NervosDAO operation semantics** | Deposit, withdrawal request, and withdrawal must work correctly with all DAO constraints (64-output limit, epoch-based since, header deps) | Already done | Already implemented in `DaoManager`. Validated by existing faucet/sampler apps. Maintain and verify during SmartTransaction removal. | +| **TS-9: iCKB conservation law enforcement** | `Input UDT + Input Receipts = Output UDT + Input Deposits` must be maintained in all transaction construction | Already done | Enforced by on-chain contract. Library must construct transactions that satisfy this invariant. `IckbUdtManager.getInputsUdtBalance` already accounts for all three representations. | +| **TS-10: Multi-network support (mainnet/testnet)** | Protocol is deployed on both networks; library must support both via `IckbSdk.from("mainnet" | "testnet")` | Already done | Already implemented in `constants.ts` with per-network dep groups and bot scripts. Devnet support via custom config objects. | +| **TS-11: npm publication with provenance** | CKB ecosystem expects packages on npm with `access: public` and `provenance: true` for supply chain verification | LOW | Already configured. Changeset-based versioning (`1001.0.0`). Ensure `package.json` files have correct `exports`, `types`, `main` fields pointing to built output. | +| **TS-12: Proper TypeScript type exports** | Library consumers expect full type information, strict mode compatibility, and no `any` leaks in public API | MEDIUM | Strict mode already enforced (`noUncheckedIndexedAccess`, `verbatimModuleSyntax`, `noImplicitOverride`). Audit public-facing types for completeness. Ensure `.d.ts` files are generated and referenced. | + +### Differentiators (Competitive Advantage) + +Features that set the iCKB library suite apart from other CKB protocol libraries (Lumos, CKB SDK JS, RGB++ SDK, NervDAO). Not required for launch, but make the library significantly more valuable. + +| Feature | Value Proposition | Complexity | Notes | +|---------|-------------------|------------|-------| +| **D-1: Multi-representation UDT value tracking** | iCKB value exists as xUDT tokens + receipt cells + DAO deposit cells simultaneously. No other CKB library handles this. The `IckbUdtManager` already computes unified balance across all three forms. | Already done (needs refinement) | Current implementation lives inside `SmartTransaction` override. After SmartTransaction removal, this logic must be preserved as standalone functions or a CCC `Udt`-compatible interface. Key differentiator: a UDT whose balance cannot be determined by reading cell data alone -- requires header lookups and receipt decoding. | +| **D-2: CCC Udt subclassing investigation** | If CCC's `Udt` class (via SSRI) can be extended for iCKB's multi-representation value, it would make iCKB a first-class citizen in the CCC ecosystem. Other protocol tokens could follow the pattern. | HIGH | CCC's `@ckb-ccc/udt` package uses SSRI server for UDT operations. iCKB's exchange rate is deterministic from block headers, not from an SSRI server. Subclassing may not be the right approach -- a compatible interface or wrapper may be better. Requires investigation of CCC's `Udt` API surface. | +| **D-3: Conversion preview with maturity estimation** | `IckbSdk.estimate()` provides real-time conversion preview with fee calculation AND estimated order fulfillment time based on pool liquidity analysis. No other CKB DEX SDK provides maturity estimation. | Already done | `IckbSdk.estimate()` and `IckbSdk.maturity()` already implement this. Ensure these survive SmartTransaction removal. | +| **D-4: Pool snapshot-based liquidity analysis** | Bot cells carry deposit pool snapshots (compact binary encoding) that enable fast liquidity estimation without scanning all deposit cells. | Already done | `PoolSnapshot` codec in `sdk/src/codec.ts`. Bot writes snapshots; SDK reads them. Unique protocol feature. | +| **D-5: Async generator cell discovery pattern** | Lazy evaluation via `async *findDeposits()`, `async *findOrders()` etc. with configurable batch sizes. More memory-efficient than collecting all cells upfront. | Already done | Pattern used consistently across `DaoManager`, `LogicManager`, `OrderManager`, `UdtManager`, `CapacityManager`. This is a genuine DX advantage over Lumos's eager collection pattern. | +| **D-6: Composable manager pattern with ScriptDeps** | Uniform `{ script, cellDeps }` interface enables managers to compose into transactions without knowing about each other. Clean dependency injection. | Already done | `DaoManager`, `OrderManager`, `LogicManager`, `OwnedOwnerManager`, `CapacityManager` all implement `ScriptDeps`. Pattern enables devnet testing with custom configs. | +| **D-7: Exchange rate calculation from block headers** | Deterministic CKB-to-iCKB conversion without oracles. `ickbExchangeRatio()` derives the rate from `header.dao.ar` (accumulated rate). | Already done | `convert()` and `ickbExchangeRatio()` in `packages/core/src/udt.ts`. Unique to iCKB protocol. Includes soft cap penalty calculation. | +| **D-8: Limit order lifecycle management** | Full mint/match/melt lifecycle for on-chain limit orders. `OrderManager` handles order creation, partial fills (preserving value conservation), and cancellation. | Already done | 988-line `OrderManager`. Includes ratio comparison, concavity checks, DOS prevention via `ckb_min_match_log`. Differentiated from CKB DEX SDK by being specifically designed for iCKB/CKB pair with integrated exchange ratio. | +| **D-9: Upstream CCC contribution pipeline** | Project has a track record of 12 merged CCC PRs. Patterns developed here become CCC-native features. This is a moat -- the maintainer shapes the framework the library depends on. | Ongoing | Continue identifying reusable patterns (FeePayer PR #328, potential UDT extensions). Each upstream merge reduces local code and increases ecosystem value. | +| **D-10: Owned-owner withdrawal delegation** | Solves NervosDAO's lock-size constraint for withdrawal delegation. `OwnedOwnerManager` handles the 1:1 pairing of owned (withdrawal request) and owner (authorization) cells via relative offset. | Already done | Unique to iCKB protocol. No other NervosDAO integration handles delegated withdrawals. | + +### Anti-Features (Commonly Requested, Often Problematic) + +Features that seem good but create problems in this context. Explicitly document what NOT to build. + +| Feature | Why Requested | Why Problematic | Alternative | +|---------|---------------|-----------------|-------------| +| **AF-1: SmartTransaction as ecosystem standard** | Was proposed as a universal CKB transaction builder pattern | Abandoned by CCC maintainers and broader ecosystem. No adoption outside iCKB. Subclassing `ccc.Transaction` couples to CCC internals. | Use utility functions on plain `ccc.Transaction`. UDT handler logic becomes standalone. If CCC PR #328 (FeePayer) lands, adopt that for fee completion. | +| **AF-2: Custom Molecule codec library** | Tempting to build a richer codec layer than CCC's `mol.*` | CCC already provides `mol.union`, `ccc.Entity.Base`, `@ccc.codec`. Custom codecs duplicate effort and diverge from ecosystem. | Use CCC's Molecule codecs exclusively. Already migrated from custom `mol.*` APIs. | +| **AF-3: UI/UX redesign during migration** | Interface app migration feels like a chance to modernize the UI | Conflates two concerns. UI redesign delays migration. The goal is to swap internals, not redesign the product. | Straight migration only: same components, same React Query patterns, swap Lumos for CCC+SDK. UI redesign is a separate future effort (out of scope). | +| **AF-4: Custom blockchain indexer** | Some CKB projects build custom indexers for better query performance | CCC's `findCells`/`findCellsOnChain` with built-in caching covers all current needs. Custom indexer adds massive operational complexity for marginal gain at iCKB's scale. | Use CCC's client cell queries with the existing filter patterns. The async generator pattern already provides efficient lazy evaluation. | +| **AF-5: Multi-chain / L2 token bridging** | RGB++ protocol enables cross-chain iCKB. Tempting to add bridging to the library. | Bridging requires fundamentally different architecture (BTC time locks, RGB++ lock scripts, different transaction patterns). Premature integration creates coupling. | Keep library focused on L1. Bridging is a separate concern that can compose with these packages. If RGB++ bridge is needed later, it should be a separate package. | +| **AF-6: Embedded wallet/signer management** | Some SDKs bundle wallet management (key storage, mnemonic handling) | CCC already provides comprehensive signer abstraction (`ccc.Signer`, `ccc.SignerCkbPrivateKey`, JoyId integration). Duplicating this creates security liability. | Delegate all signing to CCC's signer infrastructure. The SDK accepts `ccc.Signer` or `ccc.Script` -- it never manages keys. | +| **AF-7: Database/state persistence layer** | Bot and interface could benefit from persistent state (order history, balance cache) | All state is on-chain. Adding a database creates consistency problems (stale state vs chain state). The current stateless design is a feature, not a limitation. | Continue reading all state from L1 via CCC client. Pool snapshots (D-4) provide efficient state approximation without a database. | +| **AF-8: New reference/example apps** | More apps might help adoption | Existing 5 apps (bot, interface, faucet, sampler, tester) already demonstrate all library capabilities. Adding more dilutes maintenance focus. | Polish existing apps. They serve as living documentation. | +| **AF-9: CCC framework fork** | Tempting to fork CCC to get features faster | Forking creates maintenance burden and diverges from ecosystem. Upstream PRs are the correct approach. | Submit PRs upstream (already doing this with 12 merged). Track CCC PR #328 (FeePayer). Use `ccc-dev/` local build for testing changes before they land upstream. | +| **AF-10: On-chain contract changes** | Protocol improvements seem natural alongside library work | All contracts are deployed with zero-args locks (immutable, non-upgradable). Even if desirable, contract changes are impossible. | Library must match existing on-chain contract behavior exactly. All protocol rules are fixed. | + +## Feature Dependencies + +``` +SmartTransaction Removal (TS-1) + | + +-- enables --> CCC Utility Deduplication (TS-2) + | (deduplicate utilities after core restructuring) + | + +-- enables --> Clean Public API (TS-3) + | (can't finalize API until SmartTransaction is gone) + | + +-- enables --> Bot Migration (TS-5) + | (bot should migrate to final API, not intermediate) + | + +-- enables --> Interface Migration (TS-6) + | (same reasoning) + | + +-- enables --> Tester Migration (TS-7) + | (same reasoning) + | + +-- preserves --> Multi-representation UDT (D-1) + | (UDT balance logic must survive removal) + | + +-- preserves --> Conversion Preview (D-3) + | (estimation logic must survive removal) + +CCC Udt Investigation (D-2) + | + +-- requires --> SmartTransaction Removal (TS-1) + | (must understand new API shape first) + | + +-- informs --> Multi-representation UDT (D-1) + (whether to use Udt interface or custom) + +Bot Migration (TS-5) + | + +-- requires --> SmartTransaction Removal (TS-1) + +-- requires --> Clean Public API (TS-3) + +-- validates --> All library packages + +Interface Migration (TS-6) + | + +-- requires --> SmartTransaction Removal (TS-1) + +-- requires --> Clean Public API (TS-3) + +Lumos Removal (TS-4) + | + +-- requires --> Bot Migration (TS-5) + +-- requires --> Interface Migration (TS-6) + +-- requires --> Tester Migration (TS-7) + +npm Publication (TS-11) + | + +-- requires --> Clean Public API (TS-3) + +-- requires --> Type Exports (TS-12) + +-- requires --> SmartTransaction Removal (TS-1) +``` + +### Dependency Notes + +- **TS-1 (SmartTransaction Removal) is the critical path.** Every downstream task depends on it. It must happen first and must preserve D-1 (multi-representation UDT) and D-3 (conversion preview) functionality. +- **TS-5 (Bot Migration) validates the entire stack.** The bot exercises deposits, withdrawals, order matching, fee completion, and UDT balancing under real conditions. It is the integration test for the library suite. +- **TS-4 (Lumos Removal) is the final gate.** It can only happen after all three legacy apps are migrated. It removes `@ickb/lumos-utils`, `@ickb/v1-core`, and all `@ckb-lumos/*` from the monorepo. +- **D-2 (CCC Udt Investigation) is exploratory.** It should not block other work. Findings inform the API design of D-1 but the library can ship with a custom `UdtHandler` interface regardless. +- **CCC PR #328 (FeePayer) is external.** Track it but do not depend on it. Design the SmartTransaction replacement so that FeePayer can be adopted later if it merges. + +## MVP Definition + +### Launch With (v1) + +Minimum viable state for npm publication of clean CCC-aligned library packages. + +- [ ] **TS-1: SmartTransaction removal** -- Replace with utility functions on `ccc.Transaction`. This is the single most important task. All manager methods must accept `ccc.Transaction` instead of `SmartTransaction`. +- [ ] **TS-2: CCC utility deduplication** -- Adopt CCC equivalents for `max`/`min`/`gcd`/`isHex`/`hexFrom`. +- [ ] **TS-3: Clean public API** -- Audit exports, ensure intentional public surface, proper type exports. +- [ ] **TS-5: Bot migration** -- Validates the library packages work end-to-end under production conditions. +- [ ] **D-1: Multi-representation UDT preservation** -- Ensure `IckbUdtManager` functionality survives SmartTransaction removal. +- [ ] **TS-11: npm publication** -- Publish updated packages with clean API and provenance. + +### Add After Validation (v1.x) + +Features to add once core library packages are stable and published. + +- [ ] **TS-6: Interface migration** -- Trigger: bot migration succeeds, proving the API works. +- [ ] **TS-7: Tester migration** -- Trigger: bot migration succeeds. +- [ ] **TS-4: Lumos removal** -- Trigger: all three legacy apps migrated. +- [ ] **D-2: CCC Udt investigation** -- Trigger: SmartTransaction removal complete, CCC UDT API stabilizes. +- [ ] **TS-12: Type export audit** -- Trigger: public API finalized. + +### Future Consideration (v2+) + +Features to defer until library suite is stable and adopted. + +- [ ] **D-9: Upstream CCC contributions** -- Continue identifying reusable patterns. Track FeePayer PR #328. +- [ ] **Pool snapshot optimization** -- Improve compact encoding or move to a more structured format if bot requirements grow. +- [ ] **Additional UDT support** -- If other xUDT tokens need similar multi-representation handling, generalize the pattern. + +## Feature Prioritization Matrix + +| Feature | User Value | Implementation Cost | Priority | +|---------|------------|---------------------|----------| +| TS-1: SmartTransaction removal | HIGH | HIGH | **P1** | +| TS-2: CCC utility deduplication | MEDIUM | LOW | **P1** | +| TS-3: Clean public API | HIGH | MEDIUM | **P1** | +| TS-5: Bot migration | HIGH | HIGH | **P1** | +| D-1: Multi-representation UDT | HIGH | MEDIUM | **P1** | +| TS-11: npm publication | HIGH | LOW | **P1** | +| TS-6: Interface migration | HIGH | MEDIUM | **P2** | +| TS-7: Tester migration | MEDIUM | MEDIUM | **P2** | +| TS-4: Lumos removal | MEDIUM | LOW | **P2** | +| TS-12: Type export audit | MEDIUM | LOW | **P2** | +| D-2: CCC Udt investigation | MEDIUM | HIGH | **P2** | +| D-3: Conversion preview | HIGH | Already done | **--** | +| D-4: Pool snapshot | HIGH | Already done | **--** | +| D-5: Async generators | HIGH | Already done | **--** | +| D-6: ScriptDeps pattern | HIGH | Already done | **--** | +| D-7: Exchange rate | HIGH | Already done | **--** | +| D-8: Order lifecycle | HIGH | Already done | **--** | +| D-9: Upstream contributions | MEDIUM | Ongoing | **P3** | +| D-10: Owned-owner delegation | HIGH | Already done | **--** | + +**Priority key:** +- P1: Must have -- blocks npm publication of clean CCC-aligned packages +- P2: Should have -- add after P1 validates the library stack +- P3: Nice to have -- ongoing improvement + +## Competitor Feature Analysis + +| Feature | NervDAO (CCC) | Lumos NervosDAO | CKB DEX SDK | iCKB Library Suite | +|---------|---------------|-----------------|-------------|-------------------| +| NervosDAO deposit/withdraw | Yes (UI only) | Yes (framework) | No | Yes (library + apps) | +| Liquid staking token | No | No | No | Yes (iCKB xUDT) | +| Multi-representation value | No | No | No | Yes (xUDT + receipts + deposits) | +| Limit order matching | No | No | Yes (generic) | Yes (iCKB-specific, integrated rate) | +| Exchange rate calculation | No | No | No | Yes (deterministic from headers) | +| Pool liquidity analysis | No | No | No | Yes (pool snapshots) | +| Maturity estimation | No | No | No | Yes (order fulfillment time) | +| CCC-native (no Lumos) | Yes | No (IS Lumos) | Partial | Yes (target state) | +| npm published | No (app only) | Yes | Yes | Yes (5 packages) | +| Delegated DAO withdrawals | No | No | No | Yes (owned-owner pattern) | +| Wallet abstraction | Yes (multi-wallet) | Yes (secp256k1) | Yes (multiple locks) | Yes (via CCC signers) | +| TypeScript strict mode | Unknown | No | Unknown | Yes (strictest settings) | + +**Analysis:** The iCKB library suite has no direct competitor. NervDAO is a UI application, not a library. Lumos is a general framework being superseded by CCC. CKB DEX SDK handles generic order matching but not protocol-specific logic. The iCKB suite is the only npm-published library that provides NervosDAO liquid staking with multi-representation UDT handling, integrated exchange rates, and limit order matching -- all built on the modern CCC framework. + +## Sources + +- Codebase analysis: `packages/*/src/*.ts` (direct reading) -- HIGH confidence +- CCC GitHub repository: [ckb-devrel/ccc](https://github.com/ckb-devrel/ccc) -- HIGH confidence +- CCC documentation: [docs.ckbccc.com](https://docs.ckbccc.com/) -- HIGH confidence +- CCC UDT package: [ckb-devrel/ccc/packages/udt](https://github.com/ckb-devrel/ccc/tree/master/packages/udt) -- MEDIUM confidence (limited docs) +- CCC FeePayer PR: [ckb-devrel/ccc/pull/328](https://github.com/ckb-devrel/ccc/pull/328) -- MEDIUM confidence (open PR, subject to change) +- NervDAO: [ckb-devrel/nervdao](https://github.com/ckb-devrel/nervdao) -- MEDIUM confidence +- @ickb/utils on npm: [npmjs.com/@ickb/utils](https://www.npmjs.com/package/@ickb/utils/v/1000.0.42?activeTab=versions) -- HIGH confidence +- iCKB protocol overview: [nervos.org/knowledge-base/Unlocking_CKB_Liquidity_iCKB](https://www.nervos.org/knowledge-base/Unlocking_CKB_Liquidity_iCKB) -- HIGH confidence +- Nervos CKB docs: [docs.nervos.org](https://docs.nervos.org/) -- HIGH confidence +- CKB DEX SDK: [nervina-labs/ckb-dex-sdk](https://github.com/nervina-labs/ckb-dex-sdk) -- MEDIUM confidence +- Enhanced UDT Standard discussion: [Nervos Talk](https://talk.nervos.org/t/enhanced-udt-standard/8354) -- LOW confidence (discussion, not specification) + +--- +*Feature research for: CCC-based iCKB protocol library suite* +*Researched: 2026-02-21* diff --git a/.planning/research/PITFALLS.md b/.planning/research/PITFALLS.md new file mode 100644 index 0000000..73fc3c9 --- /dev/null +++ b/.planning/research/PITFALLS.md @@ -0,0 +1,287 @@ +# Pitfalls Research + +**Domain:** CKB/CCC library migration -- removing SmartTransaction, adopting CCC UDT, migrating apps from Lumos +**Researched:** 2026-02-21 +**Confidence:** HIGH (derived from direct codebase analysis, CCC source inspection, and domain-specific contract constraints) + +## Critical Pitfalls + +### Pitfall 1: Removing SmartTransaction Before Extracting All Implicit Behaviors + +**What goes wrong:** +SmartTransaction is not just a thin wrapper around `ccc.Transaction`. It carries three orthogonal responsibilities that are interleaved throughout 9 files (55 references): (1) UDT handler registration and dispatch, (2) header caching with multi-key lookup, and (3) DAO-aware `getInputsCapacity` and `completeFee` overrides including the 64-output NervosDAO check. Developers see "remove SmartTransaction, use `ccc.Transaction` + utility functions" and attempt a mechanical find-and-replace, missing that `completeFee` silently iterates all registered UDT handlers before calling `super.completeFee()`, that `clone()` shares `udtHandlers` and `headers` maps across transaction copies (shared-state semantics), and that `getInputsCapacity` adds DAO withdrawal profit to the capacity total. A naive replacement that only extracts the obvious methods will produce transactions that fail on-chain because (a) UDT change cells are never added, (b) DAO withdrawal profits are not counted in capacity balancing, or (c) headers needed for withdrawal are not in `headerDeps`. + +**Why it happens:** +SmartTransaction's design buries critical side effects in method overrides that are not visible from call sites. The callers (e.g., `LogicManager.deposit`, `DaoManager.requestWithdrawal`, `OrderManager.mint`) call `tx.addUdtHandlers()`, `tx.addHeaders()`, and `tx.getHeader()` -- methods that only exist on SmartTransaction, not on `ccc.Transaction`. These are the implicit contract. But the highest-stakes behavior -- `completeFee` iterating all handlers and `getInputsCapacity` adding DAO profit -- is triggered by the signer at transaction submission time, far from where handlers/headers were registered. + +**How to avoid:** +1. Before removing anything, catalog every SmartTransaction-specific method used across the codebase. The complete list: `addUdtHandlers`, `addHeaders`, `getHeader`, `hasUdtHandler`, `getUdtHandler`, `encodeUdtKey`, `encodeHeaderKey`, `completeFee` (override), `getInputsCapacity` (override), `getInputsUdtBalance` (override), `getOutputsUdtBalance` (override), `clone` (override with shared maps), `copy` (override with map merging), `default` (override), `from` (override). +2. Design the replacement as standalone functions for the UDT completion concern (`completeUdtChange(tx, signer)`) and header dep management (`getHeader(client, tx, key)`). Note: `getInputsCapacity` DAO profit accounting does NOT need a utility — CCC's `Transaction.getInputsCapacity()` handles this natively via `getInputsCapacityExtra()` → `Cell.getDaoProfit()`. Validate that each original override has a corresponding replacement (utility function or CCC-native method). +3. Write characterization tests BEFORE refactoring: for a known set of inputs, capture the exact `completeFee` output (number of added inputs, whether change was added) and the exact `getInputsCapacity` return value. Run these tests against the new utility functions. + +**Warning signs:** +- Any `completeFee` call that returns `[0, false]` when it previously returned `[N, true]` -- means UDT change is missing +- Transactions rejected on-chain with "ImbalancedCapacity" -- means DAO profit is not being counted +- "Header not found in HeaderDeps" errors -- means header caching was lost +- Off-by-one in output count near the 64-output NervosDAO limit -- means the DAO check was lost from `completeFee` + +**Phase to address:** +Phase 1 (Library refactor). This must be the first step -- all five library packages and all downstream apps depend on SmartTransaction. Getting this wrong blocks everything else. + +--- + +### Pitfall 2: Conservation Law Violation When Subclassing CCC Udt for iCKB Multi-Representation Value + +**What goes wrong:** +iCKB value exists in three on-chain forms: xUDT tokens (standard `u128 LE` balance), receipt cells (representing pending deposit conversions, carrying `{depositQuantity, depositAmount}`), and DAO deposit cells (locked CKB). The iCKB Logic contract enforces a conservation law: `input_udt + input_receipts = output_udt + input_deposits`. CCC's `Udt` class only understands form (1) -- it counts `u128 LE` balances in cells with a matching type script. If you subclass `Udt` and override `infoFrom`/`balanceFrom` to also count receipts and deposits (as `IckbUdtManager` currently does), you create a class that claims a balance that CCC's generic transaction completion logic does not understand. When CCC's `Udt.completeInputsByBalance` adds inputs to satisfy the declared balance, it may add receipt or deposit cells that trigger the conservation law in unexpected ways, or it may fail to add the correct header deps needed for receipt/deposit value calculation. + +Concretely, `IckbUdtManager.getInputsUdtBalance` currently (a) counts xUDT balances, (b) converts receipt cells to iCKB value using the block header's accumulated rate, and (c) subtracts deposit value when a deposit-to-withdrawal-request conversion is happening. This logic requires `tx.getHeader()` -- a SmartTransaction method -- and depends on knowing the transaction's intent (is a deposit being converted to a withdrawal request?). CCC's `Udt` has no concept of header-dependent balance calculation or intent-aware accounting. + +**Why it happens:** +The temptation is to make `IckbUdt extends Udt` so that CCC's generic transaction completion (`completeBy`, `completeInputsByBalance`) "just works" for iCKB. But iCKB's multi-representation value model is fundamentally incompatible with the assumption that UDT balance = sum of `u128 LE` fields in matching type cells. The CCC `Udt` class was designed for standard xUDT tokens, not for protocol-specific tokens with conservation laws spanning multiple cell types. + +**How to avoid:** +1. The preferred approach (see ARCHITECTURE.md and STACK.md) is to subclass `Udt` as `IckbUdt`, overriding `getInputsInfo()`/`getOutputsInfo()` rather than `infoFrom()`. This avoids the `CellAnyLike` limitation (no outPoint for header fetching) while keeping CCC's completion methods functional. However, this is an **open design question** to be resolved during Phase 3 (UDT Investigation). +2. If subclassing proves unviable, the fallback is to keep multi-representation accounting in iCKB-specific standalone functions (refactored from `IckbUdtManager`), using CCC's `Udt` only for standard xUDT operations (cell discovery, basic balance reading). +3. Whichever approach is chosen, ensure that CCC's `Udt.completeInputsByBalance()` does not inadvertently add receipt or deposit cells as if they were standard xUDT inputs. Verify that the conservation law (`input_udt + input_receipts = output_udt + input_deposits`) is enforced correctly by the overridden methods. +4. Always add required `headerDeps` explicitly -- CCC's client cache handles header fetching performance, but `headerDeps` must be on the transaction for on-chain validation. + +**Warning signs:** +- Tests where `udt.calculateBalance(signer)` returns a different value than the on-chain xUDT balance visible in an explorer +- Transaction completion that adds iCKB receipt cells as if they were xUDT cells +- Missing `headerDeps` in completed transactions (receipts require the header of their creation TX) +- CCC's generic `completeInputsByBalance()` selecting cells that trigger the conservation law unexpectedly + +**Phase to address:** +Phase 3 (UDT Investigation). The UDT handling architecture must be settled before core implementation (Phase 5), because the apps currently use `SmartTransaction.completeFee` which delegates to `IckbUdtManager.completeUdt`. Phase 3 is specifically designed to resolve this design question. + +--- + +### Pitfall 3: Exchange Rate Divergence Between TypeScript and Rust Contract + +**What goes wrong:** +The TypeScript exchange rate formula in `packages/core/src/udt.ts` must produce byte-identical results to the Rust `ickb_logic` contract's `deposit_to_ickb()` function. The formula is `iCKB = capacity * AR_0 / AR_m` with a soft cap penalty. Any divergence -- even by 1 shannon due to integer division rounding -- causes the conservation law check to fail on-chain, and the transaction is rejected. This is not caught by type checking, linting, or any compile-time analysis. It can only be caught by cross-validation tests that compare TypeScript output against known Rust contract outputs. + +The specific danger points: +- Integer division direction: Rust uses truncating division. TypeScript `BigInt` also truncates, but the order of operations matters. `(a * b) / c` may produce a different result than `a * (b / c)`. +- The soft cap formula: `amount - (amount - 100000) / 10n` where `100000` is `ICKB_SOFT_CAP_PER_DEPOSIT` in CKB units (100,000 * 10^8). Getting the unit wrong by a factor of 10^8 is catastrophic. +- The `depositCapacityDelta` constant: computed as `(82 CKB * AR_0) / ICKB_DEPOSIT_CAP`. This is a compile-time constant in the TypeScript but must match the Rust contract's treatment of occupied capacity (82 bytes for a DAO deposit cell). + +**Why it happens:** +The contract code is in Rust, the library is in TypeScript, and there are zero cross-validation tests. The developer relies on manual inspection to verify formula equivalence. Any future change to either side (e.g., adopting a CCC upstream utility for the conversion) risks introducing a subtle arithmetic difference. + +**How to avoid:** +1. Create a test fixture file with known input/output pairs derived from the Rust contract: deposit amounts at boundary conditions (1000 CKB, 100000 CKB, 1000000 CKB), various accumulated rates, and the exact expected iCKB amounts. +2. Run these as the first test in CI. If the test breaks, it means the TypeScript formula diverged from the contract. +3. Add a comment in `packages/core/src/udt.ts` at each formula step citing the exact Rust source line it corresponds to. +4. Never replace a hand-written arithmetic formula with a CCC utility without verifying the utility produces identical results for the test fixture. + +**Warning signs:** +- Any change to `ickbValue()`, `convert()`, or `ickbExchangeRatio()` in `packages/core/src/udt.ts` +- Changing the `AR_0`, `depositUsedCapacity`, or `ICKB_DEPOSIT_CAP` constants +- On-chain transaction failures with error code 11 (`AmountMismatch`) from the `ickb_logic` script + +**Phase to address:** +Phase 1 (Library refactor) -- add cross-validation tests before any refactoring touches the exchange rate code. This is a safety net for the entire migration. + +--- + +### Pitfall 4: Breaking the Conservation Law During Lumos-to-CCC App Migration + +**What goes wrong:** +The legacy bot app (`apps/bot/src/index.ts`, ~900 lines) builds iCKB transactions using Lumos primitives (`TransactionSkeleton`, `addCells`, `addCkbChange`, `addIckbUdtChange`, etc.). The new library packages build equivalent transactions using CCC primitives. During migration, the developer must produce transactions with **identical on-chain semantics** -- same cell types in the same positions, same data formats, same header deps, same witness structure. The iCKB contracts enforce position-sensitive rules: for example, the `owned_owner` script requires a 1:1 pairing between owner cells and owned cells at specific relative positions (the `owned_distance: i32` field). The order contract requires the master cell to appear at a specific offset from its order cell. Getting the cell ordering wrong produces transactions that pass TypeScript validation but fail on-chain. + +Specifically dangerous patterns in the bot migration: +- `ickbRequestWithdrawalFrom` in Lumos creates paired cells (owned withdrawal request + owner cell) with specific relative positioning. The new `OwnedOwnerManager.requestWithdrawal` must produce identical relative positions. +- `orderSatisfy`/`orderMint` in Lumos produce order cells with `master_distance` encoded as a relative `i32`. The new `OrderManager.mint` uses `Relative.create(1n)` for the same purpose. The byte encoding must be identical. +- The bot's `addCkbChange` + `addIckbUdtChange` sequence in Lumos has specific ordering semantics (iCKB change first, then CKB change). The new `SmartTransaction.completeFee` iterates UDT handlers before calling `super.completeFee()`, preserving this order. But if the replacement utility functions change this order, fee calculation will differ. + +**Why it happens:** +The migration is a "rewrite-in-place" of ~900 lines of Lumos-based transaction building. The developer focuses on making the TypeScript type-check with the new API, but the on-chain contracts don't care about TypeScript types -- they care about byte-level cell layout. The implicit contract between the off-chain code and the on-chain scripts is not captured in any type system. + +**How to avoid:** +1. Migrate the bot in a feature branch and test against CKB testnet before mainnet. +2. For each transaction type the bot produces (deposit, withdrawal request, withdrawal, order match, order melt), capture a "golden" transaction from the Lumos version (serialized bytes). Build the same transaction with the CCC version and compare byte-for-byte. Differences must be explicitly justified. +3. Test the migrated bot in a read-only mode first: build transactions but log them instead of submitting. Compare against what the Lumos version would build. +4. Keep the Lumos version running in parallel during the transition period. + +**Warning signs:** +- Transaction failures on testnet with error codes from `ickb_logic` (5-12), `owned_owner` (5-8), or `limit_order` (5-21) +- The bot producing transactions that succeed on testnet but fail on mainnet (indicating testnet-specific constants leaked) +- Order matching that produces different `ckbDelta`/`udtDelta` values than the Lumos version for the same order pool + +**Phase to address:** +App migration (deferred to future milestone, not in v1 roadmap). The bot is the highest-stakes migration because it runs autonomously and handles real CKB/iCKB value. + +--- + +### Pitfall 5: Molecule Codec Byte Layout Mismatch After Refactoring + +**What goes wrong:** +The TypeScript Molecule codecs (`ReceiptData`, `OwnedOwnerData`, `OrderInfo`, `Ratio`, etc.) use CCC's `@ccc.codec` decorators and `mol.Entity.Base`. These produce byte encodings that must match the Molecule schema at `reference/contracts/schemas/encoding.mol` exactly -- field order, sizes, endianness, padding. A refactoring that reorders fields in a TypeScript class, changes a field type, or inadvertently uses a different encoding for the same semantic value (e.g., `Uint32` vs `Int32` for `owned_distance`) will produce silently different byte encodings. The contracts will reject the transaction or, worse, misinterpret the data. + +Key risk areas: +- `ReceiptData { deposit_quantity: Uint32, deposit_amount: Uint64 }` = 12 bytes. TypeScript uses `@ccc.codec` with fields `depositQuantity` (u32 LE) and `depositAmount` (u64 LE). If someone renames or reorders these fields, the encoded bytes change. +- `OwnedOwnerData { owned_distance: Int32 }` = 4 bytes. Note this is **signed** Int32, not unsigned. Using `Uint32` would encode the same numeric value differently for negative distances. +- Order cell data layout is 89 bytes with a specific structure. The `OrderData` class in `packages/order/src/entities.ts` manually constructs this from components. Any change to the field sizes or offsets breaks order matching. + +**Why it happens:** +TypeScript field names are camelCase, Molecule schema field names are snake_case. There is no compile-time link between them. The mapping is purely by convention and manual code review. When refactoring moves entities to a different file or refactors the class hierarchy, the byte layout can change without any type error. + +**How to avoid:** +1. Add roundtrip codec tests: encode a known TypeScript object, compare to a hardcoded expected hex string, then decode and compare to the original object. +2. Generate the expected hex strings from the Molecule schema directly (or from known Rust test vectors). +3. Never change field order in `@ccc.codec`-decorated classes without verifying the byte layout. +4. Add a comment on each codec class citing the exact Molecule schema line it corresponds to. + +**Warning signs:** +- Any modification to files in `packages/order/src/entities.ts`, `packages/core/src/entities.ts`, or `packages/sdk/src/codec.ts` +- A codec class where the field order differs from the Molecule schema field order +- A cell data `outputData` that decodes to unexpected values in the CCC explorer + +**Phase to address:** +Phase 1 (Library refactor) -- add codec tests as a safety net before any refactoring. + +--- + +### Pitfall 6: Losing the 64-Output NervosDAO Limit Enforcement + +**What goes wrong:** +The NervosDAO script rejects transactions with more than 64 output cells. This limit is currently enforced in 6 separate locations in the codebase: `SmartTransaction.completeFee`, `LogicManager.deposit`, `DaoManager.deposit`, `DaoManager.requestWithdrawal`, `DaoManager.withdraw`, and `apps/bot/src/index.ts`. When SmartTransaction is removed and replaced with utility functions, the `completeFee` check is the most likely to be lost because it is an override that the caller never explicitly invokes -- it runs implicitly when the signer calls `completeFee`. If the replacement utility function does not include this check, transactions built by the SDK will occasionally exceed 64 outputs and fail on-chain in production. + +**Why it happens:** +The 64-output limit is a NervosDAO-specific gotcha that is easy to forget because (a) most transactions have far fewer than 64 outputs, (b) the limit only applies to transactions that include DAO cells, and (c) the error only manifests on-chain, not during local transaction building. The developer testing with small transactions will never hit this limit. The bot operating on mainnet with many deposits/withdrawals will. + +**How to avoid:** +1. When replacing `SmartTransaction.completeFee`, explicitly include the NervosDAO 64-output check in the replacement function. +2. Add an integration test that attempts to build a DAO transaction with 65 outputs and verifies it throws. +3. Consider consolidating the 64-output check into a single utility function (`assertDaoOutputLimit(tx, client)`) called from one place rather than scattered across 6 locations. + +**Warning signs:** +- Removing `SmartTransaction.completeFee` without grepping for `outputs.length > 64` in the codebase +- On-chain failures with NervosDAO error codes only when the bot processes large batches +- Tests passing with small transaction sizes but failing with realistic sizes + +**Phase to address:** +Phase 1 (Library refactor) -- the check must survive the SmartTransaction removal. + +--- + +## Technical Debt Patterns + +Shortcuts that seem reasonable but create long-term problems. + +| Shortcut | Immediate Benefit | Long-term Cost | When Acceptable | +|----------|-------------------|----------------|-----------------| +| Keeping SmartTransaction "just for now" while migrating apps | Apps work immediately without library changes | Two transaction models coexist, every new feature must work with both, CCC upgrades become harder | Never -- library refactor must come before app migration | +| Passing `SmartTransaction` type through public API boundaries | Avoids rewriting callers | External consumers inherit a dependency on a non-standard Transaction subclass, blocking npm publication | Never for published packages -- internal-only is acceptable during transition | +| Skipping codec roundtrip tests | Faster initial development | Silent byte-level bugs that only manifest on-chain | Never -- these tests are cheap to write and prevent catastrophic failures | +| Duplicating CCC utility functions locally instead of adopting upstream | Avoids dependency on specific CCC version | Drift between local and upstream implementations, double maintenance burden | Only if CCC version is not yet released (use `ccc-dev/` local builds to validate, then switch to published version) | +| Migrating bot without parallel Lumos fallback | Cleaner codebase, single transaction path | If CCC-based bot has subtle bugs, no way to fall back; real funds at risk | Never for mainnet -- always keep Lumos bot runnable until CCC bot is validated on testnet | +| Removing `@ickb/lumos-utils` and `@ickb/v1-core` from workspace before all apps are migrated | Simpler dependency tree | Breaks unmigrated apps, blocks incremental migration | Only after ALL apps are migrated and verified | + +## Integration Gotchas + +Common mistakes when connecting to CKB RPC and CCC. + +| Integration | Common Mistake | Correct Approach | +|-------------|----------------|------------------| +| CCC `findCells` vs `findCellsOnChain` | Using cached `findCells` for bot operations where freshness matters | Use `findCellsOnChain` for bot/time-sensitive operations, `findCells` only for UI queries where slight staleness is acceptable | +| CCC `ccc.Transaction.completeFee` | Assuming it handles UDT change automatically | It only handles CKB capacity change. UDT change must be handled separately (this is exactly what SmartTransaction's override added). The replacement must preserve this | +| CCC `Udt.completeInputsByBalance` | Assuming it works for iCKB multi-representation value | CCC's `Udt` only counts xUDT `u128 LE` balances. Receipt cells and deposit cells are invisible to it. Use iCKB-specific logic for iCKB value accounting | +| CCC `ccc.Client` header caching | Assuming headers fetched by `client.getHeaderByNumber` are automatically added to `headerDeps` | They are not. Headers must be explicitly added to the transaction's `headerDeps`. SmartTransaction's `addHeaders` did this automatically -- the replacement must too | +| NervosDAO `since` field encoding | Using `ccc.Epoch.toHex()` for the `since` field in withdrawal inputs | The `since` field requires absolute epoch encoding with specific bit layout. Verify against `ccc.epochToHex()` or the NervosDAO RFC. Incorrect encoding causes on-chain rejection | +| Lumos `TransactionSkeleton` immutability | Assuming in-place mutation works (CCC `Transaction` is mutable) | Lumos skeletons are immutable (Immutable.js). Every operation returns a new skeleton. CCC transactions are mutable. Migration code must not mix idioms (e.g., discarding the return value of a Lumos operation) | + +## Performance Traps + +Patterns that work at small scale but fail as the bot processes real volume. + +| Trap | Symptoms | Prevention | When It Breaks | +|------|----------|------------|----------------| +| Sequential `getHeader()` calls in DAO cell construction | Each DAO cell requires 1-2 RPC calls; processing 30 deposits = 60 sequential calls | Prefetch all needed headers in parallel before constructing cells (batch `getHeaderByNumber` calls) | >10 DAO cells per transaction cycle | +| Unbounded header cache in replacement for SmartTransaction.headers | Memory grows indefinitely across bot iterations | Use LRU or TTL-based cache, or create fresh context per transaction | After running for days with many DAO transactions | +| `findOrders` fetching all orders then filtering | The bot fetches ALL on-chain order cells, then filters by matchability | Use more specific RPC filters, or paginate with early termination | >1000 active orders on-chain | +| Re-fetching system state on every bot iteration | Full `getL1State` call fetches tip, deposits, withdrawals, orders each iteration | Cache tip-dependent data with short TTL, only refresh what changed | Bot with <2 second sleep interval | + +## Security Mistakes + +Domain-specific security issues beyond general web security. + +| Mistake | Risk | Prevention | +|---------|------|------------| +| Incorrect exchange rate in migrated code causes user to receive fewer iCKB than expected | Financial loss -- user deposits CKB, receives less iCKB than the contract would calculate | Cross-validation tests between TypeScript and Rust. Never approximate; use exact integer arithmetic | +| Bot private key leaked through error logging during migration | Bot wallet drained -- attacker uses private key to sign transactions | Audit all `console.log` and error handling in migrated bot. Never log `signer`, `key`, or raw env vars. The faucet already has this bug (logs ephemeral key at line 31) | +| Using testnet constants on mainnet after migration | Transactions silently produce wrong results -- wrong script hashes, wrong dep groups | Validate `getConfig("mainnet")` vs `getConfig("testnet")` constants against on-chain state in CI | +| Order matching with negative gain due to rounding error | Bot loses CKB/iCKB on every match cycle | Verify `gain > 0` assertion in migrated `bestMatch`. The current code checks this but the check could be lost during refactoring | + +## UX Pitfalls + +Common user experience mistakes during the interface app migration. + +| Pitfall | User Impact | Better Approach | +|---------|-------------|-----------------| +| Wallet connector behavior change between Lumos and CCC | JoyId users see different connection flow, potential confusion | Test with actual JoyId wallet. CCC's wallet connector API differs from Lumos -- map the exact UX flow | +| Transaction fee estimation differs between Lumos and CCC | Users see different fee amounts than before, may reject transactions | Log fee estimates from both implementations during parallel testing. Align UX copy for fee display | +| Maturity estimates change due to different epoch calculation | Users see different lock-up times, lose trust | Verify maturity calculation against both implementations for the same deposits | +| Loading states during migration | React Query cache invalidation behaves differently with new data fetching | Map `queryKey` structure from Lumos to CCC. Preserve `refetchInterval` and `staleTime` settings | + +## "Looks Done But Isn't" Checklist + +Things that appear complete but are missing critical pieces. + +- [ ] **SmartTransaction removal:** Often missing the `completeFee` UDT handler iteration -- verify that ALL registered UDT handlers have their `completeUdt` called during fee completion +- [ ] **SmartTransaction removal:** Verify that DAO profit accounting delegates to CCC's native `Transaction.getInputsCapacity()` (which handles DAO profit via `getInputsCapacityExtra()` → `Cell.getDaoProfit()`) rather than reimplementing it locally +- [ ] **SmartTransaction removal:** Often missing the shared-map semantics of `clone()` -- verify that cloned transactions share the same `udtHandlers` and `headers` maps +- [ ] **Bot migration:** Often missing the witness structure for DAO withdrawals -- verify `inputType` witness field contains the header index for each withdrawal request +- [ ] **Bot migration:** Often missing the `same-size` lock args constraint -- verify that withdrawal request lock args have the same byte length as the deposit lock args (required by `OwnedOwner` contract) +- [ ] **Interface migration:** Often missing the React Query cache key migration -- verify that changing the data-fetching layer does not cause stale data or missing cache invalidation +- [ ] **Codec refactoring:** Often missing signed vs unsigned integer encoding -- verify `OwnedOwnerData.owned_distance` uses `Int32` (signed), not `Uint32` +- [ ] **Library API cleanup:** Often missing re-export paths -- verify that consumers importing from `@ickb/utils` still get all needed types after refactoring internal module structure +- [ ] **CCC alignment:** Often missing deprecation warnings -- verify that any `@deprecated` CCC APIs used locally (`udtBalanceFrom`, `ErrorTransactionInsufficientCoin`) are migrated to their replacements + +## Recovery Strategies + +When pitfalls occur despite prevention, how to recover. + +| Pitfall | Recovery Cost | Recovery Steps | +|---------|---------------|----------------| +| Conservation law violation on testnet | LOW | Identify which term of the conservation law is wrong (xUDT, receipts, or deposits). Compare TypeScript calculation against manual computation from block headers. Fix and retest. No on-chain damage -- testnet CKB is free | +| Conservation law violation on mainnet | MEDIUM | Immediately stop bot. Transactions are rejected on-chain so no funds are lost. But pending orders may be stuck until a working bot version is deployed. Rollback to Lumos bot while fixing | +| Exchange rate divergence discovered in production | HIGH | Stop bot. Audit all recent transactions for incorrect iCKB amounts. If users received fewer iCKB than expected, the protocol's conservation law would have prevented the transaction -- so this is actually caught on-chain. The real risk is the bot failing repeatedly and missing matching opportunities | +| 64-output limit hit in production | LOW | Transaction is rejected on-chain, no funds lost. Fix the limit check, redeploy. The bot will retry on next cycle | +| Molecule codec mismatch | HIGH | All transactions using the affected codec fail on-chain. If the codec was used for publishing order data, existing orders may become unmatchable. Must deploy fix immediately and potentially recreate affected orders | +| SmartTransaction removal breaks header caching | MEDIUM | Transactions fail with "Header not found in HeaderDeps". Add headers back to the transaction context. May need to re-add sequential header fetching temporarily until batch prefetching is implemented | + +## Pitfall-to-Phase Mapping + +How roadmap phases should address these pitfalls. + +| Pitfall | Prevention Phase | Verification | +|---------|------------------|--------------| +| SmartTransaction implicit behaviors lost | Phase 1 (Library refactor) | Characterization tests pass: `completeFee` output matches, `getInputsCapacity` return matches, headers present in `headerDeps` | +| CCC Udt subclassing for multi-representation value | Phase 3 (UDT Investigation) | Design decision documented: subclass viability confirmed or fallback approach chosen; conservation law preservation verified in either case | +| Exchange rate divergence | Phase 1 (Library refactor, test infrastructure) | Cross-validation test suite exists with known Rust contract outputs; tests pass in CI | +| Conservation law violation during app migration | Future milestone (App migration) | Migrated bot produces byte-identical transactions to Lumos bot for the same inputs; testnet validation passes | +| Molecule codec byte layout mismatch | Phase 1 (Library refactor, test infrastructure) | Codec roundtrip tests exist for all 6 entity types; expected hex strings match Molecule schema | +| 64-output NervosDAO limit lost | Phase 1 (Library refactor) | Integration test that builds a 65-output DAO transaction and verifies it throws; `assertDaoOutputLimit` utility exists | +| Lumos removal breaks unmigrated apps | Future milestone (App migration) | Each app is migrated and verified individually; Lumos dependencies removed only after all apps pass | +| Private key logging in migrated code | Future milestone (App migration) | Security audit of all `console.log` calls in migrated apps; no sensitive data in logs | +| React Query cache invalidation in interface | Future milestone (App migration, interface) | Manual testing with JoyId wallet; query key structure documented; refetch intervals preserved | + +## Sources + +- Direct codebase analysis: `packages/utils/src/transaction.ts` (SmartTransaction, 517 lines), `packages/utils/src/udt.ts` (UdtManager, 393 lines), `packages/core/src/udt.ts` (IckbUdtManager, 213 lines) +- CCC `Udt` class source: `ccc-dev/ccc/packages/udt/src/udt/index.ts` (1798 lines) +- On-chain contract source: `reference/contracts/scripts/contracts/ickb_logic/src/entry.rs` (conservation law, exchange rate) +- On-chain contract source: `reference/contracts/scripts/contracts/owned_owner/` (owner/owned pairing) +- On-chain contract source: `reference/contracts/scripts/contracts/limit_order/` (order/master relationship) +- Molecule schema: `reference/contracts/schemas/encoding.mol` (byte layout definitions) +- NervosDAO RFC: https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md (64-output limit) +- `.planning/PROJECT.md` -- project requirements and constraints +- `.planning/codebase/CONCERNS.md` -- known tech debt and fragile areas +- `.planning/codebase/INTEGRATIONS.md` -- CCC API surface and contract details + +--- +*Pitfalls research for: CKB/CCC library migration (iCKB Stack v2)* +*Researched: 2026-02-21* diff --git a/.planning/research/STACK.md b/.planning/research/STACK.md new file mode 100644 index 0000000..2ba9f40 --- /dev/null +++ b/.planning/research/STACK.md @@ -0,0 +1,333 @@ +# Stack Research + +**Domain:** CCC API adoption for iCKB protocol library migration +**Researched:** 2026-02-21 +**Confidence:** HIGH (primary source: local CCC source code in `ccc-dev/ccc/`) + +## Context + +This research focuses on the CCC APIs and patterns that should be adopted as part of the iCKB stack v2 migration. The existing TypeScript/pnpm/CCC stack is established and does not need re-research. This document identifies specific CCC APIs to adopt, local utilities to replace, and patterns to follow for the SmartTransaction removal, UDT handling adoption, and CCC alignment audit. + +## Recommended Stack Changes + +### CCC APIs to Adopt (replacing local implementations) + +| CCC API | Replaces | Package(s) Affected | Confidence | +|---------|----------|---------------------|------------| +| `ccc.Transaction.completeFeeChangeToLock()` | `SmartTransaction.completeFee()` for CKB change | `@ickb/utils`, all consumers | HIGH | +| `ccc.Transaction.completeFeeBy()` | `SmartTransaction.completeFee()` convenience | `@ickb/utils`, all consumers | HIGH | +| `ccc.Transaction.completeFeeChangeToOutput()` | N/A (new capability) | Order matching, bot | HIGH | +| `ccc.Transaction.completeInputsByCapacity()` | `CapacityManager.findCapacities()` + manual add | `@ickb/utils` | HIGH | +| `ccc.Transaction.completeInputsAll()` | Custom collect-all patterns | `@ickb/utils` | HIGH | +| `ccc.Transaction.completeInputs()` | Custom accumulator patterns | `@ickb/utils` | HIGH | +| `ccc.Transaction.getInputsCapacity()` | `SmartTransaction.getInputsCapacity()` | `@ickb/utils` | HIGH | +| `ccc.Transaction.getOutputsCapacity()` | Direct usage (already available) | All packages | HIGH | +| `ccc.Transaction.getFee()` | Manual fee calculation | All packages | HIGH | +| `@ckb-ccc/udt` `Udt` class | `UdtManager` class | `@ickb/utils`, `@ickb/core` | HIGH | +| `Udt.completeInputsByBalance()` | `UdtManager.completeUdt()` input portion | `@ickb/utils`, `@ickb/core` | HIGH | +| `Udt.completeChangeToLock()` | `UdtManager.completeUdt()` change portion | `@ickb/utils`, `@ickb/core` | HIGH | +| `Udt.completeBy()` | Convenience UDT completion | `@ickb/utils`, `@ickb/core` | HIGH | +| `Udt.complete()` | Custom UDT completion with change function | `@ickb/core` (IckbUdtManager) | HIGH | +| `Udt.getInputsBalance()` / `Udt.getInputsInfo()` | `UdtManager.getInputsUdtBalance()` | `@ickb/utils`, `@ickb/core` | HIGH | +| `Udt.getOutputsBalance()` / `Udt.getOutputsInfo()` | `UdtManager.getOutputsUdtBalance()` | `@ickb/utils`, `@ickb/core` | HIGH | +| `Udt.balanceFromUnsafe()` | `ccc.udtBalanceFrom()` (deprecated) | All packages using UDT balance | HIGH | +| `Udt.infoFrom()` | Manual per-cell UDT info aggregation | `@ickb/utils`, `@ickb/core` | HIGH | +| `Udt.isUdt()` | `UdtManager.isUdt()` | `@ickb/utils`, `@ickb/core` | HIGH | +| `Udt.addCellDeps()` | `SmartTransaction.addUdtHandlers()` cell dep portion | All packages | HIGH | +| `UdtInfo` class | `[ccc.FixedPoint, ccc.FixedPoint]` tuple | `@ickb/utils`, `@ickb/core` | HIGH | +| `ErrorUdtInsufficientCoin` (from `@ckb-ccc/udt`) | `ErrorTransactionInsufficientCoin` (local) | `@ickb/utils` | HIGH | +| `ccc.numMax()` / `ccc.numMin()` | Local `max()` / `min()` for bigint | `@ickb/utils` | HIGH | +| `ccc.gcd()` | Local `gcd()` | `@ickb/utils` | HIGH | +| `ccc.isHex()` | Local `isHex()` | `@ickb/utils` | HIGH | +| `ccc.hexFrom()` | Local `hexFrom()` (partial -- CCC's takes `HexLike` not `bigint | Entity`) | `@ickb/utils` | MEDIUM | +| `ccc.reduce()` / `ccc.reduceAsync()` | Already adopted | N/A | HIGH | +| `ccc.Epoch` | Already adopted (local deleted) | N/A | HIGH | +| `ccc.Cell.getDaoProfit()` | Manual DAO profit calculation in `SmartTransaction.getInputsCapacity()` | `@ickb/utils` | HIGH | +| `ccc.CellInput.getExtraCapacity()` | Manual extra capacity in `SmartTransaction.getInputsCapacity()` | `@ickb/utils` | HIGH | +| `ccc.Cell.getNervosDaoInfo()` | Manual header fetching for deposit/withdrawal | `@ickb/dao` | HIGH | +| `ccc.CellAny` | N/A (use for output cell representation) | All packages | HIGH | +| `ccc.CellOutput.from(output, outputData)` | Manual capacity calculation | All packages | HIGH | +| `ccc.Client.cache` | `SmartTransaction.headers` map | `@ickb/utils` | HIGH | + +### Local Utilities to KEEP (no CCC equivalent) + +| Utility | Location | Why Keep | +|---------|----------|----------| +| `binarySearch()` | `packages/utils/src/utils.ts` | Domain-specific, no CCC equivalent | +| `asyncBinarySearch()` | `packages/utils/src/utils.ts` | Domain-specific, no CCC equivalent | +| `shuffle()` | `packages/utils/src/utils.ts` | Domain-specific, no CCC equivalent | +| `unique()` | `packages/utils/src/utils.ts` | Works on `ccc.Entity` with `.eq()`, CCC has no equivalent | +| `collect()` | `packages/utils/src/utils.ts` | Async generator collector, no CCC equivalent | +| `BufferedGenerator` | (if exists) | Batched async iteration, no CCC equivalent | +| `MinHeap` | `packages/utils/src/heap.ts` | Data structure, no CCC equivalent | +| `sum()` | `packages/utils/src/utils.ts` | Generic sum, no CCC equivalent | +| `ScriptDeps` interface | `packages/utils/src/utils.ts` | iCKB-specific manager composition pattern | +| `ValueComponents` interface | `packages/utils/src/utils.ts` | iCKB-specific dual-value abstraction | +| `ExchangeRatio` interface | `packages/utils/src/utils.ts` | iCKB-specific exchange rate abstraction | +| `HeaderKey` type + `getHeader()` | `packages/utils/src/utils.ts` | See analysis below | + +### CCC `@ckb-ccc/udt` Package + +**Version:** Local build from `ccc-dev/ccc/packages/udt/` +**Key classes:** `Udt`, `UdtInfo`, `UdtConfig`, `ErrorUdtInsufficientCoin` +**Depends on:** `@ckb-ccc/core`, `@ckb-ccc/ssri` + +Use `@ckb-ccc/udt` because: +1. It provides the complete UDT lifecycle: cell finding, balance calculation, input completion, change handling, transfer, mint +2. It is designed for subclassing -- `infoFrom()` and `balanceFrom()` are virtual methods that subclasses can override +3. It tracks both UDT balance AND capacity per cell via `UdtInfo` (balance, capacity, count), matching iCKB's need for dual-value tracking +4. The `complete()` method's two-phase change function (shouldModify=false for capacity estimation, shouldModify=true for mutation) is the correct pattern for iCKB's complex UDT handling + +**SSRI dependency note:** `Udt` extends `ssri.Trait`. For iCKB's use case (legacy xUDT, not SSRI-compliant), the executor will be `undefined`. This is explicitly supported -- the `Udt` class falls back to direct cell manipulation when no executor is provided. + +## SmartTransaction Removal Strategy + +### What SmartTransaction Does Today (and CCC Replacements) + +| SmartTransaction Feature | CCC Native Replacement | Notes | +|--------------------------|------------------------|-------| +| UDT handler management (`udtHandlers` map) | `Udt` instances per UDT type | Udt instances are standalone; no need for a map on the transaction | +| `completeFee()` override (UDT + CKB change) | `Udt.completeBy()` then `tx.completeFeeBy()` | Two-step: complete UDT first, then CKB fee | +| `getInputsUdtBalance()` override | `Udt.getInputsBalance()` | Direct method on Udt instance | +| `getOutputsUdtBalance()` override | `Udt.getOutputsBalance()` | Direct method on Udt instance | +| `getInputsCapacity()` override (DAO profit) | `ccc.Transaction.getInputsCapacity()` | CCC's base implementation now calls `getExtraCapacity()` per input, which includes DAO profit via `Cell.getDaoProfit()` | +| Header caching (`headers` map) | `ccc.Client.cache` (ClientCacheMemory) | Headers cached automatically by Client on fetch | +| `addHeaders()` / `getHeader()` | `client.getHeaderByHash()` / `client.getHeaderByNumber()` with auto-caching | CCC caches confirmed headers | +| `addUdtHandlers()` | `udt.addCellDeps(tx)` | Cell deps added directly by Udt instance | +| `default()` factory | `ccc.Transaction.default()` | Same pattern, no extra state | +| `clone()` with shared state | `ccc.Transaction.clone()` | No shared state needed without udtHandlers/headers maps | +| `fromLumosSkeleton()` | `ccc.Transaction.fromLumosSkeleton()` | Base class method, still available | + +### Critical Design Decision: Header Caching + +SmartTransaction's `headers` map served two purposes: +1. **Performance:** Avoid re-fetching headers +2. **Correctness:** Ensure headers are in `headerDeps` when needed for DAO calculations + +CCC's `Client.cache` handles purpose (1) -- all `getHeaderByHash()` and `getHeaderByNumber()` calls are cached if the header is confirmed. Purpose (2) -- adding to `headerDeps` -- must be handled explicitly by iCKB code. The `getHeader()` utility function in `utils.ts` should become a standalone function that: +- Fetches the header via `client.getHeaderByHash/Number/getTransaction` +- Adds the header hash to `tx.headerDeps` if not present +- Does NOT cache (CCC Client handles that) + +### Critical Design Decision: DAO Profit in getInputsCapacity + +CCC's `Transaction.getInputsCapacity()` now includes DAO profit via `CellInput.getExtraCapacity()` -> `Cell.getDaoProfit()`. This means SmartTransaction's override of `getInputsCapacity()` is **no longer needed** -- CCC does this natively. + +Verified in CCC source (`ccc-dev/ccc/packages/core/src/ckb/transaction.ts` lines 1860-1883): +```typescript +async getInputsCapacity(client: Client): Promise { + return ( + (await reduceAsync( + this.inputs, + async (acc, input) => { + const { cellOutput: { capacity } } = await input.getCell(client); + return acc + capacity; + }, + Zero, + )) + (await this.getInputsCapacityExtra(client)) + ); +} +``` + +Where `getInputsCapacityExtra` sums `getExtraCapacity()` per input, which calls `Cell.getDaoProfit()`. + +## IckbUdtManager -> CCC Udt Subclass Migration + +### Current IckbUdtManager + +`IckbUdtManager` extends `UdtManager` (local) and overrides `getInputsUdtBalance()` to account for iCKB's three value representations: +1. **xUDT cells** -- standard UDT balance from output data +2. **Receipt cells** -- iCKB value calculated from deposit amount and header's accumulated rate +3. **Deposit cells being withdrawn** -- negative iCKB value (burning UDT to withdraw deposit) + +### Recommended Approach: Subclass `Udt` from `@ckb-ccc/udt` + +Create `IckbUdt extends Udt` that overrides `getInputsInfo()` and `getOutputsInfo()` to recognize all three representations. + +**Why `getInputsInfo()`/`getOutputsInfo()` (not `infoFrom()`):** +- The natural candidate would be `infoFrom()` -- it's called by all balance/info methods, so overriding it would propagate everywhere. However, `infoFrom()` receives `CellAnyLike` which lacks `outPoint`, and iCKB receipt/deposit value calculation requires the cell's outPoint to fetch the block header via transaction hash. +- `getInputsInfo()` and `getOutputsInfo()` receive the full `TransactionLike`, so input outpoints are available for header lookups. This is cleaner than trying to thread header information through `infoFrom()`. +- CCC's `completeInputsByBalance()` calls `this.getInputsInfo()`, so overriding it changes balancing behavior correctly. + +**Why NOT override `completeInputsByBalance()`:** +- The base implementation's dual-constraint logic (balance + capacity) is correct for iCKB +- The subclass only needs to change HOW balance is calculated from cells, not the input selection strategy + +**Implementation sketch:** See ARCHITECTURE.md "Pattern 2: IckbUdt Subclass" for the full code example with `getInputsInfo()` override. + +**Note:** This is a preliminary design. The viability of subclassing CCC's `Udt` is an open question to be resolved during Phase 3 (UDT Investigation). See Pitfall 2 in PITFALLS.md for the risks involved. + +**Header fetching within `getInputsInfo()`:** + +Since `getInputsInfo()` receives the full transaction, input outpoints are directly available. The implementation can fetch headers using: + +1. **`client.getHeaderByTxHash(input.previousOutput.txHash)`** -- Fetches the block header for the transaction that created the cell. Cached by CCC Client. This is the approach used in the ARCHITECTURE.md code sketch. + +2. **`client.getTransaction()` + `client.getHeaderByHash()`** -- Alternative two-step approach: get the transaction response (which includes `blockHash`), then fetch the header. Both are cached by CCC Client. + +Option 1 is simpler and sufficient for the `getInputsInfo()` override. + +## CCC Transaction Completion Pattern + +### Old Pattern (SmartTransaction) + +```typescript +const tx = SmartTransaction.default(); +tx.addUdtHandlers(ickbUdtHandler); +// ... add outputs ... +await tx.completeFee(signer, changeLock, feeRate); +// completeFee internally calls handler.completeUdt() for each UDT, +// then super.completeFee() for CKB +``` + +### New Pattern (plain ccc.Transaction + Udt instances) + +```typescript +const tx = ccc.Transaction.default(); +// ... add outputs ... + +// Step 1: Complete UDT inputs and change +const completedTx = await ickbUdt.completeBy(tx, signer); +// OR for more control: +// const completedTx = await ickbUdt.completeChangeToLock(tx, signer, changeLock); + +// Step 2: Complete CKB capacity inputs +await completedTx.completeInputsByCapacity(signer); + +// Step 3: Complete fee with CKB change +await completedTx.completeFeeBy(signer); +// OR: await completedTx.completeFeeChangeToLock(signer, changeLock); +``` + +**Why this order matters:** +1. UDT completion first because UDT cells also contribute CKB capacity +2. CKB capacity second to cover any remaining capacity needs +3. Fee completion last because it needs the final transaction size + +This matches the pattern shown in CCC's own `Udt.transfer()` example (lines 900-904 of udt source): +```typescript +const completedTx = await udt.completeBy(tx, signer); +await completedTx.completeInputsByCapacity(signer); +await completedTx.completeFeeBy(signer); +``` + +## Utility Replacement Details + +### Replace Local `hexFrom()` (MEDIUM confidence) + +Local `hexFrom(v: bigint | ccc.Entity | ccc.BytesLike)` handles three input types: +- `bigint` -> hex string via `numToHex` +- `ccc.Entity` -> hex via `.toBytes()` then `ccc.hexFrom()` +- `ccc.BytesLike` -> delegates to `ccc.hexFrom()` + +CCC's `hexFrom(hex: HexLike)` only handles `HexLike` (which is `BytesLike`). The local version adds `bigint` and `Entity` support. + +**Recommendation:** Keep local `hexFrom()` but rename it to avoid confusion. Or split into explicit calls: use `ccc.numToHex()` for bigint, `ccc.hexFrom(entity.toBytes())` for entities. The split approach is clearer and avoids maintaining a custom wrapper. + +### Replace Local `max()`/`min()` (HIGH confidence) + +Local `max()` and `min()` are generic (work with any comparable type). CCC's `numMax()`/`numMin()` are bigint-specific. + +**Recommendation:** Use `ccc.numMax()`/`ccc.numMin()` for all bigint comparisons (which is the only use case in this codebase). Delete local `max()`/`min()` since they are only used with bigint. + +### Replace Local `gcd()` (HIGH confidence) + +Local `gcd()` accepts variadic `bigint` args. CCC's `gcd()` accepts two `NumLike` args. + +**Recommendation:** Use `ccc.gcd()` with `.reduce()` for variadic case. Or keep local wrapper if variadic is used extensively. + +### Replace Local `isHex()` (HIGH confidence) + +Both implementations are functionally equivalent (check for `0x` prefix, even length, valid hex chars). + +**Recommendation:** Use `ccc.isHex()` directly. Delete local `isHex()`. + +## What NOT to Use + +| Avoid | Why | Use Instead | +|-------|-----|-------------| +| `SmartTransaction` class | Abandoned ecosystem concept; all its features now exist in CCC natively | `ccc.Transaction` + `Udt` instances | +| `UdtHandler` interface | Coupled to SmartTransaction; CCC's `Udt` class provides richer equivalent | `Udt` class from `@ckb-ccc/udt` | +| `UdtManager` class | Replaced by CCC's `Udt` class which has the same capabilities + more | `Udt` from `@ckb-ccc/udt` | +| `CapacityManager` for input completion | CCC's `Transaction.completeInputsByCapacity()` does this natively | `tx.completeInputsByCapacity(signer)` | +| `CapacityManager` for cell finding | CCC's `Client.findCellsByLock()` and `Signer.findCells()` handle this | `client.findCellsByLock()` or `signer.findCells()` | +| `ccc.udtBalanceFrom()` | Deprecated in CCC core; marked with `@deprecated` annotation | `Udt.balanceFromUnsafe()` from `@ckb-ccc/udt` | +| `ccc.Transaction.getInputsUdtBalance()` | Deprecated in CCC core | `Udt.getInputsBalance()` from `@ckb-ccc/udt` | +| `ccc.Transaction.getOutputsUdtBalance()` | Deprecated in CCC core | `Udt.getOutputsBalance()` from `@ckb-ccc/udt` | +| `ccc.Transaction.completeInputsByUdt()` | Deprecated in CCC core | `Udt.completeInputsByBalance()` from `@ckb-ccc/udt` | +| `SmartTransaction.headers` map | Header caching now handled by `Client.cache` | Let CCC Client cache handle it | +| Manual header dep management for DAO | CCC's `getInputsCapacity()` handles DAO profit natively | Use CCC's built-in DAO profit calculation | +| `@ckb-lumos/*` packages | Being entirely replaced by CCC | CCC equivalents for all Lumos functionality | +| `@ickb/lumos-utils` | Legacy iCKB Lumos utilities being replaced | `@ickb/utils` + CCC | +| `@ickb/v1-core` | Legacy iCKB core being replaced | `@ickb/core` + CCC | + +## CapacityManager Fate + +`CapacityManager` currently has two roles: +1. **Cell finding** -- `findCapacities()` async generator +2. **Cell adding** -- `addCapacities(tx, cells)` helper + +Both are now redundant: +- Cell finding: `ccc.Transaction.completeInputsByCapacity(signer)` handles capacity collection and input addition in one step +- Cell adding: `ccc.Transaction.addInput(cell)` is the native method + +**However,** `CapacityManager` is used by the faucet app for a specific pattern: find cells matching a lock, then transfer them. This pattern could use `signer.findCells()` with a filter instead. + +**Recommendation:** Remove `CapacityManager` after verifying that `completeInputsByCapacity()` covers all use cases. For the faucet's cell-discovery-then-transfer pattern, use CCC's `client.findCellsByLock()` directly. + +## PR #328 (FeePayer) Status + +PR #328 proposes a `FeePayer` abstraction for CCC that would allow specifying who pays transaction fees. This is relevant because SmartTransaction's fee completion could designate a specific lock for fee payment. + +**Current status:** Still open (not merged as of research date). + +**Impact on migration:** Do NOT wait for PR #328. CCC's existing `completeFeeChangeToLock(signer, changeLock)` already allows specifying a change destination. The FeePayer abstraction would be a further convenience but is not blocking. + +**Recommendation:** Proceed with `completeFeeChangeToLock()` / `completeFeeBy()`. If PR #328 merges later, it can be adopted as an incremental improvement. + +## Version Compatibility + +| Package | Compatible With | Notes | +|---------|-----------------|-------| +| `@ckb-ccc/core` ^1.12.2 | `@ckb-ccc/udt` (local build) | Both from same CCC build; version-locked via catalog | +| `@ckb-ccc/udt` | `@ckb-ccc/ssri` | `Udt` extends `ssri.Trait`; comes from same CCC build | +| `@ckb-ccc/core` ^1.12.2 | Node.js >= 24 | CCC uses standard APIs; no Node.js compatibility issues | +| `@ckb-ccc/ccc` ^1.1.21 | `apps/interface` | Full bundle with wallet connectors; separate from core | + +**New dependency for packages:** `@ckb-ccc/udt` must be added to packages that subclass `Udt`. Currently only `@ickb/core` needs this (for `IckbUdt`). The `@ickb/utils` package may also need it if `UdtManager` is replaced with re-exports from `@ckb-ccc/udt`. + +## Installation Changes + +```bash +# New dependency for @ickb/core (and potentially @ickb/utils) +# Added to pnpm-workspace.yaml catalog: +# '@ckb-ccc/udt': ^1.x.x (version aligned with @ckb-ccc/core) + +# Per-package: +# @ickb/core: add @ckb-ccc/udt to dependencies +# @ickb/utils: potentially add @ckb-ccc/udt if re-exporting Udt types + +# No other new dependencies needed -- all other changes use existing @ckb-ccc/core APIs +``` + +**Note:** With `ccc-dev/` local build active, `.pnpmfile.cjs` automatically rewires all `@ckb-ccc/*` dependencies to local packages, so the `@ckb-ccc/udt` package is already available from the local CCC build. + +## Sources + +- `ccc-dev/ccc/packages/udt/src/udt/index.ts` -- CCC Udt class, full source (1798 lines) -- HIGH confidence +- `ccc-dev/ccc/packages/core/src/ckb/transaction.ts` -- CCC Transaction class, full source (2537 lines) -- HIGH confidence +- `ccc-dev/ccc/packages/core/src/client/client.ts` -- CCC Client class with caching, cell finding -- HIGH confidence +- `ccc-dev/ccc/packages/core/src/num/index.ts` -- `numMax`, `numMin`, `numFrom` etc. -- HIGH confidence +- `ccc-dev/ccc/packages/core/src/hex/index.ts` -- `isHex`, `hexFrom`, `bytesLen` -- HIGH confidence +- `ccc-dev/ccc/packages/core/src/utils/index.ts` -- `reduce`, `reduceAsync`, `gcd`, `apply`, `sleep` -- HIGH confidence +- `ccc-dev/ccc/packages/core/src/ckb/epoch.ts` -- `Epoch` class (already adopted) -- HIGH confidence +- `packages/utils/src/transaction.ts` -- Current SmartTransaction implementation (517 lines) -- HIGH confidence +- `packages/utils/src/udt.ts` -- Current UdtManager/UdtHandler implementation (393 lines) -- HIGH confidence +- `packages/utils/src/capacity.ts` -- Current CapacityManager implementation (221 lines) -- HIGH confidence +- `packages/core/src/udt.ts` -- Current IckbUdtManager implementation (213 lines) -- HIGH confidence +- `.planning/PROJECT.md` -- Project context and requirements -- HIGH confidence +- `.planning/codebase/STACK.md` -- Current stack analysis -- HIGH confidence + +--- +*Stack research for: CCC API adoption in iCKB migration* +*Researched: 2026-02-21* diff --git a/.planning/research/SUMMARY.md b/.planning/research/SUMMARY.md new file mode 100644 index 0000000..689ef8e --- /dev/null +++ b/.planning/research/SUMMARY.md @@ -0,0 +1,194 @@ +# Project Research Summary + +**Project:** iCKB Stack v2 — CCC API Migration +**Domain:** CKB blockchain protocol library suite (NervosDAO liquid staking / iCKB) +**Researched:** 2026-02-21 +**Confidence:** HIGH + +## Executive Summary + +The iCKB library suite is a unique CKB protocol library — there are no direct competitors. It handles NervosDAO liquid staking via the iCKB xUDT token, featuring multi-representation value tracking (UDT tokens + receipt cells + DAO deposit cells), limit order matching, and delegated withdrawal management. The established TypeScript/pnpm/CCC stack is sound. The entire migration centers on one architectural pivot: removing `SmartTransaction` (a `ccc.Transaction` subclass abandoned by the broader CCC ecosystem) and replacing its responsibilities with plain `ccc.Transaction` combined with CCC-native APIs — specifically the `@ckb-ccc/udt` package's `Udt` class and the transaction completion methods added to CCC core (`completeFeeBy`, `completeInputsByCapacity`, `completeFeeChangeToLock`). + +The recommended approach is a strict bottom-up refactoring that proceeds through the dependency graph: `@ickb/utils` (remove SmartTransaction/UdtHandler/UdtManager) → `@ickb/dao` and `@ickb/order` (update to plain `ccc.Transaction`) → `@ickb/core` (create `IckbUdt extends udt.Udt` with iCKB-specific balance overrides) → `@ickb/sdk` (explicit completion pipeline) → apps (bot, interface, tester migrated from Lumos). CCC's `Udt` class covers standard xUDT operations; iCKB's triple-representation value logic must remain in `IckbUdt` and must NOT be delegated to a generic Udt subclass that changes how `completeInputsByBalance` selects cells. + +The primary risk is losing implicit behaviors baked into `SmartTransaction` — particularly the DAO-profit-aware `getInputsCapacity` override, the 64-output NervosDAO limit check inside `completeFee`, and the UDT handler dispatch loop that runs before CKB fee completion. All three of these are silent, non-obvious behaviors that a mechanical find-and-replace will miss. The mitigation is straightforward: catalog every SmartTransaction-specific method, write characterization tests before touching anything, and add codec roundtrip tests to prevent byte-level regressions in the Molecule encodings that the on-chain contracts enforce. + +## Key Findings + +### Recommended Stack + +The existing TypeScript/pnpm/CCC stack requires no new technology choices. The migration is a CCC API adoption exercise: replace 14 local utilities with CCC equivalents (`ccc.numMax`/`numMin`, `ccc.gcd`, `ccc.isHex`, `Udt.balanceFromUnsafe`, etc.), add `@ckb-ccc/udt` as a dependency to `@ickb/core`, and restructure transaction building around CCC's native completion pipeline. The local `ccc-dev/` build system already makes `@ckb-ccc/udt` available via `.pnpmfile.cjs` rewriting — no additional infrastructure work needed. + +**Core technologies:** +- `@ckb-ccc/core` ^1.12.2: Transaction building, cell queries, signer abstraction — already adopted, native replacement for all SmartTransaction behaviors +- `@ckb-ccc/udt` (local ccc-dev build): UDT lifecycle management (cell finding, balance calculation, input completion, change handling) — replaces local UdtManager/UdtHandler; `IckbUdt` subclasses this +- `ccc.Transaction.completeFeeBy` / `completeFeeChangeToLock`: CKB fee completion — direct SmartTransaction.completeFee replacement for the CKB-change portion +- `ccc.Transaction.completeInputsByCapacity`: CKB capacity input collection — replaces CapacityManager's cell-finding role +- `ccc.Client.cache`: Transparent header caching — replaces SmartTransaction's `headers` map for performance; header deps must still be added explicitly + +**Do NOT use:** +- `SmartTransaction`: Abandoned ecosystem pattern; all capabilities now exist in CCC natively +- `UdtHandler` / `UdtManager`: Parallel type system absorbed by CCC's `Udt` class +- `CapacityManager` (for input completion): `tx.completeInputsByCapacity(signer)` does this in one call +- Deprecated CCC APIs: `ccc.udtBalanceFrom()`, `ccc.Transaction.getInputsUdtBalance()`, `ccc.Transaction.completeInputsByUdt()` + +### Expected Features + +**Must have (table stakes — blocks npm publication):** +- SmartTransaction removal (TS-1) — the critical path; all other work depends on it +- CCC utility deduplication (TS-2) — adopt CCC equivalents, keep iCKB-unique utilities +- Clean public API surface (TS-3) — audit exports, mark internals, curate index.ts files +- Bot migration (TS-5) — validates entire library stack under real production conditions +- Multi-representation UDT preservation (D-1) — iCKB balance logic must survive removal intact +- npm publication with provenance (TS-11) — already configured, depends on clean API + +**Should have (add after bot migration validates the library):** +- Interface app migration (TS-6) — same UI, swap Lumos internals for CCC + new packages +- Tester app migration (TS-7) — validates all transaction paths in simulation +- Complete Lumos removal (TS-4) — remove `@ickb/lumos-utils`, `@ickb/v1-core`, all `@ckb-lumos/*`; gate on all apps migrated +- CCC Udt subclassing investigation (D-2) — exploratory; informs long-term architecture +- Type export audit (TS-12) — after public API stabilizes + +**Defer (v2+):** +- Upstream CCC contributions (D-9) — continue tracking FeePayer PR #328; adopt if merged +- Additional UDT type support — generalize pattern if other xUDT tokens need multi-representation handling +- Pool snapshot encoding improvements — only if bot requirements grow beyond current capacity + +The library already implements all differentiators (D-3 through D-8, D-10): maturity estimation, pool snapshots, async generator cell discovery, composable ScriptDeps pattern, deterministic exchange rates, limit order lifecycle, delegated withdrawals. These must survive the migration unchanged. + +### Architecture Approach + +The architecture shifts from a God-object transaction (SmartTransaction carrying UDT handlers + header cache + overridden behaviors) to a layered composition model: plain `ccc.Transaction` for state, standalone utility functions for concerns like header dep management, `IckbUdt extends udt.Udt` for iCKB-specific balance calculation, and an explicit completion pipeline at the call site (complete UDT first, then CKB capacity, then fee). The build order is strictly bottom-up through the dependency graph. + +**Major components:** +1. `@ickb/utils` — transaction utilities (`addCellDeps`, `getHeader`), async data utilities (`collect`, `unique`, `binarySearch`, `MinHeap`); NO SmartTransaction, NO UdtHandler, NO UdtManager after refactor +2. `@ickb/dao` + `@ickb/order` — domain managers operating on plain `ccc.Transaction`; add cell deps directly; no UDT awareness +3. `@ickb/core` — `IckbUdt extends udt.Udt` overriding `getInputsInfo()` and `getOutputsInfo()` for triple-representation balance; `LogicManager` and `OwnedOwnerManager` for iCKB protocol operations +4. `@ickb/sdk` — `IckbSdk` facade orchestrating all managers; explicit completion pipeline: `ickbUdt.completeBy(tx, signer)` then `tx.completeFeeBy(signer)` +5. Apps (bot, interface, tester) — consume SDK; no direct manager usage for most operations + +**Key pattern — explicit completion pipeline:** +```typescript +const tx = ccc.Transaction.default(); +// domain operations... +const completedTx = await ickbUdt.completeBy(tx, signer); // UDT inputs + change +await completedTx.completeFeeBy(signer); // CKB capacity + fee +await signer.sendTransaction(completedTx); +``` + +**Key architectural decision — override `getInputsInfo()` not `infoFrom()`:** +`getInputsInfo()` receives the full transaction with input outpoints, enabling header fetching for receipt and deposit cells. `infoFrom()` receives only cells without outpoints and cannot reach the block headers needed for iCKB value calculation. + +### Critical Pitfalls + +1. **SmartTransaction implicit behaviors lost during removal** — `completeFee` silently iterates all UDT handlers, `getInputsCapacity` adds DAO withdrawal profit, `clone()` shares handler/header maps. A mechanical find-and-replace misses all three. Avoid by: cataloging every SmartTransaction-specific method, writing characterization tests before removing anything, and designing the replacement as explicit utility functions rather than a companion object. + +2. **Incorrect CCC Udt subclassing for multi-representation value** — CCC's `Udt.completeInputsByBalance` assumes UDT balance = sum of `u128 LE` fields in matching type cells. iCKB's conservation law spans xUDT cells, receipt cells, and DAO deposit cells. Avoid by: using `IckbUdt` only to override `getInputsInfo()`/`getOutputsInfo()` (which have full transaction context), NOT overriding `infoFrom()` or `balanceFrom()` for iCKB-specific representations. + +3. **Exchange rate divergence between TypeScript and Rust contract** — The `ickbValue()` formula must produce byte-identical results to the on-chain `ickb_logic` script. Integer division order and the soft-cap formula are dangerous. Avoid by: creating cross-validation tests with known Rust contract outputs BEFORE touching any exchange rate code. + +4. **64-output NervosDAO limit lost from `completeFee`** — This check is buried in SmartTransaction's `completeFee` override and currently enforced in 6 separate locations. Removal without consolidation will cause production failures. Avoid by: extracting a single `assertDaoOutputLimit(tx)` utility called from one canonical location, with an integration test that verifies a 65-output DAO transaction throws. + +5. **Conservation law violation during app migration** — The bot must produce byte-identical transactions to the Lumos version. On-chain contracts enforce position-sensitive rules (owned_distance relative offsets, master_distance in orders, witness structure for DAO withdrawals). Avoid by: migrating in a feature branch, capturing golden transactions from the Lumos bot, comparing byte-for-byte with the CCC version, and keeping the Lumos bot runnable during the testnet validation period. + +6. **Molecule codec byte layout mismatch** — `ReceiptData`, `OwnedOwnerData`, `OrderData` must match the Molecule schema exactly. TypeScript field reordering silently changes byte encoding. Avoid by: adding codec roundtrip tests with hardcoded expected hex strings before any refactoring. + +## Implications for Roadmap + +Based on research, suggested phase structure: + +### Phase 1: Library Foundation Refactor +**Rationale:** SmartTransaction removal is the critical path — 100% of downstream work depends on it. Characterization tests and codec tests must come first to create a safety net. CCC utility deduplication is cheap and cleans up the API surface. The dependency graph demands `@ickb/utils` changes before any domain package changes. +**Delivers:** CCC-native library packages with clean public API; no SmartTransaction anywhere; all P1 features ready for npm publication; test infrastructure protecting against regressions. +**Addresses:** TS-1 (SmartTransaction removal), TS-2 (utility deduplication), TS-3 (clean public API), D-1 (multi-representation UDT preservation) +**Avoids:** Pitfalls 1 (SmartTransaction implicit behaviors), 3 (exchange rate divergence), 4 (64-output limit), 6 (codec byte layout) +**Sub-phases (dependency-driven):** +1a. Test infrastructure: characterization tests for SmartTransaction behaviors; codec roundtrip tests; exchange rate cross-validation fixtures +1b. `@ickb/utils`: remove SmartTransaction, UdtHandler, UdtManager; adopt CCC utility equivalents; add `addCellDeps`/`getHeader` utility functions +1c. `@ickb/dao` + `@ickb/order` (parallel): update all manager methods from `SmartTransaction` to `ccc.Transaction` +1d. `@ickb/core`: create `IckbUdt extends udt.Udt`; update LogicManager/OwnedOwnerManager +1e. `@ickb/sdk`: implement explicit completion pipeline; update IckbSdk facade +**Research flag:** Phase 1d needs careful investigation — the `IckbUdt` subclassing approach is architecturally sound (confirmed by both STACK.md and ARCHITECTURE.md research) but the header-access-in-`getInputsInfo` pattern requires verification against the CCC `Udt` API. + +### Phase 2: Bot Migration and Library Validation +**Rationale:** The bot is the integration test for the entire library. It exercises every transaction type (deposit, withdrawal request, withdrawal, order match, order melt) under real production conditions. Bot migration cannot happen before Phase 1 completes — the bot must target the final library API, not an intermediate state. TS-5 (bot migration) is P1 precisely because it validates the library is production-ready. +**Delivers:** Fully migrated bot running on CCC + new packages; testnet validation complete; npm publication of updated packages. +**Addresses:** TS-5 (bot migration), TS-11 (npm publication) +**Avoids:** Pitfall 4 (conservation law violation during migration), Pitfall 3 (key logging security) +**Research flag:** No additional research needed — the migration pattern is well-documented by existing Lumos bot code and the new library API surface. Standard patterns apply. + +### Phase 3: App Migration and Lumos Removal +**Rationale:** Interface and tester migrations are unblocked only after bot migration proves the library API is stable and correct. Lumos removal is the final gate — can only happen after all three legacy apps are migrated. This phase is lower stakes than Phase 2 (the interface has no autonomous signing; the tester uses simulation mode). +**Delivers:** All 5 apps on CCC; zero Lumos dependencies in the monorepo; complete removal of `@ickb/lumos-utils` and `@ickb/v1-core`. +**Addresses:** TS-6 (interface migration), TS-7 (tester migration), TS-4 (Lumos removal), TS-12 (type export audit) +**Avoids:** UX pitfalls (wallet connector behavior change, fee estimation differences, React Query cache migration) +**Research flag:** Interface migration is straightforward (same UI, swap data layer) but the JoyId wallet connector behavior difference between Lumos and CCC needs manual verification with actual wallet hardware. + +### Phase 4: Ecosystem Hardening +**Rationale:** After the library is stable and published, long-term ecosystem work becomes safe to pursue without destabilizing production. +**Delivers:** CCC Udt investigation conclusions; potential upstream CCC contributions; type export completeness; improved test coverage. +**Addresses:** D-2 (CCC Udt investigation), D-9 (upstream contributions), TS-12 (type audit if deferred) +**Avoids:** Pitfall 2 (CCC Udt subclassing for multi-representation value) — this is where the subclassing viability is confirmed or the fallback approach is chosen +**Research flag:** D-2 (CCC Udt subclassing investigation) is explicitly exploratory — findings may change the long-term architecture of `IckbUdt`. Schedule this after Phase 2 validation so the decision is informed by production experience. + +### Phase Ordering Rationale + +- **Test infrastructure before code changes:** The pitfalls research is unambiguous — characterization tests and codec roundtrip tests must exist before removing SmartTransaction. Adding them after is too late. +- **Library before apps:** The feature dependency graph is strict: TS-1 → TS-5 → TS-6/TS-7 → TS-4. Any deviation risks app migration targeting an unstable API. +- **Bot before interface:** Bot validates correctness under real conditions. Interface migration is lower risk but depends on knowing the library is correct. +- **Lumos removal last:** The legacy packages must remain functional until every consumer is migrated. Early removal blocks incremental progress. +- **Udt investigation deferred:** D-2 is exploratory and should not block production library work. Its findings are architecture inputs for future decisions, not requirements for v1. + +### Research Flags + +Needs deeper research during planning: +- **Phase 1d (IckbUdt subclassing):** Confirm that CCC's `Udt.getInputsInfo()` signature provides enough context for header fetching for receipt/deposit cells. Also confirm that overriding `getInputsInfo()` (rather than `infoFrom()`) does not break any CCC internal method chains. +- **Phase 3 (JoyId wallet connector):** Manual testing with actual JoyId hardware required; CCC's wallet connector API differs from Lumos in ways that affect UX flow. + +Standard patterns (skip research-phase): +- **Phase 1b/1c (utils, dao, order refactor):** Mapping of SmartTransaction methods to CCC equivalents is fully documented in STACK.md. Straight mechanical migration with test coverage. +- **Phase 2 (bot migration):** Pattern is migration from Lumos primitives to CCC + new packages. Well-documented by existing code and the explicit completion pipeline. +- **Phase 4 (npm publication):** Already configured (changesets, provenance). Execution only. + +## Confidence Assessment + +| Area | Confidence | Notes | +|------|------------|-------| +| Stack | HIGH | Primary source is local CCC source code (`ccc-dev/ccc/`); all APIs verified by direct inspection | +| Features | HIGH | Based on direct codebase analysis + CCC docs + npm ecosystem survey; competitor analysis confirms iCKB has no direct competitors | +| Architecture | HIGH | Build order derived from package dependency graph; key patterns verified against CCC Udt source; override point resolved (`getInputsInfo`/`getOutputsInfo`, not `infoFrom`) | +| Pitfalls | HIGH | Derived from direct code reading (SmartTransaction 517 lines, IckbUdtManager 213 lines, CCC Udt 1798 lines) and on-chain contract constraints | + +**Overall confidence:** HIGH + +### Gaps to Address + +- **Resolved — CCC Udt override point:** Both ARCHITECTURE.md and STACK.md now agree on overriding `getInputsInfo()`/`getOutputsInfo()` (not `infoFrom()`). The `infoFrom()` approach was ruled out because `CellAnyLike` lacks `outPoint`, which is needed for header fetching in receipt/deposit value calculation. Final confirmation of CCC's internal method chains still needed during Phase 3 (UDT Investigation). +- **Resolved — DAO profit in CCC `getInputsCapacity`:** Verified from CCC source (transaction.ts lines 1860-1883) that `Transaction.getInputsCapacity()` handles DAO profit natively via `getInputsCapacityExtra()` → `CellInput.getExtraCapacity()` → `Cell.getDaoProfit()`. No standalone utility needed. SmartTransaction's override of `getInputsCapacity()` can be dropped without replacement. +- **CCC PR #328 (FeePayer) tracking:** Design the SmartTransaction replacement so FeePayer can be adopted as a drop-in improvement if the PR merges. Do not block on it. +- **Bot key logging security:** PITFALLS.md notes the faucet already has a private key logging bug. The bot migration must include an explicit security audit of all logging paths. + +## Sources + +### Primary (HIGH confidence) +- `ccc-dev/ccc/packages/udt/src/udt/index.ts` — CCC Udt class (1798 lines), complete UDT lifecycle API +- `ccc-dev/ccc/packages/core/src/ckb/transaction.ts` — CCC Transaction class (2537 lines), completeFee/completeInputsByCapacity/getInputsCapacity +- `ccc-dev/ccc/packages/core/src/client/client.ts` — CCC Client with cache, findCells, cell/header fetching +- `packages/utils/src/transaction.ts` — Current SmartTransaction (517 lines), source of truth for replacement requirements +- `packages/utils/src/udt.ts` — Current UdtManager/UdtHandler (393 lines) +- `packages/core/src/udt.ts` — Current IckbUdtManager (213 lines), triple-representation balance logic +- `reference/contracts/schemas/encoding.mol` — Molecule schema, byte layout ground truth +- `reference/contracts/scripts/contracts/ickb_logic/src/entry.rs` — On-chain conservation law and exchange rate +- `.planning/PROJECT.md` — Project requirements and constraints + +### Secondary (MEDIUM confidence) +- CCC GitHub: [ckb-devrel/ccc](https://github.com/ckb-devrel/ccc) — ecosystem context, PR #328 status +- CCC docs: [docs.ckbccc.com](https://docs.ckbccc.com/) — API surface documentation +- @ickb/utils on npm: [npmjs.com/@ickb/utils](https://www.npmjs.com/package/@ickb/utils) — current published versions + +### Tertiary (LOW confidence) +- Enhanced UDT Standard discussion: [Nervos Talk](https://talk.nervos.org/t/enhanced-udt-standard/8354) — ecosystem context only + +--- +*Research completed: 2026-02-21* +*Ready for roadmap: yes* diff --git a/package.json b/package.json index 1d4b2d1..bfe855b 100644 --- a/package.json +++ b/package.json @@ -34,10 +34,10 @@ "@anthropic-ai/claude-code": "latest", "@changesets/changelog-github": "^0.5.2", "@changesets/cli": "^2.29.8", - "@eslint/js": "^9.39.2", - "@typescript/native-preview": "7.0.0-dev.20260219.1", + "@eslint/js": "^9.39.3", + "@typescript/native-preview": "latest", "@vitest/coverage-v8": "3.2.4", - "eslint": "^9.39.2", + "eslint": "^9.39.3", "prettier": "^3.8.1", "prettier-plugin-organize-imports": "^4.3.0", "typedoc": "0.28.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8178294..85e52a4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,7 +18,7 @@ importers: devDependencies: '@anthropic-ai/claude-code': specifier: latest - version: 2.1.47 + version: 2.1.49 '@changesets/changelog-github': specifier: ^0.5.2 version: 0.5.2 @@ -26,17 +26,17 @@ importers: specifier: ^2.29.8 version: 2.29.8(@types/node@24.10.13) '@eslint/js': - specifier: ^9.39.2 - version: 9.39.2 + specifier: ^9.39.3 + version: 9.39.3 '@typescript/native-preview': - specifier: 7.0.0-dev.20260219.1 - version: 7.0.0-dev.20260219.1 + specifier: latest + version: 7.0.0-dev.20260220.1 '@vitest/coverage-v8': specifier: 3.2.4 version: 3.2.4(vitest@3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2)) eslint: - specifier: ^9.39.2 - version: 9.39.2(jiti@2.6.1) + specifier: ^9.39.3 + version: 9.39.3(jiti@2.6.1) prettier: specifier: ^3.8.1 version: 3.8.1 @@ -51,7 +51,7 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.56.0 - version: 8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) vitest: specifier: ^3.2.4 version: 3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) @@ -539,7 +539,7 @@ importers: version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) tsdown: specifier: 0.19.0-beta.3 - version: 0.19.0-beta.3(@typescript/native-preview@7.0.0-dev.20260219.1)(synckit@0.11.12)(typescript@5.9.3) + version: 0.19.0-beta.3(@typescript/native-preview@7.0.0-dev.20260220.1)(synckit@0.11.12)(typescript@5.9.3) typescript: specifier: ^5.9.2 version: 5.9.3 @@ -972,7 +972,7 @@ importers: version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) tsdown: specifier: 0.19.0-beta.3 - version: 0.19.0-beta.3(@typescript/native-preview@7.0.0-dev.20260219.1)(synckit@0.11.12)(typescript@5.9.3) + version: 0.19.0-beta.3(@typescript/native-preview@7.0.0-dev.20260220.1)(synckit@0.11.12)(typescript@5.9.3) typescript: specifier: ^5.9.2 version: 5.9.3 @@ -1203,8 +1203,8 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@anthropic-ai/claude-code@2.1.47': - resolution: {integrity: sha512-RuVCBdSad+tsYsSt8W2s1BICHfulLnj73YqexH8gHgFlOP7mNZOtlGod5UEdrPotedYwiDzKx3L0BiB39YNWPg==} + '@anthropic-ai/claude-code@2.1.49': + resolution: {integrity: sha512-PonEmTZlB5IZbBu9TmtOpGZnupU7OxOXTsJKcXE/4Ak5qp3ptN1wSBRdgKYnn6GDYhXijTXuVVwrCQU+NAgwPA==} engines: {node: '>=18.0.0'} hasBin: true @@ -1526,156 +1526,312 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1706,6 +1862,10 @@ packages: resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@9.39.3': + resolution: {integrity: sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/object-schema@2.1.7': resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2132,139 +2292,277 @@ packages: cpu: [arm] os: [android] + '@rollup/rollup-android-arm-eabi@4.58.0': + resolution: {integrity: sha512-mr0tmS/4FoVk1cnaeN244A/wjvGDNItZKR8hRhnmCzygyRXYtKF5jVDSIILR1U97CTzAYmbgIj/Dukg62ggG5w==} + cpu: [arm] + os: [android] + '@rollup/rollup-android-arm64@4.57.1': resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==} cpu: [arm64] os: [android] + '@rollup/rollup-android-arm64@4.58.0': + resolution: {integrity: sha512-+s++dbp+/RTte62mQD9wLSbiMTV+xr/PeRJEc/sFZFSBRlHPNPVaf5FXlzAL77Mr8FtSfQqCN+I598M8U41ccQ==} + cpu: [arm64] + os: [android] + '@rollup/rollup-darwin-arm64@4.57.1': resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==} cpu: [arm64] os: [darwin] + '@rollup/rollup-darwin-arm64@4.58.0': + resolution: {integrity: sha512-MFWBwTcYs0jZbINQBXHfSrpSQJq3IUOakcKPzfeSznONop14Pxuqa0Kg19GD0rNBMPQI2tFtu3UzapZpH0Uc1Q==} + cpu: [arm64] + os: [darwin] + '@rollup/rollup-darwin-x64@4.57.1': resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==} cpu: [x64] os: [darwin] + '@rollup/rollup-darwin-x64@4.58.0': + resolution: {integrity: sha512-yiKJY7pj9c9JwzuKYLFaDZw5gma3fI9bkPEIyofvVfsPqjCWPglSHdpdwXpKGvDeYDms3Qal8qGMEHZ1M/4Udg==} + cpu: [x64] + os: [darwin] + '@rollup/rollup-freebsd-arm64@4.57.1': resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==} cpu: [arm64] os: [freebsd] + '@rollup/rollup-freebsd-arm64@4.58.0': + resolution: {integrity: sha512-x97kCoBh5MOevpn/CNK9W1x8BEzO238541BGWBc315uOlN0AD/ifZ1msg+ZQB05Ux+VF6EcYqpiagfLJ8U3LvQ==} + cpu: [arm64] + os: [freebsd] + '@rollup/rollup-freebsd-x64@4.57.1': resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==} cpu: [x64] os: [freebsd] + '@rollup/rollup-freebsd-x64@4.58.0': + resolution: {integrity: sha512-Aa8jPoZ6IQAG2eIrcXPpjRcMjROMFxCt1UYPZZtCxRV68WkuSigYtQ/7Zwrcr2IvtNJo7T2JfDXyMLxq5L4Jlg==} + cpu: [x64] + os: [freebsd] + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} cpu: [arm] os: [linux] libc: [glibc] + '@rollup/rollup-linux-arm-gnueabihf@4.58.0': + resolution: {integrity: sha512-Ob8YgT5kD/lSIYW2Rcngs5kNB/44Q2RzBSPz9brf2WEtcGR7/f/E9HeHn1wYaAwKBni+bdXEwgHvUd0x12lQSA==} + cpu: [arm] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-arm-musleabihf@4.57.1': resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} cpu: [arm] os: [linux] libc: [musl] + '@rollup/rollup-linux-arm-musleabihf@4.58.0': + resolution: {integrity: sha512-K+RI5oP1ceqoadvNt1FecL17Qtw/n9BgRSzxif3rTL2QlIu88ccvY+Y9nnHe/cmT5zbH9+bpiJuG1mGHRVwF4Q==} + cpu: [arm] + os: [linux] + libc: [musl] + '@rollup/rollup-linux-arm64-gnu@4.57.1': resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} cpu: [arm64] os: [linux] libc: [glibc] + '@rollup/rollup-linux-arm64-gnu@4.58.0': + resolution: {integrity: sha512-T+17JAsCKUjmbopcKepJjHWHXSjeW7O5PL7lEFaeQmiVyw4kkc5/lyYKzrv6ElWRX/MrEWfPiJWqbTvfIvjM1Q==} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-arm64-musl@4.57.1': resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} cpu: [arm64] os: [linux] libc: [musl] + '@rollup/rollup-linux-arm64-musl@4.58.0': + resolution: {integrity: sha512-cCePktb9+6R9itIJdeCFF9txPU7pQeEHB5AbHu/MKsfH/k70ZtOeq1k4YAtBv9Z7mmKI5/wOLYjQ+B9QdxR6LA==} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rollup/rollup-linux-loong64-gnu@4.57.1': resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} cpu: [loong64] os: [linux] libc: [glibc] + '@rollup/rollup-linux-loong64-gnu@4.58.0': + resolution: {integrity: sha512-iekUaLkfliAsDl4/xSdoCJ1gnnIXvoNz85C8U8+ZxknM5pBStfZjeXgB8lXobDQvvPRCN8FPmmuTtH+z95HTmg==} + cpu: [loong64] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-loong64-musl@4.57.1': resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} cpu: [loong64] os: [linux] libc: [musl] + '@rollup/rollup-linux-loong64-musl@4.58.0': + resolution: {integrity: sha512-68ofRgJNl/jYJbxFjCKE7IwhbfxOl1muPN4KbIqAIe32lm22KmU7E8OPvyy68HTNkI2iV/c8y2kSPSm2mW/Q9Q==} + cpu: [loong64] + os: [linux] + libc: [musl] + '@rollup/rollup-linux-ppc64-gnu@4.57.1': resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} cpu: [ppc64] os: [linux] libc: [glibc] + '@rollup/rollup-linux-ppc64-gnu@4.58.0': + resolution: {integrity: sha512-dpz8vT0i+JqUKuSNPCP5SYyIV2Lh0sNL1+FhM7eLC457d5B9/BC3kDPp5BBftMmTNsBarcPcoz5UGSsnCiw4XQ==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-ppc64-musl@4.57.1': resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} cpu: [ppc64] os: [linux] libc: [musl] + '@rollup/rollup-linux-ppc64-musl@4.58.0': + resolution: {integrity: sha512-4gdkkf9UJ7tafnweBCR/mk4jf3Jfl0cKX9Np80t5i78kjIH0ZdezUv/JDI2VtruE5lunfACqftJ8dIMGN4oHew==} + cpu: [ppc64] + os: [linux] + libc: [musl] + '@rollup/rollup-linux-riscv64-gnu@4.57.1': resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} cpu: [riscv64] os: [linux] libc: [glibc] + '@rollup/rollup-linux-riscv64-gnu@4.58.0': + resolution: {integrity: sha512-YFS4vPnOkDTD/JriUeeZurFYoJhPf9GQQEF/v4lltp3mVcBmnsAdjEWhr2cjUCZzZNzxCG0HZOvJU44UGHSdzw==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-riscv64-musl@4.57.1': resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} cpu: [riscv64] os: [linux] libc: [musl] + '@rollup/rollup-linux-riscv64-musl@4.58.0': + resolution: {integrity: sha512-x2xgZlFne+QVNKV8b4wwaCS8pwq3y14zedZ5DqLzjdRITvreBk//4Knbcvm7+lWmms9V9qFp60MtUd0/t/PXPw==} + cpu: [riscv64] + os: [linux] + libc: [musl] + '@rollup/rollup-linux-s390x-gnu@4.57.1': resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} cpu: [s390x] os: [linux] libc: [glibc] + '@rollup/rollup-linux-s390x-gnu@4.58.0': + resolution: {integrity: sha512-jIhrujyn4UnWF8S+DHSkAkDEO3hLX0cjzxJZPLF80xFyzyUIYgSMRcYQ3+uqEoyDD2beGq7Dj7edi8OnJcS/hg==} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-x64-gnu@4.57.1': resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} cpu: [x64] os: [linux] libc: [glibc] + '@rollup/rollup-linux-x64-gnu@4.58.0': + resolution: {integrity: sha512-+410Srdoh78MKSJxTQ+hZ/Mx+ajd6RjjPwBPNd0R3J9FtL6ZA0GqiiyNjCO9In0IzZkCNrpGymSfn+kgyPQocg==} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rollup/rollup-linux-x64-musl@4.57.1': resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} cpu: [x64] os: [linux] libc: [musl] + '@rollup/rollup-linux-x64-musl@4.58.0': + resolution: {integrity: sha512-ZjMyby5SICi227y1MTR3VYBpFTdZs823Rs/hpakufleBoufoOIB6jtm9FEoxn/cgO7l6PM2rCEl5Kre5vX0QrQ==} + cpu: [x64] + os: [linux] + libc: [musl] + '@rollup/rollup-openbsd-x64@4.57.1': resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} cpu: [x64] os: [openbsd] + '@rollup/rollup-openbsd-x64@4.58.0': + resolution: {integrity: sha512-ds4iwfYkSQ0k1nb8LTcyXw//ToHOnNTJtceySpL3fa7tc/AsE+UpUFphW126A6fKBGJD5dhRvg8zw1rvoGFxmw==} + cpu: [x64] + os: [openbsd] + '@rollup/rollup-openharmony-arm64@4.57.1': resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==} cpu: [arm64] os: [openharmony] + '@rollup/rollup-openharmony-arm64@4.58.0': + resolution: {integrity: sha512-fd/zpJniln4ICdPkjWFhZYeY/bpnaN9pGa6ko+5WD38I0tTqk9lXMgXZg09MNdhpARngmxiCg0B0XUamNw/5BQ==} + cpu: [arm64] + os: [openharmony] + '@rollup/rollup-win32-arm64-msvc@4.57.1': resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==} cpu: [arm64] os: [win32] + '@rollup/rollup-win32-arm64-msvc@4.58.0': + resolution: {integrity: sha512-YpG8dUOip7DCz3nr/JUfPbIUo+2d/dy++5bFzgi4ugOGBIox+qMbbqt/JoORwvI/C9Kn2tz6+Bieoqd5+B1CjA==} + cpu: [arm64] + os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.57.1': resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==} cpu: [ia32] os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.58.0': + resolution: {integrity: sha512-b9DI8jpFQVh4hIXFr0/+N/TzLdpBIoPzjt0Rt4xJbW3mzguV3mduR9cNgiuFcuL/TeORejJhCWiAXe3E/6PxWA==} + cpu: [ia32] + os: [win32] + '@rollup/rollup-win32-x64-gnu@4.57.1': resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==} cpu: [x64] os: [win32] + '@rollup/rollup-win32-x64-gnu@4.58.0': + resolution: {integrity: sha512-CSrVpmoRJFN06LL9xhkitkwUcTZtIotYAF5p6XOR2zW0Zz5mzb3IPpcoPhB02frzMHFNo1reQ9xSF5fFm3hUsQ==} + cpu: [x64] + os: [win32] + '@rollup/rollup-win32-x64-msvc@4.57.1': resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==} cpu: [x64] os: [win32] + '@rollup/rollup-win32-x64-msvc@4.58.0': + resolution: {integrity: sha512-QFsBgQNTnh5K0t/sBsjJLq24YVqEIVkGpfN2VHsnN90soZyhaiA9UUHufcctVNL4ypJY0wrwad0wslx2KJQ1/w==} + cpu: [x64] + os: [win32] + '@shikijs/engine-oniguruma@3.22.0': resolution: {integrity: sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA==} @@ -2512,43 +2810,43 @@ packages: resolution: {integrity: sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260219.1': - resolution: {integrity: sha512-h8gG6gE0YcxJZwxFc+JHjqCoFf/EBZ0k6znspV6+NwkyyJHMIqYiawZ7Lzu2Ka8lJDO3QxXcIdw2jKaktwW2wQ==} + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260220.1': + resolution: {integrity: sha512-VZQHVaLYTpa3wfCLcFD5cfnegr4iDtzBxV6yh3tys+HYePi4TXuAqct/dmziW0cpCo/UQ2KqAPGxwVO3YMDYJA==} cpu: [arm64] os: [darwin] - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260219.1': - resolution: {integrity: sha512-/tSFdSD76V4X3bX+iXecaa41KRuPMl1LQD3nsE45zZFdmDUIhvCwFRXDP+whkcdaJy8RJTALC0wWhIJ6FUmnwA==} + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260220.1': + resolution: {integrity: sha512-ieGtyz904rlme8YWauDpCqGbnOQQ5dzUyRKU25I7MNIaoZFf0vK5gMh3SLjHC7ayWxjrCa2ezH4ka8UmyWQcPg==} cpu: [x64] os: [darwin] - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260219.1': - resolution: {integrity: sha512-9MXFr+T5LQlXuDsKTtwFdN1lbaKSMmZzabT8Gr1C74ueun91IiJVhNNISwCWY48c28Ka6O6fwxeHjU44ee/G9Q==} + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260220.1': + resolution: {integrity: sha512-nlOOABSQUe6ix/KOsZS3ALZ/sg9rhtp6SKtQnXO8X4+2XUlwVYS6nIrAQ5jG4+OsCvcESttNeHhBw817uNrsuA==} cpu: [arm64] os: [linux] - '@typescript/native-preview-linux-arm@7.0.0-dev.20260219.1': - resolution: {integrity: sha512-pmTGfe3VGoCmjyy9r68wurGBsoaqwYRZ8/i7cIxAJNnq1huKuXRnLnVoZm6uOzZ2GtjWFjwmXXCvcdfmy9+PvQ==} + '@typescript/native-preview-linux-arm@7.0.0-dev.20260220.1': + resolution: {integrity: sha512-wMA63N6XLAkO0Ibq1Qz2zkQHF6oLynYh5+q1YayzWxp1FOas0oJUdNgVbiWeisAT4IEI9SmYtVwJJNTm/cwrwg==} cpu: [arm] os: [linux] - '@typescript/native-preview-linux-x64@7.0.0-dev.20260219.1': - resolution: {integrity: sha512-EMLKx9koxTbdWFg+jaqy5MwZQ19usFug6Cw+evkCaFlDEfF5sgJ/npSRhNJLbZ451FR0eqNIKmIEA9cXlHSDuA==} + '@typescript/native-preview-linux-x64@7.0.0-dev.20260220.1': + resolution: {integrity: sha512-W7R/5ct/BGuPAmJuKFU0ZuLU2nzLA26XfoaoUHHoTLYRMMuY3LBv+7zKSUTlSGjayeWQ5KtDrfrY72LarWAXkQ==} cpu: [x64] os: [linux] - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260219.1': - resolution: {integrity: sha512-vILjYS1EnTZoiD1SfWBtk92qpDrFP9Ln38olonMjtO7mJO6SmN78GHhGR+dyGgNTHQ7PZAxGFiQwZJgrIMWNhw==} + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260220.1': + resolution: {integrity: sha512-FNXTr2lS1QLUB05jWjkBVwrDierNuxKduQq9ayloENJrsC8GfG1sXkfy8R021+ozP/D1LI/CFUn3hkB2vPXTsQ==} cpu: [arm64] os: [win32] - '@typescript/native-preview-win32-x64@7.0.0-dev.20260219.1': - resolution: {integrity: sha512-wwjOQCSViLi+mqJycnRek7GeLZXmJClcZaVYFkLRVbmIMWvWSJkafasFjnQHDinXcLiXxZYdJ+oRR/86FOt2Xw==} + '@typescript/native-preview-win32-x64@7.0.0-dev.20260220.1': + resolution: {integrity: sha512-byHRyf4dOuKOADrs43tWyPhmAgqk+XrA/XOsJnGsxUKxPwots+gf9x5kg/IxTbB3QjPsVe/V9QdMl3//sUTCmQ==} cpu: [x64] os: [win32] - '@typescript/native-preview@7.0.0-dev.20260219.1': - resolution: {integrity: sha512-Y/mfpmpZwfwyNzBgki/wUm/pWLQM2gaL5cum6lbOv8QNZUtzcIy0wTPaS08sb4yhUSGC1jGaJEPR2FNctfeC2Q==} + '@typescript/native-preview@7.0.0-dev.20260220.1': + resolution: {integrity: sha512-trYXlG98/C7Q7pqnPrKo+ksXrWqWVMncCy2x0VftD2llfL99Z//g2mpB9TmzWeKgb4d1659ESvxTowCGnzMccw==} hasBin: true '@vitejs/plugin-basic-ssl@1.2.0': @@ -2619,8 +2917,8 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true @@ -2630,6 +2928,9 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -2964,6 +3265,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -3035,6 +3341,16 @@ packages: jiti: optional: true + eslint@9.39.3: + resolution: {integrity: sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + espree@10.4.0: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3929,6 +4245,11 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rollup@4.58.0: + resolution: {integrity: sha512-wbT0mBmWbIvvq8NeEYWWvevvxnOyhKChir47S66WCxw1SXqhw7ssIYejnQEVt7XYQpsj2y8F9PM+Cr3SNEa0gw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -4259,6 +4580,46 @@ packages: yaml: optional: true + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vitest@3.2.4: resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -4388,7 +4749,7 @@ snapshots: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - '@anthropic-ai/claude-code@2.1.47': + '@anthropic-ai/claude-code@2.1.49': optionalDependencies: '@img/sharp-darwin-arm64': 0.34.5 '@img/sharp-darwin-x64': 0.34.5 @@ -4985,86 +5346,169 @@ snapshots: '@esbuild/aix-ppc64@0.25.12': optional: true + '@esbuild/aix-ppc64@0.27.3': + optional: true + '@esbuild/android-arm64@0.25.12': optional: true + '@esbuild/android-arm64@0.27.3': + optional: true + '@esbuild/android-arm@0.25.12': optional: true + '@esbuild/android-arm@0.27.3': + optional: true + '@esbuild/android-x64@0.25.12': optional: true + '@esbuild/android-x64@0.27.3': + optional: true + '@esbuild/darwin-arm64@0.25.12': optional: true + '@esbuild/darwin-arm64@0.27.3': + optional: true + '@esbuild/darwin-x64@0.25.12': optional: true + '@esbuild/darwin-x64@0.27.3': + optional: true + '@esbuild/freebsd-arm64@0.25.12': optional: true + '@esbuild/freebsd-arm64@0.27.3': + optional: true + '@esbuild/freebsd-x64@0.25.12': optional: true + '@esbuild/freebsd-x64@0.27.3': + optional: true + '@esbuild/linux-arm64@0.25.12': optional: true + '@esbuild/linux-arm64@0.27.3': + optional: true + '@esbuild/linux-arm@0.25.12': optional: true + '@esbuild/linux-arm@0.27.3': + optional: true + '@esbuild/linux-ia32@0.25.12': optional: true + '@esbuild/linux-ia32@0.27.3': + optional: true + '@esbuild/linux-loong64@0.25.12': optional: true + '@esbuild/linux-loong64@0.27.3': + optional: true + '@esbuild/linux-mips64el@0.25.12': optional: true + '@esbuild/linux-mips64el@0.27.3': + optional: true + '@esbuild/linux-ppc64@0.25.12': optional: true + '@esbuild/linux-ppc64@0.27.3': + optional: true + '@esbuild/linux-riscv64@0.25.12': optional: true + '@esbuild/linux-riscv64@0.27.3': + optional: true + '@esbuild/linux-s390x@0.25.12': optional: true + '@esbuild/linux-s390x@0.27.3': + optional: true + '@esbuild/linux-x64@0.25.12': optional: true + '@esbuild/linux-x64@0.27.3': + optional: true + '@esbuild/netbsd-arm64@0.25.12': optional: true + '@esbuild/netbsd-arm64@0.27.3': + optional: true + '@esbuild/netbsd-x64@0.25.12': optional: true + '@esbuild/netbsd-x64@0.27.3': + optional: true + '@esbuild/openbsd-arm64@0.25.12': optional: true + '@esbuild/openbsd-arm64@0.27.3': + optional: true + '@esbuild/openbsd-x64@0.25.12': optional: true + '@esbuild/openbsd-x64@0.27.3': + optional: true + '@esbuild/openharmony-arm64@0.25.12': optional: true + '@esbuild/openharmony-arm64@0.27.3': + optional: true + '@esbuild/sunos-x64@0.25.12': optional: true + '@esbuild/sunos-x64@0.27.3': + optional: true + '@esbuild/win32-arm64@0.25.12': optional: true + '@esbuild/win32-arm64@0.27.3': + optional: true + '@esbuild/win32-ia32@0.25.12': optional: true + '@esbuild/win32-ia32@0.27.3': + optional: true + '@esbuild/win32-x64@0.25.12': optional: true + '@esbuild/win32-x64@0.27.3': + optional: true + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': dependencies: eslint: 9.39.2(jiti@2.6.1) eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.3(jiti@2.6.1))': + dependencies: + eslint: 9.39.3(jiti@2.6.1) + eslint-visitor-keys: 3.4.3 + '@eslint-community/regexpp@4.12.2': {} '@eslint/config-array@0.21.1': @@ -5099,6 +5543,8 @@ snapshots: '@eslint/js@9.39.2': {} + '@eslint/js@9.39.3': {} + '@eslint/object-schema@2.1.7': {} '@eslint/plugin-kit@0.4.1': @@ -5450,78 +5896,153 @@ snapshots: '@rollup/rollup-android-arm-eabi@4.57.1': optional: true + '@rollup/rollup-android-arm-eabi@4.58.0': + optional: true + '@rollup/rollup-android-arm64@4.57.1': optional: true + '@rollup/rollup-android-arm64@4.58.0': + optional: true + '@rollup/rollup-darwin-arm64@4.57.1': optional: true + '@rollup/rollup-darwin-arm64@4.58.0': + optional: true + '@rollup/rollup-darwin-x64@4.57.1': optional: true + '@rollup/rollup-darwin-x64@4.58.0': + optional: true + '@rollup/rollup-freebsd-arm64@4.57.1': optional: true + '@rollup/rollup-freebsd-arm64@4.58.0': + optional: true + '@rollup/rollup-freebsd-x64@4.57.1': optional: true + '@rollup/rollup-freebsd-x64@4.58.0': + optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.58.0': + optional: true + '@rollup/rollup-linux-arm-musleabihf@4.57.1': optional: true + '@rollup/rollup-linux-arm-musleabihf@4.58.0': + optional: true + '@rollup/rollup-linux-arm64-gnu@4.57.1': optional: true + '@rollup/rollup-linux-arm64-gnu@4.58.0': + optional: true + '@rollup/rollup-linux-arm64-musl@4.57.1': optional: true + '@rollup/rollup-linux-arm64-musl@4.58.0': + optional: true + '@rollup/rollup-linux-loong64-gnu@4.57.1': optional: true + '@rollup/rollup-linux-loong64-gnu@4.58.0': + optional: true + '@rollup/rollup-linux-loong64-musl@4.57.1': optional: true + '@rollup/rollup-linux-loong64-musl@4.58.0': + optional: true + '@rollup/rollup-linux-ppc64-gnu@4.57.1': optional: true + '@rollup/rollup-linux-ppc64-gnu@4.58.0': + optional: true + '@rollup/rollup-linux-ppc64-musl@4.57.1': optional: true + '@rollup/rollup-linux-ppc64-musl@4.58.0': + optional: true + '@rollup/rollup-linux-riscv64-gnu@4.57.1': optional: true + '@rollup/rollup-linux-riscv64-gnu@4.58.0': + optional: true + '@rollup/rollup-linux-riscv64-musl@4.57.1': optional: true + '@rollup/rollup-linux-riscv64-musl@4.58.0': + optional: true + '@rollup/rollup-linux-s390x-gnu@4.57.1': optional: true + '@rollup/rollup-linux-s390x-gnu@4.58.0': + optional: true + '@rollup/rollup-linux-x64-gnu@4.57.1': optional: true + '@rollup/rollup-linux-x64-gnu@4.58.0': + optional: true + '@rollup/rollup-linux-x64-musl@4.57.1': optional: true + '@rollup/rollup-linux-x64-musl@4.58.0': + optional: true + '@rollup/rollup-openbsd-x64@4.57.1': optional: true + '@rollup/rollup-openbsd-x64@4.58.0': + optional: true + '@rollup/rollup-openharmony-arm64@4.57.1': optional: true + '@rollup/rollup-openharmony-arm64@4.58.0': + optional: true + '@rollup/rollup-win32-arm64-msvc@4.57.1': optional: true + '@rollup/rollup-win32-arm64-msvc@4.58.0': + optional: true + '@rollup/rollup-win32-ia32-msvc@4.57.1': optional: true + '@rollup/rollup-win32-ia32-msvc@4.58.0': + optional: true + '@rollup/rollup-win32-x64-gnu@4.57.1': optional: true + '@rollup/rollup-win32-x64-gnu@4.58.0': + optional: true + '@rollup/rollup-win32-x64-msvc@4.57.1': optional: true + '@rollup/rollup-win32-x64-msvc@4.58.0': + optional: true + '@shikijs/engine-oniguruma@3.22.0': dependencies: '@shikijs/types': 3.22.0 @@ -5714,6 +6235,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/type-utils': 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.56.0 + eslint: 9.39.3(jiti@2.6.1) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.56.0 @@ -5726,6 +6263,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.56.0 + debug: 4.4.3 + eslint: 9.39.3(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/project-service@8.56.0(typescript@5.9.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.56.0(typescript@5.9.3) @@ -5756,6 +6305,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/type-utils@8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.3(jiti@2.6.1) + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/types@8.56.0': {} '@typescript-eslint/typescript-estree@8.56.0(typescript@5.9.3)': @@ -5784,41 +6345,52 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) + eslint: 9.39.3(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/visitor-keys@8.56.0': dependencies: '@typescript-eslint/types': 8.56.0 eslint-visitor-keys: 5.0.0 - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260219.1': + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260220.1': optional: true - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260219.1': + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260220.1': optional: true - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260219.1': + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260220.1': optional: true - '@typescript/native-preview-linux-arm@7.0.0-dev.20260219.1': + '@typescript/native-preview-linux-arm@7.0.0-dev.20260220.1': optional: true - '@typescript/native-preview-linux-x64@7.0.0-dev.20260219.1': + '@typescript/native-preview-linux-x64@7.0.0-dev.20260220.1': optional: true - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260219.1': + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260220.1': optional: true - '@typescript/native-preview-win32-x64@7.0.0-dev.20260219.1': + '@typescript/native-preview-win32-x64@7.0.0-dev.20260220.1': optional: true - '@typescript/native-preview@7.0.0-dev.20260219.1': + '@typescript/native-preview@7.0.0-dev.20260220.1': optionalDependencies: - '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260219.1 - '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260219.1 - '@typescript/native-preview-linux-arm': 7.0.0-dev.20260219.1 - '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260219.1 - '@typescript/native-preview-linux-x64': 7.0.0-dev.20260219.1 - '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260219.1 - '@typescript/native-preview-win32-x64': 7.0.0-dev.20260219.1 + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260220.1 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260220.1 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20260220.1 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260220.1 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20260220.1 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260220.1 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20260220.1 '@vitejs/plugin-basic-ssl@1.2.0(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2))': dependencies: @@ -5863,13 +6435,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2))': + '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) '@vitest/pretty-format@3.2.4': dependencies: @@ -5907,11 +6479,11 @@ snapshots: dependencies: event-target-shim: 5.0.1 - acorn-jsx@5.3.2(acorn@8.15.0): + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn@8.15.0: {} + acorn@8.16.0: {} aes-js@4.0.0-beta.5: {} @@ -5922,6 +6494,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@6.14.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + ansi-colors@4.1.3: {} ansi-regex@5.0.1: {} @@ -6254,6 +6833,35 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 + esbuild@0.27.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + escalade@3.2.0: {} escape-string-regexp@4.0.0: {} @@ -6343,10 +6951,51 @@ snapshots: transitivePeerDependencies: - supports-color + eslint@9.39.3(jiti@2.6.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.3 + '@eslint/js': 9.39.3 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.14.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 + transitivePeerDependencies: + - supports-color + espree@10.4.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 esprima@4.0.1: {} @@ -7054,7 +7703,7 @@ snapshots: glob: 13.0.5 package-json-from-dist: 1.0.1 - rolldown-plugin-dts@0.20.0(@typescript/native-preview@7.0.0-dev.20260219.1)(rolldown@1.0.0-beta.58)(typescript@5.9.3): + rolldown-plugin-dts@0.20.0(@typescript/native-preview@7.0.0-dev.20260220.1)(rolldown@1.0.0-beta.58)(typescript@5.9.3): dependencies: '@babel/generator': 7.29.1 '@babel/parser': 7.29.0 @@ -7066,7 +7715,7 @@ snapshots: obug: 2.1.1 rolldown: 1.0.0-beta.58 optionalDependencies: - '@typescript/native-preview': 7.0.0-dev.20260219.1 + '@typescript/native-preview': 7.0.0-dev.20260220.1 typescript: 5.9.3 transitivePeerDependencies: - oxc-resolver @@ -7140,6 +7789,37 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.57.1 fsevents: 2.3.3 + rollup@4.58.0: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.58.0 + '@rollup/rollup-android-arm64': 4.58.0 + '@rollup/rollup-darwin-arm64': 4.58.0 + '@rollup/rollup-darwin-x64': 4.58.0 + '@rollup/rollup-freebsd-arm64': 4.58.0 + '@rollup/rollup-freebsd-x64': 4.58.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.58.0 + '@rollup/rollup-linux-arm-musleabihf': 4.58.0 + '@rollup/rollup-linux-arm64-gnu': 4.58.0 + '@rollup/rollup-linux-arm64-musl': 4.58.0 + '@rollup/rollup-linux-loong64-gnu': 4.58.0 + '@rollup/rollup-linux-loong64-musl': 4.58.0 + '@rollup/rollup-linux-ppc64-gnu': 4.58.0 + '@rollup/rollup-linux-ppc64-musl': 4.58.0 + '@rollup/rollup-linux-riscv64-gnu': 4.58.0 + '@rollup/rollup-linux-riscv64-musl': 4.58.0 + '@rollup/rollup-linux-s390x-gnu': 4.58.0 + '@rollup/rollup-linux-x64-gnu': 4.58.0 + '@rollup/rollup-linux-x64-musl': 4.58.0 + '@rollup/rollup-openbsd-x64': 4.58.0 + '@rollup/rollup-openharmony-arm64': 4.58.0 + '@rollup/rollup-win32-arm64-msvc': 4.58.0 + '@rollup/rollup-win32-ia32-msvc': 4.58.0 + '@rollup/rollup-win32-x64-gnu': 4.58.0 + '@rollup/rollup-win32-x64-msvc': 4.58.0 + fsevents: 2.3.3 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -7273,7 +7953,7 @@ snapshots: dependencies: typescript: 5.9.3 - tsdown@0.19.0-beta.3(@typescript/native-preview@7.0.0-dev.20260219.1)(synckit@0.11.12)(typescript@5.9.3): + tsdown@0.19.0-beta.3(@typescript/native-preview@7.0.0-dev.20260220.1)(synckit@0.11.12)(typescript@5.9.3): dependencies: ansis: 4.2.0 cac: 6.7.14 @@ -7284,7 +7964,7 @@ snapshots: obug: 2.1.1 picomatch: 4.0.3 rolldown: 1.0.0-beta.58 - rolldown-plugin-dts: 0.20.0(@typescript/native-preview@7.0.0-dev.20260219.1)(rolldown@1.0.0-beta.58)(typescript@5.9.3) + rolldown-plugin-dts: 0.20.0(@typescript/native-preview@7.0.0-dev.20260220.1)(rolldown@1.0.0-beta.58)(typescript@5.9.3) semver: 7.7.4 tinyexec: 1.0.2 tinyglobby: 0.2.15 @@ -7333,6 +8013,17 @@ snapshots: transitivePeerDependencies: - supports-color + typescript-eslint@8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.56.0(@typescript-eslint/parser@8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.3(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + typescript@5.9.3: {} uc.micro@2.1.0: {} @@ -7384,7 +8075,7 @@ snapshots: debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) transitivePeerDependencies: - '@types/node' - jiti @@ -7414,13 +8105,13 @@ snapshots: lightningcss: 1.31.1 yaml: 2.8.2 - vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2): + vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2): dependencies: - esbuild: 0.25.12 + esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.57.1 + rollup: 4.58.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.10.13 @@ -7433,7 +8124,7 @@ snapshots: dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2)) + '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -7451,7 +8142,7 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) vite-node: 3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: