qunitx-cli 0.23.1 → 0.23.3
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/README.md +1 -1
- package/dist/cli.js +44 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -115,7 +115,7 @@ What it does: cold-start cost dominates a single `qunitx` run — launching Chro
|
|
|
115
115
|
|
|
116
116
|
A single one-off run won't get faster from spinning the daemon up; it's an opt-in optimization aimed at two situations:
|
|
117
117
|
|
|
118
|
-
- **Local TDD loops.** Export `QUNITX_DAEMON=1` in your shell profile (or run `qunitx daemon start` once at the top of your session) and forget about it — subsequent runs reuse the daemon automatically until you `daemon stop` or 30 idle minutes pass.
|
|
118
|
+
- **Local TDD loops.** Export `QUNITX_DAEMON=1` in your shell profile (or run `qunitx daemon start` once at the top of your session) and forget about it — subsequent runs reuse the daemon automatically until you `daemon stop` or 30 idle minutes pass. Override the idle window with `QUNITX_DAEMON_IDLE_TIMEOUT` (`1h`, `45s`, `500ms`; bare numbers are minutes), or set it to `false` to disable auto-shutdown entirely.
|
|
119
119
|
- **Monorepo CI** where each package shells out to `qunitx` separately. Set `QUNITX_DAEMON=1` for the job and a single daemon is auto-spawned and reused across every package's invocation.
|
|
120
120
|
|
|
121
121
|
```sh
|
package/dist/cli.js
CHANGED
|
@@ -374,7 +374,7 @@ var init_package = __esm({
|
|
|
374
374
|
package_default = {
|
|
375
375
|
name: "qunitx-cli",
|
|
376
376
|
type: "module",
|
|
377
|
-
version: "0.23.
|
|
377
|
+
version: "0.23.3",
|
|
378
378
|
description: "Browser runner for QUnitx: run your qunitx tests in google-chrome",
|
|
379
379
|
author: "Izel Nakri",
|
|
380
380
|
license: "MIT",
|
|
@@ -748,6 +748,31 @@ var init_init = __esm({
|
|
|
748
748
|
}
|
|
749
749
|
});
|
|
750
750
|
|
|
751
|
+
// lib/utils/parse-daemon-idle-timeout.ts
|
|
752
|
+
function parseDaemonIdleTimeout(value) {
|
|
753
|
+
if (!value) return { ms: DEFAULT_DAEMON_IDLE_TIMEOUT_MS, warning: null };
|
|
754
|
+
if (/^\s*false\s*$/i.test(value)) return { ms: Infinity, warning: null };
|
|
755
|
+
const match = /^\s*(\d+(?:\.\d+)?)\s*(ms|s|m|h)?\s*$/i.exec(value);
|
|
756
|
+
if (!match) return invalid(value);
|
|
757
|
+
const n = Number(match[1]);
|
|
758
|
+
if (!(n > 0)) return invalid(value);
|
|
759
|
+
const unit = (match[2] ?? "m").toLowerCase();
|
|
760
|
+
return { ms: Math.round(n * UNIT_TO_MS[unit]), warning: null };
|
|
761
|
+
}
|
|
762
|
+
function invalid(value) {
|
|
763
|
+
return {
|
|
764
|
+
ms: DEFAULT_DAEMON_IDLE_TIMEOUT_MS,
|
|
765
|
+
warning: `\u26A0 qunitx: QUNITX_DAEMON_IDLE_TIMEOUT=${JSON.stringify(value)} is not a valid duration; using 30-minute default. Accepted: bare number = minutes, "30m", "1h", "45s", "500ms", "false" (no auto-shutdown).`
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
var UNIT_TO_MS, DEFAULT_DAEMON_IDLE_TIMEOUT_MS;
|
|
769
|
+
var init_parse_daemon_idle_timeout = __esm({
|
|
770
|
+
"lib/utils/parse-daemon-idle-timeout.ts"() {
|
|
771
|
+
UNIT_TO_MS = { ms: 1, s: 1e3, m: 6e4, h: 36e5 };
|
|
772
|
+
DEFAULT_DAEMON_IDLE_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
|
|
751
776
|
// lib/utils/close-with-grace.ts
|
|
752
777
|
function closeWithGrace(closes, graceMs = CLEANUP_GRACE_MS) {
|
|
753
778
|
return new Promise((resolve) => {
|
|
@@ -4461,6 +4486,7 @@ async function shutdownDaemon2(state, reason) {
|
|
|
4461
4486
|
}
|
|
4462
4487
|
function resetIdleTimer(state) {
|
|
4463
4488
|
if (state.idleTimer) clearTimeout(state.idleTimer);
|
|
4489
|
+
if (!Number.isFinite(IDLE_TIMEOUT_MS)) return;
|
|
4464
4490
|
state.idleTimer = setTimeout(() => void shutdownDaemon2(state, "idle timeout"), IDLE_TIMEOUT_MS);
|
|
4465
4491
|
state.idleTimer.unref();
|
|
4466
4492
|
}
|
|
@@ -4634,12 +4660,13 @@ var IDLE_TIMEOUT_MS, LIVENESS_PROBE_TIMEOUT_MS, MAX_CONSECUTIVE_CRASHES;
|
|
|
4634
4660
|
var init_server = __esm({
|
|
4635
4661
|
"lib/commands/daemon/server.ts"() {
|
|
4636
4662
|
init_daemon_socket_path();
|
|
4663
|
+
init_parse_daemon_idle_timeout();
|
|
4637
4664
|
init_socket_utils();
|
|
4638
4665
|
init_config();
|
|
4639
4666
|
init_browser();
|
|
4640
4667
|
init_tests_in_browser();
|
|
4641
4668
|
init_run();
|
|
4642
|
-
IDLE_TIMEOUT_MS =
|
|
4669
|
+
IDLE_TIMEOUT_MS = parseDaemonIdleTimeout(process.env.QUNITX_DAEMON_IDLE_TIMEOUT).ms;
|
|
4643
4670
|
LIVENESS_PROBE_TIMEOUT_MS = 500;
|
|
4644
4671
|
MAX_CONSECUTIVE_CRASHES = 2;
|
|
4645
4672
|
}
|
|
@@ -4654,7 +4681,11 @@ __export(daemon_exports, {
|
|
|
4654
4681
|
import { spawn as spawn3 } from "node:child_process";
|
|
4655
4682
|
import fs16, { existsSync as existsSync3 } from "node:fs";
|
|
4656
4683
|
import path13 from "node:path";
|
|
4657
|
-
|
|
4684
|
+
async function buildDaemonSpawn() {
|
|
4685
|
+
const sea = await import("node:sea").catch(() => null);
|
|
4686
|
+
if (sea?.isSea()) return { bin: process.execPath, args: ["daemon", "_serve"] };
|
|
4687
|
+
return { bin: process.execPath, args: [process.argv[1], "daemon", "_serve"] };
|
|
4688
|
+
}
|
|
4658
4689
|
function runDaemonCommand() {
|
|
4659
4690
|
const sub = process.argv[3];
|
|
4660
4691
|
if (sub === "_serve") return runServeMode();
|
|
@@ -4690,7 +4721,10 @@ function waitForFile(filePath, timeoutMs) {
|
|
|
4690
4721
|
});
|
|
4691
4722
|
}
|
|
4692
4723
|
async function spawnAndWaitForDaemon() {
|
|
4693
|
-
|
|
4724
|
+
const parsed = parseDaemonIdleTimeout(process.env.QUNITX_DAEMON_IDLE_TIMEOUT);
|
|
4725
|
+
if (parsed.warning) process.stderr.write(parsed.warning + "\n");
|
|
4726
|
+
const { bin, args } = await buildDaemonSpawn();
|
|
4727
|
+
spawn3(bin, args, {
|
|
4694
4728
|
detached: true,
|
|
4695
4729
|
stdio: "ignore",
|
|
4696
4730
|
env: { ...process.env, QUNITX_DAEMON_CWD: process.cwd() }
|
|
@@ -4743,11 +4777,12 @@ async function statusDaemon() {
|
|
|
4743
4777
|
);
|
|
4744
4778
|
return 0;
|
|
4745
4779
|
}
|
|
4746
|
-
var SPAWN_TIMEOUT_MS, highlight2, color2, USAGE
|
|
4780
|
+
var SPAWN_TIMEOUT_MS, highlight2, color2, USAGE;
|
|
4747
4781
|
var init_daemon = __esm({
|
|
4748
4782
|
"lib/commands/daemon/index.ts"() {
|
|
4749
4783
|
init_color();
|
|
4750
4784
|
init_daemon_socket_path();
|
|
4785
|
+
init_parse_daemon_idle_timeout();
|
|
4751
4786
|
init_client();
|
|
4752
4787
|
init_package();
|
|
4753
4788
|
SPAWN_TIMEOUT_MS = 3e4;
|
|
@@ -4761,13 +4796,13 @@ ${color2("$ qunitx daemon stop")} # Stop the running daemon
|
|
|
4761
4796
|
${color2("$ qunitx daemon status")} # Print pid, socket, and uptime
|
|
4762
4797
|
|
|
4763
4798
|
${highlight2("Environment:")}
|
|
4764
|
-
${color2("QUNITX_DAEMON=1")}
|
|
4765
|
-
${color2("QUNITX_NO_DAEMON=1")}
|
|
4799
|
+
${color2("QUNITX_DAEMON=1")} : auto-spawn the daemon on the first qunitx run; reuse it on every run after (overrides the CI=1 bypass)
|
|
4800
|
+
${color2("QUNITX_NO_DAEMON=1")} : never use the daemon for this run
|
|
4801
|
+
${color2("QUNITX_DAEMON_IDLE_TIMEOUT")} : idle window before self-shutdown (default 30m). Bare number = minutes; ${color2("ms")} / ${color2("s")} / ${color2("m")} / ${color2("h")} suffixes accepted (${color2("1h")}, ${color2("45s")}, ${color2("500ms")}). Set to ${color2("false")} to disable auto-shutdown. Read at daemon spawn; invalid values warn and fall back to the default.
|
|
4802
|
+
${color2("QUNITX_DAEMON_LOG=<path>")} : redirect the daemon's stdout + stderr to a file (otherwise lost to the detached spawn)
|
|
4766
4803
|
|
|
4767
4804
|
${highlight2("Tip:")} set ${color2("QUNITX_DAEMON=1")} to auto-spawn the daemon on the first qunitx run; ${color2("$ qunitx --help")} for top-level options.
|
|
4768
4805
|
`;
|
|
4769
|
-
__filename = fileURLToPath2(import.meta.url);
|
|
4770
|
-
CLI_ENTRY = path13.resolve(path13.dirname(__filename), "..", "..", "..", "cli.ts");
|
|
4771
4806
|
}
|
|
4772
4807
|
});
|
|
4773
4808
|
|