@@ -218,6 +218,8 @@ export class BaseConvexClient {
218218 } ,
219219 stopSocket : ( ) => this . webSocketManager . stop ( ) ,
220220 restartSocket : ( ) => this . webSocketManager . restart ( ) ,
221+ pauseSocket : ( ) => this . webSocketManager . pause ( ) ,
222+ resumeSocket : ( ) => this . webSocketManager . resume ( ) ,
221223 clearAuth : ( ) => {
222224 this . clearAuth ( ) ;
223225 } ,
@@ -258,89 +260,107 @@ export class BaseConvexClient {
258260
259261 this . webSocketManager = new WebSocketManager (
260262 wsUri ,
261- ( reconnectMetadata : ReconnectMetadata ) => {
262- // We have a new WebSocket!
263- this . mark ( "convexWebSocketOpen" ) ;
264- this . webSocketManager . sendMessage ( {
265- ...reconnectMetadata ,
266- type : "Connect" ,
267- sessionId : this . _sessionId ,
268- maxObservedTimestamp : this . maxObservedTimestamp ,
269- } ) ;
270-
271- // Throw out our remote query, reissue queries
272- // and outstanding mutations, and reauthenticate.
273- const oldRemoteQueryResults = new Set (
274- this . remoteQuerySet . remoteQueryResults ( ) . keys ( ) ,
275- ) ;
276- this . remoteQuerySet = new RemoteQuerySet ( ( queryId ) =>
277- this . state . queryPath ( queryId ) ,
278- ) ;
279- const [ querySetModification , authModification ] = this . state . restart (
280- oldRemoteQueryResults ,
281- ) ;
282- if ( authModification ) {
283- this . webSocketManager . sendMessage ( authModification ) ;
284- }
285- this . webSocketManager . sendMessage ( querySetModification ) ;
286- for ( const message of this . requestManager . restart ( ) ) {
287- this . webSocketManager . sendMessage ( message ) ;
288- }
289- } ,
290- ( serverMessage : ServerMessage ) => {
291- // Metrics events grow linearly with reconnection attempts so this
292- // conditional prevents n^2 metrics reporting.
293- if ( ! this . firstMessageReceived ) {
294- this . firstMessageReceived = true ;
295- this . mark ( "convexFirstMessageReceived" ) ;
296- this . reportMarks ( ) ;
297- }
298- switch ( serverMessage . type ) {
299- case "Transition" : {
300- this . observedTimestamp ( serverMessage . endVersion . ts ) ;
301- this . authenticationManager . onTransition ( serverMessage ) ;
302- this . remoteQuerySet . transition ( serverMessage ) ;
303- this . state . transition ( serverMessage ) ;
304- const completedRequests = this . requestManager . removeCompleted (
305- this . remoteQuerySet . timestamp ( ) ,
306- ) ;
307- this . notifyOnQueryResultChanges ( completedRequests ) ;
308- break ;
263+ {
264+ onOpen : ( reconnectMetadata : ReconnectMetadata ) => {
265+ // We have a new WebSocket!
266+ this . mark ( "convexWebSocketOpen" ) ;
267+ this . webSocketManager . sendMessage ( {
268+ ...reconnectMetadata ,
269+ type : "Connect" ,
270+ sessionId : this . _sessionId ,
271+ maxObservedTimestamp : this . maxObservedTimestamp ,
272+ } ) ;
273+
274+ // Throw out our remote query, reissue queries
275+ // and outstanding mutations, and reauthenticate.
276+ const oldRemoteQueryResults = new Set (
277+ this . remoteQuerySet . remoteQueryResults ( ) . keys ( ) ,
278+ ) ;
279+ this . remoteQuerySet = new RemoteQuerySet ( ( queryId ) =>
280+ this . state . queryPath ( queryId ) ,
281+ ) ;
282+ const [ querySetModification , authModification ] = this . state . restart (
283+ oldRemoteQueryResults ,
284+ ) ;
285+ if ( authModification ) {
286+ this . webSocketManager . sendMessage ( authModification ) ;
309287 }
310- case "MutationResponse" : {
311- if ( serverMessage . success ) {
312- this . observedTimestamp ( serverMessage . ts ) ;
313- }
314- const completedMutationId =
315- this . requestManager . onResponse ( serverMessage ) ;
316- if ( completedMutationId !== null ) {
317- this . notifyOnQueryResultChanges ( new Set ( [ completedMutationId ] ) ) ;
318- }
319- break ;
288+ this . webSocketManager . sendMessage ( querySetModification ) ;
289+ for ( const message of this . requestManager . restart ( ) ) {
290+ this . webSocketManager . sendMessage ( message ) ;
320291 }
321- case "ActionResponse" : {
322- this . requestManager . onResponse ( serverMessage ) ;
323- break ;
292+ } ,
293+ onResume : ( ) => {
294+ const remoteQueryResults = new Set (
295+ this . remoteQuerySet . remoteQueryResults ( ) . keys ( ) ,
296+ ) ;
297+ const [ querySetModification , authModification ] =
298+ this . state . resume ( remoteQueryResults ) ;
299+ if ( authModification ) {
300+ this . webSocketManager . sendMessage ( authModification ) ;
324301 }
325- case "AuthError" : {
326- this . authenticationManager . onAuthError ( serverMessage ) ;
327- break ;
302+ if ( querySetModification ) {
303+ this . webSocketManager . sendMessage ( querySetModification ) ;
328304 }
329- case "FatalError" : {
330- const error = logFatalError ( serverMessage . error ) ;
331- void this . webSocketManager . terminate ( ) ;
332- throw error ;
305+ for ( const message of this . requestManager . resume ( ) ) {
306+ this . webSocketManager . sendMessage ( message ) ;
333307 }
334- case "Ping" :
335- break ; // do nothing
336- default : {
337- const _typeCheck : never = serverMessage ;
308+ } ,
309+ onMessage : ( serverMessage : ServerMessage ) => {
310+ // Metrics events grow linearly with reconnection attempts so this
311+ // conditional prevents n^2 metrics reporting.
312+ if ( ! this . firstMessageReceived ) {
313+ this . firstMessageReceived = true ;
314+ this . mark ( "convexFirstMessageReceived" ) ;
315+ this . reportMarks ( ) ;
316+ }
317+ switch ( serverMessage . type ) {
318+ case "Transition" : {
319+ this . observedTimestamp ( serverMessage . endVersion . ts ) ;
320+ this . authenticationManager . onTransition ( serverMessage ) ;
321+ this . remoteQuerySet . transition ( serverMessage ) ;
322+ this . state . transition ( serverMessage ) ;
323+ const completedRequests = this . requestManager . removeCompleted (
324+ this . remoteQuerySet . timestamp ( ) ,
325+ ) ;
326+ this . notifyOnQueryResultChanges ( completedRequests ) ;
327+ break ;
328+ }
329+ case "MutationResponse" : {
330+ if ( serverMessage . success ) {
331+ this . observedTimestamp ( serverMessage . ts ) ;
332+ }
333+ const completedMutationId =
334+ this . requestManager . onResponse ( serverMessage ) ;
335+ if ( completedMutationId !== null ) {
336+ this . notifyOnQueryResultChanges ( new Set ( [ completedMutationId ] ) ) ;
337+ }
338+ break ;
339+ }
340+ case "ActionResponse" : {
341+ this . requestManager . onResponse ( serverMessage ) ;
342+ break ;
343+ }
344+ case "AuthError" : {
345+ this . authenticationManager . onAuthError ( serverMessage ) ;
346+ break ;
347+ }
348+ case "FatalError" : {
349+ const error = logFatalError ( serverMessage . error ) ;
350+ void this . webSocketManager . terminate ( ) ;
351+ throw error ;
352+ }
353+ case "Ping" :
354+ break ; // do nothing
355+ default : {
356+ const _typeCheck : never = serverMessage ;
357+ }
338358 }
339- }
340359
341- return {
342- hasSyncedPastLastReconnect : this . hasSyncedPastLastReconnect ( ) ,
343- } ;
360+ return {
361+ hasSyncedPastLastReconnect : this . hasSyncedPastLastReconnect ( ) ,
362+ } ;
363+ } ,
344364 } ,
345365 webSocketConstructor ,
346366 this . verbose ,
0 commit comments