Files
meshcore-analyzer/.github
9002b25bce fix(nodes): paginate /api/nodes across map/live/analytics/packets/area-map (500-row cap) (#1637)
## Summary

The server clamps `/api/nodes` `?limit` to **500** (DoS guard, PR #1540
/ v3.8.3) and orders by `last_seen DESC`. Every node-list consumer
issued a single big-`?limit` fetch and trusted it as the full set, so on
>500-node meshes the top-500-by-advert window silently hid the tail.

Because `nodes.last_seen` is updated **only on self-adverts** (never on
relay traffic; `UpsertNode` is called solely from the advert path), a
repeater that relays constantly but last advertised hours ago fell
outside that window and **vanished from the map and live view** — while
still showing "Active" in its detail panel and (since #1606) in the
paginated Nodes list.

#1606 fixed only the Nodes page (`nodes.js`). This generalizes that fix
to the deferred siblings.

## Changes

- **`public/app.js`** — new shared `fetchAllNodes(extraQuery, opts)`:
pages `limit=500` + `offset` until a short page (the server's `total` is
unreliable — clamped to the page size and overwritten with the filtered
length under area/region filters, so we stop on a short page, not on
`total`), dedups by `public_key`, returns the real deduped count as
`total`.
- **`public/map.js`**, **`public/live.js`** (keeps the
`LIVE_MAP_MAX_NODES` ceiling via `safetyCap`), **`public/analytics.js`**
(×2), **`public/packets.js`** now use the helper.
- **`public/area-map.html`** is standalone (cross-origin `baseUrl`, no
`app.js`) so it gets an inline copy of the same loop.
- **`.eslintrc.json`** — declare `fetchAllNodes` global (no-undef).

## Tests

- **`test-fetch-all-nodes-pagination.js`** — unit-tests the helper via
the real `api()`+`fetch` path: pagination past 500, short-page stop vs.
the unreliable server `total`, dedup across a page boundary, counts
pass-through, `safetyCap` bound. 5/5.
- **`test-map-nodes-pagination-e2e.js`** — browser E2E (Playwright)
proving `map.js` surfaces a 501st node reachable only on page 2 and
renders its marker. Verified **red→green**: against the pre-fix single
fetch all 3 assertions fail (500 nodes, page-2 node absent, no marker);
after the fix all pass. Wired into `deploy.yml`.

## Verification

- unit 5/5, E2E 3/3, `test-frontend-helpers.js` 611/611, `npx eslint
public/*.js` → 0 errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 04:24:08 -07:00
..