@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/package.json +3 -3
- package/src/agents/agent-device-scope.js +29 -29
- package/src/agents/agent-manager.js +103 -103
- package/src/agents/agent-permission-store.js +78 -78
- package/src/agents/agent-runtime-error.js +9 -9
- package/src/agents/agent-settings.js +71 -71
- package/src/agents/codex-agent-runtime.js +594 -594
- package/src/agents/codex-mcp-server.js +100 -100
- package/src/console-relay.js +415 -0
- package/src/filesystem/directory-reader.js +187 -187
- package/src/filesystem/hub-filesystem.js +78 -78
- package/src/filesystem/path-registry.js +78 -78
- package/src/filesystem/roots.js +115 -115
- package/src/frame-packet-contract.mjs +427 -427
- package/src/http/hub-ui-session.js +119 -119
- package/src/live-capture-transition-retry.mjs +297 -297
- package/src/live-desk-update.js +167 -108
- package/src/live-stream-monitor-contract.js +38 -38
- package/src/lzo1x.js +109 -109
- package/src/mode4-atlas-pool.js +137 -137
- package/src/mode4-atlas-sizing.js +32 -32
- package/src/mode4-atlas-worker.js +599 -599
- package/src/mode4-atlas.js +306 -306
- package/src/remote-audio-subscription-contract.mjs +109 -109
- package/src/remote-audio-subscription-contract.test.mjs +72 -72
- package/src/remote-hub.js +144 -144
- package/src/server.js +244 -222
- package/src/settings/effective-device-policy.js +16 -16
- package/src/transport/udp-protocol.js +453 -453
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,
|