livedesk 0.1.251 → 0.1.252

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/README.md CHANGED
@@ -16,12 +16,12 @@ continues to listen on the LAN.
16
16
  On startup, the launcher finds stale processes whose command line identifies
17
17
  them as a LiveDesk Hub, even if the old Hub is still starting and has not
18
18
  finished binding its ports. It also checks the Hub ports (`5179` and `5197`),
19
- waits for stale LiveDesk processes to exit, and then starts the new Hub. An
20
- unrelated process is preserved and reported instead of being terminated. If
21
- the client port remains occupied, the Hub automatically retries on a nearby
22
- port and publishes that actual endpoint to clients. The HTTP manager port
23
- remains strict so a web UI collision is reported clearly. Pass `--no-clean` to
24
- disable the startup cleanup explicitly.
19
+ waits for stale LiveDesk processes to exit, and then starts the new Hub. The
20
+ client endpoint remains fixed at TCP `5197` by default so firewall rules,
21
+ router forwarding, and direct clients keep a stable contract. An unrelated
22
+ process is preserved and reported instead of being terminated; stop it or use
23
+ an explicit `--remote-port` value. Pass `--no-clean` to disable the startup
24
+ cleanup explicitly.
25
25
 
26
26
  ## Client
27
27
 
package/bin/livedesk.js CHANGED
@@ -37,8 +37,7 @@ Hub options:
37
37
  --host <host> Hub HTTP host. Default: 127.0.0.1
38
38
  --port <port> Hub HTTP port. Default: 5179
39
39
  --remote-port <port>
40
- Preferred client connection port. Default: 5197; if busy,
41
- LiveDesk retries on a nearby port automatically.
40
+ Client connection port. Default: 5197.
42
41
  --no-clean Do not stop existing processes on the Hub ports.
43
42
 
44
43
  Common:
@@ -213,7 +212,7 @@ function runQuiet(command, args) {
213
212
  });
214
213
  }
215
214
 
216
- async function stopProcessesOnPorts(ports, { allowBusyPorts = false } = {}) {
215
+ async function stopProcessesOnPorts(ports) {
217
216
  const uniquePorts = [...new Set(ports.map(port => normalizePort(port, 0)).filter(Boolean))];
218
217
  if (uniquePorts.length === 0) {
219
218
  return;
@@ -293,11 +292,7 @@ async function stopProcessesOnPorts(ports, { allowBusyPorts = false } = {}) {
293
292
  const blocked = records.filter(record => record?.PortAvailable !== true || (record?.Port === 0 && record?.ProcessGone !== true));
294
293
  if (blocked.length > 0) {
295
294
  const summary = blocked.map(record => `${record.Pid}:${record.ProcessName || 'unknown'}@${record.Port}[port-free=${record.PortAvailable === true},process-gone=${record.ProcessGone === true}]`).join(', ');
296
- const message = `LiveDesk Hub startup cleanup could not release port/process owner(s): ${summary}`;
297
- if (!allowBusyPorts) {
298
- throw new Error(`${message}. If this is an unrelated process, use --port or stop it manually.`);
299
- }
300
- console.warn(`${message}. The client endpoint will retry on another port automatically.`);
295
+ throw new Error(`LiveDesk Hub startup cleanup could not release port/process owner(s): ${summary}. LiveDesk keeps the configured port fixed; stop that process or choose an explicit --port/--remote-port value.`);
301
296
  }
302
297
  return;
303
298
  }
@@ -355,8 +350,7 @@ async function runManager(args) {
355
350
  || getStablePairToken();
356
351
 
357
352
  if (options.cleanPortsOnStart) {
358
- await stopProcessesOnPorts([httpPort]);
359
- await stopProcessesOnPorts([remotePort], { allowBusyPorts: true });
353
+ await stopProcessesOnPorts([httpPort, remotePort]);
360
354
  }
361
355
 
362
356
  const internalHubEntry = resolve(packageRoot, 'hub', 'src', 'server.js');
@@ -4,8 +4,6 @@ import crypto from 'crypto';
4
4
 
5
5
  const DEFAULT_REMOTE_HUB_PORT = 5197;
6
6
  const DEFAULT_REMOTE_HUB_HOST = '0.0.0.0';
7
- const DEFAULT_REMOTE_HUB_PORT_FALLBACK_ATTEMPTS = 32;
8
- const REMOTE_HUB_AUTH_CALLBACK_PORT = 5198;
9
7
  const DEFAULT_HEARTBEAT_MS = 5000;
10
8
  const DEFAULT_AGENT_TASK_TIMEOUT_MS = 120000;
11
9
  const MAX_LINE_CHARS = 4 * 1024 * 1024;
@@ -1419,14 +1417,6 @@ export function createRemoteHub(options = {}) {
1419
1417
  && !isDisabledValue(env.REMOTE_HUB_DISABLED);
1420
1418
  const host = safeString(env.REMOTE_HUB_HOST || DEFAULT_REMOTE_HUB_HOST, 128);
1421
1419
  const requestedPort = normalizePort(env.REMOTE_HUB_PORT || DEFAULT_REMOTE_HUB_PORT);
1422
- const remotePortFallbackEnabled = isEnabledValue(env.REMOTE_HUB_PORT_FALLBACK, true)
1423
- && !isDisabledValue(env.REMOTE_HUB_PORT_FALLBACK_DISABLED);
1424
- const remotePortFallbackStrict = isEnabledValue(env.REMOTE_HUB_PORT_FALLBACK_STRICT, false);
1425
- const remotePortFallbackAttempts = clampNumber(
1426
- env.REMOTE_HUB_PORT_FALLBACK_ATTEMPTS,
1427
- 1,
1428
- 128,
1429
- DEFAULT_REMOTE_HUB_PORT_FALLBACK_ATTEMPTS);
1430
1420
  const heartbeatMs = clampNumber(env.REMOTE_HUB_HEARTBEAT_MS, 1000, 60000, DEFAULT_HEARTBEAT_MS);
1431
1421
  const taskTimeoutMs = clampNumber(
1432
1422
  options.taskTimeoutMs ?? env.REMOTE_HUB_TASK_TIMEOUT_MS,
@@ -4381,17 +4371,6 @@ export function createRemoteHub(options = {}) {
4381
4371
  });
4382
4372
  }
4383
4373
 
4384
- function getNextFallbackPort(currentPort, attemptedPorts) {
4385
- for (let offset = 1; offset <= 65535; offset += 1) {
4386
- const candidate = (currentPort + offset) % 65536;
4387
- if (candidate < 1 || candidate === REMOTE_HUB_AUTH_CALLBACK_PORT || attemptedPorts.has(candidate)) {
4388
- continue;
4389
- }
4390
- return candidate;
4391
- }
4392
- return 0;
4393
- }
4394
-
4395
4374
  function listenOnPort(port) {
4396
4375
  return new Promise((resolve, reject) => {
4397
4376
  const candidateServer = net.createServer(handleSocket);
@@ -4422,40 +4401,19 @@ export function createRemoteHub(options = {}) {
4422
4401
  return getStatus({ includeSecrets: false });
4423
4402
  }
4424
4403
 
4425
- const fallbackAllowed = remotePortFallbackEnabled
4426
- && !remotePortFallbackStrict
4427
- && requestedPort > 0;
4428
- const attemptedPorts = new Set();
4429
- let candidatePort = requestedPort;
4430
- let lastBindError = null;
4431
-
4432
- for (let attempt = 0; attempt < remotePortFallbackAttempts; attempt += 1) {
4433
- attemptedPorts.add(candidatePort);
4434
- try {
4435
- await listenOnPort(candidatePort);
4436
- if (candidatePort !== requestedPort) {
4437
- logWarn(
4438
- 'remote',
4439
- `Client port ${requestedPort} is already in use; LiveDesk Hub is using ${candidatePort}.`);
4440
- }
4441
- lastBindError = null;
4442
- break;
4443
- } catch (error) {
4444
- lastBindError = error;
4445
- if (error?.code !== 'EADDRINUSE' || !fallbackAllowed) {
4446
- throw error;
4447
- }
4448
-
4449
- const nextPort = getNextFallbackPort(candidatePort, attemptedPorts);
4450
- if (!nextPort) {
4451
- break;
4452
- }
4453
- candidatePort = nextPort;
4404
+ try {
4405
+ await listenOnPort(requestedPort);
4406
+ } catch (error) {
4407
+ if (error?.code === 'EADDRINUSE') {
4408
+ const conflict = new Error(
4409
+ `LiveDesk Hub requires client endpoint TCP ${requestedPort}, but that port is already in use. Close the owning process or start Hub with an explicit --remote-port value.`);
4410
+ conflict.code = 'EADDRINUSE';
4411
+ conflict.port = requestedPort;
4412
+ conflict.cause = error;
4413
+ lastError = conflict.message;
4414
+ throw conflict;
4454
4415
  }
4455
- }
4456
-
4457
- if (lastBindError) {
4458
- throw lastBindError;
4416
+ throw error;
4459
4417
  }
4460
4418
 
4461
4419
  return getStatus({ includeSecrets: false });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livedesk",
3
- "version": "0.1.251",
3
+ "version": "0.1.252",
4
4
  "description": "LiveDesk Hub and client launcher",
5
5
  "type": "module",
6
6
  "bin": {