@@ -75,27 +75,33 @@ interface SocketContextType {
7575 joinWorkflow : ( workflowId : string ) => void
7676 leaveWorkflow : ( ) => void
7777 retryConnection : ( ) => void
78+ /**
79+ * Emit functions return whether the payload was actually sent over the socket.
80+ * `false` means the emit was skipped because the target room is not currently
81+ * joined/visible; the operation queue keeps such operations pending instead of
82+ * waiting on a confirmation that will never arrive.
83+ */
7884 emitWorkflowOperation : (
7985 workflowId : string ,
8086 operation : string ,
8187 target : string ,
8288 payload : any ,
8389 operationId ?: string
84- ) => void
90+ ) => boolean
8591 emitSubblockUpdate : (
8692 blockId : string ,
8793 subblockId : string ,
8894 value : any ,
8995 operationId : string | undefined ,
9096 workflowId : string
91- ) => void
97+ ) => boolean
9298 emitVariableUpdate : (
9399 variableId : string ,
94100 field : string ,
95101 value : any ,
96102 operationId : string | undefined ,
97103 workflowId : string
98- ) => void
104+ ) => boolean
99105
100106 emitCursorUpdate : ( cursor : { x : number ; y : number } | null ) => void
101107 emitSelectionUpdate : ( selection : { type : 'block' | 'edge' | 'none' ; id ?: string } ) => void
@@ -126,9 +132,9 @@ const SocketContext = createContext<SocketContextType>({
126132 joinWorkflow : ( ) => { } ,
127133 leaveWorkflow : ( ) => { } ,
128134 retryConnection : ( ) => { } ,
129- emitWorkflowOperation : ( ) => { } ,
130- emitSubblockUpdate : ( ) => { } ,
131- emitVariableUpdate : ( ) => { } ,
135+ emitWorkflowOperation : ( ) => false ,
136+ emitSubblockUpdate : ( ) => false ,
137+ emitVariableUpdate : ( ) => false ,
132138 emitCursorUpdate : ( ) => { } ,
133139 emitSelectionUpdate : ( ) => { } ,
134140 onWorkflowOperation : ( ) => { } ,
@@ -519,6 +525,10 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
519525 setIsRetryingWorkflowJoin ( false )
520526 setVisibleWorkflowId ( workflowId )
521527 setPresenceUsers ( presenceUsers || [ ] )
528+ // A successful join is always followed by a workflow-state push that
529+ // rehydrates local stores from server truth, so a previously tripped
530+ // offline mode is safe to clear here.
531+ useOperationQueueStore . getState ( ) . clearError ( )
522532 logger . info ( `Successfully joined workflow room: ${ workflowId } ` , {
523533 presenceCount : presenceUsers ?. length || 0 ,
524534 } )
@@ -847,7 +857,13 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
847857 } , [ authFailed ] )
848858
849859 const emitWorkflowOperation = useCallback (
850- ( workflowId : string , operation : string , target : string , payload : any , operationId ?: string ) => {
860+ (
861+ workflowId : string ,
862+ operation : string ,
863+ target : string ,
864+ payload : any ,
865+ operationId ?: string
866+ ) : boolean => {
851867 if (
852868 ! socket ||
853869 ! currentWorkflowId ||
@@ -861,7 +877,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
861877 operation,
862878 target,
863879 } )
864- return
880+ return false
865881 }
866882
867883 const isPositionUpdate = operation === 'update-position' && target === 'block'
@@ -885,7 +901,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
885901 clearTimeout ( timeoutId )
886902 positionUpdateTimeouts . current . delete ( blockId )
887903 }
888- return
904+ return true
889905 }
890906
891907 pendingPositionUpdates . current . set ( blockId , {
@@ -909,16 +925,18 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
909925
910926 positionUpdateTimeouts . current . set ( blockId , timeoutId )
911927 }
912- } else {
913- socket . emit ( 'workflow-operation' , {
914- workflowId,
915- operation,
916- target,
917- payload,
918- timestamp : Date . now ( ) ,
919- operationId,
920- } )
928+ return true
921929 }
930+
931+ socket . emit ( 'workflow-operation' , {
932+ workflowId,
933+ operation,
934+ target,
935+ payload,
936+ timestamp : Date . now ( ) ,
937+ operationId,
938+ } )
939+ return true
922940 } ,
923941 [ socket , currentWorkflowId , isWorkflowVisible ]
924942 )
@@ -930,7 +948,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
930948 value : any ,
931949 operationId : string | undefined ,
932950 workflowId : string
933- ) => {
951+ ) : boolean => {
934952 if (
935953 ! socket ||
936954 workflowId !== currentWorkflowIdRef . current ||
@@ -949,7 +967,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
949967 reason,
950968 currentWorkflowId : currentWorkflowIdRef . current ,
951969 } )
952- return
970+ return false
953971 }
954972 socket . emit ( 'subblock-update' , {
955973 workflowId,
@@ -959,6 +977,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
959977 timestamp : Date . now ( ) ,
960978 operationId,
961979 } )
980+ return true
962981 } ,
963982 [ socket ]
964983 )
@@ -970,7 +989,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
970989 value : any ,
971990 operationId : string | undefined ,
972991 workflowId : string
973- ) => {
992+ ) : boolean => {
974993 if (
975994 ! socket ||
976995 workflowId !== currentWorkflowIdRef . current ||
@@ -989,7 +1008,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
9891008 reason,
9901009 currentWorkflowId : currentWorkflowIdRef . current ,
9911010 } )
992- return
1011+ return false
9931012 }
9941013 socket . emit ( 'variable-update' , {
9951014 workflowId,
@@ -999,6 +1018,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
9991018 timestamp : Date . now ( ) ,
10001019 operationId,
10011020 } )
1021+ return true
10021022 } ,
10031023 [ socket ]
10041024 )
0 commit comments