bgrun 3.12.16 → 3.12.21

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/dist/deps.js CHANGED
@@ -17,48 +17,59 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
17
  var __require = import.meta.require;
18
18
 
19
19
  // src/platform.ts
20
- var exports_platform = {};
21
- __export(exports_platform, {
22
- waitForPortFree: () => waitForPortFree,
23
- terminateProcess: () => terminateProcess,
24
- reconcileProcessPids: () => reconcileProcessPids,
25
- readFileTail: () => readFileTail,
26
- psExec: () => psExec,
27
- parseUnixListeningPorts: () => parseUnixListeningPorts,
28
- killProcessOnPort: () => killProcessOnPort,
29
- isWindows: () => isWindows,
30
- isProcessRunning: () => isProcessRunning,
31
- isPortFree: () => isPortFree,
32
- getShellCommand: () => getShellCommand,
33
- getProcessPorts: () => getProcessPorts,
34
- getProcessMemory: () => getProcessMemory,
35
- getProcessBatchResources: () => getProcessBatchResources,
36
- getPortInfo: () => getPortInfo,
37
- getHomeDir: () => getHomeDir,
38
- findPidByPort: () => findPidByPort,
39
- findChildPid: () => findChildPid,
40
- ensureDir: () => ensureDir,
41
- copyFile: () => copyFile
42
- });
43
20
  import * as fs from "fs";
44
21
  import * as os from "os";
45
22
  import { join } from "path";
46
23
  var {$ } = globalThis.Bun;
47
24
  import { createMeasure } from "measure-fn";
48
- function psExec(command, _timeoutMs = 3000) {
49
- const tmpFile = join(os.tmpdir(), `bgr-ps-${Date.now()}.ps1`);
25
+ async function psExec(command, timeoutMs = 3000) {
26
+ const tmpFile = join(os.tmpdir(), `bgr-ps-${Date.now()}-${Math.random().toString(36).substr(2, 9)}.ps1`);
50
27
  try {
51
- fs.writeFileSync(tmpFile, command);
52
- const result = Bun.spawnSync(["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", tmpFile]);
28
+ await Bun.write(tmpFile, command);
29
+ const proc = Bun.spawn([
30
+ "powershell",
31
+ "-NoProfile",
32
+ "-ExecutionPolicy",
33
+ "Bypass",
34
+ "-File",
35
+ tmpFile
36
+ ], {
37
+ stdout: "pipe",
38
+ stderr: "pipe"
39
+ });
40
+ const timeoutPromise = new Promise((_, reject) => {
41
+ setTimeout(() => reject(new Error("PowerShell command timed out")), timeoutMs);
42
+ });
43
+ const resultPromise = new Promise(async (resolve, reject) => {
44
+ try {
45
+ const stdoutPromise = proc.stdout ? new Response(proc.stdout).text() : Promise.resolve("");
46
+ const stderrPromise = proc.stderr ? new Response(proc.stderr).text() : Promise.resolve("");
47
+ const exitCode = await proc.exited;
48
+ const stdout = await stdoutPromise;
49
+ const stderr = await stderrPromise;
50
+ if (exitCode === 0) {
51
+ resolve(stdout);
52
+ } else {
53
+ resolve(stderr || "");
54
+ }
55
+ } catch (error) {
56
+ reject(error);
57
+ }
58
+ });
53
59
  try {
54
- fs.unlinkSync(tmpFile);
55
- } catch {}
56
- return result.stdout?.toString() || "";
57
- } catch {
60
+ const result = await Promise.race([resultPromise, timeoutPromise]);
61
+ return result.trim();
62
+ } catch (error) {
63
+ return "";
64
+ } finally {
65
+ try {
66
+ await Bun.sleep(100);
67
+ } catch {}
68
+ }
69
+ } finally {
58
70
  try {
59
- fs.unlinkSync(tmpFile);
71
+ fs.rmSync(tmpFile, { force: true });
60
72
  } catch {}
61
- return "";
62
73
  }
63
74
  }
64
75
  function isWindows() {
@@ -80,7 +91,7 @@ async function isProcessRunning(pid, command) {
80
91
  process.kill(pid, 0);
81
92
  return true;
82
93
  } catch {
83
- const output = psExec(`Get-Process -Id ${pid} -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Id`).trim();
94
+ const output = await psExec(`Get-Process -Id ${pid} -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Id`);
84
95
  return output === String(pid);
85
96
  }
86
97
  } else {
@@ -173,35 +184,6 @@ async function isPortFree(port) {
173
184
  return true;
174
185
  }
175
186
  }
176
- async function getPortInfo(port) {
177
- try {
178
- if (isWindows()) {
179
- const result = await $`netstat -ano | findstr :${port}`.nothrow().quiet().text();
180
- for (const line of result.split(`
181
- `)) {
182
- const match = line.match(new RegExp(`:(${port})\\s+.*LISTENING\\s+(\\d+)`));
183
- if (match) {
184
- const pid = parseInt(match[2]);
185
- if (pid > 0 && await isProcessRunning(pid)) {
186
- const nameResult = await $`powershell -NoProfile -Command "(Get-Process -Id ${pid} -ErrorAction SilentlyContinue).ProcessName"`.nothrow().quiet().text();
187
- return { inUse: true, pid, processName: nameResult.trim() || "unknown" };
188
- }
189
- }
190
- }
191
- return { inUse: false };
192
- } else {
193
- const result = await $`ss -tln sport = :${port}`.nothrow().quiet().text();
194
- const lines = result.trim().split(`
195
- `).filter((l) => l.trim());
196
- if (lines.length > 1) {
197
- return { inUse: true };
198
- }
199
- return { inUse: false };
200
- }
201
- } catch {
202
- return { inUse: false };
203
- }
204
- }
205
187
  async function waitForPortFree(port, timeoutMs = 5000) {
206
188
  const startTime = Date.now();
207
189
  const pollInterval = 300;
@@ -409,9 +391,6 @@ async function readFileTail(filePath, lines) {
409
391
  }
410
392
  }) ?? "";
411
393
  }
412
- function copyFile(src, dest) {
413
- fs.copyFileSync(src, dest);
414
- }
415
394
  async function getProcessMemory(pid) {
416
395
  const map = await getProcessBatchResources([pid]);
417
396
  return map.get(pid)?.memory || 0;
@@ -424,7 +403,7 @@ async function getProcessBatchResources(pids) {
424
403
  const pidSet = new Set(pids);
425
404
  try {
426
405
  if (isWindows()) {
427
- const output = psExec(`Get-Process -Id ${pids.join(",")} -ErrorAction SilentlyContinue | Select-Object Id, WorkingSet64 | ForEach-Object { Write-Output "$($_.Id)|$($_.WorkingSet64)" }`);
406
+ const output = await psExec(`Get-Process -Id ${pids.join(",")} -ErrorAction SilentlyContinue | Select-Object Id, WorkingSet64 | ForEach-Object { Write-Output "$($_.Id)|$($_.WorkingSet64)" }`);
428
407
  for (const line of output.split(`
429
408
  `)) {
430
409
  const sepIdx = line.indexOf("|");
@@ -504,6 +483,21 @@ async function getProcessPorts(pid) {
504
483
  return [];
505
484
  }
506
485
  }
486
+ async function resolvePidWithPorts(pid) {
487
+ const ports = await getProcessPorts(pid);
488
+ if (ports.length > 0 || !isWindows() || pid <= 0) {
489
+ return { pid, ports };
490
+ }
491
+ const childPid = await findChildPid(pid);
492
+ if (childPid === pid || childPid <= 0) {
493
+ return { pid, ports };
494
+ }
495
+ const childPorts = await getProcessPorts(childPid);
496
+ if (childPorts.length > 0) {
497
+ return { pid: childPid, ports: childPorts };
498
+ }
499
+ return { pid, ports };
500
+ }
507
501
  var plat;
508
502
  var init_platform = __esm(() => {
509
503
  plat = createMeasure("platform");
@@ -580,7 +574,7 @@ function removeProcessByName(name) {
580
574
  function updateProcessPid(name, newPid) {
581
575
  const proc = db.process.select().where({ name }).limit(1).get();
582
576
  if (proc) {
583
- db.process.update(proc.id, { pid: newPid });
577
+ proc.update({ pid: newPid });
584
578
  }
585
579
  }
586
580
  function removeAllProcesses() {
@@ -592,7 +586,7 @@ function removeAllProcesses() {
592
586
  function updateProcessEnv(name, envJson) {
593
587
  const proc = db.process.select().where({ name }).limit(1).get();
594
588
  if (proc) {
595
- db.process.update(proc.id, { env: envJson });
589
+ proc.update({ env: envJson });
596
590
  }
597
591
  }
598
592
  function getAllTemplates() {
@@ -830,6 +824,8 @@ var init_db = __esm(() => {
830
824
 
831
825
  // src/utils.ts
832
826
  import * as fs2 from "fs";
827
+ import * as os2 from "os";
828
+ import { join as join3 } from "path";
833
829
  function parseEnvString(envString) {
834
830
  const env = {};
835
831
  envString.split(",").forEach((pair) => {
@@ -845,9 +841,92 @@ function calculateRuntime(startTime) {
845
841
  const diffInMinutes = Math.floor((now - start) / (1000 * 60));
846
842
  return `${diffInMinutes} minutes`;
847
843
  }
844
+ function parseCommandEnv(command) {
845
+ const env = {};
846
+ const trimmed = command.trim();
847
+ const windowsSegments = trimmed.split(/&&/).map((segment) => segment.trim());
848
+ for (const segment of windowsSegments) {
849
+ const match = segment.match(/^set\s+([A-Za-z_][A-Za-z0-9_]*)=(.*)$/i);
850
+ if (!match)
851
+ break;
852
+ env[match[1]] = match[2].trim();
853
+ }
854
+ const unixPrefixRegex = /^(?:([A-Za-z_][A-Za-z0-9_]*)=([^\s]+)\s+)+/;
855
+ const unixPrefix = trimmed.match(unixPrefixRegex);
856
+ if (unixPrefix) {
857
+ const pairs = unixPrefix[0].trim().split(/\s+/);
858
+ for (const pair of pairs) {
859
+ const eqIdx = pair.indexOf("=");
860
+ if (eqIdx <= 0)
861
+ continue;
862
+ const key = pair.slice(0, eqIdx);
863
+ const value = pair.slice(eqIdx + 1);
864
+ if (key)
865
+ env[key] = value;
866
+ }
867
+ }
868
+ return env;
869
+ }
870
+ function getDeclaredPort(processEnv, command) {
871
+ const mergedEnv = { ...command ? parseCommandEnv(command) : {}, ...processEnv };
872
+ const raw = mergedEnv.PORT || mergedEnv.BUN_PORT || "";
873
+ const parsed = parseInt(raw, 10);
874
+ return !isNaN(parsed) && parsed > 0 ? parsed : null;
875
+ }
876
+ function buildManagedProcessEnv(parentEnv, processEnv = {}) {
877
+ const sanitizedParentEnv = {};
878
+ for (const [key, value] of Object.entries(parentEnv)) {
879
+ if (value === undefined)
880
+ continue;
881
+ if (INTERNAL_MANAGED_ENV_KEYS.includes(key))
882
+ continue;
883
+ sanitizedParentEnv[key] = value;
884
+ }
885
+ return { ...sanitizedParentEnv, ...processEnv };
886
+ }
887
+ function stringifyEnvString(env) {
888
+ return Object.entries(env).map(([key, value]) => `${key}=${value}`).join(",");
889
+ }
890
+ function getWatcherProcessName(targetName) {
891
+ return `${WATCHER_PREFIX}${encodeURIComponent(targetName)}`;
892
+ }
893
+ function getWatchedProcessName(watcherName) {
894
+ if (!watcherName.startsWith(WATCHER_PREFIX))
895
+ return null;
896
+ try {
897
+ return decodeURIComponent(watcherName.slice(WATCHER_PREFIX.length));
898
+ } catch {
899
+ return null;
900
+ }
901
+ }
902
+ function isWatcherProcessName(name) {
903
+ return getWatchedProcessName(name) !== null;
904
+ }
905
+ function isInternalProcessName(name) {
906
+ return name === "bgr-dashboard" || name === "bgr-guard" || isWatcherProcessName(name);
907
+ }
908
+ function getOperationLockPath(name) {
909
+ return join3(os2.homedir(), ".bgr", `${name}.operation.lock`);
910
+ }
911
+ function acquireProcessOperationLock(name) {
912
+ const lockPath = getOperationLockPath(name);
913
+ fs2.mkdirSync(join3(os2.homedir(), ".bgr"), { recursive: true });
914
+ fs2.writeFileSync(lockPath, JSON.stringify({ pid: process.pid, time: Date.now() }));
915
+ let released = false;
916
+ return () => {
917
+ if (released)
918
+ return;
919
+ released = true;
920
+ try {
921
+ fs2.unlinkSync(lockPath);
922
+ } catch {}
923
+ };
924
+ }
925
+ function isProcessOperationLocked(name) {
926
+ return fs2.existsSync(getOperationLockPath(name));
927
+ }
848
928
  async function getVersion() {
849
929
  try {
850
- const { join: join3 } = await import("path");
851
930
  const pkgPath = join3(import.meta.dir, "../package.json");
852
931
  const pkg = await Bun.file(pkgPath).json();
853
932
  return pkg.version || "0.0.0";
@@ -903,8 +982,10 @@ function tailFile(path, prefix, colorFn, lines) {
903
982
  } catch {}
904
983
  };
905
984
  }
985
+ var INTERNAL_MANAGED_ENV_KEYS, WATCHER_PREFIX = "bgr-watch-";
906
986
  var init_utils = __esm(() => {
907
987
  init_platform();
988
+ INTERNAL_MANAGED_ENV_KEYS = ["BUN_PORT", "BGR_STDOUT", "BGR_STDERR"];
908
989
  });
909
990
 
910
991
  // src/deps.ts