@stacksjs/rpx 0.5.0 → 0.6.0
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 +120 -107
- package/dist/hosts.d.ts +2 -1
- package/dist/https.d.ts +0 -4
- package/dist/index.js +366 -352
- package/dist/start.d.ts +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/utils.d.ts +6 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20467,7 +20467,7 @@ var quotes = collect([
|
|
|
20467
20467
|
]);
|
|
20468
20468
|
var export_prompts = import_prompts.default;
|
|
20469
20469
|
// package.json
|
|
20470
|
-
var version = "0.
|
|
20470
|
+
var version = "0.6.0";
|
|
20471
20471
|
|
|
20472
20472
|
// src/config.ts
|
|
20473
20473
|
import { homedir } from "os";
|
|
@@ -20526,6 +20526,7 @@ async function loadConfig({ name, cwd, defaultConfig }) {
|
|
|
20526
20526
|
var defaultConfig = {
|
|
20527
20527
|
from: "localhost:5173",
|
|
20528
20528
|
to: "stacks.localhost",
|
|
20529
|
+
cleanUrls: false,
|
|
20529
20530
|
https: {
|
|
20530
20531
|
basePath: "",
|
|
20531
20532
|
caCertPath: join2(homedir(), ".stacks", "ssl", `stacks.localhost.ca.crt`),
|
|
@@ -20541,14 +20542,179 @@ var config4 = await loadConfig({
|
|
|
20541
20542
|
});
|
|
20542
20543
|
|
|
20543
20544
|
// src/hosts.ts
|
|
20544
|
-
import {
|
|
20545
|
-
import
|
|
20546
|
-
import
|
|
20547
|
-
import
|
|
20545
|
+
import { exec } from "child_process";
|
|
20546
|
+
import fs from "fs";
|
|
20547
|
+
import os2 from "os";
|
|
20548
|
+
import path from "path";
|
|
20548
20549
|
import process3 from "process";
|
|
20550
|
+
import { promisify } from "util";
|
|
20551
|
+
|
|
20552
|
+
// src/utils.ts
|
|
20553
|
+
function debugLog(category, message, verbose) {
|
|
20554
|
+
if (verbose) {
|
|
20555
|
+
console.debug(`[rpx:${category}] ${message}`);
|
|
20556
|
+
}
|
|
20557
|
+
}
|
|
20558
|
+
function extractHostname(options2) {
|
|
20559
|
+
if (isMultiProxyOptions(options2)) {
|
|
20560
|
+
return options2.proxies.map((proxy) => {
|
|
20561
|
+
const domain = proxy.to || "stacks.localhost";
|
|
20562
|
+
return domain.startsWith("http") ? new URL(domain).hostname : domain;
|
|
20563
|
+
});
|
|
20564
|
+
}
|
|
20565
|
+
if (isSingleProxyOptions(options2)) {
|
|
20566
|
+
const domain = options2.to || "stacks.localhost";
|
|
20567
|
+
return [domain.startsWith("http") ? new URL(domain).hostname : domain];
|
|
20568
|
+
}
|
|
20569
|
+
return ["stacks.localhost"];
|
|
20570
|
+
}
|
|
20571
|
+
function isValidRootCA(value) {
|
|
20572
|
+
return typeof value === "object" && value !== null && "certificate" in value && "privateKey" in value && typeof value.certificate === "string" && typeof value.privateKey === "string";
|
|
20573
|
+
}
|
|
20574
|
+
function getPrimaryDomain(options2) {
|
|
20575
|
+
if (!options2)
|
|
20576
|
+
return "stacks.localhost";
|
|
20577
|
+
if (isMultiProxyOptions(options2) && options2.proxies.length > 0)
|
|
20578
|
+
return options2.proxies[0].to || "stacks.localhost";
|
|
20579
|
+
if (isSingleProxyOptions(options2))
|
|
20580
|
+
return options2.to || "stacks.localhost";
|
|
20581
|
+
return "stacks.localhost";
|
|
20582
|
+
}
|
|
20583
|
+
function isMultiProxyConfig(options2) {
|
|
20584
|
+
return "proxies" in options2 && Array.isArray(options2.proxies);
|
|
20585
|
+
}
|
|
20586
|
+
function isMultiProxyOptions(options2) {
|
|
20587
|
+
return "proxies" in options2 && Array.isArray(options2.proxies);
|
|
20588
|
+
}
|
|
20589
|
+
function isSingleProxyOptions(options2) {
|
|
20590
|
+
return "to" in options2 && typeof options2.to === "string";
|
|
20591
|
+
}
|
|
20592
|
+
|
|
20593
|
+
// src/hosts.ts
|
|
20594
|
+
var execAsync = promisify(exec);
|
|
20595
|
+
var hostsFilePath = process3.platform === "win32" ? path.join(process3.env.windir || "C:\\Windows", "System32", "drivers", "etc", "hosts") : "/etc/hosts";
|
|
20596
|
+
async function execSudo(command) {
|
|
20597
|
+
if (process3.platform === "win32")
|
|
20598
|
+
throw new Error("Administrator privileges required on Windows");
|
|
20599
|
+
try {
|
|
20600
|
+
await execAsync(`sudo ${command}`);
|
|
20601
|
+
} catch (error) {
|
|
20602
|
+
throw new Error(`Failed to execute sudo command: ${error.message}`);
|
|
20603
|
+
}
|
|
20604
|
+
}
|
|
20605
|
+
async function addHosts(hosts, verbose) {
|
|
20606
|
+
debugLog("hosts", `Adding hosts: ${hosts.join(", ")}`, verbose);
|
|
20607
|
+
debugLog("hosts", `Using hosts file at: ${hostsFilePath}`, verbose);
|
|
20608
|
+
try {
|
|
20609
|
+
const existingContent = await fs.promises.readFile(hostsFilePath, "utf-8");
|
|
20610
|
+
const newEntries = hosts.filter((host) => {
|
|
20611
|
+
const ipv4Entry = `127.0.0.1 ${host}`;
|
|
20612
|
+
const ipv6Entry = `::1 ${host}`;
|
|
20613
|
+
return !existingContent.includes(ipv4Entry) && !existingContent.includes(ipv6Entry);
|
|
20614
|
+
});
|
|
20615
|
+
if (newEntries.length === 0) {
|
|
20616
|
+
debugLog("hosts", "All hosts already exist in hosts file", verbose);
|
|
20617
|
+
log.info("All hosts are already in the hosts file");
|
|
20618
|
+
return;
|
|
20619
|
+
}
|
|
20620
|
+
const hostEntries = newEntries.map((host) => `
|
|
20621
|
+
# Added by rpx
|
|
20622
|
+
127.0.0.1 ${host}
|
|
20623
|
+
::1 ${host}`).join(`
|
|
20624
|
+
`);
|
|
20625
|
+
const tmpFile = path.join(os2.tmpdir(), "hosts.tmp");
|
|
20626
|
+
await fs.promises.writeFile(tmpFile, existingContent + hostEntries, "utf8");
|
|
20627
|
+
try {
|
|
20628
|
+
await execSudo(`cp "${tmpFile}" "${hostsFilePath}"`);
|
|
20629
|
+
log.success(`Added new hosts: ${newEntries.join(", ")}`);
|
|
20630
|
+
} catch (error) {
|
|
20631
|
+
log.error("Failed to modify hosts file automatically");
|
|
20632
|
+
log.warn("Please add these entries to your hosts file manually:");
|
|
20633
|
+
hostEntries.split(`
|
|
20634
|
+
`).forEach((entry) => log.warn(entry));
|
|
20635
|
+
if (process3.platform === "win32") {
|
|
20636
|
+
log.warn(`
|
|
20637
|
+
On Windows:`);
|
|
20638
|
+
log.warn("1. Run notepad as administrator");
|
|
20639
|
+
log.warn("2. Open C:\\Windows\\System32\\drivers\\etc\\hosts");
|
|
20640
|
+
} else {
|
|
20641
|
+
log.warn(`
|
|
20642
|
+
On Unix systems:`);
|
|
20643
|
+
log.warn(`sudo nano ${hostsFilePath}`);
|
|
20644
|
+
}
|
|
20645
|
+
throw new Error("Failed to modify hosts file: manual intervention required");
|
|
20646
|
+
} finally {
|
|
20647
|
+
fs.unlinkSync(tmpFile);
|
|
20648
|
+
}
|
|
20649
|
+
} catch (err2) {
|
|
20650
|
+
const error = err2;
|
|
20651
|
+
log.error(`Failed to manage hosts file: ${error.message}`);
|
|
20652
|
+
throw error;
|
|
20653
|
+
}
|
|
20654
|
+
}
|
|
20655
|
+
async function removeHosts(hosts, verbose) {
|
|
20656
|
+
debugLog("hosts", `Removing hosts: ${hosts.join(", ")}`, verbose);
|
|
20657
|
+
try {
|
|
20658
|
+
const content = await fs.promises.readFile(hostsFilePath, "utf-8");
|
|
20659
|
+
const lines = content.split(`
|
|
20660
|
+
`);
|
|
20661
|
+
const filteredLines = lines.filter((line, index) => {
|
|
20662
|
+
if (line.trim() === "# Added by rpx") {
|
|
20663
|
+
lines.splice(index + 1, 2);
|
|
20664
|
+
return false;
|
|
20665
|
+
}
|
|
20666
|
+
return true;
|
|
20667
|
+
});
|
|
20668
|
+
while (filteredLines[filteredLines.length - 1]?.trim() === "")
|
|
20669
|
+
filteredLines.pop();
|
|
20670
|
+
const newContent = `${filteredLines.join(`
|
|
20671
|
+
`)}
|
|
20672
|
+
`;
|
|
20673
|
+
const tmpFile = path.join(os2.tmpdir(), "hosts.tmp");
|
|
20674
|
+
await fs.promises.writeFile(tmpFile, newContent, "utf8");
|
|
20675
|
+
try {
|
|
20676
|
+
await execSudo(`cp "${tmpFile}" "${hostsFilePath}"`);
|
|
20677
|
+
log.success("Hosts removed successfully");
|
|
20678
|
+
} catch (error) {
|
|
20679
|
+
log.error("Failed to modify hosts file automatically");
|
|
20680
|
+
log.warn("Please remove these entries from your hosts file manually:");
|
|
20681
|
+
hosts.forEach((host) => {
|
|
20682
|
+
log.warn("# Added by rpx");
|
|
20683
|
+
log.warn(`127.0.0.1 ${host}`);
|
|
20684
|
+
log.warn(`::1 ${host}`);
|
|
20685
|
+
});
|
|
20686
|
+
if (process3.platform === "win32") {
|
|
20687
|
+
log.warn(`
|
|
20688
|
+
On Windows:`);
|
|
20689
|
+
log.warn("1. Run notepad as administrator");
|
|
20690
|
+
log.warn("2. Open C:\\Windows\\System32\\drivers\\etc\\hosts");
|
|
20691
|
+
} else {
|
|
20692
|
+
log.warn(`
|
|
20693
|
+
On Unix systems:`);
|
|
20694
|
+
log.warn(`sudo nano ${hostsFilePath}`);
|
|
20695
|
+
}
|
|
20696
|
+
throw new Error("Failed to modify hosts file: manual intervention required");
|
|
20697
|
+
} finally {
|
|
20698
|
+
fs.unlinkSync(tmpFile);
|
|
20699
|
+
}
|
|
20700
|
+
} catch (err2) {
|
|
20701
|
+
const error = err2;
|
|
20702
|
+
log.error(`Failed to remove hosts: ${error.message}`);
|
|
20703
|
+
throw error;
|
|
20704
|
+
}
|
|
20705
|
+
}
|
|
20706
|
+
async function checkHosts(hosts, verbose) {
|
|
20707
|
+
debugLog("hosts", `Checking hosts: ${hosts}`, verbose);
|
|
20708
|
+
const content = await fs.promises.readFile(hostsFilePath, "utf-8");
|
|
20709
|
+
return hosts.map((host) => {
|
|
20710
|
+
const ipv4Entry = `127.0.0.1 ${host}`;
|
|
20711
|
+
const ipv6Entry = `::1 ${host}`;
|
|
20712
|
+
return content.includes(ipv4Entry) || content.includes(ipv6Entry);
|
|
20713
|
+
});
|
|
20714
|
+
}
|
|
20549
20715
|
|
|
20550
20716
|
// src/https.ts
|
|
20551
|
-
import
|
|
20717
|
+
import fs5 from "fs/promises";
|
|
20552
20718
|
import { homedir as homedir2 } from "os";
|
|
20553
20719
|
import { join as join4 } from "path";
|
|
20554
20720
|
|
|
@@ -20589,7 +20755,7 @@ import process8 from "process";
|
|
|
20589
20755
|
import process102 from "process";
|
|
20590
20756
|
import process182 from "process";
|
|
20591
20757
|
import process112 from "process";
|
|
20592
|
-
import
|
|
20758
|
+
import os3 from "os";
|
|
20593
20759
|
import tty32 from "tty";
|
|
20594
20760
|
import process142 from "process";
|
|
20595
20761
|
import process132 from "process";
|
|
@@ -20598,11 +20764,11 @@ import process162 from "process";
|
|
|
20598
20764
|
import process172 from "process";
|
|
20599
20765
|
import process192 from "process";
|
|
20600
20766
|
import os22 from "os";
|
|
20601
|
-
import
|
|
20767
|
+
import path2 from "path";
|
|
20602
20768
|
import { resolve as resolve3 } from "path";
|
|
20603
20769
|
import process22 from "process";
|
|
20604
|
-
import
|
|
20605
|
-
import
|
|
20770
|
+
import fs3 from "fs";
|
|
20771
|
+
import path22 from "path";
|
|
20606
20772
|
var __create3 = Object.create;
|
|
20607
20773
|
var __getProtoOf3 = Object.getPrototypeOf;
|
|
20608
20774
|
var __defProp3 = Object.defineProperty;
|
|
@@ -48126,29 +48292,29 @@ var log2 = {
|
|
|
48126
48292
|
},
|
|
48127
48293
|
echo: (...args) => console.log(...args)
|
|
48128
48294
|
};
|
|
48129
|
-
function userDatabasePath2(
|
|
48130
|
-
return projectPath2(`database/${
|
|
48295
|
+
function userDatabasePath2(path23) {
|
|
48296
|
+
return projectPath2(`database/${path23 || ""}`);
|
|
48131
48297
|
}
|
|
48132
|
-
function appPath2(
|
|
48133
|
-
return projectPath2(`app/${
|
|
48298
|
+
function appPath2(path23) {
|
|
48299
|
+
return projectPath2(`app/${path23 || ""}`);
|
|
48134
48300
|
}
|
|
48135
|
-
function commandsPath2(
|
|
48136
|
-
return appPath2(`Commands/${
|
|
48301
|
+
function commandsPath2(path23) {
|
|
48302
|
+
return appPath2(`Commands/${path23 || ""}`);
|
|
48137
48303
|
}
|
|
48138
|
-
function logsPath2(
|
|
48139
|
-
return storagePath2(`logs/${
|
|
48304
|
+
function logsPath2(path23) {
|
|
48305
|
+
return storagePath2(`logs/${path23 || ""}`);
|
|
48140
48306
|
}
|
|
48141
48307
|
function projectPath2(filePath = "", options2) {
|
|
48142
|
-
let
|
|
48143
|
-
while (
|
|
48144
|
-
|
|
48145
|
-
const finalPath = resolve22(
|
|
48308
|
+
let path23 = process52.cwd();
|
|
48309
|
+
while (path23.includes("storage"))
|
|
48310
|
+
path23 = resolve22(path23, "..");
|
|
48311
|
+
const finalPath = resolve22(path23, filePath);
|
|
48146
48312
|
if (options2?.relative)
|
|
48147
48313
|
return relative2(process52.cwd(), finalPath);
|
|
48148
48314
|
return finalPath;
|
|
48149
48315
|
}
|
|
48150
|
-
function storagePath2(
|
|
48151
|
-
return projectPath2(`storage/${
|
|
48316
|
+
function storagePath2(path23) {
|
|
48317
|
+
return projectPath2(`storage/${path23 || ""}`);
|
|
48152
48318
|
}
|
|
48153
48319
|
var config6 = {
|
|
48154
48320
|
ai: {
|
|
@@ -53763,7 +53929,7 @@ class Err2 {
|
|
|
53763
53929
|
}
|
|
53764
53930
|
var fromThrowable2 = Result2.fromThrowable;
|
|
53765
53931
|
var import_prompts2 = __toESM22(require_prompts32(), 1);
|
|
53766
|
-
async function
|
|
53932
|
+
async function exec2(command, options2) {
|
|
53767
53933
|
const cmd = Array.isArray(command) ? command : command.match(/(?:[^\s"]|"[^"]*")+/g);
|
|
53768
53934
|
log2.debug("exec:", Array.isArray(command) ? command.join(" ") : command, options2);
|
|
53769
53935
|
log2.debug("cmd:", cmd);
|
|
@@ -53809,7 +53975,7 @@ async function runCommand(command, options2) {
|
|
|
53809
53975
|
stdio: options2?.stdio ?? [options2?.stdin ?? "inherit", "pipe", "pipe"],
|
|
53810
53976
|
verbose: options2?.verbose ?? false
|
|
53811
53977
|
};
|
|
53812
|
-
return await
|
|
53978
|
+
return await exec2(command, opts);
|
|
53813
53979
|
}
|
|
53814
53980
|
var exports_esm2 = {};
|
|
53815
53981
|
__export3(exports_esm2, {
|
|
@@ -54235,7 +54401,7 @@ function _supportsColor2(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
54235
54401
|
return min;
|
|
54236
54402
|
}
|
|
54237
54403
|
if (process112.platform === "win32") {
|
|
54238
|
-
const osRelease =
|
|
54404
|
+
const osRelease = os3.release().split(".");
|
|
54239
54405
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
54240
54406
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
54241
54407
|
}
|
|
@@ -56832,9 +56998,9 @@ var defaultConfig2 = {
|
|
|
56832
56998
|
domain: "stacks.localhost",
|
|
56833
56999
|
rootCA: { certificate: "", privateKey: "" },
|
|
56834
57000
|
basePath: "",
|
|
56835
|
-
caCertPath:
|
|
56836
|
-
certPath:
|
|
56837
|
-
keyPath:
|
|
57001
|
+
caCertPath: path2.join(os22.homedir(), ".stacks", "ssl", `stacks.localhost.ca.crt`),
|
|
57002
|
+
certPath: path2.join(os22.homedir(), ".stacks", "ssl", `stacks.localhost.crt`),
|
|
57003
|
+
keyPath: path2.join(os22.homedir(), ".stacks", "ssl", `stacks.localhost.crt.key`),
|
|
56838
57004
|
verbose: false
|
|
56839
57005
|
};
|
|
56840
57006
|
var config42 = await loadConfig2({
|
|
@@ -56853,10 +57019,10 @@ function findFoldersWithFile(rootDir, fileName) {
|
|
|
56853
57019
|
const result = [];
|
|
56854
57020
|
function search(dir) {
|
|
56855
57021
|
try {
|
|
56856
|
-
const files =
|
|
57022
|
+
const files = fs3.readdirSync(dir);
|
|
56857
57023
|
for (const file of files) {
|
|
56858
|
-
const filePath =
|
|
56859
|
-
const stats =
|
|
57024
|
+
const filePath = path22.join(dir, file);
|
|
57025
|
+
const stats = fs3.lstatSync(filePath);
|
|
56860
57026
|
if (stats.isDirectory()) {
|
|
56861
57027
|
search(filePath);
|
|
56862
57028
|
} else if (file === fileName) {
|
|
@@ -56870,26 +57036,26 @@ function findFoldersWithFile(rootDir, fileName) {
|
|
|
56870
57036
|
search(rootDir);
|
|
56871
57037
|
return result;
|
|
56872
57038
|
}
|
|
56873
|
-
function
|
|
57039
|
+
function debugLog2(category, message, verbose) {
|
|
56874
57040
|
if (verbose || config42.verbose) {
|
|
56875
57041
|
console.debug(`[tlsx:${category}] ${message}`);
|
|
56876
57042
|
}
|
|
56877
57043
|
}
|
|
56878
57044
|
function generateRandomSerial(verbose) {
|
|
56879
|
-
|
|
57045
|
+
debugLog2("cert", "Generating random serial number", verbose);
|
|
56880
57046
|
const serialNumber = makeNumberPositive(import_node_forge2.default.util.bytesToHex(import_node_forge2.default.random.getBytesSync(20)));
|
|
56881
|
-
|
|
57047
|
+
debugLog2("cert", `Generated serial number: ${serialNumber}`, verbose);
|
|
56882
57048
|
return serialNumber;
|
|
56883
57049
|
}
|
|
56884
57050
|
function calculateValidityDates(options22) {
|
|
56885
57051
|
const notBeforeDays = options22.notBeforeDays ?? 2;
|
|
56886
57052
|
const validityDays = options22.validityDays ?? (options22.validityYears ? options22.validityYears * 365 : 180);
|
|
56887
|
-
|
|
57053
|
+
debugLog2("cert", "Calculating certificate validity dates", options22.verbose);
|
|
56888
57054
|
const notBefore = new Date(Date.now() - 86400 * notBeforeDays * 1000);
|
|
56889
57055
|
const notAfter = new Date(notBefore.getTime() + validityDays * 24 * 60 * 60 * 1000);
|
|
56890
57056
|
notBefore.setUTCHours(0, 0, 0, 0);
|
|
56891
57057
|
notAfter.setUTCHours(23, 59, 59, 999);
|
|
56892
|
-
|
|
57058
|
+
debugLog2("cert", `Validity period: ${notBefore.toISOString()} to ${notAfter.toISOString()}`, options22.verbose);
|
|
56893
57059
|
return { notBefore, notAfter };
|
|
56894
57060
|
}
|
|
56895
57061
|
function generateCertificateExtensions(options22) {
|
|
@@ -56922,9 +57088,9 @@ function generateCertificateExtensions(options22) {
|
|
|
56922
57088
|
return extensions;
|
|
56923
57089
|
}
|
|
56924
57090
|
async function createRootCA(options22 = {}) {
|
|
56925
|
-
|
|
57091
|
+
debugLog2("ca", "Creating new Root CA Certificate", options22.verbose);
|
|
56926
57092
|
const keySize = options22.keySize || 2048;
|
|
56927
|
-
|
|
57093
|
+
debugLog2("ca", `Generating ${keySize}-bit RSA key pair`, options22.verbose);
|
|
56928
57094
|
const { privateKey, publicKey } = import_node_forge2.pki.rsa.generateKeyPair(keySize);
|
|
56929
57095
|
const attributes = [
|
|
56930
57096
|
{ shortName: "C", value: options22.countryName || config42.countryName },
|
|
@@ -56971,14 +57137,14 @@ async function createRootCA(options22 = {}) {
|
|
|
56971
57137
|
};
|
|
56972
57138
|
}
|
|
56973
57139
|
async function generateCertificate(options22) {
|
|
56974
|
-
|
|
56975
|
-
|
|
57140
|
+
debugLog2("cert", "Generating new certificate", options22.verbose);
|
|
57141
|
+
debugLog2("cert", `Options: ${JSON.stringify(options22)}`, options22.verbose);
|
|
56976
57142
|
if (!options22.rootCA?.certificate || !options22.rootCA?.privateKey) {
|
|
56977
57143
|
throw new Error("Root CA certificate and private key are required");
|
|
56978
57144
|
}
|
|
56979
57145
|
const caCert = import_node_forge2.pki.certificateFromPem(options22.rootCA.certificate);
|
|
56980
57146
|
const caKey = import_node_forge2.pki.privateKeyFromPem(options22.rootCA.privateKey);
|
|
56981
|
-
|
|
57147
|
+
debugLog2("cert", "Generating 2048-bit RSA key pair for host certificate", options22.verbose);
|
|
56982
57148
|
const keySize = 2048;
|
|
56983
57149
|
const { privateKey, publicKey } = import_node_forge2.pki.rsa.generateKeyPair(keySize);
|
|
56984
57150
|
const attributes = options22.certificateAttributes || [
|
|
@@ -57009,81 +57175,81 @@ async function generateCertificate(options22) {
|
|
|
57009
57175
|
};
|
|
57010
57176
|
}
|
|
57011
57177
|
async function addCertToSystemTrustStoreAndSaveCert(cert, caCert, options22) {
|
|
57012
|
-
|
|
57013
|
-
|
|
57178
|
+
debugLog2("trust", `Adding certificate to system trust store with options: ${JSON.stringify(options22)}`, options22?.verbose);
|
|
57179
|
+
debugLog2("trust", "Storing certificate and private key", options22?.verbose);
|
|
57014
57180
|
const certPath = storeCertificate(cert, options22);
|
|
57015
|
-
|
|
57181
|
+
debugLog2("trust", "Storing CA certificate", options22?.verbose);
|
|
57016
57182
|
const caCertPath = storeCACertificate(caCert, options22);
|
|
57017
57183
|
const platform22 = os4.platform();
|
|
57018
|
-
|
|
57184
|
+
debugLog2("trust", `Detected platform: ${platform22}`, options22?.verbose);
|
|
57019
57185
|
const args = "TC, C, C";
|
|
57020
57186
|
if (platform22 === "darwin") {
|
|
57021
|
-
|
|
57187
|
+
debugLog2("trust", "Adding certificate to macOS keychain", options22?.verbose);
|
|
57022
57188
|
await runCommand(`sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${caCertPath}`);
|
|
57023
57189
|
} else if (platform22 === "win32") {
|
|
57024
|
-
|
|
57190
|
+
debugLog2("trust", "Adding certificate to Windows certificate store", options22?.verbose);
|
|
57025
57191
|
await runCommand(`certutil -f -v -addstore -enterprise Root ${caCertPath}`);
|
|
57026
57192
|
} else if (platform22 === "linux") {
|
|
57027
|
-
|
|
57193
|
+
debugLog2("trust", "Adding certificate to Linux certificate store", options22?.verbose);
|
|
57028
57194
|
const rootDirectory = os4.homedir();
|
|
57029
57195
|
const targetFileName = "cert9.db";
|
|
57030
|
-
|
|
57196
|
+
debugLog2("trust", `Searching for certificate databases in ${rootDirectory}`, options22?.verbose);
|
|
57031
57197
|
const foldersWithFile = findFoldersWithFile(rootDirectory, targetFileName);
|
|
57032
57198
|
for (const folder of foldersWithFile) {
|
|
57033
|
-
|
|
57199
|
+
debugLog2("trust", `Processing certificate database in ${folder}`, options22?.verbose);
|
|
57034
57200
|
try {
|
|
57035
|
-
|
|
57201
|
+
debugLog2("trust", `Attempting to delete existing cert for ${config42.commonName}`, options22?.verbose);
|
|
57036
57202
|
await runCommand(`certutil -d sql:${folder} -D -n ${config42.commonName}`);
|
|
57037
57203
|
} catch (error) {
|
|
57038
|
-
|
|
57204
|
+
debugLog2("trust", `Warning: Error deleting existing cert: ${error}`, options22?.verbose);
|
|
57039
57205
|
console.warn(`Error deleting existing cert: ${error}`);
|
|
57040
57206
|
}
|
|
57041
|
-
|
|
57207
|
+
debugLog2("trust", `Adding new certificate to ${folder}`, options22?.verbose);
|
|
57042
57208
|
await runCommand(`certutil -d sql:${folder} -A -t ${args} -n ${config42.commonName} -i ${caCertPath}`);
|
|
57043
57209
|
log2.info(`Cert added to ${folder}`);
|
|
57044
57210
|
}
|
|
57045
57211
|
} else {
|
|
57046
|
-
|
|
57212
|
+
debugLog2("trust", `Error: Unsupported platform ${platform22}`, options22?.verbose);
|
|
57047
57213
|
throw new Error(`Unsupported platform: ${platform22}`);
|
|
57048
57214
|
}
|
|
57049
|
-
|
|
57215
|
+
debugLog2("trust", "Certificate successfully added to system trust store", options22?.verbose);
|
|
57050
57216
|
return certPath;
|
|
57051
57217
|
}
|
|
57052
57218
|
function storeCertificate(cert, options22) {
|
|
57053
|
-
|
|
57219
|
+
debugLog2("storage", `Storing certificate and private key with options: ${JSON.stringify(options22)}`, options22?.verbose);
|
|
57054
57220
|
const certPath = path3.join(options22?.basePath || config42.basePath, options22?.certPath || config42.certPath);
|
|
57055
57221
|
const certKeyPath = path3.join(options22?.basePath || config42.basePath, options22?.keyPath || config42.keyPath);
|
|
57056
|
-
|
|
57057
|
-
|
|
57222
|
+
debugLog2("storage", `Certificate path: ${certPath}`, options22?.verbose);
|
|
57223
|
+
debugLog2("storage", `Private key path: ${certKeyPath}`, options22?.verbose);
|
|
57058
57224
|
const certDir = path3.dirname(certPath);
|
|
57059
57225
|
if (!fs2.existsSync(certDir)) {
|
|
57060
|
-
|
|
57226
|
+
debugLog2("storage", `Creating certificate directory: ${certDir}`, options22?.verbose);
|
|
57061
57227
|
fs2.mkdirSync(certDir, { recursive: true });
|
|
57062
57228
|
}
|
|
57063
|
-
|
|
57229
|
+
debugLog2("storage", "Writing certificate file", options22?.verbose);
|
|
57064
57230
|
fs2.writeFileSync(certPath, cert.certificate);
|
|
57065
57231
|
const certKeyDir = path3.dirname(certKeyPath);
|
|
57066
57232
|
if (!fs2.existsSync(certKeyDir)) {
|
|
57067
|
-
|
|
57233
|
+
debugLog2("storage", `Creating private key directory: ${certKeyDir}`, options22?.verbose);
|
|
57068
57234
|
fs2.mkdirSync(certKeyDir, { recursive: true });
|
|
57069
57235
|
}
|
|
57070
|
-
|
|
57236
|
+
debugLog2("storage", "Writing private key file", options22?.verbose);
|
|
57071
57237
|
fs2.writeFileSync(certKeyPath, cert.privateKey);
|
|
57072
|
-
|
|
57238
|
+
debugLog2("storage", "Certificate and private key stored successfully", options22?.verbose);
|
|
57073
57239
|
return certPath;
|
|
57074
57240
|
}
|
|
57075
57241
|
function storeCACertificate(caCert, options22) {
|
|
57076
|
-
|
|
57242
|
+
debugLog2("storage", "Storing CA certificate", options22?.verbose);
|
|
57077
57243
|
const caCertPath = path3.join(options22?.basePath || config42.basePath, options22?.caCertPath || config42.caCertPath);
|
|
57078
|
-
|
|
57244
|
+
debugLog2("storage", `CA certificate path: ${caCertPath}`, options22?.verbose);
|
|
57079
57245
|
const caCertDir = path3.dirname(caCertPath);
|
|
57080
57246
|
if (!fs2.existsSync(caCertDir)) {
|
|
57081
|
-
|
|
57247
|
+
debugLog2("storage", `Creating CA certificate directory: ${caCertDir}`, options22?.verbose);
|
|
57082
57248
|
fs2.mkdirSync(caCertDir, { recursive: true });
|
|
57083
57249
|
}
|
|
57084
|
-
|
|
57250
|
+
debugLog2("storage", "Writing CA certificate file", options22?.verbose);
|
|
57085
57251
|
fs2.writeFileSync(caCertPath, caCert);
|
|
57086
|
-
|
|
57252
|
+
debugLog2("storage", "CA certificate stored successfully", options22?.verbose);
|
|
57087
57253
|
return caCertPath;
|
|
57088
57254
|
}
|
|
57089
57255
|
var export_tls = import_node_forge2.tls;
|
|
@@ -57092,15 +57258,6 @@ var export_forge = import_node_forge2.default;
|
|
|
57092
57258
|
|
|
57093
57259
|
// src/https.ts
|
|
57094
57260
|
var cachedSSLConfig = null;
|
|
57095
|
-
function isMultiProxyConfig(options3) {
|
|
57096
|
-
return "proxies" in options3 && Array.isArray(options3.proxies);
|
|
57097
|
-
}
|
|
57098
|
-
function isMultiProxyOptions(options3) {
|
|
57099
|
-
return "proxies" in options3 && Array.isArray(options3.proxies);
|
|
57100
|
-
}
|
|
57101
|
-
function isSingleProxyOptions(options3) {
|
|
57102
|
-
return "to" in options3 && typeof options3.to === "string";
|
|
57103
|
-
}
|
|
57104
57261
|
function resolveSSLPaths(options3, defaultConfig3) {
|
|
57105
57262
|
const domain = isMultiProxyConfig(options3) ? options3.proxies[0].to || "stacks.localhost" : options3.to || "stacks.localhost";
|
|
57106
57263
|
if (typeof options3.https === "object" && typeof defaultConfig3.https === "object") {
|
|
@@ -57144,15 +57301,6 @@ function generateWildcardPatterns(domain) {
|
|
|
57144
57301
|
patterns.add(`*.${parts.slice(1).join(".")}`);
|
|
57145
57302
|
return Array.from(patterns);
|
|
57146
57303
|
}
|
|
57147
|
-
function getPrimaryDomain(options3) {
|
|
57148
|
-
if (!options3)
|
|
57149
|
-
return "stacks.localhost";
|
|
57150
|
-
if (isMultiProxyOptions(options3) && options3.proxies.length > 0)
|
|
57151
|
-
return options3.proxies[0].to || "stacks.localhost";
|
|
57152
|
-
if (isSingleProxyOptions(options3))
|
|
57153
|
-
return options3.to || "stacks.localhost";
|
|
57154
|
-
return "stacks.localhost";
|
|
57155
|
-
}
|
|
57156
57304
|
function generateSSLPaths(options3) {
|
|
57157
57305
|
const domain = getPrimaryDomain(options3);
|
|
57158
57306
|
let basePath = "";
|
|
@@ -57190,51 +57338,50 @@ function getAllDomains(options3) {
|
|
|
57190
57338
|
return domains;
|
|
57191
57339
|
}
|
|
57192
57340
|
async function loadSSLConfig(options3) {
|
|
57193
|
-
|
|
57341
|
+
debugLog("ssl", `Loading SSL configuration`, options3.verbose);
|
|
57194
57342
|
const mergedOptions = {
|
|
57195
57343
|
...config4,
|
|
57196
57344
|
...options3
|
|
57197
57345
|
};
|
|
57198
57346
|
options3.https = httpsConfig(mergedOptions);
|
|
57199
57347
|
if (!options3.https?.keyPath && !options3.https?.certPath) {
|
|
57200
|
-
|
|
57348
|
+
debugLog("ssl", "No SSL configuration provided", options3.verbose);
|
|
57201
57349
|
return null;
|
|
57202
57350
|
}
|
|
57203
57351
|
if (options3.https?.keyPath && !options3.https?.certPath || !options3.https?.keyPath && options3.https?.certPath) {
|
|
57204
57352
|
const missing = !options3.https?.keyPath ? "keyPath" : "certPath";
|
|
57205
|
-
|
|
57353
|
+
debugLog("ssl", `Invalid SSL configuration - missing ${missing}`, options3.verbose);
|
|
57206
57354
|
throw new Error(`SSL Configuration requires both keyPath and certPath. Missing: ${missing}`);
|
|
57207
57355
|
}
|
|
57208
57356
|
try {
|
|
57209
57357
|
if (!options3.https?.keyPath || !options3.https?.certPath)
|
|
57210
57358
|
return null;
|
|
57211
57359
|
try {
|
|
57212
|
-
|
|
57213
|
-
const key = await
|
|
57214
|
-
const cert = await
|
|
57215
|
-
|
|
57360
|
+
debugLog("ssl", "Reading SSL certificate files", options3.verbose);
|
|
57361
|
+
const key = await fs5.readFile(options3.https?.keyPath, "utf8");
|
|
57362
|
+
const cert = await fs5.readFile(options3.https?.certPath, "utf8");
|
|
57363
|
+
debugLog("ssl", "SSL configuration loaded successfully", options3.verbose);
|
|
57216
57364
|
return { key, cert };
|
|
57217
57365
|
} catch (error) {
|
|
57218
|
-
|
|
57366
|
+
debugLog("ssl", `Failed to read certificates: ${error}`, options3.verbose);
|
|
57219
57367
|
return null;
|
|
57220
57368
|
}
|
|
57221
57369
|
} catch (err3) {
|
|
57222
|
-
|
|
57370
|
+
debugLog("ssl", `SSL configuration error: ${err3}`, options3.verbose);
|
|
57223
57371
|
throw err3;
|
|
57224
57372
|
}
|
|
57225
57373
|
}
|
|
57226
57374
|
async function generateCertificate2(options3) {
|
|
57227
57375
|
if (cachedSSLConfig) {
|
|
57228
|
-
|
|
57376
|
+
debugLog("ssl", "Using cached SSL configuration", options3.verbose);
|
|
57229
57377
|
return;
|
|
57230
57378
|
}
|
|
57231
57379
|
const domains = isMultiProxyOptions(options3) ? options3.proxies.map((proxy) => proxy.to) : [options3.to];
|
|
57232
|
-
|
|
57380
|
+
debugLog("ssl", `Generating certificate for domains: ${domains.join(", ")}`, options3.verbose);
|
|
57233
57381
|
const rootCAConfig = httpsConfig(options3, options3.verbose);
|
|
57234
57382
|
log.info("Generating Root CA certificate...");
|
|
57235
57383
|
const caCert = await createRootCA(rootCAConfig);
|
|
57236
57384
|
const hostConfig = httpsConfig(options3, options3.verbose);
|
|
57237
|
-
console.log("hostConfig", hostConfig);
|
|
57238
57385
|
log.info(`Generating host certificate for: ${domains.join(", ")}`);
|
|
57239
57386
|
const hostCert = await generateCertificate({
|
|
57240
57387
|
...hostConfig,
|
|
@@ -57250,7 +57397,7 @@ async function generateCertificate2(options3) {
|
|
|
57250
57397
|
ca: caCert.certificate
|
|
57251
57398
|
};
|
|
57252
57399
|
log.success(`Certificate generated successfully for ${domains.length} domain${domains.length > 1 ? "s" : ""}`);
|
|
57253
|
-
|
|
57400
|
+
debugLog("ssl", `Certificate includes domains: ${domains.join(", ")}`, options3.verbose);
|
|
57254
57401
|
}
|
|
57255
57402
|
function getSSLConfig() {
|
|
57256
57403
|
return cachedSSLConfig;
|
|
@@ -57259,29 +57406,29 @@ async function checkExistingCertificates(options3) {
|
|
|
57259
57406
|
const name = getPrimaryDomain(options3);
|
|
57260
57407
|
const paths = generateSSLPaths(options3);
|
|
57261
57408
|
try {
|
|
57262
|
-
|
|
57263
|
-
|
|
57264
|
-
|
|
57265
|
-
|
|
57266
|
-
const key = await
|
|
57267
|
-
const cert = await
|
|
57409
|
+
debugLog("ssl", `Checking certificates for ${name} at paths:`, options3?.verbose);
|
|
57410
|
+
debugLog("ssl", `CA: ${paths.caCertPath}`, options3?.verbose);
|
|
57411
|
+
debugLog("ssl", `Cert: ${paths.certPath}`, options3?.verbose);
|
|
57412
|
+
debugLog("ssl", `Key: ${paths.keyPath}`, options3?.verbose);
|
|
57413
|
+
const key = await fs5.readFile(paths.keyPath, "utf8");
|
|
57414
|
+
const cert = await fs5.readFile(paths.certPath, "utf8");
|
|
57268
57415
|
let ca;
|
|
57269
57416
|
if (paths.caCertPath) {
|
|
57270
57417
|
try {
|
|
57271
|
-
ca = await
|
|
57418
|
+
ca = await fs5.readFile(paths.caCertPath, "utf8");
|
|
57272
57419
|
} catch (err3) {
|
|
57273
|
-
|
|
57420
|
+
debugLog("ssl", `Failed to read CA cert: ${err3}`, options3?.verbose);
|
|
57274
57421
|
}
|
|
57275
57422
|
}
|
|
57276
57423
|
return { key, cert, ca };
|
|
57277
57424
|
} catch (err3) {
|
|
57278
|
-
|
|
57425
|
+
debugLog("ssl", `Failed to read certificates: ${err3}`, options3?.verbose);
|
|
57279
57426
|
return null;
|
|
57280
57427
|
}
|
|
57281
57428
|
}
|
|
57282
57429
|
function httpsConfig(options3, verbose) {
|
|
57283
57430
|
const primaryDomain = getPrimaryDomain(options3);
|
|
57284
|
-
|
|
57431
|
+
debugLog("ssl", `Primary domain: ${primaryDomain}`, verbose);
|
|
57285
57432
|
const defaultPaths = generateSSLPaths(options3);
|
|
57286
57433
|
if (typeof options3.https === "object") {
|
|
57287
57434
|
const config5 = {
|
|
@@ -57331,227 +57478,41 @@ function httpsConfig(options3, verbose) {
|
|
|
57331
57478
|
};
|
|
57332
57479
|
}
|
|
57333
57480
|
|
|
57334
|
-
// src/utils.ts
|
|
57335
|
-
function debugLog2(category, message, verbose) {
|
|
57336
|
-
if (verbose) {
|
|
57337
|
-
console.debug(`[rpx:${category}] ${message}`);
|
|
57338
|
-
}
|
|
57339
|
-
}
|
|
57340
|
-
function extractHostname(options3) {
|
|
57341
|
-
if (isMultiProxyOptions(options3)) {
|
|
57342
|
-
return options3.proxies.map((proxy) => {
|
|
57343
|
-
const domain = proxy.to || "stacks.localhost";
|
|
57344
|
-
return domain.startsWith("http") ? new URL(domain).hostname : domain;
|
|
57345
|
-
});
|
|
57346
|
-
}
|
|
57347
|
-
if (isSingleProxyOptions(options3)) {
|
|
57348
|
-
const domain = options3.to || "stacks.localhost";
|
|
57349
|
-
return [domain.startsWith("http") ? new URL(domain).hostname : domain];
|
|
57350
|
-
}
|
|
57351
|
-
return ["stacks.localhost"];
|
|
57352
|
-
}
|
|
57353
|
-
function isValidRootCA(value) {
|
|
57354
|
-
return typeof value === "object" && value !== null && "certificate" in value && "privateKey" in value && typeof value.certificate === "string" && typeof value.privateKey === "string";
|
|
57355
|
-
}
|
|
57356
|
-
|
|
57357
|
-
// src/hosts.ts
|
|
57358
|
-
var hostsFilePath = process3.platform === "win32" ? path4.join(process3.env.windir || "C:\\Windows", "System32", "drivers", "etc", "hosts") : "/etc/hosts";
|
|
57359
|
-
async function sudoWrite(operation, content) {
|
|
57360
|
-
return new Promise((resolve4, reject) => {
|
|
57361
|
-
if (process3.platform === "win32") {
|
|
57362
|
-
reject(new Error("Administrator privileges required on Windows"));
|
|
57363
|
-
return;
|
|
57364
|
-
}
|
|
57365
|
-
const tmpFile = path4.join(os3.tmpdir(), "hosts.tmp");
|
|
57366
|
-
try {
|
|
57367
|
-
if (operation === "append") {
|
|
57368
|
-
const currentContent = fs5.readFileSync(hostsFilePath, "utf8");
|
|
57369
|
-
fs5.writeFileSync(tmpFile, currentContent + content, "utf8");
|
|
57370
|
-
} else {
|
|
57371
|
-
fs5.writeFileSync(tmpFile, content, "utf8");
|
|
57372
|
-
}
|
|
57373
|
-
const sudo = spawn("sudo", ["cp", tmpFile, hostsFilePath]);
|
|
57374
|
-
sudo.on("close", (code) => {
|
|
57375
|
-
try {
|
|
57376
|
-
fs5.unlinkSync(tmpFile);
|
|
57377
|
-
if (code === 0)
|
|
57378
|
-
resolve4();
|
|
57379
|
-
else
|
|
57380
|
-
reject(new Error(`sudo process exited with code ${code}`));
|
|
57381
|
-
} catch (err3) {
|
|
57382
|
-
reject(err3);
|
|
57383
|
-
}
|
|
57384
|
-
});
|
|
57385
|
-
sudo.on("error", (err3) => {
|
|
57386
|
-
try {
|
|
57387
|
-
fs5.unlinkSync(tmpFile);
|
|
57388
|
-
} catch {
|
|
57389
|
-
}
|
|
57390
|
-
reject(err3);
|
|
57391
|
-
});
|
|
57392
|
-
} catch (err3) {
|
|
57393
|
-
reject(err3);
|
|
57394
|
-
}
|
|
57395
|
-
});
|
|
57396
|
-
}
|
|
57397
|
-
async function addHosts(hosts, verbose) {
|
|
57398
|
-
debugLog2("hosts", `Adding hosts: ${hosts.join(", ")}`, verbose);
|
|
57399
|
-
debugLog2("hosts", `Using hosts file at: ${hostsFilePath}`, verbose);
|
|
57400
|
-
try {
|
|
57401
|
-
const existingContent = await fs5.promises.readFile(hostsFilePath, "utf-8");
|
|
57402
|
-
const newEntries = hosts.filter((host) => {
|
|
57403
|
-
const ipv4Entry = `127.0.0.1 ${host}`;
|
|
57404
|
-
const ipv6Entry = `::1 ${host}`;
|
|
57405
|
-
return !existingContent.includes(ipv4Entry) && !existingContent.includes(ipv6Entry);
|
|
57406
|
-
});
|
|
57407
|
-
if (newEntries.length === 0) {
|
|
57408
|
-
debugLog2("hosts", "All hosts already exist in hosts file", verbose);
|
|
57409
|
-
log.info("All hosts are already in the hosts file");
|
|
57410
|
-
return;
|
|
57411
|
-
}
|
|
57412
|
-
const hostEntries = newEntries.map((host) => `
|
|
57413
|
-
# Added by rpx
|
|
57414
|
-
127.0.0.1 ${host}
|
|
57415
|
-
::1 ${host}`).join(`
|
|
57416
|
-
`);
|
|
57417
|
-
try {
|
|
57418
|
-
await fs5.promises.appendFile(hostsFilePath, hostEntries, { flag: "a" });
|
|
57419
|
-
log.success(`Added new hosts: ${newEntries.join(", ")}`);
|
|
57420
|
-
} catch (writeErr) {
|
|
57421
|
-
if (writeErr.code === "EACCES") {
|
|
57422
|
-
debugLog2("hosts", "Permission denied, attempting with sudo", verbose);
|
|
57423
|
-
try {
|
|
57424
|
-
await sudoWrite("append", hostEntries);
|
|
57425
|
-
log.success(`Added new hosts with sudo: ${newEntries.join(", ")}`);
|
|
57426
|
-
} catch (sudoErr) {
|
|
57427
|
-
log.error("Failed to modify hosts file automatically");
|
|
57428
|
-
log.warn("Please add these entries to your hosts file manually:");
|
|
57429
|
-
hostEntries.split(`
|
|
57430
|
-
`).forEach((entry) => log.warn(entry));
|
|
57431
|
-
if (process3.platform === "win32") {
|
|
57432
|
-
log.warn(`
|
|
57433
|
-
On Windows:`);
|
|
57434
|
-
log.warn("1. Run notepad as administrator");
|
|
57435
|
-
log.warn("2. Open C:\\Windows\\System32\\drivers\\etc\\hosts");
|
|
57436
|
-
} else {
|
|
57437
|
-
log.warn(`
|
|
57438
|
-
On Unix systems:`);
|
|
57439
|
-
log.warn(`sudo nano ${hostsFilePath}`);
|
|
57440
|
-
}
|
|
57441
|
-
throw new Error("Failed to modify hosts file: manual intervention required");
|
|
57442
|
-
}
|
|
57443
|
-
} else {
|
|
57444
|
-
throw writeErr;
|
|
57445
|
-
}
|
|
57446
|
-
}
|
|
57447
|
-
} catch (err3) {
|
|
57448
|
-
const error = err3;
|
|
57449
|
-
log.error(`Failed to manage hosts file: ${error.message}`);
|
|
57450
|
-
throw error;
|
|
57451
|
-
}
|
|
57452
|
-
}
|
|
57453
|
-
async function removeHosts(hosts, verbose) {
|
|
57454
|
-
debugLog2("hosts", `Removing hosts: ${hosts.join(", ")}`, verbose);
|
|
57455
|
-
try {
|
|
57456
|
-
const content = await fs5.promises.readFile(hostsFilePath, "utf-8");
|
|
57457
|
-
const lines = content.split(`
|
|
57458
|
-
`);
|
|
57459
|
-
const filteredLines = lines.filter((line, index) => {
|
|
57460
|
-
if (line.trim() === "# Added by rpx") {
|
|
57461
|
-
lines.splice(index + 1, 2);
|
|
57462
|
-
return false;
|
|
57463
|
-
}
|
|
57464
|
-
return true;
|
|
57465
|
-
});
|
|
57466
|
-
while (filteredLines[filteredLines.length - 1]?.trim() === "")
|
|
57467
|
-
filteredLines.pop();
|
|
57468
|
-
const newContent = `${filteredLines.join(`
|
|
57469
|
-
`)}
|
|
57470
|
-
`;
|
|
57471
|
-
try {
|
|
57472
|
-
await fs5.promises.writeFile(hostsFilePath, newContent);
|
|
57473
|
-
log.success("Hosts removed successfully");
|
|
57474
|
-
} catch (writeErr) {
|
|
57475
|
-
if (writeErr.code === "EACCES") {
|
|
57476
|
-
debugLog2("hosts", "Permission denied, attempting with sudo", verbose);
|
|
57477
|
-
try {
|
|
57478
|
-
await sudoWrite("write", newContent);
|
|
57479
|
-
log.success("Hosts removed successfully with sudo");
|
|
57480
|
-
} catch (sudoErr) {
|
|
57481
|
-
log.error("Failed to modify hosts file automatically");
|
|
57482
|
-
log.warn("Please remove these entries from your hosts file manually:");
|
|
57483
|
-
hosts.forEach((host) => {
|
|
57484
|
-
log.warn("# Added by rpx");
|
|
57485
|
-
log.warn(`127.0.0.1 ${host}`);
|
|
57486
|
-
log.warn(`::1 ${host}`);
|
|
57487
|
-
});
|
|
57488
|
-
if (process3.platform === "win32") {
|
|
57489
|
-
log.warn(`
|
|
57490
|
-
On Windows:`);
|
|
57491
|
-
log.warn("1. Run notepad as administrator");
|
|
57492
|
-
log.warn("2. Open C:\\Windows\\System32\\drivers\\etc\\hosts");
|
|
57493
|
-
} else {
|
|
57494
|
-
log.warn(`
|
|
57495
|
-
On Unix systems:`);
|
|
57496
|
-
log.warn(`sudo nano ${hostsFilePath}`);
|
|
57497
|
-
}
|
|
57498
|
-
throw new Error("Failed to modify hosts file: manual intervention required");
|
|
57499
|
-
}
|
|
57500
|
-
} else {
|
|
57501
|
-
throw writeErr;
|
|
57502
|
-
}
|
|
57503
|
-
}
|
|
57504
|
-
} catch (err3) {
|
|
57505
|
-
const error = err3;
|
|
57506
|
-
log.error(`Failed to remove hosts: ${error.message}`);
|
|
57507
|
-
throw error;
|
|
57508
|
-
}
|
|
57509
|
-
}
|
|
57510
|
-
async function checkHosts(hosts, verbose) {
|
|
57511
|
-
debugLog2("hosts", `Checking hosts: ${hosts}`, verbose);
|
|
57512
|
-
const content = await fs5.promises.readFile(hostsFilePath, "utf-8");
|
|
57513
|
-
return hosts.map((host) => {
|
|
57514
|
-
const ipv4Entry = `127.0.0.1 ${host}`;
|
|
57515
|
-
const ipv6Entry = `::1 ${host}`;
|
|
57516
|
-
return content.includes(ipv4Entry) || content.includes(ipv6Entry);
|
|
57517
|
-
});
|
|
57518
|
-
}
|
|
57519
|
-
|
|
57520
57481
|
// src/start.ts
|
|
57521
57482
|
var activeServers = new Set;
|
|
57522
57483
|
async function cleanup(options3) {
|
|
57523
|
-
|
|
57484
|
+
debugLog("cleanup", "Starting cleanup process", options3?.verbose);
|
|
57524
57485
|
console.log(`
|
|
57525
57486
|
`);
|
|
57526
57487
|
log.info("Shutting down proxy servers...");
|
|
57527
57488
|
const cleanupPromises = [];
|
|
57528
57489
|
const serverClosePromises = Array.from(activeServers).map((server) => new Promise((resolve4) => {
|
|
57529
57490
|
server.close(() => {
|
|
57530
|
-
|
|
57491
|
+
debugLog("cleanup", "Server closed successfully", options3?.verbose);
|
|
57531
57492
|
resolve4();
|
|
57532
57493
|
});
|
|
57533
57494
|
}));
|
|
57534
57495
|
cleanupPromises.push(...serverClosePromises);
|
|
57535
57496
|
if (options3?.etcHostsCleanup && options3.domains?.length) {
|
|
57536
|
-
|
|
57497
|
+
debugLog("cleanup", "Cleaning up hosts file entries", options3?.verbose);
|
|
57537
57498
|
const domainsToClean = options3.domains.filter((domain) => !domain.includes("localhost"));
|
|
57538
57499
|
if (domainsToClean.length > 0) {
|
|
57539
57500
|
log.info("Cleaning up hosts file entries...");
|
|
57540
57501
|
cleanupPromises.push(removeHosts(domainsToClean, options3?.verbose).then(() => {
|
|
57541
|
-
|
|
57502
|
+
debugLog("cleanup", `Removed hosts entries for ${domainsToClean.join(", ")}`, options3?.verbose);
|
|
57542
57503
|
}).catch((err3) => {
|
|
57543
|
-
|
|
57504
|
+
debugLog("cleanup", `Failed to remove hosts entries: ${err3}`, options3?.verbose);
|
|
57544
57505
|
log.warn(`Failed to clean up hosts file entries for ${domainsToClean.join(", ")}:`, err3);
|
|
57545
57506
|
}));
|
|
57546
57507
|
}
|
|
57547
57508
|
}
|
|
57548
57509
|
try {
|
|
57549
57510
|
await Promise.all(cleanupPromises);
|
|
57550
|
-
|
|
57511
|
+
debugLog("cleanup", "All cleanup tasks completed successfully", options3?.verbose);
|
|
57551
57512
|
log.success("All cleanup tasks completed successfully");
|
|
57552
57513
|
process9.exit(0);
|
|
57553
57514
|
} catch (err3) {
|
|
57554
|
-
|
|
57515
|
+
debugLog("cleanup", `Error during cleanup: ${err3}`, options3?.verbose);
|
|
57555
57516
|
log.error("Error during cleanup:", err3);
|
|
57556
57517
|
process9.exit(1);
|
|
57557
57518
|
}
|
|
@@ -57559,22 +57520,22 @@ async function cleanup(options3) {
|
|
|
57559
57520
|
process9.on("SIGINT", cleanup);
|
|
57560
57521
|
process9.on("SIGTERM", cleanup);
|
|
57561
57522
|
process9.on("uncaughtException", (err3) => {
|
|
57562
|
-
|
|
57523
|
+
debugLog("process", `Uncaught exception: ${err3}`, true);
|
|
57563
57524
|
log.error("Uncaught exception:", err3);
|
|
57564
57525
|
cleanup();
|
|
57565
57526
|
});
|
|
57566
57527
|
function isPortInUse(port, hostname, verbose) {
|
|
57567
|
-
|
|
57528
|
+
debugLog("port", `Checking if port ${port} is in use on ${hostname}`, verbose);
|
|
57568
57529
|
return new Promise((resolve4) => {
|
|
57569
57530
|
const server = net.createServer();
|
|
57570
57531
|
server.once("error", (err3) => {
|
|
57571
57532
|
if (err3.code === "EADDRINUSE") {
|
|
57572
|
-
|
|
57533
|
+
debugLog("port", `Port ${port} is in use`, verbose);
|
|
57573
57534
|
resolve4(true);
|
|
57574
57535
|
}
|
|
57575
57536
|
});
|
|
57576
57537
|
server.once("listening", () => {
|
|
57577
|
-
|
|
57538
|
+
debugLog("port", `Port ${port} is available`, verbose);
|
|
57578
57539
|
server.close();
|
|
57579
57540
|
resolve4(false);
|
|
57580
57541
|
});
|
|
@@ -57582,17 +57543,17 @@ function isPortInUse(port, hostname, verbose) {
|
|
|
57582
57543
|
});
|
|
57583
57544
|
}
|
|
57584
57545
|
async function findAvailablePort(startPort, hostname, verbose) {
|
|
57585
|
-
|
|
57546
|
+
debugLog("port", `Finding available port starting from ${startPort}`, verbose);
|
|
57586
57547
|
let port = startPort;
|
|
57587
57548
|
while (await isPortInUse(port, hostname, verbose)) {
|
|
57588
|
-
|
|
57549
|
+
debugLog("port", `Port ${port} is in use, trying ${port + 1}`, verbose);
|
|
57589
57550
|
port++;
|
|
57590
57551
|
}
|
|
57591
|
-
|
|
57552
|
+
debugLog("port", `Found available port: ${port}`, verbose);
|
|
57592
57553
|
return port;
|
|
57593
57554
|
}
|
|
57594
57555
|
async function testConnection(hostname, port, verbose) {
|
|
57595
|
-
|
|
57556
|
+
debugLog("connection", `Testing connection to ${hostname}:${port}`, verbose);
|
|
57596
57557
|
return new Promise((resolve4, reject) => {
|
|
57597
57558
|
const socket = net.connect({
|
|
57598
57559
|
host: hostname,
|
|
@@ -57600,30 +57561,30 @@ async function testConnection(hostname, port, verbose) {
|
|
|
57600
57561
|
timeout: 5000
|
|
57601
57562
|
});
|
|
57602
57563
|
socket.once("connect", () => {
|
|
57603
|
-
|
|
57564
|
+
debugLog("connection", `Successfully connected to ${hostname}:${port}`, verbose);
|
|
57604
57565
|
socket.end();
|
|
57605
57566
|
resolve4();
|
|
57606
57567
|
});
|
|
57607
57568
|
socket.once("timeout", () => {
|
|
57608
|
-
|
|
57569
|
+
debugLog("connection", `Connection to ${hostname}:${port} timed out`, verbose);
|
|
57609
57570
|
socket.destroy();
|
|
57610
57571
|
reject(new Error(`Connection to ${hostname}:${port} timed out`));
|
|
57611
57572
|
});
|
|
57612
57573
|
socket.once("error", (err3) => {
|
|
57613
|
-
|
|
57574
|
+
debugLog("connection", `Failed to connect to ${hostname}:${port}: ${err3}`, verbose);
|
|
57614
57575
|
socket.destroy();
|
|
57615
57576
|
reject(new Error(`Failed to connect to ${hostname}:${port}: ${err3.message}`));
|
|
57616
57577
|
});
|
|
57617
57578
|
});
|
|
57618
57579
|
}
|
|
57619
57580
|
async function startServer(options3) {
|
|
57620
|
-
|
|
57581
|
+
debugLog("server", `Starting server with options: ${JSON.stringify(options3)}`, options3.verbose);
|
|
57621
57582
|
const fromUrl = new URL((options3.from?.startsWith("http") ? options3.from : `http://${options3.from}`) || "localhost:5173");
|
|
57622
57583
|
const toUrl = new URL((options3.to?.startsWith("http") ? options3.to : `http://${options3.to}`) || "stacks.localhost");
|
|
57623
57584
|
const fromPort = Number.parseInt(fromUrl.port) || (fromUrl.protocol.includes("https:") ? 443 : 80);
|
|
57624
57585
|
const hostsToCheck = [toUrl.hostname];
|
|
57625
57586
|
if (!toUrl.hostname.includes("localhost") && !toUrl.hostname.includes("127.0.0.1")) {
|
|
57626
|
-
|
|
57587
|
+
debugLog("hosts", `Checking if hosts file entry exists for: ${toUrl.hostname}`, options3?.verbose);
|
|
57627
57588
|
try {
|
|
57628
57589
|
const hostsExist = await checkHosts(hostsToCheck, options3.verbose);
|
|
57629
57590
|
if (!hostsExist[0]) {
|
|
@@ -57646,7 +57607,7 @@ async function startServer(options3) {
|
|
|
57646
57607
|
}
|
|
57647
57608
|
}
|
|
57648
57609
|
} else {
|
|
57649
|
-
|
|
57610
|
+
debugLog("hosts", `Host entry already exists for ${toUrl.hostname}`, options3.verbose);
|
|
57650
57611
|
}
|
|
57651
57612
|
} catch (checkError) {
|
|
57652
57613
|
log.error("Failed to check hosts file:", checkError.message);
|
|
@@ -57655,7 +57616,7 @@ async function startServer(options3) {
|
|
|
57655
57616
|
try {
|
|
57656
57617
|
await testConnection(fromUrl.hostname, fromPort, options3.verbose);
|
|
57657
57618
|
} catch (err3) {
|
|
57658
|
-
|
|
57619
|
+
debugLog("server", `Connection test failed: ${err3}`, options3.verbose);
|
|
57659
57620
|
log.error(err3.message);
|
|
57660
57621
|
process9.exit(1);
|
|
57661
57622
|
}
|
|
@@ -57669,17 +57630,17 @@ async function startServer(options3) {
|
|
|
57669
57630
|
});
|
|
57670
57631
|
}
|
|
57671
57632
|
try {
|
|
57672
|
-
|
|
57633
|
+
debugLog("ssl", `Attempting to load SSL configuration for ${toUrl.hostname}`, options3.verbose);
|
|
57673
57634
|
sslConfig = await loadSSLConfig({
|
|
57674
57635
|
...options3,
|
|
57675
57636
|
to: toUrl.hostname,
|
|
57676
57637
|
https: options3.https
|
|
57677
57638
|
});
|
|
57678
57639
|
} catch (loadError) {
|
|
57679
|
-
|
|
57640
|
+
debugLog("ssl", `Failed to load certificates, will generate new ones: ${loadError}`, options3.verbose);
|
|
57680
57641
|
}
|
|
57681
57642
|
if (!sslConfig) {
|
|
57682
|
-
|
|
57643
|
+
debugLog("ssl", `Generating new certificates for ${toUrl.hostname}`, options3.verbose);
|
|
57683
57644
|
await generateCertificate2({
|
|
57684
57645
|
...options3,
|
|
57685
57646
|
from: fromUrl.toString(),
|
|
@@ -57696,11 +57657,11 @@ async function startServer(options3) {
|
|
|
57696
57657
|
}
|
|
57697
57658
|
}
|
|
57698
57659
|
} catch (err3) {
|
|
57699
|
-
|
|
57660
|
+
debugLog("server", `SSL setup failed: ${err3}`, options3.verbose);
|
|
57700
57661
|
throw err3;
|
|
57701
57662
|
}
|
|
57702
57663
|
}
|
|
57703
|
-
|
|
57664
|
+
debugLog("server", `Setting up reverse proxy with SSL config for ${toUrl.hostname}`, options3.verbose);
|
|
57704
57665
|
await setupReverseProxy({
|
|
57705
57666
|
...options3,
|
|
57706
57667
|
from: options3.from || "localhost:5173",
|
|
@@ -57713,23 +57674,69 @@ async function startServer(options3) {
|
|
|
57713
57674
|
ssl: sslConfig
|
|
57714
57675
|
});
|
|
57715
57676
|
}
|
|
57716
|
-
async function createProxyServer(from, to, fromPort, listenPort, hostname, sourceUrl, ssl, verbose) {
|
|
57717
|
-
|
|
57677
|
+
async function createProxyServer(from, to, fromPort, listenPort, hostname, sourceUrl, ssl, verbose, cleanUrls) {
|
|
57678
|
+
debugLog("proxy", `Creating proxy server ${from} -> ${to} with cleanUrls: ${cleanUrls}`, verbose);
|
|
57718
57679
|
const requestHandler = (req, res) => {
|
|
57719
|
-
|
|
57680
|
+
debugLog("request", `Incoming request: ${req.method} ${req.url}`, verbose);
|
|
57681
|
+
let path4 = req.url || "/";
|
|
57682
|
+
if (cleanUrls) {
|
|
57683
|
+
if (!path4.match(/\.[a-z0-9]+$/i)) {
|
|
57684
|
+
if (path4.endsWith("/")) {
|
|
57685
|
+
path4 = `${path4}index.html`;
|
|
57686
|
+
} else {
|
|
57687
|
+
path4 = `${path4}.html`;
|
|
57688
|
+
}
|
|
57689
|
+
}
|
|
57690
|
+
}
|
|
57720
57691
|
const proxyOptions = {
|
|
57721
57692
|
hostname: sourceUrl.hostname,
|
|
57722
57693
|
port: fromPort,
|
|
57723
|
-
path:
|
|
57694
|
+
path: path4,
|
|
57724
57695
|
method: req.method,
|
|
57725
57696
|
headers: {
|
|
57726
57697
|
...req.headers,
|
|
57727
57698
|
host: sourceUrl.host
|
|
57728
57699
|
}
|
|
57729
57700
|
};
|
|
57730
|
-
|
|
57701
|
+
debugLog("request", `Proxy request options: ${JSON.stringify(proxyOptions)}`, verbose);
|
|
57731
57702
|
const proxyReq = http.request(proxyOptions, (proxyRes) => {
|
|
57732
|
-
|
|
57703
|
+
debugLog("response", `Proxy response received with status ${proxyRes.statusCode}`, verbose);
|
|
57704
|
+
if (cleanUrls && proxyRes.statusCode === 404) {
|
|
57705
|
+
const alternativePaths = [];
|
|
57706
|
+
if (path4.endsWith(".html")) {
|
|
57707
|
+
alternativePaths.push(path4.slice(0, -5));
|
|
57708
|
+
} else if (!path4.match(/\.[a-z0-9]+$/i)) {
|
|
57709
|
+
alternativePaths.push(`${path4}.html`);
|
|
57710
|
+
}
|
|
57711
|
+
if (!path4.endsWith("/")) {
|
|
57712
|
+
alternativePaths.push(`${path4}/index.html`);
|
|
57713
|
+
}
|
|
57714
|
+
if (alternativePaths.length > 0) {
|
|
57715
|
+
debugLog("cleanUrls", `Trying alternative paths: ${alternativePaths.join(", ")}`, verbose);
|
|
57716
|
+
const tryNextPath = (paths) => {
|
|
57717
|
+
if (paths.length === 0) {
|
|
57718
|
+
res.writeHead(proxyRes.statusCode || 404, proxyRes.headers);
|
|
57719
|
+
proxyRes.pipe(res);
|
|
57720
|
+
return;
|
|
57721
|
+
}
|
|
57722
|
+
const altPath = paths[0];
|
|
57723
|
+
const altOptions = { ...proxyOptions, path: altPath };
|
|
57724
|
+
const altReq = http.request(altOptions, (altRes) => {
|
|
57725
|
+
if (altRes.statusCode === 200) {
|
|
57726
|
+
debugLog("cleanUrls", `Found matching path: ${altPath}`, verbose);
|
|
57727
|
+
res.writeHead(altRes.statusCode, altRes.headers);
|
|
57728
|
+
altRes.pipe(res);
|
|
57729
|
+
} else {
|
|
57730
|
+
tryNextPath(paths.slice(1));
|
|
57731
|
+
}
|
|
57732
|
+
});
|
|
57733
|
+
altReq.on("error", () => tryNextPath(paths.slice(1)));
|
|
57734
|
+
altReq.end();
|
|
57735
|
+
};
|
|
57736
|
+
tryNextPath(alternativePaths);
|
|
57737
|
+
return;
|
|
57738
|
+
}
|
|
57739
|
+
}
|
|
57733
57740
|
const headers = {
|
|
57734
57741
|
...proxyRes.headers,
|
|
57735
57742
|
"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
|
|
@@ -57739,7 +57746,7 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57739
57746
|
proxyRes.pipe(res);
|
|
57740
57747
|
});
|
|
57741
57748
|
proxyReq.on("error", (err3) => {
|
|
57742
|
-
|
|
57749
|
+
debugLog("request", `Proxy request failed: ${err3}`, verbose);
|
|
57743
57750
|
log.error("Proxy request failed:", err3);
|
|
57744
57751
|
res.writeHead(502);
|
|
57745
57752
|
res.end(`Proxy Error: ${err3.message}`);
|
|
@@ -57766,11 +57773,11 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57766
57773
|
allowHTTP1: true,
|
|
57767
57774
|
ALPNProtocols: ["h2", "http/1.1"]
|
|
57768
57775
|
} : undefined;
|
|
57769
|
-
|
|
57776
|
+
debugLog("server", `Creating server with SSL config: ${!!ssl}`, verbose);
|
|
57770
57777
|
const server = ssl && serverOptions ? https.createServer(serverOptions, requestHandler) : http.createServer(requestHandler);
|
|
57771
57778
|
if (ssl) {
|
|
57772
57779
|
server.on("secureConnection", (tlsSocket) => {
|
|
57773
|
-
|
|
57780
|
+
debugLog("tls", `TLS Connection established: ${JSON.stringify({
|
|
57774
57781
|
protocol: tlsSocket.getProtocol?.(),
|
|
57775
57782
|
cipher: tlsSocket.getCipher?.(),
|
|
57776
57783
|
authorized: tlsSocket.authorized,
|
|
@@ -57781,7 +57788,7 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57781
57788
|
activeServers.add(server);
|
|
57782
57789
|
return new Promise((resolve4, reject) => {
|
|
57783
57790
|
server.listen(listenPort, hostname, () => {
|
|
57784
|
-
|
|
57791
|
+
debugLog("server", `Server listening on port ${listenPort}`, verbose);
|
|
57785
57792
|
console.log("");
|
|
57786
57793
|
console.log(` ${green(bold("reverse-proxy"))} ${green(`v${version}`)}`);
|
|
57787
57794
|
console.log("");
|
|
@@ -57795,16 +57802,19 @@ async function createProxyServer(from, to, fromPort, listenPort, hostname, sourc
|
|
|
57795
57802
|
console.log(` - HTTP/2 enabled`);
|
|
57796
57803
|
console.log(` - HSTS enabled`);
|
|
57797
57804
|
}
|
|
57805
|
+
if (cleanUrls) {
|
|
57806
|
+
console.log(` ${green("\u279C")} Clean URLs enabled`);
|
|
57807
|
+
}
|
|
57798
57808
|
resolve4();
|
|
57799
57809
|
});
|
|
57800
57810
|
server.on("error", (err3) => {
|
|
57801
|
-
|
|
57811
|
+
debugLog("server", `Server error: ${err3}`, verbose);
|
|
57802
57812
|
reject(err3);
|
|
57803
57813
|
});
|
|
57804
57814
|
});
|
|
57805
57815
|
}
|
|
57806
57816
|
async function setupReverseProxy(options3) {
|
|
57807
|
-
|
|
57817
|
+
debugLog("setup", `Setting up reverse proxy: ${JSON.stringify(options3)}`, options3.verbose);
|
|
57808
57818
|
const { from, to, fromPort, sourceUrl, ssl, verbose, etcHostsCleanup, portManager } = options3;
|
|
57809
57819
|
const httpPort = 80;
|
|
57810
57820
|
const httpsPort = 443;
|
|
@@ -57813,11 +57823,11 @@ async function setupReverseProxy(options3) {
|
|
|
57813
57823
|
if (ssl && !portManager?.usedPorts.has(httpPort)) {
|
|
57814
57824
|
const isHttpPortBusy = await isPortInUse(httpPort, hostname, verbose);
|
|
57815
57825
|
if (!isHttpPortBusy) {
|
|
57816
|
-
|
|
57826
|
+
debugLog("setup", "Starting HTTP redirect server", verbose);
|
|
57817
57827
|
startHttpRedirectServer(verbose);
|
|
57818
57828
|
portManager?.usedPorts.add(httpPort);
|
|
57819
57829
|
} else {
|
|
57820
|
-
|
|
57830
|
+
debugLog("setup", "Port 80 is in use, skipping HTTP redirect", verbose);
|
|
57821
57831
|
log.warn("Port 80 is in use, HTTP to HTTPS redirect will not be available");
|
|
57822
57832
|
}
|
|
57823
57833
|
}
|
|
@@ -57835,7 +57845,7 @@ async function setupReverseProxy(options3) {
|
|
|
57835
57845
|
}
|
|
57836
57846
|
await createProxyServer(from, to, fromPort, finalPort, hostname, sourceUrl, ssl, verbose);
|
|
57837
57847
|
} catch (err3) {
|
|
57838
|
-
|
|
57848
|
+
debugLog("setup", `Setup failed: ${err3}`, verbose);
|
|
57839
57849
|
log.error(`Failed to setup reverse proxy: ${err3.message}`);
|
|
57840
57850
|
cleanup({
|
|
57841
57851
|
domains: [to],
|
|
@@ -57845,34 +57855,35 @@ async function setupReverseProxy(options3) {
|
|
|
57845
57855
|
}
|
|
57846
57856
|
}
|
|
57847
57857
|
function startHttpRedirectServer(verbose) {
|
|
57848
|
-
|
|
57858
|
+
debugLog("redirect", "Starting HTTP redirect server", verbose);
|
|
57849
57859
|
const server = http.createServer((req, res) => {
|
|
57850
57860
|
const host = req.headers.host || "";
|
|
57851
|
-
|
|
57861
|
+
debugLog("redirect", `Redirecting request from ${host}${req.url} to HTTPS`, verbose);
|
|
57852
57862
|
res.writeHead(301, {
|
|
57853
57863
|
Location: `https://${host}${req.url}`
|
|
57854
57864
|
});
|
|
57855
57865
|
res.end();
|
|
57856
57866
|
}).listen(80);
|
|
57857
57867
|
activeServers.add(server);
|
|
57858
|
-
|
|
57868
|
+
debugLog("redirect", "HTTP redirect server started", verbose);
|
|
57859
57869
|
}
|
|
57860
57870
|
function startProxy(options3) {
|
|
57861
57871
|
const mergedOptions = {
|
|
57862
57872
|
...config4,
|
|
57863
57873
|
...options3
|
|
57864
57874
|
};
|
|
57865
|
-
|
|
57875
|
+
debugLog("proxy", `Starting proxy with options: ${JSON.stringify(mergedOptions)}`, mergedOptions?.verbose);
|
|
57866
57876
|
const serverOptions = {
|
|
57867
57877
|
from: mergedOptions.from,
|
|
57868
57878
|
to: mergedOptions.to,
|
|
57879
|
+
cleanUrls: mergedOptions.cleanUrls,
|
|
57869
57880
|
https: httpsConfig(mergedOptions),
|
|
57870
57881
|
etcHostsCleanup: mergedOptions.etcHostsCleanup,
|
|
57871
57882
|
verbose: mergedOptions.verbose
|
|
57872
57883
|
};
|
|
57873
57884
|
console.log("serverOptions", serverOptions);
|
|
57874
57885
|
startServer(serverOptions).catch((err3) => {
|
|
57875
|
-
|
|
57886
|
+
debugLog("proxy", `Failed to start proxy: ${err3}`, mergedOptions.verbose);
|
|
57876
57887
|
log.error(`Failed to start proxy: ${err3.message}`);
|
|
57877
57888
|
cleanup({
|
|
57878
57889
|
domains: [mergedOptions.to],
|
|
@@ -57882,7 +57893,7 @@ function startProxy(options3) {
|
|
|
57882
57893
|
});
|
|
57883
57894
|
}
|
|
57884
57895
|
async function startProxies(options3) {
|
|
57885
|
-
|
|
57896
|
+
debugLog("proxies", "Starting proxy setup", options3?.verbose);
|
|
57886
57897
|
const mergedOptions = {
|
|
57887
57898
|
...config4,
|
|
57888
57899
|
...options3
|
|
@@ -57891,10 +57902,10 @@ async function startProxies(options3) {
|
|
|
57891
57902
|
if (mergedOptions.https) {
|
|
57892
57903
|
const existingSSLConfig = await checkExistingCertificates(mergedOptions);
|
|
57893
57904
|
if (existingSSLConfig) {
|
|
57894
|
-
|
|
57905
|
+
debugLog("ssl", `Using existing certificates for ${primaryDomain}`, mergedOptions.verbose);
|
|
57895
57906
|
mergedOptions._cachedSSLConfig = existingSSLConfig;
|
|
57896
57907
|
} else {
|
|
57897
|
-
|
|
57908
|
+
debugLog("ssl", `No valid certificates found for ${primaryDomain}, generating new ones`, mergedOptions.verbose);
|
|
57898
57909
|
await generateCertificate2(mergedOptions);
|
|
57899
57910
|
const sslConfig2 = await checkExistingCertificates(mergedOptions);
|
|
57900
57911
|
if (!sslConfig2) {
|
|
@@ -57907,11 +57918,13 @@ async function startProxies(options3) {
|
|
|
57907
57918
|
...proxy,
|
|
57908
57919
|
https: mergedOptions.https,
|
|
57909
57920
|
etcHostsCleanup: mergedOptions.etcHostsCleanup,
|
|
57921
|
+
cleanUrls: mergedOptions.cleanUrls,
|
|
57910
57922
|
verbose: mergedOptions.verbose,
|
|
57911
57923
|
_cachedSSLConfig: mergedOptions._cachedSSLConfig
|
|
57912
57924
|
})) : [{
|
|
57913
57925
|
from: mergedOptions.from || "localhost:5173",
|
|
57914
57926
|
to: mergedOptions.to || "stacks.localhost",
|
|
57927
|
+
cleanUrls: mergedOptions.cleanUrls || false,
|
|
57915
57928
|
https: mergedOptions.https,
|
|
57916
57929
|
etcHostsCleanup: mergedOptions.etcHostsCleanup,
|
|
57917
57930
|
verbose: mergedOptions.verbose,
|
|
@@ -57927,24 +57940,25 @@ async function startProxies(options3) {
|
|
|
57927
57940
|
process9.on("SIGINT", cleanupHandler);
|
|
57928
57941
|
process9.on("SIGTERM", cleanupHandler);
|
|
57929
57942
|
process9.on("uncaughtException", (err3) => {
|
|
57930
|
-
|
|
57943
|
+
debugLog("process", `Uncaught exception: ${err3}`, true);
|
|
57931
57944
|
console.error("Uncaught exception:", err3);
|
|
57932
57945
|
cleanupHandler();
|
|
57933
57946
|
});
|
|
57934
57947
|
for (const option of proxyOptions) {
|
|
57935
57948
|
try {
|
|
57936
57949
|
const domain = option.to || "stacks.localhost";
|
|
57937
|
-
|
|
57950
|
+
debugLog("proxy", `Starting proxy for ${domain} with SSL config: ${!!sslConfig}`, option.verbose);
|
|
57938
57951
|
await startServer({
|
|
57939
57952
|
from: option.from || "localhost:5173",
|
|
57940
57953
|
to: domain,
|
|
57941
|
-
|
|
57954
|
+
cleanUrls: option.cleanUrls || false,
|
|
57955
|
+
https: option.https || false,
|
|
57942
57956
|
etcHostsCleanup: option.etcHostsCleanup || false,
|
|
57943
57957
|
verbose: option.verbose || false,
|
|
57944
57958
|
_cachedSSLConfig: sslConfig
|
|
57945
57959
|
});
|
|
57946
57960
|
} catch (err3) {
|
|
57947
|
-
|
|
57961
|
+
debugLog("proxies", `Failed to start proxy for ${option.to}: ${err3}`, option.verbose);
|
|
57948
57962
|
console.error(`Failed to start proxy for ${option.to}:`, err3);
|
|
57949
57963
|
cleanupHandler();
|
|
57950
57964
|
}
|
|
@@ -57976,7 +57990,7 @@ export {
|
|
|
57976
57990
|
generateCertificate2 as generateCertificate,
|
|
57977
57991
|
extractHostname,
|
|
57978
57992
|
src_default as default,
|
|
57979
|
-
|
|
57993
|
+
debugLog,
|
|
57980
57994
|
config4 as config,
|
|
57981
57995
|
cleanup,
|
|
57982
57996
|
checkHosts,
|