mx-space / mx-space/core

refactor(http): migrate axios → ofetch in apps/core

Open
#2,760 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
558
Forks
156
Avg merge
10h 57m
Merged PRs (30d)
5

Description

Motivation

The v13.11.6 → v13.11.7 hotfix cycle exposed how thin the project's axios usage is. The sandbox shipped a fake axios that was just a fetch wrapper silently dropping the params config — moving the built-ins to native fetch was a strict simplification, and the same logic applies to the wider apps/core codebase: we have one HttpService Nest wrapper plus eight call sites, all using a small slice of axios.

ofetch (unjs/ofetch) is the natural replacement: native fetch semantics, built-in retry, responseType parsing, FetchError with error.status / error.data, undici Agent for the dev self-signed cert escape hatch.

Scope

  • In: apps/core/src/**
  • Out: packages/api-client/adaptors/axios.ts and its tests — that adapter is a public api-client opt-in for downstream consumers, not internal use.

Surface decision

Keep the HttpService NestJS provider as the seam, swap its internals.

  • Rename axiosReffetch returning an ofetch $Fetch instance.
  • Eight call sites change from httpService.axiosRef.get(url, opts) to httpService.fetch(url, opts) (or .fetch(url, { method: 'POST', body })).
  • Test mocks stay shape-compatible: { fetch: vi.fn() } replaces { axiosRef: { get } }.
  • Drop extend() and getAndCacheRequest() — no callers in the tree.
  • Drop the bindDebugVerboseInterceptor path — __debugLogger is never set anywhere, dead code.

Files affected

Production code (apps/core/src):

  • processors/helper/helper.http.service.ts — rewrite as ofetch wrapper
  • app.config.ts + app.config.test.tsAXIOS_CONFIG becomes the ofetch defaults (timeout; dev TLS via undici Agent)
  • processors/helper/helper.bark.service.ts:40 — POST JSON
  • processors/helper/helper.image.service.ts:119 — GET arrayBuffer
  • modules/webhook/webhook.service.ts:187 — POST JSON
  • modules/cron-task/cron-business.service.ts:118,155 — POST JSON
  • modules/update/update-download.service.ts:85,189 — GET (retry path) + GET (download with progress)
  • modules/comment/comment-country.service.ts:85 — GET JSON
  • modules/link/link-avatar.service.ts:107 — GET arrayBuffer, no-redirect

Tests:

  • test/src/modules/update/update.service.spec.ts:143,168,203 — replace axiosRef.get mocks
  • test/src/modules/comment/comment-country.spec.ts:31,139 — replace axiosRef.get mocks

package.json:

  • Remove axios, axios-retry
  • Add ofetch

Behaviour-preserving notes

  • Retry: axios-retry with exponentialDelay + 5 retries → ofetch retry: 5 with retryDelay: (ctx) => 1000 * 2 ** attempt (capped at 10s). Keep the warn log on retry.
  • Dev self-signed TLS: replace https.Agent({ rejectUnauthorized: false }) with new Agent({ connect: { rejectUnauthorized: false } }) from undici, passed as dispatcher.
  • Download progress (update-download.service.ts): preserve the admin progress UX by reading responseType: 'stream' (ReadableStream<Uint8Array>), tracking accumulated bytes vs Content-Length, and calling the existing pushProgress callback. ~30 LOC.
  • GitHub 403 detection (update-download.service.ts:98): axios.isAxiosError(e) && e.response?.status === 403e instanceof FetchError && e.status === 403.
  • No-redirect (link-avatar.service.ts): maxRedirects: 0redirect: 'manual' (native fetch option).
  • Default UA header (MX-Space/${PKG.version}) and 10s timeout: set in the shared ofetch.create({...}) defaults.

Out of scope

  • The sandbox runtime — already migrated off the fake axios stub in v13.11.7.
  • The api-client/adaptors/axios.ts public adapter — stays.
  • Any behaviour change beyond what is strictly necessary to swap the HTTP client.

Risk

Single-version refactor on master. Touches the egress path used by: friend-link avatar internalisation, webhook delivery, cron-driven HTTP probes, image proxy, IP geolocation, update download, Bark push. Worth landing as its own minor (v13.12.0) with manual smoke of at least: a webhook fire, an update check, and a friend-link avatar fetch.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with apps/core/src/processors/helper/helper.http.service.ts and app.config.ts, then trace the eight listed HTTP call sites and their tests. Run the update, comment-country, and app-config tests first; done means the internal calls and mocks use the new fetch seam, retry/TLS/progress behavior remains covered, and the listed package dependencies are updated.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.