@livedesk/hub 0.1.44 → 0.1.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/console-relay.js +12 -3
- package/src/server.js +19 -11
package/package.json
CHANGED
package/src/console-relay.js
CHANGED
|
@@ -107,9 +107,10 @@ export function createHubConsoleRelay(options = {}) {
|
|
|
107
107
|
let lastError = relayUrl instanceof URL ? '' : relayUrl === '' ? '' : 'invalid-relay-url';
|
|
108
108
|
let droppedBinaryMessages = 0;
|
|
109
109
|
|
|
110
|
-
const sendRelay = payload => {
|
|
110
|
+
const sendRelay = (payload, bypassBackpressure = false) => {
|
|
111
111
|
if (!relaySocket || relaySocket.readyState !== WebSocketImpl.OPEN) return false;
|
|
112
|
-
if (
|
|
112
|
+
if (!bypassBackpressure
|
|
113
|
+
&& Number(relaySocket.bufferedAmount || 0) > MAX_RELAY_BUFFERED_BYTES) return false;
|
|
113
114
|
relaySocket.send(typeof payload === 'string' || Buffer.isBuffer(payload) ? payload : JSON.stringify(payload));
|
|
114
115
|
return true;
|
|
115
116
|
};
|
|
@@ -232,6 +233,7 @@ export function createHubConsoleRelay(options = {}) {
|
|
|
232
233
|
if (!relaySocket || relaySocket.readyState !== WebSocketImpl.OPEN
|
|
233
234
|
|| Number(relaySocket.bufferedAmount || 0) > MAX_RELAY_BUFFERED_BYTES) {
|
|
234
235
|
droppedBinaryMessages += 1;
|
|
236
|
+
closeLocalSocket(key, 1013, 'console-relay-backpressure');
|
|
235
237
|
return;
|
|
236
238
|
}
|
|
237
239
|
const header = Buffer.from(`B${consoleId}${channelId}`, 'ascii');
|
|
@@ -246,7 +248,14 @@ export function createHubConsoleRelay(options = {}) {
|
|
|
246
248
|
});
|
|
247
249
|
socket.once('close', (code, reason) => {
|
|
248
250
|
if (localSockets.get(key) === socket) localSockets.delete(key);
|
|
249
|
-
|
|
251
|
+
const closeReason = String(reason || '').slice(0, 120);
|
|
252
|
+
// Do not silently punch a hole in an H.264 GOP. A tiny terminal control
|
|
253
|
+
// message is allowed behind the already-bounded video backlog so the
|
|
254
|
+
// browser replaces only this logical lane and starts again on a key.
|
|
255
|
+
sendRelay(
|
|
256
|
+
{ type: 'ws-closed', consoleId, channelId, code, reason: closeReason },
|
|
257
|
+
closeReason === 'console-relay-backpressure'
|
|
258
|
+
);
|
|
250
259
|
});
|
|
251
260
|
socket.once('error', error => {
|
|
252
261
|
sendError(consoleId, channelId, error instanceof Error ? error.message : error, 'ws-error');
|
package/src/server.js
CHANGED
|
@@ -513,11 +513,19 @@ async function getRuntimeAccessToken() {
|
|
|
513
513
|
const accessToken = String(runtimeAccessToken || '').trim();
|
|
514
514
|
const expiresSoon = runtimeAccessTokenExpiresAt > 0
|
|
515
515
|
&& runtimeAccessTokenExpiresAt <= Date.now() + HUB_ACCESS_TOKEN_REFRESH_SKEW_MS;
|
|
516
|
-
if (accessToken && !expiresSoon) {
|
|
517
|
-
return accessToken;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
|
|
516
|
+
if (accessToken && !expiresSoon) {
|
|
517
|
+
return accessToken;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// The packaged Electron main process owns the encrypted refresh token and
|
|
521
|
+
// proactively sends each rotation to this child runtime. A second refresh
|
|
522
|
+
// owner here could consume the one-time token first and make the desktop
|
|
523
|
+
// shell appear signed out after sleep.
|
|
524
|
+
if (desktopMainAuthConfig) {
|
|
525
|
+
return accessToken;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const refreshToken = String(runtimeRefreshToken || '').trim();
|
|
521
529
|
if (!refreshToken) {
|
|
522
530
|
return accessToken;
|
|
523
531
|
}
|
|
@@ -621,9 +629,9 @@ async function queryAuthoritativeRuntimeRole() {
|
|
|
621
629
|
},
|
|
622
630
|
SUPABASE_AUTH_TIMEOUT_MS
|
|
623
631
|
);
|
|
624
|
-
if (response.status === 401 || response.status === 403) {
|
|
625
|
-
clearRuntimeSession();
|
|
626
|
-
throw new Error(`hub-role-query-not-authenticated:${response.status}`);
|
|
632
|
+
if (response.status === 401 || response.status === 403) {
|
|
633
|
+
if (!desktopMainAuthConfig) clearRuntimeSession();
|
|
634
|
+
throw new Error(`hub-role-query-not-authenticated:${response.status}`);
|
|
627
635
|
}
|
|
628
636
|
if (!response.ok) {
|
|
629
637
|
throw new Error(`hub-role-query-failed:${response.status}`);
|
|
@@ -4601,9 +4609,9 @@ async function callHubSupabaseRpc(name, payload, accessToken) {
|
|
|
4601
4609
|
);
|
|
4602
4610
|
const data = await response.json().catch(() => null);
|
|
4603
4611
|
const result = Array.isArray(data) ? data[0] : data;
|
|
4604
|
-
if (response.status === 401 || response.status === 403) {
|
|
4605
|
-
clearRuntimeSession();
|
|
4606
|
-
throw new Error(`${name}-not-authenticated:${response.status}`);
|
|
4612
|
+
if (response.status === 401 || response.status === 403) {
|
|
4613
|
+
if (!desktopMainAuthConfig) clearRuntimeSession();
|
|
4614
|
+
throw new Error(`${name}-not-authenticated:${response.status}`);
|
|
4607
4615
|
}
|
|
4608
4616
|
if (!response.ok) {
|
|
4609
4617
|
throw new Error(`${name}-failed:${response.status}`);
|