Skip to content

feat: accept the native fetch directly as the HTTPProvider fetch option - #583

Merged
LautaroPetaccio merged 1 commit into
masterfrom
feat/fetchfunction-accept-native-fetch
Jun 24, 2026
Merged

LautaroPetaccio merged 1 commit into
masterfrom
feat/fetchfunction-accept-native-fetch

Conversation

@LautaroPetaccio

Copy link
Copy Markdown
Contributor

Problem

HTTPProvider's FetchFunction option typed its params with mode?: string:

export type FetchFunction = (url: string, params: { body?: any; method?: string; mode?: string; headers?: any }) => Promise<any>

The global native fetch types its init as RequestInit, whose mode is RequestMode (a string union). Since string is not assignable to RequestMode, the native fetch is not assignable to FetchFunction, so every caller has to cast:

new HTTPProvider(url, { fetch: fetch.fetch as unknown as FetchFunction })   // 👎 cast

Fix

HTTPProvider never sets mode (it only sends body/method/headers), so the field is dead weight. Dropping it makes the option accept, with no cast:

  • the global native fetch — the same WHATWG signature on web and server;
  • native-fetch components (e.g. @dcl/fetch-component's fetch);
  • and node-fetch (still assignable — existing callers keep compiling).
new HTTPProvider(url, { fetch: globalThis.fetch })   // ✅ no cast

This is a type-only change — the emitted JS is identical, so there is no runtime/behavior change.

Tests

Added compile-time assertions in test/HTTPProvider.spec.ts that globalThis.fetch and a native-fetch-component-shaped function are assignable to the option without a cast. The existing node-fetch integration spec still typechecks.

Verification

  • tsc src + full test project (incl. the node-fetch integration spec): clean
  • unit suite: 10/10
  • make build: succeeds; API report regenerated (idempotent) and committed; docs updated
  • lint: clean

Follow-up

Once published, consumers can drop their as unknown as FetchFunction casts (e.g. archipelago-workers' ws-connector).

🤖 Generated with Claude Code

FetchFunction declared `mode?: string`, which made the global native fetch
non-assignable to it (native `RequestInit` types `mode` as `RequestMode`, and
`string` is not assignable to `RequestMode`), forcing callers to cast with
`fetch as unknown as FetchFunction`. HTTPProvider never sets `mode`, so dropping
it lets the global native fetch — the same WHATWG signature on web and server —
as well as native-fetch components (e.g. @dcl/fetch-component) and node-fetch be
passed to `options.fetch` with no cast.

Type-only change: the emitted JS is unchanged, and existing callers (including
those still passing node-fetch) keep compiling. Adds compile-time assertions and
regenerates the API report and docs.
@LautaroPetaccio
LautaroPetaccio requested a review from menduz as a code owner June 24, 2026 17:44
@github-actions

Copy link
Copy Markdown

Test this pull request

  • The package can be tested by running
    yarn upgrade "https://sdk-team-cdn.decentraland.org/"

@decentraland-bot decentraland-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.

Review — feat: accept the native fetch directly as the HTTPProvider fetch option

Summary

Clean, well-motivated type-only change. Removes the unused mode?: string field from the exported FetchFunction type so that globalThis.fetch, @dcl/fetch-component, and node-fetch are directly assignable without casts.

Analysis

Type safety: The params object type is in contravariant position (parameter of the callback). Removing an optional field that HTTPProvider never sets makes the callback type strictly wider — more functions satisfy it, none are excluded. This is not a breaking change for any consumer that passes a fetch implementation.

Consumer impact: Searched across the org:

  • decentraland/lamb2 — imports FetchFunction and currently casts with as unknown as FetchFunction, with a comment at src/components.ts:141-143 explaining exactly this type mismatch. After this publishes, lamb2 can drop the cast. ✅
  • decentraland/governance / governance-ui — have unrelated local fetchFunction definitions, not importing from eth-connect. No impact.
  • No consumers found that reference mode in the params object.

Runtime impact: None. The emitted JS is identical — mode was never set by HTTPProvider (it only sets body, method, headers).

Tests: Good approach — compile-time assertions that globalThis.fetch and a @dcl/fetch-component-shaped function are assignable without casts. Existing tests unaffected. CI passes.

Docs & API report: Updated consistently with the type change.

Git conventions (ADR-6): PR title (feat: ...) and branch (feat/fetchfunction-accept-native-fetch) both comply.

Security: No security issues found. Type-only change with no runtime impact.

Verdict

No P0 or P1 findings. LGTM — approve.


Reviewed by Jarvis 🤖 · Requested by Lautaro Petaccio via Slack

@LautaroPetaccio
LautaroPetaccio merged commit ce27c1e into master Jun 24, 2026
3 checks passed
@LautaroPetaccio
LautaroPetaccio deleted the feat/fetchfunction-accept-native-fetch branch June 24, 2026 17:48
LautaroPetaccio added a commit to decentraland/archipelago-workers that referenced this pull request Jun 24, 2026
eth-connect 6.4.0 (decentraland/eth-connect#583) makes FetchFunction accept the
native fetch directly, so the `fetch.fetch as unknown as FetchFunction` cast in
the ws-connector HTTPProvider wiring is no longer needed. Bumped eth-connect in
core and ws-connector, removed the cast and the now-unused FetchFunction import.
Type-only change; no runtime behavior change.
LautaroPetaccio added a commit to decentraland/archipelago-workers that referenced this pull request Jun 24, 2026
)

* chore: migrate from @well-known-components to @dcl core-components

Replace the @well-known-components homonyms across the core, ws-connector
and stats workspaces with the published @dcl/* core-components, and bump
the existing @dcl dependencies to their latest versions.

Component swaps:
- http-server: @well-known-components/http-server -> @dcl/http-server@2 (core, stats)
- metrics:     @well-known-components/metrics     -> @dcl/metrics (core, ws-connector, stats)
- fetch:       @well-known-components/fetch-component -> @dcl/fetch-component (ws-connector, stats)
- test-helpers: @well-known-components/test-helpers -> @dcl/test-helpers (all workspaces)
- bump:        @dcl/uws-http-server -> ^1.0.1 (ws-connector)
- add:         @dcl/core-commons, @types/jest (the new @dcl/test-helpers declares
               @types/jest as a peer dependency instead of bundling it)

Adaptations:
- Move IHttpServerComponent / IFetchComponent to @dcl/core-commons in the
  component type maps so they match the native (global Request/Response) server
  and fetch returned by @dcl/http-server v2 and @dcl/fetch-component. The other
  interface types (IConfigComponent, ILoggerComponent, IBaseComponent,
  IMetricsComponent) stay on @well-known-components/interfaces.
- eth-connect's HTTPProvider and dcl-catalyst-client still type their fetch
  against node-fetch's IFetchComponent; the native fetch is runtime-compatible,
  so cast it at those call sites.
- Fix the createLocalFetchCompoment -> createLocalFetchComponent typo exposed by
  @dcl/test-helpers.

Stays on @well-known-components (no core equivalent): interfaces, logger,
env-config-provider, nats-component, pushable-channel.

* fix: pin semver to v7 so jest coverage reporter resolves semver/functions/gte

* chore: bump dcl-catalyst-client to v22 in stats to drop node-fetch

v22 replaced its cross-fetch/wkc-fetch deps (which pulled node-fetch@2)
with @dcl/fetch-component (native fetch) and accepts the native fetcher
directly, so the as-unknown-as IFetchComponent cast and the node-fetch
comment in stats/src/adapters/content.ts are no longer needed.

* chore: bump eth-connect to 6.3.1 for the HTTPProvider response-body fix

eth-connect 6.3.1 releases the response body on non-2xx HTTPProvider responses
(decentraland/eth-connect#582), which the ws-connector relies on for the on-chain
signature validation it runs on every WS authentication. Bumped in both core and
ws-connector; both resolve to 6.3.1 (the remaining root 6.2.4 is @dcl/crypto's
internal copy). The FetchFunction type is unchanged, so the existing native-fetch
cast stays.

* chore: bump eth-connect to 6.4.0 and drop the native-fetch cast

eth-connect 6.4.0 (decentraland/eth-connect#583) makes FetchFunction accept the
native fetch directly, so the `fetch.fetch as unknown as FetchFunction` cast in
the ws-connector HTTPProvider wiring is no longer needed. Bumped eth-connect in
core and ws-connector, removed the cast and the now-unused FetchFunction import.
Type-only change; no runtime behavior change.
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