@absolutejs/absolute 0.19.0-beta.1028 → 0.19.0-beta.1029

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.
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-Wwl6hk/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-Ye9d69/src/core/streamingSlotRegistrar.ts
5
5
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
6
6
  var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
7
7
  var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-Wwl6hk/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-Ye9d69/src/core/streamingSlotRegistrar.ts
5
5
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
6
6
  var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
7
7
  var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
@@ -48,7 +48,7 @@ var warnMissingStreamingSlotCollector = (primitiveName) => {
48
48
  getWarningController()?.maybeWarn(primitiveName);
49
49
  };
50
50
 
51
- // .angular-partial-tmp-Wwl6hk/src/core/streamingSlotRegistry.ts
51
+ // .angular-partial-tmp-Ye9d69/src/core/streamingSlotRegistry.ts
52
52
  var STREAMING_SLOT_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotAsyncLocalStorage");
53
53
  var isObjectRecord2 = (value) => Boolean(value) && typeof value === "object";
54
54
  var isAsyncLocalStorage = (value) => isObjectRecord2(value) && ("getStore" in value) && typeof value.getStore === "function" && ("run" in value) && typeof value.run === "function";
package/dist/cli/index.js CHANGED
@@ -652,8 +652,99 @@ var init_loadConfig = __esm(() => {
652
652
  ]);
653
653
  });
654
654
 
655
- // src/cli/utils.ts
655
+ // src/utils/portScan.ts
656
656
  var {$ } = globalThis.Bun;
657
+ var parsePort = (address) => {
658
+ const match = address.replace(/\(LISTEN\)$/, "").match(/:(\d+)$/);
659
+ return match ? Number(match[1]) : null;
660
+ }, parseLsof = (text) => {
661
+ const seen = new Set;
662
+ const listeners = [];
663
+ for (const line of text.split(`
664
+ `)) {
665
+ if (line.length === 0 || line.startsWith("COMMAND"))
666
+ continue;
667
+ const tokens = line.trim().split(/\s+/);
668
+ const [, pidText] = tokens;
669
+ const pid = Number(pidText);
670
+ const address = tokens.find((token) => /:\d+$/.test(token));
671
+ const port = address ? parsePort(address) : null;
672
+ if (!Number.isInteger(pid) || port === null)
673
+ continue;
674
+ const key = `${pid}:${port}`;
675
+ if (seen.has(key))
676
+ continue;
677
+ seen.add(key);
678
+ listeners.push({ pid, port });
679
+ }
680
+ return listeners;
681
+ }, parseSs = (text) => {
682
+ const seen = new Set;
683
+ const listeners = [];
684
+ for (const line of text.split(`
685
+ `)) {
686
+ if (line.trim().length === 0)
687
+ continue;
688
+ const [, , , local] = line.trim().split(/\s+/);
689
+ const port = local ? parsePort(local) : null;
690
+ const pidMatch = line.match(/pid=(\d+)/);
691
+ if (port === null || !pidMatch)
692
+ continue;
693
+ const pid = Number(pidMatch[1]);
694
+ const key = `${pid}:${port}`;
695
+ if (seen.has(key))
696
+ continue;
697
+ seen.add(key);
698
+ listeners.push({ pid, port });
699
+ }
700
+ return listeners;
701
+ }, rawListeners = async () => {
702
+ const lsof = await $`lsof -nP -iTCP -sTCP:LISTEN`.quiet().nothrow().text();
703
+ if (lsof.trim().length > 0)
704
+ return parseLsof(lsof);
705
+ const ssOutput = await $`ss -ltnpH`.quiet().nothrow().text();
706
+ if (ssOutput.trim().length > 0)
707
+ return parseSs(ssOutput);
708
+ return [];
709
+ }, describeProcesses = async (pids) => {
710
+ const details = new Map;
711
+ if (pids.length === 0)
712
+ return details;
713
+ const output = await $`ps -o pid=,etimes=,args= -p ${pids.join(",")}`.quiet().nothrow().text();
714
+ for (const line of output.split(`
715
+ `)) {
716
+ const trimmed = line.trim();
717
+ if (trimmed.length === 0)
718
+ continue;
719
+ const match = trimmed.match(/^(\d+)\s+(\d+)\s+(.*)$/);
720
+ if (!match)
721
+ continue;
722
+ const [, pidText, etimesText, command = ""] = match;
723
+ details.set(Number(pidText), { command, etimes: Number(etimesText) });
724
+ }
725
+ return details;
726
+ }, scanListeners = async () => {
727
+ const listeners = await rawListeners();
728
+ const pids = [...new Set(listeners.map((listener) => listener.pid))].filter((pid) => pid !== process.pid && pid > 0);
729
+ const details = await describeProcesses(pids);
730
+ return listeners.flatMap((listener) => {
731
+ const detail = details.get(listener.pid);
732
+ if (!detail)
733
+ return [];
734
+ return [
735
+ {
736
+ command: detail.command,
737
+ etimes: detail.etimes,
738
+ pid: listener.pid,
739
+ port: listener.port
740
+ }
741
+ ];
742
+ });
743
+ };
744
+ var init_portScan = () => {};
745
+
746
+ // src/cli/utils.ts
747
+ var {$: $2 } = globalThis.Bun;
657
748
  import { execSync } from "child_process";
658
749
  import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
659
750
  import { resolve as resolve2 } from "path";
@@ -745,14 +836,14 @@ var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backe
745
836
  return { downCommand, upCommand };
746
837
  }, startDatabase = async (scripts) => {
747
838
  await timed("Starting database container...", async () => {
748
- const { exitCode } = await $`${{ raw: scripts.upCommand }}`.quiet().nothrow();
839
+ const { exitCode } = await $2`${{ raw: scripts.upCommand }}`.quiet().nothrow();
749
840
  if (exitCode !== 0)
750
841
  process.exit(exitCode);
751
842
  });
752
843
  }, stopDatabase = async (scripts) => {
753
844
  console.log(`
754
845
  Stopping database container...`);
755
- await $`${{ raw: scripts.downCommand }}`.quiet().nothrow();
846
+ await $2`${{ raw: scripts.downCommand }}`.quiet().nothrow();
756
847
  }, timed = async (label, task) => {
757
848
  process.stdout.write(label);
758
849
  const start = performance.now();
@@ -170767,6 +170858,62 @@ var init_build = __esm(() => {
170767
170858
  init_telemetryEvent();
170768
170859
  });
170769
170860
 
170861
+ // src/cli/discoverInstances.ts
170862
+ var MS_PER_SECOND = 1000, isJsRuntime = (command) => /\b(bun|deno|node)\b/.test(command), untrackedName = (command) => {
170863
+ const entry = command.split(/\s+/).find((token) => /\.(cjs|js|mjs|ts)$/.test(token));
170864
+ if (entry === undefined)
170865
+ return "untracked";
170866
+ const segments = entry.split("/").filter(Boolean);
170867
+ segments.pop();
170868
+ let dir = segments.pop();
170869
+ if (dir === "build" || dir === "dist" || dir === "src")
170870
+ dir = segments.pop();
170871
+ return dir ?? "untracked";
170872
+ }, toUntrackedRecord = (listener) => ({
170873
+ command: listener.command.split(/\s+/),
170874
+ configPath: null,
170875
+ controllerPid: listener.pid,
170876
+ cwd: "",
170877
+ frameworks: [],
170878
+ host: "localhost",
170879
+ https: false,
170880
+ logFile: null,
170881
+ name: untrackedName(listener.command),
170882
+ pid: listener.pid,
170883
+ port: listener.port,
170884
+ ppid: 0,
170885
+ source: "untracked",
170886
+ startedAt: new Date(Date.now() - listener.etimes * MS_PER_SECOND).toISOString()
170887
+ }), compareInstances2 = (left, right) => {
170888
+ const leftPort = left.port ?? Number.MAX_SAFE_INTEGER;
170889
+ const rightPort = right.port ?? Number.MAX_SAFE_INTEGER;
170890
+ if (leftPort !== rightPort)
170891
+ return leftPort - rightPort;
170892
+ return left.name.localeCompare(right.name);
170893
+ }, discoverInstances = async () => {
170894
+ const registered = listLiveInstances();
170895
+ const knownPids = new Set(registered.flatMap((record) => [record.pid, record.controllerPid]));
170896
+ const knownPorts = new Set(registered.map((record) => record.port).filter((port) => port !== null));
170897
+ const listeners = await scanListeners();
170898
+ const untracked = [];
170899
+ const seen = new Set;
170900
+ for (const listener of listeners) {
170901
+ if (knownPids.has(listener.pid) || seen.has(listener.pid))
170902
+ continue;
170903
+ if (knownPorts.has(listener.port))
170904
+ continue;
170905
+ if (!isJsRuntime(listener.command))
170906
+ continue;
170907
+ seen.add(listener.pid);
170908
+ untracked.push(toUntrackedRecord(listener));
170909
+ }
170910
+ return [...registered, ...untracked].sort(compareInstances2);
170911
+ };
170912
+ var init_discoverInstances = __esm(() => {
170913
+ init_instanceRegistry();
170914
+ init_portScan();
170915
+ });
170916
+
170770
170917
  // src/cli/instanceStatus.ts
170771
170918
  import { createConnection as createConnection2 } from "net";
170772
170919
  var displayHost = (host) => host === "0.0.0.0" || host === "::" ? "localhost" : host, probePort = (host, port) => {
@@ -170908,7 +171055,7 @@ var TUI_HEADERS, STATUS_INDEX = 5, URL_INDEX = 6, helpLines2, statusLevelColor =
170908
171055
  };
170909
171056
  const refresh = async () => {
170910
171057
  const previousPid = selectedInstance()?.pid;
170911
- instances = await enrichInstances(listLiveInstances());
171058
+ instances = await enrichInstances(await discoverInstances());
170912
171059
  const foundIndex = previousPid === undefined ? 0 : instances.findIndex((instance) => instance.pid === previousPid);
170913
171060
  selectedIndex = foundIndex >= 0 ? foundIndex : Math.min(selectedIndex, Math.max(0, instances.length - 1));
170914
171061
  scheduleRender();
@@ -171309,7 +171456,7 @@ var TUI_HEADERS, STATUS_INDEX = 5, URL_INDEX = 6, helpLines2, statusLevelColor =
171309
171456
  var init_listTui = __esm(() => {
171310
171457
  init_constants();
171311
171458
  init_getDurationString();
171312
- init_instanceRegistry();
171459
+ init_discoverInstances();
171313
171460
  init_instanceStatus();
171314
171461
  init_tuiPrimitives();
171315
171462
  init_utils();
@@ -171341,7 +171488,14 @@ var exports_list = {};
171341
171488
  __export(exports_list, {
171342
171489
  runList: () => runList
171343
171490
  });
171344
- var TABLE_HEADERS, statusColor2 = (status2) => {
171491
+ var killPid = (pid) => {
171492
+ try {
171493
+ process.kill(pid, "SIGTERM");
171494
+ return true;
171495
+ } catch {
171496
+ return false;
171497
+ }
171498
+ }, TABLE_HEADERS, statusColor2 = (status2) => {
171345
171499
  if (status2 === "ready")
171346
171500
  return colors.green;
171347
171501
  if (status2 === "starting")
@@ -171380,7 +171534,24 @@ var TABLE_HEADERS, statusColor2 = (status2) => {
171380
171534
  await runListTui2();
171381
171535
  return;
171382
171536
  }
171383
- const instances = await enrichInstances(listLiveInstances());
171537
+ const instances = await enrichInstances(await discoverInstances());
171538
+ if (args.includes("--kill-all")) {
171539
+ const killed = instances.filter((instance) => killPid(instance.pid));
171540
+ process.stdout.write(`${colors.dim}Killed ${killed.length} server${killed.length === 1 ? "" : "s"}.${colors.reset}
171541
+ `);
171542
+ return;
171543
+ }
171544
+ if (args.includes("--kill")) {
171545
+ const value = args[args.indexOf("--kill") + 1];
171546
+ const target = Number(value);
171547
+ const match = instances.find((instance) => instance.pid === target || instance.port === target);
171548
+ const pid = match?.pid ?? target;
171549
+ const killed = Number.isInteger(pid) && killPid(pid);
171550
+ const label = match ? `${match.name} (pid ${pid}${match.port === null ? "" : `, port ${match.port}`})` : `pid ${pid}`;
171551
+ process.stdout.write(`${colors.dim}${killed ? `Killed ${label}` : `No server found for \`--kill ${value ?? ""}\``}.${colors.reset}
171552
+ `);
171553
+ return;
171554
+ }
171384
171555
  if (args.includes("--json")) {
171385
171556
  process.stdout.write(`${JSON.stringify(instances, null, 2)}
171386
171557
  `);
@@ -171391,7 +171562,7 @@ var TABLE_HEADERS, statusColor2 = (status2) => {
171391
171562
  var init_list = __esm(() => {
171392
171563
  init_constants();
171393
171564
  init_getDurationString();
171394
- init_instanceRegistry();
171565
+ init_discoverInstances();
171395
171566
  init_instanceStatus();
171396
171567
  init_tuiPrimitives();
171397
171568
  TABLE_HEADERS = [
@@ -172854,7 +173025,7 @@ var init_tunnelRelay = __esm(() => {
172854
173025
 
172855
173026
  // src/cli/scripts/dev.ts
172856
173027
  init_constants();
172857
- var {$: $2, env } = globalThis.Bun;
173028
+ var {$: $3, env } = globalThis.Bun;
172858
173029
  import { spawn as nodeSpawn } from "child_process";
172859
173030
  import { createWriteStream, existsSync as existsSync5, readFileSync as readFileSync7 } from "fs";
172860
173031
  import { resolve as resolve3 } from "path";
@@ -173287,6 +173458,7 @@ init_telemetryEvent();
173287
173458
  init_buildDirectoryLock();
173288
173459
  init_instanceRegistry();
173289
173460
  init_loadConfig();
173461
+ init_portScan();
173290
173462
 
173291
173463
  // src/utils/resolveDevPort.ts
173292
173464
  import { createServer } from "net";
@@ -173435,7 +173607,9 @@ var dev = async (serverEntry, configPath2) => {
173435
173607
  let { port } = initialPortProbe;
173436
173608
  if (initialPortProbe.fellBack) {
173437
173609
  const displayHost = resolvedDev.host === "0.0.0.0" ? "localhost" : resolvedDev.host;
173438
- console.log(cliTag("\x1B[33m", `Port ${resolvedDev.port} is in use, trying another one... \u2192 http://${displayHost}:${port}/`));
173610
+ const holders = (await scanListeners()).filter((listener) => listener.port === resolvedDev.port);
173611
+ const heldBy = holders.length > 0 ? ` (held by ${holders.map((holder) => `pid ${holder.pid} \u2014 ${holder.command.slice(0, 60)}`).join(", ")})` : "";
173612
+ console.log(cliTag("\x1B[33m", `Port ${resolvedDev.port} is in use${heldBy}, trying another one... \u2192 http://${displayHost}:${port}/`));
173439
173613
  }
173440
173614
  updateLockMetadata(buildDirectory, { port });
173441
173615
  const instancePid = process.pid;
@@ -173835,7 +174009,7 @@ var dev = async (serverEntry, configPath2) => {
173835
174009
  }
173836
174010
  };
173837
174011
  const runShellCommand2 = async (command) => {
173838
- await $2`${{ raw: command }}`.env({ ...process.env, FORCE_COLOR: "1" }).nothrow();
174012
+ await $3`${{ raw: command }}`.env({ ...process.env, FORCE_COLOR: "1" }).nothrow();
173839
174013
  };
173840
174014
  const openInBrowser = async () => {
173841
174015
  const url = `http://${resolvedDev.host === "0.0.0.0" ? "localhost" : resolvedDev.host}:${port}`;
@@ -176290,7 +176464,7 @@ if (command === "dev") {
176290
176464
  console.error(" config [--port n] Open the unified config UI (ESLint, tsconfig, Prettier)");
176291
176465
  console.error(" eslint Run ESLint (cached)");
176292
176466
  console.error(" info Print system info for bug reports");
176293
- console.error(" ls [--watch] [--json] List/manage running servers (alias: ps)");
176467
+ console.error(" ls [--watch] [--json] [--kill <pid|port>] [--kill-all] List/manage running servers (alias: ps)");
176294
176468
  console.error(" prettier Run Prettier check (cached)");
176295
176469
  console.error(" typecheck Run type checkers for all frameworks");
176296
176470
  console.error(" telemetry Manage anonymous telemetry");
@@ -0,0 +1,5 @@
1
+ import type { InstanceRecord } from '../../types/cli';
2
+ /** Registry-tracked instances unioned with any JS server listening on a port
3
+ * that the registry doesn't know about — so `absolute ps` shows orphans
4
+ * (dead controllers, hand-run builds) the file registry alone would miss. */
5
+ export declare const discoverInstances: () => Promise<InstanceRecord[]>;
@@ -0,0 +1,22 @@
1
+ /** Process/port discovery for `absolute ps`, used to surface running servers
2
+ * the file-based instance registry can miss — orphans whose controller died,
3
+ * hand-run `bun dist/server.js` builds, anything that never registered.
4
+ *
5
+ * Shells out via Bun's `$` to the platform's socket lister (lsof, falling
6
+ * back to ss on Linux) rather than trusting a registry file, so a live
7
+ * listener is discoverable for as long as its process is alive. */
8
+ export type PortListener = {
9
+ command: string;
10
+ etimes: number;
11
+ pid: number;
12
+ port: number;
13
+ };
14
+ /** Listening TCP servers on the machine, each annotated with the owning
15
+ * process's full command and uptime. Skips this process and any listener
16
+ * whose owner we can't describe. */
17
+ export declare const scanListeners: () => Promise<{
18
+ command: string;
19
+ etimes: number;
20
+ pid: number;
21
+ port: number;
22
+ }[]>;
@@ -28,7 +28,7 @@ export type InstanceRecord = {
28
28
  source: InstanceSource;
29
29
  startedAt: string;
30
30
  };
31
- export type InstanceSource = 'compiled' | 'dev' | 'standalone' | 'start' | 'workspace';
31
+ export type InstanceSource = 'compiled' | 'dev' | 'standalone' | 'start' | 'untracked' | 'workspace';
32
32
  export type InstanceStatus = 'ready' | 'starting' | 'stopped';
33
33
  export type InteractiveHandler = {
34
34
  clearPrompt: () => void;
package/package.json CHANGED
@@ -415,5 +415,5 @@
415
415
  ]
416
416
  }
417
417
  },
418
- "version": "0.19.0-beta.1028"
418
+ "version": "0.19.0-beta.1029"
419
419
  }