@livedesk/hub 0.1.45 → 0.1.47
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/agents/agent-result-enrichment.js +66 -66
- package/src/agents/codex-agent-runtime.js +4 -4
- package/src/console-relay.js +424 -424
- package/src/live-desk-update.js +24 -24
- package/src/remote-hub.js +6 -4
- package/src/server.js +83 -75
- package/src/settings/settings-schema.js +3 -2
package/src/live-desk-update.js
CHANGED
|
@@ -241,11 +241,11 @@ function resetReconnectCandidate(target) {
|
|
|
241
241
|
target.stabilityDeadlineAt = '';
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
export function createLiveDeskUpdateManager({
|
|
245
|
-
remoteHub,
|
|
246
|
-
currentManagerVersion,
|
|
247
|
-
currentClientVersion,
|
|
248
|
-
excludedDeviceIds = [],
|
|
244
|
+
export function createLiveDeskUpdateManager({
|
|
245
|
+
remoteHub,
|
|
246
|
+
currentManagerVersion,
|
|
247
|
+
currentClientVersion,
|
|
248
|
+
excludedDeviceIds = [],
|
|
249
249
|
restartSupported = false,
|
|
250
250
|
requestHubRestart,
|
|
251
251
|
fetchImpl = globalThis.fetch,
|
|
@@ -261,16 +261,16 @@ export function createLiveDeskUpdateManager({
|
|
|
261
261
|
let checkPromise = null;
|
|
262
262
|
let run = null;
|
|
263
263
|
let checkTimer = null;
|
|
264
|
-
let runTimer = null;
|
|
265
|
-
const excludedDeviceIdSet = new Set(
|
|
266
|
-
(Array.isArray(excludedDeviceIds) ? excludedDeviceIds : [excludedDeviceIds])
|
|
267
|
-
.map(value => String(value || '').trim())
|
|
268
|
-
.filter(Boolean)
|
|
269
|
-
);
|
|
270
|
-
const connectedClientDevices = () => connectedDevices(remoteHub)
|
|
271
|
-
.filter(device => !excludedDeviceIdSet.has(String(device?.deviceId || '')));
|
|
272
|
-
const knownOfflineClientDevices = () => knownOfflineDevices(remoteHub)
|
|
273
|
-
.filter(device => !excludedDeviceIdSet.has(String(device?.deviceId || '')));
|
|
264
|
+
let runTimer = null;
|
|
265
|
+
const excludedDeviceIdSet = new Set(
|
|
266
|
+
(Array.isArray(excludedDeviceIds) ? excludedDeviceIds : [excludedDeviceIds])
|
|
267
|
+
.map(value => String(value || '').trim())
|
|
268
|
+
.filter(Boolean)
|
|
269
|
+
);
|
|
270
|
+
const connectedClientDevices = () => connectedDevices(remoteHub)
|
|
271
|
+
.filter(device => !excludedDeviceIdSet.has(String(device?.deviceId || '')));
|
|
272
|
+
const knownOfflineClientDevices = () => knownOfflineDevices(remoteHub)
|
|
273
|
+
.filter(device => !excludedDeviceIdSet.has(String(device?.deviceId || '')));
|
|
274
274
|
const effectiveClientBatchSize = Math.max(
|
|
275
275
|
1,
|
|
276
276
|
Math.min(50, Math.floor(Number(clientBatchSize) || LIVE_DESK_UPDATE_CLIENT_BATCH_SIZE))
|
|
@@ -321,7 +321,7 @@ export function createLiveDeskUpdateManager({
|
|
|
321
321
|
const getStatus = () => {
|
|
322
322
|
const managerUpdateAvailable = !!latestRelease
|
|
323
323
|
&& compareVersions(latestRelease.latestManagerVersion, currentManagerVersion) > 0;
|
|
324
|
-
const clientDevices = connectedClientDevices();
|
|
324
|
+
const clientDevices = connectedClientDevices();
|
|
325
325
|
const outdatedClientDevices = latestRelease
|
|
326
326
|
? clientDevices.filter(device => deviceNeedsUpdate(
|
|
327
327
|
device,
|
|
@@ -330,7 +330,7 @@ export function createLiveDeskUpdateManager({
|
|
|
330
330
|
))
|
|
331
331
|
: [];
|
|
332
332
|
const pendingOfflineClientCount = latestRelease
|
|
333
|
-
? knownOfflineClientDevices().filter(device => deviceNeedsUpdate(
|
|
333
|
+
? knownOfflineClientDevices().filter(device => deviceNeedsUpdate(
|
|
334
334
|
device,
|
|
335
335
|
latestRelease.latestManagerVersion,
|
|
336
336
|
latestRelease.latestClientVersion
|
|
@@ -414,9 +414,9 @@ export function createLiveDeskUpdateManager({
|
|
|
414
414
|
if (!run || run.state !== 'failed') return [];
|
|
415
415
|
const currentTime = now();
|
|
416
416
|
const devices = new Map(
|
|
417
|
-
remoteHub.listDevices({ includeDataUrl: false })
|
|
418
|
-
.filter(device => !excludedDeviceIdSet.has(String(device?.deviceId || '')))
|
|
419
|
-
.map(device => [String(device.deviceId), device])
|
|
417
|
+
remoteHub.listDevices({ includeDataUrl: false })
|
|
418
|
+
.filter(device => !excludedDeviceIdSet.has(String(device?.deviceId || '')))
|
|
419
|
+
.map(device => [String(device.deviceId), device])
|
|
420
420
|
);
|
|
421
421
|
return run.targets.filter(target => {
|
|
422
422
|
if (target.state !== 'failed' || !target.dispatchedAt) return false;
|
|
@@ -523,7 +523,7 @@ export function createLiveDeskUpdateManager({
|
|
|
523
523
|
const activeCount = run.targets.filter(target => target.state === 'waiting').length;
|
|
524
524
|
let availableSlots = Math.max(0, run.batchSize - activeCount);
|
|
525
525
|
if (availableSlots <= 0) return true;
|
|
526
|
-
const devices = new Map(connectedClientDevices().map(device => [String(device.deviceId), device]));
|
|
526
|
+
const devices = new Map(connectedClientDevices().map(device => [String(device.deviceId), device]));
|
|
527
527
|
for (const target of run.targets) {
|
|
528
528
|
if (availableSlots <= 0) break;
|
|
529
529
|
if (!['queued', 'pending-offline'].includes(target.state)) continue;
|
|
@@ -562,7 +562,7 @@ export function createLiveDeskUpdateManager({
|
|
|
562
562
|
failRun(`Timed out waiting for ${unfinishedCount} client(s) to finish the rollout.`);
|
|
563
563
|
return;
|
|
564
564
|
}
|
|
565
|
-
const devices = new Map(connectedClientDevices().map(device => [String(device.deviceId), device]));
|
|
565
|
+
const devices = new Map(connectedClientDevices().map(device => [String(device.deviceId), device]));
|
|
566
566
|
for (const target of run.targets) {
|
|
567
567
|
if (target.state === 'failed' || target.state === 'completed') continue;
|
|
568
568
|
const device = devices.get(target.deviceId);
|
|
@@ -689,7 +689,7 @@ export function createLiveDeskUpdateManager({
|
|
|
689
689
|
if (!release) return { ok: false, error: checkError || 'LiveDesk update check failed.', ...getStatus() };
|
|
690
690
|
const managerNeedsUpdate = compareVersions(release.latestManagerVersion, currentManagerVersion) > 0;
|
|
691
691
|
const clientPackageNeedsUpdate = compareVersions(release.latestClientVersion, currentClientVersion) > 0;
|
|
692
|
-
const connected = connectedClientDevices();
|
|
692
|
+
const connected = connectedClientDevices();
|
|
693
693
|
const outdatedClients = connected.filter(device => deviceNeedsUpdate(
|
|
694
694
|
device,
|
|
695
695
|
release.latestManagerVersion,
|
|
@@ -790,7 +790,7 @@ export function createLiveDeskUpdateManager({
|
|
|
790
790
|
if (target.method === 'dedicated'
|
|
791
791
|
&& target.bootstrapRetryCount === 0
|
|
792
792
|
&& isDedicatedBootstrapFailure(failure)) {
|
|
793
|
-
const retryDevice = connectedClientDevices()
|
|
793
|
+
const retryDevice = connectedClientDevices()
|
|
794
794
|
.find(device => String(device.deviceId || '') === target.deviceId);
|
|
795
795
|
const remainingMs = Date.parse(target.deadlineAt || '') - now();
|
|
796
796
|
if (retryDevice?.connected === true && remainingMs >= 10_000) {
|
package/src/remote-hub.js
CHANGED
|
@@ -1164,10 +1164,12 @@ function normalizeRemoteKeyboardKey(value) {
|
|
|
1164
1164
|
return raw === ' ' ? ' ' : safeString(raw, 80);
|
|
1165
1165
|
}
|
|
1166
1166
|
|
|
1167
|
-
function normalizeRemoteKeyboardText(value) {
|
|
1168
|
-
const raw = String(value ?? '').replace(/\0/g, '');
|
|
1169
|
-
|
|
1170
|
-
|
|
1167
|
+
function normalizeRemoteKeyboardText(value) {
|
|
1168
|
+
const raw = String(value ?? '').replace(/\0/g, '');
|
|
1169
|
+
// Remote text is input data, not a label. Preserve leading/trailing spaces
|
|
1170
|
+
// and IME whitespace while keeping every ordered message bounded.
|
|
1171
|
+
return raw.slice(0, 256);
|
|
1172
|
+
}
|
|
1171
1173
|
|
|
1172
1174
|
function safeTaskData(value) {
|
|
1173
1175
|
if (value === undefined || value === null) return undefined;
|
package/src/server.js
CHANGED
|
@@ -7,9 +7,9 @@ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, wri
|
|
|
7
7
|
import { dirname, resolve } from 'node:path';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import os from 'node:os';
|
|
10
|
-
import { WebSocketServer } from 'ws';
|
|
11
|
-
import { createRemoteHub } from './remote-hub.js';
|
|
12
|
-
import { createHubConsoleRelay } from './console-relay.js';
|
|
10
|
+
import { WebSocketServer } from 'ws';
|
|
11
|
+
import { createRemoteHub } from './remote-hub.js';
|
|
12
|
+
import { createHubConsoleRelay } from './console-relay.js';
|
|
13
13
|
import {
|
|
14
14
|
buildImmutableRemoteFramePacket,
|
|
15
15
|
createRemoteFramePacketMetrics,
|
|
@@ -40,9 +40,9 @@ import { createAgentDeviceScope, resolveAgentTargetIds } from './agents/agent-de
|
|
|
40
40
|
import { AgentRuntimeError } from './agents/agent-runtime-error.js';
|
|
41
41
|
import { AGENT_PERMISSION_MODES, createAgentPermissionPolicy, evaluateAgentToolPermission, hashAgentPermissionPolicy } from './agents/agent-permissions.js';
|
|
42
42
|
import { createAgentPermissionStore } from './agents/agent-permission-store.js';
|
|
43
|
-
import { createAgentAuditStore } from './agents/agent-audit-store.js';
|
|
44
|
-
import { getAgentToolDefinition } from './agents/agent-tool-registry.js';
|
|
45
|
-
import { enrichAgentTaskResults } from './agents/agent-result-enrichment.js';
|
|
43
|
+
import { createAgentAuditStore } from './agents/agent-audit-store.js';
|
|
44
|
+
import { getAgentToolDefinition } from './agents/agent-tool-registry.js';
|
|
45
|
+
import { enrichAgentTaskResults } from './agents/agent-result-enrichment.js';
|
|
46
46
|
import { LiveDeskSettingsStore, SettingsConflictError } from './settings/settings-store.js';
|
|
47
47
|
import { effectiveDevicePolicy } from './settings/settings-schema.js';
|
|
48
48
|
import { buildEffectiveDevicePolicy } from './settings/effective-device-policy.js';
|
|
@@ -204,22 +204,22 @@ let verifiedLicense = {
|
|
|
204
204
|
let frameClientSeq = 0;
|
|
205
205
|
let inputClientSeq = 0;
|
|
206
206
|
let audioClientSeq = 0;
|
|
207
|
-
let liveDeskUpdateManager = null;
|
|
208
|
-
let hubTransferJobs = null;
|
|
209
|
-
let hubConsoleRelay = null;
|
|
207
|
+
let liveDeskUpdateManager = null;
|
|
208
|
+
let hubTransferJobs = null;
|
|
209
|
+
let hubConsoleRelay = null;
|
|
210
210
|
const HUB_HOST_TARGET_LEASE_MS = Math.max(5000, readPositiveIntegerEnv('LIVEDESK_HOST_TARGET_LEASE_MS', 60_000));
|
|
211
211
|
const HUB_HOST_TARGET_RENEW_MS = Math.max(1000, Math.min(
|
|
212
212
|
readPositiveIntegerEnv('LIVEDESK_HOST_TARGET_RENEW_MS', 20_000),
|
|
213
213
|
Math.max(1000, HUB_HOST_TARGET_LEASE_MS - 1000)
|
|
214
214
|
));
|
|
215
|
-
const HUB_ACCESS_TOKEN_REFRESH_SKEW_MS = 90_000;
|
|
216
|
-
const hubWakeBaseUrl = String(process.env.LIVEDESK_WAKE_URL || 'https://livedesk-wake.lovecrdm.workers.dev').trim();
|
|
217
|
-
const hubConsoleRelayBaseUrl = String(
|
|
218
|
-
process.env.LIVEDESK_CONSOLE_RELAY_URL
|
|
219
|
-
|| (process.env.LIVEDESK_TEST_MODE === '1' || process.env.LIVEDESK_AUTH_TEST_MODE === '1'
|
|
220
|
-
? 'off'
|
|
221
|
-
: 'https://livedesk-wake.lovecrdm.workers.dev')
|
|
222
|
-
).trim();
|
|
215
|
+
const HUB_ACCESS_TOKEN_REFRESH_SKEW_MS = 90_000;
|
|
216
|
+
const hubWakeBaseUrl = String(process.env.LIVEDESK_WAKE_URL || 'https://livedesk-wake.lovecrdm.workers.dev').trim();
|
|
217
|
+
const hubConsoleRelayBaseUrl = String(
|
|
218
|
+
process.env.LIVEDESK_CONSOLE_RELAY_URL
|
|
219
|
+
|| (process.env.LIVEDESK_TEST_MODE === '1' || process.env.LIVEDESK_AUTH_TEST_MODE === '1'
|
|
220
|
+
? 'off'
|
|
221
|
+
: 'https://livedesk-wake.lovecrdm.workers.dev')
|
|
222
|
+
).trim();
|
|
223
223
|
const HUB_WAKE_NOTIFY_RETRY_MS = 60_000;
|
|
224
224
|
let hubHostTargetRenewTimer = null;
|
|
225
225
|
let hubHostTargetRenewInFlight = false;
|
|
@@ -517,6 +517,14 @@ async function getRuntimeAccessToken() {
|
|
|
517
517
|
return accessToken;
|
|
518
518
|
}
|
|
519
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
|
+
|
|
520
528
|
const refreshToken = String(runtimeRefreshToken || '').trim();
|
|
521
529
|
if (!refreshToken) {
|
|
522
530
|
return accessToken;
|
|
@@ -622,7 +630,7 @@ async function queryAuthoritativeRuntimeRole() {
|
|
|
622
630
|
SUPABASE_AUTH_TIMEOUT_MS
|
|
623
631
|
);
|
|
624
632
|
if (response.status === 401 || response.status === 403) {
|
|
625
|
-
clearRuntimeSession();
|
|
633
|
+
if (!desktopMainAuthConfig) clearRuntimeSession();
|
|
626
634
|
throw new Error(`hub-role-query-not-authenticated:${response.status}`);
|
|
627
635
|
}
|
|
628
636
|
if (!response.ok) {
|
|
@@ -805,12 +813,12 @@ function getLiveDeskUpdateStatus() {
|
|
|
805
813
|
}
|
|
806
814
|
|
|
807
815
|
if (process.env.LIVEDESK_DESKTOP_HOST !== '1') {
|
|
808
|
-
liveDeskUpdateManager = createLiveDeskUpdateManager({
|
|
809
|
-
remoteHub,
|
|
810
|
-
currentManagerVersion: process.env.LIVEDESK_MANAGER_VERSION || packageInfo.version,
|
|
811
|
-
currentClientVersion: process.env.LIVEDESK_CLIENT_PACKAGE_VERSION || '',
|
|
812
|
-
excludedDeviceIds: [runtimeDeviceId],
|
|
813
|
-
restartSupported: !!String(process.env.LIVEDESK_HUB_UPDATE_REQUEST_PATH || '').trim(),
|
|
816
|
+
liveDeskUpdateManager = createLiveDeskUpdateManager({
|
|
817
|
+
remoteHub,
|
|
818
|
+
currentManagerVersion: process.env.LIVEDESK_MANAGER_VERSION || packageInfo.version,
|
|
819
|
+
currentClientVersion: process.env.LIVEDESK_CLIENT_PACKAGE_VERSION || '',
|
|
820
|
+
excludedDeviceIds: [runtimeDeviceId],
|
|
821
|
+
restartSupported: !!String(process.env.LIVEDESK_HUB_UPDATE_REQUEST_PATH || '').trim(),
|
|
814
822
|
requestHubRestart
|
|
815
823
|
});
|
|
816
824
|
}
|
|
@@ -1270,16 +1278,16 @@ async function dispatchAgentMcpTool(session, name, args = {}) {
|
|
|
1270
1278
|
remoteHub.cancelTaskBatch(result.batchId);
|
|
1271
1279
|
return { ok: false, error: 'cancelled-by-user', batchId: result.batchId };
|
|
1272
1280
|
}
|
|
1273
|
-
const batch = remoteHub.getTaskBatch(result.batchId);
|
|
1274
|
-
if (!batch) return { ok: false, error: 'task-not-found', batchId: result.batchId };
|
|
1275
|
-
if (!['queued', 'running'].includes(batch.status)) {
|
|
1276
|
-
const taskResults = enrichAgentTaskResults({
|
|
1277
|
-
operation,
|
|
1278
|
-
results: batch.results,
|
|
1279
|
-
devices: remoteHub.listDevices({ includeDataUrl: false })
|
|
1280
|
-
.filter(device => targetIds.includes(device.deviceId))
|
|
1281
|
-
});
|
|
1282
|
-
return {
|
|
1281
|
+
const batch = remoteHub.getTaskBatch(result.batchId);
|
|
1282
|
+
if (!batch) return { ok: false, error: 'task-not-found', batchId: result.batchId };
|
|
1283
|
+
if (!['queued', 'running'].includes(batch.status)) {
|
|
1284
|
+
const taskResults = enrichAgentTaskResults({
|
|
1285
|
+
operation,
|
|
1286
|
+
results: batch.results,
|
|
1287
|
+
devices: remoteHub.listDevices({ includeDataUrl: false })
|
|
1288
|
+
.filter(device => targetIds.includes(device.deviceId))
|
|
1289
|
+
});
|
|
1290
|
+
return {
|
|
1283
1291
|
ok: true,
|
|
1284
1292
|
batchId: result.batchId,
|
|
1285
1293
|
operation,
|
|
@@ -1287,8 +1295,8 @@ async function dispatchAgentMcpTool(session, name, args = {}) {
|
|
|
1287
1295
|
total: batch.total,
|
|
1288
1296
|
completed: batch.completed,
|
|
1289
1297
|
failed: batch.failed,
|
|
1290
|
-
results: taskResults.map(item => ({ deviceId: item.deviceId, deviceName: item.deviceName, status: item.status, stage: item.stage, result: String(item.result || '').slice(0, 3000), data: item.data, error: String(item.error || '').slice(0, 500) }))
|
|
1291
|
-
};
|
|
1298
|
+
results: taskResults.map(item => ({ deviceId: item.deviceId, deviceName: item.deviceName, status: item.status, stage: item.stage, result: String(item.result || '').slice(0, 3000), data: item.data, error: String(item.error || '').slice(0, 500) }))
|
|
1299
|
+
};
|
|
1292
1300
|
}
|
|
1293
1301
|
await delayAgentMcp(200);
|
|
1294
1302
|
}
|
|
@@ -1348,16 +1356,16 @@ const hubSharedFolders = createHubSharedFolders({
|
|
|
1348
1356
|
dataDir: agentDataDir
|
|
1349
1357
|
});
|
|
1350
1358
|
|
|
1351
|
-
const app = express();
|
|
1352
|
-
const httpServer = createServer(app);
|
|
1353
|
-
hubConsoleRelay = createHubConsoleRelay({
|
|
1354
|
-
url: runtimeRole === 'hub' ? hubConsoleRelayBaseUrl : 'off',
|
|
1355
|
-
deviceId: runtimeDeviceId,
|
|
1356
|
-
httpBaseUrl: `http://127.0.0.1:${httpPort}`,
|
|
1357
|
-
getAccessToken: () => getRuntimeAccessToken(),
|
|
1358
|
-
logger: console
|
|
1359
|
-
});
|
|
1360
|
-
const httpConnections = new Set();
|
|
1359
|
+
const app = express();
|
|
1360
|
+
const httpServer = createServer(app);
|
|
1361
|
+
hubConsoleRelay = createHubConsoleRelay({
|
|
1362
|
+
url: runtimeRole === 'hub' ? hubConsoleRelayBaseUrl : 'off',
|
|
1363
|
+
deviceId: runtimeDeviceId,
|
|
1364
|
+
httpBaseUrl: `http://127.0.0.1:${httpPort}`,
|
|
1365
|
+
getAccessToken: () => getRuntimeAccessToken(),
|
|
1366
|
+
logger: console
|
|
1367
|
+
});
|
|
1368
|
+
const httpConnections = new Set();
|
|
1361
1369
|
const frameWss = new WebSocketServer({ noServer: true, perMessageDeflate: false });
|
|
1362
1370
|
const atlasWss = new WebSocketServer({ noServer: true, perMessageDeflate: false });
|
|
1363
1371
|
const inputWss = new WebSocketServer({ noServer: true, perMessageDeflate: false });
|
|
@@ -4241,10 +4249,10 @@ app.get('/api/remote/status', (_req, res) => {
|
|
|
4241
4249
|
runtimeRole,
|
|
4242
4250
|
deviceId: runtimeDeviceId,
|
|
4243
4251
|
deviceName: runtimeDeviceName,
|
|
4244
|
-
roleSource: runtimeRoleSource,
|
|
4245
|
-
agentPackage: '@livedesk/client',
|
|
4246
|
-
consoleRelay: hubConsoleRelay?.inspect() || { enabled: false, state: 'starting' },
|
|
4247
|
-
frameLanes: snapshotFrameLaneResourceHealth(),
|
|
4252
|
+
roleSource: runtimeRoleSource,
|
|
4253
|
+
agentPackage: '@livedesk/client',
|
|
4254
|
+
consoleRelay: hubConsoleRelay?.inspect() || { enabled: false, state: 'starting' },
|
|
4255
|
+
frameLanes: snapshotFrameLaneResourceHealth(),
|
|
4248
4256
|
update: getLiveDeskUpdateStatus()
|
|
4249
4257
|
});
|
|
4250
4258
|
});
|
|
@@ -4476,11 +4484,11 @@ app.post('/api/auth/session', async (req, res) => {
|
|
|
4476
4484
|
csrfToken: uiSession.csrfToken,
|
|
4477
4485
|
expiresAt: uiSession.expiresAt
|
|
4478
4486
|
}
|
|
4479
|
-
});
|
|
4480
|
-
if (runtimeRole === 'hub') {
|
|
4481
|
-
hubConsoleRelay?.refresh();
|
|
4482
|
-
scheduleAuthenticatedHubHostTargetPublication('session-received');
|
|
4483
|
-
}
|
|
4487
|
+
});
|
|
4488
|
+
if (runtimeRole === 'hub') {
|
|
4489
|
+
hubConsoleRelay?.refresh();
|
|
4490
|
+
scheduleAuthenticatedHubHostTargetPublication('session-received');
|
|
4491
|
+
}
|
|
4484
4492
|
} catch (error) {
|
|
4485
4493
|
const message = error instanceof Error ? error.message : String(error);
|
|
4486
4494
|
const status = authVerificationHttpStatus(message);
|
|
@@ -4500,11 +4508,11 @@ function getHubHostTargetLeaseStatus() {
|
|
|
4500
4508
|
...hubHostTargetLeaseState,
|
|
4501
4509
|
renewing: hubHostTargetRenewInFlight,
|
|
4502
4510
|
renewalIntervalMs: HUB_HOST_TARGET_RENEW_MS,
|
|
4503
|
-
leaseDurationMs: HUB_HOST_TARGET_LEASE_MS,
|
|
4504
|
-
authenticated: Boolean(runtimeAccessToken),
|
|
4505
|
-
timerActive: Boolean(hubHostTargetRenewTimer),
|
|
4506
|
-
wake: { ...hubWakeNotificationState },
|
|
4507
|
-
consoleRelay: hubConsoleRelay?.inspect() || { enabled: false, state: 'starting' }
|
|
4511
|
+
leaseDurationMs: HUB_HOST_TARGET_LEASE_MS,
|
|
4512
|
+
authenticated: Boolean(runtimeAccessToken),
|
|
4513
|
+
timerActive: Boolean(hubHostTargetRenewTimer),
|
|
4514
|
+
wake: { ...hubWakeNotificationState },
|
|
4515
|
+
consoleRelay: hubConsoleRelay?.inspect() || { enabled: false, state: 'starting' }
|
|
4508
4516
|
};
|
|
4509
4517
|
}
|
|
4510
4518
|
|
|
@@ -4602,7 +4610,7 @@ async function callHubSupabaseRpc(name, payload, accessToken) {
|
|
|
4602
4610
|
const data = await response.json().catch(() => null);
|
|
4603
4611
|
const result = Array.isArray(data) ? data[0] : data;
|
|
4604
4612
|
if (response.status === 401 || response.status === 403) {
|
|
4605
|
-
clearRuntimeSession();
|
|
4613
|
+
if (!desktopMainAuthConfig) clearRuntimeSession();
|
|
4606
4614
|
throw new Error(`${name}-not-authenticated:${response.status}`);
|
|
4607
4615
|
}
|
|
4608
4616
|
if (!response.ok) {
|
|
@@ -4808,11 +4816,11 @@ app.get('/api/hub/status', (_req, res) => {
|
|
|
4808
4816
|
...remoteHub.getStatus({ includeSecrets: false }),
|
|
4809
4817
|
role: 'hub',
|
|
4810
4818
|
deviceId: runtimeDeviceId,
|
|
4811
|
-
deviceName: runtimeDeviceName,
|
|
4812
|
-
roleSource: runtimeRoleSource,
|
|
4813
|
-
runtimeStarted: true,
|
|
4814
|
-
consoleRelay: hubConsoleRelay?.inspect() || { enabled: false, state: 'starting' },
|
|
4815
|
-
hostTargetLease: getHubHostTargetLeaseStatus(),
|
|
4819
|
+
deviceName: runtimeDeviceName,
|
|
4820
|
+
roleSource: runtimeRoleSource,
|
|
4821
|
+
runtimeStarted: true,
|
|
4822
|
+
consoleRelay: hubConsoleRelay?.inspect() || { enabled: false, state: 'starting' },
|
|
4823
|
+
hostTargetLease: getHubHostTargetLeaseStatus(),
|
|
4816
4824
|
update: getLiveDeskUpdateStatus()
|
|
4817
4825
|
});
|
|
4818
4826
|
});
|
|
@@ -5819,14 +5827,14 @@ hubSharedFolders.startAutoSync(
|
|
|
5819
5827
|
() => remoteHub.listDevices({ includeDataUrl: false }).filter(device => device.connected).map(device => device.deviceId),
|
|
5820
5828
|
() => process.env.LIVEDESK_REMOTE_DIRECTORY || 'Desktop/LiveDeskFiles'
|
|
5821
5829
|
);
|
|
5822
|
-
httpServer.listen(httpPort, httpHost, () => {
|
|
5830
|
+
httpServer.listen(httpPort, httpHost, () => {
|
|
5823
5831
|
const status = remoteHub.getStatus({ includeSecrets: true });
|
|
5824
5832
|
const managerVersion = String(process.env.LIVEDESK_MANAGER_VERSION || packageInfo.version || 'dev');
|
|
5825
5833
|
console.log(`[LiveDesk Hub] Version ${managerVersion}`);
|
|
5826
|
-
console.log(`[LiveDesk Hub] HTTP API http://${httpHost}:${httpPort}`);
|
|
5827
|
-
console.log(`[LiveDesk Hub] Client endpoint ${status.agentEndpoint} pair=${status.pairTokenPreview}`);
|
|
5828
|
-
hubConsoleRelay?.start();
|
|
5829
|
-
});
|
|
5834
|
+
console.log(`[LiveDesk Hub] HTTP API http://${httpHost}:${httpPort}`);
|
|
5835
|
+
console.log(`[LiveDesk Hub] Client endpoint ${status.agentEndpoint} pair=${status.pairTokenPreview}`);
|
|
5836
|
+
hubConsoleRelay?.start();
|
|
5837
|
+
});
|
|
5830
5838
|
|
|
5831
5839
|
const roleWatchTimer = runtimeRole === 'hub'
|
|
5832
5840
|
? setInterval(() => { void watchAuthoritativeRuntimeRole(); }, 5000)
|
|
@@ -5907,10 +5915,10 @@ function shutdownHub(signal) {
|
|
|
5907
5915
|
const startedAt = Date.now();
|
|
5908
5916
|
console.log(`[LiveDesk Hub] Shutdown started signal=${signal} grace=${hubShutdownGraceMs}ms timeout=${hubShutdownTimeoutMs}ms.`);
|
|
5909
5917
|
if (roleWatchTimer) clearInterval(roleWatchTimer);
|
|
5910
|
-
clearInterval(browserWebSocketHeartbeatTimer);
|
|
5911
|
-
runSynchronousShutdownStep('update manager close', () => liveDeskUpdateManager?.close());
|
|
5912
|
-
runSynchronousShutdownStep('mobile console relay close', () => hubConsoleRelay?.close());
|
|
5913
|
-
atlasClients.clear();
|
|
5918
|
+
clearInterval(browserWebSocketHeartbeatTimer);
|
|
5919
|
+
runSynchronousShutdownStep('update manager close', () => liveDeskUpdateManager?.close());
|
|
5920
|
+
runSynchronousShutdownStep('mobile console relay close', () => hubConsoleRelay?.close());
|
|
5921
|
+
atlasClients.clear();
|
|
5914
5922
|
runSynchronousShutdownStep('shared folder close', () => hubSharedFolders.close());
|
|
5915
5923
|
|
|
5916
5924
|
const httpClosed = new Promise(resolveClose => {
|
|
@@ -13,7 +13,8 @@ export const DEFAULT_LIVEDESK_SETTINGS = Object.freeze({
|
|
|
13
13
|
approveNewDevices: true,
|
|
14
14
|
startWithComputer: true,
|
|
15
15
|
keepRunningInTray: true,
|
|
16
|
-
showConnectionNotifications: true
|
|
16
|
+
showConnectionNotifications: true,
|
|
17
|
+
showThisComputer: false
|
|
17
18
|
},
|
|
18
19
|
security: {
|
|
19
20
|
accessMode: 'trusted-only',
|
|
@@ -157,7 +158,7 @@ const numbers = (entries) => Object.fromEntries(entries.map(([key, min, max]) =>
|
|
|
157
158
|
|
|
158
159
|
const RULES = {
|
|
159
160
|
connection: {
|
|
160
|
-
...bools(['usePinToAddDevices', 'rotatePinAfterPairing', 'allowNewDevices', 'approveNewDevices', 'startWithComputer', 'keepRunningInTray', 'showConnectionNotifications']),
|
|
161
|
+
...bools(['usePinToAddDevices', 'rotatePinAfterPairing', 'allowNewDevices', 'approveNewDevices', 'startWithComputer', 'keepRunningInTray', 'showConnectionNotifications', 'showThisComputer']),
|
|
161
162
|
...numbers([['pinValidityMinutes', 10, 1440]])
|
|
162
163
|
},
|
|
163
164
|
security: {
|