mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-10 15:36:53 +02:00
Core Infrastructure: - Add ReqRelayState and ReqOverallState types for granular state tracking - Implement deriveOverallState() state machine with 8 query states - Create useReqTimelineEnhanced hook combining RelayStateManager + event tracking - Add comprehensive unit tests (27 tests, all passing) State Machine Logic: - DISCOVERING: NIP-65 relay selection in progress - CONNECTING: Waiting for first relay connection - LOADING: Initial events loading - LIVE: Streaming with active relays (only when actually connected!) - PARTIAL: Some relays ok, some failed/disconnected - OFFLINE: All relays disconnected after being live - CLOSED: Query completed, all relays closed - FAILED: All relays failed to connect UI Updates: - Single-word status indicators with detailed tooltips - Condensed relay status into NIP-65 section (no duplicate lists) - Per-relay subscription state badges (RECEIVING, EOSE, ERROR, OFFLINE) - Event counts per relay - Connection + Auth status integrated into single dropdown Fixes Critical Bug: - Solves "LIVE with 0 relays" issue (Scenario 5 from analysis) - Distinguishes real EOSE from relay disconnections - Accurate status for all 7 edge cases documented in analysis Technical Approach: - Hybrid: RelayStateManager for connections + event._relay for tracking - Works around applesauce-relay catchError bug without forking - No duplicate subscriptions - Production-quality error handling Tests: 27/27 passing including edge case scenarios
92 lines
2.3 KiB
TypeScript
92 lines
2.3 KiB
TypeScript
/**
|
|
* Types for REQ subscription state tracking
|
|
*
|
|
* Provides per-relay and overall state for REQ subscriptions to enable
|
|
* accurate status indicators that distinguish between EOSE, disconnection,
|
|
* timeout, and error states.
|
|
*/
|
|
|
|
/**
|
|
* Connection state from RelayStateManager
|
|
*/
|
|
export type RelayConnectionState =
|
|
| "pending" // Not yet attempted
|
|
| "connecting" // Connection in progress
|
|
| "connected" // WebSocket connected
|
|
| "disconnected" // Disconnected (expected or unexpected)
|
|
| "error"; // Connection error
|
|
|
|
/**
|
|
* Subscription state specific to this REQ
|
|
*/
|
|
export type RelaySubscriptionState =
|
|
| "waiting" // Connected but no events yet
|
|
| "receiving" // Events being received
|
|
| "eose" // EOSE received (real or timeout)
|
|
| "error"; // Subscription error
|
|
|
|
/**
|
|
* Per-relay state for a single REQ subscription
|
|
*/
|
|
export interface ReqRelayState {
|
|
url: string;
|
|
|
|
// Connection state (from RelayStateManager)
|
|
connectionState: RelayConnectionState;
|
|
|
|
// Subscription state (tracked by enhanced hook)
|
|
subscriptionState: RelaySubscriptionState;
|
|
|
|
// Event tracking
|
|
eventCount: number;
|
|
firstEventAt?: number;
|
|
lastEventAt?: number;
|
|
|
|
// Timing
|
|
connectedAt?: number;
|
|
eoseAt?: number;
|
|
disconnectedAt?: number;
|
|
|
|
// Error handling
|
|
errorMessage?: string;
|
|
errorType?: "connection" | "protocol" | "timeout" | "auth";
|
|
}
|
|
|
|
/**
|
|
* Overall query state derived from individual relay states
|
|
*/
|
|
export type ReqOverallStatus =
|
|
| "discovering" // Selecting relays (NIP-65)
|
|
| "connecting" // Waiting for first relay to connect
|
|
| "loading" // Loading initial events
|
|
| "live" // Streaming after EOSE, relays connected
|
|
| "partial" // Some relays ok, some failed
|
|
| "closed" // All relays completed and closed
|
|
| "failed" // All relays failed
|
|
| "offline"; // All relays disconnected after being live
|
|
|
|
/**
|
|
* Aggregated state for the entire query
|
|
*/
|
|
export interface ReqOverallState {
|
|
status: ReqOverallStatus;
|
|
|
|
// Relay counts
|
|
totalRelays: number;
|
|
connectedCount: number;
|
|
receivingCount: number;
|
|
eoseCount: number;
|
|
errorCount: number;
|
|
disconnectedCount: number;
|
|
|
|
// Timing
|
|
queryStartedAt: number;
|
|
firstEventAt?: number;
|
|
allEoseAt?: number;
|
|
|
|
// Flags
|
|
hasReceivedEvents: boolean;
|
|
hasActiveRelays: boolean;
|
|
allRelaysFailed: boolean;
|
|
}
|