openvibers/openvibe.live Commits
Chat sockets never carry the token in the URL (C-05): chat, the media player and the broadcast PiP send it in their first join message; a message typed while the chat socket reconnects stays in the box instead of being re-posted to global chat over REST (C-06). Docs: bots authenticate /ws/chat with an Authorization header or the join message (?token= is deprecated); POST /api/chat/send is the bots' global-chat API
Changes
@@@ -72,13 +72,18 @@ For the OpenVibe.Live VS Code companion or any other coding-feed publisher, use### WebSocket (Chat)--Pass the token as the `token` query parameter:++Send the token in an `Authorization: Bearer` header on the upgrade request (Node's `ws`, Python's `websockets` and most server libraries can), or as the `token` of your first `join` message (browsers cannot set headers):```--wss://openvibe.live/ws/chat?token=hbt_YOUR_TOKEN_HERE&streamId=123++wss://openvibe.live/ws/chat?stream=123++Authorization: Bearer hbt_YOUR_TOKEN_HERE```--The token works everywhere a JWT would — the server auto-detects the `hbt_` prefix and validates accordingly.++```json++{ "type": "join", "streamId": 123, "token": "hbt_YOUR_TOKEN_HERE" }++```++++The token works everywhere a JWT would — the server auto-detects the `hbt_` prefix and validates accordingly. A `?token=` query parameter still works but is deprecated (compatibility shim C-05): URLs end up in proxy logs and browser history, so move to the header or the `join` message.## Managing Tokens@@@ -108,11 +113,12 @@ const WebSocket = require('ws');const TOKEN = 'hbt_your_token_here';const STREAM_ID = '123';--const ws = new WebSocket(-- `wss://openvibe.live/ws/chat?token=${TOKEN}&streamId=${STREAM_ID}`--);++const ws = new WebSocket(`wss://openvibe.live/ws/chat?stream=${STREAM_ID}`, {++ headers: { Authorization: `Bearer ${TOKEN}` },++});ws.on('open', () => {++ ws.send(JSON.stringify({ type: 'join', streamId: Number(STREAM_ID) }));console.log('Connected to chat');});@@@ -92,8 +92,10 @@ Body: { "streamId": 123, "fromTime": "2024-01-01T00:00", "toTime": "2024-01-02T0### Connect```--wss://openvibe.live/ws/chat?token=JWT_OR_API_TOKEN&streamId=123++wss://openvibe.live/ws/chat?stream=123++Authorization: Bearer JWT_OR_API_TOKEN (non-browser clients)```++Browsers send the token in the first `join` message instead (`{ "type": "join", "streamId": 123, "token": "…" }`); the `ov_token`/`token` cookies also authenticate the upgrade on the site's own origin. A `?token=` query parameter still works for older bots but is deprecated (C-05): URLs are logged.### Message Types (Client → Server)| Type | Fields | Description |@@@ -96,7 +96,7 @@<h3>Base URL & Auth</h3><p>Base URL: <code>https://openvibe.live</code> (replace with your instance).</p>--<p>Auth: <code>Authorization: Bearer <JWT></code> header, or <code>?token=JWT</code> query param on WebSocket URLs.</p>++<p>Auth: <code>Authorization: Bearer <JWT></code> header. On WebSockets, the header on the upgrade request or the <code>token</code> of the first <code>join</code> message; a <code>?token=</code> query param still works but is deprecated (URLs are logged).</p><p>API tokens: <code>hbt_</code> prefix, scoped permissions, created from Dashboard → API Tokens.</p></div>@@@ -168,7 +168,7 @@ openvibe.network /api/admin/streamer-mod/* → OpenVibe.Live /api/mod/*</code><p><strong>All identity is OpenVibe SSO.</strong> There is no local password login on OpenVibe.Live — <code>POST /api/auth/register</code> and <code>POST /api/auth/login</code> are permanently disabled (return <code>410</code>). Humans sign in through openvibe.network OAuth2; OpenVibe.Live receives an <strong>RS256 JWT</strong> signed by openvibe.network and verifies it locally. For bots and scripts, use a long-lived <strong><code>hbt_</code> API token</strong> (below) — no browser login needed.</p><h3>How auth is sent</h3>--<p>Every authenticated request carries a token as <code>Authorization: Bearer <token></code> (also read from the <code>ov_token</code> cookie, or a <code>?token=</code> query param on WebSocket URLs). <code>requireAuth</code> accepts either:</p>++<p>Every authenticated request carries a token as <code>Authorization: Bearer <token></code> (also read from the <code>ov_token</code> cookie; on WebSockets also from the first <code>join</code> message, and from a deprecated <code>?token=</code> query param). <code>requireAuth</code> accepts either:</p><ul><li><strong>API token</strong> — a string starting with <code>hbt_</code>. Best for bots/integrations. Cannot itself create/list/revoke tokens.</li><li><strong>openvibe.network JWT (RS256)</strong> — from the SSO login flow; auto-links/creates a local account. Roles come from the token.</li>@@@ -491,7 +491,7 @@ while True:<table class="doc-table"><thead><tr><th>Method</th><th>Path</th><th>Auth</th><th>Description</th></tr></thead><tbody>--<tr><td>POST</td><td>/api/chat/send</td><td>Yes</td><td>Send message via REST (fallback)</td></tr>++<tr><td>POST</td><td>/api/chat/send</td><td>Yes</td><td>Post a message to global chat (bots; API tokens need the <code>chat</code> scope)</td></tr><tr><td>GET</td><td>/api/chat/:streamId/history</td><td>No</td><td>Chat history for a stream</td></tr><tr><td>GET</td><td>/api/chat/:streamId/users</td><td>No</td><td>Users in a stream's chat</td></tr><tr><td>GET</td><td>/api/chat/user/:username/profile</td><td>No</td><td>User profile card data</td></tr>@@@ -1237,7 +1237,7 @@ curl -s https://openvibe.media/live/@Goosely/chat-insight.json | jq ".chat_insig<table class="doc-table"><thead><tr><th>Method</th><th>Path</th><th>Auth</th><th>Notes</th></tr></thead><tbody>--<tr><td>POST</td><td>/api/chat/send</td><td>Yes</td><td>REST fallback to post a global chat message</td></tr>++<tr><td>POST</td><td>/api/chat/send</td><td>Yes</td><td>Post a message to global chat (bots; API tokens need the <code>chat</code> scope)</td></tr><tr><td>GET</td><td>/api/chat/:streamId/history</td><td>Opt</td><td>Per-streamer history (all slots + offline unless <code>?scope=stream</code>)</td></tr><tr><td>GET</td><td>/api/chat/global/history</td><td>Opt</td><td>Global chat history</td></tr><tr><td>GET</td><td>/api/chat/:streamId/replay</td><td>Opt</td><td>Chat replay for VOD/clip sync (<code>?from,to</code>)</td></tr>@@@ -6270,7 +6270,6 @@ function _connectMediaPipSocket() {const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';const url = new URL(`${protocol}//${window.location.host}/ws/chat`);const token = localStorage.getItem('token');-- if (token) url.searchParams.set('token', token);url.searchParams.set('stream', activeId);const ws = new WebSocket(url.toString());@@@ -2629,9 +2629,8 @@ function initChat(streamId, channelUserId = null) {const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';const token = localStorage.getItem('token');-- // Pass token and stream in URL so the server can authenticate on connect++ // The stream goes in the URL; the token only in the join message (never in a URL, where proxies log it).const params = new URLSearchParams();-- if (token) params.set('token', token);if (streamId) params.set('stream', streamId);const wsUrl = `${protocol}://${host}:${port}/ws/chat?${params.toString()}`;@@@ -2793,7 +2792,6 @@ function _reconnectChatWs(streamId) {const token = localStorage.getItem('token');const params = new URLSearchParams();-- if (token) params.set('token', token);if (streamId) params.set('stream', streamId);const wsUrl = `${protocol}://${host}:${port}/ws/chat?${params.toString()}`;@@@ -4286,9 +4284,10 @@ function sendChat(overrideInput = null) {return;}-- // If WS is down (server restarting, etc.), send to global chat via REST API++ // WS down (Chat restarting): the message stays in the box until the socket is back. It is never++ // re-routed to another room (the REST send is a bot API, not a browser fallback).if (!chatWs || chatWs.readyState !== WebSocket.OPEN) {-- _sendChatViaRest(text, input);++ addSystemMessage('Chat is reconnecting. Your message is still in the box: send it again in a moment.');return;}@@@ -4338,49 +4337,6 @@ function sendChat(overrideInput = null) {startSlowModeCooldown();}--/**-- * Fallback: send a chat message via REST API when the WebSocket is down.-- * The message goes to global chat so the user isn't silenced during reconnects.-- */--async function _sendChatViaRest(text, input) {-- const token = localStorage.getItem('token');-- if (!token) {-- addSystemMessage('Chat disconnected — log in to send messages while reconnecting');-- return;-- }-- try {-- const autoDeleteMinutes = normalizeChatAutoDeleteMinutes(chatSettings.autoDeleteMinutes);-- const payload = { message: text, reply_to_id: _chatReplyTo?.id || undefined };-- if (autoDeleteMinutes >= (chatSelfDeletePolicy.minMinutes || CHAT_SELF_DELETE_MINUTES) && canUseViewerAutoDeleteHere()) {-- payload.auto_delete_minutes = autoDeleteMinutes;-- }---- const res = await fetch('/api/chat/send', {-- method: 'POST',-- headers: {-- 'Authorization': `Bearer ${token}`,-- 'Content-Type': 'application/json',-- },-- body: JSON.stringify(payload),-- });-- if (!res.ok) {-- const err = await res.json().catch(() => ({}));-- addSystemMessage(err.error || 'Failed to send message');-- return;-- }-- // Clear input on success-- input.value = '';-- _autoResizeTextarea(input);-- input.focus();-- clearChatReply();-- if (chatStreamId) {-- addSystemMessage('Sent to global chat (stream chat reconnecting)');-- }-- } catch {-- addSystemMessage('Server unreachable — message not sent');-- }--}--/* ── Reply-to helpers ─────────────────────────────────────────── *//**@@@ -6025,7 +5981,6 @@ function _openGlobalFeed() {const token = localStorage.getItem('token');const params = new URLSearchParams();-- if (token) params.set('token', token);// No stream param = global chatconst wsUrl = `${protocol}://${host}:${port}/ws/chat?${params.toString()}`;const ws = new WebSocket(wsUrl);@@@ -840,7 +840,6 @@ function connectSocket() {const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';const url = new URL(`${protocol}//${window.location.host}/ws/chat`);-- if (mpToken()) url.searchParams.set('token', mpToken());url.searchParams.set('stream', mpLiveStream.id);const socket = new WebSocket(url.toString());
@@ -72,13 +72,18 @@ For the OpenVibe.Live VS Code companion or any other coding-feed publisher, use
@@ -72,13 +72,18 @@ For the OpenVibe.Live VS Code companion or any other coding-feed publisher, use
### WebSocket (Chat)
### WebSocket (Chat)
-Pass the token as the `token` query parameter:
+Send the token in an `Authorization: Bearer` header on the upgrade request (Node's `ws`, Python's `websockets` and most server libraries can), or as the `token` of your first `join` message (browsers cannot set headers):
```
```
-wss://openvibe.live/ws/chat?token=hbt_YOUR_TOKEN_HERE&streamId=123
+wss://openvibe.live/ws/chat?stream=123
+Authorization: Bearer hbt_YOUR_TOKEN_HERE
```
```
-The token works everywhere a JWT would — the server auto-detects the `hbt_` prefix and validates accordingly.
+```json
+{ "type": "join", "streamId": 123, "token": "hbt_YOUR_TOKEN_HERE" }
+```
+
+The token works everywhere a JWT would — the server auto-detects the `hbt_` prefix and validates accordingly. A `?token=` query parameter still works but is deprecated (compatibility shim C-05): URLs end up in proxy logs and browser history, so move to the header or the `join` message.
## Managing Tokens
## Managing Tokens
@@ -108,11 +113,12 @@ const WebSocket = require('ws');
@@ -108,11 +113,12 @@ const WebSocket = require('ws');
const TOKEN = 'hbt_your_token_here';
const TOKEN = 'hbt_your_token_here';
const STREAM_ID = '123';
const STREAM_ID = '123';
-const ws = new WebSocket(
- `wss://openvibe.live/ws/chat?token=${TOKEN}&streamId=${STREAM_ID}`
-);
+const ws = new WebSocket(`wss://openvibe.live/ws/chat?stream=${STREAM_ID}`, {
+ headers: { Authorization: `Bearer ${TOKEN}` },
+});
ws.on('open', () => {
ws.on('open', () => {
+ ws.send(JSON.stringify({ type: 'join', streamId: Number(STREAM_ID) }));
console.log('Connected to chat');
console.log('Connected to chat');
});
});
@@ -92,8 +92,10 @@ Body: { "streamId": 123, "fromTime": "2024-01-01T00:00", "toTime": "2024-01-02T0
@@ -92,8 +92,10 @@ Body: { "streamId": 123, "fromTime": "2024-01-01T00:00", "toTime": "2024-01-02T0
### Connect
### Connect
```
```
-wss://openvibe.live/ws/chat?token=JWT_OR_API_TOKEN&streamId=123
+wss://openvibe.live/ws/chat?stream=123
+Authorization: Bearer JWT_OR_API_TOKEN (non-browser clients)
```
```
+Browsers send the token in the first `join` message instead (`{ "type": "join", "streamId": 123, "token": "…" }`); the `ov_token`/`token` cookies also authenticate the upgrade on the site's own origin. A `?token=` query parameter still works for older bots but is deprecated (C-05): URLs are logged.
### Message Types (Client → Server)
### Message Types (Client → Server)
| Type | Fields | Description |
| Type | Fields | Description |
@@ -96,7 +96,7 @@
@@ -96,7 +96,7 @@
<h3>Base URL & Auth</h3>
<h3>Base URL & Auth</h3>
<p>Base URL: <code>https://openvibe.live</code> (replace with your instance).</p>
<p>Base URL: <code>https://openvibe.live</code> (replace with your instance).</p>
-<p>Auth: <code>Authorization: Bearer <JWT></code> header, or <code>?token=JWT</code> query param on WebSocket URLs.</p>
+<p>Auth: <code>Authorization: Bearer <JWT></code> header. On WebSockets, the header on the upgrade request or the <code>token</code> of the first <code>join</code> message; a <code>?token=</code> query param still works but is deprecated (URLs are logged).</p>
<p>API tokens: <code>hbt_</code> prefix, scoped permissions, created from Dashboard → API Tokens.</p>
<p>API tokens: <code>hbt_</code> prefix, scoped permissions, created from Dashboard → API Tokens.</p>
</div>
</div>
@@ -168,7 +168,7 @@ openvibe.network /api/admin/streamer-mod/* → OpenVibe.Live /api/mod/*</code>
@@ -168,7 +168,7 @@ openvibe.network /api/admin/streamer-mod/* → OpenVibe.Live /api/mod/*</code>
<p><strong>All identity is OpenVibe SSO.</strong> There is no local password login on OpenVibe.Live — <code>POST /api/auth/register</code> and <code>POST /api/auth/login</code> are permanently disabled (return <code>410</code>). Humans sign in through openvibe.network OAuth2; OpenVibe.Live receives an <strong>RS256 JWT</strong> signed by openvibe.network and verifies it locally. For bots and scripts, use a long-lived <strong><code>hbt_</code> API token</strong> (below) — no browser login needed.</p>
<p><strong>All identity is OpenVibe SSO.</strong> There is no local password login on OpenVibe.Live — <code>POST /api/auth/register</code> and <code>POST /api/auth/login</code> are permanently disabled (return <code>410</code>). Humans sign in through openvibe.network OAuth2; OpenVibe.Live receives an <strong>RS256 JWT</strong> signed by openvibe.network and verifies it locally. For bots and scripts, use a long-lived <strong><code>hbt_</code> API token</strong> (below) — no browser login needed.</p>
<h3>How auth is sent</h3>
<h3>How auth is sent</h3>
-<p>Every authenticated request carries a token as <code>Authorization: Bearer <token></code> (also read from the <code>ov_token</code> cookie, or a <code>?token=</code> query param on WebSocket URLs). <code>requireAuth</code> accepts either:</p>
+<p>Every authenticated request carries a token as <code>Authorization: Bearer <token></code> (also read from the <code>ov_token</code> cookie; on WebSockets also from the first <code>join</code> message, and from a deprecated <code>?token=</code> query param). <code>requireAuth</code> accepts either:</p>
<ul>
<ul>
<li><strong>API token</strong> — a string starting with <code>hbt_</code>. Best for bots/integrations. Cannot itself create/list/revoke tokens.</li>
<li><strong>API token</strong> — a string starting with <code>hbt_</code>. Best for bots/integrations. Cannot itself create/list/revoke tokens.</li>
<li><strong>openvibe.network JWT (RS256)</strong> — from the SSO login flow; auto-links/creates a local account. Roles come from the token.</li>
<li><strong>openvibe.network JWT (RS256)</strong> — from the SSO login flow; auto-links/creates a local account. Roles come from the token.</li>
@@ -491,7 +491,7 @@ while True:
@@ -491,7 +491,7 @@ while True:
<table class="doc-table">
<table class="doc-table">
<thead><tr><th>Method</th><th>Path</th><th>Auth</th><th>Description</th></tr></thead>
<thead><tr><th>Method</th><th>Path</th><th>Auth</th><th>Description</th></tr></thead>
<tbody>
<tbody>
-<tr><td>POST</td><td>/api/chat/send</td><td>Yes</td><td>Send message via REST (fallback)</td></tr>
+<tr><td>POST</td><td>/api/chat/send</td><td>Yes</td><td>Post a message to global chat (bots; API tokens need the <code>chat</code> scope)</td></tr>
<tr><td>GET</td><td>/api/chat/:streamId/history</td><td>No</td><td>Chat history for a stream</td></tr>
<tr><td>GET</td><td>/api/chat/:streamId/history</td><td>No</td><td>Chat history for a stream</td></tr>
<tr><td>GET</td><td>/api/chat/:streamId/users</td><td>No</td><td>Users in a stream's chat</td></tr>
<tr><td>GET</td><td>/api/chat/:streamId/users</td><td>No</td><td>Users in a stream's chat</td></tr>
<tr><td>GET</td><td>/api/chat/user/:username/profile</td><td>No</td><td>User profile card data</td></tr>
<tr><td>GET</td><td>/api/chat/user/:username/profile</td><td>No</td><td>User profile card data</td></tr>
@@ -1237,7 +1237,7 @@ curl -s https://openvibe.media/live/@Goosely/chat-insight.json | jq ".chat_insig
@@ -1237,7 +1237,7 @@ curl -s https://openvibe.media/live/@Goosely/chat-insight.json | jq ".chat_insig
<table class="doc-table">
<table class="doc-table">
<thead><tr><th>Method</th><th>Path</th><th>Auth</th><th>Notes</th></tr></thead>
<thead><tr><th>Method</th><th>Path</th><th>Auth</th><th>Notes</th></tr></thead>
<tbody>
<tbody>
-<tr><td>POST</td><td>/api/chat/send</td><td>Yes</td><td>REST fallback to post a global chat message</td></tr>
+<tr><td>POST</td><td>/api/chat/send</td><td>Yes</td><td>Post a message to global chat (bots; API tokens need the <code>chat</code> scope)</td></tr>
<tr><td>GET</td><td>/api/chat/:streamId/history</td><td>Opt</td><td>Per-streamer history (all slots + offline unless <code>?scope=stream</code>)</td></tr>
<tr><td>GET</td><td>/api/chat/:streamId/history</td><td>Opt</td><td>Per-streamer history (all slots + offline unless <code>?scope=stream</code>)</td></tr>
<tr><td>GET</td><td>/api/chat/global/history</td><td>Opt</td><td>Global chat history</td></tr>
<tr><td>GET</td><td>/api/chat/global/history</td><td>Opt</td><td>Global chat history</td></tr>
<tr><td>GET</td><td>/api/chat/:streamId/replay</td><td>Opt</td><td>Chat replay for VOD/clip sync (<code>?from,to</code>)</td></tr>
<tr><td>GET</td><td>/api/chat/:streamId/replay</td><td>Opt</td><td>Chat replay for VOD/clip sync (<code>?from,to</code>)</td></tr>
@@ -6270,7 +6270,6 @@ function _connectMediaPipSocket() {
@@ -6270,7 +6270,6 @@ function _connectMediaPipSocket() {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const url = new URL(`${protocol}//${window.location.host}/ws/chat`);
const url = new URL(`${protocol}//${window.location.host}/ws/chat`);
const token = localStorage.getItem('token');
const token = localStorage.getItem('token');
- if (token) url.searchParams.set('token', token);
url.searchParams.set('stream', activeId);
url.searchParams.set('stream', activeId);
const ws = new WebSocket(url.toString());
const ws = new WebSocket(url.toString());
@@ -2629,9 +2629,8 @@ function initChat(streamId, channelUserId = null) {
@@ -2629,9 +2629,8 @@ function initChat(streamId, channelUserId = null) {
const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
const token = localStorage.getItem('token');
const token = localStorage.getItem('token');
- // Pass token and stream in URL so the server can authenticate on connect
+ // The stream goes in the URL; the token only in the join message (never in a URL, where proxies log it).
const params = new URLSearchParams();
const params = new URLSearchParams();
- if (token) params.set('token', token);
if (streamId) params.set('stream', streamId);
if (streamId) params.set('stream', streamId);
const wsUrl = `${protocol}://${host}:${port}/ws/chat?${params.toString()}`;
const wsUrl = `${protocol}://${host}:${port}/ws/chat?${params.toString()}`;
@@ -2793,7 +2792,6 @@ function _reconnectChatWs(streamId) {
@@ -2793,7 +2792,6 @@ function _reconnectChatWs(streamId) {
const token = localStorage.getItem('token');
const token = localStorage.getItem('token');
const params = new URLSearchParams();
const params = new URLSearchParams();
- if (token) params.set('token', token);
if (streamId) params.set('stream', streamId);
if (streamId) params.set('stream', streamId);
const wsUrl = `${protocol}://${host}:${port}/ws/chat?${params.toString()}`;
const wsUrl = `${protocol}://${host}:${port}/ws/chat?${params.toString()}`;
@@ -4286,9 +4284,10 @@ function sendChat(overrideInput = null) {
@@ -4286,9 +4284,10 @@ function sendChat(overrideInput = null) {
return;
return;
}
}
- // If WS is down (server restarting, etc.), send to global chat via REST API
+ // WS down (Chat restarting): the message stays in the box until the socket is back. It is never
+ // re-routed to another room (the REST send is a bot API, not a browser fallback).
if (!chatWs || chatWs.readyState !== WebSocket.OPEN) {
if (!chatWs || chatWs.readyState !== WebSocket.OPEN) {
- _sendChatViaRest(text, input);
+ addSystemMessage('Chat is reconnecting. Your message is still in the box: send it again in a moment.');
return;
return;
}
}
@@ -4338,49 +4337,6 @@ function sendChat(overrideInput = null) {
@@ -4338,49 +4337,6 @@ function sendChat(overrideInput = null) {
startSlowModeCooldown();
startSlowModeCooldown();
}
}
-/**
- * Fallback: send a chat message via REST API when the WebSocket is down.
- * The message goes to global chat so the user isn't silenced during reconnects.
- */
-async function _sendChatViaRest(text, input) {
- const token = localStorage.getItem('token');
- if (!token) {
- addSystemMessage('Chat disconnected — log in to send messages while reconnecting');
- return;
- }
- try {
- const autoDeleteMinutes = normalizeChatAutoDeleteMinutes(chatSettings.autoDeleteMinutes);
- const payload = { message: text, reply_to_id: _chatReplyTo?.id || undefined };
- if (autoDeleteMinutes >= (chatSelfDeletePolicy.minMinutes || CHAT_SELF_DELETE_MINUTES) && canUseViewerAutoDeleteHere()) {
- payload.auto_delete_minutes = autoDeleteMinutes;
- }
-
- const res = await fetch('/api/chat/send', {
- method: 'POST',
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(payload),
- });
- if (!res.ok) {
- const err = await res.json().catch(() => ({}));
- addSystemMessage(err.error || 'Failed to send message');
- return;
- }
- // Clear input on success
- input.value = '';
- _autoResizeTextarea(input);
- input.focus();
- clearChatReply();
- if (chatStreamId) {
- addSystemMessage('Sent to global chat (stream chat reconnecting)');
- }
- } catch {
- addSystemMessage('Server unreachable — message not sent');
- }
-}
-
/* ── Reply-to helpers ─────────────────────────────────────────── */
/* ── Reply-to helpers ─────────────────────────────────────────── */
/**
/**
@@ -6025,7 +5981,6 @@ function _openGlobalFeed() {
@@ -6025,7 +5981,6 @@ function _openGlobalFeed() {
const token = localStorage.getItem('token');
const token = localStorage.getItem('token');
const params = new URLSearchParams();
const params = new URLSearchParams();
- if (token) params.set('token', token);
// No stream param = global chat
// No stream param = global chat
const wsUrl = `${protocol}://${host}:${port}/ws/chat?${params.toString()}`;
const wsUrl = `${protocol}://${host}:${port}/ws/chat?${params.toString()}`;
const ws = new WebSocket(wsUrl);
const ws = new WebSocket(wsUrl);
@@ -840,7 +840,6 @@ function connectSocket() {
@@ -840,7 +840,6 @@ function connectSocket() {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const url = new URL(`${protocol}//${window.location.host}/ws/chat`);
const url = new URL(`${protocol}//${window.location.host}/ws/chat`);
- if (mpToken()) url.searchParams.set('token', mpToken());
url.searchParams.set('stream', mpLiveStream.id);
url.searchParams.set('stream', mpLiveStream.id);
const socket = new WebSocket(url.toString());
const socket = new WebSocket(url.toString());