Skip to content

fix(caip): keep Node's fs out of the browser-reachable module graph - #12507

Merged
kaladinlight merged 3 commits into
shapeshift:developfrom
reallybeard:fix/caip-no-node-fs-in-browser-graph
Jul 30, 2026
Merged

fix(caip): keep Node's fs out of the browser-reachable module graph#12507
kaladinlight merged 3 commits into
shapeshift:developfrom
reallybeard:fix/caip-no-node-fs-in-browser-graph

Conversation

@reallybeard

@reallybeard reallybeard commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Description

@shapeshiftoss/caip cannot be consumed from a browser bundler today. In a Next.js app it fails with:

Module not found: Can't resolve 'fs'
Import trace:
  @shapeshiftoss/caip/dist/esm/adapters/coingecko/utils.js
  @shapeshiftoss/caip/dist/esm/adapters/coingecko/index.js
  @shapeshiftoss/caip/dist/esm/adapters/index.js
  @shapeshiftoss/swap-widget/dist/index.js

The cause is a single edge. adapters/coingecko/index.ts:56 re-exports from ./utils:

export { fetchData as fetchCoingeckoData, parseData as parseCoingeckoData } from './utils'

and utils.ts imported fs for writeFiles — a codegen helper whose only caller is generate.ts. That one re-export puts import fs from 'fs' into the graph every browser bundler reaches from the package entry.

I walked the published ESM graph from dist/esm/index.js to check the blast radius. 82 modules are reachable, and exactly one of them imports a Node built-in:

=== as published (8.16.9) ===
modules reachable from dist/esm/index.js: 82
reachable modules importing a Node built-in: 1
  adapters/coingecko/utils.js  imports  fs

=== with this change ===
reachable modules importing a Node built-in: 0

This PR moves writeFiles into a codegen-only writeFiles.ts in each adapter directory. generate.ts imports it from the new path.

The coincap and coinbase utils.ts files import fs for the same reason, but nothing re-exports them, so theirs is latent rather than live. They get the same treatment here so that re-exporting from them later can't reintroduce the bug.

Worth noting why this is invisible in this repo: packages/swap-widget/devDependencies includes vite-plugin-node-polyfills, so the dev server and demo build polyfill fs silently. Consumers who don't polyfill Node built-ins — the default for Next.js, and the right posture for browser bundles — get a hard failure.

No public API change. fetchCoingeckoData and parseCoingeckoData still export from utils.ts, and writeFiles was never exposed in any barrel. The only non-mechanical edit is making the AssetMap type exported so writeFiles.ts can import it as a type.

One thing left deliberately undone: the compiled generate.js and writeFiles.js still land in dist, exactly as the compiled .test.js files already do. They're just unreachable from index.js, which is what bundlers care about. If you'd rather keep them out of the tarball entirely, excluding src/**/generate.ts and src/**/writeFiles.ts from tsconfig.{esm,cjs}.json would do it — at the cost of no longer type-checking the codegen, which is why I didn't assume it.

Issue (if applicable)

None — reported from an external integration.

Risk

Low, and contained to packages/caip. Pure code movement: no logic changes, no public export changes, no dependency or lockfile changes. writeFiles bodies are moved verbatim.

The failure mode if something were wrong is loud and immediate — pnpm generate:coingecko / generate:coincap would fail to resolve writeFiles, and the two moved test suites cover its behaviour.

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

None. The moved code is build-time asset-map codegen and is never reachable at runtime.

Testing

Engineering

# codegen still works end to end — this is the real exercise of the moved code
cd packages/caip
pnpm generate:coingecko
pnpm generate:coincap
git status   # generated adapter.json files unchanged

# the two suites that cover writeFiles
pnpm test src/adapters/coingecko/utils.test.ts src/adapters/coincap/utils.test.ts

vi.mock('fs') in those suites is module-scoped, so it still intercepts the import from its new location.

Verified on my side: no Node built-in imports remain anywhere in packages/caip/src outside generate.ts and the new writeFiles.ts files; writeFiles appears in no barrel; and all touched files pass Prettier 3.0.3 with the options from .eslintrc.

I could not run ESLint, tsc, or Vitest locally — that needs a full monorepo install and I only had a shallow clone — so CI is the real check on those.

Operations

No user-facing change. Regression surface is the CoinGecko/CoinCap/Coinbase asset-id adapter maps, which the codegen commands above regenerate byte-identically.

Screenshots (if applicable)

n/a

Made with Cursor

Summary by CodeRabbit

  • Refactor
    • Reorganized adapter generation so data fetching/parsing is kept separate from generated-file writing for Coinbase, CoinCap, and CoinGecko.
    • Updated module structure and exports to improve clarity without changing generation behavior.
  • Tests
    • Adjusted adapter test imports to match the updated generation helper locations.
  • Developer Tools
    • Added clearer return typing for generation helpers and exposed the CoinGecko asset map type for better reuse during code generation.

adapters/coingecko/index.ts re-exports fetchData and parseData from
adapters/coingecko/utils.ts, and utils.ts imported `fs` for writeFiles - a
codegen helper only ever called by generate.ts. That single edge put
`import fs from 'fs'` in the graph every browser bundler reaches from the
package entry, so consuming @shapeshiftoss/caip from a Next.js app fails with
"Module not found: Can't resolve 'fs'".

Move writeFiles into a codegen-only writeFiles.ts per adapter. The public API is
unchanged: fetchCoingeckoData and parseCoingeckoData still export from utils.ts,
and writeFiles was never in a barrel. coincap and coinbase get the same
treatment - their utils.ts is not re-exported today, so the fs import there is
latent rather than live, and this keeps it that way.

Compiled generate.js/writeFiles.js still land in dist, like the compiled tests
already do, but nothing reachable from index.js imports them.
@reallybeard
reallybeard requested a review from a team as a code owner July 29, 2026 19:15
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f7857f1a-335e-4b74-8c15-c41bc6257bf6

📥 Commits

Reviewing files that changed from the base of the PR and between e6a6108 and 826cff5.

📒 Files selected for processing (3)
  • packages/caip/src/adapters/coinbase/writeFiles.ts
  • packages/caip/src/adapters/coincap/writeFiles.ts
  • packages/caip/src/adapters/coingecko/writeFiles.ts

📝 Walkthrough

Walkthrough

Coinbase, CoinCap, and CoinGecko filesystem code generation was separated from data utilities into dedicated writeFiles modules. Generators and tests import writers separately, CoinGecko exports AssetMap, and asynchronous writer return types are explicitly declared.

Changes

Adapter codegen separation

Layer / File(s) Summary
Coinbase writer extraction
packages/caip/src/adapters/coinbase/*
Coinbase filesystem writing moved into writeFiles.ts, generator imports were updated, and writer functions now declare Promise<void>.
CoinCap writer extraction
packages/caip/src/adapters/coincap/*
CoinCap writing moved into a dedicated module, generator and test imports were updated, and writer functions now declare Promise<void>.
CoinGecko writer extraction
packages/caip/src/adapters/coingecko/*
CoinGecko writing moved into a dedicated module, AssetMap became exported, imports were updated, and writer return types were added.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: 0xapotheosis

Poem

A rabbit hops through codegen bright,
Moving writers out of utility night.
Coinbase, CoinCap, Gecko too,
Each gets a home for files anew.
Typed promises guide the way—
“Hop hop!” through codegen’s day.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: removing Node fs from browser-reachable CAIP modules.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/caip/src/adapters/coinbase/writeFiles.ts`:
- Around line 8-15: All extracted writer functions need explicit Promise<void>
return types instead of inferred types. Update writeFile and writeFiles in
packages/caip/src/adapters/coinbase/writeFiles.ts, writeFiles and its nested
callback in packages/caip/src/adapters/coincap/writeFiles.ts, and writeFiles and
its nested callback in packages/caip/src/adapters/coingecko/writeFiles.ts; make
no other behavioral changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 58880c65-b493-4aa7-90eb-9ef069ee4f56

📥 Commits

Reviewing files that changed from the base of the PR and between dffc530 and e6a6108.

📒 Files selected for processing (11)
  • packages/caip/src/adapters/coinbase/generate.ts
  • packages/caip/src/adapters/coinbase/utils.ts
  • packages/caip/src/adapters/coinbase/writeFiles.ts
  • packages/caip/src/adapters/coincap/generate.ts
  • packages/caip/src/adapters/coincap/utils.test.ts
  • packages/caip/src/adapters/coincap/utils.ts
  • packages/caip/src/adapters/coincap/writeFiles.ts
  • packages/caip/src/adapters/coingecko/generate.ts
  • packages/caip/src/adapters/coingecko/utils.test.ts
  • packages/caip/src/adapters/coingecko/utils.ts
  • packages/caip/src/adapters/coingecko/writeFiles.ts
💤 Files with no reviewable changes (2)
  • packages/caip/src/adapters/coincap/utils.ts
  • packages/caip/src/adapters/coinbase/utils.ts

Comment thread packages/caip/src/adapters/coinbase/writeFiles.ts Outdated
Chris Ellis and others added 2 commits July 29, 2026 14:30
…dules

Per .cursor/rules/typescript-best-practices.mdc, which lists missing return
types as an anti-pattern. The moved code carried no annotations, so these are
new on the extracted files.
@kaladinlight
kaladinlight enabled auto-merge (squash) July 30, 2026 03:39
@kaladinlight
kaladinlight merged commit 6b5ad20 into shapeshift:develop Jul 30, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants