@absolutejs/absolute 0.19.0-beta.1016 → 0.19.0-beta.1017
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/browser.js +2 -2
- package/dist/angular/browser.js.map +3 -3
- package/dist/angular/components/constants.js +13 -0
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/angular/index.js +2 -2
- package/dist/angular/index.js.map +3 -3
- package/dist/angular/server.js +2 -2
- package/dist/angular/server.js.map +3 -3
- package/dist/build.js +2 -2
- package/dist/build.js.map +3 -3
- package/dist/cli/index.js +1163 -300
- package/dist/index.js +99 -9
- package/dist/index.js.map +6 -5
- package/dist/islands/index.js +2 -2
- package/dist/islands/index.js.map +3 -3
- package/dist/react/components/index.js +2 -2
- package/dist/react/components/index.js.map +3 -3
- package/dist/react/index.js +2 -2
- package/dist/react/index.js.map +3 -3
- package/dist/react/server.js +2 -2
- package/dist/react/server.js.map +3 -3
- package/dist/src/angular/components/constants.d.ts +13 -0
- package/dist/src/cli/instanceStatus.d.ts +21 -0
- package/dist/src/cli/listTui.d.ts +1 -0
- package/dist/src/cli/scripts/list.d.ts +1 -0
- package/dist/src/cli/tuiPrimitives.d.ts +14 -0
- package/dist/src/constants.d.ts +13 -0
- package/dist/src/utils/instanceRegistry.d.ts +13 -0
- package/dist/svelte/index.js +2 -2
- package/dist/svelte/index.js.map +3 -3
- package/dist/svelte/server.js +2 -2
- package/dist/svelte/server.js.map +3 -3
- package/dist/types/cli.d.ts +39 -0
- package/dist/vue/components/Image.js +2 -2
- package/dist/vue/components/Image.js.map +3 -3
- package/dist/vue/components/index.js +2 -2
- package/dist/vue/components/index.js.map +3 -3
- package/dist/vue/index.js +2 -2
- package/dist/vue/index.js.map +3 -3
- package/dist/vue/server.js +2 -2
- package/dist/vue/server.js.map +3 -3
- 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_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;
|
|
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, EXCLUDE_LAST_OFFSET = -1, HTTP_STATUS_OK = 200, HOURS_IN_DAY = 24, HOURS_IN_HALF_DAY = 12, INSTANCE_PROBE_TIMEOUT_MS = 250, 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, LIST_LOG_TAIL_MAX_BYTES = 65536, LIST_TUI_COLUMN_GAP = 2, LIST_TUI_DEFAULT_HEIGHT = 28, LIST_TUI_DEFAULT_WIDTH = 100, LIST_TUI_ESCAPE_SEQUENCE_TIMEOUT_MS = 30, LIST_TUI_FOOTER_LINE_COUNT = 2, LIST_TUI_MARKER_WIDTH = 2, LIST_TUI_MIN_LOG_HEIGHT = 3, LIST_TUI_MIN_URL_WIDTH = 16, LIST_TUI_RENDER_DEBOUNCE_MS = 16, LIST_TUI_STATUS_MESSAGE_TIMEOUT_MS = 4000, LIST_WATCH_REFRESH_MS = 1000, 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;
|
|
@@ -391,6 +391,120 @@ var init_buildDirectoryLock = __esm(() => {
|
|
|
391
391
|
heldLocks = new Map;
|
|
392
392
|
});
|
|
393
393
|
|
|
394
|
+
// src/utils/instanceRegistry.ts
|
|
395
|
+
import {
|
|
396
|
+
mkdirSync as mkdirSync3,
|
|
397
|
+
readFileSync as readFileSync4,
|
|
398
|
+
readdirSync,
|
|
399
|
+
unlinkSync as unlinkSync2,
|
|
400
|
+
writeFileSync as writeFileSync3
|
|
401
|
+
} from "fs";
|
|
402
|
+
import { homedir as homedir2 } from "os";
|
|
403
|
+
import { basename, join as join4 } from "path";
|
|
404
|
+
var registeredPids, exitHandlerRegistered = false, instanceFilePath = (pid) => join4(instanceRegistryDir(), `${pid}.json`), instanceLogPath = (pid) => join4(instanceRegistryDir(), `${pid}.log`), instanceRegistryDir = () => join4(homedir2(), ".absolutejs", "instances"), removeInstanceFilesSync = (pid) => {
|
|
405
|
+
try {
|
|
406
|
+
unlinkSync2(instanceFilePath(pid));
|
|
407
|
+
} catch {}
|
|
408
|
+
try {
|
|
409
|
+
unlinkSync2(instanceLogPath(pid));
|
|
410
|
+
} catch {}
|
|
411
|
+
}, registerExitHandlerOnce = () => {
|
|
412
|
+
if (exitHandlerRegistered)
|
|
413
|
+
return;
|
|
414
|
+
exitHandlerRegistered = true;
|
|
415
|
+
process.on("exit", () => {
|
|
416
|
+
for (const pid of registeredPids) {
|
|
417
|
+
removeInstanceFilesSync(pid);
|
|
418
|
+
}
|
|
419
|
+
registeredPids.clear();
|
|
420
|
+
});
|
|
421
|
+
}, isProcessAlive2 = (pid) => {
|
|
422
|
+
try {
|
|
423
|
+
process.kill(pid, 0);
|
|
424
|
+
return true;
|
|
425
|
+
} catch (error) {
|
|
426
|
+
const code = error instanceof Error && "code" in error ? error.code : undefined;
|
|
427
|
+
if (code === "ESRCH")
|
|
428
|
+
return false;
|
|
429
|
+
return true;
|
|
430
|
+
}
|
|
431
|
+
}, readJsonFile = (path) => {
|
|
432
|
+
try {
|
|
433
|
+
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
434
|
+
} catch {
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
}, SOURCES, toStringArray = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [], coerceSource = (value) => SOURCES.find((item) => item === value) ?? "standalone", coerceRecord = (parsed) => {
|
|
438
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
439
|
+
return null;
|
|
440
|
+
if (typeof parsed.pid !== "number")
|
|
441
|
+
return null;
|
|
442
|
+
return {
|
|
443
|
+
command: toStringArray(parsed.command),
|
|
444
|
+
configPath: typeof parsed.configPath === "string" ? parsed.configPath : null,
|
|
445
|
+
controllerPid: typeof parsed.controllerPid === "number" ? parsed.controllerPid : parsed.pid,
|
|
446
|
+
cwd: typeof parsed.cwd === "string" ? parsed.cwd : "",
|
|
447
|
+
frameworks: toStringArray(parsed.frameworks),
|
|
448
|
+
host: typeof parsed.host === "string" ? parsed.host : "localhost",
|
|
449
|
+
https: parsed.https === true,
|
|
450
|
+
logFile: typeof parsed.logFile === "string" ? parsed.logFile : null,
|
|
451
|
+
name: typeof parsed.name === "string" ? parsed.name : "unknown",
|
|
452
|
+
pid: parsed.pid,
|
|
453
|
+
port: typeof parsed.port === "number" ? parsed.port : null,
|
|
454
|
+
ppid: typeof parsed.ppid === "number" ? parsed.ppid : 0,
|
|
455
|
+
source: coerceSource(parsed.source),
|
|
456
|
+
startedAt: typeof parsed.startedAt === "string" ? parsed.startedAt : new Date().toISOString()
|
|
457
|
+
};
|
|
458
|
+
}, readRecordFile = (path) => coerceRecord(readJsonFile(path)), compareInstances = (left, right) => {
|
|
459
|
+
const leftPort = left.port ?? Number.MAX_SAFE_INTEGER;
|
|
460
|
+
const rightPort = right.port ?? Number.MAX_SAFE_INTEGER;
|
|
461
|
+
if (leftPort !== rightPort)
|
|
462
|
+
return leftPort - rightPort;
|
|
463
|
+
return left.name.localeCompare(right.name);
|
|
464
|
+
}, deregisterInstance = (pid) => {
|
|
465
|
+
registeredPids.delete(pid);
|
|
466
|
+
removeInstanceFilesSync(pid);
|
|
467
|
+
}, listLiveInstances = () => {
|
|
468
|
+
const directory = instanceRegistryDir();
|
|
469
|
+
let entries;
|
|
470
|
+
try {
|
|
471
|
+
entries = readdirSync(directory);
|
|
472
|
+
} catch {
|
|
473
|
+
return [];
|
|
474
|
+
}
|
|
475
|
+
const live = entries.filter((entry) => entry.endsWith(".json")).map((entry) => readRecordFile(join4(directory, entry))).filter((record) => record !== null).filter((record) => {
|
|
476
|
+
if (isProcessAlive2(record.pid))
|
|
477
|
+
return true;
|
|
478
|
+
removeInstanceFilesSync(record.pid);
|
|
479
|
+
return false;
|
|
480
|
+
});
|
|
481
|
+
return live.sort(compareInstances);
|
|
482
|
+
}, registerInstance = (record) => {
|
|
483
|
+
mkdirSync3(instanceRegistryDir(), { recursive: true });
|
|
484
|
+
writeFileSync3(instanceFilePath(record.pid), JSON.stringify(record, null, 2));
|
|
485
|
+
registeredPids.add(record.pid);
|
|
486
|
+
registerExitHandlerOnce();
|
|
487
|
+
return record;
|
|
488
|
+
}, resolveProjectName = (cwd) => {
|
|
489
|
+
const parsed = readJsonFile(join4(cwd, "package.json"));
|
|
490
|
+
if (parsed !== null && typeof parsed === "object" && typeof parsed.name === "string" && parsed.name.trim().length > 0) {
|
|
491
|
+
return parsed.name;
|
|
492
|
+
}
|
|
493
|
+
return basename(cwd) || "unknown";
|
|
494
|
+
}, updateInstance = (pid, updates) => {
|
|
495
|
+
const current = readRecordFile(instanceFilePath(pid));
|
|
496
|
+
if (!current)
|
|
497
|
+
return;
|
|
498
|
+
const next = { ...current, ...updates };
|
|
499
|
+
try {
|
|
500
|
+
writeFileSync3(instanceFilePath(pid), JSON.stringify(next, null, 2));
|
|
501
|
+
} catch {}
|
|
502
|
+
};
|
|
503
|
+
var init_instanceRegistry = __esm(() => {
|
|
504
|
+
registeredPids = new Set;
|
|
505
|
+
SOURCES = ["dev", "standalone", "start", "workspace"];
|
|
506
|
+
});
|
|
507
|
+
|
|
394
508
|
// src/utils/loadConfig.ts
|
|
395
509
|
import { resolve } from "path";
|
|
396
510
|
var RESERVED_TOP_LEVEL_KEYS, isObject = (value) => typeof value === "object" && value !== null, isCommandService = (service) => service.kind === "command" || Array.isArray(service.command), isServiceCandidate = (value) => isObject(value) && (typeof value.entry === "string" || Array.isArray(value.command)), isWorkspaceConfig = (config) => {
|
|
@@ -495,11 +609,11 @@ var init_loadConfig = __esm(() => {
|
|
|
495
609
|
// src/cli/utils.ts
|
|
496
610
|
var {$ } = globalThis.Bun;
|
|
497
611
|
import { execSync } from "child_process";
|
|
498
|
-
import { existsSync as existsSync3, readFileSync as
|
|
612
|
+
import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
|
|
499
613
|
import { resolve as resolve2 } from "path";
|
|
500
614
|
var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backend/server.ts", isWSLEnvironment = () => {
|
|
501
615
|
try {
|
|
502
|
-
const release =
|
|
616
|
+
const release = readFileSync5("/proc/version", "utf-8");
|
|
503
617
|
return /microsoft|wsl/i.test(release);
|
|
504
618
|
} catch {
|
|
505
619
|
return false;
|
|
@@ -532,6 +646,32 @@ var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backe
|
|
|
532
646
|
return;
|
|
533
647
|
}
|
|
534
648
|
console.log(`\x1B[2m${formatTimestamp()}\x1B[0m \x1B[33m[cli]\x1B[0m \x1B[33m${message}\x1B[0m`);
|
|
649
|
+
}, openUrlInBrowser = (url, onError) => {
|
|
650
|
+
if (process.env.ABSOLUTE_NO_OPEN)
|
|
651
|
+
return false;
|
|
652
|
+
const { platform: platform2 } = process;
|
|
653
|
+
const isWSL = platform2 === "linux" && isWSLEnvironment();
|
|
654
|
+
let command;
|
|
655
|
+
if (isWSL) {
|
|
656
|
+
command = "cmd.exe";
|
|
657
|
+
} else if (platform2 === "darwin") {
|
|
658
|
+
command = "open";
|
|
659
|
+
} else if (platform2 === "win32") {
|
|
660
|
+
command = "start";
|
|
661
|
+
} else {
|
|
662
|
+
command = "xdg-open";
|
|
663
|
+
}
|
|
664
|
+
const commandArgs = isWSL ? ["/c", "start", url] : [url];
|
|
665
|
+
try {
|
|
666
|
+
Bun.spawn([command, ...commandArgs], {
|
|
667
|
+
stderr: "ignore",
|
|
668
|
+
stdout: "ignore"
|
|
669
|
+
});
|
|
670
|
+
return true;
|
|
671
|
+
} catch {
|
|
672
|
+
onError?.(`Could not open browser automatically. Visit ${url}`);
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
535
675
|
}, printHelp = (subject = "server") => {
|
|
536
676
|
const title = subject === "workspace" ? "workspace" : subject;
|
|
537
677
|
console.log("");
|
|
@@ -592,15 +732,15 @@ __export(exports_devCert, {
|
|
|
592
732
|
import {
|
|
593
733
|
copyFileSync,
|
|
594
734
|
existsSync as existsSync4,
|
|
595
|
-
mkdirSync as
|
|
596
|
-
readFileSync as
|
|
735
|
+
mkdirSync as mkdirSync4,
|
|
736
|
+
readFileSync as readFileSync6,
|
|
597
737
|
rmSync
|
|
598
738
|
} from "fs";
|
|
599
739
|
import { platform as platform2 } from "os";
|
|
600
|
-
import { join as
|
|
740
|
+
import { join as join5 } from "path";
|
|
601
741
|
var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[36m[dev]\x1B[0m ${msg}`), devWarn = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[33m[dev]\x1B[0m \x1B[33m${msg}\x1B[0m`), certFilesExist = () => existsSync4(CERT_PATH) && existsSync4(KEY_PATH), isCertExpired = () => {
|
|
602
742
|
try {
|
|
603
|
-
const certPem =
|
|
743
|
+
const certPem = readFileSync6(CERT_PATH, "utf-8");
|
|
604
744
|
const proc = Bun.spawnSync(["openssl", "x509", "-enddate", "-noout"], {
|
|
605
745
|
stdin: new TextEncoder().encode(certPem)
|
|
606
746
|
});
|
|
@@ -669,7 +809,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
|
|
|
669
809
|
generateSelfSigned();
|
|
670
810
|
}
|
|
671
811
|
}, ensureDevCert = () => {
|
|
672
|
-
|
|
812
|
+
mkdirSync4(CERT_DIR, { recursive: true });
|
|
673
813
|
if (hasCert()) {
|
|
674
814
|
return { cert: CERT_PATH, key: KEY_PATH };
|
|
675
815
|
}
|
|
@@ -689,8 +829,8 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
|
|
|
689
829
|
return null;
|
|
690
830
|
try {
|
|
691
831
|
return {
|
|
692
|
-
cert:
|
|
693
|
-
key:
|
|
832
|
+
cert: readFileSync6(paths.cert, "utf-8"),
|
|
833
|
+
key: readFileSync6(paths.key, "utf-8")
|
|
694
834
|
};
|
|
695
835
|
} catch {
|
|
696
836
|
return null;
|
|
@@ -786,7 +926,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
|
|
|
786
926
|
if (platform2() !== "linux")
|
|
787
927
|
return false;
|
|
788
928
|
try {
|
|
789
|
-
return /microsoft|wsl/i.test(
|
|
929
|
+
return /microsoft|wsl/i.test(readFileSync6("/proc/version", "utf-8"));
|
|
790
930
|
} catch {
|
|
791
931
|
return false;
|
|
792
932
|
}
|
|
@@ -809,13 +949,13 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
|
|
|
809
949
|
const caRoot = mkcertCaRoot();
|
|
810
950
|
if (!caRoot)
|
|
811
951
|
return false;
|
|
812
|
-
const rootCa =
|
|
952
|
+
const rootCa = join5(caRoot, "rootCA.pem");
|
|
813
953
|
if (!existsSync4(rootCa))
|
|
814
954
|
return false;
|
|
815
955
|
const winTemp = windowsTempDir();
|
|
816
956
|
if (!winTemp)
|
|
817
957
|
return false;
|
|
818
|
-
const staged =
|
|
958
|
+
const staged = join5(winTemp, "absolutejs-mkcert-rootCA.crt");
|
|
819
959
|
try {
|
|
820
960
|
copyFileSync(rootCa, staged);
|
|
821
961
|
} catch {
|
|
@@ -851,7 +991,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
|
|
|
851
991
|
devLog("Trusted the local CA in the Windows store \u2014 Chrome/Edge on Windows now accept dev HTTPS");
|
|
852
992
|
} else {
|
|
853
993
|
const caRoot = mkcertCaRoot();
|
|
854
|
-
const hint = caRoot ? toWindowsPath(
|
|
994
|
+
const hint = caRoot ? toWindowsPath(join5(caRoot, "rootCA.pem")) : null;
|
|
855
995
|
devWarn("Could not auto-trust the local CA on Windows; Windows browsers may warn.");
|
|
856
996
|
if (hint) {
|
|
857
997
|
console.log(` Run in PowerShell: Import-Certificate -FilePath "${hint}" -CertStoreLocation Cert:\\CurrentUser\\Root`);
|
|
@@ -860,16 +1000,16 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
|
|
|
860
1000
|
}
|
|
861
1001
|
rmSync(CERT_PATH, { force: true });
|
|
862
1002
|
rmSync(KEY_PATH, { force: true });
|
|
863
|
-
|
|
1003
|
+
mkdirSync4(CERT_DIR, { recursive: true });
|
|
864
1004
|
generateWithMkcert();
|
|
865
1005
|
console.log("");
|
|
866
1006
|
devLog("mkcert installed \u2014 HTTPS certificates are now locally trusted");
|
|
867
1007
|
return true;
|
|
868
1008
|
};
|
|
869
1009
|
var init_devCert = __esm(() => {
|
|
870
|
-
CERT_DIR =
|
|
871
|
-
CERT_PATH =
|
|
872
|
-
KEY_PATH =
|
|
1010
|
+
CERT_DIR = join5(process.cwd(), ".absolutejs");
|
|
1011
|
+
CERT_PATH = join5(CERT_DIR, "cert.pem");
|
|
1012
|
+
KEY_PATH = join5(CERT_DIR, "key.pem");
|
|
873
1013
|
});
|
|
874
1014
|
|
|
875
1015
|
// src/core/prerender.ts
|
|
@@ -882,15 +1022,15 @@ __export(exports_prerender, {
|
|
|
882
1022
|
prerender: () => prerender,
|
|
883
1023
|
PRERENDER_BYPASS_HEADER: () => PRERENDER_BYPASS_HEADER
|
|
884
1024
|
});
|
|
885
|
-
import { mkdirSync as
|
|
886
|
-
import { join as
|
|
1025
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync10 } from "fs";
|
|
1026
|
+
import { join as join7 } from "path";
|
|
887
1027
|
var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_TIMEOUT_MS = 30000, PRERENDER_BYPASS_HEADER = "X-Absolute-Prerender-Bypass", routeToFilename = (route) => route === "/" ? "index.html" : `${route.slice(1).replace(/\//g, "-")}.html`, writeTimestamp = async (htmlPath) => {
|
|
888
1028
|
const metaPath = htmlPath.replace(/\.html$/, ".meta");
|
|
889
1029
|
await Bun.write(metaPath, String(Date.now()));
|
|
890
1030
|
}, readTimestamp = (htmlPath) => {
|
|
891
1031
|
const metaPath = htmlPath.replace(/\.html$/, ".meta");
|
|
892
1032
|
try {
|
|
893
|
-
const content =
|
|
1033
|
+
const content = readFileSync10(metaPath, "utf-8");
|
|
894
1034
|
return Number(content) || 0;
|
|
895
1035
|
} catch {
|
|
896
1036
|
return 0;
|
|
@@ -949,7 +1089,7 @@ var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_
|
|
|
949
1089
|
return false;
|
|
950
1090
|
const html = await res.text();
|
|
951
1091
|
const fileName = routeToFilename(route);
|
|
952
|
-
const filePath =
|
|
1092
|
+
const filePath = join7(prerenderDir, fileName);
|
|
953
1093
|
await Bun.write(filePath, html);
|
|
954
1094
|
await writeTimestamp(filePath);
|
|
955
1095
|
return true;
|
|
@@ -975,14 +1115,14 @@ var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_
|
|
|
975
1115
|
}
|
|
976
1116
|
const html = await res.text();
|
|
977
1117
|
const fileName = routeToFilename(route);
|
|
978
|
-
const filePath =
|
|
1118
|
+
const filePath = join7(prerenderDir, fileName);
|
|
979
1119
|
await Bun.write(filePath, html);
|
|
980
1120
|
await writeTimestamp(filePath);
|
|
981
1121
|
result.routes.set(route, filePath);
|
|
982
1122
|
log?.(` Pre-rendered ${route} \u2192 ${fileName} (${html.length} bytes)`);
|
|
983
1123
|
}, prerender = async (port, outDir, staticConfig, log) => {
|
|
984
|
-
const prerenderDir =
|
|
985
|
-
|
|
1124
|
+
const prerenderDir = join7(outDir, "_prerendered");
|
|
1125
|
+
mkdirSync5(prerenderDir, { recursive: true });
|
|
986
1126
|
const baseUrl = `http://localhost:${port}`;
|
|
987
1127
|
let routes;
|
|
988
1128
|
if (staticConfig.routes === "all") {
|
|
@@ -1138,7 +1278,7 @@ var init_nativeRewrite = __esm(() => {
|
|
|
1138
1278
|
|
|
1139
1279
|
// src/build/rewriteImportsPlugin.ts
|
|
1140
1280
|
import { readdir } from "fs/promises";
|
|
1141
|
-
import { join as
|
|
1281
|
+
import { join as join8 } from "path";
|
|
1142
1282
|
var escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), jsRewriteImports = (content, replacements) => {
|
|
1143
1283
|
let result = content;
|
|
1144
1284
|
for (const [specifier, webPath] of replacements) {
|
|
@@ -1216,7 +1356,7 @@ ${content}`;
|
|
|
1216
1356
|
const entries = await readdir(dir);
|
|
1217
1357
|
for (const entry of entries) {
|
|
1218
1358
|
if (entry.endsWith(".js"))
|
|
1219
|
-
allFiles.push(
|
|
1359
|
+
allFiles.push(join8(dir, entry));
|
|
1220
1360
|
}
|
|
1221
1361
|
} catch {}
|
|
1222
1362
|
}
|
|
@@ -1270,86 +1410,837 @@ var rewriteImports = async (outputPaths, vendorPaths) => {
|
|
|
1270
1410
|
return;
|
|
1271
1411
|
throw err;
|
|
1272
1412
|
}
|
|
1273
|
-
const rewritten = rewriteImportsInContent(original, vendorPaths);
|
|
1274
|
-
if (rewritten === original)
|
|
1413
|
+
const rewritten = rewriteImportsInContent(original, vendorPaths);
|
|
1414
|
+
if (rewritten === original)
|
|
1415
|
+
return;
|
|
1416
|
+
try {
|
|
1417
|
+
await Bun.write(filePath, rewritten);
|
|
1418
|
+
} catch (err) {
|
|
1419
|
+
const code = err.code;
|
|
1420
|
+
if (code === "ENOENT")
|
|
1421
|
+
return;
|
|
1422
|
+
throw err;
|
|
1423
|
+
}
|
|
1424
|
+
}));
|
|
1425
|
+
}, rewriteVendorDirectories2;
|
|
1426
|
+
var init_rewriteImports = __esm(() => {
|
|
1427
|
+
init_rewriteImportsPlugin();
|
|
1428
|
+
rewriteVendorDirectories2 = rewriteVendorDirectories;
|
|
1429
|
+
});
|
|
1430
|
+
|
|
1431
|
+
// src/cli/tuiPrimitives.ts
|
|
1432
|
+
import { openSync as openSync2 } from "fs";
|
|
1433
|
+
import { ReadStream as ReadStream2 } from "tty";
|
|
1434
|
+
var ANSI_REGEX, trySetRawMode2 = () => {
|
|
1435
|
+
if (typeof process.stdin.setRawMode !== "function") {
|
|
1436
|
+
return null;
|
|
1437
|
+
}
|
|
1438
|
+
try {
|
|
1439
|
+
process.stdin.setRawMode(true);
|
|
1440
|
+
} catch {
|
|
1441
|
+
return null;
|
|
1442
|
+
}
|
|
1443
|
+
return process.stdin;
|
|
1444
|
+
}, splitLongWord = (word, width) => {
|
|
1445
|
+
const parts = [];
|
|
1446
|
+
for (let index = 0;index < word.length; index += width) {
|
|
1447
|
+
parts.push(word.slice(index, index + width));
|
|
1448
|
+
}
|
|
1449
|
+
return parts;
|
|
1450
|
+
}, appendWrappedWord = (lines, current, word, width) => {
|
|
1451
|
+
if (current.length === 0) {
|
|
1452
|
+
if (word.length <= width)
|
|
1453
|
+
return word;
|
|
1454
|
+
lines.push(...splitLongWord(word, width));
|
|
1455
|
+
return "";
|
|
1456
|
+
}
|
|
1457
|
+
const next = `${current} ${word}`;
|
|
1458
|
+
if (next.length <= width)
|
|
1459
|
+
return next;
|
|
1460
|
+
lines.push(current);
|
|
1461
|
+
if (word.length <= width)
|
|
1462
|
+
return word;
|
|
1463
|
+
lines.push(...splitLongWord(word, width));
|
|
1464
|
+
return "";
|
|
1465
|
+
}, wrapLine = (line, width) => {
|
|
1466
|
+
if (line.length === 0)
|
|
1467
|
+
return [""];
|
|
1468
|
+
if (line.length <= width)
|
|
1469
|
+
return [line];
|
|
1470
|
+
const lines = [];
|
|
1471
|
+
let current = "";
|
|
1472
|
+
for (const word of line.split(/\s+/)) {
|
|
1473
|
+
current = appendWrappedWord(lines, current, word, width);
|
|
1474
|
+
}
|
|
1475
|
+
if (current.length > 0)
|
|
1476
|
+
lines.push(current);
|
|
1477
|
+
return lines;
|
|
1478
|
+
}, ANSI_ESCAPE_PREFIX = "\x1B[", colors, ESCAPE = "\x1B", appendRightEdge = (value, width, marker) => {
|
|
1479
|
+
if (width <= 0) {
|
|
1480
|
+
return "";
|
|
1481
|
+
}
|
|
1482
|
+
return `${padLine(value, Math.max(0, width - 1))}${marker}`;
|
|
1483
|
+
}, formatTimestamp2 = () => new Date().toLocaleTimeString([], {
|
|
1484
|
+
hour: "numeric",
|
|
1485
|
+
hour12: true,
|
|
1486
|
+
minute: "2-digit",
|
|
1487
|
+
second: "2-digit"
|
|
1488
|
+
}), isPartialEscapeSequence = (value) => {
|
|
1489
|
+
if (!value.startsWith(ANSI_ESCAPE_PREFIX)) {
|
|
1490
|
+
return false;
|
|
1491
|
+
}
|
|
1492
|
+
return Array.from(value.slice(ANSI_ESCAPE_PREFIX.length)).every((char) => char >= "0" && char <= "9");
|
|
1493
|
+
}, openTtyStream2 = () => {
|
|
1494
|
+
const fromStdin = trySetRawMode2();
|
|
1495
|
+
if (fromStdin) {
|
|
1496
|
+
return fromStdin;
|
|
1497
|
+
}
|
|
1498
|
+
try {
|
|
1499
|
+
const ttyStream = new ReadStream2(openSync2("/dev/tty", "r"));
|
|
1500
|
+
ttyStream.setRawMode(true);
|
|
1501
|
+
return ttyStream;
|
|
1502
|
+
} catch {
|
|
1503
|
+
return null;
|
|
1504
|
+
}
|
|
1505
|
+
}, padLine = (value, width) => {
|
|
1506
|
+
const plainLength = visibleLength(value);
|
|
1507
|
+
if (plainLength >= width) {
|
|
1508
|
+
return value;
|
|
1509
|
+
}
|
|
1510
|
+
return `${value}${" ".repeat(width - plainLength)}`;
|
|
1511
|
+
}, stripAnsi = (value) => value.replace(ANSI_REGEX, ""), truncateText = (value, width) => {
|
|
1512
|
+
if (width <= 0) {
|
|
1513
|
+
return "";
|
|
1514
|
+
}
|
|
1515
|
+
if (value.length <= width) {
|
|
1516
|
+
return value;
|
|
1517
|
+
}
|
|
1518
|
+
if (width <= 1) {
|
|
1519
|
+
return value.slice(0, width);
|
|
1520
|
+
}
|
|
1521
|
+
return `${value.slice(0, width - 1)}\u2026`;
|
|
1522
|
+
}, visibleLength = (value) => value.replace(ANSI_REGEX, "").length, wrapText = (value, width) => {
|
|
1523
|
+
if (width <= 0) {
|
|
1524
|
+
return [""];
|
|
1525
|
+
}
|
|
1526
|
+
const lines = value.split(`
|
|
1527
|
+
`).flatMap((rawLine) => wrapLine(rawLine.trimEnd(), width));
|
|
1528
|
+
return lines.length > 0 ? lines : [""];
|
|
1529
|
+
};
|
|
1530
|
+
var init_tuiPrimitives = __esm(() => {
|
|
1531
|
+
init_constants();
|
|
1532
|
+
ANSI_REGEX = new RegExp(`${String.fromCharCode(ANSI_ESCAPE_CODE)}\\[[0-?]*[ -/]*[@-~]`, "g");
|
|
1533
|
+
colors = {
|
|
1534
|
+
bold: "\x1B[1m",
|
|
1535
|
+
cyan: "\x1B[36m",
|
|
1536
|
+
dim: "\x1B[2m",
|
|
1537
|
+
green: "\x1B[32m",
|
|
1538
|
+
red: "\x1B[31m",
|
|
1539
|
+
reset: "\x1B[0m",
|
|
1540
|
+
yellow: "\x1B[33m"
|
|
1541
|
+
};
|
|
1542
|
+
});
|
|
1543
|
+
|
|
1544
|
+
// src/cli/scripts/build.ts
|
|
1545
|
+
var exports_build = {};
|
|
1546
|
+
__export(exports_build, {
|
|
1547
|
+
build: () => build
|
|
1548
|
+
});
|
|
1549
|
+
import { resolve as resolve9 } from "path";
|
|
1550
|
+
var cliTag3 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, tryImportBuild2 = async (candidate) => {
|
|
1551
|
+
try {
|
|
1552
|
+
const mod = await import(candidate);
|
|
1553
|
+
const buildFn = mod.build;
|
|
1554
|
+
return buildFn;
|
|
1555
|
+
} catch {
|
|
1556
|
+
return null;
|
|
1557
|
+
}
|
|
1558
|
+
}, resolveBuildModule2 = async (candidates) => {
|
|
1559
|
+
const [candidate, ...remaining] = candidates;
|
|
1560
|
+
if (!candidate) {
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1563
|
+
const mod = await tryImportBuild2(candidate);
|
|
1564
|
+
if (mod) {
|
|
1565
|
+
return mod;
|
|
1566
|
+
}
|
|
1567
|
+
return resolveBuildModule2(remaining);
|
|
1568
|
+
}, build = async (outdir, configPath2) => {
|
|
1569
|
+
const resolvedOutdir = resolve9(outdir ?? "build");
|
|
1570
|
+
const buildStart = performance.now();
|
|
1571
|
+
process.stdout.write(cliTag3("\x1B[36m", "Building assets"));
|
|
1572
|
+
const buildConfig = await loadConfig(configPath2);
|
|
1573
|
+
buildConfig.buildDirectory = resolvedOutdir;
|
|
1574
|
+
buildConfig.mode = "production";
|
|
1575
|
+
try {
|
|
1576
|
+
const buildApp = await resolveBuildModule2([
|
|
1577
|
+
resolve9(import.meta.dir, "..", "..", "core", "build"),
|
|
1578
|
+
resolve9(import.meta.dir, "..", "build")
|
|
1579
|
+
]);
|
|
1580
|
+
if (!buildApp)
|
|
1581
|
+
throw new Error("Could not locate build module");
|
|
1582
|
+
await buildApp(buildConfig);
|
|
1583
|
+
} catch (err) {
|
|
1584
|
+
sendTelemetryEvent("build:error", {
|
|
1585
|
+
durationMs: Math.round(performance.now() - buildStart)
|
|
1586
|
+
});
|
|
1587
|
+
console.error(cliTag3("\x1B[31m", "Build step failed."));
|
|
1588
|
+
console.error(err);
|
|
1589
|
+
process.exit(1);
|
|
1590
|
+
}
|
|
1591
|
+
sendTelemetryEvent("build:complete", {
|
|
1592
|
+
durationMs: Math.round(performance.now() - buildStart)
|
|
1593
|
+
});
|
|
1594
|
+
console.log(` \x1B[2m(${getDurationString(performance.now() - buildStart)})\x1B[0m`);
|
|
1595
|
+
};
|
|
1596
|
+
var init_build = __esm(() => {
|
|
1597
|
+
init_getDurationString();
|
|
1598
|
+
init_loadConfig();
|
|
1599
|
+
init_startupBanner();
|
|
1600
|
+
init_telemetryEvent();
|
|
1601
|
+
});
|
|
1602
|
+
|
|
1603
|
+
// src/cli/instanceStatus.ts
|
|
1604
|
+
import { createConnection as createConnection2 } from "net";
|
|
1605
|
+
var displayHost = (host) => host === "0.0.0.0" || host === "::" ? "localhost" : host, probePort = (host, port) => {
|
|
1606
|
+
const { promise, resolve: resolve10 } = Promise.withResolvers();
|
|
1607
|
+
const socket = createConnection2({ host: displayHost(host), port });
|
|
1608
|
+
const timeout = setTimeout(() => {
|
|
1609
|
+
socket.destroy();
|
|
1610
|
+
resolve10(false);
|
|
1611
|
+
}, INSTANCE_PROBE_TIMEOUT_MS);
|
|
1612
|
+
socket.once("connect", () => {
|
|
1613
|
+
clearTimeout(timeout);
|
|
1614
|
+
socket.end();
|
|
1615
|
+
resolve10(true);
|
|
1616
|
+
});
|
|
1617
|
+
socket.once("error", () => {
|
|
1618
|
+
clearTimeout(timeout);
|
|
1619
|
+
socket.destroy();
|
|
1620
|
+
resolve10(false);
|
|
1621
|
+
});
|
|
1622
|
+
return promise;
|
|
1623
|
+
}, probeStatus = async (record) => {
|
|
1624
|
+
if (record.port === null) {
|
|
1625
|
+
return "starting";
|
|
1626
|
+
}
|
|
1627
|
+
const reachable = await probePort(record.host, record.port);
|
|
1628
|
+
return reachable ? "ready" : "starting";
|
|
1629
|
+
}, enrichInstances = async (records) => {
|
|
1630
|
+
const now = Date.now();
|
|
1631
|
+
const statuses = await Promise.all(records.map(probeStatus));
|
|
1632
|
+
return records.map((record, index) => ({
|
|
1633
|
+
...record,
|
|
1634
|
+
status: statuses[index] ?? "starting",
|
|
1635
|
+
uptimeMs: Math.max(0, now - Date.parse(record.startedAt)),
|
|
1636
|
+
url: instanceUrl(record)
|
|
1637
|
+
}));
|
|
1638
|
+
}, instanceUrl = (record) => {
|
|
1639
|
+
if (record.port === null)
|
|
1640
|
+
return null;
|
|
1641
|
+
return `${record.https ? "https" : "http"}://${displayHost(record.host)}:${record.port}/`;
|
|
1642
|
+
};
|
|
1643
|
+
var init_instanceStatus = __esm(() => {
|
|
1644
|
+
init_constants();
|
|
1645
|
+
});
|
|
1646
|
+
|
|
1647
|
+
// src/cli/listTui.ts
|
|
1648
|
+
var exports_listTui = {};
|
|
1649
|
+
__export(exports_listTui, {
|
|
1650
|
+
runListTui: () => runListTui
|
|
1651
|
+
});
|
|
1652
|
+
import { spawn } from "child_process";
|
|
1653
|
+
import { closeSync, fstatSync, openSync as openSync3, readSync } from "fs";
|
|
1654
|
+
var TUI_HEADERS, STATUS_INDEX = 5, URL_INDEX = 6, helpLines2, statusLevelColor = (level) => {
|
|
1655
|
+
if (level === "error")
|
|
1656
|
+
return colors.red;
|
|
1657
|
+
if (level === "warn")
|
|
1658
|
+
return colors.yellow;
|
|
1659
|
+
if (level === "success")
|
|
1660
|
+
return colors.green;
|
|
1661
|
+
return colors.cyan;
|
|
1662
|
+
}, statusColor = (status2) => {
|
|
1663
|
+
if (status2 === "ready")
|
|
1664
|
+
return colors.green;
|
|
1665
|
+
if (status2 === "starting")
|
|
1666
|
+
return colors.yellow;
|
|
1667
|
+
return colors.dim;
|
|
1668
|
+
}, instanceRowCells = (instance) => [
|
|
1669
|
+
instance.name,
|
|
1670
|
+
instance.source,
|
|
1671
|
+
instance.port === null ? "-" : String(instance.port),
|
|
1672
|
+
String(instance.pid),
|
|
1673
|
+
getDurationString(instance.uptimeMs),
|
|
1674
|
+
instance.status,
|
|
1675
|
+
instance.url ?? "-"
|
|
1676
|
+
], columnWidths = (allCells) => TUI_HEADERS.map((header, index) => Math.max(visibleLength(header), ...allCells.map((cells) => visibleLength(cells[index] ?? "")))), layoutWidths = (allCells, width) => {
|
|
1677
|
+
const natural = columnWidths(allCells);
|
|
1678
|
+
const gaps = (TUI_HEADERS.length - 1) * LIST_TUI_COLUMN_GAP;
|
|
1679
|
+
const available = width - LIST_TUI_MARKER_WIDTH - gaps;
|
|
1680
|
+
const fixed = natural.reduce((sum, value, index) => index === URL_INDEX ? sum : sum + value, 0);
|
|
1681
|
+
const urlWidth = Math.max(LIST_TUI_MIN_URL_WIDTH, available - fixed);
|
|
1682
|
+
return natural.map((value, index) => index === URL_INDEX ? Math.min(value, urlWidth) : value);
|
|
1683
|
+
}, openReadFd = (path) => {
|
|
1684
|
+
try {
|
|
1685
|
+
return openSync3(path, "r");
|
|
1686
|
+
} catch {
|
|
1687
|
+
return null;
|
|
1688
|
+
}
|
|
1689
|
+
}, readLogTail = (path) => {
|
|
1690
|
+
if (!path)
|
|
1691
|
+
return [];
|
|
1692
|
+
const descriptor = openReadFd(path);
|
|
1693
|
+
if (descriptor === null)
|
|
1694
|
+
return [];
|
|
1695
|
+
try {
|
|
1696
|
+
const { size } = fstatSync(descriptor);
|
|
1697
|
+
const start2 = Math.max(0, size - LIST_LOG_TAIL_MAX_BYTES);
|
|
1698
|
+
const length = size - start2;
|
|
1699
|
+
const buffer = Buffer.alloc(length);
|
|
1700
|
+
readSync(descriptor, buffer, 0, length, start2);
|
|
1701
|
+
return buffer.toString("utf-8").split(`
|
|
1702
|
+
`).filter((line) => line.trim().length > 0);
|
|
1703
|
+
} finally {
|
|
1704
|
+
closeSync(descriptor);
|
|
1705
|
+
}
|
|
1706
|
+
}, driveListTui = async (terminal) => {
|
|
1707
|
+
const { promise, resolve: resolveExit } = Promise.withResolvers();
|
|
1708
|
+
let instances = [];
|
|
1709
|
+
let selectedIndex = 0;
|
|
1710
|
+
let mode = "list";
|
|
1711
|
+
let helpVisible = false;
|
|
1712
|
+
let portBuffer = "";
|
|
1713
|
+
let statusMessage = null;
|
|
1714
|
+
let statusTimer = null;
|
|
1715
|
+
let renderTimer = null;
|
|
1716
|
+
let refreshTimer = null;
|
|
1717
|
+
let escapeBuffer = "";
|
|
1718
|
+
let escapeTimer = null;
|
|
1719
|
+
let disposed = false;
|
|
1720
|
+
let logScrollOffset = 0;
|
|
1721
|
+
let lastLogLineCount = 0;
|
|
1722
|
+
let lastLogViewportHeight = 0;
|
|
1723
|
+
const selectedInstance = () => instances[selectedIndex];
|
|
1724
|
+
const scheduleRender = () => {
|
|
1725
|
+
if (disposed || renderTimer)
|
|
1726
|
+
return;
|
|
1727
|
+
renderTimer = setTimeout(() => {
|
|
1728
|
+
renderTimer = null;
|
|
1729
|
+
render();
|
|
1730
|
+
}, LIST_TUI_RENDER_DEBOUNCE_MS);
|
|
1731
|
+
};
|
|
1732
|
+
const setStatus = (text, level) => {
|
|
1733
|
+
statusMessage = { level, text };
|
|
1734
|
+
if (statusTimer)
|
|
1735
|
+
clearTimeout(statusTimer);
|
|
1736
|
+
statusTimer = setTimeout(() => {
|
|
1737
|
+
statusMessage = null;
|
|
1738
|
+
scheduleRender();
|
|
1739
|
+
}, LIST_TUI_STATUS_MESSAGE_TIMEOUT_MS);
|
|
1740
|
+
scheduleRender();
|
|
1741
|
+
};
|
|
1742
|
+
const refresh = async () => {
|
|
1743
|
+
const previousPid = selectedInstance()?.pid;
|
|
1744
|
+
instances = await enrichInstances(listLiveInstances());
|
|
1745
|
+
const foundIndex = previousPid === undefined ? 0 : instances.findIndex((instance) => instance.pid === previousPid);
|
|
1746
|
+
selectedIndex = foundIndex >= 0 ? foundIndex : Math.min(selectedIndex, Math.max(0, instances.length - 1));
|
|
1747
|
+
scheduleRender();
|
|
1748
|
+
};
|
|
1749
|
+
const signalPid = (pid, signal) => {
|
|
1750
|
+
try {
|
|
1751
|
+
process.kill(-pid, signal);
|
|
1752
|
+
return;
|
|
1753
|
+
} catch {}
|
|
1754
|
+
try {
|
|
1755
|
+
process.kill(pid, signal);
|
|
1756
|
+
} catch {}
|
|
1757
|
+
};
|
|
1758
|
+
const stopSelected = () => {
|
|
1759
|
+
const instance = selectedInstance();
|
|
1760
|
+
if (!instance)
|
|
1761
|
+
return;
|
|
1762
|
+
signalPid(instance.controllerPid, "SIGTERM");
|
|
1763
|
+
const message = instance.source === "workspace" ? `Stopping ${instance.name}'s workspace (pid ${instance.controllerPid}) \u2014 all its services` : `Stopped ${instance.name} (pid ${instance.controllerPid})`;
|
|
1764
|
+
setStatus(message, "success");
|
|
1765
|
+
refresh();
|
|
1766
|
+
};
|
|
1767
|
+
const restartSelected = () => {
|
|
1768
|
+
const instance = selectedInstance();
|
|
1769
|
+
if (!instance)
|
|
1770
|
+
return;
|
|
1771
|
+
if (instance.source === "workspace") {
|
|
1772
|
+
setStatus(`${instance.name} is managed by its workspace \u2014 restart the workspace itself.`, "warn");
|
|
1773
|
+
return;
|
|
1774
|
+
}
|
|
1775
|
+
const [command, ...commandArgs] = instance.command;
|
|
1776
|
+
if (!command) {
|
|
1777
|
+
setStatus(`Cannot restart ${instance.name}: no launch command recorded.`, "warn");
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
signalPid(instance.controllerPid, "SIGTERM");
|
|
1781
|
+
const child = spawn(command, commandArgs, {
|
|
1782
|
+
cwd: instance.cwd,
|
|
1783
|
+
detached: true,
|
|
1784
|
+
stdio: "ignore"
|
|
1785
|
+
});
|
|
1786
|
+
child.unref();
|
|
1787
|
+
setStatus(`Restarting ${instance.name}\u2026`, "info");
|
|
1788
|
+
refresh();
|
|
1789
|
+
};
|
|
1790
|
+
const openSelected = () => {
|
|
1791
|
+
const instance = selectedInstance();
|
|
1792
|
+
if (!instance)
|
|
1793
|
+
return;
|
|
1794
|
+
if (!instance.url) {
|
|
1795
|
+
setStatus(`${instance.name} has no URL yet.`, "warn");
|
|
1796
|
+
return;
|
|
1797
|
+
}
|
|
1798
|
+
openUrlInBrowser(instance.url, (message) => setStatus(message, "warn"));
|
|
1799
|
+
setStatus(`Opening ${instance.url}`, "info");
|
|
1800
|
+
};
|
|
1801
|
+
const stopAll = () => {
|
|
1802
|
+
const count = instances.length;
|
|
1803
|
+
instances.forEach((instance) => signalPid(instance.pid, "SIGTERM"));
|
|
1804
|
+
setStatus(`Stopped ${count} server${count === 1 ? "" : "s"}.`, "success");
|
|
1805
|
+
refresh();
|
|
1806
|
+
};
|
|
1807
|
+
const freePort = (value) => {
|
|
1808
|
+
const port = Number(value);
|
|
1809
|
+
if (!Number.isInteger(port) || port <= 0) {
|
|
1810
|
+
setStatus(`Invalid port: ${value}`, "error");
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1813
|
+
let killed = false;
|
|
1814
|
+
killStaleProcesses(port, (message) => {
|
|
1815
|
+
killed = true;
|
|
1816
|
+
setStatus(message, "warn");
|
|
1817
|
+
});
|
|
1818
|
+
if (!killed)
|
|
1819
|
+
setStatus(`Nothing is listening on port ${port}.`, "info");
|
|
1820
|
+
refresh();
|
|
1821
|
+
};
|
|
1822
|
+
const moveSelection = (direction) => {
|
|
1823
|
+
if (instances.length === 0)
|
|
1824
|
+
return;
|
|
1825
|
+
const delta = direction === "up" ? UNFOUND_INDEX : 1;
|
|
1826
|
+
selectedIndex = Math.max(0, Math.min(instances.length - 1, selectedIndex + delta));
|
|
1827
|
+
logScrollOffset = 0;
|
|
1828
|
+
scheduleRender();
|
|
1829
|
+
};
|
|
1830
|
+
const scrollLogs = (direction) => {
|
|
1831
|
+
const maxOffset = Math.max(0, lastLogLineCount - lastLogViewportHeight);
|
|
1832
|
+
const pageSize = Math.max(1, lastLogViewportHeight - 1);
|
|
1833
|
+
if (direction === "up") {
|
|
1834
|
+
logScrollOffset = Math.min(maxOffset, logScrollOffset + 1);
|
|
1835
|
+
} else if (direction === "down") {
|
|
1836
|
+
logScrollOffset = Math.max(0, logScrollOffset - 1);
|
|
1837
|
+
} else if (direction === "pageUp") {
|
|
1838
|
+
logScrollOffset = Math.min(maxOffset, logScrollOffset + pageSize);
|
|
1839
|
+
} else {
|
|
1840
|
+
logScrollOffset = Math.max(0, logScrollOffset - pageSize);
|
|
1841
|
+
}
|
|
1842
|
+
scheduleRender();
|
|
1843
|
+
};
|
|
1844
|
+
const dispose = () => {
|
|
1845
|
+
if (disposed)
|
|
1846
|
+
return;
|
|
1847
|
+
disposed = true;
|
|
1848
|
+
if (renderTimer)
|
|
1849
|
+
clearTimeout(renderTimer);
|
|
1850
|
+
if (statusTimer)
|
|
1851
|
+
clearTimeout(statusTimer);
|
|
1852
|
+
if (escapeTimer)
|
|
1853
|
+
clearTimeout(escapeTimer);
|
|
1854
|
+
if (refreshTimer)
|
|
1855
|
+
clearInterval(refreshTimer);
|
|
1856
|
+
process.stdout.off("resize", onResize);
|
|
1857
|
+
terminal.off("data", onData);
|
|
1858
|
+
if (terminal.setRawMode)
|
|
1859
|
+
terminal.setRawMode(false);
|
|
1860
|
+
if (terminal !== process.stdin)
|
|
1861
|
+
terminal.destroy();
|
|
1862
|
+
process.stdout.write("\x1B[?25h\x1B[?1049l");
|
|
1863
|
+
};
|
|
1864
|
+
const quit = () => {
|
|
1865
|
+
dispose();
|
|
1866
|
+
resolveExit();
|
|
1867
|
+
};
|
|
1868
|
+
const listActions = new Map([
|
|
1869
|
+
["f", () => enterPortMode()],
|
|
1870
|
+
["h", () => toggleHelp()],
|
|
1871
|
+
["j", () => moveSelection("down")],
|
|
1872
|
+
["k", () => moveSelection("up")],
|
|
1873
|
+
["o", () => openSelected()],
|
|
1874
|
+
["q", () => quit()],
|
|
1875
|
+
["r", () => restartSelected()],
|
|
1876
|
+
["s", () => stopSelected()],
|
|
1877
|
+
["x", () => enterConfirmMode()],
|
|
1878
|
+
["?", () => toggleHelp()]
|
|
1879
|
+
]);
|
|
1880
|
+
const toggleHelp = () => {
|
|
1881
|
+
helpVisible = !helpVisible;
|
|
1882
|
+
scheduleRender();
|
|
1883
|
+
};
|
|
1884
|
+
const enterPortMode = () => {
|
|
1885
|
+
mode = "port";
|
|
1886
|
+
portBuffer = "";
|
|
1887
|
+
scheduleRender();
|
|
1888
|
+
};
|
|
1889
|
+
const enterConfirmMode = () => {
|
|
1890
|
+
if (instances.length === 0)
|
|
1891
|
+
return;
|
|
1892
|
+
mode = "confirm";
|
|
1893
|
+
scheduleRender();
|
|
1894
|
+
};
|
|
1895
|
+
const handleListChar = (char) => {
|
|
1896
|
+
const action = listActions.get(char.toLowerCase());
|
|
1897
|
+
if (action)
|
|
1898
|
+
action();
|
|
1899
|
+
};
|
|
1900
|
+
const handlePortChar = (char) => {
|
|
1901
|
+
if (char === "\r" || char === `
|
|
1902
|
+
`) {
|
|
1903
|
+
const value = portBuffer;
|
|
1904
|
+
mode = "list";
|
|
1905
|
+
portBuffer = "";
|
|
1906
|
+
freePort(value);
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1909
|
+
if (char === "\x7F" || char === "\b") {
|
|
1910
|
+
portBuffer = portBuffer.slice(0, EXCLUDE_LAST_OFFSET);
|
|
1911
|
+
scheduleRender();
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
if (char >= "0" && char <= "9") {
|
|
1915
|
+
portBuffer += char;
|
|
1916
|
+
scheduleRender();
|
|
1917
|
+
}
|
|
1918
|
+
};
|
|
1919
|
+
const handleConfirmChar = (char) => {
|
|
1920
|
+
mode = "list";
|
|
1921
|
+
if (char.toLowerCase() === "y") {
|
|
1922
|
+
stopAll();
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1925
|
+
scheduleRender();
|
|
1926
|
+
};
|
|
1927
|
+
const clearEscapeTimer = () => {
|
|
1928
|
+
if (!escapeTimer)
|
|
1929
|
+
return;
|
|
1930
|
+
clearTimeout(escapeTimer);
|
|
1931
|
+
escapeTimer = null;
|
|
1932
|
+
};
|
|
1933
|
+
const onBareEscape = () => {
|
|
1934
|
+
if (helpVisible) {
|
|
1935
|
+
helpVisible = false;
|
|
1936
|
+
} else if (mode !== "list") {
|
|
1937
|
+
mode = "list";
|
|
1938
|
+
portBuffer = "";
|
|
1939
|
+
}
|
|
1940
|
+
scheduleRender();
|
|
1941
|
+
};
|
|
1942
|
+
const armEscapeTimer = () => {
|
|
1943
|
+
clearEscapeTimer();
|
|
1944
|
+
escapeTimer = setTimeout(() => {
|
|
1945
|
+
escapeTimer = null;
|
|
1946
|
+
escapeBuffer = "";
|
|
1947
|
+
onBareEscape();
|
|
1948
|
+
}, LIST_TUI_ESCAPE_SEQUENCE_TIMEOUT_MS);
|
|
1949
|
+
};
|
|
1950
|
+
const resetEscape = () => {
|
|
1951
|
+
clearEscapeTimer();
|
|
1952
|
+
escapeBuffer = "";
|
|
1953
|
+
};
|
|
1954
|
+
const handleEscapeSequence = (char) => {
|
|
1955
|
+
escapeBuffer += char;
|
|
1956
|
+
if (escapeBuffer === `${ESCAPE}[`) {
|
|
1957
|
+
armEscapeTimer();
|
|
1958
|
+
return;
|
|
1959
|
+
}
|
|
1960
|
+
if (escapeBuffer === `${ESCAPE}[A`) {
|
|
1961
|
+
resetEscape();
|
|
1962
|
+
moveSelection("up");
|
|
1963
|
+
return;
|
|
1964
|
+
}
|
|
1965
|
+
if (escapeBuffer === `${ESCAPE}[B`) {
|
|
1966
|
+
resetEscape();
|
|
1967
|
+
moveSelection("down");
|
|
1968
|
+
return;
|
|
1969
|
+
}
|
|
1970
|
+
if (escapeBuffer === `${ESCAPE}[5~`) {
|
|
1971
|
+
resetEscape();
|
|
1972
|
+
scrollLogs("pageUp");
|
|
1973
|
+
return;
|
|
1974
|
+
}
|
|
1975
|
+
if (escapeBuffer === `${ESCAPE}[6~`) {
|
|
1976
|
+
resetEscape();
|
|
1977
|
+
scrollLogs("pageDown");
|
|
1978
|
+
return;
|
|
1979
|
+
}
|
|
1980
|
+
if (isPartialEscapeSequence(escapeBuffer)) {
|
|
1981
|
+
armEscapeTimer();
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
resetEscape();
|
|
1985
|
+
onBareEscape();
|
|
1986
|
+
};
|
|
1987
|
+
const handleChar = (char) => {
|
|
1988
|
+
if (char === "\x03") {
|
|
1989
|
+
quit();
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
1992
|
+
if (escapeBuffer) {
|
|
1993
|
+
handleEscapeSequence(char);
|
|
1994
|
+
return;
|
|
1995
|
+
}
|
|
1996
|
+
if (char === ESCAPE) {
|
|
1997
|
+
escapeBuffer = ESCAPE;
|
|
1998
|
+
armEscapeTimer();
|
|
1999
|
+
return;
|
|
2000
|
+
}
|
|
2001
|
+
if (mode === "port") {
|
|
2002
|
+
handlePortChar(char);
|
|
1275
2003
|
return;
|
|
1276
|
-
try {
|
|
1277
|
-
await Bun.write(filePath, rewritten);
|
|
1278
|
-
} catch (err) {
|
|
1279
|
-
const code = err.code;
|
|
1280
|
-
if (code === "ENOENT")
|
|
1281
|
-
return;
|
|
1282
|
-
throw err;
|
|
1283
2004
|
}
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
2005
|
+
if (mode === "confirm") {
|
|
2006
|
+
handleConfirmChar(char);
|
|
2007
|
+
return;
|
|
2008
|
+
}
|
|
2009
|
+
handleListChar(char);
|
|
2010
|
+
};
|
|
2011
|
+
const onData = (chunk) => {
|
|
2012
|
+
for (const char of chunk.toString()) {
|
|
2013
|
+
handleChar(char);
|
|
2014
|
+
}
|
|
2015
|
+
};
|
|
2016
|
+
const onResize = () => {
|
|
2017
|
+
scheduleRender();
|
|
2018
|
+
};
|
|
2019
|
+
const titleLine = (width) => {
|
|
2020
|
+
const label = `${instances.length} live`;
|
|
2021
|
+
const left = `${colors.cyan}${colors.bold}ABSOLUTEJS${colors.reset} ${colors.dim}running servers${colors.reset} ${colors.bold}${label}${colors.reset}`;
|
|
2022
|
+
const right = `${colors.dim}${formatTimestamp2()}${colors.reset}`;
|
|
2023
|
+
const gap = Math.max(1, width - visibleLength(left) - visibleLength(right));
|
|
2024
|
+
return `${left}${" ".repeat(gap)}${right}`;
|
|
2025
|
+
};
|
|
2026
|
+
const dividerLine = (width) => `${colors.dim}${"\u2500".repeat(Math.max(width, 1))}${colors.reset}`;
|
|
2027
|
+
const colorizeCell = (cell, index, status2, isSelected, widths) => {
|
|
2028
|
+
const padded = padLine(truncateText(cell, widths[index] ?? 0), widths[index] ?? 0);
|
|
2029
|
+
if (index === STATUS_INDEX) {
|
|
2030
|
+
return `${statusColor(status2)}${padded}${colors.reset}`;
|
|
2031
|
+
}
|
|
2032
|
+
if (index === 0 && isSelected) {
|
|
2033
|
+
return `${colors.cyan}${colors.bold}${padded}${colors.reset}`;
|
|
2034
|
+
}
|
|
2035
|
+
return padded;
|
|
2036
|
+
};
|
|
2037
|
+
const renderInstanceRow = (instance, widths, isSelected) => {
|
|
2038
|
+
const body = instanceRowCells(instance).map((cell, index) => colorizeCell(cell, index, instance.status, isSelected, widths)).join(" ".repeat(LIST_TUI_COLUMN_GAP));
|
|
2039
|
+
const marker = isSelected ? `${colors.cyan}\u276F${colors.reset}` : " ";
|
|
2040
|
+
return `${marker} ${body}`;
|
|
2041
|
+
};
|
|
2042
|
+
const pushInstanceRows = (rows, width) => {
|
|
2043
|
+
if (instances.length === 0) {
|
|
2044
|
+
rows.push(padLine(`${colors.dim}No servers running. Start one with \`absolute dev\`.${colors.reset}`, width));
|
|
2045
|
+
return;
|
|
2046
|
+
}
|
|
2047
|
+
const allCells = instances.map(instanceRowCells);
|
|
2048
|
+
const widths = layoutWidths(allCells, width);
|
|
2049
|
+
const header = TUI_HEADERS.map((label, index) => padLine(label, widths[index] ?? 0)).join(" ".repeat(LIST_TUI_COLUMN_GAP));
|
|
2050
|
+
rows.push(padLine(` ${colors.dim}${header}${colors.reset}`, width));
|
|
2051
|
+
instances.forEach((instance, index) => {
|
|
2052
|
+
rows.push(padLine(renderInstanceRow(instance, widths, index === selectedIndex), width));
|
|
2053
|
+
});
|
|
2054
|
+
};
|
|
2055
|
+
const logContentLines = (width) => {
|
|
2056
|
+
if (helpVisible)
|
|
2057
|
+
return helpLines2;
|
|
2058
|
+
const instance = selectedInstance();
|
|
2059
|
+
if (!instance) {
|
|
2060
|
+
return [`${colors.dim}No server selected.${colors.reset}`];
|
|
2061
|
+
}
|
|
2062
|
+
const lines = readLogTail(instance.logFile);
|
|
2063
|
+
if (lines.length === 0) {
|
|
2064
|
+
return [`${colors.dim}No output yet.${colors.reset}`];
|
|
2065
|
+
}
|
|
2066
|
+
return lines.map((line) => truncateText(stripAnsi(line), Math.max(1, width - 1)));
|
|
2067
|
+
};
|
|
2068
|
+
const pushLogRows = (rows, width, logHeight) => {
|
|
2069
|
+
const contentLines = logContentLines(width);
|
|
2070
|
+
lastLogLineCount = contentLines.length;
|
|
2071
|
+
lastLogViewportHeight = logHeight;
|
|
2072
|
+
const end = helpVisible ? Math.min(contentLines.length, logHeight) : Math.max(0, contentLines.length - logScrollOffset);
|
|
2073
|
+
const start2 = helpVisible ? 0 : Math.max(0, end - logHeight);
|
|
2074
|
+
const visible = contentLines.slice(start2, end);
|
|
2075
|
+
visible.forEach((line) => rows.push(padLine(line, width)));
|
|
2076
|
+
for (let index = visible.length;index < logHeight; index++) {
|
|
2077
|
+
rows.push(" ".repeat(width));
|
|
2078
|
+
}
|
|
2079
|
+
};
|
|
2080
|
+
const footerLine = (width) => {
|
|
2081
|
+
if (helpVisible) {
|
|
2082
|
+
return padLine(`${colors.dim}esc or ? closes help${colors.reset}`, width);
|
|
2083
|
+
}
|
|
2084
|
+
if (mode === "port") {
|
|
2085
|
+
return padLine(`${colors.yellow}free port:${colors.reset} ${portBuffer}\u258C ${colors.dim}enter to kill \xB7 esc to cancel${colors.reset}`, width);
|
|
2086
|
+
}
|
|
2087
|
+
if (mode === "confirm") {
|
|
2088
|
+
return padLine(`${colors.yellow}Stop ALL ${instances.length} servers? ${colors.reset}${colors.bold}y${colors.reset}${colors.dim}/N${colors.reset}`, width);
|
|
2089
|
+
}
|
|
2090
|
+
const hint = "\u2191\u2193 select \xB7 s stop \xB7 r restart \xB7 o open \xB7 f free port \xB7 x stop all \xB7 ? help \xB7 q quit";
|
|
2091
|
+
return padLine(`${colors.dim}${truncateText(hint, width)}${colors.reset}`, width);
|
|
2092
|
+
};
|
|
2093
|
+
const statusLine = (width) => {
|
|
2094
|
+
if (!statusMessage) {
|
|
2095
|
+
return padLine(`${colors.dim}live \xB7 refreshing every ${LIST_WATCH_REFRESH_MS}ms${colors.reset}`, width);
|
|
2096
|
+
}
|
|
2097
|
+
return padLine(`${statusLevelColor(statusMessage.level)}${statusMessage.text}${colors.reset}`, width);
|
|
2098
|
+
};
|
|
2099
|
+
const render = () => {
|
|
2100
|
+
if (disposed)
|
|
2101
|
+
return;
|
|
2102
|
+
const width = process.stdout.columns ?? LIST_TUI_DEFAULT_WIDTH;
|
|
2103
|
+
const height = process.stdout.rows ?? LIST_TUI_DEFAULT_HEIGHT;
|
|
2104
|
+
const rows = [];
|
|
2105
|
+
rows.push(padLine(titleLine(width), width));
|
|
2106
|
+
rows.push(dividerLine(width));
|
|
2107
|
+
pushInstanceRows(rows, width);
|
|
2108
|
+
rows.push(dividerLine(width));
|
|
2109
|
+
const instance = selectedInstance();
|
|
2110
|
+
const logTitle = helpVisible || !instance ? "logs" : `logs \xB7 ${instance.name}${instance.frameworks.length > 0 ? ` \xB7 ${instance.frameworks.join(", ")}` : ""}`;
|
|
2111
|
+
rows.push(padLine(`${colors.bold}${logTitle}${colors.reset}`, width));
|
|
2112
|
+
const fixedHeight = rows.length + LIST_TUI_FOOTER_LINE_COUNT + 1;
|
|
2113
|
+
const logHeight = Math.max(height - fixedHeight, LIST_TUI_MIN_LOG_HEIGHT);
|
|
2114
|
+
pushLogRows(rows, width, logHeight);
|
|
2115
|
+
rows.push(dividerLine(width));
|
|
2116
|
+
rows.push(statusLine(width));
|
|
2117
|
+
rows.push(footerLine(width));
|
|
2118
|
+
const screen = rows.slice(0, height).map((line) => `\x1B[2K${line}`).join(`
|
|
2119
|
+
`);
|
|
2120
|
+
process.stdout.write(`\x1B[H${screen}\x1B[?25l`);
|
|
2121
|
+
};
|
|
2122
|
+
process.on("SIGINT", quit);
|
|
2123
|
+
process.on("SIGTERM", quit);
|
|
2124
|
+
process.stdout.write("\x1B[?1049h\x1B[2J\x1B[H\x1B[?25l");
|
|
2125
|
+
terminal.resume();
|
|
2126
|
+
terminal.on("data", onData);
|
|
2127
|
+
process.stdout.on("resize", onResize);
|
|
2128
|
+
refreshTimer = setInterval(() => {
|
|
2129
|
+
refresh();
|
|
2130
|
+
}, LIST_WATCH_REFRESH_MS);
|
|
2131
|
+
await refresh();
|
|
2132
|
+
render();
|
|
2133
|
+
await promise;
|
|
2134
|
+
}, runListTui = async () => {
|
|
2135
|
+
const input = openTtyStream2();
|
|
2136
|
+
if (!input) {
|
|
2137
|
+
process.stdout.write("Interactive ls requires a TTY. Run `absolute ls` for a snapshot.\n");
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
2140
|
+
await driveListTui(input);
|
|
2141
|
+
};
|
|
2142
|
+
var init_listTui = __esm(() => {
|
|
2143
|
+
init_constants();
|
|
2144
|
+
init_getDurationString();
|
|
2145
|
+
init_instanceRegistry();
|
|
2146
|
+
init_instanceStatus();
|
|
2147
|
+
init_tuiPrimitives();
|
|
2148
|
+
init_utils();
|
|
2149
|
+
TUI_HEADERS = [
|
|
2150
|
+
"NAME",
|
|
2151
|
+
"SOURCE",
|
|
2152
|
+
"PORT",
|
|
2153
|
+
"PID",
|
|
2154
|
+
"UPTIME",
|
|
2155
|
+
"STATUS",
|
|
2156
|
+
"URL"
|
|
2157
|
+
];
|
|
2158
|
+
helpLines2 = [
|
|
2159
|
+
"Hotkeys",
|
|
2160
|
+
" \u2191/\u2193 or j/k Select a server",
|
|
2161
|
+
" s Stop the selected server",
|
|
2162
|
+
" r Restart the selected server",
|
|
2163
|
+
" o Open the selected server in the browser",
|
|
2164
|
+
" f Free a port (kill whatever is listening on it)",
|
|
2165
|
+
" x Stop every listed server",
|
|
2166
|
+
" PgUp/PgDn Scroll the log pane",
|
|
2167
|
+
" ? or h Toggle this help",
|
|
2168
|
+
" q Quit (servers keep running)"
|
|
2169
|
+
];
|
|
1289
2170
|
});
|
|
1290
2171
|
|
|
1291
|
-
// src/cli/scripts/
|
|
1292
|
-
var
|
|
1293
|
-
__export(
|
|
1294
|
-
|
|
2172
|
+
// src/cli/scripts/list.ts
|
|
2173
|
+
var exports_list = {};
|
|
2174
|
+
__export(exports_list, {
|
|
2175
|
+
runList: () => runList
|
|
1295
2176
|
});
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
2177
|
+
var TABLE_HEADERS, statusColor2 = (status2) => {
|
|
2178
|
+
if (status2 === "ready")
|
|
2179
|
+
return colors.green;
|
|
2180
|
+
if (status2 === "starting")
|
|
2181
|
+
return colors.yellow;
|
|
2182
|
+
return colors.dim;
|
|
2183
|
+
}, instanceCells = (instance) => [
|
|
2184
|
+
instance.name,
|
|
2185
|
+
instance.source,
|
|
2186
|
+
instance.port === null ? "-" : String(instance.port),
|
|
2187
|
+
String(instance.pid),
|
|
2188
|
+
getDurationString(instance.uptimeMs),
|
|
2189
|
+
`${statusColor2(instance.status)}${instance.status}${colors.reset}`,
|
|
2190
|
+
instance.url ?? "-"
|
|
2191
|
+
], 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) => {
|
|
2192
|
+
if (instances.length === 0) {
|
|
2193
|
+
process.stdout.write(`${colors.dim}No AbsoluteJS servers are running. Start one with \`absolute dev\`.${colors.reset}
|
|
2194
|
+
`);
|
|
1308
2195
|
return;
|
|
1309
2196
|
}
|
|
1310
|
-
const
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
const buildStart = performance.now();
|
|
1318
|
-
process.stdout.write(cliTag3("\x1B[36m", "Building assets"));
|
|
1319
|
-
const buildConfig = await loadConfig(configPath2);
|
|
1320
|
-
buildConfig.buildDirectory = resolvedOutdir;
|
|
1321
|
-
buildConfig.mode = "production";
|
|
1322
|
-
try {
|
|
1323
|
-
const buildApp = await resolveBuildModule2([
|
|
1324
|
-
resolve9(import.meta.dir, "..", "..", "core", "build"),
|
|
1325
|
-
resolve9(import.meta.dir, "..", "build")
|
|
1326
|
-
]);
|
|
1327
|
-
if (!buildApp)
|
|
1328
|
-
throw new Error("Could not locate build module");
|
|
1329
|
-
await buildApp(buildConfig);
|
|
1330
|
-
} catch (err) {
|
|
1331
|
-
sendTelemetryEvent("build:error", {
|
|
1332
|
-
durationMs: Math.round(performance.now() - buildStart)
|
|
1333
|
-
});
|
|
1334
|
-
console.error(cliTag3("\x1B[31m", "Build step failed."));
|
|
1335
|
-
console.error(err);
|
|
1336
|
-
process.exit(1);
|
|
2197
|
+
const rows = instances.map(instanceCells);
|
|
2198
|
+
const widths = columnWidths2(rows);
|
|
2199
|
+
process.stdout.write(`${colors.dim}${renderRow(TABLE_HEADERS, widths)}${colors.reset}
|
|
2200
|
+
`);
|
|
2201
|
+
for (const cells of rows) {
|
|
2202
|
+
process.stdout.write(`${renderRow(cells, widths)}
|
|
2203
|
+
`);
|
|
1337
2204
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
2205
|
+
}, runList = async (args) => {
|
|
2206
|
+
process.stdout.on("error", (error) => {
|
|
2207
|
+
if (error instanceof Error && "code" in error && error.code === "EPIPE") {
|
|
2208
|
+
process.exit(0);
|
|
2209
|
+
}
|
|
1340
2210
|
});
|
|
1341
|
-
|
|
2211
|
+
if (args.includes("--watch") || args.includes("-w")) {
|
|
2212
|
+
const { runListTui: runListTui2 } = await Promise.resolve().then(() => (init_listTui(), exports_listTui));
|
|
2213
|
+
await runListTui2();
|
|
2214
|
+
return;
|
|
2215
|
+
}
|
|
2216
|
+
const instances = await enrichInstances(listLiveInstances());
|
|
2217
|
+
if (args.includes("--json")) {
|
|
2218
|
+
process.stdout.write(`${JSON.stringify(instances, null, 2)}
|
|
2219
|
+
`);
|
|
2220
|
+
return;
|
|
2221
|
+
}
|
|
2222
|
+
printInstanceTable(instances);
|
|
1342
2223
|
};
|
|
1343
|
-
var
|
|
2224
|
+
var init_list = __esm(() => {
|
|
2225
|
+
init_constants();
|
|
1344
2226
|
init_getDurationString();
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
2227
|
+
init_instanceRegistry();
|
|
2228
|
+
init_instanceStatus();
|
|
2229
|
+
init_tuiPrimitives();
|
|
2230
|
+
TABLE_HEADERS = [
|
|
2231
|
+
"NAME",
|
|
2232
|
+
"SOURCE",
|
|
2233
|
+
"PORT",
|
|
2234
|
+
"PID",
|
|
2235
|
+
"UPTIME",
|
|
2236
|
+
"STATUS",
|
|
2237
|
+
"URL"
|
|
2238
|
+
];
|
|
1348
2239
|
});
|
|
1349
2240
|
|
|
1350
2241
|
// src/build/externalAssetPlugin.ts
|
|
1351
|
-
import { copyFileSync as copyFileSync2, existsSync as existsSync10, mkdirSync as
|
|
1352
|
-
import { basename as
|
|
2242
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync10, mkdirSync as mkdirSync7, statSync } from "fs";
|
|
2243
|
+
import { basename as basename3, dirname as dirname3, join as join10, resolve as resolve10 } from "path";
|
|
1353
2244
|
var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
|
|
1354
2245
|
name: "absolute-external-asset",
|
|
1355
2246
|
setup(bld) {
|
|
@@ -1374,10 +2265,10 @@ var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
|
|
|
1374
2265
|
continue;
|
|
1375
2266
|
if (!statSync(assetPath).isFile())
|
|
1376
2267
|
continue;
|
|
1377
|
-
const targetPath =
|
|
2268
|
+
const targetPath = join10(outDir, basename3(assetPath));
|
|
1378
2269
|
if (existsSync10(targetPath))
|
|
1379
2270
|
continue;
|
|
1380
|
-
|
|
2271
|
+
mkdirSync7(dirname3(targetPath), { recursive: true });
|
|
1381
2272
|
copyFileSync2(assetPath, targetPath);
|
|
1382
2273
|
}
|
|
1383
2274
|
return;
|
|
@@ -1396,15 +2287,15 @@ var {env: env3 } = globalThis.Bun;
|
|
|
1396
2287
|
import {
|
|
1397
2288
|
cpSync,
|
|
1398
2289
|
existsSync as existsSync11,
|
|
1399
|
-
mkdirSync as
|
|
1400
|
-
readdirSync as
|
|
1401
|
-
readFileSync as
|
|
2290
|
+
mkdirSync as mkdirSync8,
|
|
2291
|
+
readdirSync as readdirSync3,
|
|
2292
|
+
readFileSync as readFileSync13,
|
|
1402
2293
|
rmSync as rmSync4,
|
|
1403
2294
|
statSync as statSync2,
|
|
1404
|
-
unlinkSync as
|
|
1405
|
-
writeFileSync as
|
|
2295
|
+
unlinkSync as unlinkSync4,
|
|
2296
|
+
writeFileSync as writeFileSync5
|
|
1406
2297
|
} from "fs";
|
|
1407
|
-
import { basename as
|
|
2298
|
+
import { basename as basename4, dirname as dirname4, join as join11, relative, resolve as resolve11 } from "path";
|
|
1408
2299
|
var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, compileBanner = (version2) => {
|
|
1409
2300
|
const resolvedVersion = version2 || "unknown";
|
|
1410
2301
|
console.log("");
|
|
@@ -1412,14 +2303,14 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1412
2303
|
console.log("");
|
|
1413
2304
|
}, collectFiles2 = (dir) => {
|
|
1414
2305
|
const result = [];
|
|
1415
|
-
let pending =
|
|
2306
|
+
let pending = readdirSync3(dir, { withFileTypes: true });
|
|
1416
2307
|
while (pending.length > 0) {
|
|
1417
2308
|
const entry = pending.pop();
|
|
1418
2309
|
if (!entry)
|
|
1419
2310
|
continue;
|
|
1420
|
-
const fullPath =
|
|
2311
|
+
const fullPath = join11(entry.parentPath, entry.name);
|
|
1421
2312
|
if (entry.isDirectory())
|
|
1422
|
-
pending = pending.concat(
|
|
2313
|
+
pending = pending.concat(readdirSync3(fullPath, { withFileTypes: true }));
|
|
1423
2314
|
else
|
|
1424
2315
|
result.push(fullPath);
|
|
1425
2316
|
}
|
|
@@ -1432,16 +2323,16 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1432
2323
|
return `./${parts.join("/")}`;
|
|
1433
2324
|
}, collectProjectSourceFiles = (dir) => {
|
|
1434
2325
|
const result = [];
|
|
1435
|
-
let pending =
|
|
2326
|
+
let pending = readdirSync3(dir, { withFileTypes: true });
|
|
1436
2327
|
while (pending.length > 0) {
|
|
1437
2328
|
const entry = pending.pop();
|
|
1438
2329
|
if (!entry)
|
|
1439
2330
|
continue;
|
|
1440
|
-
const fullPath =
|
|
2331
|
+
const fullPath = join11(entry.parentPath, entry.name);
|
|
1441
2332
|
if (entry.isDirectory()) {
|
|
1442
2333
|
if (SERVER_RUNTIME_SCAN_SKIP_DIRS.has(entry.name))
|
|
1443
2334
|
continue;
|
|
1444
|
-
pending = pending.concat(
|
|
2335
|
+
pending = pending.concat(readdirSync3(fullPath, { withFileTypes: true }));
|
|
1445
2336
|
} else if (hasSourceExtension(fullPath)) {
|
|
1446
2337
|
result.push(fullPath);
|
|
1447
2338
|
}
|
|
@@ -1460,11 +2351,11 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1460
2351
|
if (copied.has(assetTarget))
|
|
1461
2352
|
return;
|
|
1462
2353
|
copied.add(assetTarget);
|
|
1463
|
-
|
|
2354
|
+
mkdirSync8(dirname4(assetTarget), { recursive: true });
|
|
1464
2355
|
cpSync(assetSource, assetTarget, { force: true });
|
|
1465
2356
|
};
|
|
1466
2357
|
for (const filePath of collectProjectSourceFiles(process.cwd())) {
|
|
1467
|
-
const source =
|
|
2358
|
+
const source = readFileSync13(filePath, "utf-8");
|
|
1468
2359
|
SERVER_RUNTIME_ASSET_RE.lastIndex = 0;
|
|
1469
2360
|
let match;
|
|
1470
2361
|
while ((match = SERVER_RUNTIME_ASSET_RE.exec(source)) !== null) {
|
|
@@ -1493,7 +2384,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1493
2384
|
}
|
|
1494
2385
|
}, readPackageVersion4 = (candidate) => {
|
|
1495
2386
|
try {
|
|
1496
|
-
const pkg = JSON.parse(
|
|
2387
|
+
const pkg = JSON.parse(readFileSync13(candidate, "utf-8"));
|
|
1497
2388
|
if (pkg.name !== "@absolutejs/absolute")
|
|
1498
2389
|
return null;
|
|
1499
2390
|
const ver = pkg.version;
|
|
@@ -1552,7 +2443,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1552
2443
|
return true;
|
|
1553
2444
|
}, tryReadNodePackageJson = (packageDir) => {
|
|
1554
2445
|
try {
|
|
1555
|
-
return JSON.parse(
|
|
2446
|
+
return JSON.parse(readFileSync13(join11(packageDir, "package.json"), "utf-8"));
|
|
1556
2447
|
} catch {
|
|
1557
2448
|
return null;
|
|
1558
2449
|
}
|
|
@@ -1564,7 +2455,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1564
2455
|
if (!pkg)
|
|
1565
2456
|
return;
|
|
1566
2457
|
seen.add(specifier);
|
|
1567
|
-
const destDir =
|
|
2458
|
+
const destDir = join11(outdir, "node_modules", ...specifier.split("/"));
|
|
1568
2459
|
rmSync4(destDir, { force: true, recursive: true });
|
|
1569
2460
|
cpSync(srcDir, destDir, {
|
|
1570
2461
|
filter(source) {
|
|
@@ -1587,7 +2478,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1587
2478
|
if (!buildConfig.angularDirectory)
|
|
1588
2479
|
return;
|
|
1589
2480
|
const angularScopeDir = resolve11(process.cwd(), "node_modules", "@angular");
|
|
1590
|
-
const angularPackages = existsSync11(angularScopeDir) ?
|
|
2481
|
+
const angularPackages = existsSync11(angularScopeDir) ? readdirSync3(angularScopeDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => entry.name !== "compiler-cli").map((entry) => `@angular/${entry.name}`) : [];
|
|
1591
2482
|
const roots = new Set([...angularPackages, "rxjs", "tslib", "typescript"]);
|
|
1592
2483
|
const seen = new Set;
|
|
1593
2484
|
for (const specifier of roots) {
|
|
@@ -1604,16 +2495,16 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1604
2495
|
}
|
|
1605
2496
|
copyAngularRuntimePackages(buildConfig, outdir);
|
|
1606
2497
|
}, collectRuntimePackageSpecifiers = (distDir) => {
|
|
1607
|
-
const nodeModulesDir =
|
|
2498
|
+
const nodeModulesDir = join11(distDir, "node_modules");
|
|
1608
2499
|
if (!existsSync11(nodeModulesDir))
|
|
1609
2500
|
return [];
|
|
1610
2501
|
const specifiers = [];
|
|
1611
|
-
for (const entry of
|
|
2502
|
+
for (const entry of readdirSync3(nodeModulesDir, { withFileTypes: true })) {
|
|
1612
2503
|
if (!entry.isDirectory())
|
|
1613
2504
|
continue;
|
|
1614
2505
|
if (entry.name.startsWith("@")) {
|
|
1615
|
-
const scopeDir =
|
|
1616
|
-
for (const scopedEntry of
|
|
2506
|
+
const scopeDir = join11(nodeModulesDir, entry.name);
|
|
2507
|
+
for (const scopedEntry of readdirSync3(scopeDir, {
|
|
1617
2508
|
withFileTypes: true
|
|
1618
2509
|
})) {
|
|
1619
2510
|
if (scopedEntry.isDirectory()) {
|
|
@@ -1644,18 +2535,18 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1644
2535
|
const packageSpecifier = packageSpecifiers.find((root) => specifier === root || specifier.startsWith(`${root}/`));
|
|
1645
2536
|
if (!packageSpecifier)
|
|
1646
2537
|
return null;
|
|
1647
|
-
const packageDir =
|
|
2538
|
+
const packageDir = join11(distDir, "node_modules", ...packageSpecifier.split("/"));
|
|
1648
2539
|
const subpath = specifier.slice(packageSpecifier.length);
|
|
1649
|
-
const subPackageDir = subpath ?
|
|
1650
|
-
const resolvedPackageDir = subPackageDir && existsSync11(
|
|
1651
|
-
const packageJsonPath =
|
|
2540
|
+
const subPackageDir = subpath ? join11(packageDir, ...subpath.slice(1).split("/")) : null;
|
|
2541
|
+
const resolvedPackageDir = subPackageDir && existsSync11(join11(subPackageDir, "package.json")) ? subPackageDir : packageDir;
|
|
2542
|
+
const packageJsonPath = join11(resolvedPackageDir, "package.json");
|
|
1652
2543
|
if (!existsSync11(packageJsonPath))
|
|
1653
2544
|
return null;
|
|
1654
|
-
const pkg = JSON.parse(
|
|
2545
|
+
const pkg = JSON.parse(readFileSync13(packageJsonPath, "utf-8"));
|
|
1655
2546
|
const exportKey = resolvedPackageDir === subPackageDir ? "." : subpath ? `.${subpath}` : ".";
|
|
1656
2547
|
const rootExport = pkg.exports?.[exportKey];
|
|
1657
2548
|
const entry = pickExportEntry(rootExport) ?? (resolvedPackageDir === subPackageDir || !subpath ? pkg.module ?? pkg.main ?? "index.js" : `.${subpath}`);
|
|
1658
|
-
return
|
|
2549
|
+
return join11(resolvedPackageDir, entry);
|
|
1659
2550
|
}, 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) => {
|
|
1660
2551
|
try {
|
|
1661
2552
|
return statSync2(filePath).isFile();
|
|
@@ -1668,13 +2559,13 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1668
2559
|
const candidates = [
|
|
1669
2560
|
candidate,
|
|
1670
2561
|
...RUNTIME_JS_EXTENSIONS.map((extension) => `${candidate}${extension}`),
|
|
1671
|
-
...RUNTIME_JS_EXTENSIONS.map((extension) =>
|
|
2562
|
+
...RUNTIME_JS_EXTENSIONS.map((extension) => join11(candidate, `index${extension}`))
|
|
1672
2563
|
];
|
|
1673
2564
|
return candidates.find((filePath) => isRuntimeJsFile(filePath) && isFile(filePath)) ?? null;
|
|
1674
2565
|
}, findContainingRuntimePackageDir = (filePath) => {
|
|
1675
2566
|
let dir = dirname4(filePath);
|
|
1676
2567
|
while (dir !== dirname4(dir)) {
|
|
1677
|
-
if (isNodeModulesPath(dir) && existsSync11(
|
|
2568
|
+
if (isNodeModulesPath(dir) && existsSync11(join11(dir, "package.json"))) {
|
|
1678
2569
|
return dir;
|
|
1679
2570
|
}
|
|
1680
2571
|
dir = dirname4(dir);
|
|
@@ -1690,7 +2581,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1690
2581
|
const entry = pickExportEntry(pkg?.imports?.[specifier]);
|
|
1691
2582
|
if (!entry)
|
|
1692
2583
|
return null;
|
|
1693
|
-
return
|
|
2584
|
+
return join11(packageDir, entry);
|
|
1694
2585
|
}, collectRuntimeRewriteRoots = (distDir) => collectFiles2(distDir).filter((filePath) => isRuntimeJsFile(filePath) && !isNodeModulesPath(filePath)), rewriteRuntimeModuleSpecifiers = (distDir) => {
|
|
1695
2586
|
const packageSpecifiers = collectRuntimePackageSpecifiers(distDir);
|
|
1696
2587
|
if (packageSpecifiers.length === 0)
|
|
@@ -1709,7 +2600,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1709
2600
|
if (!filePath || seen.has(filePath))
|
|
1710
2601
|
continue;
|
|
1711
2602
|
seen.add(filePath);
|
|
1712
|
-
const source =
|
|
2603
|
+
const source = readFileSync13(filePath, "utf-8");
|
|
1713
2604
|
const rewritten = source.replace(MODULE_SPECIFIER_RE, (match, prefix, quote, specifier) => {
|
|
1714
2605
|
if (typeof specifier === "string" && specifier.startsWith(".")) {
|
|
1715
2606
|
enqueue(resolveRuntimeJsFile(resolve11(dirname4(filePath), specifier)));
|
|
@@ -1727,12 +2618,12 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1727
2618
|
return `${prefix}${quote}${ensureRelativeModuleSpecifier(filePath, target)}${quote}`;
|
|
1728
2619
|
});
|
|
1729
2620
|
if (rewritten !== source) {
|
|
1730
|
-
|
|
2621
|
+
writeFileSync5(filePath, rewritten);
|
|
1731
2622
|
}
|
|
1732
2623
|
}
|
|
1733
2624
|
}, generateEntrypoint = (distDir, serverEntry, prerenderMap, version2, buildConfig) => {
|
|
1734
2625
|
const allFiles = collectFiles2(distDir);
|
|
1735
|
-
const serverBundleName = `${
|
|
2626
|
+
const serverBundleName = `${basename4(serverEntry).replace(/\.[^.]+$/, "")}.js`;
|
|
1736
2627
|
const embeddedSkip = new Set(["_compile_entrypoint.ts"]);
|
|
1737
2628
|
const assetSkip = new Set([
|
|
1738
2629
|
serverBundleName,
|
|
@@ -2115,7 +3006,7 @@ console.log(\`
|
|
|
2115
3006
|
}, compileUnlocked = async (serverEntry, resolvedOutdir, outfile, configPath2) => {
|
|
2116
3007
|
const prerenderPort = Number(env3.COMPILE_PORT) || Number(env3.PORT) || DEFAULT_PORT + 1;
|
|
2117
3008
|
killStaleProcesses(prerenderPort);
|
|
2118
|
-
const entryName =
|
|
3009
|
+
const entryName = basename4(serverEntry).replace(/\.[^.]+$/, "");
|
|
2119
3010
|
const resolvedOutfile = resolve11(outfile ?? "compiled-server");
|
|
2120
3011
|
const absoluteVersion = resolvePackageVersion3([
|
|
2121
3012
|
resolve11(import.meta.dir, "..", "..", "..", "package.json"),
|
|
@@ -2181,7 +3072,7 @@ console.log(\`
|
|
|
2181
3072
|
}
|
|
2182
3073
|
if (existsSync11(resolve11(resolvedOutdir, "angular", "vendor", "server"))) {
|
|
2183
3074
|
const vendorDir = resolve11(resolvedOutdir, "angular", "vendor", "server");
|
|
2184
|
-
const vendorEntries =
|
|
3075
|
+
const vendorEntries = readdirSync3(vendorDir).filter((f) => f.endsWith(".js"));
|
|
2185
3076
|
const angularServerVendorPaths = {};
|
|
2186
3077
|
for (const file of vendorEntries) {
|
|
2187
3078
|
const stem = file.replace(/\.js$/, "");
|
|
@@ -2201,7 +3092,7 @@ console.log(\`
|
|
|
2201
3092
|
copyServerRuntimeAssetReferences(resolvedOutdir);
|
|
2202
3093
|
const prerenderStart = performance.now();
|
|
2203
3094
|
process.stdout.write(cliTag4("\x1B[36m", "Pre-rendering pages"));
|
|
2204
|
-
rmSync4(
|
|
3095
|
+
rmSync4(join11(resolvedOutdir, "_prerendered"), {
|
|
2205
3096
|
force: true,
|
|
2206
3097
|
recursive: true
|
|
2207
3098
|
});
|
|
@@ -2220,9 +3111,9 @@ console.log(\`
|
|
|
2220
3111
|
const compileStart = performance.now();
|
|
2221
3112
|
process.stdout.write(cliTag4("\x1B[36m", "Compiling standalone executable"));
|
|
2222
3113
|
const entrypointCode = generateEntrypoint(resolvedOutdir, serverEntry, prerenderMap, absoluteVersion, buildConfig);
|
|
2223
|
-
const entrypointPath =
|
|
3114
|
+
const entrypointPath = join11(resolvedOutdir, "_compile_entrypoint.ts");
|
|
2224
3115
|
await Bun.write(entrypointPath, entrypointCode);
|
|
2225
|
-
|
|
3116
|
+
mkdirSync8(dirname4(resolvedOutfile), { recursive: true });
|
|
2226
3117
|
const result = await Bun.build({
|
|
2227
3118
|
compile: { outfile: resolvedOutfile },
|
|
2228
3119
|
define: { "process.env.NODE_ENV": '"production"' },
|
|
@@ -2244,13 +3135,13 @@ console.log(\`
|
|
|
2244
3135
|
}
|
|
2245
3136
|
console.log(` \x1B[2m(${getDurationString(performance.now() - compileStart)})\x1B[0m`);
|
|
2246
3137
|
try {
|
|
2247
|
-
|
|
3138
|
+
unlinkSync4(entrypointPath);
|
|
2248
3139
|
} catch {}
|
|
2249
3140
|
const BYTES_PER_MB = 1048576;
|
|
2250
3141
|
const size = (Bun.file(resolvedOutfile).size / BYTES_PER_MB).toFixed(0);
|
|
2251
3142
|
const totalDuration = getDurationString(performance.now() - totalStart);
|
|
2252
3143
|
console.log(cliTag4("\x1B[32m", `Compiled to ${resolvedOutfile} (${size}MB) in ${totalDuration}`));
|
|
2253
|
-
console.log(cliTag4("\x1B[2m", `Run with: ./${
|
|
3144
|
+
console.log(cliTag4("\x1B[2m", `Run with: ./${basename4(resolvedOutfile)}`));
|
|
2254
3145
|
sendTelemetryEvent("compile:complete", {
|
|
2255
3146
|
durationMs: Math.round(performance.now() - totalStart),
|
|
2256
3147
|
entry: serverEntry,
|
|
@@ -2314,8 +3205,8 @@ var exports_typecheck = {};
|
|
|
2314
3205
|
__export(exports_typecheck, {
|
|
2315
3206
|
typecheck: () => typecheck
|
|
2316
3207
|
});
|
|
2317
|
-
import { resolve as resolve12, join as
|
|
2318
|
-
import { existsSync as existsSync12, readFileSync as
|
|
3208
|
+
import { resolve as resolve12, join as join12 } from "path";
|
|
3209
|
+
import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
|
|
2319
3210
|
import { mkdir as mkdir2, writeFile } from "fs/promises";
|
|
2320
3211
|
var isCommandService3 = (service) => service.kind === "command" || Array.isArray(service.command), resolveConfigPath = (configPath2) => resolve12(configPath2 ?? process.env.ABSOLUTE_CONFIG ?? "absolute.config.ts"), getTypecheckTargets = async (configPath2) => {
|
|
2321
3212
|
if (!existsSync12(resolveConfigPath(configPath2))) {
|
|
@@ -2394,7 +3285,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2394
3285
|
return candidates.find((candidate) => existsSync12(candidate)) ?? candidates[0];
|
|
2395
3286
|
}, ABSOLUTE_TYPECHECK_FILES, readProjectTsconfig = () => {
|
|
2396
3287
|
try {
|
|
2397
|
-
return JSON.parse(
|
|
3288
|
+
return JSON.parse(readFileSync14(resolve12("tsconfig.json"), "utf-8"));
|
|
2398
3289
|
} catch {
|
|
2399
3290
|
return {};
|
|
2400
3291
|
}
|
|
@@ -2422,7 +3313,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2422
3313
|
console.error("\x1B[31m\u2717\x1B[0m vue-tsc is required for Vue type checking. Install it: bun add -d vue-tsc");
|
|
2423
3314
|
process.exit(1);
|
|
2424
3315
|
}
|
|
2425
|
-
const vueTsconfigPath =
|
|
3316
|
+
const vueTsconfigPath = join12(cacheDir, "tsconfig.vue-check.json");
|
|
2426
3317
|
return writeFile(vueTsconfigPath, JSON.stringify({
|
|
2427
3318
|
compilerOptions: {
|
|
2428
3319
|
rootDir: ".."
|
|
@@ -2437,7 +3328,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2437
3328
|
resolve12(vueTsconfigPath),
|
|
2438
3329
|
"--incremental",
|
|
2439
3330
|
"--tsBuildInfoFile",
|
|
2440
|
-
|
|
3331
|
+
join12(cacheDir, "vue-tsc.tsbuildinfo"),
|
|
2441
3332
|
"--pretty"
|
|
2442
3333
|
]));
|
|
2443
3334
|
}, buildAngularCheck = async (cacheDir, angularDir) => {
|
|
@@ -2446,7 +3337,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2446
3337
|
console.error("\x1B[31m\u2717\x1B[0m @angular/compiler-cli is required for Angular type checking. Install it: bun add -d @angular/compiler-cli");
|
|
2447
3338
|
process.exit(1);
|
|
2448
3339
|
}
|
|
2449
|
-
const angularTsconfigPath =
|
|
3340
|
+
const angularTsconfigPath = join12(cacheDir, "tsconfig.angular-check.json");
|
|
2450
3341
|
await writeFile(angularTsconfigPath, JSON.stringify({
|
|
2451
3342
|
angularCompilerOptions: {
|
|
2452
3343
|
strictTemplates: true
|
|
@@ -2466,7 +3357,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2466
3357
|
console.error("\x1B[31m\u2717\x1B[0m typescript is required for type checking. Install it: bun add -d typescript");
|
|
2467
3358
|
process.exit(1);
|
|
2468
3359
|
}
|
|
2469
|
-
const tscConfigPath =
|
|
3360
|
+
const tscConfigPath = join12(cacheDir, "tsconfig.typecheck.json");
|
|
2470
3361
|
return writeFile(tscConfigPath, JSON.stringify({
|
|
2471
3362
|
compilerOptions: {
|
|
2472
3363
|
rootDir: ".."
|
|
@@ -2481,7 +3372,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2481
3372
|
resolve12(tscConfigPath),
|
|
2482
3373
|
"--incremental",
|
|
2483
3374
|
"--tsBuildInfoFile",
|
|
2484
|
-
|
|
3375
|
+
join12(cacheDir, "tsc.tsbuildinfo"),
|
|
2485
3376
|
"--pretty"
|
|
2486
3377
|
]));
|
|
2487
3378
|
}, buildSvelteCheck = async (cacheDir, svelteDir) => {
|
|
@@ -2490,7 +3381,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2490
3381
|
console.error("\x1B[31m\u2717\x1B[0m svelte-check is required for Svelte type checking. Install it: bun add -d svelte-check");
|
|
2491
3382
|
process.exit(1);
|
|
2492
3383
|
}
|
|
2493
|
-
const svelteTsconfigPath =
|
|
3384
|
+
const svelteTsconfigPath = join12(cacheDir, "tsconfig.svelte-check.json");
|
|
2494
3385
|
await writeFile(svelteTsconfigPath, JSON.stringify({
|
|
2495
3386
|
extends: resolve12("tsconfig.json"),
|
|
2496
3387
|
files: ABSOLUTE_TYPECHECK_FILES,
|
|
@@ -2567,7 +3458,7 @@ init_constants();
|
|
|
2567
3458
|
init_startupBanner();
|
|
2568
3459
|
var {$: $2, env } = globalThis.Bun;
|
|
2569
3460
|
import { spawn as nodeSpawn } from "child_process";
|
|
2570
|
-
import { existsSync as existsSync5, readFileSync as
|
|
3461
|
+
import { createWriteStream, existsSync as existsSync5, readFileSync as readFileSync7 } from "fs";
|
|
2571
3462
|
import { resolve as resolve3 } from "path";
|
|
2572
3463
|
|
|
2573
3464
|
// src/cli/interactive.ts
|
|
@@ -2840,6 +3731,7 @@ var createInteractiveHandler = (actions) => {
|
|
|
2840
3731
|
// src/cli/scripts/dev.ts
|
|
2841
3732
|
init_telemetryEvent();
|
|
2842
3733
|
init_buildDirectoryLock();
|
|
3734
|
+
init_instanceRegistry();
|
|
2843
3735
|
init_loadConfig();
|
|
2844
3736
|
|
|
2845
3737
|
// src/utils/resolveDevPort.ts
|
|
@@ -2882,6 +3774,7 @@ var resolveDevPort = async (requestedPort, options = {}) => {
|
|
|
2882
3774
|
init_utils();
|
|
2883
3775
|
var cliTag = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`;
|
|
2884
3776
|
var DEFAULT_PORT_RANGE = 10;
|
|
3777
|
+
var ANSI_LOG_REGEX = new RegExp(`${String.fromCharCode(ANSI_ESCAPE_CODE)}\\[[0-?]*[ -/]*[@-~]`, "g");
|
|
2885
3778
|
var confirmPrompt = (message, defaultYes = true) => {
|
|
2886
3779
|
const { promise, resolve: resolvePrompt } = Promise.withResolvers();
|
|
2887
3780
|
let selected = defaultYes;
|
|
@@ -2986,6 +3879,37 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
2986
3879
|
console.log(cliTag("\x1B[33m", `Port ${resolvedDev.port} is in use, trying another one... \u2192 http://${displayHost}:${port}/`));
|
|
2987
3880
|
}
|
|
2988
3881
|
updateLockMetadata(buildDirectory, { port });
|
|
3882
|
+
const instancePid = process.pid;
|
|
3883
|
+
const instanceLogFile = instanceLogPath(instancePid);
|
|
3884
|
+
const relaunchCommand = [
|
|
3885
|
+
process.execPath,
|
|
3886
|
+
process.argv[1] ?? "",
|
|
3887
|
+
"dev",
|
|
3888
|
+
serverEntry,
|
|
3889
|
+
...configPath2 ? ["--config", configPath2] : []
|
|
3890
|
+
].filter((part) => part.length > 0);
|
|
3891
|
+
registerInstance({
|
|
3892
|
+
command: relaunchCommand,
|
|
3893
|
+
configPath: configPath2 ?? null,
|
|
3894
|
+
controllerPid: instancePid,
|
|
3895
|
+
cwd: process.cwd(),
|
|
3896
|
+
frameworks: [],
|
|
3897
|
+
host: resolvedDev.host,
|
|
3898
|
+
https: httpsEnabled,
|
|
3899
|
+
logFile: instanceLogFile,
|
|
3900
|
+
name: resolveProjectName(process.cwd()),
|
|
3901
|
+
pid: instancePid,
|
|
3902
|
+
port,
|
|
3903
|
+
ppid: process.ppid,
|
|
3904
|
+
source: "dev",
|
|
3905
|
+
startedAt: new Date().toISOString()
|
|
3906
|
+
});
|
|
3907
|
+
const instanceLog = createWriteStream(instanceLogFile, { flags: "w" });
|
|
3908
|
+
const writeInstanceLog = (text) => {
|
|
3909
|
+
try {
|
|
3910
|
+
instanceLog.write(text.replace(ANSI_LOG_REGEX, ""));
|
|
3911
|
+
} catch {}
|
|
3912
|
+
};
|
|
2989
3913
|
const usesDocker = existsSync5(resolve3(COMPOSE_PATH));
|
|
2990
3914
|
const scripts = usesDocker ? await readDbScripts() : null;
|
|
2991
3915
|
if (scripts)
|
|
@@ -3059,6 +3983,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3059
3983
|
console.log(cliTag("\x1B[36m", `Port changed in config \u2014 switching to http://${displayHost}:${probe.port}/`));
|
|
3060
3984
|
port = probe.port;
|
|
3061
3985
|
updateLockMetadata(buildDirectory, { port });
|
|
3986
|
+
updateInstance(instancePid, { port });
|
|
3062
3987
|
}
|
|
3063
3988
|
resolvedDev = dev2;
|
|
3064
3989
|
}
|
|
@@ -3069,7 +3994,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3069
3994
|
for (const name of candidates) {
|
|
3070
3995
|
let text;
|
|
3071
3996
|
try {
|
|
3072
|
-
text =
|
|
3997
|
+
text = readFileSync7(resolve3(process.cwd(), name), "utf8");
|
|
3073
3998
|
} catch {
|
|
3074
3999
|
continue;
|
|
3075
4000
|
}
|
|
@@ -3099,6 +4024,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3099
4024
|
env: {
|
|
3100
4025
|
...process.env,
|
|
3101
4026
|
...readDotenvFiles(),
|
|
4027
|
+
ABSOLUTE_INSTANCE_MANAGED: "1",
|
|
3102
4028
|
FORCE_COLOR: "1",
|
|
3103
4029
|
NODE_ENV: "development",
|
|
3104
4030
|
ABSOLUTE_PORT: String(port),
|
|
@@ -3115,6 +4041,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3115
4041
|
if (serverReady)
|
|
3116
4042
|
interactive?.clearPrompt();
|
|
3117
4043
|
dest.write(chunk);
|
|
4044
|
+
writeInstanceLog(chunk.toString());
|
|
3118
4045
|
handleChunk(chunk);
|
|
3119
4046
|
});
|
|
3120
4047
|
};
|
|
@@ -3140,7 +4067,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3140
4067
|
};
|
|
3141
4068
|
try {
|
|
3142
4069
|
const { watch } = await import("fs");
|
|
3143
|
-
const { dirname: dirname3, join:
|
|
4070
|
+
const { dirname: dirname3, join: join6 } = await import("path");
|
|
3144
4071
|
const absServerEntry = resolve3(serverEntry);
|
|
3145
4072
|
const serverEntryDir = dirname3(absServerEntry);
|
|
3146
4073
|
const ROOT_RESTART_DENY = new Set([
|
|
@@ -3173,13 +4100,13 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3173
4100
|
if (now - last < 100)
|
|
3174
4101
|
return;
|
|
3175
4102
|
recentlyHandled.set(filename, now);
|
|
3176
|
-
scheduleServerRestart(
|
|
4103
|
+
scheduleServerRestart(join6(serverEntryDir, filename));
|
|
3177
4104
|
};
|
|
3178
4105
|
const recoveryScan = async () => {
|
|
3179
4106
|
let entries;
|
|
3180
4107
|
try {
|
|
3181
|
-
const { readdirSync } = await import("fs");
|
|
3182
|
-
entries =
|
|
4108
|
+
const { readdirSync: readdirSync2 } = await import("fs");
|
|
4109
|
+
entries = readdirSync2(serverEntryDir, { withFileTypes: true });
|
|
3183
4110
|
} catch {
|
|
3184
4111
|
return;
|
|
3185
4112
|
}
|
|
@@ -3192,7 +4119,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3192
4119
|
continue;
|
|
3193
4120
|
let st;
|
|
3194
4121
|
try {
|
|
3195
|
-
st = statSync(
|
|
4122
|
+
st = statSync(join6(serverEntryDir, entry.name));
|
|
3196
4123
|
} catch {
|
|
3197
4124
|
continue;
|
|
3198
4125
|
}
|
|
@@ -3235,6 +4162,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3235
4162
|
cfg.angularDirectory && "angular"
|
|
3236
4163
|
].filter((val) => Boolean(val));
|
|
3237
4164
|
} catch {}
|
|
4165
|
+
updateInstance(instancePid, { frameworks });
|
|
3238
4166
|
sendTelemetryEvent("dev:start", { entry: serverEntry, frameworks });
|
|
3239
4167
|
const killChildTree = (signal) => {
|
|
3240
4168
|
const childPid = serverProcess.pid;
|
|
@@ -3273,6 +4201,10 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3273
4201
|
});
|
|
3274
4202
|
if (scripts)
|
|
3275
4203
|
await stopDatabase(scripts);
|
|
4204
|
+
try {
|
|
4205
|
+
instanceLog.end();
|
|
4206
|
+
} catch {}
|
|
4207
|
+
deregisterInstance(instancePid);
|
|
3276
4208
|
process.exit(exitCode);
|
|
3277
4209
|
};
|
|
3278
4210
|
const restartServer = async () => {
|
|
@@ -3451,7 +4383,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3451
4383
|
};
|
|
3452
4384
|
|
|
3453
4385
|
// src/cli/scripts/eslint.ts
|
|
3454
|
-
import { existsSync as existsSync6, readFileSync as
|
|
4386
|
+
import { existsSync as existsSync6, readFileSync as readFileSync8, rmSync as rmSync2 } from "fs";
|
|
3455
4387
|
import { resolve as resolve4 } from "path";
|
|
3456
4388
|
var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache";
|
|
3457
4389
|
var getCacheLocation = () => process.env.ABSOLUTE_ESLINT_CACHE?.trim() || DEFAULT_CACHE_LOCATION;
|
|
@@ -3608,7 +4540,7 @@ var checkForMisplacedIgnores = () => {
|
|
|
3608
4540
|
return;
|
|
3609
4541
|
let source;
|
|
3610
4542
|
try {
|
|
3611
|
-
source =
|
|
4543
|
+
source = readFileSync8(configPath2, "utf-8");
|
|
3612
4544
|
} catch {
|
|
3613
4545
|
return;
|
|
3614
4546
|
}
|
|
@@ -3697,7 +4629,7 @@ var eslint = async (args) => {
|
|
|
3697
4629
|
init_constants();
|
|
3698
4630
|
init_utils();
|
|
3699
4631
|
import { execSync as execSync2 } from "child_process";
|
|
3700
|
-
import { existsSync as existsSync7, readFileSync as
|
|
4632
|
+
import { existsSync as existsSync7, readFileSync as readFileSync9 } from "fs";
|
|
3701
4633
|
import { arch as arch2, cpus, platform as platform3, totalmem, version } from "os";
|
|
3702
4634
|
import { resolve as resolve5 } from "path";
|
|
3703
4635
|
var bold = (str) => `\x1B[1m${str}\x1B[0m`;
|
|
@@ -3719,7 +4651,7 @@ var getPackageVersion = (packageName) => {
|
|
|
3719
4651
|
const pkgPath = __require.resolve(`${packageName}/package.json`, {
|
|
3720
4652
|
paths: [process.cwd()]
|
|
3721
4653
|
});
|
|
3722
|
-
const pkg = JSON.parse(
|
|
4654
|
+
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
3723
4655
|
const ver = pkg.version;
|
|
3724
4656
|
return ver;
|
|
3725
4657
|
} catch {
|
|
@@ -3741,7 +4673,7 @@ var getAbsoluteVersion = () => {
|
|
|
3741
4673
|
return getPackageVersion("@absolutejs/absolute");
|
|
3742
4674
|
};
|
|
3743
4675
|
var readPackageVersion = (pkgPath) => {
|
|
3744
|
-
const pkg = JSON.parse(
|
|
4676
|
+
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
3745
4677
|
const ver = pkg.version;
|
|
3746
4678
|
return ver;
|
|
3747
4679
|
};
|
|
@@ -3843,7 +4775,7 @@ var info = () => {
|
|
|
3843
4775
|
// src/cli/cache.ts
|
|
3844
4776
|
init_constants();
|
|
3845
4777
|
import { mkdir } from "fs/promises";
|
|
3846
|
-
import { join as
|
|
4778
|
+
import { join as join6 } from "path";
|
|
3847
4779
|
var {Glob } = globalThis.Bun;
|
|
3848
4780
|
var CACHE_DIR = ".absolutejs";
|
|
3849
4781
|
var MAX_FILES_PER_BATCH = 200;
|
|
@@ -3895,7 +4827,7 @@ var hashFiles = async (paths) => {
|
|
|
3895
4827
|
};
|
|
3896
4828
|
var loadCache = async (tool) => {
|
|
3897
4829
|
try {
|
|
3898
|
-
const path =
|
|
4830
|
+
const path = join6(CACHE_DIR, `${tool}.cache.json`);
|
|
3899
4831
|
const data = await Bun.file(path).json();
|
|
3900
4832
|
const result = data;
|
|
3901
4833
|
return result;
|
|
@@ -3942,7 +4874,7 @@ var runTool = async (adapter, args) => {
|
|
|
3942
4874
|
};
|
|
3943
4875
|
var saveCache = async (tool, data) => {
|
|
3944
4876
|
await mkdir(CACHE_DIR, { recursive: true });
|
|
3945
|
-
const path =
|
|
4877
|
+
const path = join6(CACHE_DIR, `${tool}.cache.json`);
|
|
3946
4878
|
await Bun.write(path, JSON.stringify(data, null, "\t"));
|
|
3947
4879
|
};
|
|
3948
4880
|
|
|
@@ -3979,13 +4911,14 @@ var prettier = async (args) => {
|
|
|
3979
4911
|
// src/cli/scripts/start.ts
|
|
3980
4912
|
init_constants();
|
|
3981
4913
|
init_getDurationString();
|
|
4914
|
+
init_instanceRegistry();
|
|
3982
4915
|
init_loadConfig();
|
|
3983
4916
|
init_startupBanner();
|
|
3984
4917
|
init_telemetryEvent();
|
|
3985
4918
|
init_utils();
|
|
3986
4919
|
var {env: env2 } = globalThis.Bun;
|
|
3987
|
-
import { existsSync as existsSync8, readFileSync as
|
|
3988
|
-
import { basename, join as
|
|
4920
|
+
import { existsSync as existsSync8, readFileSync as readFileSync11, rmSync as rmSync3 } from "fs";
|
|
4921
|
+
import { basename as basename2, join as join9, resolve as resolve7 } from "path";
|
|
3989
4922
|
var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`;
|
|
3990
4923
|
var resolvePackageVersion = (candidates) => {
|
|
3991
4924
|
for (const candidate of candidates) {
|
|
@@ -3998,7 +4931,7 @@ var resolvePackageVersion = (candidates) => {
|
|
|
3998
4931
|
};
|
|
3999
4932
|
var readPackageVersion2 = (candidate) => {
|
|
4000
4933
|
try {
|
|
4001
|
-
const pkg = JSON.parse(
|
|
4934
|
+
const pkg = JSON.parse(readFileSync11(candidate, "utf-8"));
|
|
4002
4935
|
if (pkg.name !== "@absolutejs/absolute")
|
|
4003
4936
|
return null;
|
|
4004
4937
|
const ver = pkg.version;
|
|
@@ -4062,6 +4995,7 @@ var prerenderStaticPages = async (outputPath, prerenderPort, resolvedOutdir, sta
|
|
|
4062
4995
|
killStaleProcesses(prerenderPort);
|
|
4063
4996
|
const result = await prerenderWithServer2(outputPath, prerenderPort, resolvedOutdir, staticConfig, {
|
|
4064
4997
|
ABSOLUTE_BUILD_DIR: resolvedOutdir,
|
|
4998
|
+
ABSOLUTE_INSTANCE_MANAGED: "1",
|
|
4065
4999
|
ABSOLUTE_VERSION: absoluteVersion,
|
|
4066
5000
|
FORCE_COLOR: "0",
|
|
4067
5001
|
NODE_ENV: "production",
|
|
@@ -4077,7 +5011,7 @@ var prerenderStaticPages = async (outputPath, prerenderPort, resolvedOutdir, sta
|
|
|
4077
5011
|
var start = async (serverEntry, outdir, configPath2) => {
|
|
4078
5012
|
const port = Number(env2.PORT) || DEFAULT_PORT;
|
|
4079
5013
|
killStaleProcesses(port);
|
|
4080
|
-
const entryName =
|
|
5014
|
+
const entryName = basename2(serverEntry).replace(/\.[^.]+$/, "");
|
|
4081
5015
|
const resolvedOutdir = resolve7(outdir ?? "dist");
|
|
4082
5016
|
const absoluteVersion = resolvePackageVersion([
|
|
4083
5017
|
resolve7(import.meta.dir, "..", "..", "..", "package.json"),
|
|
@@ -4104,7 +5038,7 @@ var start = async (serverEntry, outdir, configPath2) => {
|
|
|
4104
5038
|
if (!build)
|
|
4105
5039
|
throw new Error("Could not locate build module");
|
|
4106
5040
|
await build(buildConfig);
|
|
4107
|
-
rmSync3(
|
|
5041
|
+
rmSync3(join9(resolvedOutdir, "_prerendered"), {
|
|
4108
5042
|
force: true,
|
|
4109
5043
|
recursive: true
|
|
4110
5044
|
});
|
|
@@ -4217,9 +5151,9 @@ var start = async (serverEntry, outdir, configPath2) => {
|
|
|
4217
5151
|
process.exit(1);
|
|
4218
5152
|
}
|
|
4219
5153
|
if (existsSync8(resolve7(resolvedOutdir, "angular", "vendor", "server"))) {
|
|
4220
|
-
const { readdirSync } = await import("fs");
|
|
5154
|
+
const { readdirSync: readdirSync2 } = await import("fs");
|
|
4221
5155
|
const vendorDir = resolve7(resolvedOutdir, "angular", "vendor", "server");
|
|
4222
|
-
const vendorEntries =
|
|
5156
|
+
const vendorEntries = readdirSync2(vendorDir).filter((f) => f.endsWith(".js"));
|
|
4223
5157
|
const angularServerVendorPaths = {};
|
|
4224
5158
|
const { relative: pathRelative, dirname: pathDirname } = await import("path");
|
|
4225
5159
|
for (const file of vendorEntries) {
|
|
@@ -4266,6 +5200,7 @@ var start = async (serverEntry, outdir, configPath2) => {
|
|
|
4266
5200
|
...process.env,
|
|
4267
5201
|
ABSOLUTE_BUILD_DIR: resolvedOutdir,
|
|
4268
5202
|
ABSOLUTE_BUILD_DURATION: String(Math.round(totalDuration)),
|
|
5203
|
+
ABSOLUTE_INSTANCE_MANAGED: "1",
|
|
4269
5204
|
ABSOLUTE_VERSION: absoluteVersion,
|
|
4270
5205
|
FORCE_COLOR: "1",
|
|
4271
5206
|
NODE_ENV: "production",
|
|
@@ -4275,10 +5210,35 @@ var start = async (serverEntry, outdir, configPath2) => {
|
|
|
4275
5210
|
stdin: "inherit",
|
|
4276
5211
|
stdout: "inherit"
|
|
4277
5212
|
});
|
|
5213
|
+
const relaunchCommand = [
|
|
5214
|
+
process.execPath,
|
|
5215
|
+
process.argv[1] ?? "",
|
|
5216
|
+
"start",
|
|
5217
|
+
serverEntry,
|
|
5218
|
+
...outdir ? ["--outdir", outdir] : [],
|
|
5219
|
+
...configPath2 ? ["--config", configPath2] : []
|
|
5220
|
+
].filter((part) => part.length > 0);
|
|
5221
|
+
registerInstance({
|
|
5222
|
+
command: relaunchCommand,
|
|
5223
|
+
configPath: configPath2 ?? null,
|
|
5224
|
+
controllerPid: process.pid,
|
|
5225
|
+
cwd: process.cwd(),
|
|
5226
|
+
frameworks,
|
|
5227
|
+
host: env2.ABSOLUTE_HOST ?? env2.HOST ?? "localhost",
|
|
5228
|
+
https: env2.ABSOLUTE_HTTPS === "true",
|
|
5229
|
+
logFile: null,
|
|
5230
|
+
name: resolveProjectName(process.cwd()),
|
|
5231
|
+
pid: process.pid,
|
|
5232
|
+
port,
|
|
5233
|
+
ppid: process.ppid,
|
|
5234
|
+
source: "start",
|
|
5235
|
+
startedAt: new Date().toISOString()
|
|
5236
|
+
});
|
|
4278
5237
|
const cleanup = async (exitCode2 = 0) => {
|
|
4279
5238
|
if (cleaning)
|
|
4280
5239
|
return;
|
|
4281
5240
|
cleaning = true;
|
|
5241
|
+
deregisterInstance(process.pid);
|
|
4282
5242
|
sendTelemetryEvent("start:session-duration", {
|
|
4283
5243
|
duration: Math.round((Date.now() - sessionStart) / MILLISECONDS_IN_A_SECOND),
|
|
4284
5244
|
entry: serverEntry
|
|
@@ -4311,27 +5271,24 @@ var start = async (serverEntry, outdir, configPath2) => {
|
|
|
4311
5271
|
init_constants();
|
|
4312
5272
|
init_loadConfig();
|
|
4313
5273
|
init_getDurationString();
|
|
5274
|
+
init_instanceRegistry();
|
|
4314
5275
|
import {
|
|
4315
5276
|
appendFileSync,
|
|
4316
5277
|
existsSync as existsSync9,
|
|
4317
|
-
mkdirSync as
|
|
4318
|
-
readdirSync,
|
|
4319
|
-
readFileSync as
|
|
4320
|
-
unlinkSync as
|
|
4321
|
-
writeFileSync as
|
|
5278
|
+
mkdirSync as mkdirSync6,
|
|
5279
|
+
readdirSync as readdirSync2,
|
|
5280
|
+
readFileSync as readFileSync12,
|
|
5281
|
+
unlinkSync as unlinkSync3,
|
|
5282
|
+
writeFileSync as writeFileSync4
|
|
4322
5283
|
} from "fs";
|
|
4323
5284
|
import { createConnection } from "net";
|
|
4324
5285
|
import { resolve as resolve8 } from "path";
|
|
4325
5286
|
|
|
4326
5287
|
// src/cli/workspaceTui.ts
|
|
4327
5288
|
init_constants();
|
|
5289
|
+
init_tuiPrimitives();
|
|
4328
5290
|
init_getDurationString();
|
|
4329
|
-
import { openSync as openSync2 } from "fs";
|
|
4330
|
-
import { ReadStream as ReadStream2 } from "tty";
|
|
4331
5291
|
var MAX_LOG_ENTRIES = 400;
|
|
4332
|
-
var ESCAPE = "\x1B";
|
|
4333
|
-
var ANSI_REGEX = new RegExp(`${String.fromCharCode(ANSI_ESCAPE_CODE)}\\[[0-?]*[ -/]*[@-~]`, "g");
|
|
4334
|
-
var ANSI_ESCAPE_PREFIX = `${ESCAPE}[`;
|
|
4335
5292
|
var SHORTCUTS2 = new Map([
|
|
4336
5293
|
["c", "clear"],
|
|
4337
5294
|
["h", "help"],
|
|
@@ -4340,15 +5297,6 @@ var SHORTCUTS2 = new Map([
|
|
|
4340
5297
|
["q", "quit"],
|
|
4341
5298
|
["r", "restart"]
|
|
4342
5299
|
]);
|
|
4343
|
-
var colors = {
|
|
4344
|
-
bold: "\x1B[1m",
|
|
4345
|
-
cyan: "\x1B[36m",
|
|
4346
|
-
dim: "\x1B[2m",
|
|
4347
|
-
green: "\x1B[32m",
|
|
4348
|
-
red: "\x1B[31m",
|
|
4349
|
-
reset: "\x1B[0m",
|
|
4350
|
-
yellow: "\x1B[33m"
|
|
4351
|
-
};
|
|
4352
5300
|
var helpLines = [
|
|
4353
5301
|
"Hotkeys",
|
|
4354
5302
|
" h Toggle help",
|
|
@@ -4367,108 +5315,6 @@ var helpLines = [
|
|
|
4367
5315
|
" Press Esc to exit shell mode or dismiss help.",
|
|
4368
5316
|
" Use \u2191 and \u2193 to recall prior shell commands."
|
|
4369
5317
|
];
|
|
4370
|
-
var trySetRawMode2 = () => {
|
|
4371
|
-
if (typeof process.stdin.setRawMode !== "function") {
|
|
4372
|
-
return null;
|
|
4373
|
-
}
|
|
4374
|
-
try {
|
|
4375
|
-
process.stdin.setRawMode(true);
|
|
4376
|
-
} catch {
|
|
4377
|
-
return null;
|
|
4378
|
-
}
|
|
4379
|
-
return process.stdin;
|
|
4380
|
-
};
|
|
4381
|
-
var openTtyStream2 = () => {
|
|
4382
|
-
const fromStdin = trySetRawMode2();
|
|
4383
|
-
if (fromStdin) {
|
|
4384
|
-
return fromStdin;
|
|
4385
|
-
}
|
|
4386
|
-
try {
|
|
4387
|
-
const ttyStream = new ReadStream2(openSync2("/dev/tty", "r"));
|
|
4388
|
-
ttyStream.setRawMode(true);
|
|
4389
|
-
return ttyStream;
|
|
4390
|
-
} catch {
|
|
4391
|
-
return null;
|
|
4392
|
-
}
|
|
4393
|
-
};
|
|
4394
|
-
var stripAnsi = (value) => value.replace(ANSI_REGEX, "");
|
|
4395
|
-
var visibleLength = (value) => stripAnsi(value).length;
|
|
4396
|
-
var truncateText = (value, width) => {
|
|
4397
|
-
if (width <= 0) {
|
|
4398
|
-
return "";
|
|
4399
|
-
}
|
|
4400
|
-
if (value.length <= width) {
|
|
4401
|
-
return value;
|
|
4402
|
-
}
|
|
4403
|
-
if (width <= 1) {
|
|
4404
|
-
return value.slice(0, width);
|
|
4405
|
-
}
|
|
4406
|
-
return `${value.slice(0, width - 1)}\u2026`;
|
|
4407
|
-
};
|
|
4408
|
-
var padLine = (value, width) => {
|
|
4409
|
-
const plainLength = visibleLength(value);
|
|
4410
|
-
if (plainLength >= width) {
|
|
4411
|
-
return value;
|
|
4412
|
-
}
|
|
4413
|
-
return `${value}${" ".repeat(width - plainLength)}`;
|
|
4414
|
-
};
|
|
4415
|
-
var appendRightEdge = (value, width, marker) => {
|
|
4416
|
-
if (width <= 0) {
|
|
4417
|
-
return "";
|
|
4418
|
-
}
|
|
4419
|
-
return `${padLine(value, Math.max(0, width - 1))}${marker}`;
|
|
4420
|
-
};
|
|
4421
|
-
var splitLongWord = (word, width) => {
|
|
4422
|
-
const parts = [];
|
|
4423
|
-
for (let index = 0;index < word.length; index += width) {
|
|
4424
|
-
parts.push(word.slice(index, index + width));
|
|
4425
|
-
}
|
|
4426
|
-
return parts;
|
|
4427
|
-
};
|
|
4428
|
-
var appendWrappedWord = (lines, current, word, width) => {
|
|
4429
|
-
if (current.length === 0) {
|
|
4430
|
-
if (word.length <= width)
|
|
4431
|
-
return word;
|
|
4432
|
-
lines.push(...splitLongWord(word, width));
|
|
4433
|
-
return "";
|
|
4434
|
-
}
|
|
4435
|
-
const next = `${current} ${word}`;
|
|
4436
|
-
if (next.length <= width)
|
|
4437
|
-
return next;
|
|
4438
|
-
lines.push(current);
|
|
4439
|
-
if (word.length <= width)
|
|
4440
|
-
return word;
|
|
4441
|
-
lines.push(...splitLongWord(word, width));
|
|
4442
|
-
return "";
|
|
4443
|
-
};
|
|
4444
|
-
var wrapLine = (line, width) => {
|
|
4445
|
-
if (line.length === 0)
|
|
4446
|
-
return [""];
|
|
4447
|
-
if (line.length <= width)
|
|
4448
|
-
return [line];
|
|
4449
|
-
const lines = [];
|
|
4450
|
-
let current = "";
|
|
4451
|
-
for (const word of line.split(/\s+/)) {
|
|
4452
|
-
current = appendWrappedWord(lines, current, word, width);
|
|
4453
|
-
}
|
|
4454
|
-
if (current.length > 0)
|
|
4455
|
-
lines.push(current);
|
|
4456
|
-
return lines;
|
|
4457
|
-
};
|
|
4458
|
-
var wrapText = (value, width) => {
|
|
4459
|
-
if (width <= 0) {
|
|
4460
|
-
return [""];
|
|
4461
|
-
}
|
|
4462
|
-
const lines = value.split(`
|
|
4463
|
-
`).flatMap((rawLine) => wrapLine(rawLine.trimEnd(), width));
|
|
4464
|
-
return lines.length > 0 ? lines : [""];
|
|
4465
|
-
};
|
|
4466
|
-
var formatTimestamp2 = () => new Date().toLocaleTimeString([], {
|
|
4467
|
-
hour: "numeric",
|
|
4468
|
-
hour12: true,
|
|
4469
|
-
minute: "2-digit",
|
|
4470
|
-
second: "2-digit"
|
|
4471
|
-
});
|
|
4472
5318
|
var getStatusColor = (status2) => {
|
|
4473
5319
|
if (status2 === "ready")
|
|
4474
5320
|
return colors.green;
|
|
@@ -4528,12 +5374,6 @@ var getVisibleLogContent = (contentLines, logHeight, logScrollOffset) => {
|
|
|
4528
5374
|
const start2 = Math.max(0, end - logHeight);
|
|
4529
5375
|
return contentLines.slice(start2, end);
|
|
4530
5376
|
};
|
|
4531
|
-
var isPartialEscapeSequence = (value) => {
|
|
4532
|
-
if (!value.startsWith(ANSI_ESCAPE_PREFIX)) {
|
|
4533
|
-
return false;
|
|
4534
|
-
}
|
|
4535
|
-
return Array.from(value.slice(ANSI_ESCAPE_PREFIX.length)).every((char) => char >= "0" && char <= "9");
|
|
4536
|
-
};
|
|
4537
5377
|
var createWorkspaceTui = ({
|
|
4538
5378
|
actions,
|
|
4539
5379
|
headless: headlessOption,
|
|
@@ -5004,10 +5844,10 @@ var stripAnsi2 = (value) => value.replace(ANSI_REGEX2, "");
|
|
|
5004
5844
|
var sanitizeLogFileName = (value) => value.replace(/[^a-zA-Z0-9._-]/g, "_") || "unknown";
|
|
5005
5845
|
var createWorkspaceLogSink = (appendLog) => {
|
|
5006
5846
|
const logDirectory = resolve8(".absolutejs", "workspace", "logs");
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5847
|
+
mkdirSync6(logDirectory, { recursive: true });
|
|
5848
|
+
readdirSync2(logDirectory).filter((file) => file.endsWith(".log")).forEach((file) => unlinkSync3(resolve8(logDirectory, file)));
|
|
5849
|
+
writeFileSync4(resolve8(logDirectory, "all.log"), "");
|
|
5850
|
+
writeFileSync4(resolve8(logDirectory, "workspace.log"), "");
|
|
5011
5851
|
const initializedSources = new Set(["workspace"]);
|
|
5012
5852
|
const writeLog = (source, message, level) => {
|
|
5013
5853
|
const cleanMessage = stripAnsi2(message).trimEnd();
|
|
@@ -5019,7 +5859,7 @@ var createWorkspaceLogSink = (appendLog) => {
|
|
|
5019
5859
|
`;
|
|
5020
5860
|
const sourceFile = resolve8(logDirectory, `${sanitizeLogFileName(source)}.log`);
|
|
5021
5861
|
if (!initializedSources.has(source)) {
|
|
5022
|
-
|
|
5862
|
+
writeFileSync4(sourceFile, "");
|
|
5023
5863
|
initializedSources.add(source);
|
|
5024
5864
|
}
|
|
5025
5865
|
appendFileSync(sourceFile, line);
|
|
@@ -5035,7 +5875,7 @@ var createWorkspaceLogSink = (appendLog) => {
|
|
|
5035
5875
|
};
|
|
5036
5876
|
var readPackageVersion3 = (candidate) => {
|
|
5037
5877
|
try {
|
|
5038
|
-
const pkg = JSON.parse(
|
|
5878
|
+
const pkg = JSON.parse(readFileSync12(candidate, "utf-8"));
|
|
5039
5879
|
if (pkg.name !== "@absolutejs/absolute") {
|
|
5040
5880
|
return null;
|
|
5041
5881
|
}
|
|
@@ -5407,6 +6247,7 @@ var resolveAbsoluteServiceConfigPath = (service, cwd, options) => {
|
|
|
5407
6247
|
var resolveService = (name, service, workspaceEnv, options) => {
|
|
5408
6248
|
const cwd = resolve8(service.cwd ?? ".");
|
|
5409
6249
|
const envVars = Object.assign(getDefinedProcessEnv(), workspaceEnv, service.port ? { PORT: String(service.port) } : {}, service.env, {
|
|
6250
|
+
ABSOLUTE_INSTANCE_MANAGED: "1",
|
|
5410
6251
|
ABSOLUTE_WORKSPACE_MANAGED: "1",
|
|
5411
6252
|
ABSOLUTE_WORKSPACE_SERVICE_NAME: name,
|
|
5412
6253
|
ABSOLUTE_WORKSPACE_SERVICE_VISIBILITY: getVisibility(service),
|
|
@@ -5512,6 +6353,7 @@ var workspace = async (subcommand, options) => {
|
|
|
5512
6353
|
try {
|
|
5513
6354
|
service.process.kill();
|
|
5514
6355
|
} catch {}
|
|
6356
|
+
deregisterInstance(service.process.pid);
|
|
5515
6357
|
};
|
|
5516
6358
|
const runShutdownHookSafely = async (service) => {
|
|
5517
6359
|
try {
|
|
@@ -5654,6 +6496,22 @@ var workspace = async (subcommand, options) => {
|
|
|
5654
6496
|
resolved
|
|
5655
6497
|
};
|
|
5656
6498
|
running.push(runningService);
|
|
6499
|
+
registerInstance({
|
|
6500
|
+
command: [],
|
|
6501
|
+
configPath: resolved.configPath ?? null,
|
|
6502
|
+
controllerPid: process.pid,
|
|
6503
|
+
cwd: resolved.cwd,
|
|
6504
|
+
frameworks: [],
|
|
6505
|
+
host: getServicePublicHost(resolved.service),
|
|
6506
|
+
https: getServiceProtocol(resolved.service) === "https",
|
|
6507
|
+
logFile: resolve8(workspaceLogs.logDirectory, `${sanitizeLogFileName(name)}.log`),
|
|
6508
|
+
name,
|
|
6509
|
+
pid: processHandle.pid,
|
|
6510
|
+
port: resolved.service.port ?? null,
|
|
6511
|
+
ppid: process.pid,
|
|
6512
|
+
source: "workspace",
|
|
6513
|
+
startedAt: new Date().toISOString()
|
|
6514
|
+
});
|
|
5657
6515
|
processHandle.exited.then(handleServiceExit.bind(null, runningService));
|
|
5658
6516
|
await waitForReady(resolved);
|
|
5659
6517
|
const startedAt = serviceBootStartedAt.get(name);
|
|
@@ -5810,6 +6668,10 @@ if (command === "dev") {
|
|
|
5810
6668
|
} else if (command === "prettier") {
|
|
5811
6669
|
sendTelemetryEvent("cli:command", { command });
|
|
5812
6670
|
await prettier(args);
|
|
6671
|
+
} else if (command === "ls" || command === "list" || command === "ps") {
|
|
6672
|
+
sendTelemetryEvent("cli:command", { command: "ls" });
|
|
6673
|
+
const { runList: runList2 } = await Promise.resolve().then(() => (init_list(), exports_list));
|
|
6674
|
+
await runList2(args);
|
|
5813
6675
|
} else if (command === "info") {
|
|
5814
6676
|
sendTelemetryEvent("cli:command", { command });
|
|
5815
6677
|
info();
|
|
@@ -5847,6 +6709,7 @@ if (command === "dev") {
|
|
|
5847
6709
|
console.error(" config [--port n] Open the unified config UI (ESLint, tsconfig, Prettier)");
|
|
5848
6710
|
console.error(" eslint Run ESLint (cached)");
|
|
5849
6711
|
console.error(" info Print system info for bug reports");
|
|
6712
|
+
console.error(" ls [--watch] [--json] List/manage running servers (alias: list)");
|
|
5850
6713
|
console.error(" prettier Run Prettier check (cached)");
|
|
5851
6714
|
console.error(" typecheck Run type checkers for all frameworks");
|
|
5852
6715
|
console.error(" telemetry Manage anonymous telemetry");
|