livedesk 0.1.434 → 0.1.435

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.
Files changed (2) hide show
  1. package/bin/livedesk.js +69 -6
  2. package/package.json +1 -1
package/bin/livedesk.js CHANGED
@@ -576,6 +576,59 @@ function isKnownLiveDeskLauncherProcess(processName, commandLine) {
576
576
  && /(?:^|\/)bin\/livedesk\.js(?:\s|["']|$)/i.test(normalizedCommandLine);
577
577
  }
578
578
 
579
+ function existingRuntimeProbePorts() {
580
+ return [...new Set([
581
+ process.env.LIVEDESK_CLIENT_RUNTIME_PORT,
582
+ process.env.LIVEDESK_HUB_HTTP_PORT,
583
+ DEFAULT_MANAGER_HTTP_PORT
584
+ ]
585
+ .map(value => normalizePort(value, 0))
586
+ .filter(port => port > 0))];
587
+ }
588
+
589
+ async function probeExistingRuntimeIdentity(existing) {
590
+ const processId = Number(existing?.pid);
591
+ const expectedRole = String(existing?.role || '').trim().toLowerCase();
592
+ if (!Number.isInteger(processId) || processId <= 1 || !expectedRole) {
593
+ return null;
594
+ }
595
+
596
+ for (const port of existingRuntimeProbePorts()) {
597
+ const controller = new AbortController();
598
+ const timer = setTimeout(() => controller.abort(), 1200);
599
+ try {
600
+ const baseUrl = `http://127.0.0.1:${port}`;
601
+ const [healthResponse, statusResponse] = await Promise.all([
602
+ fetch(`${baseUrl}/api/health`, { cache: 'no-store', signal: controller.signal }),
603
+ fetch(`${baseUrl}/api/runtime/status`, { cache: 'no-store', signal: controller.signal })
604
+ ]);
605
+ if (!healthResponse.ok || !statusResponse.ok) {
606
+ continue;
607
+ }
608
+ const [health, status] = await Promise.all([
609
+ healthResponse.json(),
610
+ statusResponse.json()
611
+ ]);
612
+ if (health?.ok === true
613
+ && health?.product === 'LiveDesk'
614
+ && status?.ok === true
615
+ && Number(status?.runtimePid) === processId
616
+ && String(status?.role || '').trim().toLowerCase() === expectedRole) {
617
+ return {
618
+ port,
619
+ role: expectedRole,
620
+ appVersion: String(status?.appVersion || '')
621
+ };
622
+ }
623
+ } catch {
624
+ // A non-LiveDesk, stopping, or unreachable owner is not runtime proof.
625
+ } finally {
626
+ clearTimeout(timer);
627
+ }
628
+ }
629
+ return null;
630
+ }
631
+
579
632
  async function getProcessDetails(pid) {
580
633
  const processId = Number(pid);
581
634
  if (!Number.isInteger(processId) || processId <= 1) {
@@ -633,13 +686,20 @@ async function stopExistingRuntime(existing) {
633
686
 
634
687
  const details = await getProcessDetails(processId);
635
688
  if (!details) {
636
- return;
689
+ return null;
637
690
  }
638
- if (!isKnownLiveDeskLauncherProcess(details.processName, details.commandLine)) {
691
+ const commandLineConfirmed = isKnownLiveDeskLauncherProcess(details.processName, details.commandLine);
692
+ const runtimeProof = commandLineConfirmed
693
+ ? null
694
+ : await probeExistingRuntimeIdentity(existing);
695
+ if (!commandLineConfirmed && !runtimeProof) {
639
696
  throw new Error(`Existing runtime pid ${processId} is not a confirmed LiveDesk launcher; it was preserved.`);
640
697
  }
641
698
 
642
- console.log(`[LiveDesk] Stopping existing ${existing?.role || 'runtime'} launcher pid ${processId} before starting a fresh runtime.`);
699
+ const identityProof = commandLineConfirmed
700
+ ? 'command-line'
701
+ : `runtime-api:${runtimeProof.port}:${runtimeProof.appVersion || 'unknown'}`;
702
+ console.log(`[LiveDesk] Stopping existing ${existing?.role || 'runtime'} launcher pid ${processId} before starting a fresh runtime (identity=${identityProof}).`);
643
703
  if (os.platform() === 'win32') {
644
704
  await runQuiet('taskkill.exe', ['/PID', String(processId), '/T', '/F']);
645
705
  } else {
@@ -648,14 +708,17 @@ async function stopExistingRuntime(existing) {
648
708
  }
649
709
  }
650
710
  await waitForProcessExit(processId);
711
+ return runtimeProof;
651
712
  }
652
713
 
653
714
  async function restartExistingRuntime(existing, role) {
654
- await stopExistingRuntime(existing);
715
+ const runtimeProof = await stopExistingRuntime(existing);
716
+ const runtimePort = Number(runtimeProof?.port || existingRuntimeProbePorts()[0] || DEFAULT_MANAGER_HTTP_PORT);
655
717
  if (role === 'hub' || String(existing?.role || '').trim().toLowerCase() === 'hub') {
656
- await stopProcessesOnPorts([DEFAULT_MANAGER_HTTP_PORT, DEFAULT_REMOTE_HUB_PORT]);
718
+ const remotePort = normalizePort(process.env.REMOTE_HUB_PORT, DEFAULT_REMOTE_HUB_PORT);
719
+ await stopProcessesOnPorts([runtimePort, remotePort]);
657
720
  } else {
658
- await stopProcessesOnPorts([DEFAULT_MANAGER_HTTP_PORT]);
721
+ await stopProcessesOnPorts([runtimePort]);
659
722
  }
660
723
  }
661
724
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livedesk",
3
- "version": "0.1.434",
3
+ "version": "0.1.435",
4
4
  "livedeskClientVersion": "0.1.191",
5
5
  "buildFlavor": "production",
6
6
  "description": "LiveDesk Hub and client launcher",