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

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-Ye9d69/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-IJqg0M/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-Ye9d69/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-IJqg0M/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-Ye9d69/src/core/streamingSlotRegistry.ts
51
+ // .angular-partial-tmp-IJqg0M/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
@@ -170858,6 +170858,197 @@ var init_build = __esm(() => {
170858
170858
  init_telemetryEvent();
170859
170859
  });
170860
170860
 
170861
+ // src/cli/scripts/ls.ts
170862
+ var exports_ls = {};
170863
+ __export(exports_ls, {
170864
+ runLs: () => runLs
170865
+ });
170866
+ import { existsSync as existsSync10, readFileSync as readFileSync13, statSync } from "fs";
170867
+ import { join as join11, relative as relative2 } from "path";
170868
+ var DEFAULT_BUILD_DIR = "build", FRAMEWORK_SEGMENTS, FRAMEWORK_ORDER, FRAMEWORK_LABELS, KIND_LABELS, KIND_RANK, KIND_RULES, parseConfigArg = (args) => {
170869
+ const index = args.indexOf("--config");
170870
+ if (index === UNFOUND_INDEX)
170871
+ return;
170872
+ return args[index + 1];
170873
+ }, resolveBuildDir = async (configPath2) => {
170874
+ try {
170875
+ const config = await loadConfig(configPath2);
170876
+ return typeof config.buildDirectory === "string" ? config.buildDirectory : DEFAULT_BUILD_DIR;
170877
+ } catch {
170878
+ return DEFAULT_BUILD_DIR;
170879
+ }
170880
+ }, readManifest = (manifestPath) => {
170881
+ const parsed = JSON.parse(readFileSync13(manifestPath, "utf-8"));
170882
+ return parsed;
170883
+ }, detectFramework = (path) => {
170884
+ const segments = path.toLowerCase().split("/");
170885
+ const found = FRAMEWORK_SEGMENTS.find((framework) => segments.includes(framework));
170886
+ return found ?? "shared";
170887
+ }, detectKind = (id, path) => {
170888
+ const rule = KIND_RULES.find((entry) => entry.matches({ id, path }));
170889
+ return rule?.kind ?? "page";
170890
+ }, resolveDiskPath = (buildDir, value) => {
170891
+ if (existsSync10(value))
170892
+ return value;
170893
+ const underBuild = join11(buildDir, value);
170894
+ if (existsSync10(underBuild))
170895
+ return underBuild;
170896
+ return join11(process.cwd(), value);
170897
+ }, fileSize = (diskPath) => {
170898
+ try {
170899
+ return statSync(diskPath).size;
170900
+ } catch {
170901
+ return 0;
170902
+ }
170903
+ }, buildEntries = (manifest, buildDir) => Object.entries(manifest).map(([id, value]) => ({
170904
+ framework: detectFramework(value),
170905
+ id,
170906
+ kind: detectKind(id, value),
170907
+ path: value,
170908
+ sizeBytes: fileSize(resolveDiskPath(buildDir, value))
170909
+ })), sortEntries = (entries) => [...entries].sort((left, right) => KIND_RANK[left.kind] - KIND_RANK[right.kind] || left.id.localeCompare(right.id)), groupByFramework = (entries) => FRAMEWORK_ORDER.map((framework) => ({
170910
+ entries: sortEntries(entries.filter((entry) => entry.framework === framework)),
170911
+ framework
170912
+ })).filter((group) => group.entries.length > 0), formatSize = (bytes) => {
170913
+ if (bytes === 0)
170914
+ return "-";
170915
+ if (bytes < BYTES_PER_KILOBYTE)
170916
+ return `${bytes} B`;
170917
+ const kilobytes = bytes / BYTES_PER_KILOBYTE;
170918
+ if (kilobytes < BYTES_PER_KILOBYTE)
170919
+ return `${kilobytes.toFixed(1)} KB`;
170920
+ return `${(kilobytes / BYTES_PER_KILOBYTE).toFixed(1)} MB`;
170921
+ }, padStart = (value, width) => {
170922
+ const padding = width - visibleLength(value);
170923
+ if (padding <= 0)
170924
+ return value;
170925
+ return `${" ".repeat(padding)}${value}`;
170926
+ }, columnWidths = (entries) => ({
170927
+ id: Math.max(...entries.map((entry) => entry.id.length)),
170928
+ kind: Math.max(...entries.map((entry) => KIND_LABELS[entry.kind].length)),
170929
+ size: Math.max(...entries.map((entry) => formatSize(entry.sizeBytes).length))
170930
+ }), sumSizes = (entries) => entries.reduce((total, entry) => total + entry.sizeBytes, 0), pluralFiles = (count) => count === 1 ? "file" : "files", renderGroupHeader = (group) => {
170931
+ const label = FRAMEWORK_LABELS[group.framework];
170932
+ const count = group.entries.length;
170933
+ const size = formatSize(sumSizes(group.entries));
170934
+ return `
170935
+ ${colors.bold}${label}${colors.reset}${colors.dim} \xB7 ${count} ${pluralFiles(count)} \xB7 ${size}${colors.reset}`;
170936
+ }, renderEntryLine = (entry, widths) => {
170937
+ const id = padLine(entry.id, widths.id);
170938
+ const kind = padLine(KIND_LABELS[entry.kind], widths.kind);
170939
+ const size = padStart(formatSize(entry.sizeBytes), widths.size);
170940
+ return ` ${id} ${colors.dim}${kind}${colors.reset} ${size}`;
170941
+ }, visibleEntries = (entries, showAll) => showAll ? entries : entries.filter((entry) => entry.kind !== "chunk"), renderChunkSummary = (entries, showAll) => {
170942
+ const chunks = entries.filter((entry) => entry.kind === "chunk");
170943
+ if (showAll || chunks.length === 0)
170944
+ return [];
170945
+ return [
170946
+ ` ${colors.dim}+ ${chunks.length} shared ${chunks.length === 1 ? "chunk" : "chunks"} \xB7 ${formatSize(sumSizes(chunks))} (--all to list)${colors.reset}`
170947
+ ];
170948
+ }, renderGroup = (group, widths, showAll) => [
170949
+ renderGroupHeader(group),
170950
+ ...visibleEntries(group.entries, showAll).map((entry) => renderEntryLine(entry, widths)),
170951
+ ...renderChunkSummary(group.entries, showAll)
170952
+ ], renderFooter = (entries, groupCount, manifestLabel) => `
170953
+ ${colors.dim}${groupCount} ${groupCount === 1 ? "framework" : "frameworks"} \xB7 ${entries.length} ${pluralFiles(entries.length)} \xB7 ${formatSize(sumSizes(entries))} \xB7 ${manifestLabel}${colors.reset}`, printInventory = (entries, manifestLabel, showAll) => {
170954
+ const groups = groupByFramework(entries);
170955
+ const widths = columnWidths(entries);
170956
+ const lines = [
170957
+ ...groups.flatMap((group) => renderGroup(group, widths, showAll)),
170958
+ renderFooter(entries, groups.length, manifestLabel)
170959
+ ];
170960
+ process.stdout.write(`${lines.join(`
170961
+ `)}
170962
+ `);
170963
+ }, printNoBuild = (manifestPath) => {
170964
+ process.stdout.write(`${colors.dim}No build found at ${manifestPath}. Run \`absolute build\` (or \`absolute dev\`) first.${colors.reset}
170965
+ `);
170966
+ }, runLs = async (args) => {
170967
+ process.stdout.on("error", (error) => {
170968
+ if (error instanceof Error && "code" in error && error.code === "EPIPE") {
170969
+ process.exit(0);
170970
+ }
170971
+ });
170972
+ const buildDir = await resolveBuildDir(parseConfigArg(args));
170973
+ const manifestPath = join11(buildDir, "manifest.json");
170974
+ const manifestLabel = relative2(process.cwd(), manifestPath) || manifestPath;
170975
+ if (!existsSync10(manifestPath)) {
170976
+ printNoBuild(manifestLabel);
170977
+ return;
170978
+ }
170979
+ const entries = buildEntries(readManifest(manifestPath), buildDir);
170980
+ if (args.includes("--json")) {
170981
+ process.stdout.write(`${JSON.stringify(entries, null, 2)}
170982
+ `);
170983
+ return;
170984
+ }
170985
+ if (entries.length === 0) {
170986
+ process.stdout.write(`${colors.dim}${manifestLabel} is empty \u2014 nothing built yet.${colors.reset}
170987
+ `);
170988
+ return;
170989
+ }
170990
+ printInventory(entries, manifestLabel, args.includes("--all"));
170991
+ };
170992
+ var init_ls = __esm(() => {
170993
+ init_constants();
170994
+ init_loadConfig();
170995
+ init_tuiPrimitives();
170996
+ FRAMEWORK_SEGMENTS = [
170997
+ "angular",
170998
+ "html",
170999
+ "htmx",
171000
+ "react",
171001
+ "svelte",
171002
+ "vue"
171003
+ ];
171004
+ FRAMEWORK_ORDER = [
171005
+ "react",
171006
+ "vue",
171007
+ "svelte",
171008
+ "angular",
171009
+ "html",
171010
+ "htmx",
171011
+ "shared"
171012
+ ];
171013
+ FRAMEWORK_LABELS = {
171014
+ angular: "Angular",
171015
+ html: "HTML",
171016
+ htmx: "HTMX",
171017
+ react: "React",
171018
+ shared: "Shared",
171019
+ svelte: "Svelte",
171020
+ vue: "Vue"
171021
+ };
171022
+ KIND_LABELS = {
171023
+ chunk: "chunk",
171024
+ client: "client",
171025
+ css: "css",
171026
+ index: "index",
171027
+ island: "island",
171028
+ page: "page",
171029
+ script: "script"
171030
+ };
171031
+ KIND_RANK = {
171032
+ chunk: 6,
171033
+ client: 2,
171034
+ css: 4,
171035
+ index: 1,
171036
+ island: 3,
171037
+ page: 0,
171038
+ script: 5
171039
+ };
171040
+ KIND_RULES = [
171041
+ { kind: "chunk", matches: (probe) => probe.id.startsWith("Chunk") },
171042
+ { kind: "css", matches: (probe) => probe.path.endsWith(".css") },
171043
+ { kind: "page", matches: (probe) => probe.path.endsWith(".html") },
171044
+ { kind: "island", matches: (probe) => probe.id.startsWith("Island") },
171045
+ { kind: "index", matches: (probe) => probe.id.endsWith("Index") },
171046
+ { kind: "client", matches: (probe) => probe.id.endsWith("Client") },
171047
+ { kind: "page", matches: (probe) => probe.path.includes("/server/") },
171048
+ { kind: "script", matches: (probe) => probe.path.includes("/scripts/") }
171049
+ ];
171050
+ });
171051
+
170861
171052
  // src/cli/discoverInstances.ts
170862
171053
  var MS_PER_SECOND = 1000, isJsRuntime = (command) => /\b(bun|deno|node)\b/.test(command), untrackedName = (command) => {
170863
171054
  const entry = command.split(/\s+/).find((token) => /\.(cjs|js|mjs|ts)$/.test(token));
@@ -170958,10 +171149,10 @@ var init_instanceStatus = __esm(() => {
170958
171149
  init_constants();
170959
171150
  });
170960
171151
 
170961
- // src/cli/listTui.ts
170962
- var exports_listTui = {};
170963
- __export(exports_listTui, {
170964
- runListTui: () => runListTui
171152
+ // src/cli/psTui.ts
171153
+ var exports_psTui = {};
171154
+ __export(exports_psTui, {
171155
+ runPsTui: () => runPsTui
170965
171156
  });
170966
171157
  import { spawn } from "child_process";
170967
171158
  import { closeSync, fstatSync, openSync as openSync3, readSync } from "fs";
@@ -170987,8 +171178,8 @@ var TUI_HEADERS, STATUS_INDEX = 5, URL_INDEX = 6, helpLines2, statusLevelColor =
170987
171178
  getDurationString(instance.uptimeMs),
170988
171179
  instance.status,
170989
171180
  instance.url ?? "-"
170990
- ], columnWidths = (allCells) => TUI_HEADERS.map((header, index) => Math.max(visibleLength(header), ...allCells.map((cells) => visibleLength(cells[index] ?? "")))), layoutWidths = (allCells, width) => {
170991
- const natural = columnWidths(allCells);
171181
+ ], columnWidths2 = (allCells) => TUI_HEADERS.map((header, index) => Math.max(visibleLength(header), ...allCells.map((cells) => visibleLength(cells[index] ?? "")))), layoutWidths = (allCells, width) => {
171182
+ const natural = columnWidths2(allCells);
170992
171183
  const gaps = (TUI_HEADERS.length - 1) * LIST_TUI_COLUMN_GAP;
170993
171184
  const available = width - LIST_TUI_MARKER_WIDTH - gaps;
170994
171185
  const fixed = natural.reduce((sum, value, index) => index === URL_INDEX ? sum : sum + value, 0);
@@ -171445,15 +171636,15 @@ var TUI_HEADERS, STATUS_INDEX = 5, URL_INDEX = 6, helpLines2, statusLevelColor =
171445
171636
  await refresh();
171446
171637
  render();
171447
171638
  await promise;
171448
- }, runListTui = async () => {
171639
+ }, runPsTui = async () => {
171449
171640
  const input = openTtyStream2();
171450
171641
  if (!input) {
171451
- process.stdout.write("Interactive ls requires a TTY. Run `absolute ls` for a snapshot.\n");
171642
+ process.stdout.write("Interactive ps requires a TTY. Run `absolute ps` for a snapshot.\n");
171452
171643
  return;
171453
171644
  }
171454
171645
  await driveListTui(input);
171455
171646
  };
171456
- var init_listTui = __esm(() => {
171647
+ var init_psTui = __esm(() => {
171457
171648
  init_constants();
171458
171649
  init_getDurationString();
171459
171650
  init_discoverInstances();
@@ -171483,10 +171674,10 @@ var init_listTui = __esm(() => {
171483
171674
  ];
171484
171675
  });
171485
171676
 
171486
- // src/cli/scripts/list.ts
171487
- var exports_list = {};
171488
- __export(exports_list, {
171489
- runList: () => runList
171677
+ // src/cli/scripts/ps.ts
171678
+ var exports_ps = {};
171679
+ __export(exports_ps, {
171680
+ runPs: () => runPs
171490
171681
  });
171491
171682
  var killPid = (pid) => {
171492
171683
  try {
@@ -171509,29 +171700,29 @@ var killPid = (pid) => {
171509
171700
  getDurationString(instance.uptimeMs),
171510
171701
  `${statusColor2(instance.status)}${instance.status}${colors.reset}`,
171511
171702
  instance.url ?? "-"
171512
- ], columnWidths2 = (rows) => TABLE_HEADERS.map((header, index) => Math.max(visibleLength(header), ...rows.map((cells) => visibleLength(cells[index] ?? "")))), renderRow = (cells, widths) => cells.map((cell, index) => padLine(cell, widths[index] ?? 0)).join(" ".repeat(LIST_TUI_COLUMN_GAP)), printInstanceTable = (instances) => {
171703
+ ], columnWidths3 = (rows) => TABLE_HEADERS.map((header, index) => Math.max(visibleLength(header), ...rows.map((cells) => visibleLength(cells[index] ?? "")))), renderRow = (cells, widths) => cells.map((cell, index) => padLine(cell, widths[index] ?? 0)).join(" ".repeat(LIST_TUI_COLUMN_GAP)), printInstanceTable = (instances) => {
171513
171704
  if (instances.length === 0) {
171514
171705
  process.stdout.write(`${colors.dim}No AbsoluteJS servers are running. Start one with \`absolute dev\`.${colors.reset}
171515
171706
  `);
171516
171707
  return;
171517
171708
  }
171518
171709
  const rows = instances.map(instanceCells);
171519
- const widths = columnWidths2(rows);
171710
+ const widths = columnWidths3(rows);
171520
171711
  process.stdout.write(`${colors.dim}${renderRow(TABLE_HEADERS, widths)}${colors.reset}
171521
171712
  `);
171522
171713
  for (const cells of rows) {
171523
171714
  process.stdout.write(`${renderRow(cells, widths)}
171524
171715
  `);
171525
171716
  }
171526
- }, runList = async (args) => {
171717
+ }, runPs = async (args) => {
171527
171718
  process.stdout.on("error", (error) => {
171528
171719
  if (error instanceof Error && "code" in error && error.code === "EPIPE") {
171529
171720
  process.exit(0);
171530
171721
  }
171531
171722
  });
171532
171723
  if (args.includes("--watch") || args.includes("-w")) {
171533
- const { runListTui: runListTui2 } = await Promise.resolve().then(() => (init_listTui(), exports_listTui));
171534
- await runListTui2();
171724
+ const { runPsTui: runPsTui2 } = await Promise.resolve().then(() => (init_psTui(), exports_psTui));
171725
+ await runPsTui2();
171535
171726
  return;
171536
171727
  }
171537
171728
  const instances = await enrichInstances(await discoverInstances());
@@ -171559,7 +171750,7 @@ var killPid = (pid) => {
171559
171750
  }
171560
171751
  printInstanceTable(instances);
171561
171752
  };
171562
- var init_list = __esm(() => {
171753
+ var init_ps = __esm(() => {
171563
171754
  init_constants();
171564
171755
  init_getDurationString();
171565
171756
  init_discoverInstances();
@@ -171577,8 +171768,8 @@ var init_list = __esm(() => {
171577
171768
  });
171578
171769
 
171579
171770
  // src/build/externalAssetPlugin.ts
171580
- import { copyFileSync as copyFileSync2, existsSync as existsSync10, mkdirSync as mkdirSync7, statSync } from "fs";
171581
- import { basename as basename4, dirname as dirname4, join as join11, resolve as resolve11 } from "path";
171771
+ import { copyFileSync as copyFileSync2, existsSync as existsSync11, mkdirSync as mkdirSync7, statSync as statSync2 } from "fs";
171772
+ import { basename as basename4, dirname as dirname4, join as join12, resolve as resolve11 } from "path";
171582
171773
  var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
171583
171774
  name: "absolute-external-asset",
171584
171775
  setup(bld) {
@@ -171599,12 +171790,12 @@ var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
171599
171790
  if (!relPath)
171600
171791
  continue;
171601
171792
  const assetPath = resolve11(sourceDir, relPath);
171602
- if (!existsSync10(assetPath))
171793
+ if (!existsSync11(assetPath))
171603
171794
  continue;
171604
- if (!statSync(assetPath).isFile())
171795
+ if (!statSync2(assetPath).isFile())
171605
171796
  continue;
171606
- const targetPath = join11(outDir, basename4(assetPath));
171607
- if (existsSync10(targetPath))
171797
+ const targetPath = join12(outDir, basename4(assetPath));
171798
+ if (existsSync11(targetPath))
171608
171799
  continue;
171609
171800
  mkdirSync7(dirname4(targetPath), { recursive: true });
171610
171801
  copyFileSync2(assetPath, targetPath);
@@ -171624,16 +171815,16 @@ __export(exports_compile, {
171624
171815
  var {env: env3 } = globalThis.Bun;
171625
171816
  import {
171626
171817
  cpSync,
171627
- existsSync as existsSync11,
171818
+ existsSync as existsSync12,
171628
171819
  mkdirSync as mkdirSync8,
171629
171820
  readdirSync as readdirSync3,
171630
- readFileSync as readFileSync13,
171821
+ readFileSync as readFileSync14,
171631
171822
  rmSync as rmSync4,
171632
- statSync as statSync2,
171823
+ statSync as statSync3,
171633
171824
  unlinkSync as unlinkSync4,
171634
171825
  writeFileSync as writeFileSync5
171635
171826
  } from "fs";
171636
- import { basename as basename5, dirname as dirname5, join as join12, relative as relative2, resolve as resolve12 } from "path";
171827
+ import { basename as basename5, dirname as dirname5, join as join13, relative as relative3, resolve as resolve12 } from "path";
171637
171828
  var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, compileBanner = (version2) => {
171638
171829
  const resolvedVersion = version2 || "unknown";
171639
171830
  console.log("");
@@ -171646,7 +171837,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171646
171837
  const entry = pending.pop();
171647
171838
  if (!entry)
171648
171839
  continue;
171649
- const fullPath = join12(entry.parentPath, entry.name);
171840
+ const fullPath = join13(entry.parentPath, entry.name);
171650
171841
  if (entry.isDirectory())
171651
171842
  pending = pending.concat(readdirSync3(fullPath, { withFileTypes: true }));
171652
171843
  else
@@ -171666,7 +171857,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171666
171857
  const entry = pending.pop();
171667
171858
  if (!entry)
171668
171859
  continue;
171669
- const fullPath = join12(entry.parentPath, entry.name);
171860
+ const fullPath = join13(entry.parentPath, entry.name);
171670
171861
  if (entry.isDirectory()) {
171671
171862
  if (SERVER_RUNTIME_SCAN_SKIP_DIRS.has(entry.name))
171672
171863
  continue;
@@ -171681,7 +171872,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171681
171872
  const normalizedOutdir = resolve12(outdir);
171682
171873
  const copyReference = (filePath, relPath) => {
171683
171874
  const assetSource = resolve12(dirname5(filePath), relPath);
171684
- if (!existsSync11(assetSource) || !statSync2(assetSource).isFile())
171875
+ if (!existsSync12(assetSource) || !statSync3(assetSource).isFile())
171685
171876
  return;
171686
171877
  const assetTarget = resolve12(normalizedOutdir, relPath.replace(/^\.\//, ""));
171687
171878
  if (assetTarget !== normalizedOutdir && !assetTarget.startsWith(`${normalizedOutdir}/`))
@@ -171693,7 +171884,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171693
171884
  cpSync(assetSource, assetTarget, { force: true });
171694
171885
  };
171695
171886
  for (const filePath of collectProjectSourceFiles(process.cwd())) {
171696
- const source = readFileSync13(filePath, "utf-8");
171887
+ const source = readFileSync14(filePath, "utf-8");
171697
171888
  SERVER_RUNTIME_ASSET_RE.lastIndex = 0;
171698
171889
  let match;
171699
171890
  while ((match = SERVER_RUNTIME_ASSET_RE.exec(source)) !== null) {
@@ -171722,7 +171913,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171722
171913
  }
171723
171914
  }, readPackageVersion4 = (candidate) => {
171724
171915
  try {
171725
- const pkg = JSON.parse(readFileSync13(candidate, "utf-8"));
171916
+ const pkg = JSON.parse(readFileSync14(candidate, "utf-8"));
171726
171917
  if (pkg.name !== "@absolutejs/absolute")
171727
171918
  return null;
171728
171919
  const ver = pkg.version;
@@ -171765,7 +171956,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171765
171956
  resolve12(import.meta.dir, "..", "..", "..", "src", "react", "jsxDevRuntimeCompat.ts")
171766
171957
  ];
171767
171958
  for (const candidate of candidates) {
171768
- if (existsSync11(candidate))
171959
+ if (existsSync12(candidate))
171769
171960
  return candidate;
171770
171961
  }
171771
171962
  return resolve12(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.js");
@@ -171781,7 +171972,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171781
171972
  return true;
171782
171973
  }, tryReadNodePackageJson = (packageDir) => {
171783
171974
  try {
171784
- return JSON.parse(readFileSync13(join12(packageDir, "package.json"), "utf-8"));
171975
+ return JSON.parse(readFileSync14(join13(packageDir, "package.json"), "utf-8"));
171785
171976
  } catch {
171786
171977
  return null;
171787
171978
  }
@@ -171793,11 +171984,11 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171793
171984
  if (!pkg)
171794
171985
  return;
171795
171986
  seen.add(specifier);
171796
- const destDir = join12(outdir, "node_modules", ...specifier.split("/"));
171987
+ const destDir = join13(outdir, "node_modules", ...specifier.split("/"));
171797
171988
  rmSync4(destDir, { force: true, recursive: true });
171798
171989
  cpSync(srcDir, destDir, {
171799
171990
  filter(source) {
171800
- const rel = relative2(srcDir, source);
171991
+ const rel = relative3(srcDir, source);
171801
171992
  const [firstSegment] = rel.split(/[\\/]/);
171802
171993
  return firstSegment !== "node_modules" && firstSegment !== ".git";
171803
171994
  },
@@ -171816,7 +172007,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171816
172007
  if (!buildConfig.angularDirectory)
171817
172008
  return;
171818
172009
  const angularScopeDir = resolve12(process.cwd(), "node_modules", "@angular");
171819
- const angularPackages = existsSync11(angularScopeDir) ? readdirSync3(angularScopeDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => entry.name !== "compiler-cli").map((entry) => `@angular/${entry.name}`) : [];
172010
+ const angularPackages = existsSync12(angularScopeDir) ? readdirSync3(angularScopeDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => entry.name !== "compiler-cli").map((entry) => `@angular/${entry.name}`) : [];
171820
172011
  const roots = new Set([...angularPackages, "rxjs", "tslib", "typescript"]);
171821
172012
  const seen = new Set;
171822
172013
  for (const specifier of roots) {
@@ -171833,15 +172024,15 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171833
172024
  }
171834
172025
  copyAngularRuntimePackages(buildConfig, outdir);
171835
172026
  }, collectRuntimePackageSpecifiers = (distDir) => {
171836
- const nodeModulesDir = join12(distDir, "node_modules");
171837
- if (!existsSync11(nodeModulesDir))
172027
+ const nodeModulesDir = join13(distDir, "node_modules");
172028
+ if (!existsSync12(nodeModulesDir))
171838
172029
  return [];
171839
172030
  const specifiers = [];
171840
172031
  for (const entry of readdirSync3(nodeModulesDir, { withFileTypes: true })) {
171841
172032
  if (!entry.isDirectory())
171842
172033
  continue;
171843
172034
  if (entry.name.startsWith("@")) {
171844
- const scopeDir = join12(nodeModulesDir, entry.name);
172035
+ const scopeDir = join13(nodeModulesDir, entry.name);
171845
172036
  for (const scopedEntry of readdirSync3(scopeDir, {
171846
172037
  withFileTypes: true
171847
172038
  })) {
@@ -171855,7 +172046,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171855
172046
  }
171856
172047
  return specifiers.sort((a, b) => b.length - a.length);
171857
172048
  }, ensureRelativeModuleSpecifier = (fromFile, toFile) => {
171858
- const rel = relative2(dirname5(fromFile), toFile).replace(/\\/g, "/");
172049
+ const rel = relative3(dirname5(fromFile), toFile).replace(/\\/g, "/");
171859
172050
  return rel.startsWith(".") ? rel : `./${rel}`;
171860
172051
  }, pickExportEntry = (value) => {
171861
172052
  if (typeof value === "string")
@@ -171873,21 +172064,21 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171873
172064
  const packageSpecifier = packageSpecifiers.find((root) => specifier === root || specifier.startsWith(`${root}/`));
171874
172065
  if (!packageSpecifier)
171875
172066
  return null;
171876
- const packageDir = join12(distDir, "node_modules", ...packageSpecifier.split("/"));
172067
+ const packageDir = join13(distDir, "node_modules", ...packageSpecifier.split("/"));
171877
172068
  const subpath = specifier.slice(packageSpecifier.length);
171878
- const subPackageDir = subpath ? join12(packageDir, ...subpath.slice(1).split("/")) : null;
171879
- const resolvedPackageDir = subPackageDir && existsSync11(join12(subPackageDir, "package.json")) ? subPackageDir : packageDir;
171880
- const packageJsonPath = join12(resolvedPackageDir, "package.json");
171881
- if (!existsSync11(packageJsonPath))
172069
+ const subPackageDir = subpath ? join13(packageDir, ...subpath.slice(1).split("/")) : null;
172070
+ const resolvedPackageDir = subPackageDir && existsSync12(join13(subPackageDir, "package.json")) ? subPackageDir : packageDir;
172071
+ const packageJsonPath = join13(resolvedPackageDir, "package.json");
172072
+ if (!existsSync12(packageJsonPath))
171882
172073
  return null;
171883
- const pkg = JSON.parse(readFileSync13(packageJsonPath, "utf-8"));
172074
+ const pkg = JSON.parse(readFileSync14(packageJsonPath, "utf-8"));
171884
172075
  const exportKey = resolvedPackageDir === subPackageDir ? "." : subpath ? `.${subpath}` : ".";
171885
172076
  const rootExport = pkg.exports?.[exportKey];
171886
172077
  const entry = pickExportEntry(rootExport) ?? (resolvedPackageDir === subPackageDir || !subpath ? pkg.module ?? pkg.main ?? "index.js" : `.${subpath}`);
171887
- return join12(resolvedPackageDir, entry);
172078
+ return join13(resolvedPackageDir, entry);
171888
172079
  }, RUNTIME_JS_EXTENSIONS, MODULE_SPECIFIER_RE, isRuntimeJsFile = (filePath) => RUNTIME_JS_EXTENSIONS.some((extension) => filePath.endsWith(extension)), isNodeModulesPath = (filePath) => filePath.split(/[\\/]/).includes("node_modules"), isFile = (filePath) => {
171889
172080
  try {
171890
- return statSync2(filePath).isFile();
172081
+ return statSync3(filePath).isFile();
171891
172082
  } catch {
171892
172083
  return false;
171893
172084
  }
@@ -171897,13 +172088,13 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171897
172088
  const candidates = [
171898
172089
  candidate,
171899
172090
  ...RUNTIME_JS_EXTENSIONS.map((extension) => `${candidate}${extension}`),
171900
- ...RUNTIME_JS_EXTENSIONS.map((extension) => join12(candidate, `index${extension}`))
172091
+ ...RUNTIME_JS_EXTENSIONS.map((extension) => join13(candidate, `index${extension}`))
171901
172092
  ];
171902
172093
  return candidates.find((filePath) => isRuntimeJsFile(filePath) && isFile(filePath)) ?? null;
171903
172094
  }, findContainingRuntimePackageDir = (filePath) => {
171904
172095
  let dir = dirname5(filePath);
171905
172096
  while (dir !== dirname5(dir)) {
171906
- if (isNodeModulesPath(dir) && existsSync11(join12(dir, "package.json"))) {
172097
+ if (isNodeModulesPath(dir) && existsSync12(join13(dir, "package.json"))) {
171907
172098
  return dir;
171908
172099
  }
171909
172100
  dir = dirname5(dir);
@@ -171919,7 +172110,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171919
172110
  const entry = pickExportEntry(pkg?.imports?.[specifier]);
171920
172111
  if (!entry)
171921
172112
  return null;
171922
- return join12(packageDir, entry);
172113
+ return join13(packageDir, entry);
171923
172114
  }, collectRuntimeRewriteRoots = (distDir) => collectFiles2(distDir).filter((filePath) => isRuntimeJsFile(filePath) && !isNodeModulesPath(filePath)), rewriteRuntimeModuleSpecifiers = (distDir) => {
171924
172115
  const packageSpecifiers = collectRuntimePackageSpecifiers(distDir);
171925
172116
  if (packageSpecifiers.length === 0)
@@ -171938,7 +172129,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171938
172129
  if (!filePath || seen.has(filePath))
171939
172130
  continue;
171940
172131
  seen.add(filePath);
171941
- const source = readFileSync13(filePath, "utf-8");
172132
+ const source = readFileSync14(filePath, "utf-8");
171942
172133
  const rewritten = source.replace(MODULE_SPECIFIER_RE, (match, prefix, quote, specifier) => {
171943
172134
  if (typeof specifier === "string" && specifier.startsWith(".")) {
171944
172135
  enqueue(resolveRuntimeJsFile(resolve12(dirname5(filePath), specifier)));
@@ -171969,25 +172160,25 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
171969
172160
  "_compile_entrypoint.ts"
171970
172161
  ]);
171971
172162
  const embeddedFiles = allFiles.filter((file) => {
171972
- const rel = relative2(distDir, file);
172163
+ const rel = relative3(distDir, file);
171973
172164
  if (embeddedSkip.has(rel))
171974
172165
  return false;
171975
172166
  return true;
171976
172167
  });
171977
- const clientFiles = embeddedFiles.filter((file) => shouldEmbedCompiledAsset(relative2(distDir, file), assetSkip));
172168
+ const clientFiles = embeddedFiles.filter((file) => shouldEmbedCompiledAsset(relative3(distDir, file), assetSkip));
171978
172169
  const imports = [];
171979
172170
  const embeddedMappings = [];
171980
172171
  const mappings = [];
171981
172172
  const embeddedVarMap = new Map;
171982
172173
  embeddedFiles.forEach((filePath, idx) => {
171983
- const rel = relative2(distDir, filePath).replace(/\\/g, "/");
172174
+ const rel = relative3(distDir, filePath).replace(/\\/g, "/");
171984
172175
  const varName = `__a${idx}`;
171985
172176
  embeddedVarMap.set(rel, varName);
171986
172177
  imports.push(`import ${varName} from "./${rel}" with { type: "file" };`);
171987
172178
  embeddedMappings.push(` ["${rel}", ${varName}],`);
171988
172179
  });
171989
172180
  clientFiles.forEach((filePath) => {
171990
- const rel = relative2(distDir, filePath).replace(/\\/g, "/");
172181
+ const rel = relative3(distDir, filePath).replace(/\\/g, "/");
171991
172182
  const varName = embeddedVarMap.get(rel);
171992
172183
  if (!varName)
171993
172184
  return;
@@ -172001,7 +172192,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
172001
172192
  const pageVarMap = new Map;
172002
172193
  const prerenderEntries = Array.from(prerenderMap.entries());
172003
172194
  prerenderEntries.forEach(([route, filePath]) => {
172004
- const rel = relative2(distDir, filePath).replace(/\\/g, "/");
172195
+ const rel = relative3(distDir, filePath).replace(/\\/g, "/");
172005
172196
  const varName = embeddedVarMap.get(rel);
172006
172197
  if (varName)
172007
172198
  pageVarMap.set(route, varName);
@@ -172231,7 +172422,7 @@ const server = Bun.serve({
172231
172422
  },
172232
172423
  });
172233
172424
 
172234
- // Register in the global instance registry so 'absolute ls' can see this
172425
+ // Register in the global instance registry so 'absolute ps' can see this
172235
172426
  // compiled binary. Best-effort; never blocks startup. Dead entries are pruned
172236
172427
  // on read, so a hard kill that skips the exit handler is harmless.
172237
172428
  try {
@@ -172466,11 +172657,11 @@ console.log(\`
172466
172657
  process.exit(1);
172467
172658
  }
172468
172659
  const outputPath = resolve12(resolvedOutdir, `${entryName}.js`);
172469
- if (!existsSync11(outputPath)) {
172660
+ if (!existsSync12(outputPath)) {
172470
172661
  console.error(cliTag4("\x1B[31m", `Expected output not found: ${outputPath}`));
172471
172662
  process.exit(1);
172472
172663
  }
172473
- if (existsSync11(resolve12(resolvedOutdir, "angular", "vendor", "server"))) {
172664
+ if (existsSync12(resolve12(resolvedOutdir, "angular", "vendor", "server"))) {
172474
172665
  const vendorDir = resolve12(resolvedOutdir, "angular", "vendor", "server");
172475
172666
  const vendorEntries = readdirSync3(vendorDir).filter((f) => f.endsWith(".js"));
172476
172667
  const angularServerVendorPaths = {};
@@ -172480,7 +172671,7 @@ console.log(\`
172480
172671
  if (scope !== "angular" || rest.length === 0)
172481
172672
  continue;
172482
172673
  const specifier = `@angular/${rest.join("/")}`;
172483
- const relPath = relative2(dirname5(outputPath), resolve12(vendorDir, file));
172674
+ const relPath = relative3(dirname5(outputPath), resolve12(vendorDir, file));
172484
172675
  angularServerVendorPaths[specifier] = relPath.startsWith(".") ? relPath : `./${relPath}`;
172485
172676
  }
172486
172677
  if (Object.keys(angularServerVendorPaths).length > 0) {
@@ -172492,7 +172683,7 @@ console.log(\`
172492
172683
  copyServerRuntimeAssetReferences(resolvedOutdir);
172493
172684
  const prerenderStart = performance.now();
172494
172685
  process.stdout.write(cliTag4("\x1B[36m", "Pre-rendering pages"));
172495
- rmSync4(join12(resolvedOutdir, "_prerendered"), {
172686
+ rmSync4(join13(resolvedOutdir, "_prerendered"), {
172496
172687
  force: true,
172497
172688
  recursive: true
172498
172689
  });
@@ -172511,7 +172702,7 @@ console.log(\`
172511
172702
  const compileStart = performance.now();
172512
172703
  process.stdout.write(cliTag4("\x1B[36m", "Compiling standalone executable"));
172513
172704
  const entrypointCode = generateEntrypoint(resolvedOutdir, serverEntry, prerenderMap, absoluteVersion, buildConfig);
172514
- const entrypointPath = join12(resolvedOutdir, "_compile_entrypoint.ts");
172705
+ const entrypointPath = join13(resolvedOutdir, "_compile_entrypoint.ts");
172515
172706
  await Bun.write(entrypointPath, entrypointCode);
172516
172707
  mkdirSync8(dirname5(resolvedOutfile), { recursive: true });
172517
172708
  const result = await Bun.build({
@@ -172607,11 +172798,11 @@ var exports_typecheck = {};
172607
172798
  __export(exports_typecheck, {
172608
172799
  typecheck: () => typecheck
172609
172800
  });
172610
- import { resolve as resolve13, join as join13 } from "path";
172611
- import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
172801
+ import { resolve as resolve13, join as join14 } from "path";
172802
+ import { existsSync as existsSync13, readFileSync as readFileSync15 } from "fs";
172612
172803
  import { mkdir as mkdir2, writeFile } from "fs/promises";
172613
172804
  var isCommandService3 = (service) => service.kind === "command" || Array.isArray(service.command), resolveConfigPath = (configPath2) => resolve13(configPath2 ?? process.env.ABSOLUTE_CONFIG ?? "absolute.config.ts"), getTypecheckTargets = async (configPath2) => {
172614
- if (!existsSync12(resolveConfigPath(configPath2))) {
172805
+ if (!existsSync13(resolveConfigPath(configPath2))) {
172615
172806
  return [{}];
172616
172807
  }
172617
172808
  const rawConfig = await loadRawConfig(configPath2);
@@ -172632,7 +172823,7 @@ var isCommandService3 = (service) => service.kind === "command" || Array.isArray
172632
172823
  return { exitCode, name, output: (stdout + stderr).trim() };
172633
172824
  }, shellEscape = (value) => `'${value.replaceAll("'", "'\\''")}'`, runShell = async (name, command) => run(name, ["/bin/bash", "-lc", command]), findBin = (name) => {
172634
172825
  const local = resolve13("node_modules", ".bin", name);
172635
- return existsSync12(local) ? local : null;
172826
+ return existsSync13(local) ? local : null;
172636
172827
  }, ANSI_COLOR_REGEX, ANSI_PURPLE_REGEX, ANSI_CYAN_REGEX, ANSI_TOKEN_END_REGEX, stripAnsi3 = (str) => str.replace(ANSI_COLOR_REGEX, ""), formatSvelteOutput = (output) => {
172637
172828
  const cwd = `${process.cwd()}/`;
172638
172829
  const summaryMatch = stripAnsi3(output).match(/svelte-check found (\d+) error/);
@@ -172684,10 +172875,10 @@ Found ${errorCount} error${suffix}.`;
172684
172875
  resolve13(import.meta.dir, "../../types", fileName),
172685
172876
  resolve13(import.meta.dir, "../../../types", fileName)
172686
172877
  ];
172687
- return candidates.find((candidate) => existsSync12(candidate)) ?? candidates[0];
172878
+ return candidates.find((candidate) => existsSync13(candidate)) ?? candidates[0];
172688
172879
  }, ABSOLUTE_TYPECHECK_FILES, readProjectTsconfig = () => {
172689
172880
  try {
172690
- return JSON.parse(readFileSync14(resolve13("tsconfig.json"), "utf-8"));
172881
+ return JSON.parse(readFileSync15(resolve13("tsconfig.json"), "utf-8"));
172691
172882
  } catch {
172692
172883
  return {};
172693
172884
  }
@@ -172715,7 +172906,7 @@ Found ${errorCount} error${suffix}.`;
172715
172906
  console.error("\x1B[31m\u2717\x1B[0m vue-tsc is required for Vue type checking. Install it: bun add -d vue-tsc");
172716
172907
  process.exit(1);
172717
172908
  }
172718
- const vueTsconfigPath = join13(cacheDir, "tsconfig.vue-check.json");
172909
+ const vueTsconfigPath = join14(cacheDir, "tsconfig.vue-check.json");
172719
172910
  return writeFile(vueTsconfigPath, JSON.stringify({
172720
172911
  compilerOptions: {
172721
172912
  rootDir: ".."
@@ -172730,7 +172921,7 @@ Found ${errorCount} error${suffix}.`;
172730
172921
  resolve13(vueTsconfigPath),
172731
172922
  "--incremental",
172732
172923
  "--tsBuildInfoFile",
172733
- join13(cacheDir, "vue-tsc.tsbuildinfo"),
172924
+ join14(cacheDir, "vue-tsc.tsbuildinfo"),
172734
172925
  "--pretty"
172735
172926
  ]));
172736
172927
  }, buildAngularCheck = async (cacheDir, angularDir) => {
@@ -172739,7 +172930,7 @@ Found ${errorCount} error${suffix}.`;
172739
172930
  console.error("\x1B[31m\u2717\x1B[0m @angular/compiler-cli is required for Angular type checking. Install it: bun add -d @angular/compiler-cli");
172740
172931
  process.exit(1);
172741
172932
  }
172742
- const angularTsconfigPath = join13(cacheDir, "tsconfig.angular-check.json");
172933
+ const angularTsconfigPath = join14(cacheDir, "tsconfig.angular-check.json");
172743
172934
  await writeFile(angularTsconfigPath, JSON.stringify({
172744
172935
  angularCompilerOptions: {
172745
172936
  strictTemplates: true
@@ -172759,7 +172950,7 @@ Found ${errorCount} error${suffix}.`;
172759
172950
  console.error("\x1B[31m\u2717\x1B[0m typescript is required for type checking. Install it: bun add -d typescript");
172760
172951
  process.exit(1);
172761
172952
  }
172762
- const tscConfigPath = join13(cacheDir, "tsconfig.typecheck.json");
172953
+ const tscConfigPath = join14(cacheDir, "tsconfig.typecheck.json");
172763
172954
  return writeFile(tscConfigPath, JSON.stringify({
172764
172955
  compilerOptions: {
172765
172956
  rootDir: ".."
@@ -172774,7 +172965,7 @@ Found ${errorCount} error${suffix}.`;
172774
172965
  resolve13(tscConfigPath),
172775
172966
  "--incremental",
172776
172967
  "--tsBuildInfoFile",
172777
- join13(cacheDir, "tsc.tsbuildinfo"),
172968
+ join14(cacheDir, "tsc.tsbuildinfo"),
172778
172969
  "--pretty"
172779
172970
  ]));
172780
172971
  }, buildSvelteCheck = async (cacheDir, svelteDir) => {
@@ -172783,7 +172974,7 @@ Found ${errorCount} error${suffix}.`;
172783
172974
  console.error("\x1B[31m\u2717\x1B[0m svelte-check is required for Svelte type checking. Install it: bun add -d svelte-check");
172784
172975
  process.exit(1);
172785
172976
  }
172786
- const svelteTsconfigPath = join13(cacheDir, "tsconfig.svelte-check.json");
172977
+ const svelteTsconfigPath = join14(cacheDir, "tsconfig.svelte-check.json");
172787
172978
  await writeFile(svelteTsconfigPath, JSON.stringify({
172788
172979
  extends: resolve13("tsconfig.json"),
172789
172980
  files: ABSOLUTE_TYPECHECK_FILES,
@@ -176419,10 +176610,14 @@ if (command === "dev") {
176419
176610
  } else if (command === "prettier") {
176420
176611
  sendTelemetryEvent("cli:command", { command });
176421
176612
  await prettier(args);
176422
- } else if (command === "ls" || command === "ps") {
176613
+ } else if (command === "ls") {
176423
176614
  sendTelemetryEvent("cli:command", { command: "ls" });
176424
- const { runList: runList2 } = await Promise.resolve().then(() => (init_list(), exports_list));
176425
- await runList2(args);
176615
+ const { runLs: runLs2 } = await Promise.resolve().then(() => (init_ls(), exports_ls));
176616
+ await runLs2(args);
176617
+ } else if (command === "ps") {
176618
+ sendTelemetryEvent("cli:command", { command: "ps" });
176619
+ const { runPs: runPs2 } = await Promise.resolve().then(() => (init_ps(), exports_ps));
176620
+ await runPs2(args);
176426
176621
  } else if (command === "info") {
176427
176622
  sendTelemetryEvent("cli:command", { command });
176428
176623
  info();
@@ -176464,7 +176659,8 @@ if (command === "dev") {
176464
176659
  console.error(" config [--port n] Open the unified config UI (ESLint, tsconfig, Prettier)");
176465
176660
  console.error(" eslint Run ESLint (cached)");
176466
176661
  console.error(" info Print system info for bug reports");
176467
- console.error(" ls [--watch] [--json] [--kill <pid|port>] [--kill-all] List/manage running servers (alias: ps)");
176662
+ console.error(" ls [--all] [--json] List the project's built pages, islands, and assets");
176663
+ console.error(" ps [--watch] [--json] [--kill <pid|port>] [--kill-all] List/manage running servers");
176468
176664
  console.error(" prettier Run Prettier check (cached)");
176469
176665
  console.error(" typecheck Run type checkers for all frameworks");
176470
176666
  console.error(" telemetry Manage anonymous telemetry");
package/dist/index.js.map CHANGED
@@ -159,7 +159,7 @@
159
159
  "import { resolve } from 'node:path';\nimport type { IslandRegistryInput } from '../../types/island';\nimport { loadIslandRegistryBuildInfo } from '../build/islandEntries';\n\ntype RegistryModuleExport = {\n\tdefault?: unknown;\n\tislandRegistry?: unknown;\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n\ttypeof value === 'object' && value !== null;\n\nconst resolveRegistryExport = (mod: RegistryModuleExport) => {\n\tif (isRecord(mod.islandRegistry)) return mod.islandRegistry;\n\tif (isRecord(mod.default)) return mod.default;\n\n\tthrow new Error(\n\t\t'Island registry module must export `islandRegistry` or a default registry object.'\n\t);\n};\n\nconst isRegistryModuleExport = (\n\tvalue: unknown\n): value is RegistryModuleExport => isRecord(value);\n\nconst isIslandRegistryInput = (value: unknown): value is IslandRegistryInput =>\n\tisRecord(value);\n\nexport const loadIslandRegistry = async (registryPath: string) => {\n\tconst resolvedRegistryPath = resolve(registryPath);\n\tconst buildInfo = await loadIslandRegistryBuildInfo(resolvedRegistryPath);\n\tif (buildInfo.definitions.length > 0) {\n\t\treturn buildInfo.registry;\n\t}\n\n\tconst importedModule: unknown = await import(resolvedRegistryPath);\n\tif (!isRegistryModuleExport(importedModule)) {\n\t\tthrow new Error(\n\t\t\t'Island registry module must export an object namespace.'\n\t\t);\n\t}\n\n\tconst registryExport = resolveRegistryExport(importedModule);\n\tif (!isIslandRegistryInput(registryExport)) {\n\t\tthrow new Error('Resolved island registry export is not an object.');\n\t}\n\n\treturn registryExport;\n};\n",
160
160
  "import { basename } from 'node:path';\nimport type { ConventionsMap, ErrorPageProps } from '../../types/conventions';\nimport { toPascal } from './stringModifiers';\n\n// Use globalThis so the conventions map is shared across all bundles.\n// The main bundle (dist/index.js) calls setConventions, but framework\n// bundles (dist/svelte/index.js, etc.) need to read the same map.\nconst CONVENTIONS_KEY = '__absoluteConventions';\n\nconst isConventionsMap = (value: unknown): value is ConventionsMap =>\n\tBoolean(value) && typeof value === 'object';\n\nconst getMap = () => {\n\tconst value: unknown = Reflect.get(globalThis, CONVENTIONS_KEY);\n\tif (isConventionsMap(value)) return value;\n\n\tconst empty: ConventionsMap = {};\n\n\treturn empty;\n};\n\nexport const derivePageName = (pagePath: string) => {\n\tconst base = basename(pagePath);\n\t// Strip hash and extension: \"SvelteExample.abc123.js\" → \"SvelteExample\"\n\tconst dotIndex = base.indexOf('.');\n\tconst name = dotIndex > 0 ? base.slice(0, dotIndex) : base;\n\n\treturn toPascal(name);\n};\nexport const getConventions = () => getMap();\n\nconst normalizeConventionPageName = (name: string) =>\n\ttoPascal(name).replace(/\\d+$/, '');\n\nexport const resolveErrorConventionPath = (\n\tframework: keyof ConventionsMap,\n\tpageName: string\n) => {\n\tconst conventions = getMap()[framework];\n\tif (!conventions) return undefined;\n\n\tconst exact = conventions.pages?.[pageName]?.error;\n\tif (exact) return exact;\n\n\tconst normalizedPageName = normalizeConventionPageName(pageName);\n\tfor (const [candidate, page] of Object.entries(conventions.pages ?? {})) {\n\t\tif (normalizeConventionPageName(candidate) === normalizedPageName) {\n\t\t\treturn page.error ?? conventions.defaults?.error;\n\t\t}\n\t}\n\n\treturn conventions.defaults?.error;\n};\nexport const resolveNotFoundConventionPath = (\n\tframework: keyof ConventionsMap\n) => getMap()[framework]?.defaults?.notFound;\n\nexport const hasErrorConvention = (framework: keyof ConventionsMap) => {\n\tconst conventions = getMap()[framework];\n\tif (!conventions) return false;\n\tif (conventions.defaults?.error) return true;\n\n\treturn Object.values(conventions.pages ?? {}).some((page) =>\n\t\tBoolean(page.error)\n\t);\n};\n\nexport const setConventions = (map: ConventionsMap) => {\n\tReflect.set(globalThis, CONVENTIONS_KEY, map);\n};\n\nconst isDev = () => process.env.NODE_ENV === 'development';\n\nconst buildErrorProps = (error: unknown): ErrorPageProps => {\n\tif (error instanceof Error) {\n\t\treturn {\n\t\t\tname: error.name,\n\t\t\tmessage: error.message,\n\t\t\t...(isDev() && error.stack ? { stack: error.stack } : {})\n\t\t};\n\t}\n\n\treturn { name: 'Error', message: String(error) };\n};\n\nconst renderReactError = async (\n\tconventionPath: string,\n\terrorProps: ErrorPageProps\n) => {\n\tconst { createElement } = await import('react');\n\tconst { renderToReadableStream } = await import('react-dom/server');\n\tconst mod = await import(conventionPath);\n\tconst ErrorComponent = mod.default;\n\tif (typeof ErrorComponent !== 'function') return null;\n\n\tconst element = createElement(ErrorComponent, errorProps);\n\tconst stream = await renderToReadableStream(element);\n\n\treturn new Response(stream, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 500\n\t});\n};\n\nconst renderSvelteError = async (\n\tconventionPath: string,\n\terrorProps: ErrorPageProps\n) => {\n\tconst { render } = await import('svelte/server');\n\tconst mod = await import(conventionPath);\n\tconst ErrorComponent = mod.default;\n\tif (!ErrorComponent) return null;\n\n\tconst { head, body } = render(ErrorComponent, {\n\t\tprops: errorProps\n\t});\n\tconst html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 500\n\t});\n};\n\nconst unescapeVueStyles = (ssrBody: string) => {\n\tlet styles = '';\n\tconst body = ssrBody.replace(\n\t\t/<style>([\\s\\S]*?)<\\/style>/g,\n\t\t(_, css: string) => {\n\t\t\tstyles += `<style>${css\n\t\t\t\t.replace(/&quot;/g, '\"')\n\t\t\t\t.replace(/&amp;/g, '&')\n\t\t\t\t.replace(/&lt;/g, '<')\n\t\t\t\t.replace(/&gt;/g, '>')}</style>`;\n\n\t\t\treturn '';\n\t\t}\n\t);\n\n\treturn { body, styles };\n};\n\nconst renderVueError = async (\n\tconventionPath: string,\n\terrorProps: ErrorPageProps\n) => {\n\tconst { createSSRApp, h } = await import('vue');\n\tconst { renderToString } = await import('vue/server-renderer');\n\tconst mod = await import(conventionPath);\n\tconst ErrorComponent = mod.default;\n\tif (!ErrorComponent) return null;\n\n\tconst app = createSSRApp({\n\t\trender: () => h(ErrorComponent, errorProps)\n\t});\n\tconst rawBody = await renderToString(app);\n\n\t// Vue SSR escapes quotes inside <component is=\"style\"> tags.\n\t// Extract style content, unescape it, and move to <head>.\n\tconst { styles, body } = unescapeVueStyles(rawBody);\n\tconst html = `<!DOCTYPE html><html><head>${styles}</head><body><div id=\"root\">${body}</div></body></html>`;\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 500\n\t});\n};\n\nconst renderAngularError = async (\n\tconventionPath: string,\n\terrorProps: ErrorPageProps\n) => {\n\t// Angular convention error pages use the simple function-style renderer.\n\t// Class-style components (templateUrl/styleUrl trio) routed through the\n\t// full Angular SSR pipeline are tracked separately — see CLAUDE.md.\n\tconst mod = await import(conventionPath);\n\tconst renderFn = mod.default;\n\tif (typeof renderFn !== 'function') return null;\n\n\tconst html = renderFn(errorProps);\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 500\n\t});\n};\n\nconst escapeHtml = (value: string) =>\n\tvalue\n\t\t.replace(/&/g, '&amp;')\n\t\t.replace(/</g, '&lt;')\n\t\t.replace(/>/g, '&gt;')\n\t\t.replace(/\"/g, '&quot;')\n\t\t.replace(/'/g, '&#39;');\n\nconst replaceErrorTokens = (template: string, errorProps: ErrorPageProps) =>\n\ttemplate\n\t\t.replace(/\\{\\{\\s*name\\s*\\}\\}/g, escapeHtml(errorProps.name))\n\t\t.replace(/\\{\\{\\s*message\\s*\\}\\}/g, escapeHtml(errorProps.message))\n\t\t.replace(\n\t\t\t/\\{\\{\\s*stack\\s*\\}\\}/g,\n\t\t\terrorProps.stack ? escapeHtml(errorProps.stack) : ''\n\t\t);\n\nconst renderHtmlError = async (\n\tconventionPath: string,\n\terrorProps: ErrorPageProps\n) => {\n\tconst template = await Bun.file(conventionPath).text();\n\tconst html = replaceErrorTokens(template, errorProps);\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 500\n\t});\n};\n\nconst logConventionRenderError = (\n\tframework: keyof ConventionsMap,\n\tlabel: string,\n\trenderError: unknown\n) => {\n\tconst message = renderError instanceof Error ? renderError.message : '';\n\tif (\n\t\tmessage.includes('Cannot find module') ||\n\t\tmessage.includes('Cannot find package') ||\n\t\tmessage.includes('not found in module')\n\t) {\n\t\tconsole.error(\n\t\t\t`[SSR] Convention ${label} page for ${framework} failed: missing framework package. ` +\n\t\t\t\t`Ensure the ${framework} runtime is installed (e.g. bun add ${framework === 'react' ? 'react react-dom' : framework}).`\n\t\t);\n\n\t\treturn;\n\t}\n\n\tconsole.error(\n\t\t`[SSR] Failed to render ${framework} convention ${label} page:`,\n\t\trenderError\n\t);\n};\n\n// Phase 1 Ember adapter: convention pages aren't wired yet (no\n// renderEmberError analog ships in v1). Returning null falls through to\n// the generic ssrErrorPage. Phase 1.5 replaces this stub with a real\n// renderer once the convention scanner knows about .gjs/.gts files.\nconst renderEmberError = async () => null;\nconst renderEmberNotFound = async () => null;\n\nconst ERROR_RENDERERS: Record<\n\tkeyof ConventionsMap,\n\t(\n\t\tconventionPath: string,\n\t\terrorProps: ErrorPageProps\n\t) => Promise<Response | null>\n> = {\n\tangular: renderAngularError,\n\tember: renderEmberError,\n\thtml: renderHtmlError,\n\treact: renderReactError,\n\tsvelte: renderSvelteError,\n\tvue: renderVueError\n};\n\nconst tryFrameworkErrorConvention = async (\n\tframework: keyof ConventionsMap,\n\tpageName: string,\n\terrorProps: ErrorPageProps,\n\terror: unknown\n) => {\n\tlet conventionPath = resolveErrorConventionPath(framework, pageName);\n\tif (!conventionPath && error instanceof Error && error.stack) {\n\t\tfor (const match of error.stack.matchAll(\n\t\t\t/^\\s*at\\s+([A-Za-z_$][\\w$]*)/gm\n\t\t)) {\n\t\t\tconst candidate = match[1];\n\t\t\tif (!candidate) continue;\n\n\t\t\tconventionPath = resolveErrorConventionPath(framework, candidate);\n\t\t\tif (conventionPath) break;\n\t\t}\n\t}\n\tif (!conventionPath) return null;\n\n\tconst renderer = ERROR_RENDERERS[framework];\n\tif (!renderer) return null;\n\n\ttry {\n\t\treturn await renderer(conventionPath, errorProps);\n\t} catch (renderError) {\n\t\tlogConventionRenderError(framework, 'error', renderError);\n\t}\n\n\treturn null;\n};\n\nexport const renderConventionError = async (\n\tframework: keyof ConventionsMap,\n\tpageName: string,\n\terror: unknown\n) => {\n\tconst errorProps = buildErrorProps(error);\n\n\tconst frameworkResponse = await tryFrameworkErrorConvention(\n\t\tframework,\n\t\tpageName,\n\t\terrorProps,\n\t\terror\n\t);\n\tif (frameworkResponse) return frameworkResponse;\n\n\t// Universal fallback: any project can ship a plain `error.html` in\n\t// the html pages dir as the last-resort branded error page before\n\t// the inline ssrErrorPage() takes over.\n\tif (framework !== 'html') {\n\t\tconst htmlResponse = await tryFrameworkErrorConvention(\n\t\t\t'html',\n\t\t\tpageName,\n\t\t\terrorProps,\n\t\t\terror\n\t\t);\n\t\tif (htmlResponse) return htmlResponse;\n\t}\n\n\treturn null;\n};\n\nconst renderReactNotFound = async (conventionPath: string) => {\n\tconst { createElement } = await import('react');\n\tconst { renderToReadableStream } = await import('react-dom/server');\n\tconst mod = await import(conventionPath);\n\tconst NotFoundComponent = mod.default;\n\tif (typeof NotFoundComponent !== 'function') return null;\n\n\tconst element = createElement(NotFoundComponent);\n\tconst stream = await renderToReadableStream(element);\n\n\treturn new Response(stream, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 404\n\t});\n};\n\nconst renderSvelteNotFound = async (conventionPath: string) => {\n\tconst { render } = await import('svelte/server');\n\tconst mod = await import(conventionPath);\n\tconst NotFoundComponent = mod.default;\n\tif (!NotFoundComponent) return null;\n\n\tconst { head, body } = render(NotFoundComponent);\n\tconst html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 404\n\t});\n};\n\nconst renderVueNotFound = async (conventionPath: string) => {\n\tconst { createSSRApp, h } = await import('vue');\n\tconst { renderToString } = await import('vue/server-renderer');\n\tconst mod = await import(conventionPath);\n\tconst NotFoundComponent = mod.default;\n\tif (!NotFoundComponent) return null;\n\n\tconst app = createSSRApp({\n\t\trender: () => h(NotFoundComponent)\n\t});\n\tconst rawBody = await renderToString(app);\n\n\tconst { styles, body } = unescapeVueStyles(rawBody);\n\tconst html = `<!DOCTYPE html><html><head>${styles}</head><body><div id=\"root\">${body}</div></body></html>`;\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 404\n\t});\n};\n\nconst renderAngularNotFound = async (conventionPath: string) => {\n\tconst mod = await import(conventionPath);\n\tconst renderFn = mod.default;\n\tif (typeof renderFn !== 'function') return null;\n\n\tconst html = renderFn();\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 404\n\t});\n};\n\nconst renderHtmlNotFound = async (conventionPath: string) => {\n\tconst html = await Bun.file(conventionPath).text();\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 404\n\t});\n};\n\nconst NOT_FOUND_RENDERERS: Record<\n\tkeyof ConventionsMap,\n\t(conventionPath: string) => Promise<Response | null>\n> = {\n\tangular: renderAngularNotFound,\n\tember: renderEmberNotFound,\n\thtml: renderHtmlNotFound,\n\treact: renderReactNotFound,\n\tsvelte: renderSvelteNotFound,\n\tvue: renderVueNotFound\n};\n\nexport const renderConventionNotFound = async (\n\tframework: keyof ConventionsMap\n) => {\n\tconst conventionPath = resolveNotFoundConventionPath(framework);\n\tif (!conventionPath) return null;\n\n\tconst renderer = NOT_FOUND_RENDERERS[framework];\n\tif (!renderer) return null;\n\n\ttry {\n\t\treturn await renderer(conventionPath);\n\t} catch (renderError) {\n\t\tlogConventionRenderError(framework, 'not-found', renderError);\n\t}\n\n\treturn null;\n};\n\nconst NOT_FOUND_PRIORITY: (keyof ConventionsMap)[] = [\n\t'react',\n\t'svelte',\n\t'vue',\n\t'angular',\n\t'html'\n];\n\nexport const renderFirstNotFound = async () => {\n\tconst renderNext = async (frameworks: (keyof ConventionsMap)[]) => {\n\t\tconst [framework, ...remaining] = frameworks;\n\t\tif (!framework) {\n\t\t\treturn null;\n\t\t}\n\t\tif (!getMap()[framework]?.defaults?.notFound) {\n\t\t\treturn renderNext(remaining);\n\t\t}\n\n\t\tconst response = await renderConventionNotFound(framework);\n\t\tif (response) {\n\t\t\treturn response;\n\t\t}\n\n\t\treturn renderNext(remaining);\n\t};\n\n\treturn renderNext(NOT_FOUND_PRIORITY);\n};\n",
161
161
  "import { withRegisteredStreamingSlots } from './responseEnhancers';\n\nexport const wrapPageHandlerWithStreamingSlots = <\n\tT extends (...args: unknown[]) => Response | Promise<Response>\n>(\n\thandler: T,\n\toptions?: Parameters<typeof withRegisteredStreamingSlots>[1]\n) => {\n\tconst wrapped = (...args: Parameters<T>) =>\n\t\twithRegisteredStreamingSlots(() => handler(...args), options);\n\n\treturn wrapped;\n};\n",
162
- "import { argv } from 'node:process';\nimport { env } from 'bun';\nimport { Elysia } from 'elysia';\nimport { DEFAULT_PORT, MILLISECONDS_IN_A_SECOND } from '../constants';\nimport { loadDevCert } from '../dev/devCert';\nimport {\n\tregisterInstance,\n\tresolveProjectName\n} from '../utils/instanceRegistry';\nimport { getLocalIPAddress } from '../utils/networking';\nimport { startupBanner } from '../utils/startupBanner';\n\n// Env-var precedence: ABSOLUTE_HOST/ABSOLUTE_PORT (set by `bun dev` after\n// resolving config-file values + Vite-style port fallback) → legacy\n// HOST/PORT → defaults.\nlet host = env.ABSOLUTE_HOST ?? env.HOST ?? 'localhost';\nconst port = env.ABSOLUTE_PORT ?? env.PORT ?? DEFAULT_PORT;\nconst visibility = env.ABSOLUTE_WORKSPACE_SERVICE_VISIBILITY ?? 'public';\nconst managedByWorkspace = env.ABSOLUTE_WORKSPACE_MANAGED === '1';\nlet localIP: string | undefined;\n\nconst args = argv;\nconst hostFlag = args.includes('--host');\n\nif (hostFlag) {\n\tlocalIP = getLocalIPAddress();\n\thost = '0.0.0.0';\n}\n\n// TLS is enabled via ABSOLUTE_HTTPS env var set by the config loader\nconst loadTls = () => {\n\tif (env.NODE_ENV !== 'development') return undefined;\n\tif (env.ABSOLUTE_HTTPS !== 'true') return undefined;\n\n\ttry {\n\t\treturn loadDevCert();\n\t} catch {\n\t\treturn undefined;\n\t}\n};\nconst tls = loadTls();\nconst protocol = tls ? 'https' : 'http';\n\n// Publish this server to the global instance registry so `absolute ls` can see\n// it. Skipped when an outer `absolute` CLI/orchestrator already owns the entry\n// (ABSOLUTE_INSTANCE_MANAGED) — this branch is the catch-all for servers\n// started outside the CLI: a manually-run `bun server.ts` or any standalone\n// process. registerInstance handles its own exit cleanup.\nconst selfRegisterInstance = () => {\n\tif (env.ABSOLUTE_INSTANCE_MANAGED === '1') return;\n\n\tregisterInstance({\n\t\tcommand: [...process.argv],\n\t\tconfigPath: env.ABSOLUTE_CONFIG ?? null,\n\t\tcontrollerPid: process.pid,\n\t\tcwd: process.cwd(),\n\t\tframeworks: [],\n\t\thost,\n\t\thttps: protocol === 'https',\n\t\tlogFile: null,\n\t\tname: resolveProjectName(process.cwd()),\n\t\tpid: process.pid,\n\t\tport: Number(port) || null,\n\t\tppid: process.ppid,\n\t\tsource: 'standalone',\n\t\tstartedAt: new Date().toISOString()\n\t});\n};\n\nexport const networking = <A extends Elysia>(app: A) => {\n\tif (env.ABSOLUTE_COMPILED_RUNTIME === '1') return app;\n\n\t// Path B (in-place backend HMR): if a previous evaluation of this\n\t// entry already started a Bun.serve, swap its handler in place\n\t// instead of re-binding the port. The new Elysia instance becomes\n\t// the live handler atomically; the listening socket persists, so\n\t// in-flight requests, WebSocket sessions, DB pools, and module-\n\t// level globals carry across edits.\n\t//\n\t// Activation: the dev runtime sets `globalThis.__absoluteBunServer`\n\t// after the first `app.listen(...)` call; it triggers re-evaluation\n\t// of the entry via cache-busted dynamic import on file change.\n\t// Outside dev, this branch never runs (the global is unset).\n\tconst liveServer = globalThis.__absoluteBunServer;\n\tif (liveServer && typeof liveServer.reload === 'function') {\n\t\t// Backend state HMR: restore the previous Elysia instance's\n\t\t// `app.store` values for keys the new app also declares.\n\t\t// `app.store` holds anything the user (or a plugin like\n\t\t// `elysia-scoped-state`) put there via `.state(...)` — which\n\t\t// in dev was just `.state({scoped: {}})` initial values, so\n\t\t// without this every entry edit reset all per-session data.\n\t\t//\n\t\t// Behavior, mirroring frontend HMR semantics:\n\t\t// - Same key in both: restore previous live value (preserves\n\t\t// per-user state, request counters, etc. across edits).\n\t\t// - Key only in the new app: keep its fresh initial (added\n\t\t// state plugins or new `.state(...)` calls).\n\t\t// - Key only in the previous app: drop it (state the user\n\t\t// removed; new code shouldn't see it).\n\t\t//\n\t\t// Captured in the listen branch below as\n\t\t// `globalThis.__absolutePreviousAppStore`. The first reload\n\t\t// after server start finds the initial store there.\n\t\tconst prevStore = globalThis.__absolutePreviousAppStore;\n\t\tif (prevStore && app.store && typeof app.store === 'object') {\n\t\t\tconst newStore = app.store as Record<string, unknown>;\n\t\t\tconst oldStore = prevStore as Record<string, unknown>;\n\t\t\tfor (const key of Object.keys(newStore)) {\n\t\t\t\tif (key in oldStore) {\n\t\t\t\t\tnewStore[key] = oldStore[key];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tglobalThis.__absolutePreviousAppStore = app.store as Record<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>;\n\t\ttry {\n\t\t\tapp.compile();\n\t\t} catch {\n\t\t\t/* compile is best-effort; some Elysia configs skip it */\n\t\t}\n\t\t// Elysia compiles routes into Bun.serve's `routes` static map\n\t\t// at .listen() time for performance. `Bun.serve.reload({fetch})`\n\t\t// only swaps the fetch fallback — the OLD static `routes` map\n\t\t// keeps serving original handlers. Clear it on reload so every\n\t\t// request falls through to our new app's fetch.\n\t\tliveServer.reload({\n\t\t\tfetch: (request: Request) => app.fetch(request),\n\t\t\troutes: {}\n\t\t});\n\n\t\treturn app;\n\t}\n\n\tconst listened = app.listen(\n\t\t{\n\t\t\thostname: host,\n\t\t\tport: port,\n\t\t\t...(tls\n\t\t\t\t? {\n\t\t\t\t\t\ttls: {\n\t\t\t\t\t\t\tcert: tls.cert,\n\t\t\t\t\t\t\tkey: tls.key\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t: {})\n\t\t},\n\t\t() => {\n\t\t\tselfRegisterInstance();\n\n\t\t\tif (visibility === 'internal' || managedByWorkspace) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip logging on Bun --hot reloads (HMR handles its own output)\n\t\t\tconst isHotReload = Boolean(globalThis.__hmrServerStartup);\n\t\t\tglobalThis.__hmrServerStartup = true;\n\t\t\tif (isHotReload) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst buildDuration =\n\t\t\t\tglobalThis.__hmrBuildDuration ??\n\t\t\t\tNumber(env.ABSOLUTE_BUILD_DURATION || 0);\n\t\t\tconst readyDuration = process.uptime() * MILLISECONDS_IN_A_SECOND;\n\n\t\t\tconst version =\n\t\t\t\tglobalThis.__absoluteVersion || env.ABSOLUTE_VERSION || '';\n\n\t\t\tstartupBanner({\n\t\t\t\tbuildDuration,\n\t\t\t\thost,\n\t\t\t\tnetworkUrl: hostFlag\n\t\t\t\t\t? `${protocol}://${localIP}:${port}/`\n\t\t\t\t\t: undefined,\n\t\t\t\tport,\n\t\t\t\tprotocol,\n\t\t\t\treadyDuration,\n\t\t\t\tversion\n\t\t\t});\n\t\t}\n\t);\n\n\t// Capture the underlying Bun.serve instance synchronously after\n\t// `.listen()` returns. Elysia sets `app.server = Bun.serve(...)`\n\t// inline, so the assignment is observable here without waiting for\n\t// any lifecycle hook. Subsequent re-evaluations of the entry hit\n\t// the reload-aware branch above and never reach this point.\n\tif (app.server) {\n\t\tglobalThis.__absoluteBunServer = app.server;\n\t\tglobalThis.__absolutePreviousAppStore = app.store as Record<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>;\n\t\t// Path B: start the entry-file watcher now that the server is\n\t\t// bound. The watcher triggers cache-busted dynamic re-imports\n\t\t// on entry edits, which hit the reload-aware branch instead of\n\t\t// re-binding. Only runs in dev mode (compiled runtime returned\n\t\t// early at the top).\n\t\tif (env.NODE_ENV === 'development') {\n\t\t\tvoid import('../dev/serverEntryWatcher')\n\t\t\t\t.then(({ startServerEntryWatcher }) => {\n\t\t\t\t\tstartServerEntryWatcher();\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\t/* dev-only feature; never break the server */\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`[hmr] entry watcher setup failed: ${\n\t\t\t\t\t\t\terr instanceof Error ? err.message : String(err)\n\t\t\t\t\t\t}`\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t}\n\t}\n\n\treturn listened;\n};\n",
162
+ "import { argv } from 'node:process';\nimport { env } from 'bun';\nimport { Elysia } from 'elysia';\nimport { DEFAULT_PORT, MILLISECONDS_IN_A_SECOND } from '../constants';\nimport { loadDevCert } from '../dev/devCert';\nimport {\n\tregisterInstance,\n\tresolveProjectName\n} from '../utils/instanceRegistry';\nimport { getLocalIPAddress } from '../utils/networking';\nimport { startupBanner } from '../utils/startupBanner';\n\n// Env-var precedence: ABSOLUTE_HOST/ABSOLUTE_PORT (set by `bun dev` after\n// resolving config-file values + Vite-style port fallback) → legacy\n// HOST/PORT → defaults.\nlet host = env.ABSOLUTE_HOST ?? env.HOST ?? 'localhost';\nconst port = env.ABSOLUTE_PORT ?? env.PORT ?? DEFAULT_PORT;\nconst visibility = env.ABSOLUTE_WORKSPACE_SERVICE_VISIBILITY ?? 'public';\nconst managedByWorkspace = env.ABSOLUTE_WORKSPACE_MANAGED === '1';\nlet localIP: string | undefined;\n\nconst args = argv;\nconst hostFlag = args.includes('--host');\n\nif (hostFlag) {\n\tlocalIP = getLocalIPAddress();\n\thost = '0.0.0.0';\n}\n\n// TLS is enabled via ABSOLUTE_HTTPS env var set by the config loader\nconst loadTls = () => {\n\tif (env.NODE_ENV !== 'development') return undefined;\n\tif (env.ABSOLUTE_HTTPS !== 'true') return undefined;\n\n\ttry {\n\t\treturn loadDevCert();\n\t} catch {\n\t\treturn undefined;\n\t}\n};\nconst tls = loadTls();\nconst protocol = tls ? 'https' : 'http';\n\n// Publish this server to the global instance registry so `absolute ps` can see\n// it. Skipped when an outer `absolute` CLI/orchestrator already owns the entry\n// (ABSOLUTE_INSTANCE_MANAGED) — this branch is the catch-all for servers\n// started outside the CLI: a manually-run `bun server.ts` or any standalone\n// process. registerInstance handles its own exit cleanup.\nconst selfRegisterInstance = () => {\n\tif (env.ABSOLUTE_INSTANCE_MANAGED === '1') return;\n\n\tregisterInstance({\n\t\tcommand: [...process.argv],\n\t\tconfigPath: env.ABSOLUTE_CONFIG ?? null,\n\t\tcontrollerPid: process.pid,\n\t\tcwd: process.cwd(),\n\t\tframeworks: [],\n\t\thost,\n\t\thttps: protocol === 'https',\n\t\tlogFile: null,\n\t\tname: resolveProjectName(process.cwd()),\n\t\tpid: process.pid,\n\t\tport: Number(port) || null,\n\t\tppid: process.ppid,\n\t\tsource: 'standalone',\n\t\tstartedAt: new Date().toISOString()\n\t});\n};\n\nexport const networking = <A extends Elysia>(app: A) => {\n\tif (env.ABSOLUTE_COMPILED_RUNTIME === '1') return app;\n\n\t// Path B (in-place backend HMR): if a previous evaluation of this\n\t// entry already started a Bun.serve, swap its handler in place\n\t// instead of re-binding the port. The new Elysia instance becomes\n\t// the live handler atomically; the listening socket persists, so\n\t// in-flight requests, WebSocket sessions, DB pools, and module-\n\t// level globals carry across edits.\n\t//\n\t// Activation: the dev runtime sets `globalThis.__absoluteBunServer`\n\t// after the first `app.listen(...)` call; it triggers re-evaluation\n\t// of the entry via cache-busted dynamic import on file change.\n\t// Outside dev, this branch never runs (the global is unset).\n\tconst liveServer = globalThis.__absoluteBunServer;\n\tif (liveServer && typeof liveServer.reload === 'function') {\n\t\t// Backend state HMR: restore the previous Elysia instance's\n\t\t// `app.store` values for keys the new app also declares.\n\t\t// `app.store` holds anything the user (or a plugin like\n\t\t// `elysia-scoped-state`) put there via `.state(...)` — which\n\t\t// in dev was just `.state({scoped: {}})` initial values, so\n\t\t// without this every entry edit reset all per-session data.\n\t\t//\n\t\t// Behavior, mirroring frontend HMR semantics:\n\t\t// - Same key in both: restore previous live value (preserves\n\t\t// per-user state, request counters, etc. across edits).\n\t\t// - Key only in the new app: keep its fresh initial (added\n\t\t// state plugins or new `.state(...)` calls).\n\t\t// - Key only in the previous app: drop it (state the user\n\t\t// removed; new code shouldn't see it).\n\t\t//\n\t\t// Captured in the listen branch below as\n\t\t// `globalThis.__absolutePreviousAppStore`. The first reload\n\t\t// after server start finds the initial store there.\n\t\tconst prevStore = globalThis.__absolutePreviousAppStore;\n\t\tif (prevStore && app.store && typeof app.store === 'object') {\n\t\t\tconst newStore = app.store as Record<string, unknown>;\n\t\t\tconst oldStore = prevStore as Record<string, unknown>;\n\t\t\tfor (const key of Object.keys(newStore)) {\n\t\t\t\tif (key in oldStore) {\n\t\t\t\t\tnewStore[key] = oldStore[key];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tglobalThis.__absolutePreviousAppStore = app.store as Record<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>;\n\t\ttry {\n\t\t\tapp.compile();\n\t\t} catch {\n\t\t\t/* compile is best-effort; some Elysia configs skip it */\n\t\t}\n\t\t// Elysia compiles routes into Bun.serve's `routes` static map\n\t\t// at .listen() time for performance. `Bun.serve.reload({fetch})`\n\t\t// only swaps the fetch fallback — the OLD static `routes` map\n\t\t// keeps serving original handlers. Clear it on reload so every\n\t\t// request falls through to our new app's fetch.\n\t\tliveServer.reload({\n\t\t\tfetch: (request: Request) => app.fetch(request),\n\t\t\troutes: {}\n\t\t});\n\n\t\treturn app;\n\t}\n\n\tconst listened = app.listen(\n\t\t{\n\t\t\thostname: host,\n\t\t\tport: port,\n\t\t\t...(tls\n\t\t\t\t? {\n\t\t\t\t\t\ttls: {\n\t\t\t\t\t\t\tcert: tls.cert,\n\t\t\t\t\t\t\tkey: tls.key\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t: {})\n\t\t},\n\t\t() => {\n\t\t\tselfRegisterInstance();\n\n\t\t\tif (visibility === 'internal' || managedByWorkspace) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip logging on Bun --hot reloads (HMR handles its own output)\n\t\t\tconst isHotReload = Boolean(globalThis.__hmrServerStartup);\n\t\t\tglobalThis.__hmrServerStartup = true;\n\t\t\tif (isHotReload) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst buildDuration =\n\t\t\t\tglobalThis.__hmrBuildDuration ??\n\t\t\t\tNumber(env.ABSOLUTE_BUILD_DURATION || 0);\n\t\t\tconst readyDuration = process.uptime() * MILLISECONDS_IN_A_SECOND;\n\n\t\t\tconst version =\n\t\t\t\tglobalThis.__absoluteVersion || env.ABSOLUTE_VERSION || '';\n\n\t\t\tstartupBanner({\n\t\t\t\tbuildDuration,\n\t\t\t\thost,\n\t\t\t\tnetworkUrl: hostFlag\n\t\t\t\t\t? `${protocol}://${localIP}:${port}/`\n\t\t\t\t\t: undefined,\n\t\t\t\tport,\n\t\t\t\tprotocol,\n\t\t\t\treadyDuration,\n\t\t\t\tversion\n\t\t\t});\n\t\t}\n\t);\n\n\t// Capture the underlying Bun.serve instance synchronously after\n\t// `.listen()` returns. Elysia sets `app.server = Bun.serve(...)`\n\t// inline, so the assignment is observable here without waiting for\n\t// any lifecycle hook. Subsequent re-evaluations of the entry hit\n\t// the reload-aware branch above and never reach this point.\n\tif (app.server) {\n\t\tglobalThis.__absoluteBunServer = app.server;\n\t\tglobalThis.__absolutePreviousAppStore = app.store as Record<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>;\n\t\t// Path B: start the entry-file watcher now that the server is\n\t\t// bound. The watcher triggers cache-busted dynamic re-imports\n\t\t// on entry edits, which hit the reload-aware branch instead of\n\t\t// re-binding. Only runs in dev mode (compiled runtime returned\n\t\t// early at the top).\n\t\tif (env.NODE_ENV === 'development') {\n\t\t\tvoid import('../dev/serverEntryWatcher')\n\t\t\t\t.then(({ startServerEntryWatcher }) => {\n\t\t\t\t\tstartServerEntryWatcher();\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\t/* dev-only feature; never break the server */\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`[hmr] entry watcher setup failed: ${\n\t\t\t\t\t\t\terr instanceof Error ? err.message : String(err)\n\t\t\t\t\t\t}`\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t}\n\t}\n\n\treturn listened;\n};\n",
163
163
  "import {\n\tcopyFileSync,\n\texistsSync,\n\tmkdirSync,\n\treadFileSync,\n\trmSync\n} from 'node:fs';\nimport { platform } from 'node:os';\nimport { join } from 'node:path';\n\nconst CERT_DIR = join(process.cwd(), '.absolutejs');\nconst CERT_PATH = join(CERT_DIR, 'cert.pem');\nconst KEY_PATH = join(CERT_DIR, 'key.pem');\nconst CERT_VALIDITY_DAYS = 365;\n\n// Neutral log that doesn't use [hmr] tag\nconst devLog = (msg: string) =>\n\tconsole.log(\n\t\t`\\x1b[2m${new Date().toLocaleTimeString()}\\x1b[0m \\x1b[36m[dev]\\x1b[0m ${msg}`\n\t);\n\nconst devWarn = (msg: string) =>\n\tconsole.log(\n\t\t`\\x1b[2m${new Date().toLocaleTimeString()}\\x1b[0m \\x1b[33m[dev]\\x1b[0m \\x1b[33m${msg}\\x1b[0m`\n\t);\n\nconst certFilesExist = () => existsSync(CERT_PATH) && existsSync(KEY_PATH);\n\nconst isCertExpired = () => {\n\ttry {\n\t\tconst certPem = readFileSync(CERT_PATH, 'utf-8');\n\t\tconst proc = Bun.spawnSync(['openssl', 'x509', '-enddate', '-noout'], {\n\t\t\tstdin: new TextEncoder().encode(certPem)\n\t\t});\n\t\tconst output = new TextDecoder().decode(proc.stdout).trim();\n\t\tconst dateStr = output.replace('notAfter=', '');\n\t\tconst expiryDate = new Date(dateStr);\n\n\t\treturn expiryDate.getTime() < Date.now();\n\t} catch {\n\t\treturn true;\n\t}\n};\n\nexport const hasMkcert = () => {\n\ttry {\n\t\tconst result = Bun.spawnSync(['mkcert', '-version'], {\n\t\t\tstderr: 'pipe',\n\t\t\tstdout: 'pipe'\n\t\t});\n\n\t\treturn result.exitCode === 0;\n\t} catch {\n\t\treturn false;\n\t}\n};\n\nconst generateWithMkcert = () => {\n\tconst result = Bun.spawnSync(\n\t\t[\n\t\t\t'mkcert',\n\t\t\t'-cert-file',\n\t\t\tCERT_PATH,\n\t\t\t'-key-file',\n\t\t\tKEY_PATH,\n\t\t\t'localhost',\n\t\t\t'127.0.0.1',\n\t\t\t'::1'\n\t\t],\n\t\t{ stderr: 'pipe', stdout: 'pipe' }\n\t);\n\n\tif (result.exitCode !== 0) {\n\t\tconst err = new TextDecoder().decode(result.stderr);\n\t\tthrow new Error(`mkcert failed: ${err}`);\n\t}\n};\n\nconst generateSelfSigned = () => {\n\tconst proc = Bun.spawnSync(\n\t\t[\n\t\t\t'openssl',\n\t\t\t'req',\n\t\t\t'-x509',\n\t\t\t'-newkey',\n\t\t\t'ec',\n\t\t\t'-pkeyopt',\n\t\t\t'ec_paramgen_curve:prime256v1',\n\t\t\t'-days',\n\t\t\tString(CERT_VALIDITY_DAYS),\n\t\t\t'-nodes',\n\t\t\t'-keyout',\n\t\t\tKEY_PATH,\n\t\t\t'-out',\n\t\t\tCERT_PATH,\n\t\t\t'-subj',\n\t\t\t'/CN=localhost',\n\t\t\t'-addext',\n\t\t\t'subjectAltName=DNS:localhost,IP:127.0.0.1,IP:::1'\n\t\t],\n\t\t{ stderr: 'pipe', stdout: 'pipe' }\n\t);\n\n\tif (proc.exitCode !== 0) {\n\t\tconst err = new TextDecoder().decode(proc.stderr);\n\t\tthrow new Error(`openssl failed: ${err}`);\n\t}\n\n\tdevLog(\n\t\t'Using self-signed certificate — browser will show a one-time warning'\n\t);\n};\n\nconst generateCert = () => {\n\tif (hasMkcert()) {\n\t\tgenerateWithMkcert();\n\t} else {\n\t\tgenerateSelfSigned();\n\t}\n};\n\nexport const ensureDevCert = () => {\n\tmkdirSync(CERT_DIR, { recursive: true });\n\n\t// Cert exists and valid — reuse silently\n\tif (hasCert()) {\n\t\treturn { cert: CERT_PATH, key: KEY_PATH };\n\t}\n\n\t// Expired — regenerate silently\n\tif (certFilesExist()) {\n\t\tdevLog('Certificate expired, regenerating...');\n\t}\n\n\ttry {\n\t\tgenerateCert();\n\t} catch (err) {\n\t\tdevWarn(\n\t\t\t`Failed to generate certificate: ${err instanceof Error ? err.message : err}`\n\t\t);\n\n\t\treturn null;\n\t}\n\n\treturn { cert: CERT_PATH, key: KEY_PATH };\n};\nexport const hasCert = () => certFilesExist() && !isCertExpired();\nexport const loadDevCert = () => {\n\tconst paths = ensureDevCert();\n\tif (!paths) return null;\n\n\ttry {\n\t\treturn {\n\t\t\tcert: readFileSync(paths.cert, 'utf-8'),\n\t\t\tkey: readFileSync(paths.key, 'utf-8')\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n};\n\nconst commandExists = (cmd: string) => {\n\ttry {\n\t\tconst check = platform() === 'win32' ? ['where', cmd] : ['which', cmd];\n\t\tconst result = Bun.spawnSync(check, {\n\t\t\tstderr: 'pipe',\n\t\t\tstdout: 'pipe'\n\t\t});\n\n\t\treturn result.exitCode === 0;\n\t} catch {\n\t\treturn false;\n\t}\n};\n\nconst installMkcertDarwin = () => {\n\tif (!commandExists('brew')) {\n\t\tdevWarn('Install Homebrew first: https://brew.sh');\n\n\t\treturn false;\n\t}\n\n\tdevLog('Installing mkcert with Homebrew...');\n\tconst result = Bun.spawnSync(['brew', 'install', 'mkcert'], {\n\t\tstderr: 'pipe',\n\t\tstdout: 'pipe'\n\t});\n\n\treturn result.exitCode === 0;\n};\n\nconst installMkcertLinux = () => {\n\t// stdin + stderr inherit for password prompt, stdout piped to hide package logs\n\tconst sudoOpts: { stderr: 'inherit'; stdin: 'inherit'; stdout: 'pipe' } = {\n\t\tstderr: 'inherit',\n\t\tstdin: 'inherit',\n\t\tstdout: 'pipe'\n\t};\n\n\tif (commandExists('apt-get')) {\n\t\tdevLog('Installing mkcert (may prompt for password)...');\n\t\t// Install mkcert + libnss3-tools (certutil) together\n\t\t// so mkcert -install can add the CA to browser trust stores\n\t\tconst result = Bun.spawnSync(\n\t\t\t['sudo', 'apt-get', 'install', '-y', 'mkcert', 'libnss3-tools'],\n\t\t\tsudoOpts\n\t\t);\n\t\tif (result.exitCode === 0) return true;\n\t}\n\n\tif (commandExists('dnf')) {\n\t\tdevLog('Installing mkcert (may prompt for password)...');\n\t\tconst result = Bun.spawnSync(\n\t\t\t['sudo', 'dnf', 'install', '-y', 'mkcert'],\n\t\t\tsudoOpts\n\t\t);\n\t\tif (result.exitCode === 0) return true;\n\t}\n\n\tif (commandExists('pacman')) {\n\t\tdevLog('Installing mkcert (may prompt for password)...');\n\t\tconst result = Bun.spawnSync(\n\t\t\t['sudo', 'pacman', '-S', '--noconfirm', 'mkcert'],\n\t\t\tsudoOpts\n\t\t);\n\t\tif (result.exitCode === 0) return true;\n\t}\n\n\tdevWarn('Could not install mkcert automatically.');\n\tconsole.log(' See: https://github.com/FiloSottile/mkcert#installation');\n\n\treturn false;\n};\n\nconst installMkcertWin32 = () => {\n\tif (commandExists('choco')) {\n\t\tdevLog('Installing mkcert with Chocolatey...');\n\t\tconst result = Bun.spawnSync(['choco', 'install', '-y', 'mkcert'], {\n\t\t\tstderr: 'pipe',\n\t\t\tstdout: 'pipe'\n\t\t});\n\t\tif (result.exitCode === 0) return true;\n\t}\n\n\tif (commandExists('winget')) {\n\t\tdevLog('Installing mkcert with winget...');\n\t\tconst result = Bun.spawnSync(\n\t\t\t['winget', 'install', '--id', 'FiloSottile.mkcert', '-e'],\n\t\t\t{ stderr: 'pipe', stdout: 'pipe' }\n\t\t);\n\t\tif (result.exitCode === 0) return true;\n\t}\n\n\tdevWarn('Could not install mkcert automatically.');\n\tconsole.log(' See: https://github.com/FiloSottile/mkcert#installation');\n\n\treturn false;\n};\n\nconst installMkcert = () => {\n\tconst osPlatform = platform();\n\n\tif (osPlatform === 'darwin') return installMkcertDarwin();\n\tif (osPlatform === 'linux') return installMkcertLinux();\n\tif (osPlatform === 'win32') return installMkcertWin32();\n\n\treturn false;\n};\n\nconst ensureMkcert = () => {\n\tif (hasMkcert()) return true;\n\tif (!installMkcert()) return false;\n\n\t// Verify it installed\n\tif (!hasMkcert()) {\n\t\tdevWarn(\n\t\t\t'mkcert installed but not found in PATH. Restart your terminal and try again.'\n\t\t);\n\n\t\treturn false;\n\t}\n\n\treturn true;\n};\n\nconst isWSL = () => {\n\tif (platform() !== 'linux') return false;\n\ttry {\n\t\treturn /microsoft|wsl/i.test(readFileSync('/proc/version', 'utf-8'));\n\t} catch {\n\t\treturn false;\n\t}\n};\n\nconst runCapture = (cmd: string[]) => {\n\ttry {\n\t\tconst result = Bun.spawnSync(cmd, { stderr: 'pipe', stdout: 'pipe' });\n\t\tif (result.exitCode !== 0) return null;\n\t\tconst out = new TextDecoder().decode(result.stdout).trim();\n\n\t\treturn out || null;\n\t} catch {\n\t\treturn null;\n\t}\n};\n\nconst mkcertCaRoot = () => runCapture(['mkcert', '-CAROOT']);\nconst toWindowsPath = (linuxPath: string) =>\n\trunCapture(['wslpath', '-w', linuxPath]);\nconst windowsTempDir = () => {\n\tconst winTemp = runCapture(['cmd.exe', '/c', 'echo %TEMP%']);\n\tif (!winTemp) return null;\n\n\treturn runCapture(['wslpath', '-u', winTemp]);\n};\n\n/**\n * Under WSL the browser runs on Windows, whose trust store never receives the\n * CA that `mkcert -install` added on the Linux side — so dev HTTPS shows as\n * untrusted there. Stage mkcert's rootCA in a Windows-visible temp dir and\n * import it into the current user's Root store via PowerShell (no admin, no GUI\n * prompt, idempotent). Returns true when the CA is trusted on Windows.\n */\nconst trustCaOnWindows = () => {\n\tconst caRoot = mkcertCaRoot();\n\tif (!caRoot) return false;\n\tconst rootCa = join(caRoot, 'rootCA.pem');\n\tif (!existsSync(rootCa)) return false;\n\n\tconst winTemp = windowsTempDir();\n\tif (!winTemp) return false;\n\n\tconst staged = join(winTemp, 'absolutejs-mkcert-rootCA.crt');\n\ttry {\n\t\tcopyFileSync(rootCa, staged);\n\t} catch {\n\t\treturn false;\n\t}\n\n\tconst stagedWin = toWindowsPath(staged);\n\tif (!stagedWin) {\n\t\trmSync(staged, { force: true });\n\n\t\treturn false;\n\t}\n\n\tconst result = Bun.spawnSync(\n\t\t[\n\t\t\t'powershell.exe',\n\t\t\t'-NoProfile',\n\t\t\t'-Command',\n\t\t\t`Import-Certificate -FilePath '${stagedWin}' -CertStoreLocation Cert:\\\\CurrentUser\\\\Root`\n\t\t],\n\t\t{ stderr: 'pipe', stdout: 'pipe' }\n\t);\n\trmSync(staged, { force: true });\n\n\treturn result.exitCode === 0;\n};\n\n// CLI command: install mkcert, set up CA, regenerate cert\nexport const setupMkcert = () => {\n\tif (!ensureMkcert()) return false;\n\n\t// Install the local CA (adds to system trust store)\n\tconst installResult = Bun.spawnSync(['mkcert', '-install'], {\n\t\tstderr: 'pipe',\n\t\tstdin: 'inherit',\n\t\tstdout: 'pipe'\n\t});\n\n\tif (installResult.exitCode !== 0) {\n\t\tdevWarn('Failed to install local CA');\n\n\t\treturn false;\n\t}\n\n\t// On WSL the Linux trust store the step above wrote to is invisible to the\n\t// Windows browser; mirror the CA into the Windows store so HTTPS is trusted.\n\tif (isWSL()) {\n\t\tif (trustCaOnWindows()) {\n\t\t\tdevLog(\n\t\t\t\t'Trusted the local CA in the Windows store — Chrome/Edge on Windows now accept dev HTTPS'\n\t\t\t);\n\t\t} else {\n\t\t\tconst caRoot = mkcertCaRoot();\n\t\t\tconst hint = caRoot\n\t\t\t\t? toWindowsPath(join(caRoot, 'rootCA.pem'))\n\t\t\t\t: null;\n\t\t\tdevWarn(\n\t\t\t\t'Could not auto-trust the local CA on Windows; Windows browsers may warn.'\n\t\t\t);\n\t\t\tif (hint) {\n\t\t\t\tconsole.log(\n\t\t\t\t\t` Run in PowerShell: Import-Certificate -FilePath \"${hint}\" -CertStoreLocation Cert:\\\\CurrentUser\\\\Root`\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove old cert to force regeneration with mkcert\n\trmSync(CERT_PATH, { force: true });\n\trmSync(KEY_PATH, { force: true });\n\n\t// Generate new trusted cert\n\tmkdirSync(CERT_DIR, { recursive: true });\n\tgenerateWithMkcert();\n\tconsole.log('');\n\tdevLog('mkcert installed — HTTPS certificates are now locally trusted');\n\n\treturn true;\n};\n",
164
164
  "import {\n\tmkdirSync,\n\treadFileSync,\n\treaddirSync,\n\tunlinkSync,\n\twriteFileSync\n} from 'node:fs';\nimport { homedir } from 'node:os';\nimport { basename, join } from 'node:path';\nimport type { InstanceRecord, InstanceSource } from '../../types/cli';\n\n// Each running `absolute dev` writes one `<pid>.json` here on boot and a\n// sibling `<pid>.log` for its tee'd output. Living under the user's home\n// (not the project's `.absolutejs/`) is what lets `absolute ps` aggregate\n// every dev server on the machine regardless of which project launched it.\nconst registeredPids = new Set<number>();\nlet exitHandlerRegistered = false;\n\nexport const instanceFilePath = (pid: number) =>\n\tjoin(instanceRegistryDir(), `${pid}.json`);\n\nexport const instanceLogPath = (pid: number) =>\n\tjoin(instanceRegistryDir(), `${pid}.log`);\n\nexport const instanceRegistryDir = () =>\n\tjoin(homedir(), '.absolutejs', 'instances');\n\nconst removeInstanceFilesSync = (pid: number) => {\n\ttry {\n\t\tunlinkSync(instanceFilePath(pid));\n\t} catch {\n\t\t/* already gone */\n\t}\n\ttry {\n\t\tunlinkSync(instanceLogPath(pid));\n\t} catch {\n\t\t/* already gone */\n\t}\n};\n\nconst registerExitHandlerOnce = () => {\n\tif (exitHandlerRegistered) return;\n\texitHandlerRegistered = true;\n\n\t// Safety net only: a graceful `absolute dev` shutdown calls\n\t// `deregisterInstance` itself. This catches hard exits so a crashed\n\t// process doesn't leave a phantom row — `listLiveInstances` also prunes\n\t// dead pids on read as a second line of defense.\n\tprocess.on('exit', () => {\n\t\tfor (const pid of registeredPids) {\n\t\t\tremoveInstanceFilesSync(pid);\n\t\t}\n\t\tregisteredPids.clear();\n\t});\n};\n\nconst isProcessAlive = (pid: number) => {\n\ttry {\n\t\t// Signal 0 is a no-op liveness probe.\n\t\tprocess.kill(pid, 0);\n\n\t\treturn true;\n\t} catch (error) {\n\t\tconst code =\n\t\t\terror instanceof Error && 'code' in error ? error.code : undefined;\n\t\tif (code === 'ESRCH') return false;\n\n\t\t// EPERM → alive but owned by another user; anything else → assume alive.\n\t\treturn true;\n\t}\n};\n\nconst readJsonFile = (path: string) => {\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, 'utf-8'));\n\t} catch {\n\t\treturn null;\n\t}\n};\n\nconst SOURCES: InstanceSource[] = [\n\t'compiled',\n\t'dev',\n\t'standalone',\n\t'start',\n\t'workspace'\n];\n\nconst toStringArray = (value: unknown) =>\n\tArray.isArray(value)\n\t\t? value.filter((item): item is string => typeof item === 'string')\n\t\t: [];\n\nconst coerceSource = (value: unknown) =>\n\tSOURCES.find((item) => item === value) ?? 'standalone';\n\nconst coerceRecord = (parsed: ReturnType<typeof readJsonFile>) => {\n\tif (typeof parsed !== 'object' || parsed === null) return null;\n\tif (typeof parsed.pid !== 'number') return null;\n\n\treturn {\n\t\tcommand: toStringArray(parsed.command),\n\t\tconfigPath:\n\t\t\ttypeof parsed.configPath === 'string' ? parsed.configPath : null,\n\t\tcontrollerPid:\n\t\t\ttypeof parsed.controllerPid === 'number'\n\t\t\t\t? parsed.controllerPid\n\t\t\t\t: parsed.pid,\n\t\tcwd: typeof parsed.cwd === 'string' ? parsed.cwd : '',\n\t\tframeworks: toStringArray(parsed.frameworks),\n\t\thost: typeof parsed.host === 'string' ? parsed.host : 'localhost',\n\t\thttps: parsed.https === true,\n\t\tlogFile: typeof parsed.logFile === 'string' ? parsed.logFile : null,\n\t\tname: typeof parsed.name === 'string' ? parsed.name : 'unknown',\n\t\tpid: parsed.pid,\n\t\tport: typeof parsed.port === 'number' ? parsed.port : null,\n\t\tppid: typeof parsed.ppid === 'number' ? parsed.ppid : 0,\n\t\tsource: coerceSource(parsed.source),\n\t\tstartedAt:\n\t\t\ttypeof parsed.startedAt === 'string'\n\t\t\t\t? parsed.startedAt\n\t\t\t\t: new Date().toISOString()\n\t} satisfies InstanceRecord;\n};\n\nconst readRecordFile = (path: string) => coerceRecord(readJsonFile(path));\n\nconst compareInstances = (left: InstanceRecord, right: InstanceRecord) => {\n\tconst leftPort = left.port ?? Number.MAX_SAFE_INTEGER;\n\tconst rightPort = right.port ?? Number.MAX_SAFE_INTEGER;\n\tif (leftPort !== rightPort) return leftPort - rightPort;\n\n\treturn left.name.localeCompare(right.name);\n};\n\nexport const deregisterInstance = (pid: number) => {\n\tregisteredPids.delete(pid);\n\tremoveInstanceFilesSync(pid);\n};\n\n/** Read every registered instance, pruning any whose process has died, and\n * return the survivors sorted by port then name. */\nexport const listLiveInstances = () => {\n\tconst directory = instanceRegistryDir();\n\tlet entries: string[];\n\ttry {\n\t\tentries = readdirSync(directory);\n\t} catch {\n\t\treturn [];\n\t}\n\n\tconst live = entries\n\t\t.filter((entry) => entry.endsWith('.json'))\n\t\t.map((entry) => readRecordFile(join(directory, entry)))\n\t\t.filter((record): record is InstanceRecord => record !== null)\n\t\t.filter((record) => {\n\t\t\tif (isProcessAlive(record.pid)) return true;\n\t\t\tremoveInstanceFilesSync(record.pid);\n\n\t\t\treturn false;\n\t\t});\n\n\treturn live.sort(compareInstances);\n};\n\nexport const registerInstance = (record: InstanceRecord) => {\n\tmkdirSync(instanceRegistryDir(), { recursive: true });\n\twriteFileSync(\n\t\tinstanceFilePath(record.pid),\n\t\tJSON.stringify(record, null, 2)\n\t);\n\tregisteredPids.add(record.pid);\n\tregisterExitHandlerOnce();\n\n\treturn record;\n};\n\n/** Read the project label without a config flag: package.json `name`, falling\n * back to the directory name. */\nexport const resolveProjectName = (cwd: string) => {\n\tconst parsed = readJsonFile(join(cwd, 'package.json'));\n\tif (\n\t\tparsed !== null &&\n\t\ttypeof parsed === 'object' &&\n\t\ttypeof parsed.name === 'string' &&\n\t\tparsed.name.trim().length > 0\n\t) {\n\t\treturn parsed.name;\n\t}\n\n\treturn basename(cwd) || 'unknown';\n};\n\nexport const updateInstance = (\n\tpid: number,\n\tupdates: Partial<InstanceRecord>\n) => {\n\tconst current = readRecordFile(instanceFilePath(pid));\n\tif (!current) return;\n\n\tconst next = { ...current, ...updates } satisfies InstanceRecord;\n\ttry {\n\t\twriteFileSync(instanceFilePath(pid), JSON.stringify(next, null, 2));\n\t} catch {\n\t\t/* best effort */\n\t}\n};\n",
165
165
  "import os from 'os';\n\n/* Get all network IP addresses (IPv4 only)\n This handles the \"detect all network interfaces\" problem */\nexport const getAllNetworkIPs = () => {\n\tconst interfaces = os.networkInterfaces();\n\tconst addresses = Object.values(interfaces)\n\t\t.flat()\n\t\t.filter(\n\t\t\t(iface): iface is os.NetworkInterfaceInfo => iface !== undefined\n\t\t);\n\n\t// Only collect IPv4 addresses\n\tconst ipv4Addresses: string[] = [];\n\n\taddresses\n\t\t.filter((addr) => !addr.internal && addr.family === 'IPv4')\n\t\t.forEach((addr) => ipv4Addresses.push(addr.address));\n\n\treturn ipv4Addresses;\n};\n\n/* Get the first network IP address (for backward compatibility)\n This maintains compatibility with existing code that expects a single IP */\nexport const getLocalIPAddress = () => {\n\tconst allIPs = getAllNetworkIPs();\n\n\tif (allIPs.length > 0 && allIPs[0]) {\n\t\treturn allIPs[0]; // Return first IPv4 address (or first available)\n\t}\n\n\tconsole.warn('No IP address found, falling back to localhost');\n\n\treturn 'localhost'; // Fallback to localhost if no IP found\n};\n",
@@ -0,0 +1 @@
1
+ export declare const runPsTui: () => Promise<void>;
@@ -0,0 +1 @@
1
+ export declare const runLs: (args: string[]) => Promise<void>;
@@ -0,0 +1 @@
1
+ export declare const runPs: (args: string[]) => Promise<void>;
package/package.json CHANGED
@@ -415,5 +415,5 @@
415
415
  ]
416
416
  }
417
417
  },
418
- "version": "0.19.0-beta.1029"
418
+ "version": "0.19.0-beta.1030"
419
419
  }
@@ -1 +0,0 @@
1
- export declare const runListTui: () => Promise<void>;
@@ -1 +0,0 @@
1
- export declare const runList: (args: string[]) => Promise<void>;