@cliftonc/cfld 0.2.2 → 0.2.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/dist/cli.js +68 -48
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -637,13 +637,13 @@ async function startRunner(options) {
|
|
|
637
637
|
);
|
|
638
638
|
return;
|
|
639
639
|
}
|
|
640
|
-
const
|
|
640
|
+
const delay2 = BACKOFF_MS[Math.min(rapidFailures, BACKOFF_MS.length - 1)];
|
|
641
641
|
options.onStatus?.("reconnecting");
|
|
642
642
|
restartTimer = setTimeout(() => {
|
|
643
643
|
if (stopped) return;
|
|
644
644
|
options.onStatus?.("connecting");
|
|
645
645
|
spawnOnce();
|
|
646
|
-
},
|
|
646
|
+
}, delay2);
|
|
647
647
|
restartTimer.unref();
|
|
648
648
|
});
|
|
649
649
|
};
|
|
@@ -700,13 +700,15 @@ function startChild(options) {
|
|
|
700
700
|
const exited = new Promise((resolve) => {
|
|
701
701
|
markExited = resolve;
|
|
702
702
|
});
|
|
703
|
+
const ownPgid = getpgid(process.pid);
|
|
703
704
|
const trackedPgids = /* @__PURE__ */ new Set();
|
|
705
|
+
const track = (g) => {
|
|
706
|
+
if (g > 1 && g !== process.pid && g !== ownPgid) trackedPgids.add(g);
|
|
707
|
+
};
|
|
708
|
+
if (child.pid !== void 0) track(child.pid);
|
|
704
709
|
const trackTree = () => {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
for (const g of descendantPgids(pid)) {
|
|
708
|
-
if (g > 1 && g !== process.pid) trackedPgids.add(g);
|
|
709
|
-
}
|
|
710
|
+
if (child.pid === void 0) return;
|
|
711
|
+
for (const g of descendantPgids(child.pid)) track(g);
|
|
710
712
|
};
|
|
711
713
|
const poll = setInterval(trackTree, options.pollTreeMs ?? 1500);
|
|
712
714
|
poll.unref();
|
|
@@ -729,8 +731,6 @@ function startChild(options) {
|
|
|
729
731
|
});
|
|
730
732
|
const signalTree = (signal) => {
|
|
731
733
|
trackTree();
|
|
732
|
-
const pid = child.pid;
|
|
733
|
-
if (pid !== void 0) trySignalGroup(pid, signal);
|
|
734
734
|
for (const g of trackedPgids) trySignalGroup(g, signal);
|
|
735
735
|
};
|
|
736
736
|
return {
|
|
@@ -738,15 +738,15 @@ function startChild(options) {
|
|
|
738
738
|
get pid() {
|
|
739
739
|
return child.pid;
|
|
740
740
|
},
|
|
741
|
+
treeAlive() {
|
|
742
|
+
if (trackedPgids.size === 0) return false;
|
|
743
|
+
const live = livePgids();
|
|
744
|
+
for (const g of trackedPgids) if (live.has(g)) return true;
|
|
745
|
+
return false;
|
|
746
|
+
},
|
|
741
747
|
stop() {
|
|
742
|
-
if (stopped) return;
|
|
743
748
|
stopped = true;
|
|
744
|
-
clearInterval(poll);
|
|
745
749
|
signalTree("SIGINT");
|
|
746
|
-
const t = setTimeout(() => {
|
|
747
|
-
if (child.exitCode === null && !child.signalCode) signalTree("SIGKILL");
|
|
748
|
-
}, 4e3);
|
|
749
|
-
t.unref();
|
|
750
750
|
},
|
|
751
751
|
kill() {
|
|
752
752
|
clearInterval(poll);
|
|
@@ -793,18 +793,36 @@ function trySignalGroup(pgid, signal) {
|
|
|
793
793
|
} catch {
|
|
794
794
|
}
|
|
795
795
|
}
|
|
796
|
-
function
|
|
796
|
+
function getpgid(pid) {
|
|
797
|
+
try {
|
|
798
|
+
const n = Number(execSync(`ps -o pgid= -p ${pid}`, { encoding: "utf8" }).trim());
|
|
799
|
+
return Number.isInteger(n) ? n : void 0;
|
|
800
|
+
} catch {
|
|
801
|
+
return void 0;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
function livePgids() {
|
|
805
|
+
const live = /* @__PURE__ */ new Set();
|
|
806
|
+
try {
|
|
807
|
+
for (const line of execSync("ps -A -o pgid=", { encoding: "utf8" }).split("\n")) {
|
|
808
|
+
const n = Number(line.trim());
|
|
809
|
+
if (Number.isInteger(n) && n > 0) live.add(n);
|
|
810
|
+
}
|
|
811
|
+
} catch {
|
|
812
|
+
}
|
|
813
|
+
return live;
|
|
814
|
+
}
|
|
815
|
+
var delay = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
816
|
+
async function reapChild(child, graceMs = 3e3) {
|
|
797
817
|
child.stop();
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
child.exited.then(done2);
|
|
807
|
-
});
|
|
818
|
+
await Promise.race([child.exited, delay(Math.min(graceMs, 1200))]);
|
|
819
|
+
const deadline = Date.now() + graceMs + 5e3;
|
|
820
|
+
for (; ; ) {
|
|
821
|
+
child.kill();
|
|
822
|
+
if (!child.treeAlive()) return;
|
|
823
|
+
if (Date.now() >= deadline) return;
|
|
824
|
+
await delay(200);
|
|
825
|
+
}
|
|
808
826
|
}
|
|
809
827
|
function wireLines2(child, stream, onLine) {
|
|
810
828
|
const source = stream === "stdout" ? child.stdout : child.stderr;
|
|
@@ -1177,6 +1195,7 @@ async function runCommand(flags) {
|
|
|
1177
1195
|
cwd,
|
|
1178
1196
|
envKey,
|
|
1179
1197
|
noEnv: flags.noEnv,
|
|
1198
|
+
noUi: flags.noUi,
|
|
1180
1199
|
port: primary.port,
|
|
1181
1200
|
exec: flags.exec
|
|
1182
1201
|
});
|
|
@@ -1185,7 +1204,7 @@ async function launch(result, ctx) {
|
|
|
1185
1204
|
const metricsPort = await findFreePort();
|
|
1186
1205
|
const url = `https://${result.hostname}`;
|
|
1187
1206
|
const target = `localhost:${ctx.port}`;
|
|
1188
|
-
const interactive = isInteractive();
|
|
1207
|
+
const interactive = isInteractive() && !ctx.noUi;
|
|
1189
1208
|
let dashboard;
|
|
1190
1209
|
if (interactive) {
|
|
1191
1210
|
const { startDashboard } = await import("./dashboard-Q6WI32AK.js");
|
|
@@ -1228,9 +1247,9 @@ async function launch(result, ctx) {
|
|
|
1228
1247
|
dashboard?.stop();
|
|
1229
1248
|
if (opts.reason) note(`
|
|
1230
1249
|
${opts.reason}`);
|
|
1231
|
-
const
|
|
1232
|
-
if (child) reapChild(child).then(
|
|
1233
|
-
else
|
|
1250
|
+
const finish = () => process.exit(opts.code ?? 0);
|
|
1251
|
+
if (child) reapChild(child).then(finish, finish);
|
|
1252
|
+
else finish();
|
|
1234
1253
|
};
|
|
1235
1254
|
runner = await startRunner({
|
|
1236
1255
|
configPath: result.configPath,
|
|
@@ -1264,16 +1283,15 @@ ${opts.reason}`);
|
|
|
1264
1283
|
}
|
|
1265
1284
|
});
|
|
1266
1285
|
}
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
}
|
|
1286
|
+
process.once(
|
|
1287
|
+
"SIGINT",
|
|
1288
|
+
() => shutdown({ reason: "Stopping \u2014 your URL is preserved. Re-run `cfld`." })
|
|
1289
|
+
);
|
|
1290
|
+
process.once(
|
|
1291
|
+
"SIGTERM",
|
|
1292
|
+
() => shutdown({ reason: "Stopping \u2014 your URL is preserved." })
|
|
1293
|
+
);
|
|
1294
|
+
process.once("SIGHUP", () => shutdown({ reason: "Terminal closed \u2014 stopping." }));
|
|
1277
1295
|
const ready = await waitForReady(metricsPort).catch((err) => {
|
|
1278
1296
|
child?.stop();
|
|
1279
1297
|
runner?.stop();
|
|
@@ -1411,7 +1429,7 @@ async function startQuickTunnel(port, opts = {}) {
|
|
|
1411
1429
|
async function quickCommand(flags) {
|
|
1412
1430
|
const port = await resolvePort2(flags);
|
|
1413
1431
|
const target = `localhost:${port}`;
|
|
1414
|
-
const interactive = isInteractive();
|
|
1432
|
+
const interactive = isInteractive() && !flags.noUi;
|
|
1415
1433
|
const metricsPort = await findFreePort();
|
|
1416
1434
|
const envKey = flags.envKey ?? "PUBLIC_URL";
|
|
1417
1435
|
if (!interactive) step(`Starting an ephemeral tunnel to ${target}\u2026`);
|
|
@@ -1444,9 +1462,9 @@ async function quickCommand(flags) {
|
|
|
1444
1462
|
dashboard?.stop();
|
|
1445
1463
|
note(`
|
|
1446
1464
|
${opts.reason ?? "Stopped ephemeral tunnel."}`);
|
|
1447
|
-
const
|
|
1448
|
-
if (child) reapChild(child).then(
|
|
1449
|
-
else
|
|
1465
|
+
const finish = () => process.exit(opts.code ?? 0);
|
|
1466
|
+
if (child) reapChild(child).then(finish, finish);
|
|
1467
|
+
else finish();
|
|
1450
1468
|
};
|
|
1451
1469
|
tunnel = await startQuickTunnel(port, { metricsPort, onLine: emitLine });
|
|
1452
1470
|
const url = tunnel.url;
|
|
@@ -1484,10 +1502,9 @@ ${opts.reason ?? "Stopped ephemeral tunnel."}`);
|
|
|
1484
1502
|
ephemeral: true
|
|
1485
1503
|
});
|
|
1486
1504
|
}
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
}
|
|
1505
|
+
process.once("SIGINT", () => shutdown());
|
|
1506
|
+
process.once("SIGTERM", () => shutdown());
|
|
1507
|
+
process.once("SIGHUP", () => shutdown());
|
|
1491
1508
|
if (child) {
|
|
1492
1509
|
if (!dashboard) step(`Waiting for your dev server on :${port}\u2026`);
|
|
1493
1510
|
const up = await waitForPort(port, { signal: childAbort.signal });
|
|
@@ -2237,6 +2254,7 @@ ${pc7.bold("Options")}
|
|
|
2237
2254
|
--zone <domain> Cloudflare domain to use (e.g. example.com)
|
|
2238
2255
|
--env <KEY> .env key to write the URL to (default: PUBLIC_URL)
|
|
2239
2256
|
--no-env Don't write the URL to .env
|
|
2257
|
+
--no-ui Plain line-by-line output instead of the live dashboard
|
|
2240
2258
|
--exec <cmd> Dev command to run + supervise (shell form of \`-- <cmd>\`)
|
|
2241
2259
|
--force Skip confirmation (destroy)
|
|
2242
2260
|
-h, --help Show this help
|
|
@@ -2257,6 +2275,7 @@ async function main(rawArgv) {
|
|
|
2257
2275
|
zone: { type: "string" },
|
|
2258
2276
|
env: { type: "string" },
|
|
2259
2277
|
"no-env": { type: "boolean" },
|
|
2278
|
+
"no-ui": { type: "boolean" },
|
|
2260
2279
|
exec: { type: "string" },
|
|
2261
2280
|
quick: { type: "boolean" },
|
|
2262
2281
|
force: { type: "boolean" },
|
|
@@ -2280,6 +2299,7 @@ async function main(rawArgv) {
|
|
|
2280
2299
|
zone: values.zone,
|
|
2281
2300
|
envKey: values.env,
|
|
2282
2301
|
noEnv: values["no-env"],
|
|
2302
|
+
noUi: values["no-ui"],
|
|
2283
2303
|
quick: values.quick,
|
|
2284
2304
|
force: values.force,
|
|
2285
2305
|
reauth: values.reauth,
|