Skip to content

Replace SSE with WebSocket (Bun.serve), JWT auth, remove env-based admin#11

Draft
Copilot wants to merge 18 commits intomainfrom
copilot/update-websocket-integration
Draft

Replace SSE with WebSocket (Bun.serve), JWT auth, remove env-based admin#11
Copilot wants to merge 18 commits intomainfrom
copilot/update-websocket-integration

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 1, 2026

Migrate real-time transport from SSE to WebSocket, switch to Bun runtime, replace session-token auth with JWT, and move admin user management fully into the database.

WebSocket via Bun.serve()

  • server.ts — single entry point: Next.js HTTP on :3000, Bun.serve() WebSocket on :3001
  • store.ts notifySubscribers() broadcasts to globalThis.__wsClients shared between Next.js and the WS server in-process
  • Client reconnects with exponential backoff (1s → 30s cap)
  • Deleted SSE endpoint (/api/messages/stream)

JWT authentication

  • src/lib/jwt.ts — HMAC-SHA256 sign/verify with timing-safe comparison
  • auth.ts verifies JWT from cookie directly — no DB session lookup
  • loginUser() returns a signed JWT; getUserBySession()/logoutSession() removed
  • JWT_SECRET required in production, dev fallback provided

Admin stored in DB, not env

  • Removed ADMIN_USERNAME / ADMIN_PASSWORD_HASH_SHA256 env seeding from db.ts
  • First registered user is auto-promoted to admin + approved

Bun runtime

  • Scripts: bun server.ts (dev/start), bun next build
  • Kept better-sqlite3 (bun:sqlite incompatible with Next.js build workers)

CSS transitions removed

  • Stripped all transition-* Tailwind classes and inline style.transition assignments across all components
// server.ts — Bun.serve WebSocket with JWT auth
Bun.serve<WsData>({
  port: WS_PORT,
  fetch(req, server) {
    const cookies = parseCookies(req.headers.get("cookie") || "");
    const payload = verifyJwt(cookies[SESSION_COOKIE]);
    if (!payload || payload.status !== "approved") {
      return new Response("Unauthorized", { status: 401 });
    }
    if (server.upgrade(req, { data: { username: payload.sub } })) {
      return undefined;
    }
    return new Response("WebSocket upgrade failed", { status: 426 });
  },
  websocket: {
    open(ws)  { globalThis.__wsClients.add(ws); },
    close(ws) { globalThis.__wsClients.delete(ws); },
    message() {},
  },
});

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh gh auth status r (http block)
  • https://api.github.com/user
    • Triggering command: /usr/bin/gh gh api user -main/dist/ripgrep/bin/linux-x64/rg (http block)

If you need me to access, download, or install something from one of these locations, you can either:


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 14 commits February 28, 2026 23:58
Co-authored-by: ayobro1 <186326284+ayobro1@users.noreply.github.com>
Fix mobile swipe-back slide-out animation being immediately cancelled
Co-authored-by: ayobro1 <186326284+ayobro1@users.noreply.github.com>
Fix mobile channel exit animation broken by React 19 style reconciliation
Co-authored-by: ayobro1 <186326284+ayobro1@users.noreply.github.com>
Co-authored-by: ayobro1 <186326284+ayobro1@users.noreply.github.com>
Fix mobile exit animation race condition & message text selection on react
Add a 300ms delay before showing the loading spinner in MessageArea.
For fast fetches (the common case), the spinner never appears, eliminating
the brief loading flash. The timer is properly cleaned up in both the
fetch finally block and the useEffect cleanup function.

Co-authored-by: ayobro1 <186326284+ayobro1@users.noreply.github.com>
Defer loading spinner to eliminate flash on chat open
Copilot AI and others added 4 commits March 1, 2026 02:12
- Replace better-sqlite3 with bun:sqlite
- Add JWT sign/verify (src/lib/jwt.ts) for stateless auth
- Update auth.ts to use JWT instead of DB sessions
- Update store.ts: remove getUserBySession/logoutSession, use signJwt,
  first registered user becomes admin, WebSocket pub/sub
- Add server.ts with Next.js HTTP + Bun.serve WebSocket
- Replace SSE EventSource with WebSocket in MessageArea.tsx
- Simplify logout route (cookie-only, no server session)
- Delete SSE stream route
- Remove all CSS transition classes from components
- Update package.json scripts for bun, remove better-sqlite3
- Remove .npmrc, update .gitignore, .env.local.example, tsconfig.json

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: ayobro1 <186326284+ayobro1@users.noreply.github.com>
…type safety

Co-authored-by: ayobro1 <186326284+ayobro1@users.noreply.github.com>
Copilot AI changed the title [WIP] Replace SSE with WebSocket for data streaming Replace SSE with WebSocket (Bun.serve), JWT auth, remove env-based admin Mar 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants