livedesk 0.1.449 → 0.1.451
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/bin/livedesk.js +4 -0
- package/client/bin/livedesk-client.js +314 -105
- package/client/package.json +5 -5
- package/client/src/runtime/client-runtime-server.js +19 -4
- package/hub/package.json +1 -1
- package/hub/src/agents/agent-manager.js +5 -2
- package/hub/src/agents/codex-agent-runtime.js +10 -13
- package/hub/src/remote-hub.js +19 -6
- package/hub/src/server.js +5 -3
- package/hub/src/transport/udp-hub-transport.js +22 -22
- package/hub/src/transport/udp-protocol.js +51 -26
- package/package.json +6 -6
- package/web/dist/assets/{index-BPpXtm8K.css → index-9QTFmh8R.css} +1 -1
- package/web/dist/assets/{index-CDA-kp_V.js → index-BFwWY4pa.js} +12 -12
- package/web/dist/index.html +2 -2
|
@@ -150,6 +150,11 @@ function normalizeSlotNumber(value) {
|
|
|
150
150
|
: 0;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
function normalizeRoleVersion(value) {
|
|
154
|
+
const roleVersion = Number(String(value ?? '').trim());
|
|
155
|
+
return Number.isInteger(roleVersion) && roleVersion >= 0 ? roleVersion : 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
153
158
|
function readCpuTotals() {
|
|
154
159
|
return os.cpus().reduce((totals, cpu) => {
|
|
155
160
|
const times = Object.values(cpu.times || {}).map(Number);
|
|
@@ -655,9 +660,9 @@ export function createClientRuntimeServer(options = {}) {
|
|
|
655
660
|
manager: '',
|
|
656
661
|
pairToken: '',
|
|
657
662
|
slotNumber: normalizeSlotNumber(options.slot),
|
|
658
|
-
assignedHubId:
|
|
663
|
+
assignedHubId: normalizeString(options.assignedHubId ?? process.env.LIVEDESK_ASSIGNED_HUB_ID, 160),
|
|
659
664
|
endpointCandidates: [],
|
|
660
|
-
roleVersion:
|
|
665
|
+
roleVersion: normalizeRoleVersion(options.roleVersion ?? process.env.LIVEDESK_ROLE_VERSION),
|
|
661
666
|
connectedAt: '',
|
|
662
667
|
message: 'Sign in with Google or enter a Hub PIN to start this Client.',
|
|
663
668
|
startup: false,
|
|
@@ -788,6 +793,12 @@ export function createClientRuntimeServer(options = {}) {
|
|
|
788
793
|
name: accountProfile.name || state.auth.name,
|
|
789
794
|
avatarUrl: accountProfile.avatarUrl || state.auth.avatarUrl
|
|
790
795
|
};
|
|
796
|
+
state.lastError = '';
|
|
797
|
+
if (state.message.startsWith('Client authentication needs attention:')) {
|
|
798
|
+
state.message = state.agent.state === 'running'
|
|
799
|
+
? 'Connected to the LiveDesk Hub.'
|
|
800
|
+
: normalizeString(message, 1000) || 'Client credentials accepted. Finding the Hub.';
|
|
801
|
+
}
|
|
791
802
|
}
|
|
792
803
|
return;
|
|
793
804
|
}
|
|
@@ -795,7 +806,9 @@ export function createClientRuntimeServer(options = {}) {
|
|
|
795
806
|
loggedOut = false;
|
|
796
807
|
state.connectedAt = new Date().toISOString();
|
|
797
808
|
state.manager = normalizeString(choice?.manager, 256);
|
|
798
|
-
|
|
809
|
+
if (Object.prototype.hasOwnProperty.call(choice || {}, 'hubDeviceId')) {
|
|
810
|
+
state.assignedHubId = normalizeString(choice?.hubDeviceId, 160);
|
|
811
|
+
}
|
|
799
812
|
state.endpointCandidates = Array.isArray(choice?.endpointCandidates)
|
|
800
813
|
? choice.endpointCandidates.map(value => normalizeString(value, 256)).filter(Boolean)
|
|
801
814
|
: [];
|
|
@@ -1337,7 +1350,9 @@ export function createClientRuntimeServer(options = {}) {
|
|
|
1337
1350
|
if (patch.manager) state.manager = normalizeString(patch.manager, 256);
|
|
1338
1351
|
if (patch.pairToken) state.pairToken = normalizeString(patch.pairToken, 256);
|
|
1339
1352
|
if (normalizeSlotNumber(patch.slotNumber)) state.slotNumber = normalizeSlotNumber(patch.slotNumber);
|
|
1340
|
-
if (
|
|
1353
|
+
if (Object.prototype.hasOwnProperty.call(patch, 'assignedHubId')) {
|
|
1354
|
+
state.assignedHubId = normalizeString(patch.assignedHubId, 160);
|
|
1355
|
+
}
|
|
1341
1356
|
if (patch.message) state.message = normalizeString(patch.message, 1000);
|
|
1342
1357
|
if (Number.isInteger(patch.roleVersion)) state.roleVersion = patch.roleVersion;
|
|
1343
1358
|
if (Array.isArray(patch.endpointCandidates)) state.endpointCandidates = patch.endpointCandidates;
|
package/hub/package.json
CHANGED
|
@@ -42,7 +42,11 @@ export function createAgentManager({
|
|
|
42
42
|
|
|
43
43
|
async function publicSettings() {
|
|
44
44
|
const current = await settings.get();
|
|
45
|
-
const {
|
|
45
|
+
const {
|
|
46
|
+
codexMaxTurns: _codexMaxTurns,
|
|
47
|
+
provider: _provider,
|
|
48
|
+
...exposedSettings
|
|
49
|
+
} = current;
|
|
46
50
|
const codex = await getCodexStatus();
|
|
47
51
|
const securityStatus = runtime?.getSecurityStatus?.() || {
|
|
48
52
|
isolatedCodexHome: false,
|
|
@@ -55,7 +59,6 @@ export function createAgentManager({
|
|
|
55
59
|
};
|
|
56
60
|
return {
|
|
57
61
|
...exposedSettings,
|
|
58
|
-
provider: AGENT_PROVIDER_CODEX,
|
|
59
62
|
codexInstallation: codex.installed ? 'installed' : 'not-installed',
|
|
60
63
|
codexAuth: codex.authenticated,
|
|
61
64
|
codexStatus: codex.status,
|
|
@@ -3,10 +3,9 @@ import { access, link, mkdir, stat, unlink } from 'node:fs/promises';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { spawn } from 'node:child_process';
|
|
6
|
-
import { createRequire } from 'node:module';
|
|
7
|
-
import { AgentProviderError } from './provider-errors.js';
|
|
8
|
-
import {
|
|
9
|
-
import { AGENT_TOOL_NAMES } from './agent-tool-registry.js';
|
|
6
|
+
import { createRequire } from 'node:module';
|
|
7
|
+
import { AgentProviderError } from './provider-errors.js';
|
|
8
|
+
import { AGENT_TOOL_NAMES } from './agent-tool-registry.js';
|
|
10
9
|
import { createAgentPermissionPolicy, hashAgentPermissionPolicy } from './agent-permissions.js';
|
|
11
10
|
|
|
12
11
|
const require = createRequire(import.meta.url);
|
|
@@ -427,11 +426,10 @@ export function createCodexAgentRuntime({
|
|
|
427
426
|
}
|
|
428
427
|
|
|
429
428
|
function publicRun(run) {
|
|
430
|
-
return {
|
|
431
|
-
runId: run.runId,
|
|
432
|
-
status: run.status,
|
|
433
|
-
|
|
434
|
-
instruction: run.instruction,
|
|
429
|
+
return {
|
|
430
|
+
runId: run.runId,
|
|
431
|
+
status: run.status,
|
|
432
|
+
instruction: run.instruction,
|
|
435
433
|
threadId: run.threadId,
|
|
436
434
|
finalResponse: run.finalResponse,
|
|
437
435
|
error: run.error,
|
|
@@ -654,10 +652,9 @@ export function createCodexAgentRuntime({
|
|
|
654
652
|
const permissionPolicy = freezeAgentPermissionPolicy(input.permissionPolicy && typeof input.permissionPolicy === 'object'
|
|
655
653
|
? input.permissionPolicy
|
|
656
654
|
: createAgentPermissionPolicy({ mode: input.permissionMode || 'safe-auto', deviceIds, maxToolCalls: settings.codexMaxToolCalls }));
|
|
657
|
-
const run = {
|
|
658
|
-
runId: crypto.randomUUID(),
|
|
659
|
-
status: 'queued',
|
|
660
|
-
provider: AGENT_PROVIDER_CODEX,
|
|
655
|
+
const run = {
|
|
656
|
+
runId: crypto.randomUUID(),
|
|
657
|
+
status: 'queued',
|
|
661
658
|
instruction,
|
|
662
659
|
deviceIds,
|
|
663
660
|
threadId: '',
|
package/hub/src/remote-hub.js
CHANGED
|
@@ -4232,9 +4232,11 @@ export function createRemoteHub(options = {}) {
|
|
|
4232
4232
|
const captureTimingAvailable = hasFrameCaptureTiming(message);
|
|
4233
4233
|
const videoTransport = transport === 'udp-p2p'
|
|
4234
4234
|
? 'p2p-udp'
|
|
4235
|
-
: transport === '
|
|
4236
|
-
? '
|
|
4237
|
-
: '
|
|
4235
|
+
: transport === 'relay-binary'
|
|
4236
|
+
? 'encrypted-relay'
|
|
4237
|
+
: transport === 'ws-binary'
|
|
4238
|
+
? 'direct-ws'
|
|
4239
|
+
: 'direct-tcp';
|
|
4238
4240
|
device.latestLiveFrame = {
|
|
4239
4241
|
streamId,
|
|
4240
4242
|
frameSeq,
|
|
@@ -4322,9 +4324,16 @@ export function createRemoteHub(options = {}) {
|
|
|
4322
4324
|
deltaRefreshTileCount: Number.isFinite(Number(message.deltaRefreshTileCount)) ? Number(message.deltaRefreshTileCount) : 0,
|
|
4323
4325
|
deltaTotalTiles: Number.isFinite(Number(message.deltaTotalTiles)) ? Number(message.deltaTotalTiles) : 0,
|
|
4324
4326
|
videoTransport,
|
|
4325
|
-
frameTransportActive: safeString(message.frameTransportActive, 20)
|
|
4327
|
+
frameTransportActive: safeString(message.frameTransportActive, 20)
|
|
4328
|
+
|| (videoTransport === 'p2p-udp' ? 'p2p' : videoTransport === 'encrypted-relay' ? 'relay' : 'direct'),
|
|
4326
4329
|
frameTransportProtocol: safeString(message.frameTransportProtocol, 20)
|
|
4327
|
-
|| (videoTransport === 'p2p-udp'
|
|
4330
|
+
|| (videoTransport === 'p2p-udp'
|
|
4331
|
+
? 'udp'
|
|
4332
|
+
: videoTransport === 'encrypted-relay'
|
|
4333
|
+
? 'relay'
|
|
4334
|
+
: videoTransport === 'direct-ws'
|
|
4335
|
+
? 'ws'
|
|
4336
|
+
: 'tcp'),
|
|
4328
4337
|
frameTransportState: safeString(message.frameTransportState, 20) || 'active',
|
|
4329
4338
|
frameTransportP2pReady: message.frameTransportP2pReady === true,
|
|
4330
4339
|
frameTransportReason: safeString(message.frameTransportReason, 240),
|
|
@@ -4518,7 +4527,11 @@ export function createRemoteHub(options = {}) {
|
|
|
4518
4527
|
}
|
|
4519
4528
|
|
|
4520
4529
|
const frameKind = safeString(header.frameKind || header.kind || header.frameType || '', 40).toLowerCase();
|
|
4521
|
-
const binaryTransport =
|
|
4530
|
+
const binaryTransport = socket.__liveDeskRelayControl === true
|
|
4531
|
+
? 'relay-binary'
|
|
4532
|
+
: state.binaryTransport === 'ws-binary'
|
|
4533
|
+
? 'ws-binary'
|
|
4534
|
+
: 'binary';
|
|
4522
4535
|
if (frameKind === 'thumbnail' || header.type === 'thumbnail.binary') {
|
|
4523
4536
|
applyThumbnailFrame(device, header, framePayload, binaryTransport);
|
|
4524
4537
|
return;
|
package/hub/src/server.js
CHANGED
|
@@ -2127,9 +2127,11 @@ function buildRemoteFrameBinaryPacket(frameEvent, diagnostics = {}) {
|
|
|
2127
2127
|
transport: frame.transport || '',
|
|
2128
2128
|
videoTransport: frame.videoTransport || (frame.transport === 'udp-p2p'
|
|
2129
2129
|
? 'p2p-udp'
|
|
2130
|
-
: frame.transport === '
|
|
2131
|
-
? '
|
|
2132
|
-
: '
|
|
2130
|
+
: frame.transport === 'relay-binary'
|
|
2131
|
+
? 'encrypted-relay'
|
|
2132
|
+
: frame.transport === 'ws-binary'
|
|
2133
|
+
? 'direct-ws'
|
|
2134
|
+
: 'direct-tcp'),
|
|
2133
2135
|
frameTransportActive: frame.frameTransportActive || '',
|
|
2134
2136
|
frameTransportProtocol: frame.frameTransportProtocol || '',
|
|
2135
2137
|
frameTransportState: frame.frameTransportState || '',
|
|
@@ -2,10 +2,10 @@ import crypto from 'node:crypto';
|
|
|
2
2
|
import { lookup } from 'node:dns/promises';
|
|
3
3
|
import dgram from 'node:dgram';
|
|
4
4
|
import {
|
|
5
|
-
UDP_MAX_DATAGRAM_BYTES,
|
|
6
|
-
UDP_P2P_PROTOCOL,
|
|
7
|
-
UdpFrameReassembler,
|
|
8
|
-
UdpReplayWindow,
|
|
5
|
+
UDP_MAX_DATAGRAM_BYTES,
|
|
6
|
+
UDP_P2P_PROTOCOL,
|
|
7
|
+
UdpFrameReassembler,
|
|
8
|
+
UdpReplayWindow,
|
|
9
9
|
decodeRendezvousMessage,
|
|
10
10
|
decodeUdpPacket,
|
|
11
11
|
encodeRendezvousMessage,
|
|
@@ -52,7 +52,7 @@ export function createHubUdpTransport({ env = process.env, logEvent = () => {},
|
|
|
52
52
|
const socket = dgram.createSocket('udp4');
|
|
53
53
|
const sessions = new Map();
|
|
54
54
|
let frameHandler = () => {};
|
|
55
|
-
let eventHandler = () => {};
|
|
55
|
+
let eventHandler = () => {};
|
|
56
56
|
let started = false;
|
|
57
57
|
let boundPort = requestedPort;
|
|
58
58
|
let sequence = crypto.randomInt(1, 0x7fffffff);
|
|
@@ -65,20 +65,20 @@ export function createHubUdpTransport({ env = process.env, logEvent = () => {},
|
|
|
65
65
|
if (trace) logEvent('udp', `${type} ${JSON.stringify({ deviceId: event.deviceId || '', state: event.state || '', reason: event.reason || '' })}`);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
function nextSequence() {
|
|
69
|
-
sequence = (sequence + 1) >>> 0;
|
|
70
|
-
return sequence;
|
|
71
|
-
}
|
|
72
|
-
|
|
68
|
+
function nextSequence() {
|
|
69
|
+
sequence = (sequence + 1) >>> 0;
|
|
70
|
+
return sequence;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
73
|
function sendPacket(session, type, header = {}, payload = Buffer.alloc(0), address = session.clientEndpoint || session.peerEndpoint) {
|
|
74
74
|
if (!address || !session) return false;
|
|
75
|
-
let packet;
|
|
76
|
-
try {
|
|
77
|
-
packet = encodeUdpPacket({ type, sessionId: session.sessionId, key: session.key, sequence: nextSequence(), header, payload });
|
|
78
|
-
} catch (error) {
|
|
79
|
-
logWarn('udp', `UDP packet rejected device=${session.deviceId}: ${error?.message || error}`);
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
75
|
+
let packet;
|
|
76
|
+
try {
|
|
77
|
+
packet = encodeUdpPacket({ type, sessionId: session.sessionId, key: session.key, sequence: nextSequence(), header, payload });
|
|
78
|
+
} catch (error) {
|
|
79
|
+
logWarn('udp', `UDP packet rejected device=${session.deviceId}: ${error?.message || error}`);
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
82
|
socket.send(packet, address.port, address.address);
|
|
83
83
|
return true;
|
|
84
84
|
}
|
|
@@ -288,9 +288,9 @@ export function createHubUdpTransport({ env = process.env, logEvent = () => {},
|
|
|
288
288
|
keyBase64: key.toString('base64'),
|
|
289
289
|
rendezvousToken: crypto.randomBytes(16).toString('hex'),
|
|
290
290
|
sendControl,
|
|
291
|
-
clientEndpoint: null,
|
|
292
|
-
peerEndpoint: null,
|
|
293
|
-
replay: new UdpReplayWindow(),
|
|
291
|
+
clientEndpoint: null,
|
|
292
|
+
peerEndpoint: null,
|
|
293
|
+
replay: new UdpReplayWindow(),
|
|
294
294
|
reassembler: new UdpFrameReassembler({ maxPending: maxPendingFrames, timeoutMs: frameTimeoutMs }),
|
|
295
295
|
ready: false,
|
|
296
296
|
createdAt: Date.now(),
|
|
@@ -333,8 +333,8 @@ export function createHubUdpTransport({ env = process.env, logEvent = () => {},
|
|
|
333
333
|
return {
|
|
334
334
|
enabled,
|
|
335
335
|
preferred: preferP2p,
|
|
336
|
-
state: session.ready ? 'udp-ready' : 'udp-session-created',
|
|
337
|
-
ready: session.ready,
|
|
336
|
+
state: session.ready ? 'udp-ready' : 'udp-session-created',
|
|
337
|
+
ready: session.ready,
|
|
338
338
|
sessionId: session.sessionId,
|
|
339
339
|
lastPacketAt: session.lastPacketAt ? new Date(session.lastPacketAt).toISOString() : '',
|
|
340
340
|
framesReceived: session.framesReceived,
|
|
@@ -2,9 +2,11 @@ import crypto from 'node:crypto';
|
|
|
2
2
|
import { inflateRawSync } from 'node:zlib';
|
|
3
3
|
|
|
4
4
|
export const UDP_P2P_PROTOCOL = 'livedesk.udp.p2p.v1';
|
|
5
|
-
export const UDP_P2P_VERSION = 1;
|
|
6
|
-
export const UDP_MAX_DATAGRAM_BYTES = 1200;
|
|
7
|
-
|
|
5
|
+
export const UDP_P2P_VERSION = 1;
|
|
6
|
+
export const UDP_MAX_DATAGRAM_BYTES = 1200;
|
|
7
|
+
const UDP_SERIAL_MODULUS = 0x1_0000_0000;
|
|
8
|
+
const UDP_SERIAL_HALF_RANGE = 0x8000_0000;
|
|
9
|
+
export const UDP_PACKET_TYPES = Object.freeze({
|
|
8
10
|
probe: 1,
|
|
9
11
|
'probe-ack': 2,
|
|
10
12
|
ready: 3,
|
|
@@ -83,13 +85,21 @@ function decodeFramedPayload(payload, legacyHeader = null) {
|
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
function packetTypeCode(type) {
|
|
88
|
+
function packetTypeCode(type) {
|
|
87
89
|
const code = typeof type === 'number' ? type : UDP_PACKET_TYPES[String(type || '').toLowerCase()];
|
|
88
90
|
if (!code || !UDP_PACKET_TYPE_NAMES.has(code)) throw new Error('invalid-udp-packet-type');
|
|
89
91
|
return code;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function normalizeSequence(value) {
|
|
95
|
+
const sequence = Number(value);
|
|
96
|
+
if (!Number.isInteger(sequence) || sequence < 0 || sequence >= UDP_SERIAL_MODULUS) {
|
|
97
|
+
throw new Error('invalid-udp-packet-sequence');
|
|
98
|
+
}
|
|
99
|
+
return sequence;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function encodeHeader(header) {
|
|
93
103
|
const bytes = Buffer.from(JSON.stringify(header && typeof header === 'object' ? header : {}), 'utf8');
|
|
94
104
|
if (bytes.length > UDP_MAX_HEADER_BYTES) throw new Error('udp-packet-header-too-large');
|
|
95
105
|
return bytes;
|
|
@@ -103,9 +113,9 @@ export function createUdpSessionKey() {
|
|
|
103
113
|
return crypto.randomBytes(32);
|
|
104
114
|
}
|
|
105
115
|
|
|
106
|
-
export function encodeUdpPacket({ type, sessionId, key, sequence = 0, header = {}, payload = Buffer.alloc(0) }) {
|
|
107
|
-
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
108
|
-
const sessionBytes = Buffer.from(normalizedSessionId, 'utf8');
|
|
116
|
+
export function encodeUdpPacket({ type, sessionId, key, sequence = 0, header = {}, payload = Buffer.alloc(0) }) {
|
|
117
|
+
const normalizedSessionId = normalizeSessionId(sessionId);
|
|
118
|
+
const sessionBytes = Buffer.from(normalizedSessionId, 'utf8');
|
|
109
119
|
const headerBytes = encodeHeader(header);
|
|
110
120
|
const payloadBytes = asBuffer(payload);
|
|
111
121
|
if (payloadBytes.length > UDP_MAX_PAYLOAD_BYTES) throw new Error('udp-packet-payload-too-large');
|
|
@@ -117,8 +127,8 @@ export function encodeUdpPacket({ type, sessionId, key, sequence = 0, header = {
|
|
|
117
127
|
preamble[6] = sessionBytes.length;
|
|
118
128
|
preamble.writeUInt16BE(headerBytes.length, 7);
|
|
119
129
|
preamble.writeUInt16BE(payloadBytes.length, 9);
|
|
120
|
-
preamble.writeUInt32BE((Number(sequence) >>> 0), 11);
|
|
121
|
-
const nonce = crypto.randomBytes(UDP_NONCE_BYTES);
|
|
130
|
+
preamble.writeUInt32BE((Number(sequence) >>> 0), 11);
|
|
131
|
+
const nonce = crypto.randomBytes(UDP_NONCE_BYTES);
|
|
122
132
|
const associatedData = Buffer.concat([preamble, nonce, sessionBytes, headerBytes]);
|
|
123
133
|
const cipher = crypto.createCipheriv('aes-256-gcm', normalizeKey(key), nonce);
|
|
124
134
|
cipher.setAAD(associatedData);
|
|
@@ -169,26 +179,41 @@ export function decodeUdpPacket(packet, key) {
|
|
|
169
179
|
}
|
|
170
180
|
}
|
|
171
181
|
|
|
172
|
-
export class UdpReplayWindow {
|
|
182
|
+
export class UdpReplayWindow {
|
|
173
183
|
constructor(size = 512) {
|
|
174
184
|
this.size = Math.max(32, Math.min(4096, Math.floor(Number(size) || 512)));
|
|
175
185
|
this.highest = -1;
|
|
176
186
|
this.seen = new Set();
|
|
177
187
|
}
|
|
178
188
|
|
|
179
|
-
accept(sequence) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
189
|
+
accept(sequence) {
|
|
190
|
+
let value;
|
|
191
|
+
try {
|
|
192
|
+
value = normalizeSequence(sequence);
|
|
193
|
+
} catch {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
if (this.seen.has(value)) return false;
|
|
197
|
+
if (this.highest >= 0) {
|
|
198
|
+
const forward = (value - this.highest + UDP_SERIAL_MODULUS) % UDP_SERIAL_MODULUS;
|
|
199
|
+
if (forward === 0 || forward === UDP_SERIAL_HALF_RANGE) return false;
|
|
200
|
+
if (forward > UDP_SERIAL_HALF_RANGE) {
|
|
201
|
+
const age = (this.highest - value + UDP_SERIAL_MODULUS) % UDP_SERIAL_MODULUS;
|
|
202
|
+
if (age > this.size) return false;
|
|
203
|
+
} else {
|
|
204
|
+
this.highest = value;
|
|
205
|
+
}
|
|
206
|
+
} else {
|
|
207
|
+
this.highest = value;
|
|
208
|
+
}
|
|
209
|
+
this.seen.add(value);
|
|
210
|
+
for (const item of this.seen) {
|
|
211
|
+
const age = (this.highest - item + UDP_SERIAL_MODULUS) % UDP_SERIAL_MODULUS;
|
|
212
|
+
if (age > this.size) this.seen.delete(item);
|
|
213
|
+
}
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
192
217
|
|
|
193
218
|
export class UdpFrameReassembler {
|
|
194
219
|
constructor({ maxPending = 2, timeoutMs = 500, maxFrameBytes = 8 * 1024 * 1024 } = {}) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livedesk",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"livedeskClientVersion": "0.1.
|
|
3
|
+
"version": "0.1.451",
|
|
4
|
+
"livedeskClientVersion": "0.1.206",
|
|
5
5
|
"buildFlavor": "production",
|
|
6
6
|
"description": "LiveDesk Hub and client launcher",
|
|
7
7
|
"type": "module",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"ws": "^8.18.3"
|
|
50
50
|
},
|
|
51
51
|
"optionalDependencies": {
|
|
52
|
-
"@livedesk/fast-linux-x64": "0.1.
|
|
53
|
-
"@livedesk/fast-osx-arm64": "0.1.
|
|
54
|
-
"@livedesk/fast-osx-x64": "0.1.
|
|
55
|
-
"@livedesk/fast-win-x64": "0.1.
|
|
52
|
+
"@livedesk/fast-linux-x64": "0.1.412",
|
|
53
|
+
"@livedesk/fast-osx-arm64": "0.1.412",
|
|
54
|
+
"@livedesk/fast-osx-x64": "0.1.412",
|
|
55
|
+
"@livedesk/fast-win-x64": "0.1.412"
|
|
56
56
|
},
|
|
57
57
|
"publishConfig": {
|
|
58
58
|
"access": "public"
|