Skip to content

refactor(indexer): replace axios with native fetch API - #3553

Merged
stalniy merged 7 commits into
mainfrom
refactor/indexer-replace-axios-with-fetch
Aug 5, 2026
Merged

refactor(indexer): replace axios with native fetch API#3553
stalniy merged 7 commits into
mainfrom
refactor/indexer-replace-axios-with-fetch

Conversation

@stalniy

@stalniy stalniy commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Why

Closes CON-169

What

Swap the axios HTTP client and node-fetch for Node's native fetch across the indexer. Behavior is preserved: non-2xx responses still throw (via an explicit ok check or a small HttpResponseError carrying status and body), timeouts use AbortSignal.timeout, and provider status/version calls keep bypassing self-signed cert verification through an undici Agent dispatcher.

Summary by CodeRabbit

  • Bug Fixes
    • Improved indexer reliability when communicating with blockchain nodes and external service endpoints.
    • Added clearer handling for failed responses, timeouts, rate limits, and RPC errors.
    • Improved support for endpoints using self-signed certificates.
    • Preserved provider status, validator information, pricing history, and location lookup behavior while improving request handling.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 5 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 051e008d-f88d-4db3-b9ea-5e30278344ca

📥 Commits

Reviewing files that changed from the base of the PR and between c571bfa and 15cd25f.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • apps/indexer/package.json
  • apps/indexer/src/chain/nodeAccessor.ts
  • apps/indexer/src/chain/nodeInfo.ts
  • apps/indexer/src/db/keybaseProvider.ts
  • apps/indexer/src/db/priceHistoryProvider.ts
  • apps/indexer/src/providers/ipLocationProvider.ts
  • apps/indexer/src/providers/providerStatusProvider.ts
  • apps/indexer/src/providers/statusEndpointHandlers/rest.ts
  • apps/indexer/src/scheduler.ts
  • apps/indexer/src/shared/utils/fetch.ts
📝 Walkthrough

Walkthrough

The indexer replaces Axios and node-fetch with native fetch. It adds timeout handling, HTTP response errors, typed response shapes, self-signed certificate support, and wrapped node access errors.

Changes

Indexer HTTP migration

Layer / File(s) Summary
Shared fetch transport
apps/indexer/package.json, apps/indexer/src/shared/utils/fetch.ts, apps/indexer/src/db/keybaseProvider.ts
The indexer removes Axios and node-fetch, adds undici, provides fetchAllowingSelfSignedCerts, and types Keybase responses.
Node status and RPC requests
apps/indexer/src/chain/nodeInfo.ts, apps/indexer/src/chain/nodeAccessor.ts
Node requests use native fetch, timeout signals, explicit HTTP errors, preserved response bodies, and wrapped NodeAccessError causes.
Provider status and location requests
apps/indexer/src/providers/providerStatusProvider.ts, apps/indexer/src/providers/statusEndpointHandlers/rest.ts, apps/indexer/src/providers/ipLocationProvider.ts, apps/indexer/src/db/priceHistoryProvider.ts
Provider requests use fetch-based transport, certificate handling where required, explicit status checks, JSON parsing, truncated error bodies, and named response types.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: ygrishajev

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/indexer-replace-axios-with-fetch

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

@stalniy
stalniy force-pushed the refactor/indexer-replace-axios-with-fetch branch from 62d011d to 1823182 Compare August 4, 2026 15:41
@codecov

codecov Bot commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.05%. Comparing base (c571bfa) to head (15cd25f).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3553      +/-   ##
==========================================
- Coverage   75.08%   75.05%   -0.03%     
==========================================
  Files        1162     1162              
  Lines       30165    30165              
  Branches     7503     7509       +6     
==========================================
- Hits        22649    22640       -9     
- Misses       6638     6651      +13     
+ Partials      878      874       -4     
Flag Coverage Δ
api 88.51% <ø> (-0.10%) ⬇️
deploy-web 64.65% <ø> (-0.01%) ⬇️
log-collector 85.85% <ø> (ø)
notifications 93.84% <ø> (ø)
provider-console 81.38% <ø> (ø)
provider-inventory 84.98% <ø> (ø)
provider-proxy 88.17% <ø> (ø)
tx-signer 86.72% <ø> (ø)
see 7 files with indirect coverage changes
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread apps/indexer/src/chain/nodeInfo.ts
Comment thread apps/indexer/src/providers/ipLocationProvider.ts

@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: 4

🤖 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 `@apps/indexer/src/chain/nodeInfo.ts`:
- Around line 179-181: Update the non-OK response handling around
HttpResponseError to read the body once with response.text(), parse it only when
valid JSON, and preserve the original text otherwise. Do not catch body-read
failures so aborts and other read errors propagate; add a regression test
covering a non-JSON HTTP error response.
- Around line 110-112: Update the non-OK response branch in updateStatus to
cancel or fully consume response.body before throwing HttpResponseError, while
preserving response.status for the exception. Keep the existing
successful-response handling and retry behavior unchanged.

In `@apps/indexer/src/db/priceHistoryProvider.ts`:
- Line 22: Update the response handling around the PriceHistoryProvider request
to check response.ok before invoking response.json(). When the response is
non-2xx, throw an error that includes the HTTP status, and preserve the existing
JSON parsing flow for successful responses.

In `@apps/indexer/src/providers/ipLocationProvider.ts`:
- Around line 19-20: Update the fetch flow in the IP location provider to check
response.ok immediately after fetch and throw for non-2xx responses before
invoking response.json(). Preserve JSON parsing and provider updates only for
successful responses.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5e96dd37-e870-40f0-a18b-d13c3c186907

📥 Commits

Reviewing files that changed from the base of the PR and between 49e9015 and 1823182.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • apps/indexer/package.json
  • apps/indexer/src/chain/nodeInfo.ts
  • apps/indexer/src/db/keybaseProvider.ts
  • apps/indexer/src/db/priceHistoryProvider.ts
  • apps/indexer/src/providers/ipLocationProvider.ts
  • apps/indexer/src/providers/providerStatusProvider.ts
  • apps/indexer/src/providers/statusEndpointHandlers/rest.ts
  • apps/indexer/src/scheduler.ts
  • apps/indexer/src/shared/utils/fetch.ts
💤 Files with no reviewable changes (1)
  • apps/indexer/src/scheduler.ts

Comment thread apps/indexer/src/chain/nodeInfo.ts Outdated
Comment thread apps/indexer/src/chain/nodeInfo.ts Outdated
Comment thread apps/indexer/src/db/priceHistoryProvider.ts
Comment thread apps/indexer/src/providers/ipLocationProvider.ts

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Beyond the two previously flagged findings on this PR, this run also examined whether skipping the response body drain on the updateStatus() non-ok path in apps/indexer/src/chain/nodeInfo.ts (unlike the query() path, which reads the body via response.json().catch()) could exhaust the undici connection pool. Given the low request volume and periodic polling nature of node-status checks, this doesn't rise to a real issue and needs no action.

Extended reasoning...

This run re-examined the PR (no new commits since the prior bug-hunting pass) and found no new bugs beyond the two already posted as inline comments (the DOMException.message mutation regression in nodeInfo.ts/nodeAccessor.ts, and the missing ok-check in ipLocationProvider.ts). One additional candidate was investigated and ruled out: an unconsumed response body on the non-2xx path of updateStatus() in nodeInfo.ts potentially exhausting the undici connection pool. Given the low, periodic call volume of node status polling, this isn't a practical concern. Deferring rather than approving since the existing critical inline finding (DOMException message mutation) is still unresolved.

@github-actions github-actions Bot added size: M and removed size: S labels Aug 4, 2026
@stalniy
stalniy enabled auto-merge August 4, 2026 16:23
@stalniy
stalniy disabled auto-merge August 4, 2026 16:23

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No new issues from this run. This PR needed several correction rounds already (timeout-error handling, non-2xx JSON parsing, response body draining) to get the fetch migration behaviorally correct, so I'd like a human to confirm the final state before merge rather than rely on my read alone.

What was reviewed:

  • Confirmed the previously flagged issues are now fixed in the current commit: the DOMException message-mutation bug in nodeAccessor.ts (now wraps in a new Error with cause), the missing response.ok checks in ipLocationProvider.ts and priceHistoryProvider.ts, and non-JSON error body handling in nodeInfo.ts (now reads the body once via response.text() and keeps raw text when it isn't JSON).
  • Checked the non-2xx / timeout error paths across nodeInfo.ts, nodeAccessor.ts, providerStatusProvider.ts, rest.ts against the PR's stated invariant that non-2xx responses still throw.
  • Investigated claims that unread response bodies on non-2xx paths in providerStatusProvider.ts/rest.ts leak undici connections — ruled out this run.
Extended reasoning...

This PR replaces axios and node-fetch with native fetch across the indexer's HTTP call sites: blockchain node RPC/status queries (nodeInfo.ts, nodeAccessor.ts), provider version/status checks including a self-signed-cert dispatcher (providerStatusProvider.ts, rest.ts, shared/utils/fetch.ts), and two external data providers (keybaseProvider.ts, priceHistoryProvider.ts). It also drops axios/node-fetch and adds undici as a direct dependency.

Security risks

No new security-sensitive surface is introduced. The self-signed-cert bypass (rejectUnauthorized: false) is carried over from the prior axios httpsAgent configuration, not newly introduced, and is scoped to provider status/version calls as before. No auth, crypto, or permission logic is touched.

Level of scrutiny

This warrants more than a rubber stamp. Native fetch has different failure semantics than axios (no automatic reject on non-2xx, DOMException instead of a plain Error on timeout, one-shot body streams), and this PR's own history shows those differences bit it in practice: my prior bug-hunting pass caught a genuine regression (timeout errors getting swapped for an opaque TypeError due to mutating a getter-only DOMException.message), and CodeRabbit caught missing ok-checks and body-draining/preservation issues. All of those have since been fixed in commits 0d02834 and 5847644, and this run's bug hunter found nothing further, including ruling out a connection-pool-exhaustion theory on the remaining non-2xx paths. Given the code now touches blockchain sync reliability (nodeAccessor/nodeInfo feed chainSync's downloadBlock/downloadBlocks) and required multiple correction rounds to get right, a human sanity-check of the final diff is warranted before merge.

Other factors

Codecov reports full coverage of modified/coverable lines, but there are no dedicated unit tests for the new HttpResponseError/toHttpResponseError error-shaping logic or the timeout/ok-check branches added to nodeInfo.ts, nodeAccessor.ts, ipLocationProvider.ts, or priceHistoryProvider.ts — the coverage is presumably incidental from existing higher-level tests rather than targeted regression tests for the fetch-migration edge cases that were just fixed.

@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: 2

🤖 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 `@apps/indexer/src/db/priceHistoryProvider.ts`:
- Around line 22-25: Update the non-OK response branches in
apps/indexer/src/db/priceHistoryProvider.ts lines 22-25 and
apps/indexer/src/providers/ipLocationProvider.ts lines 20-23 to consume the
response body before throwing, include a bounded text representation alongside
the endpoint or IP and status, and preserve the existing error behavior
otherwise.

In `@apps/indexer/src/providers/ipLocationProvider.ts`:
- Around line 18-23: Update the fetch endpoint in getIpLocation to use the HTTPS
scheme for the IP-location request, preserving the existing response validation
and error handling.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cf1e03fa-88f8-475b-93c1-8986c5f79530

📥 Commits

Reviewing files that changed from the base of the PR and between 1823182 and 5847644.

📒 Files selected for processing (4)
  • apps/indexer/src/chain/nodeAccessor.ts
  • apps/indexer/src/chain/nodeInfo.ts
  • apps/indexer/src/db/priceHistoryProvider.ts
  • apps/indexer/src/providers/ipLocationProvider.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/indexer/src/chain/nodeInfo.ts

Comment thread apps/indexer/src/db/priceHistoryProvider.ts
Comment thread apps/indexer/src/providers/ipLocationProvider.ts
Comment thread apps/indexer/src/providers/ipLocationProvider.ts Outdated
@stalniy
stalniy force-pushed the refactor/indexer-replace-axios-with-fetch branch from 10c5fe0 to 19dabb7 Compare August 5, 2026 09:45
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

Comment thread package-lock.json
stalniy and others added 7 commits August 5, 2026 11:46
Swap the axios HTTP client for Node's native fetch across the indexer.
Behavior is preserved: non-2xx responses still throw (via an explicit
ok check or a small HttpResponseError carrying status and body),
timeouts use AbortSignal.timeout, and provider status/version calls keep
bypassing self-signed cert verification through an undici Agent
dispatcher.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Response.json() resolves to Promise<unknown> under undici-types (IDE) but
Promise<any> under DOM lib (CLI tsc). Cast/annotate the parsed bodies so
both resolutions type-check identically instead of relying on implicit any.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
node-fetch was not imported anywhere in the source; Node's global fetch
covers all HTTP calls. Remove it along with its now-orphaned
@types/node-fetch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eduler

Drop the remaining node-fetch imports in favour of Node's global fetch.
Behavior is unchanged (node-fetch v2 and global fetch both leave non-2xx
responses unthrown, follow redirects and apply no timeout here); the
parsed json() bodies are cast explicitly so they type-check under both
undici-types and DOM lib resolutions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Node's fetch rejects timeouts with a getter-only DOMException, so mutating
err.message in NodeAccessor swallowed the real error with a TypeError. Wrap
instead, and read non-2xx bodies once as text so plain-text errors survive and
the connection returns to the undici pool.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…errors

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@stalniy
stalniy force-pushed the refactor/indexer-replace-axios-with-fetch branch from 19dabb7 to 15cd25f Compare August 5, 2026 09:46
@stalniy
stalniy enabled auto-merge August 5, 2026 09:52
Comment thread apps/indexer/src/providers/statusEndpointHandlers/rest.ts
@stalniy
stalniy added this pull request to the merge queue Aug 5, 2026
Merged via the queue into main with commit f4cd38c Aug 5, 2026
59 checks passed
@stalniy
stalniy deleted the refactor/indexer-replace-axios-with-fetch branch August 5, 2026 10:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants