22 * SSE Client for SmallTalk
33 * Handles real-time updates using Server-Sent Events (SSE)
44 */
5+
6+ // Suppress browser extension errors that interfere with SSE
7+ ( function ( ) {
8+ 'use strict' ;
9+
10+ // Suppress chrome extension errors - only if the API exists
11+ if ( typeof chrome !== 'undefined' &&
12+ chrome . runtime &&
13+ chrome . runtime . onMessage &&
14+ chrome . runtime . onMessage . addListener ) {
15+ try {
16+ const originalAddListener = chrome . runtime . onMessage . addListener ;
17+ chrome . runtime . onMessage . addListener = function ( ...args ) {
18+ try {
19+ return originalAddListener . apply ( this , args ) ;
20+ } catch ( e ) {
21+ // Suppress extension errors
22+ console . debug ( 'Suppressed extension error:' , e . message ) ;
23+ }
24+ } ;
25+ } catch ( e ) {
26+ // Silently fail if we can't override the listener
27+ console . debug ( 'Could not override chrome extension listener:' , e . message ) ;
28+ }
29+ }
30+
31+ // Global error handler for uncaught extension errors
32+ window . addEventListener ( 'error' , function ( event ) {
33+ if ( event . message &&
34+ ( event . message . includes ( 'Extension context invalidated' ) ||
35+ event . message . includes ( 'Could not establish connection' ) ||
36+ event . message . includes ( 'Receiving end does not exist' ) ) ) {
37+ event . preventDefault ( ) ;
38+ console . debug ( 'Suppressed extension-related error:' , event . message ) ;
39+ return true ;
40+ }
41+ } ) ;
42+ } ) ( ) ;
43+
544class SSEClient {
645 constructor ( ) {
746 this . eventSource = null ;
@@ -51,6 +90,15 @@ class SSEClient {
5190 * @param {string } meetingCode - The meeting Code
5291 */
5392 connect ( meetingCode ) {
93+ // Check if EventSource is supported
94+ if ( ! SSEClient . isSupported ( ) ) {
95+ console . error ( 'SSE is not supported in this browser' ) ;
96+ if ( typeof update === 'function' ) {
97+ update ( { error : 'SSE is not supported in this browser' } ) ;
98+ }
99+ return ;
100+ }
101+
54102 if ( this . eventSource ) {
55103 this . disconnect ( ) ;
56104 }
@@ -61,9 +109,14 @@ class SSEClient {
61109
62110 try {
63111 this . eventSource = new EventSource ( url ) ;
64- this . connected = true ;
65- this . reconnectAttempts = 0 ;
66- this . trigger ( 'connected' ) ;
112+
113+ // Wait for the connection to open before marking as connected
114+ this . eventSource . addEventListener ( 'open' , ( ) => {
115+ console . log ( 'SSE connection established successfully' ) ;
116+ this . connected = true ;
117+ this . reconnectAttempts = 0 ;
118+ this . trigger ( 'connected' ) ;
119+ } ) ;
67120
68121 // Start the update interval for smooth rendering
69122 this . startUpdateInterval ( ) ;
@@ -105,30 +158,47 @@ class SSEClient {
105158 // Error handling
106159 this . eventSource . onerror = ( error ) => {
107160 console . error ( 'SSE Connection error:' , error ) ;
108- console . error ( 'EventSource readyState:' , this . eventSource . readyState ) ;
161+
162+ // Check the readyState to determine the type of error
163+ const readyState = this . eventSource ? this . eventSource . readyState : null ;
164+ console . error ( 'EventSource readyState:' , readyState ) ;
165+
166+ // ReadyState values: 0 = CONNECTING, 1 = OPEN, 2 = CLOSED
167+ let errorMessage = 'Connection error' ;
168+
169+ if ( readyState === EventSource . CLOSED || readyState === 2 ) {
170+ errorMessage = 'Connection closed by server' ;
171+ } else if ( readyState === EventSource . CONNECTING || readyState === 0 ) {
172+ errorMessage = 'Unable to establish connection' ;
173+ }
174+
109175 console . error ( 'Connection details:' , {
110176 url : url ,
111177 meetingCode : this . meetingCode ,
112- reconnectAttempts : this . reconnectAttempts
178+ reconnectAttempts : this . reconnectAttempts ,
179+ errorMessage : errorMessage
113180 } ) ;
114-
181+
115182 this . connected = false ;
116183 this . stopUpdateInterval ( ) ;
117184 this . trigger ( 'disconnected' ) ;
118185
119186 if ( this . reconnectAttempts < this . maxReconnectAttempts ) {
120187 this . reconnectAttempts ++ ;
121188 const delay = this . reconnectDelay * Math . pow ( 1.5 , this . reconnectAttempts - 1 ) ;
122- console . log ( `Attempting to reconnect in ${ delay } ms (attempt ${ this . reconnectAttempts } /${ this . maxReconnectAttempts } )` ) ;
189+ console . log ( `Attempting to reconnect in ${ delay } ms (attempt ${ this . reconnectAttempts } /${ this . maxReconnectAttempts } )... ` ) ;
123190
124191 setTimeout ( ( ) => {
125192 this . connect ( this . meetingCode ) ;
126193 } , delay ) ;
127194 } else {
128- console . error ( 'Max reconnect attempts reached, giving up ' ) ;
195+ console . error ( 'Max reconnect attempts reached. Connection failed permanently. ' ) ;
129196 // Call update with error data
130197 if ( typeof update === 'function' ) {
131- update ( { error : 'Max reconnect attempts reached' } ) ;
198+ update ( {
199+ error : 'Connection failed after multiple attempts. Please refresh the page.' ,
200+ type : 'connection_error'
201+ } ) ;
132202 }
133203 }
134204 } ;
@@ -155,7 +225,7 @@ class SSEClient {
155225 if ( this . updateInterval ) {
156226 clearInterval ( this . updateInterval ) ;
157227 }
158-
228+
159229 this . updateInterval = setInterval ( ( ) => {
160230 this . processMessageQueue ( ) ;
161231 } , 50 ) ; // Update every 50ms for smooth rendering
@@ -233,7 +303,7 @@ class SSEClient {
233303 if ( data . final ) {
234304 console . log ( 'Message is final, marking as complete:' , messageId ) ;
235305 this . pendingMessages [ messageId ] . final = true ;
236-
306+
237307 // Queue final update
238308 this . messageQueue . set ( messageId , {
239309 ...this . pendingMessages [ messageId ] ,
0 commit comments