@livedesk/hub 0.1.41 → 0.1.43

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/src/remote-hub.js CHANGED
@@ -286,7 +286,7 @@ function normalizePort(value) {
286
286
  return clampNumber(value, 0, 65535, DEFAULT_REMOTE_HUB_PORT);
287
287
  }
288
288
 
289
- function safeString(value, maxLength = 200) {
289
+ function safeString(value, maxLength = 200) {
290
290
  return String(value ?? '').replace(/[\r\n\t]/g, ' ').trim().slice(0, maxLength);
291
291
  }
292
292
 
@@ -1119,55 +1119,55 @@ function getAccountRouteEndpointReason(endpoint, context = {}) {
1119
1119
  return 'ok';
1120
1120
  }
1121
1121
 
1122
- function safeText(value, maxLength = 1000) {
1123
- return String(value ?? '').replace(/\0/g, '').trim().slice(0, maxLength);
1124
- }
1125
-
1126
- function normalizeClientUpdateVerifiedProof(device, message, receivedAt) {
1127
- const operationId = safeString(message?.operationId, 180);
1128
- const attemptId = safeString(message?.attemptId, 180);
1129
- const productVersion = safeString(message?.productVersion, 40);
1130
- const agentVersion = safeString(message?.agentVersion, 40);
1131
- const completedAt = safeString(message?.completedAt, 64);
1132
- const launcherPid = Math.max(0, Math.floor(Number(message?.launcherPid) || 0));
1133
- const agentPid = Math.max(0, Math.floor(Number(message?.agentPid) || 0));
1134
- const supervisorPid = Math.max(0, Math.floor(Number(message?.supervisorPid) || 0));
1135
- if (!operationId
1136
- || !attemptId
1137
- || !productVersion
1138
- || !agentVersion
1139
- || !Number.isFinite(Date.parse(completedAt))
1140
- || launcherPid <= 1
1141
- || agentPid <= 1
1142
- || supervisorPid <= 1
1143
- || agentPid !== Number(device?.pid || 0)
1144
- || productVersion !== String(device?.productVersion || '')
1145
- || agentVersion !== String(device?.agentVersion || '')) {
1146
- return null;
1147
- }
1148
- return {
1149
- operationId,
1150
- attemptId,
1151
- sessionId: String(device.sessionId || ''),
1152
- launcherPid,
1153
- agentPid,
1154
- supervisorPid,
1155
- productVersion,
1156
- agentVersion,
1157
- completedAt,
1158
- receivedAt
1159
- };
1160
- }
1161
-
1162
- function normalizeRemoteKeyboardKey(value) {
1163
- const raw = String(value ?? '').replace(/\0/g, '');
1164
- return raw === ' ' ? ' ' : safeString(raw, 80);
1165
- }
1166
-
1167
- function normalizeRemoteKeyboardText(value) {
1168
- const raw = String(value ?? '').replace(/\0/g, '');
1169
- return raw === ' ' ? ' ' : safeText(raw, 256);
1170
- }
1122
+ function safeText(value, maxLength = 1000) {
1123
+ return String(value ?? '').replace(/\0/g, '').trim().slice(0, maxLength);
1124
+ }
1125
+
1126
+ function normalizeClientUpdateVerifiedProof(device, message, receivedAt) {
1127
+ const operationId = safeString(message?.operationId, 180);
1128
+ const attemptId = safeString(message?.attemptId, 180);
1129
+ const productVersion = safeString(message?.productVersion, 40);
1130
+ const agentVersion = safeString(message?.agentVersion, 40);
1131
+ const completedAt = safeString(message?.completedAt, 64);
1132
+ const launcherPid = Math.max(0, Math.floor(Number(message?.launcherPid) || 0));
1133
+ const agentPid = Math.max(0, Math.floor(Number(message?.agentPid) || 0));
1134
+ const supervisorPid = Math.max(0, Math.floor(Number(message?.supervisorPid) || 0));
1135
+ if (!operationId
1136
+ || !attemptId
1137
+ || !productVersion
1138
+ || !agentVersion
1139
+ || !Number.isFinite(Date.parse(completedAt))
1140
+ || launcherPid <= 1
1141
+ || agentPid <= 1
1142
+ || supervisorPid <= 1
1143
+ || agentPid !== Number(device?.pid || 0)
1144
+ || productVersion !== String(device?.productVersion || '')
1145
+ || agentVersion !== String(device?.agentVersion || '')) {
1146
+ return null;
1147
+ }
1148
+ return {
1149
+ operationId,
1150
+ attemptId,
1151
+ sessionId: String(device.sessionId || ''),
1152
+ launcherPid,
1153
+ agentPid,
1154
+ supervisorPid,
1155
+ productVersion,
1156
+ agentVersion,
1157
+ completedAt,
1158
+ receivedAt
1159
+ };
1160
+ }
1161
+
1162
+ function normalizeRemoteKeyboardKey(value) {
1163
+ const raw = String(value ?? '').replace(/\0/g, '');
1164
+ return raw === ' ' ? ' ' : safeString(raw, 80);
1165
+ }
1166
+
1167
+ function normalizeRemoteKeyboardText(value) {
1168
+ const raw = String(value ?? '').replace(/\0/g, '');
1169
+ return raw === ' ' ? ' ' : safeText(raw, 256);
1170
+ }
1171
1171
 
1172
1172
  function safeTaskData(value) {
1173
1173
  if (value === undefined || value === null) return undefined;
@@ -1248,14 +1248,14 @@ function readRawRemoteInputMonitorIndex(input) {
1248
1248
  return undefined;
1249
1249
  }
1250
1250
 
1251
- function normalizeRemoteInputEvent(value = {}) {
1251
+ function normalizeRemoteInputEvent(value = {}) {
1252
1252
  const input = value && typeof value === 'object' ? value : {};
1253
1253
  const type = safeString(input.type || input.Type, 48);
1254
1254
  const normalizedX = Number(input.normalizedX ?? input.NormalizedX);
1255
1255
  const normalizedY = Number(input.normalizedY ?? input.NormalizedY);
1256
1256
  const deltaX = Number(input.deltaX ?? input.DeltaX);
1257
1257
  const deltaY = Number(input.deltaY ?? input.DeltaY);
1258
- const keyCode = Number(input.keyCode ?? input.KeyCode);
1258
+ const keyCode = Number(input.keyCode ?? input.KeyCode);
1259
1259
  const location = Number(input.location ?? input.Location);
1260
1260
  const monitorIndex = parseExactLiveStreamMonitorIndex(readRawRemoteInputMonitorIndex(input));
1261
1261
  const inputSeq = Number(input.inputSeq ?? input.InputSeq);
@@ -1263,18 +1263,18 @@ function normalizeRemoteInputEvent(value = {}) {
1263
1263
  const hubReceivedAtEpochMs = Number(input.hubReceivedAtEpochMs ?? input.HubReceivedAtEpochMs);
1264
1264
  const captureGeneration = Number(input.captureGeneration ?? input.CaptureGeneration);
1265
1265
  const rawPressedCodes = input.pressedCodes ?? input.PressedCodes;
1266
- const pressedCodes = Array.isArray(rawPressedCodes)
1266
+ const pressedCodes = Array.isArray(rawPressedCodes)
1267
1267
  ? [...new Set(rawPressedCodes
1268
1268
  .map(code => safeString(code, 80))
1269
1269
  .filter(Boolean))]
1270
1270
  .slice(0, 64)
1271
- : null;
1272
- const key = normalizeRemoteKeyboardKey(input.key ?? input.Key);
1273
- let code = safeString(input.code ?? input.Code, 80);
1274
- if ((!code || code === 'Unidentified') && (key === ' ' || key === 'Spacebar' || keyCode === 32)) {
1275
- code = 'Space';
1276
- }
1277
- return {
1271
+ : null;
1272
+ const key = normalizeRemoteKeyboardKey(input.key ?? input.Key);
1273
+ let code = safeString(input.code ?? input.Code, 80);
1274
+ if ((!code || code === 'Unidentified') && (key === ' ' || key === 'Spacebar' || keyCode === 32)) {
1275
+ code = 'Space';
1276
+ }
1277
+ return {
1278
1278
  type,
1279
1279
  // A missing monitor is not equivalent to the primary display. Control
1280
1280
  // input must prove the exact monitor owned by its capture generation.
@@ -1284,11 +1284,11 @@ function normalizeRemoteInputEvent(value = {}) {
1284
1284
  button: safeString(input.button || input.Button, 24),
1285
1285
  deltaX: Number.isFinite(deltaX) ? Math.max(-4096, Math.min(4096, deltaX)) : 0,
1286
1286
  deltaY: Number.isFinite(deltaY) ? Math.max(-4096, Math.min(4096, deltaY)) : 0,
1287
- key,
1288
- code,
1287
+ key,
1288
+ code,
1289
1289
  keyCode: Number.isFinite(keyCode) ? Math.max(0, Math.min(65535, Math.trunc(keyCode))) : 0,
1290
1290
  location: Number.isFinite(location) ? Math.max(0, Math.min(255, Math.trunc(location))) : 0,
1291
- text: normalizeRemoteKeyboardText(input.text ?? input.Text),
1291
+ text: normalizeRemoteKeyboardText(input.text ?? input.Text),
1292
1292
  repeat: input.repeat === true || input.Repeat === true,
1293
1293
  pressedCodes,
1294
1294
  shiftKey: input.shiftKey === true || input.ShiftKey === true,
@@ -1399,7 +1399,7 @@ function buildRemoteFramePath(deviceId, frameKind, frame) {
1399
1399
  return `/api/remote/devices/${encodeURIComponent(deviceId)}/${endpoint}?${params.toString()}`;
1400
1400
  }
1401
1401
 
1402
- function serializeRemoteFrame(frame, deviceId, frameKind, options = {}) {
1402
+ function serializeRemoteFrame(frame, deviceId, frameKind, options = {}) {
1403
1403
  if (!frame) {
1404
1404
  return null;
1405
1405
  }
@@ -1421,27 +1421,27 @@ function serializeRemoteFrame(frame, deviceId, frameKind, options = {}) {
1421
1421
  serialized.dataUrl = dataUrl || buildFrameDataUrl(payload, '', publicFrame.mimeType || publicFrame.format || 'image/jpeg');
1422
1422
  }
1423
1423
 
1424
- return serialized;
1425
- }
1426
-
1427
- function serializeActiveLiveStream(activeLiveStream, deviceId) {
1428
- if (!activeLiveStream) {
1429
- return null;
1430
- }
1431
-
1432
- return {
1433
- ...activeLiveStream,
1434
- // The active descriptor is status metadata. Preserve the Hub's exact
1435
- // internal frame owner for delivery, but never copy encoded bytes or
1436
- // its access token into a browser status snapshot.
1437
- latestFrame: serializeRemoteFrame(
1438
- activeLiveStream.latestFrame,
1439
- deviceId,
1440
- 'live',
1441
- { includeDataUrl: false }
1442
- )
1443
- };
1444
- }
1424
+ return serialized;
1425
+ }
1426
+
1427
+ function serializeActiveLiveStream(activeLiveStream, deviceId) {
1428
+ if (!activeLiveStream) {
1429
+ return null;
1430
+ }
1431
+
1432
+ return {
1433
+ ...activeLiveStream,
1434
+ // The active descriptor is status metadata. Preserve the Hub's exact
1435
+ // internal frame owner for delivery, but never copy encoded bytes or
1436
+ // its access token into a browser status snapshot.
1437
+ latestFrame: serializeRemoteFrame(
1438
+ activeLiveStream.latestFrame,
1439
+ deviceId,
1440
+ 'live',
1441
+ { includeDataUrl: false }
1442
+ )
1443
+ };
1444
+ }
1445
1445
 
1446
1446
  function getRecentFrameCache(device, frameKind) {
1447
1447
  if (!device) {
@@ -1632,7 +1632,7 @@ function serializeDevice(device, options = {}) {
1632
1632
  },
1633
1633
  latestThumbnail: serializeRemoteFrame(device.latestThumbnail, device.deviceId, 'thumbnail', options),
1634
1634
  latestLiveFrame: serializeRemoteFrame(device.latestLiveFrame, device.deviceId, 'live', options),
1635
- activeLiveStream: serializeActiveLiveStream(device.activeLiveStream, device.deviceId),
1635
+ activeLiveStream: serializeActiveLiveStream(device.activeLiveStream, device.deviceId),
1636
1636
  liveCapturePause: device.liveCapturePause
1637
1637
  ? {
1638
1638
  token: device.liveCapturePause.token,
@@ -1662,9 +1662,9 @@ function serializeDevice(device, options = {}) {
1662
1662
  byteLength: device.latestAudioFrame.byteLength
1663
1663
  }
1664
1664
  : null,
1665
- latestAudioStatus: device.latestAudioStatus ? { ...device.latestAudioStatus } : null,
1666
- clientUpdateProof: device.clientUpdateProof ? { ...device.clientUpdateProof } : null,
1667
- udp: device.udp ? { ...device.udp } : { enabled: false, state: 'tcp-only', ready: false },
1665
+ latestAudioStatus: device.latestAudioStatus ? { ...device.latestAudioStatus } : null,
1666
+ clientUpdateProof: device.clientUpdateProof ? { ...device.clientUpdateProof } : null,
1667
+ udp: device.udp ? { ...device.udp } : { enabled: false, state: 'tcp-only', ready: false },
1668
1668
  latestTask: device.latestTask ? { ...device.latestTask } : null,
1669
1669
  synthetic: device.synthetic === true,
1670
1670
  recentTasks: Array.isArray(device.recentTasks)
@@ -4464,9 +4464,9 @@ export function createRemoteHub(options = {}) {
4464
4464
  liveCapturePause: existing?.liveCapturePause || null,
4465
4465
  activeAudioStream: null,
4466
4466
  latestAudioFrame: null,
4467
- latestAudioStatus: null,
4468
- clientUpdateProof: null,
4469
- udp: {
4467
+ latestAudioStatus: null,
4468
+ clientUpdateProof: null,
4469
+ udp: {
4470
4470
  enabled: capabilities.udpP2p === true,
4471
4471
  state: 'tcp-only',
4472
4472
  ready: false,
@@ -7479,7 +7479,7 @@ export function createRemoteHub(options = {}) {
7479
7479
  device.counters.statusReceived += 1;
7480
7480
  emitRemoteEvent('RemoteDeviceStatus', device);
7481
7481
  break;
7482
- case 'command.result':
7482
+ case 'command.result':
7483
7483
  case 'command.error':
7484
7484
  device.counters.commandResultsReceived += 1;
7485
7485
  {
@@ -7507,23 +7507,23 @@ export function createRemoteHub(options = {}) {
7507
7507
  commandId: safeString(message.commandId, 128),
7508
7508
  result: message.result ?? null,
7509
7509
  error: safeString(message.error, 500)
7510
- });
7511
- break;
7512
- case 'client.update.verified': {
7513
- const receivedAt = new Date().toISOString();
7514
- const proof = normalizeClientUpdateVerifiedProof(device, message, receivedAt);
7515
- if (!proof) {
7516
- logWarn(
7517
- 'remote',
7518
- `ignored invalid Client update supervisor proof from ${device.deviceName} (${device.deviceId})`
7519
- );
7520
- break;
7521
- }
7522
- device.clientUpdateProof = proof;
7523
- emitRemoteEvent('RemoteClientUpdateVerified', device, { proof });
7524
- break;
7525
- }
7526
- case 'input.applied':
7510
+ });
7511
+ break;
7512
+ case 'client.update.verified': {
7513
+ const receivedAt = new Date().toISOString();
7514
+ const proof = normalizeClientUpdateVerifiedProof(device, message, receivedAt);
7515
+ if (!proof) {
7516
+ logWarn(
7517
+ 'remote',
7518
+ `ignored invalid Client update supervisor proof from ${device.deviceName} (${device.deviceId})`
7519
+ );
7520
+ break;
7521
+ }
7522
+ device.clientUpdateProof = proof;
7523
+ emitRemoteEvent('RemoteClientUpdateVerified', device, { proof });
7524
+ break;
7525
+ }
7526
+ case 'input.applied':
7527
7527
  case 'input.error':
7528
7528
  handleRemoteInputOutcome(device, message, 'main');
7529
7529
  break;
@@ -9705,39 +9705,39 @@ export function createRemoteHub(options = {}) {
9705
9705
  liveStreamReplacementStillPending(activeLiveStream)
9706
9706
  ? 'stream-restart-superseded'
9707
9707
  : 'stream-start-timeout');
9708
- }
9709
- const commandId = safeString(options.commandId, 128) || crypto.randomUUID();
9710
- const restartToken = safeString(options.restartToken, 128);
9711
- if (activeLiveStream
9712
- && options.forceRestart === true
9713
- && restartToken
9714
- && safeString(activeLiveStream.restartToken, 128) === restartToken
9715
- && liveStreamMatchesOptions(activeLiveStream, normalized)
9716
- && liveStreamIsReusable(activeLiveStream)) {
9717
- emitRemoteEvent('RemoteLiveStreamRestartTokenReused', device, {
9718
- streamId,
9719
- commandId: activeLiveStream.commandId,
9720
- restartToken,
9721
- captureGeneration: Number(activeLiveStream.captureGeneration || 0)
9722
- });
9723
- return {
9724
- ok: true,
9725
- commandId: activeLiveStream.commandId,
9726
- sessionId: device.sessionId,
9727
- streamId,
9728
- streamPurpose,
9729
- fps: Number(activeLiveStream.fps || fps),
9730
- mode: activeLiveStream.mode || transfer.mode,
9731
- frameMode: activeLiveStream.frameMode || transfer.frameMode,
9732
- monitorIndex: Number(activeLiveStream.monitorIndex ?? monitorIndex),
9733
- captureGeneration: Number(activeLiveStream.captureGeneration || 0),
9734
- ready: liveStreamHasCurrentFrame(activeLiveStream),
9735
- pending: activeLiveStream.open !== true,
9736
- reused: true
9737
- };
9738
- }
9739
- if (activeLiveStream
9740
- && options.forceRestart !== true
9708
+ }
9709
+ const commandId = safeString(options.commandId, 128) || crypto.randomUUID();
9710
+ const restartToken = safeString(options.restartToken, 128);
9711
+ if (activeLiveStream
9712
+ && options.forceRestart === true
9713
+ && restartToken
9714
+ && safeString(activeLiveStream.restartToken, 128) === restartToken
9715
+ && liveStreamMatchesOptions(activeLiveStream, normalized)
9716
+ && liveStreamIsReusable(activeLiveStream)) {
9717
+ emitRemoteEvent('RemoteLiveStreamRestartTokenReused', device, {
9718
+ streamId,
9719
+ commandId: activeLiveStream.commandId,
9720
+ restartToken,
9721
+ captureGeneration: Number(activeLiveStream.captureGeneration || 0)
9722
+ });
9723
+ return {
9724
+ ok: true,
9725
+ commandId: activeLiveStream.commandId,
9726
+ sessionId: device.sessionId,
9727
+ streamId,
9728
+ streamPurpose,
9729
+ fps: Number(activeLiveStream.fps || fps),
9730
+ mode: activeLiveStream.mode || transfer.mode,
9731
+ frameMode: activeLiveStream.frameMode || transfer.frameMode,
9732
+ monitorIndex: Number(activeLiveStream.monitorIndex ?? monitorIndex),
9733
+ captureGeneration: Number(activeLiveStream.captureGeneration || 0),
9734
+ ready: liveStreamHasCurrentFrame(activeLiveStream),
9735
+ pending: activeLiveStream.open !== true,
9736
+ reused: true
9737
+ };
9738
+ }
9739
+ if (activeLiveStream
9740
+ && options.forceRestart !== true
9741
9741
  && options.reuseExisting === true
9742
9742
  && liveStreamMatchesOptions(activeLiveStream, normalized)
9743
9743
  && liveStreamIsReusable(activeLiveStream)) {
@@ -9867,7 +9867,7 @@ export function createRemoteHub(options = {}) {
9867
9867
  monitorIndex,
9868
9868
  monitorCount: 1,
9869
9869
  startedAt: now,
9870
- restartToken,
9870
+ restartToken,
9871
9871
  stoppedAt: '',
9872
9872
  stopReason: '',
9873
9873
  stopPending: false,