@absolutejs/absolute 0.19.0-beta.1016 → 0.19.0-beta.1018
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 +1215 -303
- 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,126 @@ 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 = [
|
|
506
|
+
"compiled",
|
|
507
|
+
"dev",
|
|
508
|
+
"standalone",
|
|
509
|
+
"start",
|
|
510
|
+
"workspace"
|
|
511
|
+
];
|
|
512
|
+
});
|
|
513
|
+
|
|
394
514
|
// src/utils/loadConfig.ts
|
|
395
515
|
import { resolve } from "path";
|
|
396
516
|
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 +615,11 @@ var init_loadConfig = __esm(() => {
|
|
|
495
615
|
// src/cli/utils.ts
|
|
496
616
|
var {$ } = globalThis.Bun;
|
|
497
617
|
import { execSync } from "child_process";
|
|
498
|
-
import { existsSync as existsSync3, readFileSync as
|
|
618
|
+
import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
|
|
499
619
|
import { resolve as resolve2 } from "path";
|
|
500
620
|
var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backend/server.ts", isWSLEnvironment = () => {
|
|
501
621
|
try {
|
|
502
|
-
const release =
|
|
622
|
+
const release = readFileSync5("/proc/version", "utf-8");
|
|
503
623
|
return /microsoft|wsl/i.test(release);
|
|
504
624
|
} catch {
|
|
505
625
|
return false;
|
|
@@ -532,6 +652,32 @@ var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backe
|
|
|
532
652
|
return;
|
|
533
653
|
}
|
|
534
654
|
console.log(`\x1B[2m${formatTimestamp()}\x1B[0m \x1B[33m[cli]\x1B[0m \x1B[33m${message}\x1B[0m`);
|
|
655
|
+
}, openUrlInBrowser = (url, onError) => {
|
|
656
|
+
if (process.env.ABSOLUTE_NO_OPEN)
|
|
657
|
+
return false;
|
|
658
|
+
const { platform: platform2 } = process;
|
|
659
|
+
const isWSL = platform2 === "linux" && isWSLEnvironment();
|
|
660
|
+
let command;
|
|
661
|
+
if (isWSL) {
|
|
662
|
+
command = "cmd.exe";
|
|
663
|
+
} else if (platform2 === "darwin") {
|
|
664
|
+
command = "open";
|
|
665
|
+
} else if (platform2 === "win32") {
|
|
666
|
+
command = "start";
|
|
667
|
+
} else {
|
|
668
|
+
command = "xdg-open";
|
|
669
|
+
}
|
|
670
|
+
const commandArgs = isWSL ? ["/c", "start", url] : [url];
|
|
671
|
+
try {
|
|
672
|
+
Bun.spawn([command, ...commandArgs], {
|
|
673
|
+
stderr: "ignore",
|
|
674
|
+
stdout: "ignore"
|
|
675
|
+
});
|
|
676
|
+
return true;
|
|
677
|
+
} catch {
|
|
678
|
+
onError?.(`Could not open browser automatically. Visit ${url}`);
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
535
681
|
}, printHelp = (subject = "server") => {
|
|
536
682
|
const title = subject === "workspace" ? "workspace" : subject;
|
|
537
683
|
console.log("");
|
|
@@ -592,15 +738,15 @@ __export(exports_devCert, {
|
|
|
592
738
|
import {
|
|
593
739
|
copyFileSync,
|
|
594
740
|
existsSync as existsSync4,
|
|
595
|
-
mkdirSync as
|
|
596
|
-
readFileSync as
|
|
741
|
+
mkdirSync as mkdirSync4,
|
|
742
|
+
readFileSync as readFileSync6,
|
|
597
743
|
rmSync
|
|
598
744
|
} from "fs";
|
|
599
745
|
import { platform as platform2 } from "os";
|
|
600
|
-
import { join as
|
|
746
|
+
import { join as join5 } from "path";
|
|
601
747
|
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
748
|
try {
|
|
603
|
-
const certPem =
|
|
749
|
+
const certPem = readFileSync6(CERT_PATH, "utf-8");
|
|
604
750
|
const proc = Bun.spawnSync(["openssl", "x509", "-enddate", "-noout"], {
|
|
605
751
|
stdin: new TextEncoder().encode(certPem)
|
|
606
752
|
});
|
|
@@ -669,7 +815,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
|
|
|
669
815
|
generateSelfSigned();
|
|
670
816
|
}
|
|
671
817
|
}, ensureDevCert = () => {
|
|
672
|
-
|
|
818
|
+
mkdirSync4(CERT_DIR, { recursive: true });
|
|
673
819
|
if (hasCert()) {
|
|
674
820
|
return { cert: CERT_PATH, key: KEY_PATH };
|
|
675
821
|
}
|
|
@@ -689,8 +835,8 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
|
|
|
689
835
|
return null;
|
|
690
836
|
try {
|
|
691
837
|
return {
|
|
692
|
-
cert:
|
|
693
|
-
key:
|
|
838
|
+
cert: readFileSync6(paths.cert, "utf-8"),
|
|
839
|
+
key: readFileSync6(paths.key, "utf-8")
|
|
694
840
|
};
|
|
695
841
|
} catch {
|
|
696
842
|
return null;
|
|
@@ -786,7 +932,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
|
|
|
786
932
|
if (platform2() !== "linux")
|
|
787
933
|
return false;
|
|
788
934
|
try {
|
|
789
|
-
return /microsoft|wsl/i.test(
|
|
935
|
+
return /microsoft|wsl/i.test(readFileSync6("/proc/version", "utf-8"));
|
|
790
936
|
} catch {
|
|
791
937
|
return false;
|
|
792
938
|
}
|
|
@@ -809,13 +955,13 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
|
|
|
809
955
|
const caRoot = mkcertCaRoot();
|
|
810
956
|
if (!caRoot)
|
|
811
957
|
return false;
|
|
812
|
-
const rootCa =
|
|
958
|
+
const rootCa = join5(caRoot, "rootCA.pem");
|
|
813
959
|
if (!existsSync4(rootCa))
|
|
814
960
|
return false;
|
|
815
961
|
const winTemp = windowsTempDir();
|
|
816
962
|
if (!winTemp)
|
|
817
963
|
return false;
|
|
818
|
-
const staged =
|
|
964
|
+
const staged = join5(winTemp, "absolutejs-mkcert-rootCA.crt");
|
|
819
965
|
try {
|
|
820
966
|
copyFileSync(rootCa, staged);
|
|
821
967
|
} catch {
|
|
@@ -851,7 +997,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
|
|
|
851
997
|
devLog("Trusted the local CA in the Windows store \u2014 Chrome/Edge on Windows now accept dev HTTPS");
|
|
852
998
|
} else {
|
|
853
999
|
const caRoot = mkcertCaRoot();
|
|
854
|
-
const hint = caRoot ? toWindowsPath(
|
|
1000
|
+
const hint = caRoot ? toWindowsPath(join5(caRoot, "rootCA.pem")) : null;
|
|
855
1001
|
devWarn("Could not auto-trust the local CA on Windows; Windows browsers may warn.");
|
|
856
1002
|
if (hint) {
|
|
857
1003
|
console.log(` Run in PowerShell: Import-Certificate -FilePath "${hint}" -CertStoreLocation Cert:\\CurrentUser\\Root`);
|
|
@@ -860,16 +1006,16 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
|
|
|
860
1006
|
}
|
|
861
1007
|
rmSync(CERT_PATH, { force: true });
|
|
862
1008
|
rmSync(KEY_PATH, { force: true });
|
|
863
|
-
|
|
1009
|
+
mkdirSync4(CERT_DIR, { recursive: true });
|
|
864
1010
|
generateWithMkcert();
|
|
865
1011
|
console.log("");
|
|
866
1012
|
devLog("mkcert installed \u2014 HTTPS certificates are now locally trusted");
|
|
867
1013
|
return true;
|
|
868
1014
|
};
|
|
869
1015
|
var init_devCert = __esm(() => {
|
|
870
|
-
CERT_DIR =
|
|
871
|
-
CERT_PATH =
|
|
872
|
-
KEY_PATH =
|
|
1016
|
+
CERT_DIR = join5(process.cwd(), ".absolutejs");
|
|
1017
|
+
CERT_PATH = join5(CERT_DIR, "cert.pem");
|
|
1018
|
+
KEY_PATH = join5(CERT_DIR, "key.pem");
|
|
873
1019
|
});
|
|
874
1020
|
|
|
875
1021
|
// src/core/prerender.ts
|
|
@@ -882,15 +1028,15 @@ __export(exports_prerender, {
|
|
|
882
1028
|
prerender: () => prerender,
|
|
883
1029
|
PRERENDER_BYPASS_HEADER: () => PRERENDER_BYPASS_HEADER
|
|
884
1030
|
});
|
|
885
|
-
import { mkdirSync as
|
|
886
|
-
import { join as
|
|
1031
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync10 } from "fs";
|
|
1032
|
+
import { join as join7 } from "path";
|
|
887
1033
|
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
1034
|
const metaPath = htmlPath.replace(/\.html$/, ".meta");
|
|
889
1035
|
await Bun.write(metaPath, String(Date.now()));
|
|
890
1036
|
}, readTimestamp = (htmlPath) => {
|
|
891
1037
|
const metaPath = htmlPath.replace(/\.html$/, ".meta");
|
|
892
1038
|
try {
|
|
893
|
-
const content =
|
|
1039
|
+
const content = readFileSync10(metaPath, "utf-8");
|
|
894
1040
|
return Number(content) || 0;
|
|
895
1041
|
} catch {
|
|
896
1042
|
return 0;
|
|
@@ -949,7 +1095,7 @@ var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_
|
|
|
949
1095
|
return false;
|
|
950
1096
|
const html = await res.text();
|
|
951
1097
|
const fileName = routeToFilename(route);
|
|
952
|
-
const filePath =
|
|
1098
|
+
const filePath = join7(prerenderDir, fileName);
|
|
953
1099
|
await Bun.write(filePath, html);
|
|
954
1100
|
await writeTimestamp(filePath);
|
|
955
1101
|
return true;
|
|
@@ -975,14 +1121,14 @@ var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_
|
|
|
975
1121
|
}
|
|
976
1122
|
const html = await res.text();
|
|
977
1123
|
const fileName = routeToFilename(route);
|
|
978
|
-
const filePath =
|
|
1124
|
+
const filePath = join7(prerenderDir, fileName);
|
|
979
1125
|
await Bun.write(filePath, html);
|
|
980
1126
|
await writeTimestamp(filePath);
|
|
981
1127
|
result.routes.set(route, filePath);
|
|
982
1128
|
log?.(` Pre-rendered ${route} \u2192 ${fileName} (${html.length} bytes)`);
|
|
983
1129
|
}, prerender = async (port, outDir, staticConfig, log) => {
|
|
984
|
-
const prerenderDir =
|
|
985
|
-
|
|
1130
|
+
const prerenderDir = join7(outDir, "_prerendered");
|
|
1131
|
+
mkdirSync5(prerenderDir, { recursive: true });
|
|
986
1132
|
const baseUrl = `http://localhost:${port}`;
|
|
987
1133
|
let routes;
|
|
988
1134
|
if (staticConfig.routes === "all") {
|
|
@@ -1138,7 +1284,7 @@ var init_nativeRewrite = __esm(() => {
|
|
|
1138
1284
|
|
|
1139
1285
|
// src/build/rewriteImportsPlugin.ts
|
|
1140
1286
|
import { readdir } from "fs/promises";
|
|
1141
|
-
import { join as
|
|
1287
|
+
import { join as join8 } from "path";
|
|
1142
1288
|
var escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), jsRewriteImports = (content, replacements) => {
|
|
1143
1289
|
let result = content;
|
|
1144
1290
|
for (const [specifier, webPath] of replacements) {
|
|
@@ -1216,7 +1362,7 @@ ${content}`;
|
|
|
1216
1362
|
const entries = await readdir(dir);
|
|
1217
1363
|
for (const entry of entries) {
|
|
1218
1364
|
if (entry.endsWith(".js"))
|
|
1219
|
-
allFiles.push(
|
|
1365
|
+
allFiles.push(join8(dir, entry));
|
|
1220
1366
|
}
|
|
1221
1367
|
} catch {}
|
|
1222
1368
|
}
|
|
@@ -1270,86 +1416,837 @@ var rewriteImports = async (outputPaths, vendorPaths) => {
|
|
|
1270
1416
|
return;
|
|
1271
1417
|
throw err;
|
|
1272
1418
|
}
|
|
1273
|
-
const rewritten = rewriteImportsInContent(original, vendorPaths);
|
|
1274
|
-
if (rewritten === original)
|
|
1419
|
+
const rewritten = rewriteImportsInContent(original, vendorPaths);
|
|
1420
|
+
if (rewritten === original)
|
|
1421
|
+
return;
|
|
1422
|
+
try {
|
|
1423
|
+
await Bun.write(filePath, rewritten);
|
|
1424
|
+
} catch (err) {
|
|
1425
|
+
const code = err.code;
|
|
1426
|
+
if (code === "ENOENT")
|
|
1427
|
+
return;
|
|
1428
|
+
throw err;
|
|
1429
|
+
}
|
|
1430
|
+
}));
|
|
1431
|
+
}, rewriteVendorDirectories2;
|
|
1432
|
+
var init_rewriteImports = __esm(() => {
|
|
1433
|
+
init_rewriteImportsPlugin();
|
|
1434
|
+
rewriteVendorDirectories2 = rewriteVendorDirectories;
|
|
1435
|
+
});
|
|
1436
|
+
|
|
1437
|
+
// src/cli/tuiPrimitives.ts
|
|
1438
|
+
import { openSync as openSync2 } from "fs";
|
|
1439
|
+
import { ReadStream as ReadStream2 } from "tty";
|
|
1440
|
+
var ANSI_REGEX, trySetRawMode2 = () => {
|
|
1441
|
+
if (typeof process.stdin.setRawMode !== "function") {
|
|
1442
|
+
return null;
|
|
1443
|
+
}
|
|
1444
|
+
try {
|
|
1445
|
+
process.stdin.setRawMode(true);
|
|
1446
|
+
} catch {
|
|
1447
|
+
return null;
|
|
1448
|
+
}
|
|
1449
|
+
return process.stdin;
|
|
1450
|
+
}, splitLongWord = (word, width) => {
|
|
1451
|
+
const parts = [];
|
|
1452
|
+
for (let index = 0;index < word.length; index += width) {
|
|
1453
|
+
parts.push(word.slice(index, index + width));
|
|
1454
|
+
}
|
|
1455
|
+
return parts;
|
|
1456
|
+
}, appendWrappedWord = (lines, current, word, width) => {
|
|
1457
|
+
if (current.length === 0) {
|
|
1458
|
+
if (word.length <= width)
|
|
1459
|
+
return word;
|
|
1460
|
+
lines.push(...splitLongWord(word, width));
|
|
1461
|
+
return "";
|
|
1462
|
+
}
|
|
1463
|
+
const next = `${current} ${word}`;
|
|
1464
|
+
if (next.length <= width)
|
|
1465
|
+
return next;
|
|
1466
|
+
lines.push(current);
|
|
1467
|
+
if (word.length <= width)
|
|
1468
|
+
return word;
|
|
1469
|
+
lines.push(...splitLongWord(word, width));
|
|
1470
|
+
return "";
|
|
1471
|
+
}, wrapLine = (line, width) => {
|
|
1472
|
+
if (line.length === 0)
|
|
1473
|
+
return [""];
|
|
1474
|
+
if (line.length <= width)
|
|
1475
|
+
return [line];
|
|
1476
|
+
const lines = [];
|
|
1477
|
+
let current = "";
|
|
1478
|
+
for (const word of line.split(/\s+/)) {
|
|
1479
|
+
current = appendWrappedWord(lines, current, word, width);
|
|
1480
|
+
}
|
|
1481
|
+
if (current.length > 0)
|
|
1482
|
+
lines.push(current);
|
|
1483
|
+
return lines;
|
|
1484
|
+
}, ANSI_ESCAPE_PREFIX = "\x1B[", colors, ESCAPE = "\x1B", appendRightEdge = (value, width, marker) => {
|
|
1485
|
+
if (width <= 0) {
|
|
1486
|
+
return "";
|
|
1487
|
+
}
|
|
1488
|
+
return `${padLine(value, Math.max(0, width - 1))}${marker}`;
|
|
1489
|
+
}, formatTimestamp2 = () => new Date().toLocaleTimeString([], {
|
|
1490
|
+
hour: "numeric",
|
|
1491
|
+
hour12: true,
|
|
1492
|
+
minute: "2-digit",
|
|
1493
|
+
second: "2-digit"
|
|
1494
|
+
}), isPartialEscapeSequence = (value) => {
|
|
1495
|
+
if (!value.startsWith(ANSI_ESCAPE_PREFIX)) {
|
|
1496
|
+
return false;
|
|
1497
|
+
}
|
|
1498
|
+
return Array.from(value.slice(ANSI_ESCAPE_PREFIX.length)).every((char) => char >= "0" && char <= "9");
|
|
1499
|
+
}, openTtyStream2 = () => {
|
|
1500
|
+
const fromStdin = trySetRawMode2();
|
|
1501
|
+
if (fromStdin) {
|
|
1502
|
+
return fromStdin;
|
|
1503
|
+
}
|
|
1504
|
+
try {
|
|
1505
|
+
const ttyStream = new ReadStream2(openSync2("/dev/tty", "r"));
|
|
1506
|
+
ttyStream.setRawMode(true);
|
|
1507
|
+
return ttyStream;
|
|
1508
|
+
} catch {
|
|
1509
|
+
return null;
|
|
1510
|
+
}
|
|
1511
|
+
}, padLine = (value, width) => {
|
|
1512
|
+
const plainLength = visibleLength(value);
|
|
1513
|
+
if (plainLength >= width) {
|
|
1514
|
+
return value;
|
|
1515
|
+
}
|
|
1516
|
+
return `${value}${" ".repeat(width - plainLength)}`;
|
|
1517
|
+
}, stripAnsi = (value) => value.replace(ANSI_REGEX, ""), truncateText = (value, width) => {
|
|
1518
|
+
if (width <= 0) {
|
|
1519
|
+
return "";
|
|
1520
|
+
}
|
|
1521
|
+
if (value.length <= width) {
|
|
1522
|
+
return value;
|
|
1523
|
+
}
|
|
1524
|
+
if (width <= 1) {
|
|
1525
|
+
return value.slice(0, width);
|
|
1526
|
+
}
|
|
1527
|
+
return `${value.slice(0, width - 1)}\u2026`;
|
|
1528
|
+
}, visibleLength = (value) => value.replace(ANSI_REGEX, "").length, wrapText = (value, width) => {
|
|
1529
|
+
if (width <= 0) {
|
|
1530
|
+
return [""];
|
|
1531
|
+
}
|
|
1532
|
+
const lines = value.split(`
|
|
1533
|
+
`).flatMap((rawLine) => wrapLine(rawLine.trimEnd(), width));
|
|
1534
|
+
return lines.length > 0 ? lines : [""];
|
|
1535
|
+
};
|
|
1536
|
+
var init_tuiPrimitives = __esm(() => {
|
|
1537
|
+
init_constants();
|
|
1538
|
+
ANSI_REGEX = new RegExp(`${String.fromCharCode(ANSI_ESCAPE_CODE)}\\[[0-?]*[ -/]*[@-~]`, "g");
|
|
1539
|
+
colors = {
|
|
1540
|
+
bold: "\x1B[1m",
|
|
1541
|
+
cyan: "\x1B[36m",
|
|
1542
|
+
dim: "\x1B[2m",
|
|
1543
|
+
green: "\x1B[32m",
|
|
1544
|
+
red: "\x1B[31m",
|
|
1545
|
+
reset: "\x1B[0m",
|
|
1546
|
+
yellow: "\x1B[33m"
|
|
1547
|
+
};
|
|
1548
|
+
});
|
|
1549
|
+
|
|
1550
|
+
// src/cli/scripts/build.ts
|
|
1551
|
+
var exports_build = {};
|
|
1552
|
+
__export(exports_build, {
|
|
1553
|
+
build: () => build
|
|
1554
|
+
});
|
|
1555
|
+
import { resolve as resolve9 } from "path";
|
|
1556
|
+
var cliTag3 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, tryImportBuild2 = async (candidate) => {
|
|
1557
|
+
try {
|
|
1558
|
+
const mod = await import(candidate);
|
|
1559
|
+
const buildFn = mod.build;
|
|
1560
|
+
return buildFn;
|
|
1561
|
+
} catch {
|
|
1562
|
+
return null;
|
|
1563
|
+
}
|
|
1564
|
+
}, resolveBuildModule2 = async (candidates) => {
|
|
1565
|
+
const [candidate, ...remaining] = candidates;
|
|
1566
|
+
if (!candidate) {
|
|
1567
|
+
return;
|
|
1568
|
+
}
|
|
1569
|
+
const mod = await tryImportBuild2(candidate);
|
|
1570
|
+
if (mod) {
|
|
1571
|
+
return mod;
|
|
1572
|
+
}
|
|
1573
|
+
return resolveBuildModule2(remaining);
|
|
1574
|
+
}, build = async (outdir, configPath2) => {
|
|
1575
|
+
const resolvedOutdir = resolve9(outdir ?? "build");
|
|
1576
|
+
const buildStart = performance.now();
|
|
1577
|
+
process.stdout.write(cliTag3("\x1B[36m", "Building assets"));
|
|
1578
|
+
const buildConfig = await loadConfig(configPath2);
|
|
1579
|
+
buildConfig.buildDirectory = resolvedOutdir;
|
|
1580
|
+
buildConfig.mode = "production";
|
|
1581
|
+
try {
|
|
1582
|
+
const buildApp = await resolveBuildModule2([
|
|
1583
|
+
resolve9(import.meta.dir, "..", "..", "core", "build"),
|
|
1584
|
+
resolve9(import.meta.dir, "..", "build")
|
|
1585
|
+
]);
|
|
1586
|
+
if (!buildApp)
|
|
1587
|
+
throw new Error("Could not locate build module");
|
|
1588
|
+
await buildApp(buildConfig);
|
|
1589
|
+
} catch (err) {
|
|
1590
|
+
sendTelemetryEvent("build:error", {
|
|
1591
|
+
durationMs: Math.round(performance.now() - buildStart)
|
|
1592
|
+
});
|
|
1593
|
+
console.error(cliTag3("\x1B[31m", "Build step failed."));
|
|
1594
|
+
console.error(err);
|
|
1595
|
+
process.exit(1);
|
|
1596
|
+
}
|
|
1597
|
+
sendTelemetryEvent("build:complete", {
|
|
1598
|
+
durationMs: Math.round(performance.now() - buildStart)
|
|
1599
|
+
});
|
|
1600
|
+
console.log(` \x1B[2m(${getDurationString(performance.now() - buildStart)})\x1B[0m`);
|
|
1601
|
+
};
|
|
1602
|
+
var init_build = __esm(() => {
|
|
1603
|
+
init_getDurationString();
|
|
1604
|
+
init_loadConfig();
|
|
1605
|
+
init_startupBanner();
|
|
1606
|
+
init_telemetryEvent();
|
|
1607
|
+
});
|
|
1608
|
+
|
|
1609
|
+
// src/cli/instanceStatus.ts
|
|
1610
|
+
import { createConnection as createConnection2 } from "net";
|
|
1611
|
+
var displayHost = (host) => host === "0.0.0.0" || host === "::" ? "localhost" : host, probePort = (host, port) => {
|
|
1612
|
+
const { promise, resolve: resolve10 } = Promise.withResolvers();
|
|
1613
|
+
const socket = createConnection2({ host: displayHost(host), port });
|
|
1614
|
+
const timeout = setTimeout(() => {
|
|
1615
|
+
socket.destroy();
|
|
1616
|
+
resolve10(false);
|
|
1617
|
+
}, INSTANCE_PROBE_TIMEOUT_MS);
|
|
1618
|
+
socket.once("connect", () => {
|
|
1619
|
+
clearTimeout(timeout);
|
|
1620
|
+
socket.end();
|
|
1621
|
+
resolve10(true);
|
|
1622
|
+
});
|
|
1623
|
+
socket.once("error", () => {
|
|
1624
|
+
clearTimeout(timeout);
|
|
1625
|
+
socket.destroy();
|
|
1626
|
+
resolve10(false);
|
|
1627
|
+
});
|
|
1628
|
+
return promise;
|
|
1629
|
+
}, probeStatus = async (record) => {
|
|
1630
|
+
if (record.port === null) {
|
|
1631
|
+
return "starting";
|
|
1632
|
+
}
|
|
1633
|
+
const reachable = await probePort(record.host, record.port);
|
|
1634
|
+
return reachable ? "ready" : "starting";
|
|
1635
|
+
}, enrichInstances = async (records) => {
|
|
1636
|
+
const now = Date.now();
|
|
1637
|
+
const statuses = await Promise.all(records.map(probeStatus));
|
|
1638
|
+
return records.map((record, index) => ({
|
|
1639
|
+
...record,
|
|
1640
|
+
status: statuses[index] ?? "starting",
|
|
1641
|
+
uptimeMs: Math.max(0, now - Date.parse(record.startedAt)),
|
|
1642
|
+
url: instanceUrl(record)
|
|
1643
|
+
}));
|
|
1644
|
+
}, instanceUrl = (record) => {
|
|
1645
|
+
if (record.port === null)
|
|
1646
|
+
return null;
|
|
1647
|
+
return `${record.https ? "https" : "http"}://${displayHost(record.host)}:${record.port}/`;
|
|
1648
|
+
};
|
|
1649
|
+
var init_instanceStatus = __esm(() => {
|
|
1650
|
+
init_constants();
|
|
1651
|
+
});
|
|
1652
|
+
|
|
1653
|
+
// src/cli/listTui.ts
|
|
1654
|
+
var exports_listTui = {};
|
|
1655
|
+
__export(exports_listTui, {
|
|
1656
|
+
runListTui: () => runListTui
|
|
1657
|
+
});
|
|
1658
|
+
import { spawn } from "child_process";
|
|
1659
|
+
import { closeSync, fstatSync, openSync as openSync3, readSync } from "fs";
|
|
1660
|
+
var TUI_HEADERS, STATUS_INDEX = 5, URL_INDEX = 6, helpLines2, statusLevelColor = (level) => {
|
|
1661
|
+
if (level === "error")
|
|
1662
|
+
return colors.red;
|
|
1663
|
+
if (level === "warn")
|
|
1664
|
+
return colors.yellow;
|
|
1665
|
+
if (level === "success")
|
|
1666
|
+
return colors.green;
|
|
1667
|
+
return colors.cyan;
|
|
1668
|
+
}, statusColor = (status2) => {
|
|
1669
|
+
if (status2 === "ready")
|
|
1670
|
+
return colors.green;
|
|
1671
|
+
if (status2 === "starting")
|
|
1672
|
+
return colors.yellow;
|
|
1673
|
+
return colors.dim;
|
|
1674
|
+
}, instanceRowCells = (instance) => [
|
|
1675
|
+
instance.name,
|
|
1676
|
+
instance.source,
|
|
1677
|
+
instance.port === null ? "-" : String(instance.port),
|
|
1678
|
+
String(instance.pid),
|
|
1679
|
+
getDurationString(instance.uptimeMs),
|
|
1680
|
+
instance.status,
|
|
1681
|
+
instance.url ?? "-"
|
|
1682
|
+
], columnWidths = (allCells) => TUI_HEADERS.map((header, index) => Math.max(visibleLength(header), ...allCells.map((cells) => visibleLength(cells[index] ?? "")))), layoutWidths = (allCells, width) => {
|
|
1683
|
+
const natural = columnWidths(allCells);
|
|
1684
|
+
const gaps = (TUI_HEADERS.length - 1) * LIST_TUI_COLUMN_GAP;
|
|
1685
|
+
const available = width - LIST_TUI_MARKER_WIDTH - gaps;
|
|
1686
|
+
const fixed = natural.reduce((sum, value, index) => index === URL_INDEX ? sum : sum + value, 0);
|
|
1687
|
+
const urlWidth = Math.max(LIST_TUI_MIN_URL_WIDTH, available - fixed);
|
|
1688
|
+
return natural.map((value, index) => index === URL_INDEX ? Math.min(value, urlWidth) : value);
|
|
1689
|
+
}, openReadFd = (path) => {
|
|
1690
|
+
try {
|
|
1691
|
+
return openSync3(path, "r");
|
|
1692
|
+
} catch {
|
|
1693
|
+
return null;
|
|
1694
|
+
}
|
|
1695
|
+
}, readLogTail = (path) => {
|
|
1696
|
+
if (!path)
|
|
1697
|
+
return [];
|
|
1698
|
+
const descriptor = openReadFd(path);
|
|
1699
|
+
if (descriptor === null)
|
|
1700
|
+
return [];
|
|
1701
|
+
try {
|
|
1702
|
+
const { size } = fstatSync(descriptor);
|
|
1703
|
+
const start2 = Math.max(0, size - LIST_LOG_TAIL_MAX_BYTES);
|
|
1704
|
+
const length = size - start2;
|
|
1705
|
+
const buffer = Buffer.alloc(length);
|
|
1706
|
+
readSync(descriptor, buffer, 0, length, start2);
|
|
1707
|
+
return buffer.toString("utf-8").split(`
|
|
1708
|
+
`).filter((line) => line.trim().length > 0);
|
|
1709
|
+
} finally {
|
|
1710
|
+
closeSync(descriptor);
|
|
1711
|
+
}
|
|
1712
|
+
}, driveListTui = async (terminal) => {
|
|
1713
|
+
const { promise, resolve: resolveExit } = Promise.withResolvers();
|
|
1714
|
+
let instances = [];
|
|
1715
|
+
let selectedIndex = 0;
|
|
1716
|
+
let mode = "list";
|
|
1717
|
+
let helpVisible = false;
|
|
1718
|
+
let portBuffer = "";
|
|
1719
|
+
let statusMessage = null;
|
|
1720
|
+
let statusTimer = null;
|
|
1721
|
+
let renderTimer = null;
|
|
1722
|
+
let refreshTimer = null;
|
|
1723
|
+
let escapeBuffer = "";
|
|
1724
|
+
let escapeTimer = null;
|
|
1725
|
+
let disposed = false;
|
|
1726
|
+
let logScrollOffset = 0;
|
|
1727
|
+
let lastLogLineCount = 0;
|
|
1728
|
+
let lastLogViewportHeight = 0;
|
|
1729
|
+
const selectedInstance = () => instances[selectedIndex];
|
|
1730
|
+
const scheduleRender = () => {
|
|
1731
|
+
if (disposed || renderTimer)
|
|
1732
|
+
return;
|
|
1733
|
+
renderTimer = setTimeout(() => {
|
|
1734
|
+
renderTimer = null;
|
|
1735
|
+
render();
|
|
1736
|
+
}, LIST_TUI_RENDER_DEBOUNCE_MS);
|
|
1737
|
+
};
|
|
1738
|
+
const setStatus = (text, level) => {
|
|
1739
|
+
statusMessage = { level, text };
|
|
1740
|
+
if (statusTimer)
|
|
1741
|
+
clearTimeout(statusTimer);
|
|
1742
|
+
statusTimer = setTimeout(() => {
|
|
1743
|
+
statusMessage = null;
|
|
1744
|
+
scheduleRender();
|
|
1745
|
+
}, LIST_TUI_STATUS_MESSAGE_TIMEOUT_MS);
|
|
1746
|
+
scheduleRender();
|
|
1747
|
+
};
|
|
1748
|
+
const refresh = async () => {
|
|
1749
|
+
const previousPid = selectedInstance()?.pid;
|
|
1750
|
+
instances = await enrichInstances(listLiveInstances());
|
|
1751
|
+
const foundIndex = previousPid === undefined ? 0 : instances.findIndex((instance) => instance.pid === previousPid);
|
|
1752
|
+
selectedIndex = foundIndex >= 0 ? foundIndex : Math.min(selectedIndex, Math.max(0, instances.length - 1));
|
|
1753
|
+
scheduleRender();
|
|
1754
|
+
};
|
|
1755
|
+
const signalPid = (pid, signal) => {
|
|
1756
|
+
try {
|
|
1757
|
+
process.kill(-pid, signal);
|
|
1758
|
+
return;
|
|
1759
|
+
} catch {}
|
|
1760
|
+
try {
|
|
1761
|
+
process.kill(pid, signal);
|
|
1762
|
+
} catch {}
|
|
1763
|
+
};
|
|
1764
|
+
const stopSelected = () => {
|
|
1765
|
+
const instance = selectedInstance();
|
|
1766
|
+
if (!instance)
|
|
1767
|
+
return;
|
|
1768
|
+
signalPid(instance.controllerPid, "SIGTERM");
|
|
1769
|
+
const message = instance.source === "workspace" ? `Stopping ${instance.name}'s workspace (pid ${instance.controllerPid}) \u2014 all its services` : `Stopped ${instance.name} (pid ${instance.controllerPid})`;
|
|
1770
|
+
setStatus(message, "success");
|
|
1771
|
+
refresh();
|
|
1772
|
+
};
|
|
1773
|
+
const restartSelected = () => {
|
|
1774
|
+
const instance = selectedInstance();
|
|
1775
|
+
if (!instance)
|
|
1776
|
+
return;
|
|
1777
|
+
if (instance.source === "workspace") {
|
|
1778
|
+
setStatus(`${instance.name} is managed by its workspace \u2014 restart the workspace itself.`, "warn");
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
const [command, ...commandArgs] = instance.command;
|
|
1782
|
+
if (!command) {
|
|
1783
|
+
setStatus(`Cannot restart ${instance.name}: no launch command recorded.`, "warn");
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1786
|
+
signalPid(instance.controllerPid, "SIGTERM");
|
|
1787
|
+
const child = spawn(command, commandArgs, {
|
|
1788
|
+
cwd: instance.cwd,
|
|
1789
|
+
detached: true,
|
|
1790
|
+
stdio: "ignore"
|
|
1791
|
+
});
|
|
1792
|
+
child.unref();
|
|
1793
|
+
setStatus(`Restarting ${instance.name}\u2026`, "info");
|
|
1794
|
+
refresh();
|
|
1795
|
+
};
|
|
1796
|
+
const openSelected = () => {
|
|
1797
|
+
const instance = selectedInstance();
|
|
1798
|
+
if (!instance)
|
|
1799
|
+
return;
|
|
1800
|
+
if (!instance.url) {
|
|
1801
|
+
setStatus(`${instance.name} has no URL yet.`, "warn");
|
|
1802
|
+
return;
|
|
1803
|
+
}
|
|
1804
|
+
openUrlInBrowser(instance.url, (message) => setStatus(message, "warn"));
|
|
1805
|
+
setStatus(`Opening ${instance.url}`, "info");
|
|
1806
|
+
};
|
|
1807
|
+
const stopAll = () => {
|
|
1808
|
+
const count = instances.length;
|
|
1809
|
+
instances.forEach((instance) => signalPid(instance.pid, "SIGTERM"));
|
|
1810
|
+
setStatus(`Stopped ${count} server${count === 1 ? "" : "s"}.`, "success");
|
|
1811
|
+
refresh();
|
|
1812
|
+
};
|
|
1813
|
+
const freePort = (value) => {
|
|
1814
|
+
const port = Number(value);
|
|
1815
|
+
if (!Number.isInteger(port) || port <= 0) {
|
|
1816
|
+
setStatus(`Invalid port: ${value}`, "error");
|
|
1817
|
+
return;
|
|
1818
|
+
}
|
|
1819
|
+
let killed = false;
|
|
1820
|
+
killStaleProcesses(port, (message) => {
|
|
1821
|
+
killed = true;
|
|
1822
|
+
setStatus(message, "warn");
|
|
1823
|
+
});
|
|
1824
|
+
if (!killed)
|
|
1825
|
+
setStatus(`Nothing is listening on port ${port}.`, "info");
|
|
1826
|
+
refresh();
|
|
1827
|
+
};
|
|
1828
|
+
const moveSelection = (direction) => {
|
|
1829
|
+
if (instances.length === 0)
|
|
1830
|
+
return;
|
|
1831
|
+
const delta = direction === "up" ? UNFOUND_INDEX : 1;
|
|
1832
|
+
selectedIndex = Math.max(0, Math.min(instances.length - 1, selectedIndex + delta));
|
|
1833
|
+
logScrollOffset = 0;
|
|
1834
|
+
scheduleRender();
|
|
1835
|
+
};
|
|
1836
|
+
const scrollLogs = (direction) => {
|
|
1837
|
+
const maxOffset = Math.max(0, lastLogLineCount - lastLogViewportHeight);
|
|
1838
|
+
const pageSize = Math.max(1, lastLogViewportHeight - 1);
|
|
1839
|
+
if (direction === "up") {
|
|
1840
|
+
logScrollOffset = Math.min(maxOffset, logScrollOffset + 1);
|
|
1841
|
+
} else if (direction === "down") {
|
|
1842
|
+
logScrollOffset = Math.max(0, logScrollOffset - 1);
|
|
1843
|
+
} else if (direction === "pageUp") {
|
|
1844
|
+
logScrollOffset = Math.min(maxOffset, logScrollOffset + pageSize);
|
|
1845
|
+
} else {
|
|
1846
|
+
logScrollOffset = Math.max(0, logScrollOffset - pageSize);
|
|
1847
|
+
}
|
|
1848
|
+
scheduleRender();
|
|
1849
|
+
};
|
|
1850
|
+
const dispose = () => {
|
|
1851
|
+
if (disposed)
|
|
1852
|
+
return;
|
|
1853
|
+
disposed = true;
|
|
1854
|
+
if (renderTimer)
|
|
1855
|
+
clearTimeout(renderTimer);
|
|
1856
|
+
if (statusTimer)
|
|
1857
|
+
clearTimeout(statusTimer);
|
|
1858
|
+
if (escapeTimer)
|
|
1859
|
+
clearTimeout(escapeTimer);
|
|
1860
|
+
if (refreshTimer)
|
|
1861
|
+
clearInterval(refreshTimer);
|
|
1862
|
+
process.stdout.off("resize", onResize);
|
|
1863
|
+
terminal.off("data", onData);
|
|
1864
|
+
if (terminal.setRawMode)
|
|
1865
|
+
terminal.setRawMode(false);
|
|
1866
|
+
if (terminal !== process.stdin)
|
|
1867
|
+
terminal.destroy();
|
|
1868
|
+
process.stdout.write("\x1B[?25h\x1B[?1049l");
|
|
1869
|
+
};
|
|
1870
|
+
const quit = () => {
|
|
1871
|
+
dispose();
|
|
1872
|
+
resolveExit();
|
|
1873
|
+
};
|
|
1874
|
+
const listActions = new Map([
|
|
1875
|
+
["f", () => enterPortMode()],
|
|
1876
|
+
["h", () => toggleHelp()],
|
|
1877
|
+
["j", () => moveSelection("down")],
|
|
1878
|
+
["k", () => moveSelection("up")],
|
|
1879
|
+
["o", () => openSelected()],
|
|
1880
|
+
["q", () => quit()],
|
|
1881
|
+
["r", () => restartSelected()],
|
|
1882
|
+
["s", () => stopSelected()],
|
|
1883
|
+
["x", () => enterConfirmMode()],
|
|
1884
|
+
["?", () => toggleHelp()]
|
|
1885
|
+
]);
|
|
1886
|
+
const toggleHelp = () => {
|
|
1887
|
+
helpVisible = !helpVisible;
|
|
1888
|
+
scheduleRender();
|
|
1889
|
+
};
|
|
1890
|
+
const enterPortMode = () => {
|
|
1891
|
+
mode = "port";
|
|
1892
|
+
portBuffer = "";
|
|
1893
|
+
scheduleRender();
|
|
1894
|
+
};
|
|
1895
|
+
const enterConfirmMode = () => {
|
|
1896
|
+
if (instances.length === 0)
|
|
1897
|
+
return;
|
|
1898
|
+
mode = "confirm";
|
|
1899
|
+
scheduleRender();
|
|
1900
|
+
};
|
|
1901
|
+
const handleListChar = (char) => {
|
|
1902
|
+
const action = listActions.get(char.toLowerCase());
|
|
1903
|
+
if (action)
|
|
1904
|
+
action();
|
|
1905
|
+
};
|
|
1906
|
+
const handlePortChar = (char) => {
|
|
1907
|
+
if (char === "\r" || char === `
|
|
1908
|
+
`) {
|
|
1909
|
+
const value = portBuffer;
|
|
1910
|
+
mode = "list";
|
|
1911
|
+
portBuffer = "";
|
|
1912
|
+
freePort(value);
|
|
1913
|
+
return;
|
|
1914
|
+
}
|
|
1915
|
+
if (char === "\x7F" || char === "\b") {
|
|
1916
|
+
portBuffer = portBuffer.slice(0, EXCLUDE_LAST_OFFSET);
|
|
1917
|
+
scheduleRender();
|
|
1918
|
+
return;
|
|
1919
|
+
}
|
|
1920
|
+
if (char >= "0" && char <= "9") {
|
|
1921
|
+
portBuffer += char;
|
|
1922
|
+
scheduleRender();
|
|
1923
|
+
}
|
|
1924
|
+
};
|
|
1925
|
+
const handleConfirmChar = (char) => {
|
|
1926
|
+
mode = "list";
|
|
1927
|
+
if (char.toLowerCase() === "y") {
|
|
1928
|
+
stopAll();
|
|
1929
|
+
return;
|
|
1930
|
+
}
|
|
1931
|
+
scheduleRender();
|
|
1932
|
+
};
|
|
1933
|
+
const clearEscapeTimer = () => {
|
|
1934
|
+
if (!escapeTimer)
|
|
1935
|
+
return;
|
|
1936
|
+
clearTimeout(escapeTimer);
|
|
1937
|
+
escapeTimer = null;
|
|
1938
|
+
};
|
|
1939
|
+
const onBareEscape = () => {
|
|
1940
|
+
if (helpVisible) {
|
|
1941
|
+
helpVisible = false;
|
|
1942
|
+
} else if (mode !== "list") {
|
|
1943
|
+
mode = "list";
|
|
1944
|
+
portBuffer = "";
|
|
1945
|
+
}
|
|
1946
|
+
scheduleRender();
|
|
1947
|
+
};
|
|
1948
|
+
const armEscapeTimer = () => {
|
|
1949
|
+
clearEscapeTimer();
|
|
1950
|
+
escapeTimer = setTimeout(() => {
|
|
1951
|
+
escapeTimer = null;
|
|
1952
|
+
escapeBuffer = "";
|
|
1953
|
+
onBareEscape();
|
|
1954
|
+
}, LIST_TUI_ESCAPE_SEQUENCE_TIMEOUT_MS);
|
|
1955
|
+
};
|
|
1956
|
+
const resetEscape = () => {
|
|
1957
|
+
clearEscapeTimer();
|
|
1958
|
+
escapeBuffer = "";
|
|
1959
|
+
};
|
|
1960
|
+
const handleEscapeSequence = (char) => {
|
|
1961
|
+
escapeBuffer += char;
|
|
1962
|
+
if (escapeBuffer === `${ESCAPE}[`) {
|
|
1963
|
+
armEscapeTimer();
|
|
1964
|
+
return;
|
|
1965
|
+
}
|
|
1966
|
+
if (escapeBuffer === `${ESCAPE}[A`) {
|
|
1967
|
+
resetEscape();
|
|
1968
|
+
moveSelection("up");
|
|
1969
|
+
return;
|
|
1970
|
+
}
|
|
1971
|
+
if (escapeBuffer === `${ESCAPE}[B`) {
|
|
1972
|
+
resetEscape();
|
|
1973
|
+
moveSelection("down");
|
|
1974
|
+
return;
|
|
1975
|
+
}
|
|
1976
|
+
if (escapeBuffer === `${ESCAPE}[5~`) {
|
|
1977
|
+
resetEscape();
|
|
1978
|
+
scrollLogs("pageUp");
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
if (escapeBuffer === `${ESCAPE}[6~`) {
|
|
1982
|
+
resetEscape();
|
|
1983
|
+
scrollLogs("pageDown");
|
|
1984
|
+
return;
|
|
1985
|
+
}
|
|
1986
|
+
if (isPartialEscapeSequence(escapeBuffer)) {
|
|
1987
|
+
armEscapeTimer();
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
resetEscape();
|
|
1991
|
+
onBareEscape();
|
|
1992
|
+
};
|
|
1993
|
+
const handleChar = (char) => {
|
|
1994
|
+
if (char === "\x03") {
|
|
1995
|
+
quit();
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1998
|
+
if (escapeBuffer) {
|
|
1999
|
+
handleEscapeSequence(char);
|
|
2000
|
+
return;
|
|
2001
|
+
}
|
|
2002
|
+
if (char === ESCAPE) {
|
|
2003
|
+
escapeBuffer = ESCAPE;
|
|
2004
|
+
armEscapeTimer();
|
|
2005
|
+
return;
|
|
2006
|
+
}
|
|
2007
|
+
if (mode === "port") {
|
|
2008
|
+
handlePortChar(char);
|
|
2009
|
+
return;
|
|
2010
|
+
}
|
|
2011
|
+
if (mode === "confirm") {
|
|
2012
|
+
handleConfirmChar(char);
|
|
2013
|
+
return;
|
|
2014
|
+
}
|
|
2015
|
+
handleListChar(char);
|
|
2016
|
+
};
|
|
2017
|
+
const onData = (chunk) => {
|
|
2018
|
+
for (const char of chunk.toString()) {
|
|
2019
|
+
handleChar(char);
|
|
2020
|
+
}
|
|
2021
|
+
};
|
|
2022
|
+
const onResize = () => {
|
|
2023
|
+
scheduleRender();
|
|
2024
|
+
};
|
|
2025
|
+
const titleLine = (width) => {
|
|
2026
|
+
const label = `${instances.length} live`;
|
|
2027
|
+
const left = `${colors.cyan}${colors.bold}ABSOLUTEJS${colors.reset} ${colors.dim}running servers${colors.reset} ${colors.bold}${label}${colors.reset}`;
|
|
2028
|
+
const right = `${colors.dim}${formatTimestamp2()}${colors.reset}`;
|
|
2029
|
+
const gap = Math.max(1, width - visibleLength(left) - visibleLength(right));
|
|
2030
|
+
return `${left}${" ".repeat(gap)}${right}`;
|
|
2031
|
+
};
|
|
2032
|
+
const dividerLine = (width) => `${colors.dim}${"\u2500".repeat(Math.max(width, 1))}${colors.reset}`;
|
|
2033
|
+
const colorizeCell = (cell, index, status2, isSelected, widths) => {
|
|
2034
|
+
const padded = padLine(truncateText(cell, widths[index] ?? 0), widths[index] ?? 0);
|
|
2035
|
+
if (index === STATUS_INDEX) {
|
|
2036
|
+
return `${statusColor(status2)}${padded}${colors.reset}`;
|
|
2037
|
+
}
|
|
2038
|
+
if (index === 0 && isSelected) {
|
|
2039
|
+
return `${colors.cyan}${colors.bold}${padded}${colors.reset}`;
|
|
2040
|
+
}
|
|
2041
|
+
return padded;
|
|
2042
|
+
};
|
|
2043
|
+
const renderInstanceRow = (instance, widths, isSelected) => {
|
|
2044
|
+
const body = instanceRowCells(instance).map((cell, index) => colorizeCell(cell, index, instance.status, isSelected, widths)).join(" ".repeat(LIST_TUI_COLUMN_GAP));
|
|
2045
|
+
const marker = isSelected ? `${colors.cyan}\u276F${colors.reset}` : " ";
|
|
2046
|
+
return `${marker} ${body}`;
|
|
2047
|
+
};
|
|
2048
|
+
const pushInstanceRows = (rows, width) => {
|
|
2049
|
+
if (instances.length === 0) {
|
|
2050
|
+
rows.push(padLine(`${colors.dim}No servers running. Start one with \`absolute dev\`.${colors.reset}`, width));
|
|
1275
2051
|
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
2052
|
}
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
2053
|
+
const allCells = instances.map(instanceRowCells);
|
|
2054
|
+
const widths = layoutWidths(allCells, width);
|
|
2055
|
+
const header = TUI_HEADERS.map((label, index) => padLine(label, widths[index] ?? 0)).join(" ".repeat(LIST_TUI_COLUMN_GAP));
|
|
2056
|
+
rows.push(padLine(` ${colors.dim}${header}${colors.reset}`, width));
|
|
2057
|
+
instances.forEach((instance, index) => {
|
|
2058
|
+
rows.push(padLine(renderInstanceRow(instance, widths, index === selectedIndex), width));
|
|
2059
|
+
});
|
|
2060
|
+
};
|
|
2061
|
+
const logContentLines = (width) => {
|
|
2062
|
+
if (helpVisible)
|
|
2063
|
+
return helpLines2;
|
|
2064
|
+
const instance = selectedInstance();
|
|
2065
|
+
if (!instance) {
|
|
2066
|
+
return [`${colors.dim}No server selected.${colors.reset}`];
|
|
2067
|
+
}
|
|
2068
|
+
const lines = readLogTail(instance.logFile);
|
|
2069
|
+
if (lines.length === 0) {
|
|
2070
|
+
return [`${colors.dim}No output yet.${colors.reset}`];
|
|
2071
|
+
}
|
|
2072
|
+
return lines.map((line) => truncateText(stripAnsi(line), Math.max(1, width - 1)));
|
|
2073
|
+
};
|
|
2074
|
+
const pushLogRows = (rows, width, logHeight) => {
|
|
2075
|
+
const contentLines = logContentLines(width);
|
|
2076
|
+
lastLogLineCount = contentLines.length;
|
|
2077
|
+
lastLogViewportHeight = logHeight;
|
|
2078
|
+
const end = helpVisible ? Math.min(contentLines.length, logHeight) : Math.max(0, contentLines.length - logScrollOffset);
|
|
2079
|
+
const start2 = helpVisible ? 0 : Math.max(0, end - logHeight);
|
|
2080
|
+
const visible = contentLines.slice(start2, end);
|
|
2081
|
+
visible.forEach((line) => rows.push(padLine(line, width)));
|
|
2082
|
+
for (let index = visible.length;index < logHeight; index++) {
|
|
2083
|
+
rows.push(" ".repeat(width));
|
|
2084
|
+
}
|
|
2085
|
+
};
|
|
2086
|
+
const footerLine = (width) => {
|
|
2087
|
+
if (helpVisible) {
|
|
2088
|
+
return padLine(`${colors.dim}esc or ? closes help${colors.reset}`, width);
|
|
2089
|
+
}
|
|
2090
|
+
if (mode === "port") {
|
|
2091
|
+
return padLine(`${colors.yellow}free port:${colors.reset} ${portBuffer}\u258C ${colors.dim}enter to kill \xB7 esc to cancel${colors.reset}`, width);
|
|
2092
|
+
}
|
|
2093
|
+
if (mode === "confirm") {
|
|
2094
|
+
return padLine(`${colors.yellow}Stop ALL ${instances.length} servers? ${colors.reset}${colors.bold}y${colors.reset}${colors.dim}/N${colors.reset}`, width);
|
|
2095
|
+
}
|
|
2096
|
+
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";
|
|
2097
|
+
return padLine(`${colors.dim}${truncateText(hint, width)}${colors.reset}`, width);
|
|
2098
|
+
};
|
|
2099
|
+
const statusLine = (width) => {
|
|
2100
|
+
if (!statusMessage) {
|
|
2101
|
+
return padLine(`${colors.dim}live \xB7 refreshing every ${LIST_WATCH_REFRESH_MS}ms${colors.reset}`, width);
|
|
2102
|
+
}
|
|
2103
|
+
return padLine(`${statusLevelColor(statusMessage.level)}${statusMessage.text}${colors.reset}`, width);
|
|
2104
|
+
};
|
|
2105
|
+
const render = () => {
|
|
2106
|
+
if (disposed)
|
|
2107
|
+
return;
|
|
2108
|
+
const width = process.stdout.columns ?? LIST_TUI_DEFAULT_WIDTH;
|
|
2109
|
+
const height = process.stdout.rows ?? LIST_TUI_DEFAULT_HEIGHT;
|
|
2110
|
+
const rows = [];
|
|
2111
|
+
rows.push(padLine(titleLine(width), width));
|
|
2112
|
+
rows.push(dividerLine(width));
|
|
2113
|
+
pushInstanceRows(rows, width);
|
|
2114
|
+
rows.push(dividerLine(width));
|
|
2115
|
+
const instance = selectedInstance();
|
|
2116
|
+
const logTitle = helpVisible || !instance ? "logs" : `logs \xB7 ${instance.name}${instance.frameworks.length > 0 ? ` \xB7 ${instance.frameworks.join(", ")}` : ""}`;
|
|
2117
|
+
rows.push(padLine(`${colors.bold}${logTitle}${colors.reset}`, width));
|
|
2118
|
+
const fixedHeight = rows.length + LIST_TUI_FOOTER_LINE_COUNT + 1;
|
|
2119
|
+
const logHeight = Math.max(height - fixedHeight, LIST_TUI_MIN_LOG_HEIGHT);
|
|
2120
|
+
pushLogRows(rows, width, logHeight);
|
|
2121
|
+
rows.push(dividerLine(width));
|
|
2122
|
+
rows.push(statusLine(width));
|
|
2123
|
+
rows.push(footerLine(width));
|
|
2124
|
+
const screen = rows.slice(0, height).map((line) => `\x1B[2K${line}`).join(`
|
|
2125
|
+
`);
|
|
2126
|
+
process.stdout.write(`\x1B[H${screen}\x1B[?25l`);
|
|
2127
|
+
};
|
|
2128
|
+
process.on("SIGINT", quit);
|
|
2129
|
+
process.on("SIGTERM", quit);
|
|
2130
|
+
process.stdout.write("\x1B[?1049h\x1B[2J\x1B[H\x1B[?25l");
|
|
2131
|
+
terminal.resume();
|
|
2132
|
+
terminal.on("data", onData);
|
|
2133
|
+
process.stdout.on("resize", onResize);
|
|
2134
|
+
refreshTimer = setInterval(() => {
|
|
2135
|
+
refresh();
|
|
2136
|
+
}, LIST_WATCH_REFRESH_MS);
|
|
2137
|
+
await refresh();
|
|
2138
|
+
render();
|
|
2139
|
+
await promise;
|
|
2140
|
+
}, runListTui = async () => {
|
|
2141
|
+
const input = openTtyStream2();
|
|
2142
|
+
if (!input) {
|
|
2143
|
+
process.stdout.write("Interactive ls requires a TTY. Run `absolute ls` for a snapshot.\n");
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
await driveListTui(input);
|
|
2147
|
+
};
|
|
2148
|
+
var init_listTui = __esm(() => {
|
|
2149
|
+
init_constants();
|
|
2150
|
+
init_getDurationString();
|
|
2151
|
+
init_instanceRegistry();
|
|
2152
|
+
init_instanceStatus();
|
|
2153
|
+
init_tuiPrimitives();
|
|
2154
|
+
init_utils();
|
|
2155
|
+
TUI_HEADERS = [
|
|
2156
|
+
"NAME",
|
|
2157
|
+
"SOURCE",
|
|
2158
|
+
"PORT",
|
|
2159
|
+
"PID",
|
|
2160
|
+
"UPTIME",
|
|
2161
|
+
"STATUS",
|
|
2162
|
+
"URL"
|
|
2163
|
+
];
|
|
2164
|
+
helpLines2 = [
|
|
2165
|
+
"Hotkeys",
|
|
2166
|
+
" \u2191/\u2193 or j/k Select a server",
|
|
2167
|
+
" s Stop the selected server",
|
|
2168
|
+
" r Restart the selected server",
|
|
2169
|
+
" o Open the selected server in the browser",
|
|
2170
|
+
" f Free a port (kill whatever is listening on it)",
|
|
2171
|
+
" x Stop every listed server",
|
|
2172
|
+
" PgUp/PgDn Scroll the log pane",
|
|
2173
|
+
" ? or h Toggle this help",
|
|
2174
|
+
" q Quit (servers keep running)"
|
|
2175
|
+
];
|
|
1289
2176
|
});
|
|
1290
2177
|
|
|
1291
|
-
// src/cli/scripts/
|
|
1292
|
-
var
|
|
1293
|
-
__export(
|
|
1294
|
-
|
|
2178
|
+
// src/cli/scripts/list.ts
|
|
2179
|
+
var exports_list = {};
|
|
2180
|
+
__export(exports_list, {
|
|
2181
|
+
runList: () => runList
|
|
1295
2182
|
});
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
2183
|
+
var TABLE_HEADERS, statusColor2 = (status2) => {
|
|
2184
|
+
if (status2 === "ready")
|
|
2185
|
+
return colors.green;
|
|
2186
|
+
if (status2 === "starting")
|
|
2187
|
+
return colors.yellow;
|
|
2188
|
+
return colors.dim;
|
|
2189
|
+
}, instanceCells = (instance) => [
|
|
2190
|
+
instance.name,
|
|
2191
|
+
instance.source,
|
|
2192
|
+
instance.port === null ? "-" : String(instance.port),
|
|
2193
|
+
String(instance.pid),
|
|
2194
|
+
getDurationString(instance.uptimeMs),
|
|
2195
|
+
`${statusColor2(instance.status)}${instance.status}${colors.reset}`,
|
|
2196
|
+
instance.url ?? "-"
|
|
2197
|
+
], 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) => {
|
|
2198
|
+
if (instances.length === 0) {
|
|
2199
|
+
process.stdout.write(`${colors.dim}No AbsoluteJS servers are running. Start one with \`absolute dev\`.${colors.reset}
|
|
2200
|
+
`);
|
|
1308
2201
|
return;
|
|
1309
2202
|
}
|
|
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);
|
|
2203
|
+
const rows = instances.map(instanceCells);
|
|
2204
|
+
const widths = columnWidths2(rows);
|
|
2205
|
+
process.stdout.write(`${colors.dim}${renderRow(TABLE_HEADERS, widths)}${colors.reset}
|
|
2206
|
+
`);
|
|
2207
|
+
for (const cells of rows) {
|
|
2208
|
+
process.stdout.write(`${renderRow(cells, widths)}
|
|
2209
|
+
`);
|
|
1337
2210
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
2211
|
+
}, runList = async (args) => {
|
|
2212
|
+
process.stdout.on("error", (error) => {
|
|
2213
|
+
if (error instanceof Error && "code" in error && error.code === "EPIPE") {
|
|
2214
|
+
process.exit(0);
|
|
2215
|
+
}
|
|
1340
2216
|
});
|
|
1341
|
-
|
|
2217
|
+
if (args.includes("--watch") || args.includes("-w")) {
|
|
2218
|
+
const { runListTui: runListTui2 } = await Promise.resolve().then(() => (init_listTui(), exports_listTui));
|
|
2219
|
+
await runListTui2();
|
|
2220
|
+
return;
|
|
2221
|
+
}
|
|
2222
|
+
const instances = await enrichInstances(listLiveInstances());
|
|
2223
|
+
if (args.includes("--json")) {
|
|
2224
|
+
process.stdout.write(`${JSON.stringify(instances, null, 2)}
|
|
2225
|
+
`);
|
|
2226
|
+
return;
|
|
2227
|
+
}
|
|
2228
|
+
printInstanceTable(instances);
|
|
1342
2229
|
};
|
|
1343
|
-
var
|
|
2230
|
+
var init_list = __esm(() => {
|
|
2231
|
+
init_constants();
|
|
1344
2232
|
init_getDurationString();
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
2233
|
+
init_instanceRegistry();
|
|
2234
|
+
init_instanceStatus();
|
|
2235
|
+
init_tuiPrimitives();
|
|
2236
|
+
TABLE_HEADERS = [
|
|
2237
|
+
"NAME",
|
|
2238
|
+
"SOURCE",
|
|
2239
|
+
"PORT",
|
|
2240
|
+
"PID",
|
|
2241
|
+
"UPTIME",
|
|
2242
|
+
"STATUS",
|
|
2243
|
+
"URL"
|
|
2244
|
+
];
|
|
1348
2245
|
});
|
|
1349
2246
|
|
|
1350
2247
|
// src/build/externalAssetPlugin.ts
|
|
1351
|
-
import { copyFileSync as copyFileSync2, existsSync as existsSync10, mkdirSync as
|
|
1352
|
-
import { basename as
|
|
2248
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync10, mkdirSync as mkdirSync7, statSync } from "fs";
|
|
2249
|
+
import { basename as basename3, dirname as dirname3, join as join10, resolve as resolve10 } from "path";
|
|
1353
2250
|
var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
|
|
1354
2251
|
name: "absolute-external-asset",
|
|
1355
2252
|
setup(bld) {
|
|
@@ -1374,10 +2271,10 @@ var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
|
|
|
1374
2271
|
continue;
|
|
1375
2272
|
if (!statSync(assetPath).isFile())
|
|
1376
2273
|
continue;
|
|
1377
|
-
const targetPath =
|
|
2274
|
+
const targetPath = join10(outDir, basename3(assetPath));
|
|
1378
2275
|
if (existsSync10(targetPath))
|
|
1379
2276
|
continue;
|
|
1380
|
-
|
|
2277
|
+
mkdirSync7(dirname3(targetPath), { recursive: true });
|
|
1381
2278
|
copyFileSync2(assetPath, targetPath);
|
|
1382
2279
|
}
|
|
1383
2280
|
return;
|
|
@@ -1396,15 +2293,15 @@ var {env: env3 } = globalThis.Bun;
|
|
|
1396
2293
|
import {
|
|
1397
2294
|
cpSync,
|
|
1398
2295
|
existsSync as existsSync11,
|
|
1399
|
-
mkdirSync as
|
|
1400
|
-
readdirSync as
|
|
1401
|
-
readFileSync as
|
|
2296
|
+
mkdirSync as mkdirSync8,
|
|
2297
|
+
readdirSync as readdirSync3,
|
|
2298
|
+
readFileSync as readFileSync13,
|
|
1402
2299
|
rmSync as rmSync4,
|
|
1403
2300
|
statSync as statSync2,
|
|
1404
|
-
unlinkSync as
|
|
1405
|
-
writeFileSync as
|
|
2301
|
+
unlinkSync as unlinkSync4,
|
|
2302
|
+
writeFileSync as writeFileSync5
|
|
1406
2303
|
} from "fs";
|
|
1407
|
-
import { basename as
|
|
2304
|
+
import { basename as basename4, dirname as dirname4, join as join11, relative, resolve as resolve11 } from "path";
|
|
1408
2305
|
var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, compileBanner = (version2) => {
|
|
1409
2306
|
const resolvedVersion = version2 || "unknown";
|
|
1410
2307
|
console.log("");
|
|
@@ -1412,14 +2309,14 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1412
2309
|
console.log("");
|
|
1413
2310
|
}, collectFiles2 = (dir) => {
|
|
1414
2311
|
const result = [];
|
|
1415
|
-
let pending =
|
|
2312
|
+
let pending = readdirSync3(dir, { withFileTypes: true });
|
|
1416
2313
|
while (pending.length > 0) {
|
|
1417
2314
|
const entry = pending.pop();
|
|
1418
2315
|
if (!entry)
|
|
1419
2316
|
continue;
|
|
1420
|
-
const fullPath =
|
|
2317
|
+
const fullPath = join11(entry.parentPath, entry.name);
|
|
1421
2318
|
if (entry.isDirectory())
|
|
1422
|
-
pending = pending.concat(
|
|
2319
|
+
pending = pending.concat(readdirSync3(fullPath, { withFileTypes: true }));
|
|
1423
2320
|
else
|
|
1424
2321
|
result.push(fullPath);
|
|
1425
2322
|
}
|
|
@@ -1432,16 +2329,16 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1432
2329
|
return `./${parts.join("/")}`;
|
|
1433
2330
|
}, collectProjectSourceFiles = (dir) => {
|
|
1434
2331
|
const result = [];
|
|
1435
|
-
let pending =
|
|
2332
|
+
let pending = readdirSync3(dir, { withFileTypes: true });
|
|
1436
2333
|
while (pending.length > 0) {
|
|
1437
2334
|
const entry = pending.pop();
|
|
1438
2335
|
if (!entry)
|
|
1439
2336
|
continue;
|
|
1440
|
-
const fullPath =
|
|
2337
|
+
const fullPath = join11(entry.parentPath, entry.name);
|
|
1441
2338
|
if (entry.isDirectory()) {
|
|
1442
2339
|
if (SERVER_RUNTIME_SCAN_SKIP_DIRS.has(entry.name))
|
|
1443
2340
|
continue;
|
|
1444
|
-
pending = pending.concat(
|
|
2341
|
+
pending = pending.concat(readdirSync3(fullPath, { withFileTypes: true }));
|
|
1445
2342
|
} else if (hasSourceExtension(fullPath)) {
|
|
1446
2343
|
result.push(fullPath);
|
|
1447
2344
|
}
|
|
@@ -1460,11 +2357,11 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1460
2357
|
if (copied.has(assetTarget))
|
|
1461
2358
|
return;
|
|
1462
2359
|
copied.add(assetTarget);
|
|
1463
|
-
|
|
2360
|
+
mkdirSync8(dirname4(assetTarget), { recursive: true });
|
|
1464
2361
|
cpSync(assetSource, assetTarget, { force: true });
|
|
1465
2362
|
};
|
|
1466
2363
|
for (const filePath of collectProjectSourceFiles(process.cwd())) {
|
|
1467
|
-
const source =
|
|
2364
|
+
const source = readFileSync13(filePath, "utf-8");
|
|
1468
2365
|
SERVER_RUNTIME_ASSET_RE.lastIndex = 0;
|
|
1469
2366
|
let match;
|
|
1470
2367
|
while ((match = SERVER_RUNTIME_ASSET_RE.exec(source)) !== null) {
|
|
@@ -1493,7 +2390,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1493
2390
|
}
|
|
1494
2391
|
}, readPackageVersion4 = (candidate) => {
|
|
1495
2392
|
try {
|
|
1496
|
-
const pkg = JSON.parse(
|
|
2393
|
+
const pkg = JSON.parse(readFileSync13(candidate, "utf-8"));
|
|
1497
2394
|
if (pkg.name !== "@absolutejs/absolute")
|
|
1498
2395
|
return null;
|
|
1499
2396
|
const ver = pkg.version;
|
|
@@ -1552,7 +2449,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1552
2449
|
return true;
|
|
1553
2450
|
}, tryReadNodePackageJson = (packageDir) => {
|
|
1554
2451
|
try {
|
|
1555
|
-
return JSON.parse(
|
|
2452
|
+
return JSON.parse(readFileSync13(join11(packageDir, "package.json"), "utf-8"));
|
|
1556
2453
|
} catch {
|
|
1557
2454
|
return null;
|
|
1558
2455
|
}
|
|
@@ -1564,7 +2461,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1564
2461
|
if (!pkg)
|
|
1565
2462
|
return;
|
|
1566
2463
|
seen.add(specifier);
|
|
1567
|
-
const destDir =
|
|
2464
|
+
const destDir = join11(outdir, "node_modules", ...specifier.split("/"));
|
|
1568
2465
|
rmSync4(destDir, { force: true, recursive: true });
|
|
1569
2466
|
cpSync(srcDir, destDir, {
|
|
1570
2467
|
filter(source) {
|
|
@@ -1587,7 +2484,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1587
2484
|
if (!buildConfig.angularDirectory)
|
|
1588
2485
|
return;
|
|
1589
2486
|
const angularScopeDir = resolve11(process.cwd(), "node_modules", "@angular");
|
|
1590
|
-
const angularPackages = existsSync11(angularScopeDir) ?
|
|
2487
|
+
const angularPackages = existsSync11(angularScopeDir) ? readdirSync3(angularScopeDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => entry.name !== "compiler-cli").map((entry) => `@angular/${entry.name}`) : [];
|
|
1591
2488
|
const roots = new Set([...angularPackages, "rxjs", "tslib", "typescript"]);
|
|
1592
2489
|
const seen = new Set;
|
|
1593
2490
|
for (const specifier of roots) {
|
|
@@ -1604,16 +2501,16 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1604
2501
|
}
|
|
1605
2502
|
copyAngularRuntimePackages(buildConfig, outdir);
|
|
1606
2503
|
}, collectRuntimePackageSpecifiers = (distDir) => {
|
|
1607
|
-
const nodeModulesDir =
|
|
2504
|
+
const nodeModulesDir = join11(distDir, "node_modules");
|
|
1608
2505
|
if (!existsSync11(nodeModulesDir))
|
|
1609
2506
|
return [];
|
|
1610
2507
|
const specifiers = [];
|
|
1611
|
-
for (const entry of
|
|
2508
|
+
for (const entry of readdirSync3(nodeModulesDir, { withFileTypes: true })) {
|
|
1612
2509
|
if (!entry.isDirectory())
|
|
1613
2510
|
continue;
|
|
1614
2511
|
if (entry.name.startsWith("@")) {
|
|
1615
|
-
const scopeDir =
|
|
1616
|
-
for (const scopedEntry of
|
|
2512
|
+
const scopeDir = join11(nodeModulesDir, entry.name);
|
|
2513
|
+
for (const scopedEntry of readdirSync3(scopeDir, {
|
|
1617
2514
|
withFileTypes: true
|
|
1618
2515
|
})) {
|
|
1619
2516
|
if (scopedEntry.isDirectory()) {
|
|
@@ -1644,18 +2541,18 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1644
2541
|
const packageSpecifier = packageSpecifiers.find((root) => specifier === root || specifier.startsWith(`${root}/`));
|
|
1645
2542
|
if (!packageSpecifier)
|
|
1646
2543
|
return null;
|
|
1647
|
-
const packageDir =
|
|
2544
|
+
const packageDir = join11(distDir, "node_modules", ...packageSpecifier.split("/"));
|
|
1648
2545
|
const subpath = specifier.slice(packageSpecifier.length);
|
|
1649
|
-
const subPackageDir = subpath ?
|
|
1650
|
-
const resolvedPackageDir = subPackageDir && existsSync11(
|
|
1651
|
-
const packageJsonPath =
|
|
2546
|
+
const subPackageDir = subpath ? join11(packageDir, ...subpath.slice(1).split("/")) : null;
|
|
2547
|
+
const resolvedPackageDir = subPackageDir && existsSync11(join11(subPackageDir, "package.json")) ? subPackageDir : packageDir;
|
|
2548
|
+
const packageJsonPath = join11(resolvedPackageDir, "package.json");
|
|
1652
2549
|
if (!existsSync11(packageJsonPath))
|
|
1653
2550
|
return null;
|
|
1654
|
-
const pkg = JSON.parse(
|
|
2551
|
+
const pkg = JSON.parse(readFileSync13(packageJsonPath, "utf-8"));
|
|
1655
2552
|
const exportKey = resolvedPackageDir === subPackageDir ? "." : subpath ? `.${subpath}` : ".";
|
|
1656
2553
|
const rootExport = pkg.exports?.[exportKey];
|
|
1657
2554
|
const entry = pickExportEntry(rootExport) ?? (resolvedPackageDir === subPackageDir || !subpath ? pkg.module ?? pkg.main ?? "index.js" : `.${subpath}`);
|
|
1658
|
-
return
|
|
2555
|
+
return join11(resolvedPackageDir, entry);
|
|
1659
2556
|
}, 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
2557
|
try {
|
|
1661
2558
|
return statSync2(filePath).isFile();
|
|
@@ -1668,13 +2565,13 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1668
2565
|
const candidates = [
|
|
1669
2566
|
candidate,
|
|
1670
2567
|
...RUNTIME_JS_EXTENSIONS.map((extension) => `${candidate}${extension}`),
|
|
1671
|
-
...RUNTIME_JS_EXTENSIONS.map((extension) =>
|
|
2568
|
+
...RUNTIME_JS_EXTENSIONS.map((extension) => join11(candidate, `index${extension}`))
|
|
1672
2569
|
];
|
|
1673
2570
|
return candidates.find((filePath) => isRuntimeJsFile(filePath) && isFile(filePath)) ?? null;
|
|
1674
2571
|
}, findContainingRuntimePackageDir = (filePath) => {
|
|
1675
2572
|
let dir = dirname4(filePath);
|
|
1676
2573
|
while (dir !== dirname4(dir)) {
|
|
1677
|
-
if (isNodeModulesPath(dir) && existsSync11(
|
|
2574
|
+
if (isNodeModulesPath(dir) && existsSync11(join11(dir, "package.json"))) {
|
|
1678
2575
|
return dir;
|
|
1679
2576
|
}
|
|
1680
2577
|
dir = dirname4(dir);
|
|
@@ -1690,7 +2587,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1690
2587
|
const entry = pickExportEntry(pkg?.imports?.[specifier]);
|
|
1691
2588
|
if (!entry)
|
|
1692
2589
|
return null;
|
|
1693
|
-
return
|
|
2590
|
+
return join11(packageDir, entry);
|
|
1694
2591
|
}, collectRuntimeRewriteRoots = (distDir) => collectFiles2(distDir).filter((filePath) => isRuntimeJsFile(filePath) && !isNodeModulesPath(filePath)), rewriteRuntimeModuleSpecifiers = (distDir) => {
|
|
1695
2592
|
const packageSpecifiers = collectRuntimePackageSpecifiers(distDir);
|
|
1696
2593
|
if (packageSpecifiers.length === 0)
|
|
@@ -1709,7 +2606,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1709
2606
|
if (!filePath || seen.has(filePath))
|
|
1710
2607
|
continue;
|
|
1711
2608
|
seen.add(filePath);
|
|
1712
|
-
const source =
|
|
2609
|
+
const source = readFileSync13(filePath, "utf-8");
|
|
1713
2610
|
const rewritten = source.replace(MODULE_SPECIFIER_RE, (match, prefix, quote, specifier) => {
|
|
1714
2611
|
if (typeof specifier === "string" && specifier.startsWith(".")) {
|
|
1715
2612
|
enqueue(resolveRuntimeJsFile(resolve11(dirname4(filePath), specifier)));
|
|
@@ -1727,12 +2624,12 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1727
2624
|
return `${prefix}${quote}${ensureRelativeModuleSpecifier(filePath, target)}${quote}`;
|
|
1728
2625
|
});
|
|
1729
2626
|
if (rewritten !== source) {
|
|
1730
|
-
|
|
2627
|
+
writeFileSync5(filePath, rewritten);
|
|
1731
2628
|
}
|
|
1732
2629
|
}
|
|
1733
2630
|
}, generateEntrypoint = (distDir, serverEntry, prerenderMap, version2, buildConfig) => {
|
|
1734
2631
|
const allFiles = collectFiles2(distDir);
|
|
1735
|
-
const serverBundleName = `${
|
|
2632
|
+
const serverBundleName = `${basename4(serverEntry).replace(/\.[^.]+$/, "")}.js`;
|
|
1736
2633
|
const embeddedSkip = new Set(["_compile_entrypoint.ts"]);
|
|
1737
2634
|
const assetSkip = new Set([
|
|
1738
2635
|
serverBundleName,
|
|
@@ -1786,10 +2683,10 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
1786
2683
|
${imports.join(`
|
|
1787
2684
|
`)}
|
|
1788
2685
|
|
|
1789
|
-
import { existsSync } from "node:fs";
|
|
2686
|
+
import { existsSync, mkdirSync, unlinkSync } from "node:fs";
|
|
1790
2687
|
import { mkdir } from "node:fs/promises";
|
|
1791
|
-
import { dirname, join } from "node:path";
|
|
1792
|
-
import { tmpdir } from "node:os";
|
|
2688
|
+
import { basename, dirname, join } from "node:path";
|
|
2689
|
+
import { homedir, tmpdir } from "node:os";
|
|
1793
2690
|
import { createHash } from "node:crypto";
|
|
1794
2691
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
1795
2692
|
import { pathToFileURL } from "node:url";
|
|
@@ -1986,6 +2883,49 @@ const server = Bun.serve({
|
|
|
1986
2883
|
},
|
|
1987
2884
|
});
|
|
1988
2885
|
|
|
2886
|
+
// Register in the global instance registry so 'absolute ls' can see this
|
|
2887
|
+
// compiled binary. Best-effort; never blocks startup. Dead entries are pruned
|
|
2888
|
+
// on read, so a hard kill that skips the exit handler is harmless.
|
|
2889
|
+
try {
|
|
2890
|
+
const absInstancesDir = join(homedir(), ".absolutejs", "instances");
|
|
2891
|
+
mkdirSync(absInstancesDir, { recursive: true });
|
|
2892
|
+
const absInstanceFile = join(absInstancesDir, process.pid + ".json");
|
|
2893
|
+
writeFileSync(
|
|
2894
|
+
absInstanceFile,
|
|
2895
|
+
JSON.stringify(
|
|
2896
|
+
{
|
|
2897
|
+
// Bun sets process.argv[0] to "bun" in a compiled binary;
|
|
2898
|
+
// process.execPath is the real standalone executable path.
|
|
2899
|
+
command: process.execPath ? [process.execPath] : [],
|
|
2900
|
+
configPath: null,
|
|
2901
|
+
controllerPid: process.pid,
|
|
2902
|
+
cwd: process.cwd(),
|
|
2903
|
+
frameworks: [],
|
|
2904
|
+
host: "localhost",
|
|
2905
|
+
https: false,
|
|
2906
|
+
logFile: null,
|
|
2907
|
+
name: basename(process.execPath || "compiled"),
|
|
2908
|
+
pid: process.pid,
|
|
2909
|
+
port: server.port,
|
|
2910
|
+
ppid: process.ppid,
|
|
2911
|
+
source: "compiled",
|
|
2912
|
+
startedAt: new Date().toISOString()
|
|
2913
|
+
},
|
|
2914
|
+
null,
|
|
2915
|
+
2
|
|
2916
|
+
)
|
|
2917
|
+
);
|
|
2918
|
+
process.on("exit", () => {
|
|
2919
|
+
try {
|
|
2920
|
+
unlinkSync(absInstanceFile);
|
|
2921
|
+
} catch {
|
|
2922
|
+
/* already gone */
|
|
2923
|
+
}
|
|
2924
|
+
});
|
|
2925
|
+
} catch {
|
|
2926
|
+
/* registry is best-effort */
|
|
2927
|
+
}
|
|
2928
|
+
|
|
1989
2929
|
const assetCount = Object.keys(ASSETS).length;
|
|
1990
2930
|
const pageCount = Object.keys(PAGES).length;
|
|
1991
2931
|
console.log(\`
|
|
@@ -2115,7 +3055,7 @@ console.log(\`
|
|
|
2115
3055
|
}, compileUnlocked = async (serverEntry, resolvedOutdir, outfile, configPath2) => {
|
|
2116
3056
|
const prerenderPort = Number(env3.COMPILE_PORT) || Number(env3.PORT) || DEFAULT_PORT + 1;
|
|
2117
3057
|
killStaleProcesses(prerenderPort);
|
|
2118
|
-
const entryName =
|
|
3058
|
+
const entryName = basename4(serverEntry).replace(/\.[^.]+$/, "");
|
|
2119
3059
|
const resolvedOutfile = resolve11(outfile ?? "compiled-server");
|
|
2120
3060
|
const absoluteVersion = resolvePackageVersion3([
|
|
2121
3061
|
resolve11(import.meta.dir, "..", "..", "..", "package.json"),
|
|
@@ -2181,7 +3121,7 @@ console.log(\`
|
|
|
2181
3121
|
}
|
|
2182
3122
|
if (existsSync11(resolve11(resolvedOutdir, "angular", "vendor", "server"))) {
|
|
2183
3123
|
const vendorDir = resolve11(resolvedOutdir, "angular", "vendor", "server");
|
|
2184
|
-
const vendorEntries =
|
|
3124
|
+
const vendorEntries = readdirSync3(vendorDir).filter((f) => f.endsWith(".js"));
|
|
2185
3125
|
const angularServerVendorPaths = {};
|
|
2186
3126
|
for (const file of vendorEntries) {
|
|
2187
3127
|
const stem = file.replace(/\.js$/, "");
|
|
@@ -2201,7 +3141,7 @@ console.log(\`
|
|
|
2201
3141
|
copyServerRuntimeAssetReferences(resolvedOutdir);
|
|
2202
3142
|
const prerenderStart = performance.now();
|
|
2203
3143
|
process.stdout.write(cliTag4("\x1B[36m", "Pre-rendering pages"));
|
|
2204
|
-
rmSync4(
|
|
3144
|
+
rmSync4(join11(resolvedOutdir, "_prerendered"), {
|
|
2205
3145
|
force: true,
|
|
2206
3146
|
recursive: true
|
|
2207
3147
|
});
|
|
@@ -2220,9 +3160,9 @@ console.log(\`
|
|
|
2220
3160
|
const compileStart = performance.now();
|
|
2221
3161
|
process.stdout.write(cliTag4("\x1B[36m", "Compiling standalone executable"));
|
|
2222
3162
|
const entrypointCode = generateEntrypoint(resolvedOutdir, serverEntry, prerenderMap, absoluteVersion, buildConfig);
|
|
2223
|
-
const entrypointPath =
|
|
3163
|
+
const entrypointPath = join11(resolvedOutdir, "_compile_entrypoint.ts");
|
|
2224
3164
|
await Bun.write(entrypointPath, entrypointCode);
|
|
2225
|
-
|
|
3165
|
+
mkdirSync8(dirname4(resolvedOutfile), { recursive: true });
|
|
2226
3166
|
const result = await Bun.build({
|
|
2227
3167
|
compile: { outfile: resolvedOutfile },
|
|
2228
3168
|
define: { "process.env.NODE_ENV": '"production"' },
|
|
@@ -2244,13 +3184,13 @@ console.log(\`
|
|
|
2244
3184
|
}
|
|
2245
3185
|
console.log(` \x1B[2m(${getDurationString(performance.now() - compileStart)})\x1B[0m`);
|
|
2246
3186
|
try {
|
|
2247
|
-
|
|
3187
|
+
unlinkSync4(entrypointPath);
|
|
2248
3188
|
} catch {}
|
|
2249
3189
|
const BYTES_PER_MB = 1048576;
|
|
2250
3190
|
const size = (Bun.file(resolvedOutfile).size / BYTES_PER_MB).toFixed(0);
|
|
2251
3191
|
const totalDuration = getDurationString(performance.now() - totalStart);
|
|
2252
3192
|
console.log(cliTag4("\x1B[32m", `Compiled to ${resolvedOutfile} (${size}MB) in ${totalDuration}`));
|
|
2253
|
-
console.log(cliTag4("\x1B[2m", `Run with: ./${
|
|
3193
|
+
console.log(cliTag4("\x1B[2m", `Run with: ./${basename4(resolvedOutfile)}`));
|
|
2254
3194
|
sendTelemetryEvent("compile:complete", {
|
|
2255
3195
|
durationMs: Math.round(performance.now() - totalStart),
|
|
2256
3196
|
entry: serverEntry,
|
|
@@ -2314,8 +3254,8 @@ var exports_typecheck = {};
|
|
|
2314
3254
|
__export(exports_typecheck, {
|
|
2315
3255
|
typecheck: () => typecheck
|
|
2316
3256
|
});
|
|
2317
|
-
import { resolve as resolve12, join as
|
|
2318
|
-
import { existsSync as existsSync12, readFileSync as
|
|
3257
|
+
import { resolve as resolve12, join as join12 } from "path";
|
|
3258
|
+
import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
|
|
2319
3259
|
import { mkdir as mkdir2, writeFile } from "fs/promises";
|
|
2320
3260
|
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
3261
|
if (!existsSync12(resolveConfigPath(configPath2))) {
|
|
@@ -2394,7 +3334,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2394
3334
|
return candidates.find((candidate) => existsSync12(candidate)) ?? candidates[0];
|
|
2395
3335
|
}, ABSOLUTE_TYPECHECK_FILES, readProjectTsconfig = () => {
|
|
2396
3336
|
try {
|
|
2397
|
-
return JSON.parse(
|
|
3337
|
+
return JSON.parse(readFileSync14(resolve12("tsconfig.json"), "utf-8"));
|
|
2398
3338
|
} catch {
|
|
2399
3339
|
return {};
|
|
2400
3340
|
}
|
|
@@ -2422,7 +3362,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2422
3362
|
console.error("\x1B[31m\u2717\x1B[0m vue-tsc is required for Vue type checking. Install it: bun add -d vue-tsc");
|
|
2423
3363
|
process.exit(1);
|
|
2424
3364
|
}
|
|
2425
|
-
const vueTsconfigPath =
|
|
3365
|
+
const vueTsconfigPath = join12(cacheDir, "tsconfig.vue-check.json");
|
|
2426
3366
|
return writeFile(vueTsconfigPath, JSON.stringify({
|
|
2427
3367
|
compilerOptions: {
|
|
2428
3368
|
rootDir: ".."
|
|
@@ -2437,7 +3377,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2437
3377
|
resolve12(vueTsconfigPath),
|
|
2438
3378
|
"--incremental",
|
|
2439
3379
|
"--tsBuildInfoFile",
|
|
2440
|
-
|
|
3380
|
+
join12(cacheDir, "vue-tsc.tsbuildinfo"),
|
|
2441
3381
|
"--pretty"
|
|
2442
3382
|
]));
|
|
2443
3383
|
}, buildAngularCheck = async (cacheDir, angularDir) => {
|
|
@@ -2446,7 +3386,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2446
3386
|
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
3387
|
process.exit(1);
|
|
2448
3388
|
}
|
|
2449
|
-
const angularTsconfigPath =
|
|
3389
|
+
const angularTsconfigPath = join12(cacheDir, "tsconfig.angular-check.json");
|
|
2450
3390
|
await writeFile(angularTsconfigPath, JSON.stringify({
|
|
2451
3391
|
angularCompilerOptions: {
|
|
2452
3392
|
strictTemplates: true
|
|
@@ -2466,7 +3406,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2466
3406
|
console.error("\x1B[31m\u2717\x1B[0m typescript is required for type checking. Install it: bun add -d typescript");
|
|
2467
3407
|
process.exit(1);
|
|
2468
3408
|
}
|
|
2469
|
-
const tscConfigPath =
|
|
3409
|
+
const tscConfigPath = join12(cacheDir, "tsconfig.typecheck.json");
|
|
2470
3410
|
return writeFile(tscConfigPath, JSON.stringify({
|
|
2471
3411
|
compilerOptions: {
|
|
2472
3412
|
rootDir: ".."
|
|
@@ -2481,7 +3421,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2481
3421
|
resolve12(tscConfigPath),
|
|
2482
3422
|
"--incremental",
|
|
2483
3423
|
"--tsBuildInfoFile",
|
|
2484
|
-
|
|
3424
|
+
join12(cacheDir, "tsc.tsbuildinfo"),
|
|
2485
3425
|
"--pretty"
|
|
2486
3426
|
]));
|
|
2487
3427
|
}, buildSvelteCheck = async (cacheDir, svelteDir) => {
|
|
@@ -2490,7 +3430,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
2490
3430
|
console.error("\x1B[31m\u2717\x1B[0m svelte-check is required for Svelte type checking. Install it: bun add -d svelte-check");
|
|
2491
3431
|
process.exit(1);
|
|
2492
3432
|
}
|
|
2493
|
-
const svelteTsconfigPath =
|
|
3433
|
+
const svelteTsconfigPath = join12(cacheDir, "tsconfig.svelte-check.json");
|
|
2494
3434
|
await writeFile(svelteTsconfigPath, JSON.stringify({
|
|
2495
3435
|
extends: resolve12("tsconfig.json"),
|
|
2496
3436
|
files: ABSOLUTE_TYPECHECK_FILES,
|
|
@@ -2567,7 +3507,7 @@ init_constants();
|
|
|
2567
3507
|
init_startupBanner();
|
|
2568
3508
|
var {$: $2, env } = globalThis.Bun;
|
|
2569
3509
|
import { spawn as nodeSpawn } from "child_process";
|
|
2570
|
-
import { existsSync as existsSync5, readFileSync as
|
|
3510
|
+
import { createWriteStream, existsSync as existsSync5, readFileSync as readFileSync7 } from "fs";
|
|
2571
3511
|
import { resolve as resolve3 } from "path";
|
|
2572
3512
|
|
|
2573
3513
|
// src/cli/interactive.ts
|
|
@@ -2840,6 +3780,7 @@ var createInteractiveHandler = (actions) => {
|
|
|
2840
3780
|
// src/cli/scripts/dev.ts
|
|
2841
3781
|
init_telemetryEvent();
|
|
2842
3782
|
init_buildDirectoryLock();
|
|
3783
|
+
init_instanceRegistry();
|
|
2843
3784
|
init_loadConfig();
|
|
2844
3785
|
|
|
2845
3786
|
// src/utils/resolveDevPort.ts
|
|
@@ -2882,6 +3823,7 @@ var resolveDevPort = async (requestedPort, options = {}) => {
|
|
|
2882
3823
|
init_utils();
|
|
2883
3824
|
var cliTag = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`;
|
|
2884
3825
|
var DEFAULT_PORT_RANGE = 10;
|
|
3826
|
+
var ANSI_LOG_REGEX = new RegExp(`${String.fromCharCode(ANSI_ESCAPE_CODE)}\\[[0-?]*[ -/]*[@-~]`, "g");
|
|
2885
3827
|
var confirmPrompt = (message, defaultYes = true) => {
|
|
2886
3828
|
const { promise, resolve: resolvePrompt } = Promise.withResolvers();
|
|
2887
3829
|
let selected = defaultYes;
|
|
@@ -2986,6 +3928,37 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
2986
3928
|
console.log(cliTag("\x1B[33m", `Port ${resolvedDev.port} is in use, trying another one... \u2192 http://${displayHost}:${port}/`));
|
|
2987
3929
|
}
|
|
2988
3930
|
updateLockMetadata(buildDirectory, { port });
|
|
3931
|
+
const instancePid = process.pid;
|
|
3932
|
+
const instanceLogFile = instanceLogPath(instancePid);
|
|
3933
|
+
const relaunchCommand = [
|
|
3934
|
+
process.execPath,
|
|
3935
|
+
process.argv[1] ?? "",
|
|
3936
|
+
"dev",
|
|
3937
|
+
serverEntry,
|
|
3938
|
+
...configPath2 ? ["--config", configPath2] : []
|
|
3939
|
+
].filter((part) => part.length > 0);
|
|
3940
|
+
registerInstance({
|
|
3941
|
+
command: relaunchCommand,
|
|
3942
|
+
configPath: configPath2 ?? null,
|
|
3943
|
+
controllerPid: instancePid,
|
|
3944
|
+
cwd: process.cwd(),
|
|
3945
|
+
frameworks: [],
|
|
3946
|
+
host: resolvedDev.host,
|
|
3947
|
+
https: httpsEnabled,
|
|
3948
|
+
logFile: instanceLogFile,
|
|
3949
|
+
name: resolveProjectName(process.cwd()),
|
|
3950
|
+
pid: instancePid,
|
|
3951
|
+
port,
|
|
3952
|
+
ppid: process.ppid,
|
|
3953
|
+
source: "dev",
|
|
3954
|
+
startedAt: new Date().toISOString()
|
|
3955
|
+
});
|
|
3956
|
+
const instanceLog = createWriteStream(instanceLogFile, { flags: "w" });
|
|
3957
|
+
const writeInstanceLog = (text) => {
|
|
3958
|
+
try {
|
|
3959
|
+
instanceLog.write(text.replace(ANSI_LOG_REGEX, ""));
|
|
3960
|
+
} catch {}
|
|
3961
|
+
};
|
|
2989
3962
|
const usesDocker = existsSync5(resolve3(COMPOSE_PATH));
|
|
2990
3963
|
const scripts = usesDocker ? await readDbScripts() : null;
|
|
2991
3964
|
if (scripts)
|
|
@@ -3059,6 +4032,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3059
4032
|
console.log(cliTag("\x1B[36m", `Port changed in config \u2014 switching to http://${displayHost}:${probe.port}/`));
|
|
3060
4033
|
port = probe.port;
|
|
3061
4034
|
updateLockMetadata(buildDirectory, { port });
|
|
4035
|
+
updateInstance(instancePid, { port });
|
|
3062
4036
|
}
|
|
3063
4037
|
resolvedDev = dev2;
|
|
3064
4038
|
}
|
|
@@ -3069,7 +4043,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3069
4043
|
for (const name of candidates) {
|
|
3070
4044
|
let text;
|
|
3071
4045
|
try {
|
|
3072
|
-
text =
|
|
4046
|
+
text = readFileSync7(resolve3(process.cwd(), name), "utf8");
|
|
3073
4047
|
} catch {
|
|
3074
4048
|
continue;
|
|
3075
4049
|
}
|
|
@@ -3099,6 +4073,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3099
4073
|
env: {
|
|
3100
4074
|
...process.env,
|
|
3101
4075
|
...readDotenvFiles(),
|
|
4076
|
+
ABSOLUTE_INSTANCE_MANAGED: "1",
|
|
3102
4077
|
FORCE_COLOR: "1",
|
|
3103
4078
|
NODE_ENV: "development",
|
|
3104
4079
|
ABSOLUTE_PORT: String(port),
|
|
@@ -3115,6 +4090,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3115
4090
|
if (serverReady)
|
|
3116
4091
|
interactive?.clearPrompt();
|
|
3117
4092
|
dest.write(chunk);
|
|
4093
|
+
writeInstanceLog(chunk.toString());
|
|
3118
4094
|
handleChunk(chunk);
|
|
3119
4095
|
});
|
|
3120
4096
|
};
|
|
@@ -3140,7 +4116,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3140
4116
|
};
|
|
3141
4117
|
try {
|
|
3142
4118
|
const { watch } = await import("fs");
|
|
3143
|
-
const { dirname: dirname3, join:
|
|
4119
|
+
const { dirname: dirname3, join: join6 } = await import("path");
|
|
3144
4120
|
const absServerEntry = resolve3(serverEntry);
|
|
3145
4121
|
const serverEntryDir = dirname3(absServerEntry);
|
|
3146
4122
|
const ROOT_RESTART_DENY = new Set([
|
|
@@ -3173,13 +4149,13 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3173
4149
|
if (now - last < 100)
|
|
3174
4150
|
return;
|
|
3175
4151
|
recentlyHandled.set(filename, now);
|
|
3176
|
-
scheduleServerRestart(
|
|
4152
|
+
scheduleServerRestart(join6(serverEntryDir, filename));
|
|
3177
4153
|
};
|
|
3178
4154
|
const recoveryScan = async () => {
|
|
3179
4155
|
let entries;
|
|
3180
4156
|
try {
|
|
3181
|
-
const { readdirSync } = await import("fs");
|
|
3182
|
-
entries =
|
|
4157
|
+
const { readdirSync: readdirSync2 } = await import("fs");
|
|
4158
|
+
entries = readdirSync2(serverEntryDir, { withFileTypes: true });
|
|
3183
4159
|
} catch {
|
|
3184
4160
|
return;
|
|
3185
4161
|
}
|
|
@@ -3192,7 +4168,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3192
4168
|
continue;
|
|
3193
4169
|
let st;
|
|
3194
4170
|
try {
|
|
3195
|
-
st = statSync(
|
|
4171
|
+
st = statSync(join6(serverEntryDir, entry.name));
|
|
3196
4172
|
} catch {
|
|
3197
4173
|
continue;
|
|
3198
4174
|
}
|
|
@@ -3235,6 +4211,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3235
4211
|
cfg.angularDirectory && "angular"
|
|
3236
4212
|
].filter((val) => Boolean(val));
|
|
3237
4213
|
} catch {}
|
|
4214
|
+
updateInstance(instancePid, { frameworks });
|
|
3238
4215
|
sendTelemetryEvent("dev:start", { entry: serverEntry, frameworks });
|
|
3239
4216
|
const killChildTree = (signal) => {
|
|
3240
4217
|
const childPid = serverProcess.pid;
|
|
@@ -3273,6 +4250,10 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3273
4250
|
});
|
|
3274
4251
|
if (scripts)
|
|
3275
4252
|
await stopDatabase(scripts);
|
|
4253
|
+
try {
|
|
4254
|
+
instanceLog.end();
|
|
4255
|
+
} catch {}
|
|
4256
|
+
deregisterInstance(instancePid);
|
|
3276
4257
|
process.exit(exitCode);
|
|
3277
4258
|
};
|
|
3278
4259
|
const restartServer = async () => {
|
|
@@ -3451,7 +4432,7 @@ var dev = async (serverEntry, configPath2) => {
|
|
|
3451
4432
|
};
|
|
3452
4433
|
|
|
3453
4434
|
// src/cli/scripts/eslint.ts
|
|
3454
|
-
import { existsSync as existsSync6, readFileSync as
|
|
4435
|
+
import { existsSync as existsSync6, readFileSync as readFileSync8, rmSync as rmSync2 } from "fs";
|
|
3455
4436
|
import { resolve as resolve4 } from "path";
|
|
3456
4437
|
var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache";
|
|
3457
4438
|
var getCacheLocation = () => process.env.ABSOLUTE_ESLINT_CACHE?.trim() || DEFAULT_CACHE_LOCATION;
|
|
@@ -3608,7 +4589,7 @@ var checkForMisplacedIgnores = () => {
|
|
|
3608
4589
|
return;
|
|
3609
4590
|
let source;
|
|
3610
4591
|
try {
|
|
3611
|
-
source =
|
|
4592
|
+
source = readFileSync8(configPath2, "utf-8");
|
|
3612
4593
|
} catch {
|
|
3613
4594
|
return;
|
|
3614
4595
|
}
|
|
@@ -3697,7 +4678,7 @@ var eslint = async (args) => {
|
|
|
3697
4678
|
init_constants();
|
|
3698
4679
|
init_utils();
|
|
3699
4680
|
import { execSync as execSync2 } from "child_process";
|
|
3700
|
-
import { existsSync as existsSync7, readFileSync as
|
|
4681
|
+
import { existsSync as existsSync7, readFileSync as readFileSync9 } from "fs";
|
|
3701
4682
|
import { arch as arch2, cpus, platform as platform3, totalmem, version } from "os";
|
|
3702
4683
|
import { resolve as resolve5 } from "path";
|
|
3703
4684
|
var bold = (str) => `\x1B[1m${str}\x1B[0m`;
|
|
@@ -3719,7 +4700,7 @@ var getPackageVersion = (packageName) => {
|
|
|
3719
4700
|
const pkgPath = __require.resolve(`${packageName}/package.json`, {
|
|
3720
4701
|
paths: [process.cwd()]
|
|
3721
4702
|
});
|
|
3722
|
-
const pkg = JSON.parse(
|
|
4703
|
+
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
3723
4704
|
const ver = pkg.version;
|
|
3724
4705
|
return ver;
|
|
3725
4706
|
} catch {
|
|
@@ -3741,7 +4722,7 @@ var getAbsoluteVersion = () => {
|
|
|
3741
4722
|
return getPackageVersion("@absolutejs/absolute");
|
|
3742
4723
|
};
|
|
3743
4724
|
var readPackageVersion = (pkgPath) => {
|
|
3744
|
-
const pkg = JSON.parse(
|
|
4725
|
+
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
3745
4726
|
const ver = pkg.version;
|
|
3746
4727
|
return ver;
|
|
3747
4728
|
};
|
|
@@ -3843,7 +4824,7 @@ var info = () => {
|
|
|
3843
4824
|
// src/cli/cache.ts
|
|
3844
4825
|
init_constants();
|
|
3845
4826
|
import { mkdir } from "fs/promises";
|
|
3846
|
-
import { join as
|
|
4827
|
+
import { join as join6 } from "path";
|
|
3847
4828
|
var {Glob } = globalThis.Bun;
|
|
3848
4829
|
var CACHE_DIR = ".absolutejs";
|
|
3849
4830
|
var MAX_FILES_PER_BATCH = 200;
|
|
@@ -3895,7 +4876,7 @@ var hashFiles = async (paths) => {
|
|
|
3895
4876
|
};
|
|
3896
4877
|
var loadCache = async (tool) => {
|
|
3897
4878
|
try {
|
|
3898
|
-
const path =
|
|
4879
|
+
const path = join6(CACHE_DIR, `${tool}.cache.json`);
|
|
3899
4880
|
const data = await Bun.file(path).json();
|
|
3900
4881
|
const result = data;
|
|
3901
4882
|
return result;
|
|
@@ -3942,7 +4923,7 @@ var runTool = async (adapter, args) => {
|
|
|
3942
4923
|
};
|
|
3943
4924
|
var saveCache = async (tool, data) => {
|
|
3944
4925
|
await mkdir(CACHE_DIR, { recursive: true });
|
|
3945
|
-
const path =
|
|
4926
|
+
const path = join6(CACHE_DIR, `${tool}.cache.json`);
|
|
3946
4927
|
await Bun.write(path, JSON.stringify(data, null, "\t"));
|
|
3947
4928
|
};
|
|
3948
4929
|
|
|
@@ -3979,13 +4960,14 @@ var prettier = async (args) => {
|
|
|
3979
4960
|
// src/cli/scripts/start.ts
|
|
3980
4961
|
init_constants();
|
|
3981
4962
|
init_getDurationString();
|
|
4963
|
+
init_instanceRegistry();
|
|
3982
4964
|
init_loadConfig();
|
|
3983
4965
|
init_startupBanner();
|
|
3984
4966
|
init_telemetryEvent();
|
|
3985
4967
|
init_utils();
|
|
3986
4968
|
var {env: env2 } = globalThis.Bun;
|
|
3987
|
-
import { existsSync as existsSync8, readFileSync as
|
|
3988
|
-
import { basename, join as
|
|
4969
|
+
import { existsSync as existsSync8, readFileSync as readFileSync11, rmSync as rmSync3 } from "fs";
|
|
4970
|
+
import { basename as basename2, join as join9, resolve as resolve7 } from "path";
|
|
3989
4971
|
var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`;
|
|
3990
4972
|
var resolvePackageVersion = (candidates) => {
|
|
3991
4973
|
for (const candidate of candidates) {
|
|
@@ -3998,7 +4980,7 @@ var resolvePackageVersion = (candidates) => {
|
|
|
3998
4980
|
};
|
|
3999
4981
|
var readPackageVersion2 = (candidate) => {
|
|
4000
4982
|
try {
|
|
4001
|
-
const pkg = JSON.parse(
|
|
4983
|
+
const pkg = JSON.parse(readFileSync11(candidate, "utf-8"));
|
|
4002
4984
|
if (pkg.name !== "@absolutejs/absolute")
|
|
4003
4985
|
return null;
|
|
4004
4986
|
const ver = pkg.version;
|
|
@@ -4062,6 +5044,7 @@ var prerenderStaticPages = async (outputPath, prerenderPort, resolvedOutdir, sta
|
|
|
4062
5044
|
killStaleProcesses(prerenderPort);
|
|
4063
5045
|
const result = await prerenderWithServer2(outputPath, prerenderPort, resolvedOutdir, staticConfig, {
|
|
4064
5046
|
ABSOLUTE_BUILD_DIR: resolvedOutdir,
|
|
5047
|
+
ABSOLUTE_INSTANCE_MANAGED: "1",
|
|
4065
5048
|
ABSOLUTE_VERSION: absoluteVersion,
|
|
4066
5049
|
FORCE_COLOR: "0",
|
|
4067
5050
|
NODE_ENV: "production",
|
|
@@ -4077,7 +5060,7 @@ var prerenderStaticPages = async (outputPath, prerenderPort, resolvedOutdir, sta
|
|
|
4077
5060
|
var start = async (serverEntry, outdir, configPath2) => {
|
|
4078
5061
|
const port = Number(env2.PORT) || DEFAULT_PORT;
|
|
4079
5062
|
killStaleProcesses(port);
|
|
4080
|
-
const entryName =
|
|
5063
|
+
const entryName = basename2(serverEntry).replace(/\.[^.]+$/, "");
|
|
4081
5064
|
const resolvedOutdir = resolve7(outdir ?? "dist");
|
|
4082
5065
|
const absoluteVersion = resolvePackageVersion([
|
|
4083
5066
|
resolve7(import.meta.dir, "..", "..", "..", "package.json"),
|
|
@@ -4104,7 +5087,7 @@ var start = async (serverEntry, outdir, configPath2) => {
|
|
|
4104
5087
|
if (!build)
|
|
4105
5088
|
throw new Error("Could not locate build module");
|
|
4106
5089
|
await build(buildConfig);
|
|
4107
|
-
rmSync3(
|
|
5090
|
+
rmSync3(join9(resolvedOutdir, "_prerendered"), {
|
|
4108
5091
|
force: true,
|
|
4109
5092
|
recursive: true
|
|
4110
5093
|
});
|
|
@@ -4217,9 +5200,9 @@ var start = async (serverEntry, outdir, configPath2) => {
|
|
|
4217
5200
|
process.exit(1);
|
|
4218
5201
|
}
|
|
4219
5202
|
if (existsSync8(resolve7(resolvedOutdir, "angular", "vendor", "server"))) {
|
|
4220
|
-
const { readdirSync } = await import("fs");
|
|
5203
|
+
const { readdirSync: readdirSync2 } = await import("fs");
|
|
4221
5204
|
const vendorDir = resolve7(resolvedOutdir, "angular", "vendor", "server");
|
|
4222
|
-
const vendorEntries =
|
|
5205
|
+
const vendorEntries = readdirSync2(vendorDir).filter((f) => f.endsWith(".js"));
|
|
4223
5206
|
const angularServerVendorPaths = {};
|
|
4224
5207
|
const { relative: pathRelative, dirname: pathDirname } = await import("path");
|
|
4225
5208
|
for (const file of vendorEntries) {
|
|
@@ -4266,6 +5249,7 @@ var start = async (serverEntry, outdir, configPath2) => {
|
|
|
4266
5249
|
...process.env,
|
|
4267
5250
|
ABSOLUTE_BUILD_DIR: resolvedOutdir,
|
|
4268
5251
|
ABSOLUTE_BUILD_DURATION: String(Math.round(totalDuration)),
|
|
5252
|
+
ABSOLUTE_INSTANCE_MANAGED: "1",
|
|
4269
5253
|
ABSOLUTE_VERSION: absoluteVersion,
|
|
4270
5254
|
FORCE_COLOR: "1",
|
|
4271
5255
|
NODE_ENV: "production",
|
|
@@ -4275,10 +5259,35 @@ var start = async (serverEntry, outdir, configPath2) => {
|
|
|
4275
5259
|
stdin: "inherit",
|
|
4276
5260
|
stdout: "inherit"
|
|
4277
5261
|
});
|
|
5262
|
+
const relaunchCommand = [
|
|
5263
|
+
process.execPath,
|
|
5264
|
+
process.argv[1] ?? "",
|
|
5265
|
+
"start",
|
|
5266
|
+
serverEntry,
|
|
5267
|
+
...outdir ? ["--outdir", outdir] : [],
|
|
5268
|
+
...configPath2 ? ["--config", configPath2] : []
|
|
5269
|
+
].filter((part) => part.length > 0);
|
|
5270
|
+
registerInstance({
|
|
5271
|
+
command: relaunchCommand,
|
|
5272
|
+
configPath: configPath2 ?? null,
|
|
5273
|
+
controllerPid: process.pid,
|
|
5274
|
+
cwd: process.cwd(),
|
|
5275
|
+
frameworks,
|
|
5276
|
+
host: env2.ABSOLUTE_HOST ?? env2.HOST ?? "localhost",
|
|
5277
|
+
https: env2.ABSOLUTE_HTTPS === "true",
|
|
5278
|
+
logFile: null,
|
|
5279
|
+
name: resolveProjectName(process.cwd()),
|
|
5280
|
+
pid: process.pid,
|
|
5281
|
+
port,
|
|
5282
|
+
ppid: process.ppid,
|
|
5283
|
+
source: "start",
|
|
5284
|
+
startedAt: new Date().toISOString()
|
|
5285
|
+
});
|
|
4278
5286
|
const cleanup = async (exitCode2 = 0) => {
|
|
4279
5287
|
if (cleaning)
|
|
4280
5288
|
return;
|
|
4281
5289
|
cleaning = true;
|
|
5290
|
+
deregisterInstance(process.pid);
|
|
4282
5291
|
sendTelemetryEvent("start:session-duration", {
|
|
4283
5292
|
duration: Math.round((Date.now() - sessionStart) / MILLISECONDS_IN_A_SECOND),
|
|
4284
5293
|
entry: serverEntry
|
|
@@ -4311,27 +5320,24 @@ var start = async (serverEntry, outdir, configPath2) => {
|
|
|
4311
5320
|
init_constants();
|
|
4312
5321
|
init_loadConfig();
|
|
4313
5322
|
init_getDurationString();
|
|
5323
|
+
init_instanceRegistry();
|
|
4314
5324
|
import {
|
|
4315
5325
|
appendFileSync,
|
|
4316
5326
|
existsSync as existsSync9,
|
|
4317
|
-
mkdirSync as
|
|
4318
|
-
readdirSync,
|
|
4319
|
-
readFileSync as
|
|
4320
|
-
unlinkSync as
|
|
4321
|
-
writeFileSync as
|
|
5327
|
+
mkdirSync as mkdirSync6,
|
|
5328
|
+
readdirSync as readdirSync2,
|
|
5329
|
+
readFileSync as readFileSync12,
|
|
5330
|
+
unlinkSync as unlinkSync3,
|
|
5331
|
+
writeFileSync as writeFileSync4
|
|
4322
5332
|
} from "fs";
|
|
4323
5333
|
import { createConnection } from "net";
|
|
4324
5334
|
import { resolve as resolve8 } from "path";
|
|
4325
5335
|
|
|
4326
5336
|
// src/cli/workspaceTui.ts
|
|
4327
5337
|
init_constants();
|
|
5338
|
+
init_tuiPrimitives();
|
|
4328
5339
|
init_getDurationString();
|
|
4329
|
-
import { openSync as openSync2 } from "fs";
|
|
4330
|
-
import { ReadStream as ReadStream2 } from "tty";
|
|
4331
5340
|
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
5341
|
var SHORTCUTS2 = new Map([
|
|
4336
5342
|
["c", "clear"],
|
|
4337
5343
|
["h", "help"],
|
|
@@ -4340,15 +5346,6 @@ var SHORTCUTS2 = new Map([
|
|
|
4340
5346
|
["q", "quit"],
|
|
4341
5347
|
["r", "restart"]
|
|
4342
5348
|
]);
|
|
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
5349
|
var helpLines = [
|
|
4353
5350
|
"Hotkeys",
|
|
4354
5351
|
" h Toggle help",
|
|
@@ -4367,108 +5364,6 @@ var helpLines = [
|
|
|
4367
5364
|
" Press Esc to exit shell mode or dismiss help.",
|
|
4368
5365
|
" Use \u2191 and \u2193 to recall prior shell commands."
|
|
4369
5366
|
];
|
|
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
5367
|
var getStatusColor = (status2) => {
|
|
4473
5368
|
if (status2 === "ready")
|
|
4474
5369
|
return colors.green;
|
|
@@ -4528,12 +5423,6 @@ var getVisibleLogContent = (contentLines, logHeight, logScrollOffset) => {
|
|
|
4528
5423
|
const start2 = Math.max(0, end - logHeight);
|
|
4529
5424
|
return contentLines.slice(start2, end);
|
|
4530
5425
|
};
|
|
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
5426
|
var createWorkspaceTui = ({
|
|
4538
5427
|
actions,
|
|
4539
5428
|
headless: headlessOption,
|
|
@@ -5004,10 +5893,10 @@ var stripAnsi2 = (value) => value.replace(ANSI_REGEX2, "");
|
|
|
5004
5893
|
var sanitizeLogFileName = (value) => value.replace(/[^a-zA-Z0-9._-]/g, "_") || "unknown";
|
|
5005
5894
|
var createWorkspaceLogSink = (appendLog) => {
|
|
5006
5895
|
const logDirectory = resolve8(".absolutejs", "workspace", "logs");
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5896
|
+
mkdirSync6(logDirectory, { recursive: true });
|
|
5897
|
+
readdirSync2(logDirectory).filter((file) => file.endsWith(".log")).forEach((file) => unlinkSync3(resolve8(logDirectory, file)));
|
|
5898
|
+
writeFileSync4(resolve8(logDirectory, "all.log"), "");
|
|
5899
|
+
writeFileSync4(resolve8(logDirectory, "workspace.log"), "");
|
|
5011
5900
|
const initializedSources = new Set(["workspace"]);
|
|
5012
5901
|
const writeLog = (source, message, level) => {
|
|
5013
5902
|
const cleanMessage = stripAnsi2(message).trimEnd();
|
|
@@ -5019,7 +5908,7 @@ var createWorkspaceLogSink = (appendLog) => {
|
|
|
5019
5908
|
`;
|
|
5020
5909
|
const sourceFile = resolve8(logDirectory, `${sanitizeLogFileName(source)}.log`);
|
|
5021
5910
|
if (!initializedSources.has(source)) {
|
|
5022
|
-
|
|
5911
|
+
writeFileSync4(sourceFile, "");
|
|
5023
5912
|
initializedSources.add(source);
|
|
5024
5913
|
}
|
|
5025
5914
|
appendFileSync(sourceFile, line);
|
|
@@ -5035,7 +5924,7 @@ var createWorkspaceLogSink = (appendLog) => {
|
|
|
5035
5924
|
};
|
|
5036
5925
|
var readPackageVersion3 = (candidate) => {
|
|
5037
5926
|
try {
|
|
5038
|
-
const pkg = JSON.parse(
|
|
5927
|
+
const pkg = JSON.parse(readFileSync12(candidate, "utf-8"));
|
|
5039
5928
|
if (pkg.name !== "@absolutejs/absolute") {
|
|
5040
5929
|
return null;
|
|
5041
5930
|
}
|
|
@@ -5407,6 +6296,7 @@ var resolveAbsoluteServiceConfigPath = (service, cwd, options) => {
|
|
|
5407
6296
|
var resolveService = (name, service, workspaceEnv, options) => {
|
|
5408
6297
|
const cwd = resolve8(service.cwd ?? ".");
|
|
5409
6298
|
const envVars = Object.assign(getDefinedProcessEnv(), workspaceEnv, service.port ? { PORT: String(service.port) } : {}, service.env, {
|
|
6299
|
+
ABSOLUTE_INSTANCE_MANAGED: "1",
|
|
5410
6300
|
ABSOLUTE_WORKSPACE_MANAGED: "1",
|
|
5411
6301
|
ABSOLUTE_WORKSPACE_SERVICE_NAME: name,
|
|
5412
6302
|
ABSOLUTE_WORKSPACE_SERVICE_VISIBILITY: getVisibility(service),
|
|
@@ -5512,6 +6402,7 @@ var workspace = async (subcommand, options) => {
|
|
|
5512
6402
|
try {
|
|
5513
6403
|
service.process.kill();
|
|
5514
6404
|
} catch {}
|
|
6405
|
+
deregisterInstance(service.process.pid);
|
|
5515
6406
|
};
|
|
5516
6407
|
const runShutdownHookSafely = async (service) => {
|
|
5517
6408
|
try {
|
|
@@ -5654,6 +6545,22 @@ var workspace = async (subcommand, options) => {
|
|
|
5654
6545
|
resolved
|
|
5655
6546
|
};
|
|
5656
6547
|
running.push(runningService);
|
|
6548
|
+
registerInstance({
|
|
6549
|
+
command: [],
|
|
6550
|
+
configPath: resolved.configPath ?? null,
|
|
6551
|
+
controllerPid: process.pid,
|
|
6552
|
+
cwd: resolved.cwd,
|
|
6553
|
+
frameworks: [],
|
|
6554
|
+
host: getServicePublicHost(resolved.service),
|
|
6555
|
+
https: getServiceProtocol(resolved.service) === "https",
|
|
6556
|
+
logFile: resolve8(workspaceLogs.logDirectory, `${sanitizeLogFileName(name)}.log`),
|
|
6557
|
+
name,
|
|
6558
|
+
pid: processHandle.pid,
|
|
6559
|
+
port: resolved.service.port ?? null,
|
|
6560
|
+
ppid: process.pid,
|
|
6561
|
+
source: "workspace",
|
|
6562
|
+
startedAt: new Date().toISOString()
|
|
6563
|
+
});
|
|
5657
6564
|
processHandle.exited.then(handleServiceExit.bind(null, runningService));
|
|
5658
6565
|
await waitForReady(resolved);
|
|
5659
6566
|
const startedAt = serviceBootStartedAt.get(name);
|
|
@@ -5810,6 +6717,10 @@ if (command === "dev") {
|
|
|
5810
6717
|
} else if (command === "prettier") {
|
|
5811
6718
|
sendTelemetryEvent("cli:command", { command });
|
|
5812
6719
|
await prettier(args);
|
|
6720
|
+
} else if (command === "ls" || command === "list" || command === "ps") {
|
|
6721
|
+
sendTelemetryEvent("cli:command", { command: "ls" });
|
|
6722
|
+
const { runList: runList2 } = await Promise.resolve().then(() => (init_list(), exports_list));
|
|
6723
|
+
await runList2(args);
|
|
5813
6724
|
} else if (command === "info") {
|
|
5814
6725
|
sendTelemetryEvent("cli:command", { command });
|
|
5815
6726
|
info();
|
|
@@ -5847,6 +6758,7 @@ if (command === "dev") {
|
|
|
5847
6758
|
console.error(" config [--port n] Open the unified config UI (ESLint, tsconfig, Prettier)");
|
|
5848
6759
|
console.error(" eslint Run ESLint (cached)");
|
|
5849
6760
|
console.error(" info Print system info for bug reports");
|
|
6761
|
+
console.error(" ls [--watch] [--json] List/manage running servers (alias: list)");
|
|
5850
6762
|
console.error(" prettier Run Prettier check (cached)");
|
|
5851
6763
|
console.error(" typecheck Run type checkers for all frameworks");
|
|
5852
6764
|
console.error(" telemetry Manage anonymous telemetry");
|