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

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 (106) hide show
  1. package/dist/angular/browser.js +1 -19
  2. package/dist/angular/browser.js.map +3 -3
  3. package/dist/angular/components/constants.js +78 -0
  4. package/dist/angular/components/core/streamingSlotRegistrar.js +58 -0
  5. package/dist/angular/components/core/streamingSlotRegistry.js +114 -0
  6. package/dist/angular/components/defer-slot-payload.js +6 -0
  7. package/dist/angular/components/defer-slot-templates.directive.js +44 -0
  8. package/dist/angular/components/defer-slot.component.js +149 -0
  9. package/dist/angular/components/image.component.js +202 -0
  10. package/dist/angular/components/index.js +4 -0
  11. package/dist/angular/components/stream-slot.component.js +103 -0
  12. package/dist/angular/index.js +91 -36
  13. package/dist/angular/index.js.map +6 -6
  14. package/dist/angular/server.js +91 -36
  15. package/dist/angular/server.js.map +6 -6
  16. package/dist/build.js +242 -162
  17. package/dist/build.js.map +12 -12
  18. package/dist/cli/index.js +214 -142
  19. package/dist/client/index.js +86 -31
  20. package/dist/client/index.js.map +4 -4
  21. package/dist/core/streamingSlotRegistrar.js +1 -19
  22. package/dist/core/streamingSlotRegistrar.js.map +2 -2
  23. package/dist/core/streamingSlotRegistry.js +1 -19
  24. package/dist/core/streamingSlotRegistry.js.map +2 -2
  25. package/dist/dev/client/constants.ts +26 -0
  26. package/dist/dev/client/cssUtils.ts +307 -0
  27. package/dist/dev/client/domDiff.ts +226 -0
  28. package/dist/dev/client/domState.ts +421 -0
  29. package/dist/dev/client/domTracker.ts +61 -0
  30. package/dist/dev/client/errorOverlay.ts +184 -0
  31. package/dist/dev/client/frameworkDetect.ts +63 -0
  32. package/dist/dev/client/handlers/angular.ts +578 -0
  33. package/dist/dev/client/handlers/angularRuntime.ts +231 -0
  34. package/dist/dev/client/handlers/html.ts +364 -0
  35. package/dist/dev/client/handlers/htmx.ts +278 -0
  36. package/dist/dev/client/handlers/react.ts +108 -0
  37. package/dist/dev/client/handlers/rebuild.ts +153 -0
  38. package/dist/dev/client/handlers/svelte.ts +334 -0
  39. package/dist/dev/client/handlers/vue.ts +292 -0
  40. package/dist/dev/client/headPatch.ts +233 -0
  41. package/dist/dev/client/hmrClient.ts +273 -0
  42. package/dist/dev/client/hmrState.ts +14 -0
  43. package/dist/dev/client/moduleVersions.ts +62 -0
  44. package/dist/dev/client/reactRefreshSetup.ts +31 -0
  45. package/dist/index.js +282 -187
  46. package/dist/index.js.map +15 -15
  47. package/dist/islands/browser.js +1 -19
  48. package/dist/islands/browser.js.map +2 -2
  49. package/dist/islands/index.js +80 -26
  50. package/dist/islands/index.js.map +5 -5
  51. package/dist/react/browser.js +7 -25
  52. package/dist/react/browser.js.map +2 -2
  53. package/dist/react/components/browser/index.js +101 -101
  54. package/dist/react/components/index.js +104 -122
  55. package/dist/react/components/index.js.map +3 -3
  56. package/dist/react/hooks/index.js +1 -19
  57. package/dist/react/hooks/index.js.map +2 -2
  58. package/dist/react/index.js +101 -46
  59. package/dist/react/index.js.map +6 -6
  60. package/dist/react/jsxDevRuntimeCompat.js +1 -19
  61. package/dist/react/jsxDevRuntimeCompat.js.map +2 -2
  62. package/dist/react/server.js +13 -30
  63. package/dist/react/server.js.map +4 -4
  64. package/dist/src/angular/components/constants.d.ts +75 -0
  65. package/dist/src/angular/components/defer-slot-templates.directive.d.ts +7 -0
  66. package/dist/src/angular/components/defer-slot.component.d.ts +5 -2
  67. package/dist/src/angular/components/image.component.d.ts +5 -2
  68. package/dist/src/angular/components/index.d.ts +4 -4
  69. package/dist/src/angular/components/stream-slot.component.d.ts +3 -0
  70. package/dist/src/client/streamSwap.d.ts +0 -10
  71. package/dist/src/constants.d.ts +1 -0
  72. package/dist/src/dev/rebuildTrigger.d.ts +1 -1
  73. package/dist/src/svelte/renderToPipeableStream.d.ts +2 -2
  74. package/dist/src/svelte/renderToReadableStream.d.ts +2 -2
  75. package/dist/src/svelte/renderToString.d.ts +2 -2
  76. package/dist/src/vue/components/Image.d.ts +3 -3
  77. package/dist/svelte/browser.js +1 -19
  78. package/dist/svelte/browser.js.map +2 -2
  79. package/dist/svelte/components/AwaitSlot.svelte +39 -0
  80. package/dist/svelte/components/AwaitSlot.svelte.d.ts +2 -0
  81. package/dist/svelte/components/Head.svelte +144 -0
  82. package/dist/svelte/components/Head.svelte.d.ts +2 -0
  83. package/dist/svelte/components/Image.svelte +164 -0
  84. package/dist/svelte/components/Image.svelte.d.ts +5 -0
  85. package/dist/svelte/components/Island.svelte +71 -0
  86. package/dist/svelte/components/Island.svelte.d.ts +5 -0
  87. package/dist/svelte/components/JsonLd.svelte +21 -0
  88. package/dist/svelte/components/JsonLd.svelte.d.ts +2 -0
  89. package/dist/svelte/components/StreamSlot.svelte +41 -0
  90. package/dist/svelte/components/StreamSlot.svelte.d.ts +2 -0
  91. package/dist/svelte/index.js +93 -37
  92. package/dist/svelte/index.js.map +7 -7
  93. package/dist/svelte/server.js +16 -32
  94. package/dist/svelte/server.js.map +5 -5
  95. package/dist/types/globals.d.ts +130 -0
  96. package/dist/vue/browser.js +1 -19
  97. package/dist/vue/browser.js.map +2 -2
  98. package/dist/vue/components/Image.js +1 -19
  99. package/dist/vue/components/Image.js.map +3 -3
  100. package/dist/vue/components/index.js +1 -19
  101. package/dist/vue/components/index.js.map +3 -3
  102. package/dist/vue/index.js +91 -36
  103. package/dist/vue/index.js.map +7 -7
  104. package/dist/vue/server.js +13 -30
  105. package/dist/vue/server.js.map +4 -4
  106. package/package.json +1 -1
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, 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;
21
+ var ANSI_ESCAPE_CODE = 27, 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;
@@ -663,17 +663,26 @@ var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_
663
663
  const visited = new Set;
664
664
  const queue = ["/"];
665
665
  const routes = [];
666
- while (queue.length > 0) {
666
+ const crawlNextRoute = async () => {
667
667
  const path = queue.shift();
668
- if (!path || visited.has(path))
669
- continue;
668
+ if (!path) {
669
+ return;
670
+ }
671
+ if (visited.has(path)) {
672
+ await crawlNextRoute();
673
+ return;
674
+ }
670
675
  visited.add(path);
671
676
  const html = await fetchRoute(baseUrl, path).catch(() => null);
672
- if (!html)
673
- continue;
677
+ if (!html) {
678
+ await crawlNextRoute();
679
+ return;
680
+ }
674
681
  routes.push(path);
675
682
  queue.push(...extractLinks(html, visited));
676
- }
683
+ await crawlNextRoute();
684
+ };
685
+ await crawlNextRoute();
677
686
  return routes;
678
687
  }, rerenderRoute = async (route, port, prerenderDir) => {
679
688
  try {
@@ -723,9 +732,7 @@ var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_
723
732
  dir: prerenderDir,
724
733
  routes: new Map
725
734
  };
726
- for (const route of routes) {
727
- await prerenderRoute(baseUrl, route, prerenderDir, result, log);
728
- }
735
+ await routes.reduce((chain, route) => chain.then(() => prerenderRoute(baseUrl, route, prerenderDir, result, log)), Promise.resolve());
729
736
  return result;
730
737
  }, getStartupTimeoutMs = () => {
731
738
  const rawTimeout = Bun.env.ABSOLUTE_PRERENDER_STARTUP_TIMEOUT_MS;
@@ -733,13 +740,17 @@ var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_
733
740
  return Number.isFinite(parsedTimeout) && parsedTimeout > 0 ? parsedTimeout : DEFAULT_STARTUP_TIMEOUT_MS;
734
741
  }, waitForServerReady = async (port) => {
735
742
  const deadline = performance.now() + getStartupTimeoutMs();
736
- while (performance.now() < deadline) {
743
+ const pollServer = async () => {
744
+ if (performance.now() >= deadline) {
745
+ return false;
746
+ }
737
747
  if (await probePrerenderServer(port)) {
738
748
  return true;
739
749
  }
740
750
  await Bun.sleep(STARTUP_POLL_INTERVAL_MS);
741
- }
742
- return false;
751
+ return pollServer();
752
+ };
753
+ return pollServer();
743
754
  }, probePrerenderServer = async (port) => {
744
755
  const res = await fetch(`http://localhost:${port}/`).catch(() => null);
745
756
  if (!res) {
@@ -756,10 +767,11 @@ var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_
756
767
  const decoder = new TextDecoder;
757
768
  const read = () => {
758
769
  reader.read().then(({ done, value }) => {
759
- if (done)
770
+ if (done) {
760
771
  return;
772
+ }
761
773
  output.push(decoder.decode(value, { stream: true }));
762
- read();
774
+ return read();
763
775
  }).catch(() => {});
764
776
  };
765
777
  read();
@@ -853,12 +865,15 @@ var cliTag3 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
853
865
  return null;
854
866
  }
855
867
  }, resolveBuildModule2 = async (candidates) => {
856
- for (const candidate of candidates) {
857
- const mod = await tryImportBuild2(candidate);
858
- if (mod)
859
- return mod;
868
+ const [candidate, ...remaining] = candidates;
869
+ if (!candidate) {
870
+ return;
860
871
  }
861
- return;
872
+ const mod = await tryImportBuild2(candidate);
873
+ if (mod) {
874
+ return mod;
875
+ }
876
+ return resolveBuildModule2(remaining);
862
877
  }, resolveJsxDevRuntimeCompatPath2 = () => {
863
878
  const candidates = [
864
879
  resolve7(import.meta.dir, "..", "..", "dist", "react", "jsxDevRuntimeCompat.js"),
@@ -1203,7 +1218,7 @@ var isCommandService3 = (service) => service.kind === "command" || Array.isArray
1203
1218
  }, shellEscape = (value) => `'${value.replaceAll("'", "'\\''")}'`, runShell = async (name, command) => run(name, ["/bin/bash", "-lc", command]), findBin = (name) => {
1204
1219
  const local = resolve8("node_modules", ".bin", name);
1205
1220
  return existsSync10(local) ? local : null;
1206
- }, stripAnsi3 = (str) => str.replace(/\x1b\[[0-9;]*m/g, ""), formatSvelteOutput = (output) => {
1221
+ }, ANSI_COLOR_REGEX, ANSI_PURPLE_REGEX, ANSI_CYAN_REGEX, ANSI_TOKEN_END_REGEX, stripAnsi3 = (str) => str.replace(ANSI_COLOR_REGEX, ""), formatSvelteOutput = (output) => {
1207
1222
  const cwd = `${process.cwd()}/`;
1208
1223
  const summaryMatch = stripAnsi3(output).match(/svelte-check found (\d+) error/);
1209
1224
  const errorCount = summaryMatch ? parseInt(summaryMatch[1] ?? "0", 10) : 0;
@@ -1220,10 +1235,10 @@ var isCommandService3 = (service) => service.kind === "command" || Array.isArray
1220
1235
  `\x1B[96m${pathMatch[1]}\x1B[0m:\x1B[93m${pathMatch[2]}\x1B[0m`
1221
1236
  ];
1222
1237
  }
1223
- if (result.includes("\x1B[35m")) {
1238
+ if (result.includes(ANSI_PURPLE_REGEX)) {
1224
1239
  const plainLine = stripAnsi3(result);
1225
- const before = stripAnsi3(result.split("\x1B[35m")[0] ?? "");
1226
- const token = stripAnsi3((result.split("\x1B[35m")[1] ?? "").split(/\x1b\[3[69]m/)[0] ?? "");
1240
+ const before = stripAnsi3(result.split(ANSI_PURPLE_REGEX)[0] ?? "");
1241
+ const token = stripAnsi3((result.split(ANSI_PURPLE_REGEX)[1] ?? "").split(ANSI_TOKEN_END_REGEX)[0] ?? "");
1227
1242
  if (!token)
1228
1243
  return [result];
1229
1244
  const expanded = before.replace(/\t/g, " ");
@@ -1234,7 +1249,7 @@ var isCommandService3 = (service) => service.kind === "command" || Array.isArray
1234
1249
  `${" ".repeat(expanded.length)}\x1B[91m${underline}\x1B[0m`
1235
1250
  ];
1236
1251
  }
1237
- if (/^\x1b\[36m|\t/.test(result) && !result.includes("Error") && !result.includes("\x1B[35m")) {
1252
+ if (ANSI_CYAN_REGEX.test(result) && !result.includes("Error") && !result.includes(ANSI_PURPLE_REGEX)) {
1238
1253
  return [];
1239
1254
  }
1240
1255
  return [result];
@@ -1377,6 +1392,11 @@ Found ${errorCount} error${suffix}.`;
1377
1392
  };
1378
1393
  var init_typecheck = __esm(() => {
1379
1394
  init_loadConfig();
1395
+ init_constants();
1396
+ ANSI_COLOR_REGEX = new RegExp(`${String.fromCharCode(ANSI_ESCAPE_CODE)}\\[[0-9;]*m`, "g");
1397
+ ANSI_PURPLE_REGEX = `${String.fromCharCode(ANSI_ESCAPE_CODE)}[35m`;
1398
+ ANSI_CYAN_REGEX = new RegExp(`^${String.fromCharCode(ANSI_ESCAPE_CODE)}\\[36m|\\t`);
1399
+ ANSI_TOKEN_END_REGEX = new RegExp(`${String.fromCharCode(ANSI_ESCAPE_CODE)}\\[3[69]m`);
1380
1400
  TYPECHECK_EXCLUDE = [
1381
1401
  "../node_modules/**/*",
1382
1402
  "../**/.absolutejs/**/*",
@@ -1431,7 +1451,10 @@ var trySetRawMode = () => {
1431
1451
  } catch {
1432
1452
  return null;
1433
1453
  }
1434
- return process.stdin;
1454
+ return {
1455
+ destroyOnDispose: false,
1456
+ stream: process.stdin
1457
+ };
1435
1458
  };
1436
1459
  var openTtyStream = () => {
1437
1460
  const fromStdin = trySetRawMode();
@@ -1441,7 +1464,10 @@ var openTtyStream = () => {
1441
1464
  try {
1442
1465
  const ttyStream = new ReadStream(openSync("/dev/tty", "r"));
1443
1466
  ttyStream.setRawMode(true);
1444
- return ttyStream;
1467
+ return {
1468
+ destroyOnDispose: true,
1469
+ stream: ttyStream
1470
+ };
1445
1471
  } catch {
1446
1472
  return null;
1447
1473
  }
@@ -1633,19 +1659,19 @@ var createInteractiveHandler = (actions) => {
1633
1659
  processChar(str.charAt(idx));
1634
1660
  }
1635
1661
  };
1636
- const ttyStream = openTtyStream();
1637
- const input = ttyStream ?? process.stdin;
1662
+ const ttyInput = openTtyStream();
1663
+ const input = ttyInput?.stream ?? process.stdin;
1638
1664
  input.resume();
1639
1665
  input.on("data", onData);
1640
1666
  const disposeTtyStream = () => {
1641
- if (!ttyStream) {
1667
+ if (!ttyInput) {
1642
1668
  return;
1643
1669
  }
1644
1670
  try {
1645
- ttyStream.setRawMode(false);
1671
+ ttyInput.stream.setRawMode?.(false);
1646
1672
  } catch {}
1647
- if (ttyStream !== process.stdin) {
1648
- ttyStream.destroy();
1673
+ if (ttyInput.destroyOnDispose) {
1674
+ ttyInput.stream.destroy?.();
1649
1675
  }
1650
1676
  };
1651
1677
  const dispose = () => {
@@ -1668,7 +1694,7 @@ init_loadConfig();
1668
1694
  init_utils();
1669
1695
  var cliTag = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`;
1670
1696
  var confirmPrompt = (message, defaultYes = true) => {
1671
- const { promise, resolve: resolve4 } = Promise.withResolvers();
1697
+ const { promise, resolve: resolvePrompt } = Promise.withResolvers();
1672
1698
  let selected = defaultYes;
1673
1699
  const render = () => {
1674
1700
  const yes = selected ? "\x1B[36m\u25CF\x1B[0m Yes" : "\x1B[2m\u25CB Yes\x1B[0m";
@@ -1694,7 +1720,7 @@ var confirmPrompt = (message, defaultYes = true) => {
1694
1720
  process.stdout.write(`\x1B[2K\x1B[32m\u25C7\x1B[0m ${message}
1695
1721
  \x1B[2K \x1B[2m${label}\x1B[0m
1696
1722
  \x1B[?25h`);
1697
- resolve4(selected);
1723
+ resolvePrompt(selected);
1698
1724
  } else if (key === "\x03") {
1699
1725
  process.stdout.write("\x1B[?25h");
1700
1726
  process.stdin.setRawMode(false);
@@ -2203,9 +2229,7 @@ var runTool = async (adapter, args) => {
2203
2229
  batches.push(changed.slice(idx, idx + MAX_FILES_PER_BATCH));
2204
2230
  }
2205
2231
  const failedFiles = new Set;
2206
- for (const batch of batches) {
2207
- await runBatch(adapter, batch, args, failedFiles);
2208
- }
2232
+ await batches.reduce((chain, batch) => chain.then(() => runBatch(adapter, batch, args, failedFiles)), Promise.resolve());
2209
2233
  for (const file of failedFiles) {
2210
2234
  delete cache.files[file];
2211
2235
  }
@@ -2285,13 +2309,15 @@ var readPackageVersion2 = (candidate) => {
2285
2309
  return null;
2286
2310
  };
2287
2311
  var resolveBuildModule = async (candidates) => {
2288
- for (const candidate of candidates) {
2289
- const mod = await tryImportBuild(candidate);
2290
- if (mod) {
2291
- return mod;
2292
- }
2312
+ const [candidate, ...remaining] = candidates;
2313
+ if (!candidate) {
2314
+ return;
2293
2315
  }
2294
- return;
2316
+ const mod = await tryImportBuild(candidate);
2317
+ if (mod) {
2318
+ return mod;
2319
+ }
2320
+ return resolveBuildModule(remaining);
2295
2321
  };
2296
2322
  var tryImportBuild = async (candidate) => {
2297
2323
  try {
@@ -2581,7 +2607,8 @@ import { openSync as openSync2 } from "fs";
2581
2607
  import { ReadStream as ReadStream2 } from "tty";
2582
2608
  var MAX_LOG_ENTRIES = 400;
2583
2609
  var ESCAPE = "\x1B";
2584
- var ANSI_REGEX = /\x1B\[[0-?]*[ -/]*[@-~]/g;
2610
+ var ANSI_REGEX = new RegExp(`${String.fromCharCode(ANSI_ESCAPE_CODE)}\\[[0-?]*[ -/]*[@-~]`, "g");
2611
+ var ANSI_ESCAPE_PREFIX = `${ESCAPE}[`;
2585
2612
  var SHORTCUTS2 = new Map([
2586
2613
  ["c", "clear"],
2587
2614
  ["h", "help"],
@@ -2773,6 +2800,17 @@ var getWorkspaceStatus = (services) => {
2773
2800
  }
2774
2801
  return "ready";
2775
2802
  };
2803
+ var getVisibleLogContent = (contentLines, logHeight, logScrollOffset) => {
2804
+ const end = Math.max(0, contentLines.length - logScrollOffset);
2805
+ const start2 = Math.max(0, end - logHeight);
2806
+ return contentLines.slice(start2, end);
2807
+ };
2808
+ var isPartialEscapeSequence = (value) => {
2809
+ if (!value.startsWith(ANSI_ESCAPE_PREFIX)) {
2810
+ return false;
2811
+ }
2812
+ return Array.from(value.slice(ANSI_ESCAPE_PREFIX.length)).every((char) => char >= "0" && char <= "9");
2813
+ };
2776
2814
  var createWorkspaceTui = ({
2777
2815
  actions,
2778
2816
  services,
@@ -2896,11 +2934,7 @@ var createWorkspaceTui = ({
2896
2934
  lastLogViewportHeight = logHeight;
2897
2935
  logScrollOffset = Math.min(logScrollOffset, Math.max(0, contentLines.length - logHeight));
2898
2936
  }
2899
- const visibleContent = helpVisible ? contentLines.slice(0, logHeight) : (() => {
2900
- const end = Math.max(0, contentLines.length - logScrollOffset);
2901
- const start3 = Math.max(0, end - logHeight);
2902
- return contentLines.slice(start3, end);
2903
- })();
2937
+ const visibleContent = helpVisible ? contentLines.slice(0, logHeight) : getVisibleLogContent(contentLines, logHeight, logScrollOffset);
2904
2938
  const maxLogScrollOffset = !helpVisible ? Math.max(0, contentLines.length - logHeight) : 0;
2905
2939
  const shouldShowScrollbar = !helpVisible && maxLogScrollOffset > 0;
2906
2940
  const scrollbarThumbHeight = shouldShowScrollbar ? Math.max(1, Math.min(logHeight, Math.round(logHeight / contentLines.length * logHeight))) : 0;
@@ -3093,7 +3127,7 @@ var createWorkspaceTui = ({
3093
3127
  handleScrollEscape("end");
3094
3128
  return;
3095
3129
  }
3096
- if (/^\x1b\[[0-9]*$/.test(escapeBuffer)) {
3130
+ if (isPartialEscapeSequence(escapeBuffer)) {
3097
3131
  armEscapeTimer();
3098
3132
  return;
3099
3133
  }
@@ -3161,16 +3195,15 @@ var createWorkspaceTui = ({
3161
3195
  }
3162
3196
  await handlePrintableChar(char);
3163
3197
  };
3198
+ const processInputChars = async (chars) => {
3199
+ await Array.from(chars).reduce((chain, char) => chain.then(() => handleChar(char)), Promise.resolve());
3200
+ };
3164
3201
  const onResize = () => {
3165
3202
  scheduleRender();
3166
3203
  };
3167
3204
  const onData = (chunk) => {
3168
3205
  const chars = chunk.toString();
3169
- (async () => {
3170
- for (const char of chars) {
3171
- await handleChar(char);
3172
- }
3173
- })();
3206
+ processInputChars(chars);
3174
3207
  };
3175
3208
  const start2 = () => {
3176
3209
  process.stdout.write("\x1B[?1049h\x1B[2J\x1B[H\x1B[?25l");
@@ -3222,8 +3255,8 @@ var createWorkspaceTui = ({
3222
3255
 
3223
3256
  // src/cli/scripts/workspace.ts
3224
3257
  init_utils();
3225
- var ANSI_REGEX2 = /\x1B\[[0-?]*[ -/]*[@-~]/g;
3226
- var sleep = (ms) => new Promise((resolvePromise) => setTimeout(resolvePromise, ms));
3258
+ var ANSI_REGEX2 = new RegExp(`${String.fromCharCode(ANSI_ESCAPE_CODE)}\\[[0-?]*[ -/]*[@-~]`, "g");
3259
+ var sleep = (durationMs) => Bun.sleep(durationMs);
3227
3260
  var stripAnsi2 = (value) => value.replace(ANSI_REGEX2, "");
3228
3261
  var sanitizeLogFileName = (value) => value.replace(/[^a-zA-Z0-9._-]/g, "_") || "unknown";
3229
3262
  var createWorkspaceLogSink = (appendLog) => {
@@ -3250,11 +3283,11 @@ var createWorkspaceLogSink = (appendLog) => {
3250
3283
  appendFileSync(resolve6(logDirectory, "all.log"), line);
3251
3284
  };
3252
3285
  return {
3253
- logDirectory,
3254
3286
  appendLog: (source, message, level = "info") => {
3255
3287
  writeLog(source, message, level);
3256
3288
  appendLog(source, message, level);
3257
- }
3289
+ },
3290
+ logDirectory
3258
3291
  };
3259
3292
  };
3260
3293
  var readPackageVersion3 = (candidate) => {
@@ -3299,6 +3332,7 @@ var getDefaultReadyConfig = (service) => {
3299
3332
  return;
3300
3333
  };
3301
3334
  var normalizeExpectedStatuses = (value) => Array.isArray(value) ? value : [value ?? HTTP_STATUS_OK];
3335
+ var runSequentially = (items, action) => items.reduce((chain, item) => chain.then(() => action(item)), Promise.resolve());
3302
3336
  var resolveServiceHttpUrl = (service, path) => {
3303
3337
  if (!path.startsWith("/")) {
3304
3338
  throw new Error(`ready path must start with "/" for service probes. Received "${path}".`);
@@ -3310,17 +3344,18 @@ var resolveServiceHttpUrl = (service, path) => {
3310
3344
  };
3311
3345
  var resolveHttpReadyProbe = (service, ready) => {
3312
3346
  if (typeof ready === "string") {
3313
- if (isAbsoluteService(service)) {
3347
+ if (!isAbsoluteService(service)) {
3314
3348
  return {
3315
- type: "http",
3316
- url: resolveServiceHttpUrl(service, ready),
3317
- method: "GET",
3318
3349
  expectStatus: [HTTP_STATUS_OK],
3319
3350
  headers: {},
3320
3351
  intervalMs: WORKSPACE_READY_PROBE_INTERVAL_MS,
3321
- timeoutMs: WORKSPACE_READY_TIMEOUT_MS
3352
+ method: "GET",
3353
+ timeoutMs: WORKSPACE_READY_TIMEOUT_MS,
3354
+ type: "http",
3355
+ url: ready
3322
3356
  };
3323
3357
  }
3358
+ const url2 = resolveServiceHttpUrl(service, ready);
3324
3359
  return {
3325
3360
  expectStatus: [HTTP_STATUS_OK],
3326
3361
  headers: {},
@@ -3328,26 +3363,38 @@ var resolveHttpReadyProbe = (service, ready) => {
3328
3363
  method: "GET",
3329
3364
  timeoutMs: WORKSPACE_READY_TIMEOUT_MS,
3330
3365
  type: "http",
3331
- url: ready
3366
+ url: url2
3332
3367
  };
3333
3368
  }
3334
3369
  if (ready.path && ready.url) {
3335
3370
  throw new Error('ready HTTP probe cannot define both "path" and "url".');
3336
3371
  }
3337
- const url = ready.path ? resolveServiceHttpUrl(service, ready.path) : ready.url ? ready.url : isAbsoluteService(service) ? resolveServiceHttpUrl(service, "/hmr-status") : null;
3372
+ const url = resolveHttpReadyProbeUrl(service, ready);
3338
3373
  if (!url) {
3339
3374
  throw new Error('ready HTTP probe requires either "url" or "path".');
3340
3375
  }
3341
3376
  return {
3342
- type: "http",
3343
- url,
3344
- method: ready.method ?? "GET",
3345
3377
  expectStatus: normalizeExpectedStatuses(ready.expectStatus),
3346
3378
  headers: ready.headers ?? {},
3347
3379
  intervalMs: ready.intervalMs ?? WORKSPACE_READY_PROBE_INTERVAL_MS,
3348
- timeoutMs: ready.timeoutMs ?? WORKSPACE_READY_TIMEOUT_MS
3380
+ method: ready.method ?? "GET",
3381
+ timeoutMs: ready.timeoutMs ?? WORKSPACE_READY_TIMEOUT_MS,
3382
+ type: "http",
3383
+ url
3349
3384
  };
3350
3385
  };
3386
+ var resolveHttpReadyProbeUrl = (service, ready) => {
3387
+ if (ready.path) {
3388
+ return resolveServiceHttpUrl(service, ready.path);
3389
+ }
3390
+ if (ready.url) {
3391
+ return ready.url;
3392
+ }
3393
+ if (isAbsoluteService(service)) {
3394
+ return resolveServiceHttpUrl(service, "/hmr-status");
3395
+ }
3396
+ return null;
3397
+ };
3351
3398
  var resolveReadyProbe = (service, ready = service.ready ?? getDefaultReadyConfig(service)) => {
3352
3399
  if (ready === false || !ready) {
3353
3400
  return null;
@@ -3357,11 +3404,11 @@ var resolveReadyProbe = (service, ready = service.ready ?? getDefaultReadyConfig
3357
3404
  }
3358
3405
  if (ready.type === "tcp") {
3359
3406
  return {
3360
- type: "tcp",
3361
3407
  host: ready.host ?? getServicePublicHost(service),
3362
- port: ready.port,
3363
3408
  intervalMs: ready.intervalMs ?? WORKSPACE_READY_PROBE_INTERVAL_MS,
3364
- timeoutMs: ready.timeoutMs ?? WORKSPACE_READY_TIMEOUT_MS
3409
+ port: ready.port,
3410
+ timeoutMs: ready.timeoutMs ?? WORKSPACE_READY_TIMEOUT_MS,
3411
+ type: "tcp"
3365
3412
  };
3366
3413
  }
3367
3414
  if (ready.type === "command") {
@@ -3381,14 +3428,16 @@ var resolveReadyProbe = (service, ready = service.ready ?? getDefaultReadyConfig
3381
3428
  return resolveHttpReadyProbe(service, ready);
3382
3429
  };
3383
3430
  var probeHttpReady = async (ready) => {
3431
+ const signal = AbortSignal.timeout(Math.min(ready.timeoutMs, WORKSPACE_READY_ATTEMPT_TIMEOUT_MS));
3384
3432
  const response = await fetch(ready.url, {
3385
- method: ready.method,
3386
3433
  headers: ready.headers,
3387
- signal: AbortSignal.timeout(Math.min(ready.timeoutMs, WORKSPACE_READY_ATTEMPT_TIMEOUT_MS))
3434
+ method: ready.method,
3435
+ signal
3388
3436
  });
3389
3437
  return ready.expectStatus.includes(response.status);
3390
3438
  };
3391
- var probeTcpReady = async (ready) => new Promise((resolveProbe) => {
3439
+ var probeTcpReady = async (ready) => {
3440
+ const { promise, resolve: resolveProbe } = Promise.withResolvers();
3392
3441
  const socket = createConnection({
3393
3442
  host: ready.host,
3394
3443
  port: ready.port
@@ -3407,7 +3456,8 @@ var probeTcpReady = async (ready) => new Promise((resolveProbe) => {
3407
3456
  socket.destroy();
3408
3457
  resolveProbe(false);
3409
3458
  });
3410
- });
3459
+ return promise;
3460
+ };
3411
3461
  var probeCommandReady = async (ready, service) => {
3412
3462
  const processHandle = Bun.spawn(ready.command, {
3413
3463
  cwd: service.cwd,
@@ -3437,14 +3487,30 @@ var waitForReady = async (service) => {
3437
3487
  await sleep(resolved.ms);
3438
3488
  return;
3439
3489
  }
3440
- const startedAt = Date.now();
3441
- while (Date.now() - startedAt < resolved.timeoutMs) {
3442
- if (await probeReady(resolved, service)) {
3443
- return;
3444
- }
3445
- await sleep(resolved.intervalMs);
3490
+ const isReady = await pollReady(resolved, service, Date.now());
3491
+ if (isReady) {
3492
+ return;
3446
3493
  }
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(" ")})`);
3494
+ throw new Error(formatReadyTimeoutMessage(resolved));
3495
+ };
3496
+ var pollReady = async (resolved, service, startedAt) => {
3497
+ if (Date.now() - startedAt >= resolved.timeoutMs) {
3498
+ return false;
3499
+ }
3500
+ if (await probeReady(resolved, service)) {
3501
+ return true;
3502
+ }
3503
+ await sleep(resolved.intervalMs);
3504
+ return pollReady(resolved, service, startedAt);
3505
+ };
3506
+ var formatReadyTimeoutMessage = (resolved) => {
3507
+ if (resolved.type === "http") {
3508
+ return `service did not become ready within ${resolved.timeoutMs}ms (${resolved.url})`;
3509
+ }
3510
+ if (resolved.type === "tcp") {
3511
+ return `service did not become ready within ${resolved.timeoutMs}ms (tcp://${resolved.host}:${resolved.port})`;
3512
+ }
3513
+ return `service did not become ready within ${resolved.timeoutMs}ms (${resolved.command.join(" ")})`;
3448
3514
  };
3449
3515
  var probeReady = async (resolved, service) => {
3450
3516
  try {
@@ -3533,13 +3599,17 @@ var pipeProcessLogs = (name, processHandle, appendLog) => {
3533
3599
  const forward = async (stream, level) => {
3534
3600
  let buffer = "";
3535
3601
  const reader = stream.getReader();
3536
- let chunk = await readLogChunk(reader);
3537
- while (chunk !== null) {
3602
+ const forwardNextChunk = async () => {
3603
+ const chunk = await readLogChunk(reader);
3604
+ if (chunk === null) {
3605
+ appendRemainingLogBuffer(buffer, name, level, appendLog);
3606
+ reader.releaseLock();
3607
+ return;
3608
+ }
3538
3609
  buffer = appendLogChunk(buffer, chunk, name, level, appendLog);
3539
- chunk = await readLogChunk(reader);
3540
- }
3541
- appendRemainingLogBuffer(buffer, name, level, appendLog);
3542
- reader.releaseLock();
3610
+ await forwardNextChunk();
3611
+ };
3612
+ await forwardNextChunk();
3543
3613
  };
3544
3614
  forward(processHandle.stdout, "info");
3545
3615
  forward(processHandle.stderr, "error");
@@ -3575,7 +3645,7 @@ var getServicePublicHost = (service) => {
3575
3645
  var getServiceProtocol = (service) => service.env?.ABSOLUTE_HTTPS === "true" || process.env.ABSOLUTE_HTTPS === "true" ? "https" : "http";
3576
3646
  var createWorkspaceServiceEnv = (services) => {
3577
3647
  const workspaceEnv = {};
3578
- for (const [name, service] of Object.entries(services).filter(([, service2]) => Boolean(service2.port))) {
3648
+ for (const [name, service] of Object.entries(services).filter(([, filteredService]) => Boolean(filteredService.port))) {
3579
3649
  const envKey = `ABSOLUTE_SERVICE_${name.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_URL`;
3580
3650
  workspaceEnv[envKey] = `${getServiceProtocol(service)}://${getServicePublicHost(service)}:${service.port}`;
3581
3651
  }
@@ -3690,9 +3760,7 @@ var workspace = async (subcommand, options) => {
3690
3760
  running.length = 0;
3691
3761
  snapshot.forEach((service) => killProcess(service));
3692
3762
  await Promise.all(snapshot.map((service) => service.process.exited));
3693
- for (const service of snapshot.reverse()) {
3694
- await runShutdownHookSafely(service);
3695
- }
3763
+ await runSequentially(snapshot.reverse(), runShutdownHookSafely);
3696
3764
  };
3697
3765
  const appendRecentLogs = (lines, logsToPrint) => {
3698
3766
  if (logsToPrint.length === 0) {
@@ -3778,54 +3846,58 @@ var workspace = async (subcommand, options) => {
3778
3846
  await killProcesses();
3779
3847
  process.exit(exitCode);
3780
3848
  };
3849
+ const handleServiceExit = (runningService, exitCode) => {
3850
+ if (shuttingDown || restarting) {
3851
+ return;
3852
+ }
3853
+ if (!running.includes(runningService)) {
3854
+ return;
3855
+ }
3856
+ const serviceName = runningService.name;
3857
+ const normalizedExitCode = exitCode || 1;
3858
+ tui.setServiceStatus(serviceName, "error", `exit code ${normalizedExitCode}`);
3859
+ readyServiceNames.delete(serviceName);
3860
+ addLog("workspace", `${serviceName} exited with code ${normalizedExitCode}. Shutting down workspace.`, "error");
3861
+ shutdown(normalizedExitCode);
3862
+ };
3863
+ const startService = async (name) => {
3864
+ const service = services[name];
3865
+ if (!service) {
3866
+ throw new Error(`services is missing "${name}"`);
3867
+ }
3868
+ const resolved = resolveService(name, service, workspaceEnv, options);
3869
+ const port = (resolved.service.port ?? Number(resolved.env.PORT ?? "")) || DEFAULT_PORT;
3870
+ killStaleServicePort(port);
3871
+ if (isAbsoluteService(resolved.service) && resolved.configPath && !existsSync8(resolved.configPath)) {
3872
+ throw new Error(`${name} references missing config "${resolved.configPath}"`);
3873
+ }
3874
+ serviceBootStartedAt.set(name, performance.now());
3875
+ readyServiceNames.delete(name);
3876
+ tui.setServiceStatus(name, restarting ? "restarting" : "starting");
3877
+ const processHandle = Bun.spawn(resolved.command, {
3878
+ cwd: resolved.cwd,
3879
+ env: resolved.env,
3880
+ stderr: "pipe",
3881
+ stdin: "ignore",
3882
+ stdout: "pipe"
3883
+ });
3884
+ pipeProcessLogs(name, processHandle, addLog);
3885
+ const runningService = {
3886
+ name,
3887
+ process: processHandle,
3888
+ resolved
3889
+ };
3890
+ running.push(runningService);
3891
+ processHandle.exited.then(handleServiceExit.bind(null, runningService));
3892
+ await waitForReady(resolved);
3893
+ const startedAt = serviceBootStartedAt.get(name);
3894
+ const readyDuration = typeof startedAt === "number" ? `ready in ${getDurationString(performance.now() - startedAt)}` : undefined;
3895
+ readyServiceNames.add(name);
3896
+ tui.setServiceStatus(name, "ready", readyDuration);
3897
+ };
3781
3898
  const startServices = async () => {
3782
3899
  tui.setReadyDuration(null);
3783
- for (const name of orderedNames) {
3784
- const service = services[name];
3785
- if (!service) {
3786
- throw new Error(`services is missing "${name}"`);
3787
- }
3788
- const resolved = resolveService(name, service, workspaceEnv, options);
3789
- const port = (resolved.service.port ?? Number(resolved.env.PORT ?? "")) || DEFAULT_PORT;
3790
- killStaleServicePort(port);
3791
- if (isAbsoluteService(resolved.service) && resolved.configPath && !existsSync8(resolved.configPath)) {
3792
- throw new Error(`${name} references missing config "${resolved.configPath}"`);
3793
- }
3794
- serviceBootStartedAt.set(name, performance.now());
3795
- readyServiceNames.delete(name);
3796
- tui.setServiceStatus(name, restarting ? "restarting" : "starting");
3797
- const processHandle = Bun.spawn(resolved.command, {
3798
- cwd: resolved.cwd,
3799
- env: resolved.env,
3800
- stderr: "pipe",
3801
- stdin: "ignore",
3802
- stdout: "pipe"
3803
- });
3804
- pipeProcessLogs(name, processHandle, addLog);
3805
- const runningService = {
3806
- name,
3807
- process: processHandle,
3808
- resolved
3809
- };
3810
- running.push(runningService);
3811
- processHandle.exited.then((exitCode) => {
3812
- if (shuttingDown || restarting) {
3813
- return;
3814
- }
3815
- if (!running.includes(runningService)) {
3816
- return;
3817
- }
3818
- tui.setServiceStatus(name, "error", `exit code ${exitCode || 1}`);
3819
- readyServiceNames.delete(name);
3820
- addLog("workspace", `${name} exited with code ${exitCode || 1}. Shutting down workspace.`, "error");
3821
- shutdown(exitCode || 1);
3822
- });
3823
- await waitForReady(resolved);
3824
- const startedAt = serviceBootStartedAt.get(name);
3825
- const readyDuration = typeof startedAt === "number" ? `ready in ${getDurationString(performance.now() - startedAt)}` : undefined;
3826
- readyServiceNames.add(name);
3827
- tui.setServiceStatus(name, "ready", readyDuration);
3828
- }
3900
+ await runSequentially(orderedNames, startService);
3829
3901
  };
3830
3902
  const restartWorkspace = async () => {
3831
3903
  if (shuttingDown || restarting) {
@@ -3910,7 +3982,7 @@ var workspace = async (subcommand, options) => {
3910
3982
  tui.start();
3911
3983
  await startServices();
3912
3984
  tui.setReadyDuration(performance.now() - workspaceBootStartedAt);
3913
- await new Promise(() => {});
3985
+ await Promise.withResolvers().promise;
3914
3986
  };
3915
3987
 
3916
3988
  // src/cli/index.ts