@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.
@@ -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
- return raw === ' ' ? ' ' : safeText(raw, 256);
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: {