From 910ea23cf1a74169bb1142efd6d62266f4ded178 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Wed, 11 Mar 2026 01:22:05 -0600 Subject: [PATCH] docs: add HANDOFF.md for Node.js cache-only migration Detailed instructions for the next step: making the Node.js server read only from Go-generated _cache/ files, removing all upstream API fetching from the Node.js code path. --- HANDOFF.md | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 HANDOFF.md diff --git a/HANDOFF.md b/HANDOFF.md new file mode 100644 index 0000000..81c71ab --- /dev/null +++ b/HANDOFF.md @@ -0,0 +1,144 @@ +# Handoff: Node.js Server → Cache-Only Mode + +## Context + +The Go `webicached` daemon now generates the legacy `_cache/YYYY-MM/{pkg}.json` +files that the Node.js server reads. The next step is to make the Node.js server +read **only** from these cache files and never fetch from upstream APIs itself. + +This decouples the two: Go handles all upstream fetching and classification, +Node.js just serves what's in the cache. + +## Current Node.js Data Flow + +``` +Request → builds.js → builds-cacher.js + ├── Read _cache/YYYY-MM/{pkg}.json + ├── If missing: require({pkg}/releases.js).latest() + │ → fetch from GitHub/etc → write cache → return + ├── transformAndUpdate() — classify, sort, organize + └── Background: if stale (>15min), re-fetch +``` + +Key files: +- `_webi/builds.js` — entry point, creates BuildsCacher, starts background refresh +- `_webi/builds-cacher.js` — the big one: cache read, fetch, classify, resolve +- `_webi/serve-installer.js` — HTTP handler, calls `Builds.getPackage()` +- `_webi/transform-releases.js` — legacy release API endpoint +- `{pkg}/releases.js` — per-package fetcher (GitHub, git-tag, etc.) + +## What Needs to Change + +### 1. `_webi/builds.js` — Remove upstream fetching + +Current (`builds.js:14-18`): +```js +let bc = BuildsCacher.create({ caches: CACHE_DIR, installers: INSTALLERS_DIR }); +bc.freshenRandomPackage(600 * 1000); // ← DELETE: background refresh timer +``` + +`Builds.init()` (line 20-35) fetches ALL packages on startup via `bc.getPackages()`. +This triggers `getLatestBuilds()` for any missing cache. Change it to only load +from existing cache files — if a package has no cache file, skip it (don't fetch). + +### 2. `_webi/builds-cacher.js` — Cache-only reads + +**`getPackages()` (line 320-413):** +Currently falls through to `getLatestBuilds()` when cache file is missing (line +380-382). Remove that fallback — if no cache file exists, return empty/error. + +Also remove the background stale check (lines 392-410) that re-fetches when +data is older than 15 minutes. + +**`getLatestBuilds()` (line 130-178):** +This function `require()`s `{pkg}/releases.js` and calls `.latest()` to fetch +from upstream. It should be dead code after the changes above. Can be removed +or stubbed. + +**`freshenRandomPackage()` (line 418-448):** +The background timer that picks a random package and re-fetches it. Remove entirely. + +### 3. Cache file format + +The Go cache writes the same JSON format the Node code expects: + +```json +{ + "releases": [ + { + "name": "bat-v0.26.1-x86_64-unknown-linux-musl.tar.gz", + "version": "0.26.1", + "lts": false, + "channel": "stable", + "date": "2025-01-01", + "os": "linux", + "arch": "x86_64", + "libc": "musl", + "ext": ".tar.gz", + "download": "https://github.com/..." + } + ] +} +``` + +Timestamp file: `_cache/YYYY-MM/{pkg}.updated.txt` — float seconds since epoch. + +### 4. What should NOT change + +- `transformAndUpdate()` — still needed to classify, sort, and organize by triplet +- `selectPackage()` — still needed for format preference +- `findMatchingPackages()` — still needed for version/triplet resolution +- `enumerateLatestVersions()` — still needed +- `_enumerateTriplets()` — still needed for arch fallback +- All the serve/render code (`serve-installer.js`, `transform-releases.js`, etc.) + +### 5. `{pkg}/releases.js` files + +These become dead code once the Node server stops fetching. Don't delete them +yet — they're still useful as documentation of where each package's releases +come from. But they should no longer be `require()`d at runtime. + +## Go Cache State + +The Go `webicached` generates cache for 101 packages (all non-alias packages). +Aliases are handled via symlinks in the cache directory (e.g., `ripgrep.json` → +`rg.json`). + +To regenerate the cache from existing raw data (no API calls): +```sh +cd .claude/worktrees/ref-webi-go +./webicached -once -no-fetch +``` + +To fetch fresh + regenerate: +```sh +./webicached -once +``` + +The raw upstream data lives in `_cache/raw/{pkg}/a/` — one JSON file per release +tag. This is the canonical source of truth. + +## Testing + +After changes, verify the Node server still works: +1. Start the server (however it's normally started) +2. `curl -sS localhost:PORT/api/releases/bat.json | jq '.releases | length'` +3. `curl -sS localhost:PORT/api/releases/bat.tab | head -5` +4. `curl -A 'curl/8.0' localhost:PORT/bat@stable` — should return bash script + +## Files Summary + +| File | Action | +|------|--------| +| `_webi/builds.js` | Remove background refresh, make init() cache-only | +| `_webi/builds-cacher.js` | Remove `getLatestBuilds()` fallback and stale re-fetch | +| `{pkg}/releases.js` | Dead code — don't require() at runtime | +| `_webi/serve-installer.js` | No changes needed | +| `_webi/transform-releases.js` | No changes needed | + +## Branch Info + +- Go rewrite work: branch `ref-webi-go`, worktree at + `.claude/worktrees/ref-webi-go` +- Node.js changes: should happen on `main` branch in the main repo + (`/Users/aj/Projects/webi-installers`)