Files
gods-eye-view/server
Pedro Lobato 44817e1286 fix(realtime): bound the debug-log sink and stop blocking on its writes
Ported onto the split provider layout: the route now lives in
server/providers/openai/debug-log.js and its state belongs to the handler
the factory returns rather than to module scope.

/api/realtime/debug-log is the one route in its family left unhardened.
Both siblings enforce a limiter through openai/rate-limit.js, and this was
the only handler still writing with fs.appendFileSync on the request path.

- Always-on per-IP limiter (120/min, 400 global). Deliberately not the
  opt-in openAiRateLimiter(): that one defaults to unlimited so throttling
  cannot silently change what a user spends, and this sink spends disk and
  event-loop time rather than provider quota.
- Serialized async appends with a 32 MB rotation ceiling and one retained
  generation. REALTIME_DEBUG_LOG_MAX_BYTES caps a single request body; it
  never bounded the file those bodies accumulate into, so any local page
  could grow .gev-logs/realtime-conversations.jsonl for as long as the dev
  server ran. Serializing also closes a read-then-write race on the size
  check, where concurrent callers all stat under the ceiling and none
  rotates.
- Generic 400/500 answers separating a malformed record or oversized body
  from a failed write, instead of echoing error.message — an errno and an
  absolute path for an fs failure.
- readRequestBody marks an oversized body with code 'BODY_TOO_LARGE', the
  marker its sibling readRequestBodyCapped already sets, so the two cases
  are distinguishable without matching on text.

Coverage extends src/tooling/localServices.test.mjs, which already drives
the real handler over a temporary sourceRoot. Both new tests fail on the
previous implementation and pass with this one.

Refs #23. Does not add authentication: these proxies have no auth
mechanism today, so introducing one is a maintainer design decision.
2026-09-14 21:24:12 -05:00
..