openvibers/openvibe.live Commits

Chat: relay to PowerChat per CHANNEL, not per live session

OP OpenVibers committed 18 Aug 2026 · 504ec5d622 · 1 file, +18 −11

The PowerChat overlay only received chat while the streamer was live. The
forwardChat() call was nested inside `if (client.streamId)`, so an offline
channel viewer — whose client has channelUserId set but streamId null — never
reached it.

That gating was wrong for this relay specifically. Viewers can chat in a channel
whenever they like; those messages are already saved with channel_user_id and
broadcast to the whole channel room (the code immediately above does exactly
that, and its own comment notes it covers "offline viewers"). The overlay was
the only consumer that never saw them.

Moved out to its own block gated on client.channelUserId alone. forwardChat()
itself only requires an OAuth connection with chat:write, so nothing else had to
change. TTS, soundboards and AI chat viewers stay stream-scoped — those
genuinely need a live session.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Xw6Sf5zzSALw8m93XNu5JE

Changes

ddiff --git a/server/chat/chat-server.js b/server/chat/chat-server.js
iindex cb0fc6d3..2467002e 100644
---- a/server/chat/chat-server.js
++++ b/server/chat/chat-server.js
@@@ -891,22 +891,29 @@ class ChatServer {
});
} catch { /* non-critical */ }
-- // Merge real chat into the streamer's PowerChat unified overlay (chat:write).
-- try {
-- if (client.channelUserId) {
-- require('../integrations/powerchat-platform').forwardChat(client.channelUserId, {
-- chatterName: username,
-- externalChatterId: client.user?.id ? ('u' + client.user.id) : ('a' + (client.anonId || 'anon')),
-- message: text,
-- avatarUrl: client.user?.avatar_url || undefined,
-- });
-- }
-- } catch { /* non-critical */ }
} else if (!client.channelUserId) {
// Pure global chat (homepage) — offline channel messages were already
// delivered to the channel room above.
this.broadcastGlobal(chatMsg);
}
++
++ // Merge real chat into the streamer's PowerChat unified overlay (chat:write).
++ // Scoped to the CHANNEL, not the live session. This used to sit inside the
++ // `if (client.streamId)` block above, so it only fired while the streamer was
++ // live — yet viewers can chat in a channel whenever they like, and those
++ // messages are already persisted and broadcast channel-wide. The overlay simply
++ // never saw them. Chat is a property of the channel; only TTS, soundboards and
++ // AI viewers genuinely need a live stream.
++ try {
++ if (client.channelUserId) {
++ require('../integrations/powerchat-platform').forwardChat(client.channelUserId, {
++ chatterName: username,
++ externalChatterId: client.user?.id ? ('u' + client.user.id) : ('a' + (client.anonId || 'anon')),
++ message: text,
++ avatarUrl: client.user?.avatar_url || undefined,
++ });
++ }
++ } catch { /* non-critical */ }
}
handleBangCommand(ws, client, text) {