Add the reusable browser shell primitives Phase B views build on: - store.js: observable store (get/set/subscribe) - events.js: job activity adapter — SSE preferred, polling fallback, sharing the event `seq` as cursor so a transport switch drops nothing - api.js: cancellable() (AbortController) + job endpoints; aborted requests reject with code "cancelled" Make the SSE stream generically consumable: emit default `message` events with the type in the JSON payload instead of `event: <type>`, so a browser EventSource receives the open-ended type set (state:*, claimed, …) via onmessage without enumerating it. The `event: done` sentinel and resumable `id:` cursors are unchanged. Tests: frontend/js/tests/ in-browser unit suite (api errors + cancellation, store transitions, routing, SSE→polling fallback) served over the app's static mount and driven by tests/e2e/test_frontend_shell.py, which also asserts asset loading, deep-link + reload restore, JSON-only /api/v1, and a clean console/network. Reuses the installed playwright — no JS toolchain added. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2.7 KiB
2.7 KiB