dashboard: SharedWorker for SSE multiplexing (closes #448)
mara on #448: "firefox disconnects bc of too many tabs. needs bg service worker". picked SharedWorker over full Service Worker: smaller change, addresses the actual problem (shared connection across tabs), no offline-cache scope creep. architecture per-tab `new EventSource('/dashboard/stream')` replaced with a SharedWorker-backed facade. one SharedWorker instance per origin holds ONE upstream EventSource and fans every server-sent event out to every connected tab via MessagePort. N hyperhive tabs now share ONE backend connection, immune to Firefox's per-tab SSE throttling under many-open-tabs pressure. wire protocol (port.postMessage): tab → worker { kind: 'subscribe', url: '/dashboard/stream' } { kind: 'unsubscribe', url: '/dashboard/stream' } worker → tab { kind: 'open', url } { kind: 'message', url, data: '<raw SSE data>' } { kind: 'error', url } subscription tracking is per (port, url). a late subscriber that joins after the upstream is already OPEN gets a synthetic 'open' event so its onStreamOpen handler still runs (triggers the snapshot re-sync that recovers events lost during the join gap). unsubscribing the last port for a URL closes the upstream EventSource so we don't leak idle streams. files - frontend/packages/dashboard/src/stream-worker.js: new — the worker. multi-URL multiplexing via Map<url, {es, ports}>. - frontend/packages/dashboard/src/common.js: new exported helper openStream(url) — returns an EventSource-shaped facade backed by the SharedWorker. graceful fallback to direct EventSource when SharedWorker is unavailable. - frontend/packages/dashboard/src/app.js: replaces the inline new EventSource('/dashboard/stream') with openStream. - frontend/packages/dashboard/src/flow.js: passes streamFactory: openStream to termCreate so the broker terminal's SSE goes through the worker too. - frontend/packages/shared/src/terminal.js: accepts an optional streamFactory(url) option. default unchanged — non-dashboard consumers (per-agent UI) keep using direct EventSource. - frontend/packages/dashboard/build.mjs: new esbuild entry for stream-worker.js → dist/static/stream-worker.js (separate bundle because SharedWorker scripts run in a different global scope and can't be inlined into app.js). scope kept tight - per-agent UI's /events/stream stays on direct EventSource. the agent UI's tab count per agent is typically 1; SharedWorker helps when you have N tabs hitting the SAME stream and the per-agent stream URLs differ. if mara wants the agent UI to share its workers too it's a separate small PR. - no offline-cache, no push notifications — those need full Service Worker; explicit non-goal here per the design Q. validation - npm run build --workspace=@hive/dashboard clean. - stream-worker.js bundle: 1.8 kb. - app.js: 154 kb → 158 kb. flow.js: 29.9 kb → 32 kb. - browser smoke test isn't possible from inside iris's container; the EventSource-shaped facade preserves the exact onmessage / onopen / onerror surface the existing IIFE consumers use.
This commit is contained in:
parent
8dc3432570
commit
4504f9ede3
6 changed files with 246 additions and 3 deletions
|
|
@ -16,6 +16,7 @@ import {
|
|||
$, el,
|
||||
Panel, NOTIF,
|
||||
appendLinkified,
|
||||
openStream,
|
||||
} from './common.js';
|
||||
|
||||
(() => {
|
||||
|
|
@ -185,6 +186,10 @@ import {
|
|||
pillAnchor: flowMain,
|
||||
historyUrl: '/dashboard/history',
|
||||
streamUrl: '/dashboard/stream',
|
||||
// #448: route through the SharedWorker so this page's SSE shares
|
||||
// a single backend connection with /index.html (and any other
|
||||
// open hyperhive tab).
|
||||
streamFactory: openStream,
|
||||
renderers: {
|
||||
sent: (ev, api) => renderMsg(ev, api, '→'),
|
||||
delivered: (ev, api) => renderMsg(ev, api, '✓'),
|
||||
|
|
|
|||
Loading…
Reference in a new issue