livedesk 0.1.458 → 0.1.460
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 +52 -25
- package/client/package.json +5 -5
- package/diagnostics/livedesk-mode3-capture-smoke.mjs +183 -0
- package/diagnostics/livedesk-transport-physical-core.mjs +503 -0
- package/diagnostics/livedesk-transport-physical.mjs +508 -0
- package/hub/package.json +1 -1
- package/hub/src/remote-hub.js +813 -30
- package/hub/src/server.js +155 -5
- package/hub/src/transport/udp-hub-transport.js +110 -8
- package/hub/src/transport/udp-rendezvous.js +6 -2
- package/package.json +7 -7
package/hub/src/server.js
CHANGED
|
@@ -1303,7 +1303,7 @@ function isPrivateHubHostname(value) {
|
|
|
1303
1303
|
return !!match && Number(match[2]) >= 16 && Number(match[2]) <= 31;
|
|
1304
1304
|
}
|
|
1305
1305
|
|
|
1306
|
-
function isLoopbackAddress(value) {
|
|
1306
|
+
function isLoopbackAddress(value) {
|
|
1307
1307
|
const address = String(value || '').trim().toLowerCase();
|
|
1308
1308
|
return address === '127.0.0.1' || address === '::1' || address === '::ffff:127.0.0.1';
|
|
1309
1309
|
}
|
|
@@ -1449,6 +1449,31 @@ function normalizeDeviceIds(value) {
|
|
|
1449
1449
|
return ids;
|
|
1450
1450
|
}
|
|
1451
1451
|
|
|
1452
|
+
function requireLocalTransportDiagnosticRequest(req, res) {
|
|
1453
|
+
const forwardedFor = String(req.headers['x-forwarded-for'] || '').trim();
|
|
1454
|
+
const forwardedHost = String(req.headers['x-forwarded-host'] || '').trim();
|
|
1455
|
+
const browserOrigin = String(req.headers.origin || '').trim();
|
|
1456
|
+
const browserFetchSite = String(req.headers['sec-fetch-site'] || '').trim();
|
|
1457
|
+
if (!isLoopbackAddress(req.socket?.remoteAddress)
|
|
1458
|
+
|| !isLoopbackHostname(requestHostname(req))
|
|
1459
|
+
|| forwardedFor
|
|
1460
|
+
|| forwardedHost
|
|
1461
|
+
|| browserOrigin
|
|
1462
|
+
|| browserFetchSite) {
|
|
1463
|
+
res.status(403).json({ ok: false, error: 'transport-diagnostic-loopback-only' });
|
|
1464
|
+
return false;
|
|
1465
|
+
}
|
|
1466
|
+
if (runtimeRole !== 'hub') {
|
|
1467
|
+
res.status(403).json({ ok: false, error: 'role-not-allowed' });
|
|
1468
|
+
return false;
|
|
1469
|
+
}
|
|
1470
|
+
return true;
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
function transportDiagnosticToken(req) {
|
|
1474
|
+
return String(req.headers['x-livedesk-diagnostic-token'] || '').trim();
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1452
1477
|
function rejectRetiredAgentTaskRequest(req, res) {
|
|
1453
1478
|
const body = req.body && typeof req.body === 'object' ? req.body : {};
|
|
1454
1479
|
const approvalLevel = String(body.approvalLevel || '').trim().toLowerCase();
|
|
@@ -3093,7 +3118,7 @@ app.post('/api/settings/agent/summary', async (req, res) => {
|
|
|
3093
3118
|
}
|
|
3094
3119
|
});
|
|
3095
3120
|
|
|
3096
|
-
app.get('/api/remote/status', (_req, res) => {
|
|
3121
|
+
app.get('/api/remote/status', (_req, res) => {
|
|
3097
3122
|
noStore(res);
|
|
3098
3123
|
if (runtimeRole !== 'hub') {
|
|
3099
3124
|
res.status(403).json({ ok: false, error: 'role-not-allowed' });
|
|
@@ -3111,9 +3136,134 @@ app.get('/api/remote/status', (_req, res) => {
|
|
|
3111
3136
|
agentPackage: '@livedesk/client',
|
|
3112
3137
|
update: getLiveDeskUpdateStatus()
|
|
3113
3138
|
});
|
|
3114
|
-
});
|
|
3115
|
-
|
|
3116
|
-
app.
|
|
3139
|
+
});
|
|
3140
|
+
|
|
3141
|
+
app.post('/api/remote/diagnostics/transport/start', async (req, res) => {
|
|
3142
|
+
noStore(res);
|
|
3143
|
+
if (!requireLocalTransportDiagnosticRequest(req, res)) return;
|
|
3144
|
+
const requestController = new AbortController();
|
|
3145
|
+
let responseFinished = false;
|
|
3146
|
+
let issuedLease = null;
|
|
3147
|
+
let releaseIssuedLeasePromise = null;
|
|
3148
|
+
const detachResponseLifecycle = () => {
|
|
3149
|
+
res.off('finish', markResponseFinished);
|
|
3150
|
+
res.off('close', abortPendingStart);
|
|
3151
|
+
};
|
|
3152
|
+
const releaseIssuedLease = reason => {
|
|
3153
|
+
if (!issuedLease?.leaseId || !issuedLease?.token) {
|
|
3154
|
+
return releaseIssuedLeasePromise || Promise.resolve(null);
|
|
3155
|
+
}
|
|
3156
|
+
if (!releaseIssuedLeasePromise) {
|
|
3157
|
+
const lease = issuedLease;
|
|
3158
|
+
releaseIssuedLeasePromise = Promise.resolve(remoteHub.stopTransportDiagnostic(
|
|
3159
|
+
lease.leaseId,
|
|
3160
|
+
lease.token,
|
|
3161
|
+
reason
|
|
3162
|
+
)).catch(() => null);
|
|
3163
|
+
}
|
|
3164
|
+
return releaseIssuedLeasePromise;
|
|
3165
|
+
};
|
|
3166
|
+
const markResponseFinished = () => {
|
|
3167
|
+
responseFinished = true;
|
|
3168
|
+
issuedLease = null;
|
|
3169
|
+
detachResponseLifecycle();
|
|
3170
|
+
};
|
|
3171
|
+
const abortPendingStart = () => {
|
|
3172
|
+
if (responseFinished) return;
|
|
3173
|
+
requestController.abort();
|
|
3174
|
+
void releaseIssuedLease('start-response-closed');
|
|
3175
|
+
detachResponseLifecycle();
|
|
3176
|
+
};
|
|
3177
|
+
res.once('finish', markResponseFinished);
|
|
3178
|
+
res.once('close', abortPendingStart);
|
|
3179
|
+
try {
|
|
3180
|
+
const result = await remoteHub.startTransportDiagnostic(
|
|
3181
|
+
String(req.body?.deviceId || ''),
|
|
3182
|
+
Number(req.body?.ttlMs || 0),
|
|
3183
|
+
{ signal: requestController.signal });
|
|
3184
|
+
if (result?.leaseId && result?.token) {
|
|
3185
|
+
issuedLease = {
|
|
3186
|
+
leaseId: result.leaseId,
|
|
3187
|
+
token: result.token
|
|
3188
|
+
};
|
|
3189
|
+
}
|
|
3190
|
+
if (requestController.signal.aborted) {
|
|
3191
|
+
await releaseIssuedLease('start-response-closed');
|
|
3192
|
+
return;
|
|
3193
|
+
}
|
|
3194
|
+
res.status(result.ok ? 200 : 409).json(result);
|
|
3195
|
+
} catch (error) {
|
|
3196
|
+
if (requestController.signal.aborted) return;
|
|
3197
|
+
res.status(500).json({
|
|
3198
|
+
ok: false,
|
|
3199
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3200
|
+
});
|
|
3201
|
+
} finally {
|
|
3202
|
+
if (res.writableFinished) {
|
|
3203
|
+
markResponseFinished();
|
|
3204
|
+
} else if (requestController.signal.aborted) {
|
|
3205
|
+
detachResponseLifecycle();
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
});
|
|
3209
|
+
|
|
3210
|
+
app.get('/api/remote/diagnostics/transport/:leaseId', (req, res) => {
|
|
3211
|
+
noStore(res);
|
|
3212
|
+
if (!requireLocalTransportDiagnosticRequest(req, res)) return;
|
|
3213
|
+
const token = transportDiagnosticToken(req);
|
|
3214
|
+
if (!token) {
|
|
3215
|
+
res.status(401).json({ ok: false, error: 'transport-diagnostic-token-required' });
|
|
3216
|
+
return;
|
|
3217
|
+
}
|
|
3218
|
+
const result = remoteHub.getTransportDiagnostic(req.params.leaseId, token);
|
|
3219
|
+
res.status(result.ok ? 200 : 404).json(result);
|
|
3220
|
+
});
|
|
3221
|
+
|
|
3222
|
+
app.post('/api/remote/diagnostics/transport/:leaseId/phase', async (req, res) => {
|
|
3223
|
+
noStore(res);
|
|
3224
|
+
if (!requireLocalTransportDiagnosticRequest(req, res)) return;
|
|
3225
|
+
const token = transportDiagnosticToken(req);
|
|
3226
|
+
if (!token) {
|
|
3227
|
+
res.status(401).json({ ok: false, error: 'transport-diagnostic-token-required' });
|
|
3228
|
+
return;
|
|
3229
|
+
}
|
|
3230
|
+
try {
|
|
3231
|
+
const result = await remoteHub.setTransportDiagnosticPhase(
|
|
3232
|
+
req.params.leaseId,
|
|
3233
|
+
token,
|
|
3234
|
+
String(req.body?.phase || ''));
|
|
3235
|
+
res.status(result.ok ? 200 : 409).json(result);
|
|
3236
|
+
} catch (error) {
|
|
3237
|
+
res.status(500).json({
|
|
3238
|
+
ok: false,
|
|
3239
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3240
|
+
});
|
|
3241
|
+
}
|
|
3242
|
+
});
|
|
3243
|
+
|
|
3244
|
+
app.delete('/api/remote/diagnostics/transport/:leaseId', async (req, res) => {
|
|
3245
|
+
noStore(res);
|
|
3246
|
+
if (!requireLocalTransportDiagnosticRequest(req, res)) return;
|
|
3247
|
+
const token = transportDiagnosticToken(req);
|
|
3248
|
+
if (!token) {
|
|
3249
|
+
res.status(401).json({ ok: false, error: 'transport-diagnostic-token-required' });
|
|
3250
|
+
return;
|
|
3251
|
+
}
|
|
3252
|
+
try {
|
|
3253
|
+
const result = await remoteHub.stopTransportDiagnostic(
|
|
3254
|
+
req.params.leaseId,
|
|
3255
|
+
token,
|
|
3256
|
+
String(req.body?.reason || 'runner-complete'));
|
|
3257
|
+
res.status(result.ok ? 200 : 409).json(result);
|
|
3258
|
+
} catch (error) {
|
|
3259
|
+
res.status(500).json({
|
|
3260
|
+
ok: false,
|
|
3261
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3262
|
+
});
|
|
3263
|
+
}
|
|
3264
|
+
});
|
|
3265
|
+
|
|
3266
|
+
app.get('/api/runtime/status', (_req, res) => {
|
|
3117
3267
|
noStore(res);
|
|
3118
3268
|
res.json({ ok: true, ...hubRuntimeStatus(runtimeManager, { role: runtimeRole, deviceId: runtimeDeviceId, deviceName: runtimeDeviceName, roleSource: runtimeRoleSource }) });
|
|
3119
3269
|
});
|
|
@@ -36,6 +36,27 @@ function normalizedAddress(value) {
|
|
|
36
36
|
return address.startsWith('::ffff:') ? address.slice(7) : address;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
function isPublicIPv4(value) {
|
|
40
|
+
const address = normalizedAddress(value);
|
|
41
|
+
const octets = address.split('.').map(Number);
|
|
42
|
+
if (octets.length !== 4
|
|
43
|
+
|| octets.some(octet => !Number.isInteger(octet) || octet < 0 || octet > 255)) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
const [a, b] = octets;
|
|
47
|
+
const c = octets[2];
|
|
48
|
+
return a !== 0
|
|
49
|
+
&& a !== 10
|
|
50
|
+
&& a !== 127
|
|
51
|
+
&& !(a === 100 && b >= 64 && b <= 127)
|
|
52
|
+
&& !(a === 169 && b === 254)
|
|
53
|
+
&& !(a === 172 && b >= 16 && b <= 31)
|
|
54
|
+
&& !(a === 192 && (b === 0 || b === 168 || (b === 88 && c === 99)))
|
|
55
|
+
&& !(a === 198 && (b === 18 || b === 19 || (b === 51 && c === 100)))
|
|
56
|
+
&& !(a === 203 && b === 0 && c === 113)
|
|
57
|
+
&& !(a >= 224);
|
|
58
|
+
}
|
|
59
|
+
|
|
39
60
|
export function createHubUdpTransport({ env = process.env, logEvent = () => {}, logWarn = () => {} } = {}) {
|
|
40
61
|
const enabled = isEnabled(env.LIVEDESK_UDP_ENABLED, true);
|
|
41
62
|
const preferP2p = isEnabled(env.LIVEDESK_UDP_PREFER_P2P, false);
|
|
@@ -182,9 +203,21 @@ export function createHubUdpTransport({ env = process.env, logEvent = () => {},
|
|
|
182
203
|
const session = [...sessions.values()].find(item => item.sessionId === safeText(message.roomId, 160));
|
|
183
204
|
if (!session || message.protocol !== UDP_P2P_PROTOCOL || !isTrustedRendezvousSource(rinfo)) return;
|
|
184
205
|
const address = safeText(message.host, 128);
|
|
185
|
-
const port = Number(message.port);
|
|
186
|
-
if (!address || !Number.isInteger(port) || port < 1 || port > 65535) return;
|
|
187
|
-
|
|
206
|
+
const port = Number(message.port);
|
|
207
|
+
if (!address || !Number.isInteger(port) || port < 1 || port > 65535) return;
|
|
208
|
+
const observedAddress = normalizedAddress(message.observedHost);
|
|
209
|
+
const observedPort = Number(message.observedPort);
|
|
210
|
+
if (observedAddress
|
|
211
|
+
&& Number.isInteger(observedPort)
|
|
212
|
+
&& observedPort >= 1
|
|
213
|
+
&& observedPort <= 65535) {
|
|
214
|
+
session.hubRendezvousEndpoint = {
|
|
215
|
+
address: observedAddress,
|
|
216
|
+
port: observedPort
|
|
217
|
+
};
|
|
218
|
+
session.hubRendezvousObservedAt = Date.now();
|
|
219
|
+
}
|
|
220
|
+
session.peerEndpoint = { address, port };
|
|
188
221
|
session.lastPeerAt = Date.now();
|
|
189
222
|
sendPacket(session, 'probe', { punch: true }, Buffer.alloc(0), session.peerEndpoint);
|
|
190
223
|
emit('UdpPeerEndpointObserved', { deviceId: session.deviceId, endpoint: `${address}:${port}` });
|
|
@@ -290,6 +323,8 @@ export function createHubUdpTransport({ env = process.env, logEvent = () => {},
|
|
|
290
323
|
sendControl,
|
|
291
324
|
clientEndpoint: null,
|
|
292
325
|
peerEndpoint: null,
|
|
326
|
+
hubRendezvousEndpoint: null,
|
|
327
|
+
hubRendezvousObservedAt: 0,
|
|
293
328
|
replay: new UdpReplayWindow(),
|
|
294
329
|
reassembler: new UdpFrameReassembler({ maxPending: maxPendingFrames, timeoutMs: frameTimeoutMs }),
|
|
295
330
|
ready: false,
|
|
@@ -327,7 +362,7 @@ export function createHubUdpTransport({ env = process.env, logEvent = () => {},
|
|
|
327
362
|
emit('UdpSessionClosed', { deviceId: id, reason: 'tcp-session-closed' });
|
|
328
363
|
}
|
|
329
364
|
|
|
330
|
-
function getDeviceStatus(deviceId) {
|
|
365
|
+
function getDeviceStatus(deviceId) {
|
|
331
366
|
const session = sessions.get(safeText(deviceId, 160));
|
|
332
367
|
if (!session) return { enabled, state: enabled ? 'disabled' : 'tcp-only', ready: false };
|
|
333
368
|
return {
|
|
@@ -340,7 +375,72 @@ export function createHubUdpTransport({ env = process.env, logEvent = () => {},
|
|
|
340
375
|
framesReceived: session.framesReceived,
|
|
341
376
|
...session.reassembler.getStats()
|
|
342
377
|
};
|
|
343
|
-
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async function refreshDeviceDiagnosticNetwork(deviceId, { timeoutMs = 3_000 } = {}) {
|
|
381
|
+
const session = sessions.get(safeText(deviceId, 160));
|
|
382
|
+
if (!session || !started || !rendezvousHost) return false;
|
|
383
|
+
const requestedAt = Date.now();
|
|
384
|
+
await resolveRendezvousAddresses();
|
|
385
|
+
if (!sendRendezvousRegister(session)) return false;
|
|
386
|
+
const deadline = requestedAt + numberEnv(timeoutMs, 250, 5_000, 3_000);
|
|
387
|
+
while (Date.now() < deadline) {
|
|
388
|
+
if (session.hubRendezvousObservedAt >= requestedAt) return true;
|
|
389
|
+
await new Promise(resolve => {
|
|
390
|
+
const timer = setTimeout(resolve, 40);
|
|
391
|
+
timer.unref?.();
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function getDeviceDiagnosticNetwork(deviceId, { salt = '' } = {}) {
|
|
398
|
+
const session = sessions.get(safeText(deviceId, 160));
|
|
399
|
+
const clientAddress = normalizedAddress(session?.clientEndpoint?.address);
|
|
400
|
+
const normalizedHubAddress = normalizedAddress(session?.hubRendezvousEndpoint?.address);
|
|
401
|
+
const hubAddressObservedAt = session?.hubRendezvousObservedAt
|
|
402
|
+
? new Date(session.hubRendezvousObservedAt).toISOString()
|
|
403
|
+
: '';
|
|
404
|
+
const digest = value => value
|
|
405
|
+
? crypto.createHash('sha256')
|
|
406
|
+
.update(`${safeText(salt, 160)}:${value}`)
|
|
407
|
+
.digest('hex')
|
|
408
|
+
.slice(0, 16)
|
|
409
|
+
: '';
|
|
410
|
+
if (!session?.ready || !clientAddress) {
|
|
411
|
+
return {
|
|
412
|
+
evidence: 'authenticated-udp-endpoint-unavailable',
|
|
413
|
+
differentPublicEgress: null,
|
|
414
|
+
clientAddressHash: '',
|
|
415
|
+
hubAddressHash: digest(normalizedHubAddress),
|
|
416
|
+
hubAddressObservedAt,
|
|
417
|
+
hubEndpointSource: normalizedHubAddress
|
|
418
|
+
? 'trusted-rendezvous-observation'
|
|
419
|
+
: 'unavailable'
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
const clientAddressPublic = isPublicIPv4(clientAddress);
|
|
423
|
+
const hubAddressPublic = isPublicIPv4(normalizedHubAddress);
|
|
424
|
+
return {
|
|
425
|
+
evidence: normalizedHubAddress
|
|
426
|
+
? 'authenticated-udp-endpoint-rendezvous-observed'
|
|
427
|
+
: 'authenticated-udp-endpoint-hub-egress-unavailable',
|
|
428
|
+
differentPublicEgress: clientAddressPublic && hubAddressPublic
|
|
429
|
+
? clientAddress !== normalizedHubAddress
|
|
430
|
+
: null,
|
|
431
|
+
clientAddressHash: digest(clientAddress),
|
|
432
|
+
hubAddressHash: digest(normalizedHubAddress),
|
|
433
|
+
clientAddressPublic,
|
|
434
|
+
hubAddressPublic,
|
|
435
|
+
endpointAuthenticated: true,
|
|
436
|
+
udpReady: session.ready === true,
|
|
437
|
+
observedAt: session.lastPacketAt ? new Date(session.lastPacketAt).toISOString() : '',
|
|
438
|
+
hubAddressObservedAt,
|
|
439
|
+
hubEndpointSource: normalizedHubAddress
|
|
440
|
+
? 'trusted-rendezvous-observation'
|
|
441
|
+
: 'unavailable'
|
|
442
|
+
};
|
|
443
|
+
}
|
|
344
444
|
|
|
345
445
|
async function close() {
|
|
346
446
|
stopRendezvousRefreshTimer();
|
|
@@ -354,9 +454,11 @@ export function createHubUdpTransport({ env = process.env, logEvent = () => {},
|
|
|
354
454
|
start,
|
|
355
455
|
close,
|
|
356
456
|
registerDevice,
|
|
357
|
-
unregisterDevice,
|
|
358
|
-
getDeviceStatus,
|
|
359
|
-
|
|
457
|
+
unregisterDevice,
|
|
458
|
+
getDeviceStatus,
|
|
459
|
+
refreshDeviceDiagnosticNetwork,
|
|
460
|
+
getDeviceDiagnosticNetwork,
|
|
461
|
+
getStatus,
|
|
360
462
|
setFrameHandler: handler => { frameHandler = typeof handler === 'function' ? handler : () => {}; },
|
|
361
463
|
setEventHandler: handler => { eventHandler = typeof handler === 'function' ? handler : () => {}; }
|
|
362
464
|
};
|
|
@@ -300,7 +300,9 @@ export function createUdpRendezvousServer({
|
|
|
300
300
|
roomId,
|
|
301
301
|
role: 'client',
|
|
302
302
|
host: client.address,
|
|
303
|
-
port: client.port
|
|
303
|
+
port: client.port,
|
|
304
|
+
observedHost: hub.address,
|
|
305
|
+
observedPort: hub.port
|
|
304
306
|
}, hub.address, hub.port);
|
|
305
307
|
send({
|
|
306
308
|
type: 'rendezvous.peer',
|
|
@@ -308,7 +310,9 @@ export function createUdpRendezvousServer({
|
|
|
308
310
|
roomId,
|
|
309
311
|
role: 'hub',
|
|
310
312
|
host: hub.address,
|
|
311
|
-
port: hub.port
|
|
313
|
+
port: hub.port,
|
|
314
|
+
observedHost: client.address,
|
|
315
|
+
observedPort: client.port
|
|
312
316
|
}, client.address, client.port);
|
|
313
317
|
}
|
|
314
318
|
|
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.460",
|
|
4
|
+
"livedeskClientVersion": "0.1.213",
|
|
5
5
|
"buildFlavor": "production",
|
|
6
6
|
"description": "LiveDesk Hub and client launcher",
|
|
7
7
|
"type": "module",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"README.md"
|
|
22
22
|
],
|
|
23
23
|
"scripts": {
|
|
24
|
-
"check": "node --check bin/livedesk.js && node --check diagnostics/livedesk-mode3-capture-smoke.mjs && node --check diagnostics/livedesk-mac-physical-gate-core.mjs && node --check diagnostics/livedesk-mac-physical-isolation.mjs && node --check scripts/sync-web-dist.js",
|
|
24
|
+
"check": "node --check bin/livedesk.js && node --check diagnostics/livedesk-mode3-capture-smoke.mjs && node --check diagnostics/livedesk-mac-physical-gate-core.mjs && node --check diagnostics/livedesk-mac-physical-isolation.mjs && node --check diagnostics/livedesk-transport-physical-core.mjs && node --check diagnostics/livedesk-transport-physical.mjs && node --check scripts/sync-web-dist.js",
|
|
25
25
|
"build": "node scripts/sync-web-dist.js",
|
|
26
26
|
"prepack": "node scripts/sync-web-dist.js",
|
|
27
27
|
"pack:dry": "npm pack --dry-run"
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"ws": "^8.18.3"
|
|
51
51
|
},
|
|
52
52
|
"optionalDependencies": {
|
|
53
|
-
"@livedesk/fast-linux-x64": "0.1.
|
|
54
|
-
"@livedesk/fast-osx-arm64": "0.1.
|
|
55
|
-
"@livedesk/fast-osx-x64": "0.1.
|
|
56
|
-
"@livedesk/fast-win-x64": "0.1.
|
|
53
|
+
"@livedesk/fast-linux-x64": "0.1.417",
|
|
54
|
+
"@livedesk/fast-osx-arm64": "0.1.417",
|
|
55
|
+
"@livedesk/fast-osx-x64": "0.1.417",
|
|
56
|
+
"@livedesk/fast-win-x64": "0.1.417"
|
|
57
57
|
},
|
|
58
58
|
"publishConfig": {
|
|
59
59
|
"access": "public"
|