rechrome 1.35.0 → 1.35.1
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/package.json +1 -1
- package/rechrome.js +53 -13
- package/rechrome.ts +53 -13
package/package.json
CHANGED
package/rechrome.js
CHANGED
|
@@ -1509,11 +1509,7 @@ async function shareSet(snapshot: string[], opts: { listener?: string; local?: b
|
|
|
1509
1509
|
// A one-profile link names its profile, so the other machine needs no --profile.
|
|
1510
1510
|
const only = snapshot.length === 1 ? `?profile=${encodeURIComponent(snapshot[0])}` : "";
|
|
1511
1511
|
const local = `http://${listener.key}@${listenerAddress(listener)}${normalizePrefix(listener.prefix)}${only}`;
|
|
1512
|
-
|
|
1513
|
-
for (let i = 0; i < 20 && !ready; i++) {
|
|
1514
|
-
ready = await fetch(serviceUrl(local, "ping"), { headers: { Authorization: `Bearer ${listener.key}` }, signal: AbortSignal.timeout(1000) }).then(r => r.ok).catch(() => false);
|
|
1515
|
-
if (!ready) await Bun.sleep(250);
|
|
1516
|
-
}
|
|
1512
|
+
const ready = await waitForListener(listener);
|
|
1517
1513
|
if (!ready) console.error(`[rech] warning: listener "${name}" is not answering yet; check the daemon with rech status.`);
|
|
1518
1514
|
if (opts.tailscaleServe && !listener.publicUrl) {
|
|
1519
1515
|
const publicUrl = await exposeWithTailscaleServe(listener);
|
|
@@ -1570,6 +1566,32 @@ async function exposeWithTailscaleServe(listener: Listener): Promise<string | nu
|
|
|
1570
1566
|
return (await detectTailscaleServe(listener.port, prefix)).routeUrl;
|
|
1571
1567
|
}
|
|
1572
1568
|
|
|
1569
|
+
/** The daemon reloads listeners.json about every second: wait (up to ~5s) until this listener answers. */
|
|
1570
|
+
async function waitForListener(listener: Listener): Promise<boolean> {
|
|
1571
|
+
const url = `http://${listener.key}@${listenerAddress(listener)}${normalizePrefix(listener.prefix)}`;
|
|
1572
|
+
for (let i = 0; i < 20; i++) {
|
|
1573
|
+
if (await fetch(serviceUrl(url, "ping"), { headers: { Authorization: `Bearer ${listener.key}` }, signal: AbortSignal.timeout(1000) }).then(r => r.ok).catch(() => false)) return true;
|
|
1574
|
+
await Bun.sleep(250);
|
|
1575
|
+
}
|
|
1576
|
+
return false;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
/**
|
|
1580
|
+
* Ask how other machines will reach a link: "tailscale-serve", a detected network address
|
|
1581
|
+
* (plain HTTP), "127.0.0.1" for the user's own proxy, or `extra` choices; null when cancelled.
|
|
1582
|
+
*/
|
|
1583
|
+
async function askReachability(question: string, extra: { label: string; value: string }[] = []): Promise<string | null> {
|
|
1584
|
+
const serve = !!tailscaleBinary();
|
|
1585
|
+
// With Tailscale Serve on offer, a plain-HTTP Tailscale IP would only be a worse duplicate.
|
|
1586
|
+
const networks = (await detectListenChoices()).filter(c => c.kind !== "local" && !(serve && c.kind === "tailscale"));
|
|
1587
|
+
return promptChoice(question, [
|
|
1588
|
+
...(serve ? [{ label: "Tailscale: HTTPS, only your tailnet", value: "tailscale-serve" }] : []),
|
|
1589
|
+
...networks.map(c => ({ label: `${c.label.split(" — ")[0]} network: http://${c.address}, plain HTTP`, value: c.address })),
|
|
1590
|
+
{ label: "My own reverse proxy", value: "127.0.0.1" },
|
|
1591
|
+
...extra,
|
|
1592
|
+
], 0);
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1573
1595
|
/**
|
|
1574
1596
|
* Give one profile its own link. In a terminal, ask how the other machines will reach it
|
|
1575
1597
|
* (Tailscale Serve, a detected network, or the user's own proxy); without one, create a
|
|
@@ -1580,14 +1602,7 @@ async function shareNewLink(profile: string, opts: { local?: boolean; save?: boo
|
|
|
1580
1602
|
const name = uniqueShareName(profileSlug(profile), (await requireListeners()).listeners, served);
|
|
1581
1603
|
let host = "127.0.0.1", tailscaleServe = false;
|
|
1582
1604
|
if (isInteractive()) {
|
|
1583
|
-
const
|
|
1584
|
-
// With Tailscale Serve on offer, a plain-HTTP Tailscale IP would only be a worse duplicate.
|
|
1585
|
-
const networks = (await detectListenChoices()).filter(c => c.kind !== "local" && !(serve && c.kind === "tailscale"));
|
|
1586
|
-
const how = await promptChoice(`How will your other machines reach it?`, [
|
|
1587
|
-
...(serve ? [{ label: "Tailscale: HTTPS, only your tailnet", value: "tailscale-serve" }] : []),
|
|
1588
|
-
...networks.map(c => ({ label: `${c.label.split(" — ")[0]} network: http://${c.address}, plain HTTP`, value: c.address })),
|
|
1589
|
-
{ label: "My own reverse proxy", value: "127.0.0.1" },
|
|
1590
|
-
], 0);
|
|
1605
|
+
const how = await askReachability(`How will your other machines reach it?`);
|
|
1591
1606
|
if (!how) throw new Error("Cancelled; nothing shared.");
|
|
1592
1607
|
tailscaleServe = how === "tailscale-serve";
|
|
1593
1608
|
host = tailscaleServe ? "127.0.0.1" : how;
|
|
@@ -1726,6 +1741,31 @@ async function printProfileUri(selector?: string, listener?: string, opts: { loc
|
|
|
1726
1741
|
const serve = await detectTailscaleServe(pending.port, normalizePrefix(pending.prefix));
|
|
1727
1742
|
if (serve.routeUrl && !serve.funnel) { pending.publicUrl = serve.routeUrl; await writeListeners(config); }
|
|
1728
1743
|
}
|
|
1744
|
+
// Still only reachable from this machine (no proxy recorded or detected): a link like that is
|
|
1745
|
+
// useless to hand out, so ask how other machines reach it, or say how to expose it.
|
|
1746
|
+
if (config && pending && pending.profiles !== "*" && !pending.publicUrl && isLoopback(pending.host) && !opts.local) {
|
|
1747
|
+
const steps = () => { for (const line of listenerNextSteps(pending, profile)) console.error(line); };
|
|
1748
|
+
if (!interactive) {
|
|
1749
|
+
console.error(`[rech] this link only works on this machine: listener "${pending.name}" is on ${listenerAddress(pending)} and no proxy is recorded.`);
|
|
1750
|
+
steps();
|
|
1751
|
+
} else {
|
|
1752
|
+
const KEEP = "\0keep";
|
|
1753
|
+
const how = await askReachability(`Link "${pending.name}" only works on this machine (${listenerAddress(pending)}). How will your other machines reach it?`,
|
|
1754
|
+
[{ label: "Nothing: keep it on this machine", value: KEEP }]);
|
|
1755
|
+
if (!how) throw cancelled();
|
|
1756
|
+
if (how === "tailscale-serve") {
|
|
1757
|
+
const routeUrl = await exposeWithTailscaleServe(pending);
|
|
1758
|
+
if (routeUrl) { pending.publicUrl = routeUrl; await writeListeners(config); }
|
|
1759
|
+
} else if (how === "127.0.0.1") steps();
|
|
1760
|
+
else if (how !== KEEP) {
|
|
1761
|
+
// Same key and prefix, now bound on that network; links already handed out change host.
|
|
1762
|
+
pending.host = how;
|
|
1763
|
+
await writeListeners(config);
|
|
1764
|
+
if (!(await waitForListener(pending))) console.error(`[rech] warning: listener "${pending.name}" is not answering on ${listenerAddress(pending)} yet; check the daemon with rech status.`);
|
|
1765
|
+
uri = profileConnectionUri(profile, undefined, config.listeners, pending.name);
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1729
1769
|
const publicUrl = pending?.publicUrl;
|
|
1730
1770
|
if (publicUrl && !opts.local) uri = rebaseConnectionUrl(publicUrl, uri);
|
|
1731
1771
|
console.log(uri);
|
package/rechrome.ts
CHANGED
|
@@ -1509,11 +1509,7 @@ async function shareSet(snapshot: string[], opts: { listener?: string; local?: b
|
|
|
1509
1509
|
// A one-profile link names its profile, so the other machine needs no --profile.
|
|
1510
1510
|
const only = snapshot.length === 1 ? `?profile=${encodeURIComponent(snapshot[0])}` : "";
|
|
1511
1511
|
const local = `http://${listener.key}@${listenerAddress(listener)}${normalizePrefix(listener.prefix)}${only}`;
|
|
1512
|
-
|
|
1513
|
-
for (let i = 0; i < 20 && !ready; i++) {
|
|
1514
|
-
ready = await fetch(serviceUrl(local, "ping"), { headers: { Authorization: `Bearer ${listener.key}` }, signal: AbortSignal.timeout(1000) }).then(r => r.ok).catch(() => false);
|
|
1515
|
-
if (!ready) await Bun.sleep(250);
|
|
1516
|
-
}
|
|
1512
|
+
const ready = await waitForListener(listener);
|
|
1517
1513
|
if (!ready) console.error(`[rech] warning: listener "${name}" is not answering yet; check the daemon with rech status.`);
|
|
1518
1514
|
if (opts.tailscaleServe && !listener.publicUrl) {
|
|
1519
1515
|
const publicUrl = await exposeWithTailscaleServe(listener);
|
|
@@ -1570,6 +1566,32 @@ async function exposeWithTailscaleServe(listener: Listener): Promise<string | nu
|
|
|
1570
1566
|
return (await detectTailscaleServe(listener.port, prefix)).routeUrl;
|
|
1571
1567
|
}
|
|
1572
1568
|
|
|
1569
|
+
/** The daemon reloads listeners.json about every second: wait (up to ~5s) until this listener answers. */
|
|
1570
|
+
async function waitForListener(listener: Listener): Promise<boolean> {
|
|
1571
|
+
const url = `http://${listener.key}@${listenerAddress(listener)}${normalizePrefix(listener.prefix)}`;
|
|
1572
|
+
for (let i = 0; i < 20; i++) {
|
|
1573
|
+
if (await fetch(serviceUrl(url, "ping"), { headers: { Authorization: `Bearer ${listener.key}` }, signal: AbortSignal.timeout(1000) }).then(r => r.ok).catch(() => false)) return true;
|
|
1574
|
+
await Bun.sleep(250);
|
|
1575
|
+
}
|
|
1576
|
+
return false;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
/**
|
|
1580
|
+
* Ask how other machines will reach a link: "tailscale-serve", a detected network address
|
|
1581
|
+
* (plain HTTP), "127.0.0.1" for the user's own proxy, or `extra` choices; null when cancelled.
|
|
1582
|
+
*/
|
|
1583
|
+
async function askReachability(question: string, extra: { label: string; value: string }[] = []): Promise<string | null> {
|
|
1584
|
+
const serve = !!tailscaleBinary();
|
|
1585
|
+
// With Tailscale Serve on offer, a plain-HTTP Tailscale IP would only be a worse duplicate.
|
|
1586
|
+
const networks = (await detectListenChoices()).filter(c => c.kind !== "local" && !(serve && c.kind === "tailscale"));
|
|
1587
|
+
return promptChoice(question, [
|
|
1588
|
+
...(serve ? [{ label: "Tailscale: HTTPS, only your tailnet", value: "tailscale-serve" }] : []),
|
|
1589
|
+
...networks.map(c => ({ label: `${c.label.split(" — ")[0]} network: http://${c.address}, plain HTTP`, value: c.address })),
|
|
1590
|
+
{ label: "My own reverse proxy", value: "127.0.0.1" },
|
|
1591
|
+
...extra,
|
|
1592
|
+
], 0);
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1573
1595
|
/**
|
|
1574
1596
|
* Give one profile its own link. In a terminal, ask how the other machines will reach it
|
|
1575
1597
|
* (Tailscale Serve, a detected network, or the user's own proxy); without one, create a
|
|
@@ -1580,14 +1602,7 @@ async function shareNewLink(profile: string, opts: { local?: boolean; save?: boo
|
|
|
1580
1602
|
const name = uniqueShareName(profileSlug(profile), (await requireListeners()).listeners, served);
|
|
1581
1603
|
let host = "127.0.0.1", tailscaleServe = false;
|
|
1582
1604
|
if (isInteractive()) {
|
|
1583
|
-
const
|
|
1584
|
-
// With Tailscale Serve on offer, a plain-HTTP Tailscale IP would only be a worse duplicate.
|
|
1585
|
-
const networks = (await detectListenChoices()).filter(c => c.kind !== "local" && !(serve && c.kind === "tailscale"));
|
|
1586
|
-
const how = await promptChoice(`How will your other machines reach it?`, [
|
|
1587
|
-
...(serve ? [{ label: "Tailscale: HTTPS, only your tailnet", value: "tailscale-serve" }] : []),
|
|
1588
|
-
...networks.map(c => ({ label: `${c.label.split(" — ")[0]} network: http://${c.address}, plain HTTP`, value: c.address })),
|
|
1589
|
-
{ label: "My own reverse proxy", value: "127.0.0.1" },
|
|
1590
|
-
], 0);
|
|
1605
|
+
const how = await askReachability(`How will your other machines reach it?`);
|
|
1591
1606
|
if (!how) throw new Error("Cancelled; nothing shared.");
|
|
1592
1607
|
tailscaleServe = how === "tailscale-serve";
|
|
1593
1608
|
host = tailscaleServe ? "127.0.0.1" : how;
|
|
@@ -1726,6 +1741,31 @@ async function printProfileUri(selector?: string, listener?: string, opts: { loc
|
|
|
1726
1741
|
const serve = await detectTailscaleServe(pending.port, normalizePrefix(pending.prefix));
|
|
1727
1742
|
if (serve.routeUrl && !serve.funnel) { pending.publicUrl = serve.routeUrl; await writeListeners(config); }
|
|
1728
1743
|
}
|
|
1744
|
+
// Still only reachable from this machine (no proxy recorded or detected): a link like that is
|
|
1745
|
+
// useless to hand out, so ask how other machines reach it, or say how to expose it.
|
|
1746
|
+
if (config && pending && pending.profiles !== "*" && !pending.publicUrl && isLoopback(pending.host) && !opts.local) {
|
|
1747
|
+
const steps = () => { for (const line of listenerNextSteps(pending, profile)) console.error(line); };
|
|
1748
|
+
if (!interactive) {
|
|
1749
|
+
console.error(`[rech] this link only works on this machine: listener "${pending.name}" is on ${listenerAddress(pending)} and no proxy is recorded.`);
|
|
1750
|
+
steps();
|
|
1751
|
+
} else {
|
|
1752
|
+
const KEEP = "\0keep";
|
|
1753
|
+
const how = await askReachability(`Link "${pending.name}" only works on this machine (${listenerAddress(pending)}). How will your other machines reach it?`,
|
|
1754
|
+
[{ label: "Nothing: keep it on this machine", value: KEEP }]);
|
|
1755
|
+
if (!how) throw cancelled();
|
|
1756
|
+
if (how === "tailscale-serve") {
|
|
1757
|
+
const routeUrl = await exposeWithTailscaleServe(pending);
|
|
1758
|
+
if (routeUrl) { pending.publicUrl = routeUrl; await writeListeners(config); }
|
|
1759
|
+
} else if (how === "127.0.0.1") steps();
|
|
1760
|
+
else if (how !== KEEP) {
|
|
1761
|
+
// Same key and prefix, now bound on that network; links already handed out change host.
|
|
1762
|
+
pending.host = how;
|
|
1763
|
+
await writeListeners(config);
|
|
1764
|
+
if (!(await waitForListener(pending))) console.error(`[rech] warning: listener "${pending.name}" is not answering on ${listenerAddress(pending)} yet; check the daemon with rech status.`);
|
|
1765
|
+
uri = profileConnectionUri(profile, undefined, config.listeners, pending.name);
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1729
1769
|
const publicUrl = pending?.publicUrl;
|
|
1730
1770
|
if (publicUrl && !opts.local) uri = rebaseConnectionUrl(publicUrl, uri);
|
|
1731
1771
|
console.log(uri);
|