CORTEX
All projects

SSE-Observatory

PROTOTYPE

A browser-based debugger for Server-Sent Events: query language, replay, and multi-tab stream sharing.

Personal project · Feb–Mar 2026

THE PROBLEM

Debugging an SSE stream usually means curl and scrolling logs. There is no easy way to filter, correlate or replay a live stream.

HOW IT WORKS

  • A SharedWorker multiplexes one SSE connection across browser tabs, with reconnect backoff.
  • User-written interceptors run in a sandboxed worker pool with a 100 ms timeout and are terminated if they hang.
  • Events are filtered with a recursive-descent query language (AND, OR, parentheses) compiled to closures. A canvas timeline and time-travel playback (seek, step, return to live) support replay.
  • An Express proxy handles CORS and auth headers, with an SSRF guard, rate limiting and short-lived one-time tickets.

THE PIPELINE

  1. Express proxyCORS and auth headers, SSRF guard, rate limiting, one-time tickets.
  2. SharedWorkerOne SSE connection multiplexed across tabs, with reconnect backoff.
  3. Interceptor workersSandboxed pool with a 100 ms timeout; hung workers are terminated.
  4. Query languageRecursive descent, compiled to closures (AND, OR, parentheses).
  5. Timeline and replayCanvas timeline with seek, step and return to live.
One upstream connection is shared by every tab; user code only ever runs in a worker that can be killed.

SCREENSHOTS

Captured from the project's own repository. Select an image to open it full size.

ENGINEERING EVIDENCE

  • One shared SSE connection per stream across tabs, with reconnect backoff. sharedSSEWorker.ts ↗
  • Interceptors are isolated in workers and killed on timeout. interceptorSandbox.ts ↗
  • Recursive-descent parser that compiles queries into predicate functions. queryParser.ts ↗
  • Server-side SSRF guard (private-IP and hostname checks) and rate limiting in the proxy. server.js ↗
  • About 103 unit tests plus 18 Playwright end-to-end tests, including reconnect-storm, memory-pressure and worker-death scenarios.

WHAT ISN'T DONE

  • Events are held in a capped array (1,000) rather than a true ring buffer.
  • Interceptor workers are killed on timeout, but they are not isolated from the network.
  • No CI workflow yet.

NEXT STEPS

Each one comes from a gap listed above. It says what fixing the gap would take; it is not a promise.

  • Replace the capped array with a real ring buffer.
  • Isolate interceptor workers from the network, not only kill them on timeout.
  • Add a CI workflow.

STACK

  • TypeScript
  • React
  • Vite
  • Web Workers
  • SharedWorker
  • IndexedDB
  • Express
  • Vitest
  • Playwright