@absolutejs/absolute 0.19.0-beta.704 → 0.19.0-beta.706

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/angular/browser.js +6 -4
  2. package/dist/angular/browser.js.map +3 -3
  3. package/dist/angular/index.js +71 -82
  4. package/dist/angular/index.js.map +10 -10
  5. package/dist/angular/server.js +70 -81
  6. package/dist/angular/server.js.map +10 -10
  7. package/dist/build.js +152 -84
  8. package/dist/build.js.map +15 -15
  9. package/dist/cli/index.js +330 -296
  10. package/dist/client/index.js +7 -4
  11. package/dist/client/index.js.map +3 -3
  12. package/dist/index.js +253 -153
  13. package/dist/index.js.map +24 -24
  14. package/dist/islands/index.js +9 -6
  15. package/dist/islands/index.js.map +5 -5
  16. package/dist/react/browser.js +7 -7
  17. package/dist/react/browser.js.map +2 -2
  18. package/dist/react/components/browser/index.js +101 -101
  19. package/dist/react/components/index.js +104 -104
  20. package/dist/react/components/index.js.map +2 -2
  21. package/dist/react/index.js +77 -88
  22. package/dist/react/index.js.map +10 -10
  23. package/dist/react/jsxDevRuntimeCompat.js +1 -6
  24. package/dist/react/jsxDevRuntimeCompat.js.map +3 -3
  25. package/dist/react/server.js +57 -71
  26. package/dist/react/server.js.map +8 -8
  27. package/dist/src/angular/components/defer-slot-templates.directive.d.ts +0 -7
  28. package/dist/src/angular/components/defer-slot.component.d.ts +2 -5
  29. package/dist/src/angular/components/image.component.d.ts +2 -5
  30. package/dist/src/angular/components/index.d.ts +4 -4
  31. package/dist/src/angular/components/stream-slot.component.d.ts +0 -3
  32. package/dist/src/angular/pageHandler.d.ts +6 -1
  33. package/dist/src/angular/ssrRender.d.ts +1 -1
  34. package/dist/src/build/buildAngularVendor.d.ts +3 -4
  35. package/dist/src/constants.d.ts +21 -0
  36. package/dist/src/core/ssrCache.d.ts +1 -1
  37. package/dist/src/core/wrapPageHandlerWithStreamingSlots.d.ts +1 -1
  38. package/dist/src/react/jsxDevRuntimeCompat.d.ts +3 -6
  39. package/dist/src/react/pageHandler.d.ts +2 -1
  40. package/dist/src/svelte/pageHandler.d.ts +2 -2
  41. package/dist/src/utils/defineConfig.d.ts +2 -2
  42. package/dist/src/utils/imageProcessing.d.ts +1 -1
  43. package/dist/src/utils/loadConfig.d.ts +38 -2
  44. package/dist/src/vue/components/Image.d.ts +3 -3
  45. package/dist/src/vue/components/index.d.ts +1 -1
  46. package/dist/src/vue/index.d.ts +1 -1
  47. package/dist/src/vue/pageHandler.d.ts +2 -1
  48. package/dist/svelte/index.js +52 -58
  49. package/dist/svelte/index.js.map +10 -10
  50. package/dist/svelte/server.js +46 -55
  51. package/dist/svelte/server.js.map +9 -9
  52. package/dist/vue/components/Image.js +18 -18
  53. package/dist/vue/components/Image.js.map +3 -3
  54. package/dist/vue/components/index.js +77 -62
  55. package/dist/vue/components/index.js.map +5 -5
  56. package/dist/vue/index.js +137 -142
  57. package/dist/vue/index.js.map +13 -13
  58. package/dist/vue/server.js +54 -77
  59. package/dist/vue/server.js.map +8 -8
  60. package/package.json +42 -42
  61. package/dist/angular/components/constants.js +0 -56
  62. package/dist/angular/components/core/streamingSlotRegistrar.js +0 -58
  63. package/dist/angular/components/core/streamingSlotRegistry.js +0 -114
  64. package/dist/angular/components/defer-slot-payload.js +0 -6
  65. package/dist/angular/components/defer-slot-templates.directive.js +0 -44
  66. package/dist/angular/components/defer-slot.component.js +0 -149
  67. package/dist/angular/components/image.component.js +0 -202
  68. package/dist/angular/components/index.js +0 -4
  69. package/dist/angular/components/stream-slot.component.js +0 -103
  70. package/dist/dev/client/constants.ts +0 -26
  71. package/dist/dev/client/cssUtils.ts +0 -307
  72. package/dist/dev/client/domDiff.ts +0 -226
  73. package/dist/dev/client/domState.ts +0 -421
  74. package/dist/dev/client/domTracker.ts +0 -61
  75. package/dist/dev/client/errorOverlay.ts +0 -184
  76. package/dist/dev/client/frameworkDetect.ts +0 -63
  77. package/dist/dev/client/handlers/angular.ts +0 -551
  78. package/dist/dev/client/handlers/angularRuntime.ts +0 -206
  79. package/dist/dev/client/handlers/html.ts +0 -363
  80. package/dist/dev/client/handlers/htmx.ts +0 -272
  81. package/dist/dev/client/handlers/react.ts +0 -108
  82. package/dist/dev/client/handlers/rebuild.ts +0 -153
  83. package/dist/dev/client/handlers/svelte.ts +0 -332
  84. package/dist/dev/client/handlers/vue.ts +0 -292
  85. package/dist/dev/client/headPatch.ts +0 -233
  86. package/dist/dev/client/hmrClient.ts +0 -251
  87. package/dist/dev/client/hmrState.ts +0 -14
  88. package/dist/dev/client/moduleVersions.ts +0 -62
  89. package/dist/dev/client/reactRefreshSetup.ts +0 -33
  90. package/dist/src/angular/components/constants.d.ts +0 -53
  91. package/dist/svelte/components/AwaitSlot.svelte +0 -39
  92. package/dist/svelte/components/AwaitSlot.svelte.d.ts +0 -2
  93. package/dist/svelte/components/Head.svelte +0 -144
  94. package/dist/svelte/components/Head.svelte.d.ts +0 -2
  95. package/dist/svelte/components/Image.svelte +0 -164
  96. package/dist/svelte/components/Image.svelte.d.ts +0 -5
  97. package/dist/svelte/components/Island.svelte +0 -71
  98. package/dist/svelte/components/Island.svelte.d.ts +0 -5
  99. package/dist/svelte/components/JsonLd.svelte +0 -21
  100. package/dist/svelte/components/JsonLd.svelte.d.ts +0 -2
  101. package/dist/svelte/components/StreamSlot.svelte +0 -41
  102. package/dist/svelte/components/StreamSlot.svelte.d.ts +0 -2
  103. package/dist/types/globals.d.ts +0 -121
package/dist/cli/index.js CHANGED
@@ -18,7 +18,7 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
18
18
  var __require = import.meta.require;
19
19
 
20
20
  // src/constants.ts
21
- var ANSI_ESCAPE_LENGTH = 3, ASCII_SPACE = 32, BASE_36_RADIX = 36, BYTES_PER_KILOBYTE = 1024, CLI_ARGS_OFFSET = 3, DEFAULT_PORT = 3000, HOURS_IN_DAY = 24, HOURS_IN_HALF_DAY = 12, MAX_ERROR_LENGTH = 200, MILLISECONDS_IN_A_SECOND = 1000, MINUTES_IN_AN_HOUR = 60, SECONDS_IN_A_MINUTE = 60, MILLISECONDS_IN_A_MINUTE, MILLISECONDS_IN_A_DAY, SIGINT_EXIT_CODE = 130, SIGTERM_EXIT_CODE = 143, TIME_PRECISION = 2, TWO_THIRDS, UNFOUND_INDEX = -1;
21
+ var ANSI_ESCAPE_LENGTH = 3, ASCII_SPACE = 32, BASE_36_RADIX = 36, BYTES_PER_KILOBYTE = 1024, CLI_ARGS_OFFSET = 3, DEFAULT_PORT = 3000, HTTP_STATUS_OK = 200, HOURS_IN_DAY = 24, HOURS_IN_HALF_DAY = 12, MAX_ERROR_LENGTH = 200, MILLISECONDS_IN_A_SECOND = 1000, MINUTES_IN_AN_HOUR = 60, SECONDS_IN_A_MINUTE = 60, MILLISECONDS_IN_A_MINUTE, MILLISECONDS_IN_A_DAY, SIGINT_EXIT_CODE = 130, SIGTERM_EXIT_CODE = 143, TIME_PRECISION = 2, TWO_THIRDS, UNFOUND_INDEX = -1, WORKSPACE_COMMAND_ARGS_OFFSET = 3, WORKSPACE_FAILURE_LOG_PRINT_LIMIT = 30, WORKSPACE_FAILURE_RECENT_LOG_LIMIT = 60, WORKSPACE_READY_ATTEMPT_TIMEOUT_MS = 5000, WORKSPACE_READY_PROBE_INTERVAL_MS = 250, WORKSPACE_READY_TIMEOUT_MS = 30000, WORKSPACE_SHUTDOWN_TIMEOUT_MS = 1e4, WORKSPACE_TUI_DEFAULT_HEIGHT = 28, WORKSPACE_TUI_DEFAULT_WIDTH = 100, WORKSPACE_TUI_ESCAPE_SEQUENCE_TIMEOUT_MS = 30, WORKSPACE_TUI_FOOTER_LINE_COUNT = 3, WORKSPACE_TUI_MIN_LOG_HEIGHT = 3, WORKSPACE_TUI_MIN_SERVICE_NAME_WIDTH = 7, WORKSPACE_TUI_MIN_TARGET_WIDTH = 8, WORKSPACE_TUI_MIN_WRAP_WIDTH = 12, WORKSPACE_TUI_PROMPT_CURSOR_OFFSET = 3, WORKSPACE_TUI_RECENT_LOG_LIMIT = 40, WORKSPACE_TUI_RENDER_DEBOUNCE_MS = 16, WORKSPACE_TUI_STATUS_WIDTH = 10, WORKSPACE_TUI_TARGET_PADDING_WIDTH = 6, WORKSPACE_TUI_VISIBILITY_WIDTH = 8;
22
22
  var init_constants = __esm(() => {
23
23
  MILLISECONDS_IN_A_MINUTE = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
24
24
  MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR * HOURS_IN_DAY;
@@ -222,7 +222,7 @@ var RESERVED_TOP_LEVEL_KEYS, isObject = (value) => typeof value === "object" &&
222
222
  return false;
223
223
  }
224
224
  return entries.every(([, value]) => isServiceCandidate(value));
225
- }, getWorkspaceServices = (config) => {
225
+ }, isConfigInput = (value) => isObject(value), getWorkspaceServices = (config) => {
226
226
  if (!isWorkspaceConfig(config)) {
227
227
  throw new Error("absolute.config.ts is not a multi-service config. Define top-level named services with `entry` or `command` before using `absolute workspace dev`.");
228
228
  }
@@ -249,6 +249,16 @@ var RESERVED_TOP_LEVEL_KEYS, isObject = (value) => typeof value === "object" &&
249
249
  ...serviceConfig
250
250
  } = service;
251
251
  return serviceConfig;
252
+ }, loadConfig = async (configPath2) => {
253
+ const config = await loadRawConfig(configPath2);
254
+ const serviceName = process.env.ABSOLUTE_WORKSPACE_SERVICE_NAME;
255
+ if (typeof serviceName === "string" && serviceName.length > 0) {
256
+ return projectServiceConfig(config, serviceName);
257
+ }
258
+ if (isWorkspaceConfig(config)) {
259
+ throw new Error("absolute.config.ts defines multiple services. Use `absolute workspace dev` or set ABSOLUTE_WORKSPACE_SERVICE_NAME before loading a specific service config.");
260
+ }
261
+ return config;
252
262
  }, loadRawConfig = async (configPath2) => {
253
263
  const resolved = resolve(configPath2 ?? process.env.ABSOLUTE_CONFIG ?? "absolute.config.ts");
254
264
  const mod = await import(resolved);
@@ -257,20 +267,10 @@ var RESERVED_TOP_LEVEL_KEYS, isObject = (value) => typeof value === "object" &&
257
267
  throw new Error(`Config file "${resolved}" does not export a valid configuration.
258
268
  Expected: export default defineConfig({ ... })`);
259
269
  }
260
- if (!isObject(config)) {
270
+ if (!isConfigInput(config)) {
261
271
  throw new Error(`Config file "${resolved}" must export an object configuration.`);
262
272
  }
263
273
  return config;
264
- }, loadConfig = async (configPath2) => {
265
- const config = await loadRawConfig(configPath2);
266
- const serviceName = process.env.ABSOLUTE_WORKSPACE_SERVICE_NAME;
267
- if (typeof serviceName === "string" && serviceName.length > 0) {
268
- return projectServiceConfig(config, serviceName);
269
- }
270
- if (isWorkspaceConfig(config)) {
271
- throw new Error("absolute.config.ts defines multiple services. Use `absolute workspace dev` or set ABSOLUTE_WORKSPACE_SERVICE_NAME before loading a specific service config.");
272
- }
273
- return config;
274
274
  };
275
275
  var init_loadConfig = __esm(() => {
276
276
  RESERVED_TOP_LEVEL_KEYS = new Set([
@@ -734,16 +734,21 @@ var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_
734
734
  }, waitForServerReady = async (port) => {
735
735
  const deadline = performance.now() + getStartupTimeoutMs();
736
736
  while (performance.now() < deadline) {
737
- const res = await fetch(`http://localhost:${port}/`).catch(() => null);
738
- if (res) {
739
- await res.body?.cancel().catch(() => {
740
- return;
741
- });
737
+ if (await probePrerenderServer(port)) {
742
738
  return true;
743
739
  }
744
740
  await Bun.sleep(STARTUP_POLL_INTERVAL_MS);
745
741
  }
746
742
  return false;
743
+ }, probePrerenderServer = async (port) => {
744
+ const res = await fetch(`http://localhost:${port}/`).catch(() => null);
745
+ if (!res) {
746
+ return false;
747
+ }
748
+ await res.body?.cancel().catch(() => {
749
+ return;
750
+ });
751
+ return true;
747
752
  }, captureStreamOutput = (stream, output) => {
748
753
  if (!stream)
749
754
  return;
@@ -822,7 +827,7 @@ var cliTag3 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
822
827
  result.push(fullPath);
823
828
  }
824
829
  return result;
825
- }, readPackageVersion3 = (candidate) => {
830
+ }, readPackageVersion4 = (candidate) => {
826
831
  try {
827
832
  const pkg = JSON.parse(readFileSync9(candidate, "utf-8"));
828
833
  if (pkg.name !== "@absolutejs/absolute")
@@ -834,7 +839,7 @@ var cliTag3 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
834
839
  }
835
840
  }, resolvePackageVersion3 = (candidates) => {
836
841
  for (const candidate of candidates) {
837
- const version2 = readPackageVersion3(candidate);
842
+ const version2 = readPackageVersion4(candidate);
838
843
  if (version2)
839
844
  return version2;
840
845
  }
@@ -1348,15 +1353,11 @@ Found ${errorCount} error${suffix}.`;
1348
1353
  await mkdir2(cacheDir, { recursive: true });
1349
1354
  const checks = [];
1350
1355
  checks.push(hasVue ? buildVueTscCheck(cacheDir) : buildTscCheck(cacheDir));
1351
- if (hasSvelte) {
1352
- for (const svelteDir of svelteDirs) {
1353
- checks.push(buildSvelteCheck(cacheDir, svelteDir));
1354
- }
1356
+ for (const svelteDir of hasSvelte ? svelteDirs : []) {
1357
+ checks.push(buildSvelteCheck(cacheDir, svelteDir));
1355
1358
  }
1356
- if (hasAngular) {
1357
- for (const angularDir of angularDirs) {
1358
- checks.push(buildAngularCheck(cacheDir, angularDir));
1359
- }
1359
+ for (const angularDir of hasAngular ? angularDirs : []) {
1360
+ checks.push(buildAngularCheck(cacheDir, angularDir));
1360
1361
  }
1361
1362
  const results = await Promise.all(checks);
1362
1363
  const failed = results.filter((res) => res.exitCode !== 0);
@@ -1666,7 +1667,8 @@ init_telemetryEvent();
1666
1667
  init_loadConfig();
1667
1668
  init_utils();
1668
1669
  var cliTag = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`;
1669
- var confirmPrompt = (message, defaultYes = true) => new Promise((_resolve) => {
1670
+ var confirmPrompt = (message, defaultYes = true) => {
1671
+ const { promise, resolve: resolve4 } = Promise.withResolvers();
1670
1672
  let selected = defaultYes;
1671
1673
  const render = () => {
1672
1674
  const yes = selected ? "\x1B[36m\u25CF\x1B[0m Yes" : "\x1B[2m\u25CB Yes\x1B[0m";
@@ -1692,7 +1694,7 @@ var confirmPrompt = (message, defaultYes = true) => new Promise((_resolve) => {
1692
1694
  process.stdout.write(`\x1B[2K\x1B[32m\u25C7\x1B[0m ${message}
1693
1695
  \x1B[2K \x1B[2m${label}\x1B[0m
1694
1696
  \x1B[?25h`);
1695
- _resolve(selected);
1697
+ resolve4(selected);
1696
1698
  } else if (key === "\x03") {
1697
1699
  process.stdout.write("\x1B[?25h");
1698
1700
  process.stdin.setRawMode(false);
@@ -1700,7 +1702,8 @@ var confirmPrompt = (message, defaultYes = true) => new Promise((_resolve) => {
1700
1702
  }
1701
1703
  };
1702
1704
  process.stdin.on("data", onData);
1703
- });
1705
+ return promise;
1706
+ };
1704
1707
  var setupCertWithPrompt = async (ensureDevCert2, setupMkcert2) => {
1705
1708
  const install = await confirmPrompt("Install mkcert for trusted HTTPS? (no browser warning)");
1706
1709
  if (install) {
@@ -1926,15 +1929,20 @@ var dev = async (serverEntry, configPath2) => {
1926
1929
  return true;
1927
1930
  };
1928
1931
  const monitorServer = async () => {
1929
- while (!cleaning) {
1930
- const current = serverProcess;
1931
- const exitCode = await current.exited;
1932
- if (cleaning || serverProcess !== current)
1933
- continue;
1934
- const shouldContinue = await handleServerExit(exitCode);
1935
- if (!shouldContinue)
1936
- return;
1932
+ if (cleaning) {
1933
+ return;
1934
+ }
1935
+ const current = serverProcess;
1936
+ const exitCode = await current.exited;
1937
+ if (cleaning || serverProcess !== current) {
1938
+ await monitorServer();
1939
+ return;
1940
+ }
1941
+ const shouldContinue = await handleServerExit(exitCode);
1942
+ if (!shouldContinue) {
1943
+ return;
1937
1944
  }
1945
+ await monitorServer();
1938
1946
  };
1939
1947
  await monitorServer();
1940
1948
  };
@@ -1999,18 +2007,19 @@ var getAbsoluteVersion = () => {
1999
2007
  resolve4(import.meta.dir, "..", "..", "package.json"),
2000
2008
  resolve4(import.meta.dir, "..", "..", "..", "package.json")
2001
2009
  ];
2002
- for (const pkgPath of candidates) {
2003
- if (!existsSync6(pkgPath))
2004
- continue;
2005
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
2006
- const ver = pkg.version;
2007
- return ver;
2008
- }
2010
+ const pkgPath = candidates.find((candidate) => existsSync6(candidate));
2011
+ if (pkgPath)
2012
+ return readPackageVersion(pkgPath);
2009
2013
  } catch {
2010
2014
  return getPackageVersion("@absolutejs/absolute");
2011
2015
  }
2012
2016
  return getPackageVersion("@absolutejs/absolute");
2013
2017
  };
2018
+ var readPackageVersion = (pkgPath) => {
2019
+ const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
2020
+ const ver = pkg.version;
2021
+ return ver;
2022
+ };
2014
2023
  var detectCI = () => {
2015
2024
  const { env: env2 } = process;
2016
2025
  if (env2.GITHUB_ACTIONS)
@@ -2258,14 +2267,14 @@ import { basename, resolve as resolve5 } from "path";
2258
2267
  var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`;
2259
2268
  var resolvePackageVersion = (candidates) => {
2260
2269
  for (const candidate of candidates) {
2261
- const version2 = readPackageVersion(candidate);
2270
+ const version2 = readPackageVersion2(candidate);
2262
2271
  if (version2) {
2263
2272
  return version2;
2264
2273
  }
2265
2274
  }
2266
2275
  return "";
2267
2276
  };
2268
- var readPackageVersion = (candidate) => {
2277
+ var readPackageVersion2 = (candidate) => {
2269
2278
  try {
2270
2279
  const pkg = JSON.parse(readFileSync7(candidate, "utf-8"));
2271
2280
  if (pkg.name !== "@absolutejs/absolute")
@@ -2659,54 +2668,49 @@ var appendRightEdge = (value, width, marker) => {
2659
2668
  }
2660
2669
  return `${padLine(value, Math.max(0, width - 1))}${marker}`;
2661
2670
  };
2671
+ var splitLongWord = (word, width) => {
2672
+ const parts = [];
2673
+ for (let index = 0;index < word.length; index += width) {
2674
+ parts.push(word.slice(index, index + width));
2675
+ }
2676
+ return parts;
2677
+ };
2678
+ var appendWrappedWord = (lines, current, word, width) => {
2679
+ if (current.length === 0) {
2680
+ if (word.length <= width)
2681
+ return word;
2682
+ lines.push(...splitLongWord(word, width));
2683
+ return "";
2684
+ }
2685
+ const next = `${current} ${word}`;
2686
+ if (next.length <= width)
2687
+ return next;
2688
+ lines.push(current);
2689
+ if (word.length <= width)
2690
+ return word;
2691
+ lines.push(...splitLongWord(word, width));
2692
+ return "";
2693
+ };
2694
+ var wrapLine = (line, width) => {
2695
+ if (line.length === 0)
2696
+ return [""];
2697
+ if (line.length <= width)
2698
+ return [line];
2699
+ const lines = [];
2700
+ let current = "";
2701
+ for (const word of line.split(/\s+/)) {
2702
+ current = appendWrappedWord(lines, current, word, width);
2703
+ }
2704
+ if (current.length > 0)
2705
+ lines.push(current);
2706
+ return lines;
2707
+ };
2662
2708
  var wrapText = (value, width) => {
2663
2709
  if (width <= 0) {
2664
2710
  return [""];
2665
2711
  }
2666
- const lines = [];
2667
- for (const rawLine of value.split(`
2668
- `)) {
2669
- const line = rawLine.trimEnd();
2670
- if (line.length === 0) {
2671
- lines.push("");
2672
- continue;
2673
- }
2674
- if (line.length <= width) {
2675
- lines.push(line);
2676
- continue;
2677
- }
2678
- const words = line.split(/\s+/);
2679
- let current = "";
2680
- for (const word of words) {
2681
- if (current.length === 0) {
2682
- if (word.length <= width) {
2683
- current = word;
2684
- continue;
2685
- }
2686
- for (let index = 0;index < word.length; index += width) {
2687
- lines.push(word.slice(index, index + width));
2688
- }
2689
- continue;
2690
- }
2691
- const next = `${current} ${word}`;
2692
- if (next.length <= width) {
2693
- current = next;
2694
- continue;
2695
- }
2696
- lines.push(current);
2697
- if (word.length <= width) {
2698
- current = word;
2699
- continue;
2700
- }
2701
- for (let index = 0;index < word.length; index += width) {
2702
- lines.push(word.slice(index, index + width));
2703
- }
2704
- current = "";
2705
- }
2706
- if (current.length > 0) {
2707
- lines.push(current);
2708
- }
2709
- }
2712
+ const lines = value.split(`
2713
+ `).flatMap((rawLine) => wrapLine(rawLine.trimEnd(), width));
2710
2714
  return lines.length > 0 ? lines : [""];
2711
2715
  };
2712
2716
  var formatTimestamp2 = () => new Date().toLocaleTimeString([], {
@@ -2811,7 +2815,7 @@ var createWorkspaceTui = ({
2811
2815
  renderTimer = setTimeout(() => {
2812
2816
  renderTimer = null;
2813
2817
  render();
2814
- }, 16);
2818
+ }, WORKSPACE_TUI_RENDER_DEBOUNCE_MS);
2815
2819
  };
2816
2820
  const clearPendingEscape = () => {
2817
2821
  if (!escapeTimer) {
@@ -2826,7 +2830,7 @@ var createWorkspaceTui = ({
2826
2830
  escapeTimer = null;
2827
2831
  escapeBuffer = "";
2828
2832
  exitEscapeMode();
2829
- }, 30);
2833
+ }, WORKSPACE_TUI_ESCAPE_SEQUENCE_TIMEOUT_MS);
2830
2834
  };
2831
2835
  const resetPrompt = () => {
2832
2836
  promptBuffer = "";
@@ -2848,16 +2852,16 @@ var createWorkspaceTui = ({
2848
2852
  if (disposed) {
2849
2853
  return;
2850
2854
  }
2851
- const width = process.stdout.columns ?? 100;
2852
- const height = process.stdout.rows ?? 28;
2855
+ const width = process.stdout.columns ?? WORKSPACE_TUI_DEFAULT_WIDTH;
2856
+ const height = process.stdout.rows ?? WORKSPACE_TUI_DEFAULT_HEIGHT;
2853
2857
  const servicesSnapshot = [...serviceStates.values()];
2854
2858
  const workspaceStatus = getWorkspaceStatus(servicesSnapshot);
2855
2859
  const statusLabel = workspaceStatus === "ready" && readyDurationMs !== null ? `${colors.dim}ready in${colors.reset} ${colors.bold}${getDurationString(readyDurationMs)}${colors.reset}` : `${colors.dim}${workspaceStatus}${colors.reset}`;
2856
2860
  const title = `${colors.cyan}${colors.bold}ABSOLUTEJS WORKSPACE${colors.reset} ${colors.dim}v${version2}${colors.reset} ${statusLabel}`;
2857
2861
  const divider = `${colors.dim}${"\u2500".repeat(Math.max(width, 1))}${colors.reset}`;
2858
- const serviceNameWidth = Math.max(7, ...servicesSnapshot.map((service) => service.name.length));
2859
- const visibilityWidth = 8;
2860
- const statusWidth = 10;
2862
+ const serviceNameWidth = Math.max(WORKSPACE_TUI_MIN_SERVICE_NAME_WIDTH, ...servicesSnapshot.map((service) => service.name.length));
2863
+ const visibilityWidth = WORKSPACE_TUI_VISIBILITY_WIDTH;
2864
+ const statusWidth = WORKSPACE_TUI_STATUS_WIDTH;
2861
2865
  const rows = [];
2862
2866
  rows.push(padLine(title, width));
2863
2867
  rows.push(divider);
@@ -2865,21 +2869,21 @@ var createWorkspaceTui = ({
2865
2869
  for (const service of servicesSnapshot) {
2866
2870
  const stateColor = getStatusColor(service.status);
2867
2871
  const detail = service.detail ? ` \xB7 ${service.detail}` : "";
2868
- const targetWidth = Math.max(width - serviceNameWidth - visibilityWidth - statusWidth - 6, 8);
2872
+ const targetWidth = Math.max(width - serviceNameWidth - visibilityWidth - statusWidth - WORKSPACE_TUI_TARGET_PADDING_WIDTH, WORKSPACE_TUI_MIN_TARGET_WIDTH);
2869
2873
  const target = truncateText(`${getTargetLabel(service)}${detail}`, targetWidth);
2870
2874
  const targetColor = service.visibility === "public" && service.status !== "ready" ? colors.dim : colors.reset;
2871
2875
  const row = `${colors.bold}${service.name.padEnd(serviceNameWidth)}${colors.reset} ${colors.dim}${service.visibility.padEnd(visibilityWidth)}${colors.reset} ${stateColor}${service.status.padEnd(statusWidth)}${colors.reset} ${targetColor}${target}${colors.reset}`;
2872
2876
  rows.push(padLine(row, width));
2873
2877
  }
2874
2878
  rows.push(divider);
2875
- const footerLines = 3;
2879
+ const footerLines = WORKSPACE_TUI_FOOTER_LINE_COUNT;
2876
2880
  const fixedHeight = rows.length + footerLines;
2877
- const logHeight = Math.max(height - fixedHeight, 3);
2881
+ const logHeight = Math.max(height - fixedHeight, WORKSPACE_TUI_MIN_LOG_HEIGHT);
2878
2882
  const logWidth = Math.max(width - 1, 1);
2879
2883
  const contentLines = helpVisible ? helpLines : logEntries.flatMap((entry) => {
2880
2884
  const prefixPlain = `${entry.timestamp} [${entry.source}] `;
2881
2885
  const prefixColor = `${colors.dim}${entry.timestamp}${colors.reset} ${getSourceColor(entry.source)}[${entry.source}]${colors.reset} `;
2882
- const wrapped = wrapText(entry.message, Math.max(logWidth - prefixPlain.length, 12));
2886
+ const wrapped = wrapText(entry.message, Math.max(logWidth - prefixPlain.length, WORKSPACE_TUI_MIN_WRAP_WIDTH));
2883
2887
  return wrapped.map((line, index) => {
2884
2888
  if (index === 0) {
2885
2889
  return `${prefixColor}${getLogColor(entry.level)}${line}${colors.reset}`;
@@ -2927,7 +2931,7 @@ var createWorkspaceTui = ({
2927
2931
  `);
2928
2932
  process.stdout.write(`\x1B[H${screen}`);
2929
2933
  if (shellMode) {
2930
- const promptColumn = Math.min(promptBuffer.length + 3, width);
2934
+ const promptColumn = Math.min(promptBuffer.length + WORKSPACE_TUI_PROMPT_CURSOR_OFFSET, width);
2931
2935
  const promptRow = Math.min(rows.length, height);
2932
2936
  process.stdout.write(`\x1B[${promptRow};${promptColumn}H\x1B[?25h`);
2933
2937
  return;
@@ -2971,7 +2975,7 @@ var createWorkspaceTui = ({
2971
2975
  logScrollOffset = 0;
2972
2976
  scheduleRender();
2973
2977
  };
2974
- const getRecentLogs = (limit = 40) => logEntries.slice(Math.max(0, logEntries.length - limit));
2978
+ const getRecentLogs = (limit = WORKSPACE_TUI_RECENT_LOG_LIMIT) => logEntries.slice(Math.max(0, logEntries.length - limit));
2975
2979
  const getServiceSnapshot = () => [...serviceStates.values()].map((service) => ({
2976
2980
  detail: service.detail,
2977
2981
  name: service.name,
@@ -2983,21 +2987,35 @@ var createWorkspaceTui = ({
2983
2987
  if (!shellMode || shellHistory.length === 0) {
2984
2988
  return;
2985
2989
  }
2986
- if (direction === "up") {
2987
- if (shellHistoryIndex < shellHistory.length - 1) {
2988
- shellHistoryIndex++;
2989
- }
2990
- } else if (shellHistoryIndex <= 0) {
2990
+ if (direction === "up" && shellHistoryIndex < shellHistory.length - 1) {
2991
+ shellHistoryIndex++;
2992
+ }
2993
+ if (direction === "down" && shellHistoryIndex <= 0) {
2991
2994
  shellHistoryIndex = UNFOUND_INDEX;
2992
2995
  promptBuffer = "";
2993
2996
  scheduleRender();
2994
2997
  return;
2995
- } else {
2998
+ }
2999
+ if (direction === "down") {
2996
3000
  shellHistoryIndex--;
2997
3001
  }
2998
3002
  promptBuffer = shellHistoryIndex === UNFOUND_INDEX ? "" : shellHistory[shellHistory.length - 1 - shellHistoryIndex] ?? "";
2999
3003
  scheduleRender();
3000
3004
  };
3005
+ const handleArrowEscape = (direction) => {
3006
+ clearPendingEscape();
3007
+ escapeBuffer = "";
3008
+ if (shellMode) {
3009
+ navigateShellHistory(direction);
3010
+ return;
3011
+ }
3012
+ scrollLogs(direction);
3013
+ };
3014
+ const handleScrollEscape = (mode) => {
3015
+ clearPendingEscape();
3016
+ escapeBuffer = "";
3017
+ scrollLogs(mode);
3018
+ };
3001
3019
  const scrollLogs = (direction) => {
3002
3020
  if (helpVisible) {
3003
3021
  return;
@@ -3052,47 +3070,27 @@ var createWorkspaceTui = ({
3052
3070
  return;
3053
3071
  }
3054
3072
  if (escapeBuffer === `${ESCAPE}[A`) {
3055
- clearPendingEscape();
3056
- escapeBuffer = "";
3057
- if (shellMode) {
3058
- navigateShellHistory("up");
3059
- } else {
3060
- scrollLogs("up");
3061
- }
3073
+ handleArrowEscape("up");
3062
3074
  return;
3063
3075
  }
3064
3076
  if (escapeBuffer === `${ESCAPE}[B`) {
3065
- clearPendingEscape();
3066
- escapeBuffer = "";
3067
- if (shellMode) {
3068
- navigateShellHistory("down");
3069
- } else {
3070
- scrollLogs("down");
3071
- }
3077
+ handleArrowEscape("down");
3072
3078
  return;
3073
3079
  }
3074
3080
  if (escapeBuffer === `${ESCAPE}[5~`) {
3075
- clearPendingEscape();
3076
- escapeBuffer = "";
3077
- scrollLogs("pageUp");
3081
+ handleScrollEscape("pageUp");
3078
3082
  return;
3079
3083
  }
3080
3084
  if (escapeBuffer === `${ESCAPE}[6~`) {
3081
- clearPendingEscape();
3082
- escapeBuffer = "";
3083
- scrollLogs("pageDown");
3085
+ handleScrollEscape("pageDown");
3084
3086
  return;
3085
3087
  }
3086
3088
  if (escapeBuffer === `${ESCAPE}[H` || escapeBuffer === `${ESCAPE}[1~`) {
3087
- clearPendingEscape();
3088
- escapeBuffer = "";
3089
- scrollLogs("home");
3089
+ handleScrollEscape("home");
3090
3090
  return;
3091
3091
  }
3092
3092
  if (escapeBuffer === `${ESCAPE}[F` || escapeBuffer === `${ESCAPE}[4~`) {
3093
- clearPendingEscape();
3094
- escapeBuffer = "";
3095
- scrollLogs("end");
3093
+ handleScrollEscape("end");
3096
3094
  return;
3097
3095
  }
3098
3096
  if (/^\x1b\[[0-9]*$/.test(escapeBuffer)) {
@@ -3101,6 +3099,40 @@ var createWorkspaceTui = ({
3101
3099
  }
3102
3100
  exitEscapeMode();
3103
3101
  };
3102
+ const handleBackspace = () => {
3103
+ if (!shellMode) {
3104
+ return;
3105
+ }
3106
+ if (promptBuffer.length > 0) {
3107
+ promptBuffer = promptBuffer.slice(0, UNFOUND_INDEX);
3108
+ scheduleRender();
3109
+ return;
3110
+ }
3111
+ resetPrompt();
3112
+ };
3113
+ const handleEnter = async () => {
3114
+ if (!shellMode) {
3115
+ return;
3116
+ }
3117
+ await submitShellCommand();
3118
+ };
3119
+ const handlePrintableChar = async (char) => {
3120
+ if (shellMode) {
3121
+ promptBuffer += char;
3122
+ scheduleRender();
3123
+ return;
3124
+ }
3125
+ if (char === "$") {
3126
+ shellMode = true;
3127
+ promptBuffer = "";
3128
+ scheduleRender();
3129
+ return;
3130
+ }
3131
+ const shortcut = SHORTCUTS2.get(char.toLowerCase());
3132
+ if (shortcut) {
3133
+ await runShortcut(shortcut);
3134
+ }
3135
+ };
3104
3136
  const handleChar = async (char) => {
3105
3137
  if (char === "\x03") {
3106
3138
  await actions.quit();
@@ -3116,42 +3148,18 @@ var createWorkspaceTui = ({
3116
3148
  return;
3117
3149
  }
3118
3150
  if (char === "\x7F" || char === "\b") {
3119
- if (!shellMode) {
3120
- return;
3121
- }
3122
- if (promptBuffer.length > 0) {
3123
- promptBuffer = promptBuffer.slice(0, UNFOUND_INDEX);
3124
- scheduleRender();
3125
- return;
3126
- }
3127
- resetPrompt();
3151
+ handleBackspace();
3128
3152
  return;
3129
3153
  }
3130
3154
  if (char === "\r" || char === `
3131
3155
  `) {
3132
- if (shellMode) {
3133
- await submitShellCommand();
3134
- }
3156
+ await handleEnter();
3135
3157
  return;
3136
3158
  }
3137
3159
  if (char.charCodeAt(0) < ASCII_SPACE) {
3138
3160
  return;
3139
3161
  }
3140
- if (!shellMode) {
3141
- if (char === "$") {
3142
- shellMode = true;
3143
- promptBuffer = "";
3144
- scheduleRender();
3145
- return;
3146
- }
3147
- const shortcut = SHORTCUTS2.get(char.toLowerCase());
3148
- if (shortcut) {
3149
- await runShortcut(shortcut);
3150
- }
3151
- return;
3152
- }
3153
- promptBuffer += char;
3154
- scheduleRender();
3162
+ await handlePrintableChar(char);
3155
3163
  };
3156
3164
  const onResize = () => {
3157
3165
  scheduleRender();
@@ -3176,6 +3184,16 @@ var createWorkspaceTui = ({
3176
3184
  process.stdout.on("resize", onResize);
3177
3185
  render();
3178
3186
  };
3187
+ const disposeInput = () => {
3188
+ if (!input) {
3189
+ return;
3190
+ }
3191
+ input.off("data", onData);
3192
+ setRawMode(false);
3193
+ if (input !== process.stdin) {
3194
+ input.destroy();
3195
+ }
3196
+ };
3179
3197
  const dispose = () => {
3180
3198
  if (disposed) {
3181
3199
  return;
@@ -3187,13 +3205,7 @@ var createWorkspaceTui = ({
3187
3205
  renderTimer = null;
3188
3206
  }
3189
3207
  process.stdout.off("resize", onResize);
3190
- if (input) {
3191
- input.off("data", onData);
3192
- setRawMode(false);
3193
- if (input !== process.stdin) {
3194
- input.destroy();
3195
- }
3196
- }
3208
+ disposeInput();
3197
3209
  process.stdout.write("\x1B[?25h\x1B[?1049l");
3198
3210
  };
3199
3211
  return {
@@ -3217,11 +3229,7 @@ var sanitizeLogFileName = (value) => value.replace(/[^a-zA-Z0-9._-]/g, "_") || "
3217
3229
  var createWorkspaceLogSink = (appendLog) => {
3218
3230
  const logDirectory = resolve6(".absolutejs", "workspace", "logs");
3219
3231
  mkdirSync4(logDirectory, { recursive: true });
3220
- for (const file of readdirSync(logDirectory)) {
3221
- if (file.endsWith(".log")) {
3222
- unlinkSync(resolve6(logDirectory, file));
3223
- }
3224
- }
3232
+ readdirSync(logDirectory).filter((file) => file.endsWith(".log")).forEach((file) => unlinkSync(resolve6(logDirectory, file)));
3225
3233
  writeFileSync2(resolve6(logDirectory, "all.log"), "");
3226
3234
  writeFileSync2(resolve6(logDirectory, "workspace.log"), "");
3227
3235
  const initializedSources = new Set(["workspace"]);
@@ -3249,13 +3257,13 @@ var createWorkspaceLogSink = (appendLog) => {
3249
3257
  }
3250
3258
  };
3251
3259
  };
3252
- var readPackageVersion2 = (candidate) => {
3260
+ var readPackageVersion3 = (candidate) => {
3253
3261
  try {
3254
3262
  const pkg = JSON.parse(readFileSync8(candidate, "utf-8"));
3255
3263
  if (pkg.name !== "@absolutejs/absolute") {
3256
3264
  return null;
3257
3265
  }
3258
- const version2 = pkg.version;
3266
+ const { version: version2 } = pkg;
3259
3267
  return version2;
3260
3268
  } catch {
3261
3269
  return null;
@@ -3268,7 +3276,7 @@ var resolvePackageVersion2 = () => {
3268
3276
  resolve6(import.meta.dir, "..", "..", "..", "..", "package.json")
3269
3277
  ];
3270
3278
  for (const candidate of candidates) {
3271
- const version2 = readPackageVersion2(candidate);
3279
+ const version2 = readPackageVersion3(candidate);
3272
3280
  if (version2) {
3273
3281
  return version2;
3274
3282
  }
@@ -3290,7 +3298,7 @@ var getDefaultReadyConfig = (service) => {
3290
3298
  }
3291
3299
  return;
3292
3300
  };
3293
- var normalizeExpectedStatuses = (value) => Array.isArray(value) ? value : [value ?? 200];
3301
+ var normalizeExpectedStatuses = (value) => Array.isArray(value) ? value : [value ?? HTTP_STATUS_OK];
3294
3302
  var resolveServiceHttpUrl = (service, path) => {
3295
3303
  if (!path.startsWith("/")) {
3296
3304
  throw new Error(`ready path must start with "/" for service probes. Received "${path}".`);
@@ -3307,20 +3315,20 @@ var resolveHttpReadyProbe = (service, ready) => {
3307
3315
  type: "http",
3308
3316
  url: resolveServiceHttpUrl(service, ready),
3309
3317
  method: "GET",
3310
- expectStatus: [200],
3318
+ expectStatus: [HTTP_STATUS_OK],
3311
3319
  headers: {},
3312
- intervalMs: 250,
3313
- timeoutMs: 30000
3320
+ intervalMs: WORKSPACE_READY_PROBE_INTERVAL_MS,
3321
+ timeoutMs: WORKSPACE_READY_TIMEOUT_MS
3314
3322
  };
3315
3323
  }
3316
3324
  return {
3317
- type: "http",
3318
- url: ready,
3319
- method: "GET",
3320
- expectStatus: [200],
3325
+ expectStatus: [HTTP_STATUS_OK],
3321
3326
  headers: {},
3322
- intervalMs: 250,
3323
- timeoutMs: 30000
3327
+ intervalMs: WORKSPACE_READY_PROBE_INTERVAL_MS,
3328
+ method: "GET",
3329
+ timeoutMs: WORKSPACE_READY_TIMEOUT_MS,
3330
+ type: "http",
3331
+ url: ready
3324
3332
  };
3325
3333
  }
3326
3334
  if (ready.path && ready.url) {
@@ -3336,8 +3344,8 @@ var resolveHttpReadyProbe = (service, ready) => {
3336
3344
  method: ready.method ?? "GET",
3337
3345
  expectStatus: normalizeExpectedStatuses(ready.expectStatus),
3338
3346
  headers: ready.headers ?? {},
3339
- intervalMs: ready.intervalMs ?? 250,
3340
- timeoutMs: ready.timeoutMs ?? 30000
3347
+ intervalMs: ready.intervalMs ?? WORKSPACE_READY_PROBE_INTERVAL_MS,
3348
+ timeoutMs: ready.timeoutMs ?? WORKSPACE_READY_TIMEOUT_MS
3341
3349
  };
3342
3350
  };
3343
3351
  var resolveReadyProbe = (service, ready = service.ready ?? getDefaultReadyConfig(service)) => {
@@ -3352,22 +3360,22 @@ var resolveReadyProbe = (service, ready = service.ready ?? getDefaultReadyConfig
3352
3360
  type: "tcp",
3353
3361
  host: ready.host ?? getServicePublicHost(service),
3354
3362
  port: ready.port,
3355
- intervalMs: ready.intervalMs ?? 250,
3356
- timeoutMs: ready.timeoutMs ?? 30000
3363
+ intervalMs: ready.intervalMs ?? WORKSPACE_READY_PROBE_INTERVAL_MS,
3364
+ timeoutMs: ready.timeoutMs ?? WORKSPACE_READY_TIMEOUT_MS
3357
3365
  };
3358
3366
  }
3359
3367
  if (ready.type === "command") {
3360
3368
  return {
3361
- type: "command",
3362
3369
  command: ready.command,
3363
- intervalMs: ready.intervalMs ?? 250,
3364
- timeoutMs: ready.timeoutMs ?? 30000
3370
+ intervalMs: ready.intervalMs ?? WORKSPACE_READY_PROBE_INTERVAL_MS,
3371
+ timeoutMs: ready.timeoutMs ?? WORKSPACE_READY_TIMEOUT_MS,
3372
+ type: "command"
3365
3373
  };
3366
3374
  }
3367
3375
  if (ready.type === "delay") {
3368
3376
  return {
3369
- type: "delay",
3370
- ms: ready.ms
3377
+ ms: ready.ms,
3378
+ type: "delay"
3371
3379
  };
3372
3380
  }
3373
3381
  return resolveHttpReadyProbe(service, ready);
@@ -3376,7 +3384,7 @@ var probeHttpReady = async (ready) => {
3376
3384
  const response = await fetch(ready.url, {
3377
3385
  method: ready.method,
3378
3386
  headers: ready.headers,
3379
- signal: AbortSignal.timeout(Math.min(ready.timeoutMs, 5000))
3387
+ signal: AbortSignal.timeout(Math.min(ready.timeoutMs, WORKSPACE_READY_ATTEMPT_TIMEOUT_MS))
3380
3388
  });
3381
3389
  return ready.expectStatus.includes(response.status);
3382
3390
  };
@@ -3388,7 +3396,7 @@ var probeTcpReady = async (ready) => new Promise((resolveProbe) => {
3388
3396
  const timeout = setTimeout(() => {
3389
3397
  socket.destroy();
3390
3398
  resolveProbe(false);
3391
- }, Math.min(ready.timeoutMs, 5000));
3399
+ }, Math.min(ready.timeoutMs, WORKSPACE_READY_ATTEMPT_TIMEOUT_MS));
3392
3400
  socket.once("connect", () => {
3393
3401
  clearTimeout(timeout);
3394
3402
  socket.end();
@@ -3412,7 +3420,7 @@ var probeCommandReady = async (ready, service) => {
3412
3420
  try {
3413
3421
  processHandle.kill();
3414
3422
  } catch {}
3415
- }, Math.min(ready.timeoutMs, 5000));
3423
+ }, Math.min(ready.timeoutMs, WORKSPACE_READY_ATTEMPT_TIMEOUT_MS));
3416
3424
  try {
3417
3425
  const exitCode = await processHandle.exited;
3418
3426
  return exitCode === 0;
@@ -3431,16 +3439,24 @@ var waitForReady = async (service) => {
3431
3439
  }
3432
3440
  const startedAt = Date.now();
3433
3441
  while (Date.now() - startedAt < resolved.timeoutMs) {
3434
- try {
3435
- const isReady = resolved.type === "http" ? await probeHttpReady(resolved) : resolved.type === "tcp" ? await probeTcpReady(resolved) : await probeCommandReady(resolved, service);
3436
- if (isReady) {
3437
- return;
3438
- }
3439
- } catch {}
3442
+ if (await probeReady(resolved, service)) {
3443
+ return;
3444
+ }
3440
3445
  await sleep(resolved.intervalMs);
3441
3446
  }
3442
3447
  throw new Error(resolved.type === "http" ? `service did not become ready within ${resolved.timeoutMs}ms (${resolved.url})` : resolved.type === "tcp" ? `service did not become ready within ${resolved.timeoutMs}ms (tcp://${resolved.host}:${resolved.port})` : `service did not become ready within ${resolved.timeoutMs}ms (${resolved.command.join(" ")})`);
3443
3448
  };
3449
+ var probeReady = async (resolved, service) => {
3450
+ try {
3451
+ if (resolved.type === "http")
3452
+ return probeHttpReady(resolved);
3453
+ if (resolved.type === "tcp")
3454
+ return probeTcpReady(resolved);
3455
+ return probeCommandReady(resolved, service);
3456
+ } catch {
3457
+ return false;
3458
+ }
3459
+ };
3444
3460
  var resolveShutdownHook = (shutdown) => {
3445
3461
  if (!shutdown) {
3446
3462
  return null;
@@ -3448,12 +3464,12 @@ var resolveShutdownHook = (shutdown) => {
3448
3464
  if (Array.isArray(shutdown)) {
3449
3465
  return {
3450
3466
  command: shutdown,
3451
- timeoutMs: 1e4
3467
+ timeoutMs: WORKSPACE_SHUTDOWN_TIMEOUT_MS
3452
3468
  };
3453
3469
  }
3454
3470
  return {
3455
3471
  command: shutdown.command,
3456
- timeoutMs: shutdown.timeoutMs ?? 1e4
3472
+ timeoutMs: shutdown.timeoutMs ?? WORKSPACE_SHUTDOWN_TIMEOUT_MS
3457
3473
  };
3458
3474
  };
3459
3475
  var runShutdownHook = async (service, onLog) => {
@@ -3477,11 +3493,7 @@ var runShutdownHook = async (service, onLog) => {
3477
3493
  }, hook.timeoutMs);
3478
3494
  try {
3479
3495
  const exitCode = await processHandle.exited;
3480
- if (exitCode === 0) {
3481
- onLog("workspace", `${service.name} shutdown hook finished.`, "success");
3482
- return;
3483
- }
3484
- onLog("workspace", `${service.name} shutdown hook exited with code ${exitCode || 1}.`, "warn");
3496
+ onLog("workspace", exitCode === 0 ? `${service.name} shutdown hook finished.` : `${service.name} shutdown hook exited with code ${exitCode || 1}.`, exitCode === 0 ? "success" : "warn");
3485
3497
  } finally {
3486
3498
  clearTimeout(timeout);
3487
3499
  }
@@ -3521,36 +3533,38 @@ var pipeProcessLogs = (name, processHandle, appendLog) => {
3521
3533
  const forward = async (stream, level) => {
3522
3534
  let buffer = "";
3523
3535
  const reader = stream.getReader();
3524
- try {
3525
- while (true) {
3526
- const { done, value } = await reader.read();
3527
- if (done) {
3528
- break;
3529
- }
3530
- if (!value) {
3531
- continue;
3532
- }
3533
- buffer += Buffer.from(value).toString();
3534
- const lines = buffer.split(`
3535
- `);
3536
- buffer = lines.pop() ?? "";
3537
- for (const line of lines) {
3538
- if (line.trim().length === 0) {
3539
- continue;
3540
- }
3541
- appendLog(name, line, level);
3542
- }
3543
- }
3544
- } finally {
3545
- if (buffer.trim().length > 0) {
3546
- appendLog(name, buffer, level);
3547
- }
3548
- reader.releaseLock();
3536
+ let chunk = await readLogChunk(reader);
3537
+ while (chunk !== null) {
3538
+ buffer = appendLogChunk(buffer, chunk, name, level, appendLog);
3539
+ chunk = await readLogChunk(reader);
3549
3540
  }
3541
+ appendRemainingLogBuffer(buffer, name, level, appendLog);
3542
+ reader.releaseLock();
3550
3543
  };
3551
3544
  forward(processHandle.stdout, "info");
3552
3545
  forward(processHandle.stderr, "error");
3553
3546
  };
3547
+ var readLogChunk = async (reader) => {
3548
+ const { done, value } = await reader.read();
3549
+ if (done)
3550
+ return null;
3551
+ if (!value)
3552
+ return "";
3553
+ return Buffer.from(value).toString();
3554
+ };
3555
+ var appendLogChunk = (buffer, chunk, name, level, appendLog) => {
3556
+ const lines = `${buffer}${chunk}`.split(`
3557
+ `);
3558
+ const nextBuffer = lines.pop() ?? "";
3559
+ lines.filter((line) => line.trim().length > 0).forEach((line) => appendLog(name, line, level));
3560
+ return nextBuffer;
3561
+ };
3562
+ var appendRemainingLogBuffer = (buffer, name, level, appendLog) => {
3563
+ if (buffer.trim().length === 0) {
3564
+ return;
3565
+ }
3566
+ appendLog(name, buffer, level);
3567
+ };
3554
3568
  var getServicePublicHost = (service) => {
3555
3569
  const host = service.env?.HOST ?? process.env.HOST ?? "localhost";
3556
3570
  if (host === "0.0.0.0" || host === "::") {
@@ -3561,35 +3575,37 @@ var getServicePublicHost = (service) => {
3561
3575
  var getServiceProtocol = (service) => service.env?.ABSOLUTE_HTTPS === "true" || process.env.ABSOLUTE_HTTPS === "true" ? "https" : "http";
3562
3576
  var createWorkspaceServiceEnv = (services) => {
3563
3577
  const workspaceEnv = {};
3564
- for (const [name, service] of Object.entries(services)) {
3565
- if (!service.port) {
3566
- continue;
3567
- }
3578
+ for (const [name, service] of Object.entries(services).filter(([, service2]) => Boolean(service2.port))) {
3568
3579
  const envKey = `ABSOLUTE_SERVICE_${name.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_URL`;
3569
3580
  workspaceEnv[envKey] = `${getServiceProtocol(service)}://${getServicePublicHost(service)}:${service.port}`;
3570
3581
  }
3571
3582
  return workspaceEnv;
3572
3583
  };
3584
+ var getDefinedProcessEnv = () => Object.fromEntries(Object.entries(process.env).filter((entry) => typeof entry[1] === "string"));
3585
+ var resolveAbsoluteServiceConfigPath = (service, cwd, options) => {
3586
+ if (service.config)
3587
+ return resolve6(cwd, service.config);
3588
+ if (options.configPath)
3589
+ return resolve6(options.configPath);
3590
+ if (process.env.ABSOLUTE_CONFIG)
3591
+ return resolve6(process.env.ABSOLUTE_CONFIG);
3592
+ return;
3593
+ };
3573
3594
  var resolveService = (name, service, workspaceEnv, options) => {
3574
3595
  const cwd = resolve6(service.cwd ?? ".");
3575
- const envVars = {
3576
- ...process.env,
3577
- ...workspaceEnv,
3578
- ...service.env,
3596
+ const envVars = Object.assign(getDefinedProcessEnv(), workspaceEnv, service.env, {
3579
3597
  ABSOLUTE_WORKSPACE_MANAGED: "1",
3580
3598
  ABSOLUTE_WORKSPACE_SERVICE_NAME: name,
3581
3599
  ABSOLUTE_WORKSPACE_SERVICE_VISIBILITY: getVisibility(service),
3582
3600
  FORCE_COLOR: "1",
3583
3601
  NODE_ENV: "development"
3584
- };
3602
+ });
3585
3603
  if (service.port && !envVars.PORT) {
3586
3604
  envVars.PORT = String(service.port);
3587
3605
  }
3588
3606
  if (isAbsoluteService(service)) {
3589
- const configPath2 = service.config ? resolve6(cwd, service.config) : options.configPath ? resolve6(options.configPath) : process.env.ABSOLUTE_CONFIG ? resolve6(process.env.ABSOLUTE_CONFIG) : undefined;
3590
- if (configPath2) {
3591
- envVars.ABSOLUTE_CONFIG = configPath2;
3592
- }
3607
+ const configPath2 = resolveAbsoluteServiceConfigPath(service, cwd, options);
3608
+ Object.assign(envVars, configPath2 ? { ABSOLUTE_CONFIG: configPath2 } : {});
3593
3609
  const command = [
3594
3610
  process.execPath,
3595
3611
  "--hot",
@@ -3656,30 +3672,43 @@ var workspace = async (subcommand, options) => {
3656
3672
  });
3657
3673
  const workspaceLogs = createWorkspaceLogSink(tui.addLog);
3658
3674
  const addLog = workspaceLogs.appendLog;
3675
+ const killProcess = (service) => {
3676
+ try {
3677
+ service.process.kill();
3678
+ } catch {}
3679
+ };
3680
+ const runShutdownHookSafely = async (service) => {
3681
+ try {
3682
+ await runShutdownHook(service.resolved, addLog);
3683
+ } catch (error) {
3684
+ const message = error instanceof Error ? error.message : String(error);
3685
+ addLog("workspace", `${service.name} shutdown hook failed: ${message}`, "warn");
3686
+ }
3687
+ };
3659
3688
  const killProcesses = async () => {
3660
3689
  const snapshot = [...running];
3661
3690
  running.length = 0;
3662
- for (const service of snapshot) {
3663
- try {
3664
- service.process.kill();
3665
- } catch {}
3666
- }
3691
+ snapshot.forEach((service) => killProcess(service));
3667
3692
  await Promise.all(snapshot.map((service) => service.process.exited));
3668
3693
  for (const service of snapshot.reverse()) {
3669
- try {
3670
- await runShutdownHook(service.resolved, addLog);
3671
- } catch (error) {
3672
- const message = error instanceof Error ? error.message : String(error);
3673
- addLog("workspace", `${service.name} shutdown hook failed: ${message}`, "warn");
3674
- }
3694
+ await runShutdownHookSafely(service);
3675
3695
  }
3676
3696
  };
3697
+ const appendRecentLogs = (lines, logsToPrint) => {
3698
+ if (logsToPrint.length === 0) {
3699
+ return;
3700
+ }
3701
+ lines.push("", "Recent logs:");
3702
+ logsToPrint.forEach((entry) => {
3703
+ lines.push(` ${entry.timestamp} [${entry.source}] ${entry.message}`);
3704
+ });
3705
+ };
3677
3706
  const printFailureSummary = (exitCode) => {
3678
3707
  const servicesSnapshot = tui.getServiceSnapshot();
3679
- const recentLogs = tui.getRecentLogs(60);
3708
+ const recentLogs = tui.getRecentLogs(WORKSPACE_FAILURE_RECENT_LOG_LIMIT);
3680
3709
  const failedServices = servicesSnapshot.filter((service) => service.status === "error");
3681
3710
  const relevantLogs = recentLogs.filter((entry) => entry.level === "error" || entry.level === "warn" || entry.source === "workspace" || failedServices.some((service) => service.name === entry.source));
3682
- const logsToPrint = (relevantLogs.length > 0 ? relevantLogs : recentLogs).slice(-30);
3711
+ const logsToPrint = (relevantLogs.length > 0 ? relevantLogs : recentLogs).slice(-WORKSPACE_FAILURE_LOG_PRINT_LIMIT);
3683
3712
  const lines = [
3684
3713
  "",
3685
3714
  `\x1B[31mABSOLUTEJS WORKSPACE exited with code ${exitCode}\x1B[0m`,
@@ -3690,12 +3719,7 @@ var workspace = async (subcommand, options) => {
3690
3719
  return ` - ${service.name}: ${service.status} \xB7 ${service.target}${detail}`;
3691
3720
  })
3692
3721
  ];
3693
- if (logsToPrint.length > 0) {
3694
- lines.push("", "Recent logs:");
3695
- for (const entry of logsToPrint) {
3696
- lines.push(` ${entry.timestamp} [${entry.source}] ${entry.message}`);
3697
- }
3698
- }
3722
+ appendRecentLogs(lines, logsToPrint);
3699
3723
  lines.push("");
3700
3724
  process.stderr.write(`${lines.join(`
3701
3725
  `)}
@@ -3710,6 +3734,34 @@ var workspace = async (subcommand, options) => {
3710
3734
  process.kill(processHandle.pid, signal);
3711
3735
  } catch {}
3712
3736
  };
3737
+ const resumeRunningServices = () => {
3738
+ running.forEach((service) => {
3739
+ sendSignalToService(service.process, "SIGCONT");
3740
+ });
3741
+ paused = false;
3742
+ };
3743
+ const markRunningServicesReady = () => {
3744
+ running.forEach((service) => {
3745
+ readyServiceNames.add(service.name);
3746
+ tui.setServiceStatus(service.name, "ready");
3747
+ });
3748
+ };
3749
+ const pauseRunningServices = () => {
3750
+ running.forEach((service) => {
3751
+ sendSignalToService(service.process, "SIGSTOP");
3752
+ readyServiceNames.delete(service.name);
3753
+ tui.setServiceStatus(service.name, "paused");
3754
+ });
3755
+ paused = true;
3756
+ };
3757
+ const killStaleServicePort = (port) => {
3758
+ if (port <= 0) {
3759
+ return;
3760
+ }
3761
+ killStaleProcesses(port, (message) => {
3762
+ addLog("workspace", message, "warn");
3763
+ });
3764
+ };
3713
3765
  const shutdown = async (exitCode = 0) => {
3714
3766
  if (shuttingDown) {
3715
3767
  return;
@@ -3721,10 +3773,7 @@ var workspace = async (subcommand, options) => {
3721
3773
  printFailureSummary(exitCode);
3722
3774
  }
3723
3775
  if (paused) {
3724
- for (const service of running) {
3725
- sendSignalToService(service.process, "SIGCONT");
3726
- }
3727
- paused = false;
3776
+ resumeRunningServices();
3728
3777
  }
3729
3778
  await killProcesses();
3730
3779
  process.exit(exitCode);
@@ -3738,11 +3787,7 @@ var workspace = async (subcommand, options) => {
3738
3787
  }
3739
3788
  const resolved = resolveService(name, service, workspaceEnv, options);
3740
3789
  const port = (resolved.service.port ?? Number(resolved.env.PORT ?? "")) || DEFAULT_PORT;
3741
- if (port > 0) {
3742
- killStaleProcesses(port, (message) => {
3743
- addLog("workspace", message, "warn");
3744
- });
3745
- }
3790
+ killStaleServicePort(port);
3746
3791
  if (isAbsoluteService(resolved.service) && resolved.configPath && !existsSync8(resolved.configPath)) {
3747
3792
  throw new Error(`${name} references missing config "${resolved.configPath}"`);
3748
3793
  }
@@ -3788,10 +3833,7 @@ var workspace = async (subcommand, options) => {
3788
3833
  }
3789
3834
  restarting = true;
3790
3835
  if (paused) {
3791
- for (const service of running) {
3792
- sendSignalToService(service.process, "SIGCONT");
3793
- }
3794
- paused = false;
3836
+ resumeRunningServices();
3795
3837
  }
3796
3838
  addLog("workspace", "Restarting workspace...", "info");
3797
3839
  readyServiceNames.clear();
@@ -3806,20 +3848,12 @@ var workspace = async (subcommand, options) => {
3806
3848
  };
3807
3849
  const togglePause = () => {
3808
3850
  if (paused) {
3809
- for (const service of running) {
3810
- sendSignalToService(service.process, "SIGCONT");
3811
- readyServiceNames.add(service.name);
3812
- tui.setServiceStatus(service.name, "ready");
3813
- }
3851
+ resumeRunningServices();
3852
+ markRunningServicesReady();
3814
3853
  paused = false;
3815
3854
  addLog("workspace", "Workspace resumed.", "success");
3816
3855
  } else {
3817
- for (const service of running) {
3818
- sendSignalToService(service.process, "SIGSTOP");
3819
- readyServiceNames.delete(service.name);
3820
- tui.setServiceStatus(service.name, "paused");
3821
- }
3822
- paused = true;
3856
+ pauseRunningServices();
3823
3857
  addLog("workspace", "Workspace paused.", "warn");
3824
3858
  }
3825
3859
  };
@@ -3885,7 +3919,7 @@ init_telemetryEvent();
3885
3919
  init_constants();
3886
3920
  init_utils();
3887
3921
  var [command] = process.argv.slice(2);
3888
- var [workspaceCommand] = process.argv.slice(3);
3922
+ var [workspaceCommand] = process.argv.slice(WORKSPACE_COMMAND_ARGS_OFFSET);
3889
3923
  var args = process.argv.slice(CLI_ARGS_OFFSET);
3890
3924
  var parseNamedArg = (flag) => {
3891
3925
  const idx = args.indexOf(flag);