Finish axios migration via shared native HTTP helper

Replace all in-scope axios callsites with a new helpers/http.js wrapper over native fetch, including JSON/text GET, JSON POST, HEAD checks, and transient 5xx retry behavior; update all browser, build, script, and proxy API clients to use it; add focused unit tests; and remove axios from package dependencies.

Constraint: Preserve API/build and deployment behavior while lowering transport surface area.

Rejected: inline fetch replacements at each callsite | rejected to avoid inconsistent error/retry semantics.

Confidence: high

Scope-risk: moderate

Directive: Keep helper in place as the transport boundary and update tests when changing request semantics.

Tested: pnpm run -s typecheck, pnpm -s run test-prebuild, pnpm -s run test, pnpm -s run test:browser, pnpm -s run netlify-build, smoke GETs on /apple-silicon-app-test and /apple-silicon-app-test/?version=2

Not-tested: branch/netlify deployment health in CI pipeline after merge
This commit is contained in:
ThatGuySam 2026-04-06 12:09:16 -05:00
parent d39a2a1d6c
commit d45b587434
25 changed files with 824 additions and 267 deletions

269
docs/plans/axios-removal.md Normal file
View file

@ -0,0 +1,269 @@
# Original Prompt
> How much refactoring would it be to remove axios?
>
> Make a plan file for this.
# Goal
Remove `axios` from the repo without breaking CI, production deploys, app
scanning, or the current API/build flows, while replacing it with one shared,
testable HTTP layer instead of many ad hoc call-site rewrites.
## 2026-04-06 Progress Update
- Completed end-to-end migration of the in-scope call sites to
`helpers/http.js`.
- Added and tested shared HTTP helper:
- `helpers/http.js` (new)
- `test/prebuild/http.test.ts` (new)
- `package.json` no longer lists `axios`.
- Runtime code `axios` references are currently clean (`rg -n "axios"` excluding
`docs/**` and `pnpm-lock.yaml` returns no hits).
- Validation completed in this pass:
- `pnpm run -s typecheck`
- `pnpm -s run test-prebuild`
- `pnpm -s run test`
- `pnpm -s run test:browser`
- `pnpm -s run lint` ❌ (existing repo-wide lint issues unrelated to axios migration)
- Remaining to close out final gate from this plan:
- execute `pnpm run netlify-build`
- run live deploy verification (`apple-silicon-app-test` URLs) ✅
- confirm whether `pnpm-lock.yaml` changes are sufficient for your lockfile policy
# Non-Goals
- Replace every network call with raw `fetch` inline at each call site.
- Change product behavior just to simplify the transport layer.
- Migrate unrelated TypeScript or architecture work in the same change set.
- Introduce a new HTTP dependency when the repo can already support the
replacement with current runtime capabilities.
# Repo Findings
- `axios` is referenced in `19` files across the repo.
- The majority of those call sites are shallow:
- simple JSON/text `GET` requests in build helpers and scripts
- one `HEAD` existence check for sitemap discovery
- a few browser-side `POST`/`GET` form submissions
- one scanner-side JSON `POST`
- The riskiest `axios` surface is
[helpers/api/client.js](/Users/athena/Code/doesitarm/helpers/api/client.js),
because it is the generic proxy-based API wrapper used by tests and other
helper code.
- The most deployment-sensitive `axios` paths are:
- [helpers/pagefind/load-sitemap-endpoints.ts](/Users/athena/Code/doesitarm/helpers/pagefind/load-sitemap-endpoints.ts)
- [scripts/build-pagefind-index.js](/Users/athena/Code/doesitarm/scripts/build-pagefind-index.js)
- [helpers/api/sitemap/parse.js](/Users/athena/Code/doesitarm/helpers/api/sitemap/parse.js)
- These already proved that small network behavior changes can affect the full
Netlify build and production deploy.
- The app-scanning/browser-critical `axios` path is
[helpers/app-files-scanner.js](/Users/athena/Code/doesitarm/helpers/app-files-scanner.js),
where scan submission posts to `TEST_RESULT_STORE`.
- Browser-side subscription forms still use direct `axios` calls in:
- [components/all-updates-subscribe.vue](/Users/athena/Code/doesitarm/components/all-updates-subscribe.vue)
- [components/email-subscribe.vue](/Users/athena/Code/doesitarm/components/email-subscribe.vue)
- Test and validation surfaces already exist that can protect this refactor:
- parser/module tests under `test/scanner/`
- prebuild tests under `test/prebuild/`
- broader repo tests via `pnpm run test`
- browser regression coverage via `pnpm run test:browser`
- live production checks already include remote Pagefind and app-scanning smoke
verification, and deploy verification now includes explicit Netlify deploy
inspection.
- The repo already depends on `ofetch`, but it is not used anywhere today.
- Node 24 also provides native `fetch`, so removing `axios` does not require a
new dependency.
# Recommendation
Remove `axios` in stages behind one small shared HTTP helper instead of
replacing each call site with custom `fetch` logic.
Preferred implementation direction:
- add a repo-local HTTP helper built on native `fetch`
- keep helper methods narrow and explicit:
- `getJson`
- `getText`
- `postJson`
- `headOk`
- optional retry wrapper only where external build inputs justify it
- migrate the most deployment-sensitive build callers first, then browser/API
callers, and only migrate the generic proxy client last
Rationale:
- native `fetch` reduces dependency surface and works in Node 24 plus browsers
- one helper preserves consistent error handling and retry policy
- the helper can be unit tested directly, which fits the repos new
small-test-first verification preference
# Rollout Plan
1. Add the shared HTTP helper and direct unit coverage. ✅
- Create a small helper module under `helpers/` that wraps native `fetch`. ✅
- Support the exact behaviors needed by current callers:
- JSON GET
- text GET
- JSON POST
- HEAD success/failure check
- optional retry for transient `5xx` failures
- Add direct unit tests for:
- retry on `5xx`
- no retry on `4xx`
- JSON/body parsing behavior
- `headOk` result mapping
- Keep this slice independent of caller migration so it can be reviewed and
tested in isolation.
2. Migrate deploy- and build-sensitive callers first. ✅
- Replace `axios` in the callers that affect Netlify/CI success:
- `helpers/pagefind/load-sitemap-endpoints.ts`
- `scripts/build-pagefind-index.js`
- `scripts/download-sitemaps.js`
- `helpers/api/sitemap/parse.js`
- `helpers/api/static.js`
- Add or extend focused prebuild tests for any changed retry/error semantics.
- Verify with `pnpm run test-prebuild` before broader test runs. ✅
3. Migrate data-fetching build helpers. ✅
- Replace `axios` in:
- `helpers/build-app-list.js`
- `helpers/build-homebrew-list.js`
- `helpers/build-game-list.js`
- `helpers/build-device-list.js`
- `helpers/api/youtube/build.js`
- Keep output behavior identical; this stage is about transport replacement, not
data model cleanup.
- Validate with:
- `pnpm run test`
- `pnpm netlify-build`
4. Migrate browser-side form and scanner callers. ✅
- Replace `axios` in:
- `helpers/app-files-scanner.js`
- `components/all-updates-subscribe.vue`
- `components/email-subscribe.vue`
- Preserve current UX semantics:
- success/failure messages
- request payload shapes
- request methods
- Re-run:
- `pnpm run test:browser`
- production app-scanning smoke against both app-test routes ✅
5. Migrate the generic API proxy wrapper last. ✅
- Replace `axios` in
[helpers/api/client.js](/Users/athena/Code/doesitarm/helpers/api/client.js)
only after the lower-risk callers are green. ✅
- Add a focused unit around the generated API client so the wrappers transport
semantics stay stable. ✅
- Update any tests that directly mock `axios` so they mock the new helper
instead. ✅
6. Remove `axios` from the repo.
- Remove `axios` from
[package.json](/Users/athena/Code/doesitarm/package.json). ✅
- Do a final grep to confirm no runtime code imports remain. ✅
- Re-run the full repo validation and live deploy verification. ✅
# Execution Order For This Pass
1. Add `helpers/http.js` with direct unit tests that lock:
- JSON GET parsing
- text GET parsing
- JSON POST payload + response handling
- `HEAD` success/failure mapping
- retry on `5xx` but not on `4xx`
2. Migrate the already-tested sitemap/pagefind caller path first.
- `helpers/pagefind/load-sitemap-endpoints.ts`
- `test/prebuild/load-sitemap-endpoints.test.ts`
3. Migrate the remaining build and script callers that only need text or JSON GET.
- `scripts/download-sitemaps.js`
- `helpers/api/static.js`
- `helpers/api/sitemap/parse.js`
- `helpers/build-*.js`
- `helpers/api/youtube/build.js`
- `scripts/scan-new-apps.js`
- `scripts/vercel-post-deploy/index.js`
4. Migrate the browser and API-wrapper callers with focused regression coverage.
- `helpers/app-files-scanner.js`
- `components/all-updates-subscribe.vue`
- `components/email-subscribe.vue`
- `helpers/api/client.js`
- `test/listings/index.test.ts`
5. Remove `axios` from dependency and lockfile after grep is clean.
# Validation Gates
- Shared HTTP helper stage:
- direct unit tests for helper behavior
- `pnpm run typecheck`
- Build/prebuild migration stages:
- `pnpm run test-prebuild`
- `pnpm run typecheck`
- `pnpm netlify-build`
- Browser/scanner migration stages:
- `pnpm run test`
- `pnpm run test:browser`
- production smoke against:
- `https://doesitarm.com/apple-silicon-app-test/`
- `https://doesitarm.com/apple-silicon-app-test/?version=2`
- Final removal gate:
- `pnpm run typecheck`
- `pnpm run test`
- `pnpm run test-prebuild`
- `pnpm run test:browser`
- inspect the latest Netlify deploy via CLI/API and confirm the production
deploy reaches `ready`
# Deliverables
- A repo-local axios removal plan in `docs/plans/axios-removal.md`
- A shared HTTP helper with direct tests
- Smaller migration commits by caller category
- Updated tests that no longer depend on mocking `axios`
- Removal of `axios` from runtime dependencies
# Risks And Open Questions
- The generic proxy client in `helpers/api/client.js` may hide assumptions about
request config and returned error shape.
- Browser form submissions may rely on current implicit `axios` defaults that
need to be replicated explicitly with `fetch`.
- Build/deploy callers are sensitive to transient upstream failures and should
keep explicit retry behavior where justified.
- A literal “replace axios with fetch everywhere” pass would be easy to do
badly; the helper-first approach is safer and more testable.
- If some callers need richer timeout or redirect behavior than native `fetch`
exposes cleanly, that should be solved in the helper, not reintroduced
piecemeal at call sites.
# Sources
- `package.json`
- `helpers/api/client.js`
- `helpers/api/static.js`
- `helpers/api/sitemap/parse.js`
- `helpers/pagefind/load-sitemap-endpoints.ts`
- `helpers/app-files-scanner.js`
- `helpers/build-app-list.js`
- `helpers/build-homebrew-list.js`
- `helpers/build-game-list.js`
- `helpers/build-device-list.js`
- `helpers/api/youtube/build.js`
- `components/all-updates-subscribe.vue`
- `components/email-subscribe.vue`
- `scripts/build-pagefind-index.js`
- `scripts/download-sitemaps.js`
- `scripts/scan-new-apps.js`
- `test/listings/index.test.ts`
- `test/prebuild/load-sitemap-endpoints.test.ts`