Skip to content

Conversation

@Lokimorty
Copy link
Contributor

Summary

Implements push-based real-time updates for the Sessions page using Server-Sent Events. New sessions now appear instantly without manual reload or polling - updates only happen when actual session creation events occur.

Changes

  • Added SSE event emitter and stream endpoint for session notifications
  • Modified tracking endpoint to emit events when sessions are created
  • Created useSessionStream hook to connect clients to the SSE stream
  • Fixed LoadingPanel to prevent UI flicker during background refetches

Notes

This uses in-memory pub/sub, suitable for single-server deployments. Multi-server setups would need Redis pub/sub.

Implements push-based real-time updates for the Sessions page. New sessions now appear instantly without manual reload or polling.

Changes:
- Add SSE event emitter for session creation notifications
- Create SSE stream endpoint at /api/websites/[id]/sessions/stream
- Emit session events in tracking endpoint when sessions are created
- Add useSessionStream hook to connect to SSE and invalidate queries
- Fix LoadingPanel to prevent flicker during background refetches
@vercel
Copy link

vercel bot commented Dec 10, 2025

@Lokimorty is attempting to deploy a commit to the umami-software Team on Vercel.

A member of the Team first needs to authorize it.

@Lokimorty Lokimorty changed the title Add real-time session updates via Server-Sent Events feat(sessions): add real-time session updates via server-sent events Dec 10, 2025
Improvements:
- Add Redis pub/sub support for multi-server deployments
- Add authentication check to SSE stream endpoint
- Add 30s heartbeat keepalive for long-lived connections
- Implement exponential backoff reconnection logic in client
- Fix TypeScript types (websiteId optional, timer types)
- Use specific query key invalidation instead of broad match
- Fix undefined access in session-events listener map
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Dec 10, 2025

Greptile Overview

Greptile Summary

Implemented real-time session updates using Server-Sent Events with in-memory pub/sub pattern. When new sessions are created via /api/send, events are emitted and pushed to connected clients through SSE streams, triggering automatic UI updates.

  • Added in-memory event emitter (session-events.ts) for pub/sub pattern
  • Created SSE endpoint at /api/websites/{websiteId}/sessions/stream
  • Modified tracking endpoint to emit session creation events
  • Created useSessionStream hook to connect React components to SSE
  • Fixed LoadingPanel to prevent UI flicker during background refetches

Critical Issue: SSE endpoint missing authentication - any unauthenticated user can access session data streams
Memory Leak: Empty listener sets never removed from in-memory map

Confidence Score: 1/5

  • This PR has a critical security vulnerability - the SSE endpoint allows unauthorized access to session data
  • Score reflects the missing authentication on the SSE endpoint (line 3-7 in route.ts), which is a critical security flaw. All other similar endpoints in the codebase use parseRequest and canViewWebsite checks. Additionally, there's a memory leak in the event emitter and missing error handling.
  • Pay critical attention to src/app/api/websites/[websiteId]/sessions/stream/route.ts - must add authentication before merge

Important Files Changed

File Analysis

Filename Score Overview
src/app/api/websites/[websiteId]/sessions/stream/route.ts 0/5 new SSE endpoint missing authentication/authorization - critical security vulnerability
src/lib/session-events.ts 2/5 in-memory pub/sub with memory leak - empty listener sets never cleaned up
src/components/hooks/useSessionStream.ts 3/5 SSE client hook without error handling or reconnection logic

Sequence Diagram

sequenceDiagram
    participant Client as Browser Client
    participant UI as SessionsDataTable
    participant Hook as useSessionStream
    participant SSE as /sessions/stream
    participant Events as session-events.ts
    participant Track as /api/send
    participant DB as Database

    Client->>UI: Navigate to sessions page
    UI->>Hook: Initialize useSessionStream(websiteId)
    Hook->>SSE: GET /api/websites/{websiteId}/sessions/stream
    SSE->>Events: subscribeToSessions(websiteId, callback)
    Events-->>SSE: return unsubscribe function
    SSE-->>Hook: SSE connection established
    
    Note over Client,Track: User visits tracked website
    Client->>Track: POST /api/send (tracking event)
    Track->>DB: createSession(sessionData)
    DB-->>Track: session created
    Track->>Events: emitSessionCreated(websiteId, sessionId)
    Events->>SSE: invoke listener callback
    SSE->>Hook: SSE message with sessionId
    Hook->>UI: queryClient.invalidateQueries(['sessions'])
    UI->>DB: refetch sessions data
    DB-->>UI: updated sessions list
    UI->>Client: display new session
    
    Client->>UI: Navigate away
    Hook->>SSE: EventSource.close()
    SSE->>Events: unsubscribe()
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (3)

  1. src/app/api/websites/[websiteId]/sessions/stream/route.ts, line 3-7 (link)

    logic: missing authentication and authorization - endpoint allows anyone to stream session updates without verifying they have permission to view this website

  2. src/lib/session-events.ts, line 11-13 (link)

    logic: empty listener sets are never cleaned up from memory

  3. src/components/hooks/useSessionStream.ts, line 10-14 (link)

    style: missing error handling - connection failures, network issues, or server errors will silently fail without retry or notification

7 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@Lokimorty
Copy link
Contributor Author

Lokimorty commented Dec 10, 2025

Authentication: Added the missing parseRequest() and canViewWebsite() checks to the SSE endpoint. Now it properly validates permissions before streaming any session data (see stream/route.ts:12-22)

Memory leak: Fixed the listener cleanup logic. Empty sets are now removed from the map when the last listener unsubscribes (session-events.ts:18-20)

Error handling: Added try/catch blocks around JSON parsing with proper error logging (useSessionStream.ts:30-33)

Reconnection: Implemented exponential backoff that starts at 1s and caps at 30s (useSessionStream.ts:41-47)

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.

1 participant