@@ -206,6 +206,55 @@ describe('POST /api/sessions/[sessionId]/signal', () => {
206206 expect ( body . error ) . toBe ( 'Not authorized to send signals in this session' ) ;
207207 } ) ;
208208
209+ it ( 'allows authenticated viewer signaling with senderId=user.id when user is an active participant' , async ( ) => {
210+ const otherUserSession = { ...mockSession , host_user_id : 'host-user-id' } ;
211+ let callCount = 0 ;
212+
213+ const mockChannel = {
214+ subscribe : vi . fn ( ) . mockImplementation ( ( callback ) => {
215+ callback ( 'SUBSCRIBED' ) ;
216+ return mockChannel ;
217+ } ) ,
218+ send : vi . fn ( ) . mockResolvedValue ( 'ok' ) ,
219+ } ;
220+
221+ const mockFrom = vi . fn ( ) . mockReturnValue ( {
222+ select : vi . fn ( ) . mockReturnThis ( ) ,
223+ eq : vi . fn ( ) . mockReturnThis ( ) ,
224+ is : vi . fn ( ) . mockReturnThis ( ) ,
225+ single : vi . fn ( ) . mockImplementation ( ( ) => {
226+ callCount ++ ;
227+ if ( callCount === 1 ) {
228+ // Session lookup
229+ return Promise . resolve ( { data : otherUserSession , error : null } ) ;
230+ }
231+ if ( callCount === 2 ) {
232+ // Participant lookup by signal.senderId (user.id) misses
233+ return Promise . resolve ( { data : null , error : { code : 'PGRST116' } } ) ;
234+ }
235+ // Participant lookup by user_id succeeds
236+ return Promise . resolve ( { data : { id : 'participant-row-id' } , error : null } ) ;
237+ } ) ,
238+ } ) ;
239+
240+ const mockSupabase = createMockSupabaseClient ( {
241+ from : mockFrom ,
242+ channel : vi . fn ( ) . mockReturnValue ( mockChannel ) ,
243+ removeChannel : vi . fn ( ) . mockResolvedValue ( 'ok' ) ,
244+ } ) ;
245+ vi . mocked ( createClient ) . mockResolvedValue ( mockSupabase as never ) ;
246+ mockGetAuthenticatedUser . mockResolvedValue ( { user : mockUser , error : null } ) ;
247+
248+ const response = await POST ( createRequest ( 'test-session-id' , validSignal ) , {
249+ params : Promise . resolve ( { sessionId : 'test-session-id' } ) ,
250+ } ) ;
251+ const body = await response . json ( ) ;
252+
253+ expect ( response . status ) . toBe ( 200 ) ;
254+ expect ( body . data . sent ) . toBe ( true ) ;
255+ expect ( mockChannel . send ) . toHaveBeenCalled ( ) ;
256+ } ) ;
257+
209258 it ( 'returns 400 for invalid signal type' , async ( ) => {
210259 const invalidSignal = {
211260 type : 'invalid-type' ,
0 commit comments