terraphim / terraphim/terraphim-ai

[Research] WebSocket and Streaming Patterns in Web Components

Open
#227 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

research web-components
Dominant language
Rust
Stars
62
Forks
5
Avg merge
2h 27m
Merged PRs (30d)
1

Description

Research Objective

Investigate WebSocket management and SSE streaming patterns for Chat and Search Web Components.

Current State

  • Chat uses WebSocket for real-time messaging (Chat.svelte)
  • Search uses EventSource (SSE) for summarization updates (Search.svelte)
  • Connection state management in Svelte lifecycle
  • Tauri uses polling fallback (no EventSource support)
  • Automatic reconnection on error

References:

  • Chat WebSocket: desktop/src/lib/Chat/Chat.svelte
  • Search SSE: desktop/src/lib/Search/Search.svelte:102-224

Research Questions

  1. How to manage WebSocket/SSE lifecycle in Web Components?
  2. Connection state management patterns?
  3. Automatic reconnection strategies?
  4. Memory leak prevention?
  5. Multiple component instances sharing connections?
  6. Fallback strategies (polling for Tauri)?

Streaming Patterns to Evaluate

Pattern 1: Component-Owned Connection

Each component manages its own connection.

Pros:

  • Simple, self-contained
  • Component controls lifecycle
  • Easy to reason about

Cons:

  • Multiple connections for same data
  • Resource waste
  • Reconnection complexity

Implementation:

class TerraphimChat extends HTMLElement {
  connectedCallback() {
    this.ws = new WebSocket(this.wsUrl);
    this.ws.onmessage = (e) => this.handleMessage(e);
    this.ws.onerror = () => this.reconnect();
  }
  
  disconnectedCallback() {
    this.ws?.close();
  }
}
Pattern 2: Shared Connection Service

Singleton service manages connections, components subscribe.

Pros:

  • Single connection shared
  • Centralized error handling
  • Efficient resource use

Cons:

  • Need pub/sub system
  • State management complexity
  • Service lifecycle management

Implementation:

// Singleton service
class WebSocketService {
  subscribe(channel, handler) { ... }
  unsubscribe(channel, handler) { ... }
}

// Component uses service
class TerraphimChat extends HTMLElement {
  connectedCallback() {
    this.handler = (msg) => this.handleMessage(msg);
    wsService.subscribe('chat', this.handler);
  }
  
  disconnectedCallback() {
    wsService.unsubscribe('chat', this.handler);
  }
}
Pattern 3: Custom Element with Connection Attribute

Parent manages connection, children receive via attribute/property.

Pros:

  • Flexible composition
  • Parent controls connection
  • Children remain simple

Cons:

  • Tight coupling
  • Complex prop passing

Implementation:

<terraphim-connection url="ws://...">
  <terraphim-chat></terraphim-chat>
  <terraphim-notifications></terraphim-notifications>
</terraphim-connection>

Lifecycle Management

Connection States
  1. Disconnected - Initial state
  2. Connecting - Establishing connection
  3. Connected - Active connection
  4. Reconnecting - Attempting to reconnect
  5. Failed - Permanent failure
State Machine
Disconnected -> Connecting -> Connected
                     ↓             ↓
                  Failed      Reconnecting
                                   ↓
                              Connected
Reconnection Strategy
  • Exponential backoff: 1s, 2s, 4s, 8s, 16s, max 30s
  • Max retries: Configurable (default: infinite)
  • Jitter: Random delay to prevent thundering herd
  • Health check: Ping/pong to detect stale connections

Memory Leak Prevention

Common Pitfalls:
  1. Not closing connections on component removal
  2. Event listener leaks - not removing listeners
  3. Circular references - component refs in closures
  4. Pending reconnect timers - not clearing timeouts
Solutions:
class TerraphimChat extends HTMLElement {
  disconnectedCallback() {
    // Close connection
    this.ws?.close();
    
    // Clear timers
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
    }
    
    // Remove listeners
    this.ws = null;
  }
}

Tauri Fallback Strategy

Problem:

Tauri doesn't support EventSource (SSE), needs polling fallback.

Solution:

Detect environment and use appropriate strategy.

class TerraphimSearch extends HTMLElement {
  startStreaming() {
    if (this.isTauri) {
      this.startPolling();
    } else {
      this.startSSE();
    }
  }
  
  startPolling() {
    this.pollInterval = setInterval(
      () => this.fetchUpdate(),
      2000
    );
  }
  
  startSSE() {
    this.eventSource = new EventSource(this.url);
    this.eventSource.onmessage = (e) => this.handleUpdate(e);
  }
}

Features to Maintain

Chat WebSocket:
  • Real-time message delivery
  • Connection state indicators
  • Automatic reconnection
  • Message queuing during disconnect
  • Error handling
Search SSE:
  • Real-time summarization updates
  • Fallback to polling (Tauri)
  • Connection health monitoring
  • Graceful degradation
New Requirements:
  • Memory leak prevention
  • Multiple component instances
  • Configurable reconnection
  • Connection sharing (optional)
  • Observable state

Technical Challenges

Challenge 1: Reconnection UX

Problem: How to indicate reconnecting state to user?
Solution:

  • Emit custom events for state changes
  • Parent can show notification/banner
  • Component-level indicators
Challenge 2: Message Ordering

Problem: Messages may arrive out of order during reconnect
Solution:

  • Sequence numbers
  • Message buffering
  • Conflict resolution
Challenge 3: Shared State

Problem: Multiple components need same stream data
Solution:

  • Pub/sub pattern
  • State management integration
  • Observable streams
Challenge 4: Testing

Problem: Hard to test WebSocket/SSE behavior
Solution:

  • Mock WebSocket/EventSource
  • Dependency injection
  • Simulate network conditions

Acceptance Criteria

  • Connection management pattern selected
  • Lifecycle hooks documented
  • Reconnection strategy implemented
  • Memory leak prevention verified
  • Tauri polling fallback tested
  • State machine documented
  • Error handling comprehensive
  • Prototype with WebSocket + SSE

References

Documentation

Findings will be documented in: .docs/research-websocket-patterns.md

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read desktop/src/lib/Chat/Chat.svelte and desktop/src/lib/Search/Search.svelte:102-224, then compare the existing WebSocket, SSE, lifecycle, and Tauri polling behavior. Document the selected connection pattern, state and reconnection strategy, leak-prevention guidance, and WebSocket/SSE prototype findings in .docs/research-websocket-patterns.md.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, tauri
Domain
desktop, documentation, frontend
Issue type
Documentation
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.