vite-plugin-rpx 0.11.28 → 0.11.29
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/index.js +314 -238
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -22023,8 +22023,14 @@ function generateWildcardPatterns(domain) {
|
|
|
22023
22023
|
const patterns = new Set;
|
|
22024
22024
|
patterns.add(domain);
|
|
22025
22025
|
const parts = domain.split(".");
|
|
22026
|
-
if (parts.length >=
|
|
22027
|
-
|
|
22026
|
+
if (parts.length >= 3) {
|
|
22027
|
+
const tld = parts[parts.length - 1];
|
|
22028
|
+
const sld = parts[parts.length - 2];
|
|
22029
|
+
const secondLevelSuffixes = new Set(["co", "com", "org", "net", "ac", "gov", "edu"]);
|
|
22030
|
+
const baseIsPublicSuffix = parts.length === 3 && tld.length === 2 && secondLevelSuffixes.has(sld);
|
|
22031
|
+
if (!baseIsPublicSuffix)
|
|
22032
|
+
patterns.add(`*.${parts.slice(1).join(".")}`);
|
|
22033
|
+
}
|
|
22028
22034
|
return Array.from(patterns);
|
|
22029
22035
|
}
|
|
22030
22036
|
function generateSSLPaths(options) {
|
|
@@ -22146,7 +22152,15 @@ async function generateCertificate(options) {
|
|
|
22146
22152
|
const scriptPath = join12(sslDir, "trust-rpx-cert.sh");
|
|
22147
22153
|
const scriptContent = `#!/bin/bash
|
|
22148
22154
|
echo "Trusting RPX Root CA"
|
|
22149
|
-
|
|
22155
|
+
# SUDO_PASSWORD (e.g. from a Stacks app's .env) makes the trust step
|
|
22156
|
+
# non-interactive. Without it, fall back to a normal sudo prompt.
|
|
22157
|
+
if [ -n "$SUDO_PASSWORD" ]
|
|
22158
|
+
then
|
|
22159
|
+
printf '%s
|
|
22160
|
+
' "$SUDO_PASSWORD" | sudo -S -p '' security add-trusted-cert ${MACOS_CA_TRUST_FLAGS} -k ${MACOS_SYSTEM_KEYCHAIN} "${rootCAPaths.caCertPath}"
|
|
22161
|
+
else
|
|
22162
|
+
sudo security add-trusted-cert ${MACOS_CA_TRUST_FLAGS} -k ${MACOS_SYSTEM_KEYCHAIN} "${rootCAPaths.caCertPath}"
|
|
22163
|
+
fi
|
|
22150
22164
|
echo "Root CA trusted! Please restart your browser."
|
|
22151
22165
|
echo "If you still see certificate warnings, type 'thisisunsafe' on the warning page in Chrome/Arc browsers."
|
|
22152
22166
|
`;
|
|
@@ -22157,7 +22171,15 @@ echo "If you still see certificate warnings, type 'thisisunsafe' on the warning
|
|
|
22157
22171
|
const scriptPath = join12(sslDir, "trust-rpx-cert.sh");
|
|
22158
22172
|
const scriptContent = `#!/bin/bash
|
|
22159
22173
|
echo "Trusting RPX Root CA"
|
|
22160
|
-
|
|
22174
|
+
# SUDO_PASSWORD (e.g. from a Stacks app's .env) makes the trust step
|
|
22175
|
+
# non-interactive. Without it, fall back to a normal sudo prompt.
|
|
22176
|
+
if [ -n "$SUDO_PASSWORD" ]
|
|
22177
|
+
then
|
|
22178
|
+
printf '%s
|
|
22179
|
+
' "$SUDO_PASSWORD" | sudo -S -p '' security add-trusted-cert ${MACOS_CA_TRUST_FLAGS} -k ${MACOS_SYSTEM_KEYCHAIN} "${rootCAPaths.caCertPath}"
|
|
22180
|
+
else
|
|
22181
|
+
sudo security add-trusted-cert ${MACOS_CA_TRUST_FLAGS} -k ${MACOS_SYSTEM_KEYCHAIN} "${rootCAPaths.caCertPath}"
|
|
22182
|
+
fi
|
|
22161
22183
|
echo "Root CA trusted! Please restart your browser."
|
|
22162
22184
|
echo "If you still see certificate warnings, type 'thisisunsafe' on the warning page in Chrome/Arc browsers."
|
|
22163
22185
|
`;
|
|
@@ -24871,15 +24893,262 @@ var init_site_supervisor = __esm(() => {
|
|
|
24871
24893
|
init_utils();
|
|
24872
24894
|
init_logger();
|
|
24873
24895
|
});
|
|
24896
|
+
// ../rpx/src/hosts.ts
|
|
24897
|
+
import { exec } from "node:child_process";
|
|
24898
|
+
import fs4 from "node:fs";
|
|
24899
|
+
import os2 from "node:os";
|
|
24900
|
+
import path8 from "node:path";
|
|
24901
|
+
import * as process26 from "node:process";
|
|
24902
|
+
import { promisify } from "node:util";
|
|
24903
|
+
function isLoopbackDevelopmentHost(host) {
|
|
24904
|
+
const normalized = host.trim().toLowerCase();
|
|
24905
|
+
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".localhost.");
|
|
24906
|
+
}
|
|
24907
|
+
async function execSudo(command) {
|
|
24908
|
+
if (process26.platform === "win32")
|
|
24909
|
+
throw new Error("Administrator privileges required on Windows");
|
|
24910
|
+
if (isProcessElevated()) {
|
|
24911
|
+
const { stdout } = await execAsync(command);
|
|
24912
|
+
return stdout;
|
|
24913
|
+
}
|
|
24914
|
+
const sudoPassword = getSudoPassword();
|
|
24915
|
+
const escaped = command.replace(/'/g, `'\\''`);
|
|
24916
|
+
try {
|
|
24917
|
+
if (sudoPassword) {
|
|
24918
|
+
const { stdout } = await execAsync(`echo '${sudoPassword}' | sudo -S sh -c '${escaped}' 2>/dev/null`);
|
|
24919
|
+
sudoPrivilegesAcquired = true;
|
|
24920
|
+
return stdout;
|
|
24921
|
+
}
|
|
24922
|
+
if (sudoPrivilegesAcquired) {
|
|
24923
|
+
try {
|
|
24924
|
+
const { stdout } = await execAsync(`sudo -n sh -c '${escaped}'`);
|
|
24925
|
+
return stdout;
|
|
24926
|
+
} catch (error) {
|
|
24927
|
+
debugLog("hosts", "Cached sudo privileges expired, requesting again", true);
|
|
24928
|
+
}
|
|
24929
|
+
}
|
|
24930
|
+
try {
|
|
24931
|
+
const { stdout } = await execAsync(`sudo -n sh -c '${escaped}'`);
|
|
24932
|
+
sudoPrivilegesAcquired = true;
|
|
24933
|
+
return stdout;
|
|
24934
|
+
} catch {
|
|
24935
|
+
throw new Error("sudo required but no cached credentials (set SUDO_PASSWORD in .env or run sudo -v)");
|
|
24936
|
+
}
|
|
24937
|
+
} catch (error) {
|
|
24938
|
+
throw new Error(`Failed to execute sudo command: ${error.message}`);
|
|
24939
|
+
}
|
|
24940
|
+
}
|
|
24941
|
+
function parseHostsLine(line) {
|
|
24942
|
+
const hashIndex = line.indexOf("#");
|
|
24943
|
+
const body = (hashIndex === -1 ? line : line.slice(0, hashIndex)).trim();
|
|
24944
|
+
if (!body)
|
|
24945
|
+
return null;
|
|
24946
|
+
const comment = hashIndex === -1 ? "" : line.slice(hashIndex + 1).trim();
|
|
24947
|
+
const [address, ...names] = body.split(/\s+/);
|
|
24948
|
+
if (!address || names.length === 0)
|
|
24949
|
+
return null;
|
|
24950
|
+
const marker = /^rpx(?::pid=(\d+))?$/.exec(comment);
|
|
24951
|
+
return {
|
|
24952
|
+
address,
|
|
24953
|
+
names,
|
|
24954
|
+
comment,
|
|
24955
|
+
rpxPid: marker?.[1] ? Number.parseInt(marker[1], 10) : null,
|
|
24956
|
+
rpxManaged: marker !== null
|
|
24957
|
+
};
|
|
24958
|
+
}
|
|
24959
|
+
function hostsLineMapsHost(line, host) {
|
|
24960
|
+
const parsed = parseHostsLine(line);
|
|
24961
|
+
return parsed !== null && LOOPBACK_ADDRESSES.has(parsed.address) && parsed.names.includes(host);
|
|
24962
|
+
}
|
|
24963
|
+
function filterRpxHostsEntries(content, hostsToRemove) {
|
|
24964
|
+
const removal = new Set(hostsToRemove);
|
|
24965
|
+
const removed = new Set;
|
|
24966
|
+
const lines = content.split(`
|
|
24967
|
+
`);
|
|
24968
|
+
const out = [];
|
|
24969
|
+
let i2 = 0;
|
|
24970
|
+
while (i2 < lines.length) {
|
|
24971
|
+
const line = lines[i2];
|
|
24972
|
+
if (line.trim() === LEGACY_HOSTS_MARKER) {
|
|
24973
|
+
const block = [];
|
|
24974
|
+
let j2 = i2 + 1;
|
|
24975
|
+
while (j2 < lines.length) {
|
|
24976
|
+
const blockLine = lines[j2];
|
|
24977
|
+
if (blockLine.trim() === "" || blockLine.trim().startsWith("#"))
|
|
24978
|
+
break;
|
|
24979
|
+
block.push(blockLine);
|
|
24980
|
+
j2++;
|
|
24981
|
+
}
|
|
24982
|
+
const kept = block.filter((blockLine) => {
|
|
24983
|
+
const parsed2 = parseHostsLine(blockLine);
|
|
24984
|
+
const hit = parsed2 !== null && LOOPBACK_ADDRESSES.has(parsed2.address) && parsed2.names.some((n2) => removal.has(n2));
|
|
24985
|
+
if (hit) {
|
|
24986
|
+
for (const name of parsed2.names) {
|
|
24987
|
+
if (removal.has(name))
|
|
24988
|
+
removed.add(name);
|
|
24989
|
+
}
|
|
24990
|
+
}
|
|
24991
|
+
return !hit;
|
|
24992
|
+
});
|
|
24993
|
+
if (kept.length > 0 || block.length === 0)
|
|
24994
|
+
out.push(line, ...kept);
|
|
24995
|
+
i2 = j2;
|
|
24996
|
+
continue;
|
|
24997
|
+
}
|
|
24998
|
+
const parsed = parseHostsLine(line);
|
|
24999
|
+
if (parsed?.rpxManaged && LOOPBACK_ADDRESSES.has(parsed.address) && parsed.names.some((n2) => removal.has(n2))) {
|
|
25000
|
+
for (const name of parsed.names) {
|
|
25001
|
+
if (removal.has(name))
|
|
25002
|
+
removed.add(name);
|
|
25003
|
+
}
|
|
25004
|
+
i2++;
|
|
25005
|
+
continue;
|
|
25006
|
+
}
|
|
25007
|
+
out.push(line);
|
|
25008
|
+
i2++;
|
|
25009
|
+
}
|
|
25010
|
+
while (out.length > 0 && out[out.length - 1].trim() === "")
|
|
25011
|
+
out.pop();
|
|
25012
|
+
return { content: `${out.join(`
|
|
25013
|
+
`)}
|
|
25014
|
+
`, removed: [...removed] };
|
|
25015
|
+
}
|
|
25016
|
+
async function readHostsFile(verbose) {
|
|
25017
|
+
try {
|
|
25018
|
+
return await fs4.promises.readFile(hostsFilePath, "utf-8");
|
|
25019
|
+
} catch {
|
|
25020
|
+
debugLog("hosts", "Reading hosts file requires elevated permissions, using sudo", verbose);
|
|
25021
|
+
return execSudo(`cat "${hostsFilePath}"`);
|
|
25022
|
+
}
|
|
25023
|
+
}
|
|
25024
|
+
async function writeHostsFile(content, verbose) {
|
|
25025
|
+
const tmpFile = path8.join(os2.tmpdir(), `rpx-hosts-${Date.now()}.tmp`);
|
|
25026
|
+
try {
|
|
25027
|
+
await fs4.promises.writeFile(tmpFile, content, "utf8");
|
|
25028
|
+
await execSudo(`cat "${tmpFile}" | tee "${hostsFilePath}" > /dev/null`);
|
|
25029
|
+
} finally {
|
|
25030
|
+
await fs4.promises.unlink(tmpFile).catch((err) => {
|
|
25031
|
+
debugLog("hosts", `Failed to remove temporary file: ${err}`, verbose);
|
|
25032
|
+
});
|
|
25033
|
+
}
|
|
25034
|
+
}
|
|
25035
|
+
async function addHosts(hosts, verbose) {
|
|
25036
|
+
const needsHostsFile = hosts.filter((h2) => !isLoopbackDevelopmentHost(h2));
|
|
25037
|
+
const skipped = hosts.filter((h2) => isLoopbackDevelopmentHost(h2));
|
|
25038
|
+
if (skipped.length > 0) {
|
|
25039
|
+
debugLog("hosts", `Skipping /etc/hosts for loopback dev names: ${skipped.join(", ")}`, verbose);
|
|
25040
|
+
}
|
|
25041
|
+
if (needsHostsFile.length === 0)
|
|
25042
|
+
return;
|
|
25043
|
+
debugLog("hosts", `Adding hosts: ${needsHostsFile.join(", ")}`, verbose);
|
|
25044
|
+
debugLog("hosts", `Using hosts file at: ${hostsFilePath}`, verbose);
|
|
25045
|
+
try {
|
|
25046
|
+
let existingContent;
|
|
25047
|
+
try {
|
|
25048
|
+
existingContent = await readHostsFile(verbose);
|
|
25049
|
+
} catch (sudoErr) {
|
|
25050
|
+
console.log(" Could not read hosts file — skipping hosts setup");
|
|
25051
|
+
debugLog("hosts", `sudo read also failed: ${sudoErr}`, verbose);
|
|
25052
|
+
throw new Error(`Cannot read hosts file: ${sudoErr}`);
|
|
25053
|
+
}
|
|
25054
|
+
const existingLines = existingContent.split(`
|
|
25055
|
+
`);
|
|
25056
|
+
const newEntries = needsHostsFile.filter((host) => !existingLines.some((line) => hostsLineMapsHost(line, host)));
|
|
25057
|
+
if (newEntries.length === 0) {
|
|
25058
|
+
debugLog("hosts", "All hosts already exist in hosts file", verbose);
|
|
25059
|
+
return;
|
|
25060
|
+
}
|
|
25061
|
+
const pid3 = process26.pid;
|
|
25062
|
+
const hostEntries = newEntries.map((host) => `
|
|
25063
|
+
127.0.0.1 ${host} ${RPX_HOSTS_MARKER}:pid=${pid3}
|
|
25064
|
+
::1 ${host} ${RPX_HOSTS_MARKER}:pid=${pid3}`).join(`
|
|
25065
|
+
`);
|
|
25066
|
+
try {
|
|
25067
|
+
await writeHostsFile(existingContent + hostEntries, verbose);
|
|
25068
|
+
console.log(` Hosts updated: ${newEntries.join(", ")}`);
|
|
25069
|
+
} catch (error) {
|
|
25070
|
+
console.log(" Could not update hosts file automatically");
|
|
25071
|
+
console.log(" Add these entries to /etc/hosts:");
|
|
25072
|
+
newEntries.forEach((host) => {
|
|
25073
|
+
console.log(` 127.0.0.1 ${host}`);
|
|
25074
|
+
console.log(` ::1 ${host}`);
|
|
25075
|
+
});
|
|
25076
|
+
console.log(` Or run: sudo nano ${hostsFilePath}`);
|
|
25077
|
+
}
|
|
25078
|
+
} catch (err) {
|
|
25079
|
+
const error = err;
|
|
25080
|
+
debugLog("hosts", `Failed to manage hosts file: ${error.message}`, verbose);
|
|
25081
|
+
}
|
|
25082
|
+
}
|
|
25083
|
+
async function removeHosts(hosts, verbose) {
|
|
25084
|
+
debugLog("hosts", `Removing hosts: ${hosts.join(", ")}`, verbose);
|
|
25085
|
+
try {
|
|
25086
|
+
let content;
|
|
25087
|
+
try {
|
|
25088
|
+
content = await readHostsFile(verbose);
|
|
25089
|
+
} catch (sudoErr) {
|
|
25090
|
+
debugLog("hosts", `sudo read also failed: ${sudoErr}`, verbose);
|
|
25091
|
+
throw new Error(`Cannot read hosts file: ${sudoErr}`);
|
|
25092
|
+
}
|
|
25093
|
+
const { content: newContent, removed } = filterRpxHostsEntries(content, hosts);
|
|
25094
|
+
if (removed.length === 0) {
|
|
25095
|
+
debugLog("hosts", "No matching rpx-managed hosts found to remove", verbose);
|
|
25096
|
+
return;
|
|
25097
|
+
}
|
|
25098
|
+
try {
|
|
25099
|
+
await writeHostsFile(newContent, verbose);
|
|
25100
|
+
debugLog("hosts", `Hosts removed successfully: ${removed.join(", ")}`, verbose);
|
|
25101
|
+
} catch (error) {
|
|
25102
|
+
debugLog("hosts", "Could not clean up hosts file automatically", verbose);
|
|
25103
|
+
}
|
|
25104
|
+
} catch (err) {
|
|
25105
|
+
debugLog("hosts", `Failed to clean up hosts file: ${err.message}`, verbose);
|
|
25106
|
+
}
|
|
25107
|
+
}
|
|
25108
|
+
async function checkHosts(hosts, verbose) {
|
|
25109
|
+
debugLog("hosts", `Checking hosts: ${hosts}`, verbose);
|
|
25110
|
+
let content;
|
|
25111
|
+
try {
|
|
25112
|
+
content = await fs4.promises.readFile(hostsFilePath, "utf-8");
|
|
25113
|
+
} catch (readErr) {
|
|
25114
|
+
debugLog("hosts", `Error reading hosts file: ${readErr}`, verbose);
|
|
25115
|
+
try {
|
|
25116
|
+
const sudoPassword = getSudoPassword();
|
|
25117
|
+
let cmd;
|
|
25118
|
+
if (sudoPassword) {
|
|
25119
|
+
cmd = `echo '${sudoPassword}' | sudo -S cat "${hostsFilePath}" 2>/dev/null`;
|
|
25120
|
+
} else {
|
|
25121
|
+
cmd = `sudo -n cat "${hostsFilePath}" 2>/dev/null || cat "${hostsFilePath}" 2>/dev/null || echo ""`;
|
|
25122
|
+
}
|
|
25123
|
+
const { stdout } = await execAsync(cmd);
|
|
25124
|
+
content = stdout;
|
|
25125
|
+
} catch (sudoErr) {
|
|
25126
|
+
debugLog("hosts", `Cannot read hosts file, assuming entries don't exist: ${sudoErr}`, verbose);
|
|
25127
|
+
return hosts.map(() => false);
|
|
25128
|
+
}
|
|
25129
|
+
}
|
|
25130
|
+
const lines = content.split(`
|
|
25131
|
+
`);
|
|
25132
|
+
return hosts.map((host) => lines.some((line) => hostsLineMapsHost(line, host)));
|
|
25133
|
+
}
|
|
25134
|
+
var execAsync, hostsFilePath, RPX_HOSTS_MARKER = "# rpx", LEGACY_HOSTS_MARKER = "# Added by rpx", LOOPBACK_ADDRESSES, sudoPrivilegesAcquired = false;
|
|
25135
|
+
var init_hosts = __esm(() => {
|
|
25136
|
+
init_registry();
|
|
25137
|
+
init_utils();
|
|
25138
|
+
execAsync = promisify(exec);
|
|
25139
|
+
hostsFilePath = process26.platform === "win32" ? path8.join(process26.env.windir || "C:\\Windows", "System32", "drivers", "etc", "hosts") : "/etc/hosts";
|
|
25140
|
+
LOOPBACK_ADDRESSES = new Set(["127.0.0.1", "::1"]);
|
|
25141
|
+
});
|
|
25142
|
+
|
|
24874
25143
|
// ../rpx/src/dns-state.ts
|
|
24875
25144
|
import * as fsp5 from "node:fs/promises";
|
|
24876
25145
|
import { homedir as homedir11 } from "node:os";
|
|
24877
|
-
import * as
|
|
25146
|
+
import * as path9 from "node:path";
|
|
24878
25147
|
function defaultRpxDir() {
|
|
24879
|
-
return
|
|
25148
|
+
return path9.join(homedir11(), ".stacks", "rpx");
|
|
24880
25149
|
}
|
|
24881
25150
|
function getDnsStatePath(rpxDir = defaultRpxDir()) {
|
|
24882
|
-
return
|
|
25151
|
+
return path9.join(rpxDir, RPX_DNS_STATE_FILE);
|
|
24883
25152
|
}
|
|
24884
25153
|
async function loadDnsState(rpxDir = defaultRpxDir()) {
|
|
24885
25154
|
try {
|
|
@@ -24983,8 +25252,8 @@ __export(exports_dns, {
|
|
|
24983
25252
|
});
|
|
24984
25253
|
import dgram from "node:dgram";
|
|
24985
25254
|
import * as fsp6 from "node:fs/promises";
|
|
24986
|
-
import * as
|
|
24987
|
-
import * as
|
|
25255
|
+
import * as path10 from "node:path";
|
|
25256
|
+
import * as process27 from "node:process";
|
|
24988
25257
|
function parseHeader(buffer) {
|
|
24989
25258
|
return {
|
|
24990
25259
|
id: buffer.readUInt16BE(0),
|
|
@@ -25098,7 +25367,7 @@ function buildNxdomainResponse(queryId, question) {
|
|
|
25098
25367
|
return Buffer.concat(parts);
|
|
25099
25368
|
}
|
|
25100
25369
|
async function startDnsServer(domains, verbose) {
|
|
25101
|
-
if (
|
|
25370
|
+
if (process27.platform !== "darwin")
|
|
25102
25371
|
return false;
|
|
25103
25372
|
const devDomains = devDomainsFromHosts(domains);
|
|
25104
25373
|
if (devDomains.length === 0)
|
|
@@ -25218,7 +25487,7 @@ port ${DNS_PORT}
|
|
|
25218
25487
|
`;
|
|
25219
25488
|
}
|
|
25220
25489
|
function resolverFilePath(basename) {
|
|
25221
|
-
return
|
|
25490
|
+
return path10.join(MACOS_RESOLVER_DIR, basename);
|
|
25222
25491
|
}
|
|
25223
25492
|
function contentLooksLikeRpxResolver(content) {
|
|
25224
25493
|
return content.includes("127.0.0.1") && content.includes(String(DNS_PORT));
|
|
@@ -25233,7 +25502,7 @@ async function readResolverFile(basename) {
|
|
|
25233
25502
|
}
|
|
25234
25503
|
}
|
|
25235
25504
|
async function flushDnsCache(verbose) {
|
|
25236
|
-
if (
|
|
25505
|
+
if (process27.platform !== "darwin")
|
|
25237
25506
|
return;
|
|
25238
25507
|
const { execSudoSync: execSudoSync2, getSudoPassword: getSudoPassword2, isProcessElevated: isProcessElevated2 } = await Promise.resolve().then(() => (init_utils(), exports_utils));
|
|
25239
25508
|
if (!isProcessElevated2() && !getSudoPassword2()) {
|
|
@@ -25270,7 +25539,7 @@ async function setupResolver(verbose, domains) {
|
|
|
25270
25539
|
return setupDevelopmentDns({ domains: domains ?? [], verbose });
|
|
25271
25540
|
}
|
|
25272
25541
|
async function installResolvers(basenames, verbose) {
|
|
25273
|
-
if (
|
|
25542
|
+
if (process27.platform !== "darwin")
|
|
25274
25543
|
return true;
|
|
25275
25544
|
const { getSudoPassword: getSudoPassword2, isProcessElevated: isProcessElevated2 } = await Promise.resolve().then(() => (init_utils(), exports_utils));
|
|
25276
25545
|
if (!isProcessElevated2() && !getSudoPassword2()) {
|
|
@@ -25288,7 +25557,7 @@ async function installResolvers(basenames, verbose) {
|
|
|
25288
25557
|
}
|
|
25289
25558
|
}
|
|
25290
25559
|
async function uninstallResolvers(basenames, verbose) {
|
|
25291
|
-
if (
|
|
25560
|
+
if (process27.platform !== "darwin")
|
|
25292
25561
|
return;
|
|
25293
25562
|
const { getSudoPassword: getSudoPassword2, isProcessElevated: isProcessElevated2 } = await Promise.resolve().then(() => (init_utils(), exports_utils));
|
|
25294
25563
|
if (!isProcessElevated2() && !getSudoPassword2())
|
|
@@ -25302,7 +25571,7 @@ async function uninstallResolvers(basenames, verbose) {
|
|
|
25302
25571
|
}
|
|
25303
25572
|
}
|
|
25304
25573
|
async function removeLegacyTldResolvers(verbose) {
|
|
25305
|
-
if (
|
|
25574
|
+
if (process27.platform !== "darwin")
|
|
25306
25575
|
return [];
|
|
25307
25576
|
const removed = [];
|
|
25308
25577
|
for (const label of LEGACY_TLD_RESOLVER_LABELS) {
|
|
@@ -25337,7 +25606,7 @@ async function setupDevelopmentDns(opts) {
|
|
|
25337
25606
|
version: DNS_STATE_VERSION,
|
|
25338
25607
|
resolvers: basenames,
|
|
25339
25608
|
domains,
|
|
25340
|
-
ownerPid: opts.ownerPid ??
|
|
25609
|
+
ownerPid: opts.ownerPid ?? process27.pid,
|
|
25341
25610
|
updatedAt: new Date().toISOString()
|
|
25342
25611
|
};
|
|
25343
25612
|
await saveDnsState(rpxDir, state);
|
|
@@ -25361,7 +25630,7 @@ async function syncDevelopmentDnsFromRegistry(entries, opts = {}) {
|
|
|
25361
25630
|
domains,
|
|
25362
25631
|
rpxDir,
|
|
25363
25632
|
verbose: opts.verbose,
|
|
25364
|
-
ownerPid: opts.ownerPid ??
|
|
25633
|
+
ownerPid: opts.ownerPid ?? process27.pid
|
|
25365
25634
|
});
|
|
25366
25635
|
}
|
|
25367
25636
|
async function tearDownDevelopmentDns(opts = {}) {
|
|
@@ -25403,13 +25672,13 @@ var init_dns = __esm(() => {
|
|
|
25403
25672
|
import { spawn as nodeSpawn } from "node:child_process";
|
|
25404
25673
|
import * as fsp7 from "node:fs/promises";
|
|
25405
25674
|
import { homedir as homedir12 } from "node:os";
|
|
25406
|
-
import * as
|
|
25407
|
-
import * as
|
|
25675
|
+
import * as path11 from "node:path";
|
|
25676
|
+
import * as process28 from "node:process";
|
|
25408
25677
|
function getDaemonRpxDir() {
|
|
25409
|
-
return
|
|
25678
|
+
return path11.join(homedir12(), ".stacks", "rpx");
|
|
25410
25679
|
}
|
|
25411
25680
|
function getDaemonPidPath(rpxDir = getDaemonRpxDir()) {
|
|
25412
|
-
return
|
|
25681
|
+
return path11.join(rpxDir, "daemon.pid");
|
|
25413
25682
|
}
|
|
25414
25683
|
async function readDaemonPid(rpxDir = getDaemonRpxDir()) {
|
|
25415
25684
|
try {
|
|
@@ -25428,12 +25697,12 @@ async function releaseDaemonLock(rpxDir = getDaemonRpxDir()) {
|
|
|
25428
25697
|
await fsp7.unlink(getDaemonPidPath(rpxDir)).catch(() => {});
|
|
25429
25698
|
}
|
|
25430
25699
|
function defaultDaemonSpawnCommand() {
|
|
25431
|
-
const
|
|
25432
|
-
const interpName =
|
|
25700
|
+
const exec2 = process28.execPath;
|
|
25701
|
+
const interpName = path11.basename(exec2).toLowerCase();
|
|
25433
25702
|
const isInterpreter = interpName === "bun" || interpName === "node" || interpName.startsWith("bun-");
|
|
25434
|
-
if (isInterpreter &&
|
|
25435
|
-
return [
|
|
25436
|
-
return [
|
|
25703
|
+
if (isInterpreter && process28.argv[1])
|
|
25704
|
+
return [exec2, process28.argv[1], "daemon:start"];
|
|
25705
|
+
return [exec2, "daemon:start"];
|
|
25437
25706
|
}
|
|
25438
25707
|
async function ensureDaemonRunning(opts = {}) {
|
|
25439
25708
|
const rpxDir = opts.rpxDir ?? getDaemonRpxDir();
|
|
@@ -25458,8 +25727,8 @@ async function ensureDaemonRunning(opts = {}) {
|
|
|
25458
25727
|
const child = nodeSpawn(command[0], command.slice(1), {
|
|
25459
25728
|
detached: true,
|
|
25460
25729
|
stdio: "ignore",
|
|
25461
|
-
cwd: opts.spawnCwd ??
|
|
25462
|
-
env: opts.spawnEnv ? { ...
|
|
25730
|
+
cwd: opts.spawnCwd ?? process28.cwd(),
|
|
25731
|
+
env: opts.spawnEnv ? { ...process28.env, ...opts.spawnEnv } : process28.env
|
|
25463
25732
|
});
|
|
25464
25733
|
child.unref();
|
|
25465
25734
|
let spawnError = null;
|
|
@@ -25472,10 +25741,10 @@ async function ensureDaemonRunning(opts = {}) {
|
|
|
25472
25741
|
while (Date.now() < deadline) {
|
|
25473
25742
|
if (spawnError)
|
|
25474
25743
|
throw spawnError;
|
|
25475
|
-
const
|
|
25476
|
-
if (
|
|
25477
|
-
debugLog("daemon", `daemon registered with pid=${
|
|
25478
|
-
return { pid:
|
|
25744
|
+
const pid5 = await readDaemonPid(rpxDir);
|
|
25745
|
+
if (pid5 !== null && isPidAlive(pid5)) {
|
|
25746
|
+
debugLog("daemon", `daemon registered with pid=${pid5}`, verbose);
|
|
25747
|
+
return { pid: pid5, spawned: true };
|
|
25479
25748
|
}
|
|
25480
25749
|
await new Promise((resolve14) => setTimeout(resolve14, pollMs));
|
|
25481
25750
|
}
|
|
@@ -25497,6 +25766,7 @@ var init_daemon = __esm(() => {
|
|
|
25497
25766
|
init_static_files();
|
|
25498
25767
|
init_auth();
|
|
25499
25768
|
init_registry();
|
|
25769
|
+
init_hosts();
|
|
25500
25770
|
init_dns();
|
|
25501
25771
|
init_utils();
|
|
25502
25772
|
registryUpstreamPools = new Map;
|
|
@@ -25531,9 +25801,9 @@ init_daemon();
|
|
|
25531
25801
|
init_logger();
|
|
25532
25802
|
init_registry();
|
|
25533
25803
|
init_utils();
|
|
25534
|
-
import * as
|
|
25535
|
-
import * as
|
|
25536
|
-
import * as
|
|
25804
|
+
import * as fs5 from "node:fs";
|
|
25805
|
+
import * as path12 from "node:path";
|
|
25806
|
+
import * as process29 from "node:process";
|
|
25537
25807
|
function deriveIdFromTarget(to, routePath) {
|
|
25538
25808
|
const base = routePath && routePath !== "/" ? `${to}${routePath}` : to;
|
|
25539
25809
|
const cleaned = base.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 128);
|
|
@@ -25561,8 +25831,8 @@ async function runViaDaemon(opts) {
|
|
|
25561
25831
|
from: p2.from,
|
|
25562
25832
|
to: p2.to,
|
|
25563
25833
|
path: p2.path,
|
|
25564
|
-
pid: opts.persistent ? undefined :
|
|
25565
|
-
cwd:
|
|
25834
|
+
pid: opts.persistent ? undefined : process29.pid,
|
|
25835
|
+
cwd: process29.cwd(),
|
|
25566
25836
|
createdAt,
|
|
25567
25837
|
cleanUrls: p2.cleanUrls,
|
|
25568
25838
|
changeOrigin: p2.changeOrigin,
|
|
@@ -25600,219 +25870,24 @@ async function runViaDaemon(opts) {
|
|
|
25600
25870
|
};
|
|
25601
25871
|
const onSignal = (sig) => {
|
|
25602
25872
|
debugLog("runner", `received ${sig}, unregistering ${idsForCleanup.length} entries`, verbose);
|
|
25603
|
-
cleanup().finally(() =>
|
|
25873
|
+
cleanup().finally(() => process29.exit(0));
|
|
25604
25874
|
};
|
|
25605
|
-
|
|
25606
|
-
|
|
25607
|
-
|
|
25875
|
+
process29.once("SIGINT", onSignal);
|
|
25876
|
+
process29.once("SIGTERM", onSignal);
|
|
25877
|
+
process29.once("exit", () => {
|
|
25608
25878
|
if (cleaned)
|
|
25609
25879
|
return;
|
|
25610
25880
|
for (const id of idsForCleanup) {
|
|
25611
25881
|
try {
|
|
25612
|
-
|
|
25882
|
+
fs5.unlinkSync(path12.join(dirForCleanup, `${id}.json`));
|
|
25613
25883
|
} catch {}
|
|
25614
25884
|
}
|
|
25615
25885
|
});
|
|
25616
25886
|
await new Promise(() => {});
|
|
25617
25887
|
}
|
|
25618
25888
|
|
|
25619
|
-
// ../rpx/src/hosts.ts
|
|
25620
|
-
init_utils();
|
|
25621
|
-
import { exec } from "node:child_process";
|
|
25622
|
-
import fs5 from "node:fs";
|
|
25623
|
-
import os2 from "node:os";
|
|
25624
|
-
import path12 from "node:path";
|
|
25625
|
-
import * as process29 from "node:process";
|
|
25626
|
-
import { promisify } from "node:util";
|
|
25627
|
-
var execAsync = promisify(exec);
|
|
25628
|
-
function isLoopbackDevelopmentHost(host) {
|
|
25629
|
-
const normalized = host.trim().toLowerCase();
|
|
25630
|
-
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".localhost.");
|
|
25631
|
-
}
|
|
25632
|
-
var hostsFilePath = process29.platform === "win32" ? path12.join(process29.env.windir || "C:\\Windows", "System32", "drivers", "etc", "hosts") : "/etc/hosts";
|
|
25633
|
-
var sudoPrivilegesAcquired = false;
|
|
25634
|
-
async function execSudo(command) {
|
|
25635
|
-
if (process29.platform === "win32")
|
|
25636
|
-
throw new Error("Administrator privileges required on Windows");
|
|
25637
|
-
if (isProcessElevated()) {
|
|
25638
|
-
const { stdout } = await execAsync(command);
|
|
25639
|
-
return stdout;
|
|
25640
|
-
}
|
|
25641
|
-
const sudoPassword = getSudoPassword();
|
|
25642
|
-
const escaped = command.replace(/'/g, `'\\''`);
|
|
25643
|
-
try {
|
|
25644
|
-
if (sudoPassword) {
|
|
25645
|
-
const { stdout } = await execAsync(`echo '${sudoPassword}' | sudo -S sh -c '${escaped}' 2>/dev/null`);
|
|
25646
|
-
sudoPrivilegesAcquired = true;
|
|
25647
|
-
return stdout;
|
|
25648
|
-
}
|
|
25649
|
-
if (sudoPrivilegesAcquired) {
|
|
25650
|
-
try {
|
|
25651
|
-
const { stdout } = await execAsync(`sudo -n sh -c '${escaped}'`);
|
|
25652
|
-
return stdout;
|
|
25653
|
-
} catch (error) {
|
|
25654
|
-
debugLog("hosts", "Cached sudo privileges expired, requesting again", true);
|
|
25655
|
-
}
|
|
25656
|
-
}
|
|
25657
|
-
try {
|
|
25658
|
-
const { stdout } = await execAsync(`sudo -n sh -c '${escaped}'`);
|
|
25659
|
-
sudoPrivilegesAcquired = true;
|
|
25660
|
-
return stdout;
|
|
25661
|
-
} catch {
|
|
25662
|
-
throw new Error("sudo required but no cached credentials (set SUDO_PASSWORD in .env or run sudo -v)");
|
|
25663
|
-
}
|
|
25664
|
-
} catch (error) {
|
|
25665
|
-
throw new Error(`Failed to execute sudo command: ${error.message}`);
|
|
25666
|
-
}
|
|
25667
|
-
}
|
|
25668
|
-
async function addHosts(hosts, verbose) {
|
|
25669
|
-
const needsHostsFile = hosts.filter((h2) => !isLoopbackDevelopmentHost(h2));
|
|
25670
|
-
const skipped = hosts.filter((h2) => isLoopbackDevelopmentHost(h2));
|
|
25671
|
-
if (skipped.length > 0) {
|
|
25672
|
-
debugLog("hosts", `Skipping /etc/hosts for loopback dev names: ${skipped.join(", ")}`, verbose);
|
|
25673
|
-
}
|
|
25674
|
-
if (needsHostsFile.length === 0)
|
|
25675
|
-
return;
|
|
25676
|
-
debugLog("hosts", `Adding hosts: ${needsHostsFile.join(", ")}`, verbose);
|
|
25677
|
-
debugLog("hosts", `Using hosts file at: ${hostsFilePath}`, verbose);
|
|
25678
|
-
try {
|
|
25679
|
-
let existingContent;
|
|
25680
|
-
try {
|
|
25681
|
-
existingContent = await fs5.promises.readFile(hostsFilePath, "utf-8");
|
|
25682
|
-
} catch {
|
|
25683
|
-
debugLog("hosts", "Reading hosts file requires elevated permissions, using sudo", verbose);
|
|
25684
|
-
try {
|
|
25685
|
-
existingContent = await execSudo(`cat "${hostsFilePath}"`);
|
|
25686
|
-
} catch (sudoErr) {
|
|
25687
|
-
console.log(" Could not read hosts file — skipping hosts setup");
|
|
25688
|
-
debugLog("hosts", `sudo read also failed: ${sudoErr}`, verbose);
|
|
25689
|
-
throw new Error(`Cannot read hosts file: ${sudoErr}`);
|
|
25690
|
-
}
|
|
25691
|
-
}
|
|
25692
|
-
const newEntries = needsHostsFile.filter((host) => {
|
|
25693
|
-
const ipv4Entry = `127.0.0.1 ${host}`;
|
|
25694
|
-
const ipv6Entry = `::1 ${host}`;
|
|
25695
|
-
return !existingContent.includes(ipv4Entry) && !existingContent.includes(ipv6Entry);
|
|
25696
|
-
});
|
|
25697
|
-
if (newEntries.length === 0) {
|
|
25698
|
-
debugLog("hosts", "All hosts already exist in hosts file", verbose);
|
|
25699
|
-
return;
|
|
25700
|
-
}
|
|
25701
|
-
const hostEntries = newEntries.map((host) => `
|
|
25702
|
-
# Added by rpx
|
|
25703
|
-
127.0.0.1 ${host}
|
|
25704
|
-
::1 ${host}`).join(`
|
|
25705
|
-
`);
|
|
25706
|
-
const tmpFile = path12.join(os2.tmpdir(), `rpx-hosts-${Date.now()}.tmp`);
|
|
25707
|
-
try {
|
|
25708
|
-
await fs5.promises.writeFile(tmpFile, existingContent + hostEntries, "utf8");
|
|
25709
|
-
await execSudo(`cat "${tmpFile}" | tee "${hostsFilePath}" > /dev/null`);
|
|
25710
|
-
console.log(` Hosts updated: ${newEntries.join(", ")}`);
|
|
25711
|
-
} catch (error) {
|
|
25712
|
-
console.log(" Could not update hosts file automatically");
|
|
25713
|
-
console.log(" Add these entries to /etc/hosts:");
|
|
25714
|
-
newEntries.forEach((host) => {
|
|
25715
|
-
console.log(` 127.0.0.1 ${host}`);
|
|
25716
|
-
console.log(` ::1 ${host}`);
|
|
25717
|
-
});
|
|
25718
|
-
console.log(` Or run: sudo nano ${hostsFilePath}`);
|
|
25719
|
-
} finally {
|
|
25720
|
-
try {
|
|
25721
|
-
await fs5.promises.unlink(tmpFile);
|
|
25722
|
-
} catch {}
|
|
25723
|
-
}
|
|
25724
|
-
} catch (err) {
|
|
25725
|
-
const error = err;
|
|
25726
|
-
debugLog("hosts", `Failed to manage hosts file: ${error.message}`, verbose);
|
|
25727
|
-
}
|
|
25728
|
-
}
|
|
25729
|
-
async function removeHosts(hosts, verbose) {
|
|
25730
|
-
debugLog("hosts", `Removing hosts: ${hosts.join(", ")}`, verbose);
|
|
25731
|
-
try {
|
|
25732
|
-
let content;
|
|
25733
|
-
try {
|
|
25734
|
-
content = await fs5.promises.readFile(hostsFilePath, "utf-8");
|
|
25735
|
-
} catch {
|
|
25736
|
-
debugLog("hosts", "Reading hosts file requires elevated permissions, using sudo", verbose);
|
|
25737
|
-
try {
|
|
25738
|
-
content = await execSudo(`cat "${hostsFilePath}"`);
|
|
25739
|
-
} catch (sudoErr) {
|
|
25740
|
-
debugLog("hosts", `sudo read also failed: ${sudoErr}`, verbose);
|
|
25741
|
-
throw new Error(`Cannot read hosts file: ${sudoErr}`);
|
|
25742
|
-
}
|
|
25743
|
-
}
|
|
25744
|
-
const lines = content.split(`
|
|
25745
|
-
`);
|
|
25746
|
-
let modified = false;
|
|
25747
|
-
const filteredLines = lines.filter((line) => {
|
|
25748
|
-
const isHostLine = hosts.some((host) => line.includes(` ${host}`) && (line.includes("127.0.0.1") || line.includes("::1")));
|
|
25749
|
-
if (isHostLine) {
|
|
25750
|
-
modified = true;
|
|
25751
|
-
return false;
|
|
25752
|
-
}
|
|
25753
|
-
if (line.trim() === "# Added by rpx") {
|
|
25754
|
-
modified = true;
|
|
25755
|
-
return false;
|
|
25756
|
-
}
|
|
25757
|
-
return true;
|
|
25758
|
-
});
|
|
25759
|
-
if (!modified) {
|
|
25760
|
-
debugLog("hosts", "No matching hosts found to remove", verbose);
|
|
25761
|
-
return;
|
|
25762
|
-
}
|
|
25763
|
-
while (filteredLines[filteredLines.length - 1]?.trim() === "")
|
|
25764
|
-
filteredLines.pop();
|
|
25765
|
-
const newContent = `${filteredLines.join(`
|
|
25766
|
-
`)}
|
|
25767
|
-
`;
|
|
25768
|
-
const tmpFile = path12.join(os2.tmpdir(), `rpx-hosts-${Date.now()}.tmp`);
|
|
25769
|
-
try {
|
|
25770
|
-
await fs5.promises.writeFile(tmpFile, newContent, "utf8");
|
|
25771
|
-
await execSudo(`cat "${tmpFile}" | tee "${hostsFilePath}" > /dev/null`);
|
|
25772
|
-
debugLog("hosts", "Hosts removed successfully", verbose);
|
|
25773
|
-
} catch (error) {
|
|
25774
|
-
debugLog("hosts", "Could not clean up hosts file automatically", verbose);
|
|
25775
|
-
} finally {
|
|
25776
|
-
try {
|
|
25777
|
-
await fs5.promises.unlink(tmpFile);
|
|
25778
|
-
} catch (unlinkErr) {
|
|
25779
|
-
debugLog("hosts", `Failed to remove temporary file: ${unlinkErr}`, verbose);
|
|
25780
|
-
}
|
|
25781
|
-
}
|
|
25782
|
-
} catch (err) {
|
|
25783
|
-
debugLog("hosts", `Failed to clean up hosts file: ${err.message}`, verbose);
|
|
25784
|
-
}
|
|
25785
|
-
}
|
|
25786
|
-
async function checkHosts(hosts, verbose) {
|
|
25787
|
-
debugLog("hosts", `Checking hosts: ${hosts}`, verbose);
|
|
25788
|
-
let content;
|
|
25789
|
-
try {
|
|
25790
|
-
content = await fs5.promises.readFile(hostsFilePath, "utf-8");
|
|
25791
|
-
} catch (readErr) {
|
|
25792
|
-
debugLog("hosts", `Error reading hosts file: ${readErr}`, verbose);
|
|
25793
|
-
try {
|
|
25794
|
-
const sudoPassword = getSudoPassword();
|
|
25795
|
-
let cmd;
|
|
25796
|
-
if (sudoPassword) {
|
|
25797
|
-
cmd = `echo '${sudoPassword}' | sudo -S cat "${hostsFilePath}" 2>/dev/null`;
|
|
25798
|
-
} else {
|
|
25799
|
-
cmd = `sudo -n cat "${hostsFilePath}" 2>/dev/null || cat "${hostsFilePath}" 2>/dev/null || echo ""`;
|
|
25800
|
-
}
|
|
25801
|
-
const { stdout } = await execAsync(cmd);
|
|
25802
|
-
content = stdout;
|
|
25803
|
-
} catch (sudoErr) {
|
|
25804
|
-
debugLog("hosts", `Cannot read hosts file, assuming entries don't exist: ${sudoErr}`, verbose);
|
|
25805
|
-
return hosts.map(() => false);
|
|
25806
|
-
}
|
|
25807
|
-
}
|
|
25808
|
-
return hosts.map((host) => {
|
|
25809
|
-
const ipv4Entry = `127.0.0.1 ${host}`;
|
|
25810
|
-
const ipv6Entry = `::1 ${host}`;
|
|
25811
|
-
return content.includes(ipv4Entry) || content.includes(ipv6Entry);
|
|
25812
|
-
});
|
|
25813
|
-
}
|
|
25814
|
-
|
|
25815
25889
|
// ../rpx/src/start.ts
|
|
25890
|
+
init_hosts();
|
|
25816
25891
|
init_https();
|
|
25817
25892
|
init_port_manager();
|
|
25818
25893
|
|
|
@@ -26846,6 +26921,7 @@ function logToConsole(options) {
|
|
|
26846
26921
|
|
|
26847
26922
|
// ../rpx/src/index.ts
|
|
26848
26923
|
init_config();
|
|
26924
|
+
init_hosts();
|
|
26849
26925
|
init_https();
|
|
26850
26926
|
init_macos_trust();
|
|
26851
26927
|
init_cert_inspect();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-rpx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.11.
|
|
4
|
+
"version": "0.11.29",
|
|
5
5
|
"description": "A modern and smart reverse proxy. Vite plugin.",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.org>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"typecheck": "bunx tsc --noEmit"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@stacksjs/rpx": "0.11.
|
|
50
|
+
"@stacksjs/rpx": "0.11.29",
|
|
51
51
|
"@stacksjs/tlsx": "^0.13.9"
|
|
52
52
|
},
|
|
53
53
|
"simple-git-hooks": {
|