You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Introduces src/server/utils/apiResponse.ts with ok<T>(res, data?) and
fail(res, status, code, message, extra?) matching the ApiService wire
contract. Converts ignoredNodeRoutes (errors → fail(); bare-array success
left unchanged) and dataExchangeRoutes (import success → ok(res); three
bare errors → fail() with STATS_FAILED/EXPORT_FAILED/IMPORT_FAILED codes).
Deletes the now-unused local ApiErrorResponse interface. Test expectations
updated to assert the full {success, error, code} envelope. CLAUDE.md
documents the helper and the "does-not-unwrap-data" gotcha. REMEDIATION_EPIC.md
marks 1.3 and 1.4 done with phase-log entries.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AphLfgUJWaFNAgU5UXdJ4n
Copy file name to clipboardExpand all lines: CLAUDE.md
+16Lines changed: 16 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,6 +34,22 @@
34
34
-**Never push directly to main. Always use a branch.**
35
35
- After bulk find-and-replace or sed, verify modified functions have correct `async`/`await` signatures. Route handlers and callbacks need `async` if `await` was added inside.
36
36
37
+
### Response envelope
38
+
API handlers use a shared envelope helper — `src/server/utils/apiResponse.ts`:
39
+
- Success: `ok(res, data)` → `{ success: true, data }` (omit `data` for `{ success: true }`).
**New or modified handlers must use these.**`code` is a SCREAMING_SNAKE machine
43
+
code; reuse an existing one where it fits.
44
+
45
+
**Gotcha:** the frontend `ApiService.request()` returns the raw JSON body and
46
+
does **not** unwrap `data`. So `ok(res, x)` is only correct for handlers that
47
+
already return `{ success: true, data }` — converting a bare-payload handler
48
+
(`res.json(array)`) breaks its consumer. `fail()` is always safe: `ApiService`
49
+
reads only `error`/`code`/`retryAfterSeconds` and ignores `success` on errors.
50
+
Existing bare-`{error}` handlers convert opportunistically as they're touched
51
+
(Phases 2/4); this is not a mass conversion.
52
+
37
53
## Multi-Source Architecture (4.x)
38
54
39
55
MeshMonitor 4.x supports **N concurrent Meshtastic node connections** ("sources"). Pre-4.0 code that referenced a singleton `meshtasticManager` is now a `@deprecated` JSDoc-tagged compatibility shim at the bottom of `src/server/meshtasticManager.ts` — IDEs will strikethrough usages but `tsc` does not error.
Copy file name to clipboardExpand all lines: docs/internal/dev-notes/REMEDIATION_EPIC.md
+4-2Lines changed: 4 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -22,8 +22,8 @@ Each unchecked phase = one worktree → architect spec → implementation → re
22
22
-[x]**0.5** — `@typescript-eslint/no-floating-promises` as `error` for non-test code; violations fixed or explicitly `void`/`.catch()`ed.
23
23
-[x]**1.1** — `withSourceScope` fails closed: omitting `sourceId` throws; explicit `ALL_SOURCES` sentinel for the documented global-by-design consumers (channel decryption, estimated positions, automations); full call-site audit.
24
24
-[x]**1.2** — Type-check the tests: `tsconfig.tests.json` (full strict — see phase log deviation), wired into CI non-blocking first; flip to blocking once clean.
25
-
-[]**1.3** — Integration-grade route-test harness: in-memory SQLite + real Express app with real `requirePermission`/session/auth wiring; 3–5 representative route test files converted (source-scoped permission coverage); no mass conversion.
26
-
-[]**1.4** — Lint ratchets: `no-explicit-any` → `error` with checked-in baseline; forbid raw `fetch(` in `src/components/**`/`src/pages/**` (baselined); `react-hooks/exhaustive-deps` + `prefer-const` → `error`.
25
+
-[x]**1.3** — Integration-grade route-test harness: in-memory SQLite + real Express app with real `requirePermission`/session/auth wiring; 3–5 representative route test files converted (source-scoped permission coverage); no mass conversion.
26
+
-[x]**1.4** — Lint ratchets: `no-explicit-any` → `error` with checked-in baseline; forbid raw `fetch(` in `src/components/**`/`src/pages/**` (baselined); `react-hooks/exhaustive-deps` + `prefer-const` → `error`.
27
27
-[ ]**1.5** — Response-envelope convention: `ok(res, data)` / `fail(res, status, code, msg)` helper for the `{ success, error, code }` envelope; documented in CLAUDE.md; new/modified handlers must use it.
28
28
-[ ]**1.6** — Schema-drift tripwire: CI test diffing `createTables()` schema vs full migration replay (001→latest), normalized `sqlite_master`, fail on divergence.
29
29
@@ -46,3 +46,5 @@ Record per-phase: PR link, deviations from plan, follow-ups.
46
46
-**1.1** — PR #3976 merged (ALL_SOURCES unique-symbol sentinel; runtime throw + Tier-2 required params; 3 real leaks fixed: server.ts getNodeCount refresh, deleteNode→deleteNeighborInfoInvolvingNode, meshtasticManager pending-DM fetch). Review-loop correction: implementer's repo-body `?? ALL_SOURCES` normalization (silent fail-open) reverted; explicit per-call-site decisions instead. CI: Quick Tests outgrew its 15-min cap (#3385 redux) → raised to 25 min in this PR.
47
47
**Follow-up findings (1.1 architect §10, epic backlog):** hand-rolled fail-open `if (sourceId)` filters bypass the helper — all of `meshcore.ts`, `notifications.ts` subscriptions, parts of `channels.ts`, `nodes.ts:getAllNodesSqlite`; legacy `*Sync`/`*Sqlite` twins partially covered (Phase 3.4 deletes them); facade `getNode(nodeNum)` single-source-assumption chain (revisit with Phase 2).
48
48
-**1.2** — PR TBD (tsconfig.tests.json + `typecheck:tests` script + non-blocking CI steps in ci.yml/pr-tests.yml). Deviations: (a) kept FULL strict incl. noImplicitAny — plan's "noImplicitAny off" injects ~50 false-positive errors into prod src via evolving-any inference; (b) top-level `tests/` dir NOT included — its files pull @types/node into the program and poison frontend inference (~60 spurious errors). Baseline: 283 errors, all in src test files, 0 prod. Flip-to-blocking when count reaches 0 (burndown is a follow-up; top ~8 files hold ~150 errors).
49
+
-**1.3** — PR #3986 merged (createRouteTestApp() real-middleware harness + 4 conversions). Ride-alongs: real prod bug fixed (v1/messages GET 500'd without sourceId under fail-closed — missing ?? ALL_SOURCES) + harness anonymous-user race fix. 3 CodeQL alerts on the test fixture left open for human triage (recommend dismiss as used-in-tests).
50
+
-**1.4** — PR #3989 merged (count-based lint ratchet, eslint-baseline.json 410 files/2,515 violations; no-explicit-any/exhaustive-deps/prefer-const → error; raw-fetch ban in components/pages; CI lint now BLOCKING — closes the 0.5 deviation). Census correction: 727 pre-existing errors (468 config false-positives fixed at config level, not baselined).
0 commit comments