@stacksjs/rpx 0.4.1 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +394 -308
- package/dist/config.d.ts +3 -2
- package/dist/hosts.d.ts +2 -1
- package/dist/https.d.ts +10 -8
- package/dist/index.js +681 -584
- package/dist/start.d.ts +2 -4
- package/dist/types.d.ts +12 -18
- package/dist/utils.d.ts +11 -2
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -20461,11 +20461,11 @@ var quotes = collect([
|
|
|
20461
20461
|
]);
|
|
20462
20462
|
var export_prompts = import_prompts.default;
|
|
20463
20463
|
// package.json
|
|
20464
|
-
var version = "0.
|
|
20464
|
+
var version = "0.5.1";
|
|
20465
20465
|
|
|
20466
20466
|
// src/config.ts
|
|
20467
|
-
import
|
|
20468
|
-
import
|
|
20467
|
+
import { homedir } from "os";
|
|
20468
|
+
import { join as join2 } from "path";
|
|
20469
20469
|
|
|
20470
20470
|
// node_modules/bun-config/dist/index.js
|
|
20471
20471
|
import { resolve } from "path";
|
|
@@ -20517,24 +20517,27 @@ async function loadConfig({ name, cwd, defaultConfig }) {
|
|
|
20517
20517
|
}
|
|
20518
20518
|
|
|
20519
20519
|
// src/config.ts
|
|
20520
|
+
var defaultConfig = {
|
|
20521
|
+
from: "localhost:5173",
|
|
20522
|
+
to: "stacks.localhost",
|
|
20523
|
+
https: {
|
|
20524
|
+
basePath: "",
|
|
20525
|
+
caCertPath: join2(homedir(), ".stacks", "ssl", `stacks.localhost.ca.crt`),
|
|
20526
|
+
certPath: join2(homedir(), ".stacks", "ssl", `stacks.localhost.crt`),
|
|
20527
|
+
keyPath: join2(homedir(), ".stacks", "ssl", `stacks.localhost.crt.key`)
|
|
20528
|
+
},
|
|
20529
|
+
etcHostsCleanup: true,
|
|
20530
|
+
verbose: true
|
|
20531
|
+
};
|
|
20520
20532
|
var config4 = await loadConfig({
|
|
20521
20533
|
name: "reverse-proxy",
|
|
20522
|
-
defaultConfig
|
|
20523
|
-
from: "localhost:5173",
|
|
20524
|
-
to: "stacks.localhost",
|
|
20525
|
-
https: {
|
|
20526
|
-
caCertPath: path.join(os2.homedir(), ".stacks", "ssl", `stacks.localhost.ca.crt`),
|
|
20527
|
-
certPath: path.join(os2.homedir(), ".stacks", "ssl", `stacks.localhost.crt`),
|
|
20528
|
-
keyPath: path.join(os2.homedir(), ".stacks", "ssl", `stacks.localhost.crt.key`)
|
|
20529
|
-
},
|
|
20530
|
-
etcHostsCleanup: true,
|
|
20531
|
-
verbose: false
|
|
20532
|
-
}
|
|
20534
|
+
defaultConfig
|
|
20533
20535
|
});
|
|
20534
20536
|
|
|
20535
20537
|
// src/https.ts
|
|
20536
|
-
import
|
|
20537
|
-
import
|
|
20538
|
+
import fs3 from "fs/promises";
|
|
20539
|
+
import { homedir as homedir2 } from "os";
|
|
20540
|
+
import { join as join4 } from "path";
|
|
20538
20541
|
|
|
20539
20542
|
// node_modules/@stacksjs/tlsx/dist/index.js
|
|
20540
20543
|
import fs2 from "fs";
|
|
@@ -20558,7 +20561,7 @@ import {
|
|
|
20558
20561
|
dirname as dirname3,
|
|
20559
20562
|
extname as extname2,
|
|
20560
20563
|
isAbsolute as isAbsolute2,
|
|
20561
|
-
join as
|
|
20564
|
+
join as join3,
|
|
20562
20565
|
normalize as normalize2,
|
|
20563
20566
|
parse as parse2,
|
|
20564
20567
|
relative as relative2,
|
|
@@ -20573,7 +20576,7 @@ import process8 from "process";
|
|
|
20573
20576
|
import process102 from "process";
|
|
20574
20577
|
import process182 from "process";
|
|
20575
20578
|
import process112 from "process";
|
|
20576
|
-
import
|
|
20579
|
+
import os2 from "os";
|
|
20577
20580
|
import tty32 from "tty";
|
|
20578
20581
|
import process142 from "process";
|
|
20579
20582
|
import process132 from "process";
|
|
@@ -20582,11 +20585,11 @@ import process162 from "process";
|
|
|
20582
20585
|
import process172 from "process";
|
|
20583
20586
|
import process192 from "process";
|
|
20584
20587
|
import os22 from "os";
|
|
20585
|
-
import
|
|
20588
|
+
import path from "path";
|
|
20586
20589
|
import { resolve as resolve3 } from "path";
|
|
20587
20590
|
import process22 from "process";
|
|
20588
20591
|
import fs from "fs";
|
|
20589
|
-
import
|
|
20592
|
+
import path2 from "path";
|
|
20590
20593
|
var __create3 = Object.create;
|
|
20591
20594
|
var __getProtoOf3 = Object.getPrototypeOf;
|
|
20592
20595
|
var __defProp3 = Object.defineProperty;
|
|
@@ -48110,29 +48113,29 @@ var log2 = {
|
|
|
48110
48113
|
},
|
|
48111
48114
|
echo: (...args) => console.log(...args)
|
|
48112
48115
|
};
|
|
48113
|
-
function userDatabasePath2(
|
|
48114
|
-
return projectPath2(`database/${
|
|
48116
|
+
function userDatabasePath2(path22) {
|
|
48117
|
+
return projectPath2(`database/${path22 || ""}`);
|
|
48115
48118
|
}
|
|
48116
|
-
function appPath2(
|
|
48117
|
-
return projectPath2(`app/${
|
|
48119
|
+
function appPath2(path22) {
|
|
48120
|
+
return projectPath2(`app/${path22 || ""}`);
|
|
48118
48121
|
}
|
|
48119
|
-
function commandsPath2(
|
|
48120
|
-
return appPath2(`Commands/${
|
|
48122
|
+
function commandsPath2(path22) {
|
|
48123
|
+
return appPath2(`Commands/${path22 || ""}`);
|
|
48121
48124
|
}
|
|
48122
|
-
function logsPath2(
|
|
48123
|
-
return storagePath2(`logs/${
|
|
48125
|
+
function logsPath2(path22) {
|
|
48126
|
+
return storagePath2(`logs/${path22 || ""}`);
|
|
48124
48127
|
}
|
|
48125
48128
|
function projectPath2(filePath = "", options2) {
|
|
48126
|
-
let
|
|
48127
|
-
while (
|
|
48128
|
-
|
|
48129
|
-
const finalPath = resolve22(
|
|
48129
|
+
let path22 = process52.cwd();
|
|
48130
|
+
while (path22.includes("storage"))
|
|
48131
|
+
path22 = resolve22(path22, "..");
|
|
48132
|
+
const finalPath = resolve22(path22, filePath);
|
|
48130
48133
|
if (options2?.relative)
|
|
48131
48134
|
return relative2(process52.cwd(), finalPath);
|
|
48132
48135
|
return finalPath;
|
|
48133
48136
|
}
|
|
48134
|
-
function storagePath2(
|
|
48135
|
-
return projectPath2(`storage/${
|
|
48137
|
+
function storagePath2(path22) {
|
|
48138
|
+
return projectPath2(`storage/${path22 || ""}`);
|
|
48136
48139
|
}
|
|
48137
48140
|
var config6 = {
|
|
48138
48141
|
ai: {
|
|
@@ -54219,7 +54222,7 @@ function _supportsColor2(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
54219
54222
|
return min;
|
|
54220
54223
|
}
|
|
54221
54224
|
if (process112.platform === "win32") {
|
|
54222
|
-
const osRelease =
|
|
54225
|
+
const osRelease = os2.release().split(".");
|
|
54223
54226
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
54224
54227
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
54225
54228
|
}
|
|
@@ -56793,35 +56796,37 @@ function deepMerge2(target, source) {
|
|
|
56793
56796
|
function isObject32(item) {
|
|
56794
56797
|
return Boolean(item && typeof item === "object" && !Array.isArray(item));
|
|
56795
56798
|
}
|
|
56796
|
-
async function loadConfig2({ name, cwd, defaultConfig }) {
|
|
56799
|
+
async function loadConfig2({ name, cwd, defaultConfig: defaultConfig2 }) {
|
|
56797
56800
|
const configPath = resolve3(cwd || process22.cwd(), `${name}.config`);
|
|
56798
56801
|
try {
|
|
56799
56802
|
const importedConfig = await import(configPath);
|
|
56800
56803
|
const loadedConfig = importedConfig.default || importedConfig;
|
|
56801
|
-
return deepMerge2(
|
|
56804
|
+
return deepMerge2(defaultConfig2, loadedConfig);
|
|
56802
56805
|
} catch (error) {
|
|
56803
|
-
return
|
|
56804
|
-
}
|
|
56805
|
-
}
|
|
56806
|
+
return defaultConfig2;
|
|
56807
|
+
}
|
|
56808
|
+
}
|
|
56809
|
+
var defaultConfig2 = {
|
|
56810
|
+
altNameIPs: ["127.0.0.1"],
|
|
56811
|
+
altNameURIs: ["localhost"],
|
|
56812
|
+
organizationName: "Local Development",
|
|
56813
|
+
countryName: "US",
|
|
56814
|
+
stateName: "California",
|
|
56815
|
+
localityName: "Playa Vista",
|
|
56816
|
+
commonName: "stacks.localhost",
|
|
56817
|
+
validityDays: 825,
|
|
56818
|
+
hostCertCN: "stacks.localhost",
|
|
56819
|
+
domain: "stacks.localhost",
|
|
56820
|
+
rootCA: { certificate: "", privateKey: "" },
|
|
56821
|
+
basePath: "",
|
|
56822
|
+
caCertPath: path.join(os22.homedir(), ".stacks", "ssl", `stacks.localhost.ca.crt`),
|
|
56823
|
+
certPath: path.join(os22.homedir(), ".stacks", "ssl", `stacks.localhost.crt`),
|
|
56824
|
+
keyPath: path.join(os22.homedir(), ".stacks", "ssl", `stacks.localhost.crt.key`),
|
|
56825
|
+
verbose: false
|
|
56826
|
+
};
|
|
56806
56827
|
var config42 = await loadConfig2({
|
|
56807
56828
|
name: "tls",
|
|
56808
|
-
defaultConfig:
|
|
56809
|
-
altNameIPs: ["127.0.0.1"],
|
|
56810
|
-
altNameURIs: ["localhost"],
|
|
56811
|
-
organizationName: "Local Development",
|
|
56812
|
-
countryName: "US",
|
|
56813
|
-
stateName: "California",
|
|
56814
|
-
localityName: "Playa Vista",
|
|
56815
|
-
commonName: "stacks.localhost",
|
|
56816
|
-
validityDays: 825,
|
|
56817
|
-
hostCertCN: "stacks.localhost",
|
|
56818
|
-
domain: "stacks.localhost",
|
|
56819
|
-
rootCAObject: { certificate: "", privateKey: "" },
|
|
56820
|
-
caCertPath: path2.join(os22.homedir(), ".stacks", "ssl", `stacks.localhost.ca.crt`),
|
|
56821
|
-
certPath: path2.join(os22.homedir(), ".stacks", "ssl", `stacks.localhost.crt`),
|
|
56822
|
-
keyPath: path2.join(os22.homedir(), ".stacks", "ssl", `stacks.localhost.crt.key`),
|
|
56823
|
-
verbose: false
|
|
56824
|
-
}
|
|
56829
|
+
defaultConfig: defaultConfig2
|
|
56825
56830
|
});
|
|
56826
56831
|
var import_node_forge = __toESM3(require_lib2(), 1);
|
|
56827
56832
|
function makeNumberPositive(hexString) {
|
|
@@ -56837,7 +56842,7 @@ function findFoldersWithFile(rootDir, fileName) {
|
|
|
56837
56842
|
try {
|
|
56838
56843
|
const files = fs.readdirSync(dir);
|
|
56839
56844
|
for (const file of files) {
|
|
56840
|
-
const filePath =
|
|
56845
|
+
const filePath = path2.join(dir, file);
|
|
56841
56846
|
const stats = fs.lstatSync(filePath);
|
|
56842
56847
|
if (stats.isDirectory()) {
|
|
56843
56848
|
search(filePath);
|
|
@@ -56955,12 +56960,12 @@ async function createRootCA(options22 = {}) {
|
|
|
56955
56960
|
async function generateCertificate(options22) {
|
|
56956
56961
|
debugLog("cert", "Generating new certificate", options22.verbose);
|
|
56957
56962
|
debugLog("cert", `Options: ${JSON.stringify(options22)}`, options22.verbose);
|
|
56958
|
-
if (!options22.
|
|
56963
|
+
if (!options22.rootCA?.certificate || !options22.rootCA?.privateKey) {
|
|
56959
56964
|
throw new Error("Root CA certificate and private key are required");
|
|
56960
56965
|
}
|
|
56961
|
-
const caCert = import_node_forge2.pki.certificateFromPem(options22.
|
|
56962
|
-
const caKey = import_node_forge2.pki.privateKeyFromPem(options22.
|
|
56963
|
-
debugLog("cert", "Generating 2048-bit RSA key pair for host certificate", options22
|
|
56966
|
+
const caCert = import_node_forge2.pki.certificateFromPem(options22.rootCA.certificate);
|
|
56967
|
+
const caKey = import_node_forge2.pki.privateKeyFromPem(options22.rootCA.privateKey);
|
|
56968
|
+
debugLog("cert", "Generating 2048-bit RSA key pair for host certificate", options22.verbose);
|
|
56964
56969
|
const keySize = 2048;
|
|
56965
56970
|
const { privateKey, publicKey } = import_node_forge2.pki.rsa.generateKeyPair(keySize);
|
|
56966
56971
|
const attributes = options22.certificateAttributes || [
|
|
@@ -57033,8 +57038,8 @@ async function addCertToSystemTrustStoreAndSaveCert(cert, caCert, options22) {
|
|
|
57033
57038
|
}
|
|
57034
57039
|
function storeCertificate(cert, options22) {
|
|
57035
57040
|
debugLog("storage", `Storing certificate and private key with options: ${JSON.stringify(options22)}`, options22?.verbose);
|
|
57036
|
-
const certPath = options22?.certPath || config42.certPath;
|
|
57037
|
-
const certKeyPath = options22?.keyPath || config42.keyPath;
|
|
57041
|
+
const certPath = path3.join(options22?.basePath || config42.basePath, options22?.certPath || config42.certPath);
|
|
57042
|
+
const certKeyPath = path3.join(options22?.basePath || config42.basePath, options22?.keyPath || config42.keyPath);
|
|
57038
57043
|
debugLog("storage", `Certificate path: ${certPath}`, options22?.verbose);
|
|
57039
57044
|
debugLog("storage", `Private key path: ${certKeyPath}`, options22?.verbose);
|
|
57040
57045
|
const certDir = path3.dirname(certPath);
|
|
@@ -57056,7 +57061,7 @@ function storeCertificate(cert, options22) {
|
|
|
57056
57061
|
}
|
|
57057
57062
|
function storeCACertificate(caCert, options22) {
|
|
57058
57063
|
debugLog("storage", "Storing CA certificate", options22?.verbose);
|
|
57059
|
-
const caCertPath = options22?.caCertPath || config42.caCertPath;
|
|
57064
|
+
const caCertPath = path3.join(options22?.basePath || config42.basePath, options22?.caCertPath || config42.caCertPath);
|
|
57060
57065
|
debugLog("storage", `CA certificate path: ${caCertPath}`, options22?.verbose);
|
|
57061
57066
|
const caCertDir = path3.dirname(caCertPath);
|
|
57062
57067
|
if (!fs2.existsSync(caCertDir)) {
|
|
@@ -57078,114 +57083,171 @@ function debugLog2(category, message, verbose) {
|
|
|
57078
57083
|
console.debug(`[rpx:${category}] ${message}`);
|
|
57079
57084
|
}
|
|
57080
57085
|
}
|
|
57081
|
-
function
|
|
57082
|
-
if (
|
|
57086
|
+
function extractHostname(options3) {
|
|
57087
|
+
if (isMultiProxyOptions(options3)) {
|
|
57083
57088
|
return options3.proxies.map((proxy) => {
|
|
57084
|
-
const
|
|
57085
|
-
return
|
|
57089
|
+
const domain = proxy.to || "stacks.localhost";
|
|
57090
|
+
return domain.startsWith("http") ? new URL(domain).hostname : domain;
|
|
57086
57091
|
});
|
|
57087
57092
|
}
|
|
57088
|
-
|
|
57089
|
-
|
|
57093
|
+
if (isSingleProxyOptions(options3)) {
|
|
57094
|
+
const domain = options3.to || "stacks.localhost";
|
|
57095
|
+
return [domain.startsWith("http") ? new URL(domain).hostname : domain];
|
|
57096
|
+
}
|
|
57097
|
+
return ["stacks.localhost"];
|
|
57098
|
+
}
|
|
57099
|
+
function isValidRootCA(value) {
|
|
57100
|
+
return typeof value === "object" && value !== null && "certificate" in value && "privateKey" in value && typeof value.certificate === "string" && typeof value.privateKey === "string";
|
|
57101
|
+
}
|
|
57102
|
+
function getPrimaryDomain(options3) {
|
|
57103
|
+
if (!options3)
|
|
57104
|
+
return "stacks.localhost";
|
|
57105
|
+
if (isMultiProxyOptions(options3) && options3.proxies.length > 0)
|
|
57106
|
+
return options3.proxies[0].to || "stacks.localhost";
|
|
57107
|
+
if (isSingleProxyOptions(options3))
|
|
57108
|
+
return options3.to || "stacks.localhost";
|
|
57109
|
+
return "stacks.localhost";
|
|
57110
|
+
}
|
|
57111
|
+
function isMultiProxyConfig(options3) {
|
|
57112
|
+
return "proxies" in options3 && Array.isArray(options3.proxies);
|
|
57113
|
+
}
|
|
57114
|
+
function isMultiProxyOptions(options3) {
|
|
57115
|
+
return "proxies" in options3 && Array.isArray(options3.proxies);
|
|
57116
|
+
}
|
|
57117
|
+
function isSingleProxyOptions(options3) {
|
|
57118
|
+
return "to" in options3 && typeof options3.to === "string";
|
|
57090
57119
|
}
|
|
57091
57120
|
|
|
57092
57121
|
// src/https.ts
|
|
57093
57122
|
var cachedSSLConfig = null;
|
|
57094
|
-
function
|
|
57095
|
-
|
|
57123
|
+
function resolveSSLPaths(options3, defaultConfig3) {
|
|
57124
|
+
const domain = isMultiProxyConfig(options3) ? options3.proxies[0].to || "stacks.localhost" : options3.to || "stacks.localhost";
|
|
57125
|
+
if (typeof options3.https === "object" && typeof defaultConfig3.https === "object") {
|
|
57126
|
+
const hasAllPaths = options3.https.caCertPath && options3.https.certPath && options3.https.keyPath;
|
|
57127
|
+
if (hasAllPaths) {
|
|
57128
|
+
const baseConfig = httpsConfig({
|
|
57129
|
+
...options3,
|
|
57130
|
+
to: domain,
|
|
57131
|
+
https: defaultConfig3.https
|
|
57132
|
+
});
|
|
57133
|
+
const altNameIPs = options3.https.altNameIPs?.filter((ip) => ip !== undefined) || baseConfig.altNameIPs;
|
|
57134
|
+
const altNameURIs = options3.https.altNameURIs?.filter((uri) => uri !== undefined) || baseConfig.altNameURIs;
|
|
57135
|
+
return {
|
|
57136
|
+
...baseConfig,
|
|
57137
|
+
caCertPath: options3.https.caCertPath || baseConfig.caCertPath,
|
|
57138
|
+
certPath: options3.https.certPath || baseConfig.certPath,
|
|
57139
|
+
keyPath: options3.https.keyPath || baseConfig.keyPath,
|
|
57140
|
+
basePath: options3.https.basePath || baseConfig.basePath,
|
|
57141
|
+
commonName: options3.https.commonName || baseConfig.commonName,
|
|
57142
|
+
organizationName: options3.https.organizationName || baseConfig.organizationName,
|
|
57143
|
+
countryName: options3.https.countryName || baseConfig.countryName,
|
|
57144
|
+
stateName: options3.https.stateName || baseConfig.stateName,
|
|
57145
|
+
localityName: options3.https.localityName || baseConfig.localityName,
|
|
57146
|
+
validityDays: options3.https.validityDays || baseConfig.validityDays,
|
|
57147
|
+
altNameIPs,
|
|
57148
|
+
altNameURIs,
|
|
57149
|
+
verbose: options3.verbose || baseConfig.verbose
|
|
57150
|
+
};
|
|
57151
|
+
}
|
|
57152
|
+
}
|
|
57153
|
+
return httpsConfig({
|
|
57154
|
+
...options3,
|
|
57155
|
+
to: domain
|
|
57156
|
+
});
|
|
57096
57157
|
}
|
|
57097
57158
|
function generateWildcardPatterns(domain) {
|
|
57098
57159
|
const patterns = new Set;
|
|
57099
57160
|
patterns.add(domain);
|
|
57100
57161
|
const parts = domain.split(".");
|
|
57101
|
-
if (parts.length >= 2)
|
|
57162
|
+
if (parts.length >= 2)
|
|
57102
57163
|
patterns.add(`*.${parts.slice(1).join(".")}`);
|
|
57103
|
-
}
|
|
57104
57164
|
return Array.from(patterns);
|
|
57105
57165
|
}
|
|
57106
|
-
function
|
|
57107
|
-
const
|
|
57108
|
-
|
|
57109
|
-
|
|
57110
|
-
|
|
57111
|
-
|
|
57112
|
-
|
|
57113
|
-
|
|
57114
|
-
|
|
57115
|
-
|
|
57116
|
-
}
|
|
57117
|
-
|
|
57118
|
-
|
|
57119
|
-
debugLog2("ssl", `Using HTTPS config: ${JSON.stringify(httpsConfig)}`, verbose);
|
|
57120
|
-
const allPatterns = new Set;
|
|
57121
|
-
domains.forEach((domain) => {
|
|
57122
|
-
allPatterns.add(domain);
|
|
57123
|
-
generateWildcardPatterns(domain).forEach((pattern) => allPatterns.add(pattern));
|
|
57124
|
-
});
|
|
57125
|
-
allPatterns.add("localhost");
|
|
57126
|
-
allPatterns.add("*.localhost");
|
|
57127
|
-
const uniqueDomains = Array.from(allPatterns);
|
|
57128
|
-
debugLog2("ssl", `Generated domain patterns: ${uniqueDomains.join(", ")}`, verbose);
|
|
57166
|
+
function generateSSLPaths(options3) {
|
|
57167
|
+
const domain = getPrimaryDomain(options3);
|
|
57168
|
+
let basePath = "";
|
|
57169
|
+
if (typeof options3?.https === "object") {
|
|
57170
|
+
basePath = options3.https.basePath || "";
|
|
57171
|
+
return {
|
|
57172
|
+
caCertPath: options3.https.caCertPath || join4(basePath, `${domain}.ca.crt`),
|
|
57173
|
+
certPath: options3.https.certPath || join4(basePath, `${domain}.crt`),
|
|
57174
|
+
keyPath: options3.https.keyPath || join4(basePath, `${domain}.key`)
|
|
57175
|
+
};
|
|
57176
|
+
}
|
|
57177
|
+
const sslBase = basePath || join4(homedir2(), ".stacks", "ssl");
|
|
57178
|
+
const sanitizedDomain = domain.replace(/\*/g, "wildcard");
|
|
57129
57179
|
return {
|
|
57130
|
-
|
|
57131
|
-
|
|
57132
|
-
|
|
57133
|
-
certPath: httpsConfig?.certPath ?? path4.join(sslBase, "rpx.crt"),
|
|
57134
|
-
keyPath: httpsConfig?.keyPath ?? path4.join(sslBase, "rpx.key"),
|
|
57135
|
-
altNameIPs: httpsConfig?.altNameIPs ?? ["127.0.0.1", "::1"],
|
|
57136
|
-
altNameURIs: httpsConfig?.altNameURIs ?? [],
|
|
57137
|
-
commonName: httpsConfig?.commonName ?? domains[0],
|
|
57138
|
-
organizationName: httpsConfig?.organizationName ?? "Local Development",
|
|
57139
|
-
countryName: httpsConfig?.countryName ?? "US",
|
|
57140
|
-
stateName: httpsConfig?.stateName ?? "California",
|
|
57141
|
-
localityName: httpsConfig?.localityName ?? "Playa Vista",
|
|
57142
|
-
validityDays: httpsConfig?.validityDays ?? 825,
|
|
57143
|
-
verbose: verbose ?? false,
|
|
57144
|
-
subjectAltNames: uniqueDomains.map((domain) => ({
|
|
57145
|
-
type: 2,
|
|
57146
|
-
value: domain
|
|
57147
|
-
}))
|
|
57180
|
+
caCertPath: join4(sslBase, `${sanitizedDomain}.ca.crt`),
|
|
57181
|
+
certPath: join4(sslBase, `${sanitizedDomain}.crt`),
|
|
57182
|
+
keyPath: join4(sslBase, `${sanitizedDomain}.key`)
|
|
57148
57183
|
};
|
|
57149
57184
|
}
|
|
57150
|
-
function
|
|
57151
|
-
const
|
|
57152
|
-
|
|
57153
|
-
|
|
57154
|
-
|
|
57155
|
-
|
|
57156
|
-
|
|
57157
|
-
|
|
57158
|
-
|
|
57159
|
-
|
|
57160
|
-
|
|
57161
|
-
|
|
57162
|
-
|
|
57163
|
-
|
|
57164
|
-
|
|
57165
|
-
|
|
57166
|
-
verbose
|
|
57167
|
-
};
|
|
57185
|
+
function getAllDomains(options3) {
|
|
57186
|
+
const domains = new Set;
|
|
57187
|
+
if (isMultiProxyOptions(options3)) {
|
|
57188
|
+
options3.proxies.forEach((proxy) => {
|
|
57189
|
+
const domain = proxy.to || "stacks.localhost";
|
|
57190
|
+
generateWildcardPatterns(domain).forEach((pattern) => domains.add(pattern));
|
|
57191
|
+
});
|
|
57192
|
+
} else if (isSingleProxyOptions(options3)) {
|
|
57193
|
+
const domain = options3.to || "stacks.localhost";
|
|
57194
|
+
generateWildcardPatterns(domain).forEach((pattern) => domains.add(pattern));
|
|
57195
|
+
} else {
|
|
57196
|
+
domains.add("stacks.localhost");
|
|
57197
|
+
}
|
|
57198
|
+
domains.add("localhost");
|
|
57199
|
+
domains.add("*.localhost");
|
|
57200
|
+
return domains;
|
|
57168
57201
|
}
|
|
57169
|
-
function
|
|
57170
|
-
|
|
57202
|
+
async function loadSSLConfig(options3) {
|
|
57203
|
+
debugLog2("ssl", `Loading SSL configuration`, options3.verbose);
|
|
57204
|
+
const mergedOptions = {
|
|
57205
|
+
...config4,
|
|
57206
|
+
...options3
|
|
57207
|
+
};
|
|
57208
|
+
options3.https = httpsConfig(mergedOptions);
|
|
57209
|
+
if (!options3.https?.keyPath && !options3.https?.certPath) {
|
|
57210
|
+
debugLog2("ssl", "No SSL configuration provided", options3.verbose);
|
|
57211
|
+
return null;
|
|
57212
|
+
}
|
|
57213
|
+
if (options3.https?.keyPath && !options3.https?.certPath || !options3.https?.keyPath && options3.https?.certPath) {
|
|
57214
|
+
const missing = !options3.https?.keyPath ? "keyPath" : "certPath";
|
|
57215
|
+
debugLog2("ssl", `Invalid SSL configuration - missing ${missing}`, options3.verbose);
|
|
57216
|
+
throw new Error(`SSL Configuration requires both keyPath and certPath. Missing: ${missing}`);
|
|
57217
|
+
}
|
|
57218
|
+
try {
|
|
57219
|
+
if (!options3.https?.keyPath || !options3.https?.certPath)
|
|
57220
|
+
return null;
|
|
57221
|
+
try {
|
|
57222
|
+
debugLog2("ssl", "Reading SSL certificate files", options3.verbose);
|
|
57223
|
+
const key = await fs3.readFile(options3.https?.keyPath, "utf8");
|
|
57224
|
+
const cert = await fs3.readFile(options3.https?.certPath, "utf8");
|
|
57225
|
+
debugLog2("ssl", "SSL configuration loaded successfully", options3.verbose);
|
|
57226
|
+
return { key, cert };
|
|
57227
|
+
} catch (error) {
|
|
57228
|
+
debugLog2("ssl", `Failed to read certificates: ${error}`, options3.verbose);
|
|
57229
|
+
return null;
|
|
57230
|
+
}
|
|
57231
|
+
} catch (err3) {
|
|
57232
|
+
debugLog2("ssl", `SSL configuration error: ${err3}`, options3.verbose);
|
|
57233
|
+
throw err3;
|
|
57234
|
+
}
|
|
57171
57235
|
}
|
|
57172
57236
|
async function generateCertificate2(options3) {
|
|
57173
57237
|
if (cachedSSLConfig) {
|
|
57174
|
-
|
|
57175
|
-
debugLog2("ssl", "Using cached SSL configuration", verbose2);
|
|
57238
|
+
debugLog2("ssl", "Using cached SSL configuration", options3.verbose);
|
|
57176
57239
|
return;
|
|
57177
57240
|
}
|
|
57178
|
-
const domains =
|
|
57179
|
-
|
|
57180
|
-
|
|
57181
|
-
const rootCAConfig = generateRootCAConfig(verbose);
|
|
57241
|
+
const domains = isMultiProxyOptions(options3) ? options3.proxies.map((proxy) => proxy.to) : [options3.to];
|
|
57242
|
+
debugLog2("ssl", `Generating certificate for domains: ${domains.join(", ")}`, options3.verbose);
|
|
57243
|
+
const rootCAConfig = httpsConfig(options3, options3.verbose);
|
|
57182
57244
|
log.info("Generating Root CA certificate...");
|
|
57183
57245
|
const caCert = await createRootCA(rootCAConfig);
|
|
57184
|
-
const hostConfig =
|
|
57246
|
+
const hostConfig = httpsConfig(options3, options3.verbose);
|
|
57185
57247
|
log.info(`Generating host certificate for: ${domains.join(", ")}`);
|
|
57186
57248
|
const hostCert = await generateCertificate({
|
|
57187
57249
|
...hostConfig,
|
|
57188
|
-
|
|
57250
|
+
rootCA: {
|
|
57189
57251
|
certificate: caCert.certificate,
|
|
57190
57252
|
privateKey: caCert.privateKey
|
|
57191
57253
|
}
|
|
@@ -57197,69 +57259,116 @@ async function generateCertificate2(options3) {
|
|
|
57197
57259
|
ca: caCert.certificate
|
|
57198
57260
|
};
|
|
57199
57261
|
log.success(`Certificate generated successfully for ${domains.length} domain${domains.length > 1 ? "s" : ""}`);
|
|
57200
|
-
debugLog2("ssl", `Certificate includes domains: ${domains.join(", ")}`, verbose);
|
|
57262
|
+
debugLog2("ssl", `Certificate includes domains: ${domains.join(", ")}`, options3.verbose);
|
|
57201
57263
|
}
|
|
57202
57264
|
function getSSLConfig() {
|
|
57203
57265
|
return cachedSSLConfig;
|
|
57204
57266
|
}
|
|
57267
|
+
async function checkExistingCertificates(options3) {
|
|
57268
|
+
const name = getPrimaryDomain(options3);
|
|
57269
|
+
const paths = generateSSLPaths(options3);
|
|
57270
|
+
try {
|
|
57271
|
+
debugLog2("ssl", `Checking certificates for ${name} at paths:`, options3?.verbose);
|
|
57272
|
+
debugLog2("ssl", `CA: ${paths.caCertPath}`, options3?.verbose);
|
|
57273
|
+
debugLog2("ssl", `Cert: ${paths.certPath}`, options3?.verbose);
|
|
57274
|
+
debugLog2("ssl", `Key: ${paths.keyPath}`, options3?.verbose);
|
|
57275
|
+
const key = await fs3.readFile(paths.keyPath, "utf8");
|
|
57276
|
+
const cert = await fs3.readFile(paths.certPath, "utf8");
|
|
57277
|
+
let ca;
|
|
57278
|
+
if (paths.caCertPath) {
|
|
57279
|
+
try {
|
|
57280
|
+
ca = await fs3.readFile(paths.caCertPath, "utf8");
|
|
57281
|
+
} catch (err3) {
|
|
57282
|
+
debugLog2("ssl", `Failed to read CA cert: ${err3}`, options3?.verbose);
|
|
57283
|
+
}
|
|
57284
|
+
}
|
|
57285
|
+
return { key, cert, ca };
|
|
57286
|
+
} catch (err3) {
|
|
57287
|
+
debugLog2("ssl", `Failed to read certificates: ${err3}`, options3?.verbose);
|
|
57288
|
+
return null;
|
|
57289
|
+
}
|
|
57290
|
+
}
|
|
57291
|
+
function httpsConfig(options3, verbose) {
|
|
57292
|
+
const primaryDomain = getPrimaryDomain(options3);
|
|
57293
|
+
debugLog2("ssl", `Primary domain: ${primaryDomain}`, verbose);
|
|
57294
|
+
const defaultPaths = generateSSLPaths(options3);
|
|
57295
|
+
if (typeof options3.https === "object") {
|
|
57296
|
+
const config5 = {
|
|
57297
|
+
domain: primaryDomain,
|
|
57298
|
+
hostCertCN: primaryDomain,
|
|
57299
|
+
basePath: options3.https.basePath || "",
|
|
57300
|
+
caCertPath: options3.https.caCertPath || defaultPaths.caCertPath,
|
|
57301
|
+
certPath: options3.https.certPath || defaultPaths.certPath,
|
|
57302
|
+
keyPath: options3.https.keyPath || defaultPaths.keyPath,
|
|
57303
|
+
altNameIPs: ["127.0.0.1", "::1"],
|
|
57304
|
+
altNameURIs: [],
|
|
57305
|
+
commonName: options3.https.commonName || primaryDomain,
|
|
57306
|
+
organizationName: options3.https.organizationName || "Local Development",
|
|
57307
|
+
countryName: options3.https.countryName || "US",
|
|
57308
|
+
stateName: options3.https.stateName || "California",
|
|
57309
|
+
localityName: options3.https.localityName || "Playa Vista",
|
|
57310
|
+
validityDays: options3.https.validityDays || 825,
|
|
57311
|
+
verbose: verbose || false,
|
|
57312
|
+
subjectAltNames: Array.from(getAllDomains(options3)).map((domain) => ({
|
|
57313
|
+
type: 2,
|
|
57314
|
+
value: domain
|
|
57315
|
+
}))
|
|
57316
|
+
};
|
|
57317
|
+
if (isValidRootCA(options3.https.rootCA)) {
|
|
57318
|
+
config5.rootCA = options3.https.rootCA;
|
|
57319
|
+
}
|
|
57320
|
+
return config5;
|
|
57321
|
+
}
|
|
57322
|
+
return {
|
|
57323
|
+
domain: primaryDomain,
|
|
57324
|
+
hostCertCN: primaryDomain,
|
|
57325
|
+
basePath: "",
|
|
57326
|
+
...defaultPaths,
|
|
57327
|
+
altNameIPs: ["127.0.0.1", "::1"],
|
|
57328
|
+
altNameURIs: [],
|
|
57329
|
+
commonName: primaryDomain,
|
|
57330
|
+
organizationName: "Local Development",
|
|
57331
|
+
countryName: "US",
|
|
57332
|
+
stateName: "California",
|
|
57333
|
+
localityName: "Playa Vista",
|
|
57334
|
+
validityDays: 825,
|
|
57335
|
+
verbose: verbose || false,
|
|
57336
|
+
subjectAltNames: Array.from(getAllDomains(options3)).map((domain) => ({
|
|
57337
|
+
type: 2,
|
|
57338
|
+
value: domain
|
|
57339
|
+
}))
|
|
57340
|
+
};
|
|
57341
|
+
}
|
|
57205
57342
|
|
|
57206
57343
|
// src/start.ts
|
|
57207
|
-
import * as fs5 from "fs";
|
|
57208
57344
|
import * as http from "http";
|
|
57209
57345
|
import * as https from "https";
|
|
57210
57346
|
import * as net from "net";
|
|
57211
57347
|
import process9 from "process";
|
|
57212
57348
|
|
|
57213
57349
|
// src/hosts.ts
|
|
57214
|
-
import {
|
|
57215
|
-
import
|
|
57216
|
-
import
|
|
57217
|
-
import
|
|
57350
|
+
import { exec as exec2 } from "child_process";
|
|
57351
|
+
import fs5 from "fs";
|
|
57352
|
+
import os3 from "os";
|
|
57353
|
+
import path4 from "path";
|
|
57218
57354
|
import process3 from "process";
|
|
57219
|
-
|
|
57220
|
-
|
|
57221
|
-
|
|
57222
|
-
|
|
57223
|
-
|
|
57224
|
-
|
|
57225
|
-
|
|
57226
|
-
|
|
57227
|
-
|
|
57228
|
-
|
|
57229
|
-
|
|
57230
|
-
fs3.writeFileSync(tmpFile, currentContent + content, "utf8");
|
|
57231
|
-
} else {
|
|
57232
|
-
fs3.writeFileSync(tmpFile, content, "utf8");
|
|
57233
|
-
}
|
|
57234
|
-
const sudo = spawn("sudo", ["cp", tmpFile, hostsFilePath]);
|
|
57235
|
-
sudo.on("close", (code) => {
|
|
57236
|
-
try {
|
|
57237
|
-
fs3.unlinkSync(tmpFile);
|
|
57238
|
-
if (code === 0)
|
|
57239
|
-
resolve4();
|
|
57240
|
-
else
|
|
57241
|
-
reject(new Error(`sudo process exited with code ${code}`));
|
|
57242
|
-
} catch (err3) {
|
|
57243
|
-
reject(err3);
|
|
57244
|
-
}
|
|
57245
|
-
});
|
|
57246
|
-
sudo.on("error", (err3) => {
|
|
57247
|
-
try {
|
|
57248
|
-
fs3.unlinkSync(tmpFile);
|
|
57249
|
-
} catch {
|
|
57250
|
-
}
|
|
57251
|
-
reject(err3);
|
|
57252
|
-
});
|
|
57253
|
-
} catch (err3) {
|
|
57254
|
-
reject(err3);
|
|
57255
|
-
}
|
|
57256
|
-
});
|
|
57355
|
+
import { promisify } from "util";
|
|
57356
|
+
var execAsync = promisify(exec2);
|
|
57357
|
+
var hostsFilePath = process3.platform === "win32" ? path4.join(process3.env.windir || "C:\\Windows", "System32", "drivers", "etc", "hosts") : "/etc/hosts";
|
|
57358
|
+
async function execSudo(command) {
|
|
57359
|
+
if (process3.platform === "win32")
|
|
57360
|
+
throw new Error("Administrator privileges required on Windows");
|
|
57361
|
+
try {
|
|
57362
|
+
await execAsync(`sudo ${command}`);
|
|
57363
|
+
} catch (error) {
|
|
57364
|
+
throw new Error(`Failed to execute sudo command: ${error.message}`);
|
|
57365
|
+
}
|
|
57257
57366
|
}
|
|
57258
57367
|
async function addHosts(hosts, verbose) {
|
|
57259
57368
|
debugLog2("hosts", `Adding hosts: ${hosts.join(", ")}`, verbose);
|
|
57260
57369
|
debugLog2("hosts", `Using hosts file at: ${hostsFilePath}`, verbose);
|
|
57261
57370
|
try {
|
|
57262
|
-
const existingContent = await
|
|
57371
|
+
const existingContent = await fs5.promises.readFile(hostsFilePath, "utf-8");
|
|
57263
57372
|
const newEntries = hosts.filter((host) => {
|
|
57264
57373
|
const ipv4Entry = `127.0.0.1 ${host}`;
|
|
57265
57374
|
const ipv6Entry = `::1 ${host}`;
|
|
@@ -57275,35 +57384,29 @@ async function addHosts(hosts, verbose) {
|
|
|
57275
57384
|
127.0.0.1 ${host}
|
|
57276
57385
|
::1 ${host}`).join(`
|
|
57277
57386
|
`);
|
|
57387
|
+
const tmpFile = path4.join(os3.tmpdir(), "hosts.tmp");
|
|
57388
|
+
await fs5.promises.writeFile(tmpFile, existingContent + hostEntries, "utf8");
|
|
57278
57389
|
try {
|
|
57279
|
-
await
|
|
57390
|
+
await execSudo(`cp "${tmpFile}" "${hostsFilePath}"`);
|
|
57280
57391
|
log.success(`Added new hosts: ${newEntries.join(", ")}`);
|
|
57281
|
-
} catch (
|
|
57282
|
-
|
|
57283
|
-
|
|
57284
|
-
|
|
57285
|
-
await sudoWrite("append", hostEntries);
|
|
57286
|
-
log.success(`Added new hosts with sudo: ${newEntries.join(", ")}`);
|
|
57287
|
-
} catch (sudoErr) {
|
|
57288
|
-
log.error("Failed to modify hosts file automatically");
|
|
57289
|
-
log.warn("Please add these entries to your hosts file manually:");
|
|
57290
|
-
hostEntries.split(`
|
|
57392
|
+
} catch (error) {
|
|
57393
|
+
log.error("Failed to modify hosts file automatically");
|
|
57394
|
+
log.warn("Please add these entries to your hosts file manually:");
|
|
57395
|
+
hostEntries.split(`
|
|
57291
57396
|
`).forEach((entry) => log.warn(entry));
|
|
57292
|
-
|
|
57293
|
-
|
|
57397
|
+
if (process3.platform === "win32") {
|
|
57398
|
+
log.warn(`
|
|
57294
57399
|
On Windows:`);
|
|
57295
|
-
|
|
57296
|
-
|
|
57297
|
-
} else {
|
|
57298
|
-
log.warn(`
|
|
57299
|
-
On Unix systems:`);
|
|
57300
|
-
log.warn(`sudo nano ${hostsFilePath}`);
|
|
57301
|
-
}
|
|
57302
|
-
throw new Error("Failed to modify hosts file: manual intervention required");
|
|
57303
|
-
}
|
|
57400
|
+
log.warn("1. Run notepad as administrator");
|
|
57401
|
+
log.warn("2. Open C:\\Windows\\System32\\drivers\\etc\\hosts");
|
|
57304
57402
|
} else {
|
|
57305
|
-
|
|
57403
|
+
log.warn(`
|
|
57404
|
+
On Unix systems:`);
|
|
57405
|
+
log.warn(`sudo nano ${hostsFilePath}`);
|
|
57306
57406
|
}
|
|
57407
|
+
throw new Error("Failed to modify hosts file: manual intervention required");
|
|
57408
|
+
} finally {
|
|
57409
|
+
fs5.unlinkSync(tmpFile);
|
|
57307
57410
|
}
|
|
57308
57411
|
} catch (err3) {
|
|
57309
57412
|
const error = err3;
|
|
@@ -57314,7 +57417,7 @@ On Unix systems:`);
|
|
|
57314
57417
|
async function removeHosts(hosts, verbose) {
|
|
57315
57418
|
debugLog2("hosts", `Removing hosts: ${hosts.join(", ")}`, verbose);
|
|
57316
57419
|
try {
|
|
57317
|
-
const content = await
|
|
57420
|
+
const content = await fs5.promises.readFile(hostsFilePath, "utf-8");
|
|
57318
57421
|
const lines = content.split(`
|
|
57319
57422
|
`);
|
|
57320
57423
|
const filteredLines = lines.filter((line, index) => {
|
|
@@ -57329,38 +57432,32 @@ async function removeHosts(hosts, verbose) {
|
|
|
57329
57432
|
const newContent = `${filteredLines.join(`
|
|
57330
57433
|
`)}
|
|
57331
57434
|
`;
|
|
57435
|
+
const tmpFile = path4.join(os3.tmpdir(), "hosts.tmp");
|
|
57436
|
+
await fs5.promises.writeFile(tmpFile, newContent, "utf8");
|
|
57332
57437
|
try {
|
|
57333
|
-
await
|
|
57438
|
+
await execSudo(`cp "${tmpFile}" "${hostsFilePath}"`);
|
|
57334
57439
|
log.success("Hosts removed successfully");
|
|
57335
|
-
} catch (
|
|
57336
|
-
|
|
57337
|
-
|
|
57338
|
-
|
|
57339
|
-
|
|
57340
|
-
|
|
57341
|
-
|
|
57342
|
-
|
|
57343
|
-
|
|
57344
|
-
|
|
57345
|
-
log.warn("# Added by rpx");
|
|
57346
|
-
log.warn(`127.0.0.1 ${host}`);
|
|
57347
|
-
log.warn(`::1 ${host}`);
|
|
57348
|
-
});
|
|
57349
|
-
if (process3.platform === "win32") {
|
|
57350
|
-
log.warn(`
|
|
57440
|
+
} catch (error) {
|
|
57441
|
+
log.error("Failed to modify hosts file automatically");
|
|
57442
|
+
log.warn("Please remove these entries from your hosts file manually:");
|
|
57443
|
+
hosts.forEach((host) => {
|
|
57444
|
+
log.warn("# Added by rpx");
|
|
57445
|
+
log.warn(`127.0.0.1 ${host}`);
|
|
57446
|
+
log.warn(`::1 ${host}`);
|
|
57447
|
+
});
|
|
57448
|
+
if (process3.platform === "win32") {
|
|
57449
|
+
log.warn(`
|
|
57351
57450
|
On Windows:`);
|
|
57352
|
-
|
|
57353
|
-
|
|
57354
|
-
} else {
|
|
57355
|
-
log.warn(`
|
|
57356
|
-
On Unix systems:`);
|
|
57357
|
-
log.warn(`sudo nano ${hostsFilePath}`);
|
|
57358
|
-
}
|
|
57359
|
-
throw new Error("Failed to modify hosts file: manual intervention required");
|
|
57360
|
-
}
|
|
57451
|
+
log.warn("1. Run notepad as administrator");
|
|
57452
|
+
log.warn("2. Open C:\\Windows\\System32\\drivers\\etc\\hosts");
|
|
57361
57453
|
} else {
|
|
57362
|
-
|
|
57454
|
+
log.warn(`
|
|
57455
|
+
On Unix systems:`);
|
|
57456
|
+
log.warn(`sudo nano ${hostsFilePath}`);
|
|
57363
57457
|
}
|
|
57458
|
+
throw new Error("Failed to modify hosts file: manual intervention required");
|
|
57459
|
+
} finally {
|
|
57460
|
+
fs5.unlinkSync(tmpFile);
|
|
57364
57461
|
}
|
|
57365
57462
|
} catch (err3) {
|
|
57366
57463
|
const error = err3;
|
|
@@ -57370,7 +57467,7 @@ On Unix systems:`);
|
|
|
57370
57467
|
}
|
|
57371
57468
|
async function checkHosts(hosts, verbose) {
|
|
57372
57469
|
debugLog2("hosts", `Checking hosts: ${hosts}`, verbose);
|
|
57373
|
-
const content = await
|
|
57470
|
+
const content = await fs5.promises.readFile(hostsFilePath, "utf-8");
|
|
57374
57471
|
return hosts.map((host) => {
|
|
57375
57472
|
const ipv4Entry = `127.0.0.1 ${host}`;
|
|
57376
57473
|
const ipv6Entry = `::1 ${host}`;
|
|
@@ -57424,39 +57521,6 @@ process9.on("uncaughtException", (err3) => {
|
|
|
57424
57521
|
log.error("Uncaught exception:", err3);
|
|
57425
57522
|
cleanup();
|
|
57426
57523
|
});
|
|
57427
|
-
async function loadSSLConfig(options3) {
|
|
57428
|
-
debugLog2("ssl", `Loading SSL configuration`, options3.verbose);
|
|
57429
|
-
if (options3.https === true)
|
|
57430
|
-
options3.https = httpsConfig(options3);
|
|
57431
|
-
else if (options3.https === false)
|
|
57432
|
-
return null;
|
|
57433
|
-
if (!options3.https?.keyPath && !options3.https?.certPath) {
|
|
57434
|
-
debugLog2("ssl", "No SSL configuration provided", options3.verbose);
|
|
57435
|
-
return null;
|
|
57436
|
-
}
|
|
57437
|
-
if (options3.https?.keyPath && !options3.https?.certPath || !options3.https?.keyPath && options3.https?.certPath) {
|
|
57438
|
-
const missing = !options3.https?.keyPath ? "keyPath" : "certPath";
|
|
57439
|
-
debugLog2("ssl", `Invalid SSL configuration - missing ${missing}`, options3.verbose);
|
|
57440
|
-
throw new Error(`SSL Configuration requires both keyPath and certPath. Missing: ${missing}`);
|
|
57441
|
-
}
|
|
57442
|
-
try {
|
|
57443
|
-
if (!options3.https?.keyPath || !options3.https?.certPath)
|
|
57444
|
-
return null;
|
|
57445
|
-
try {
|
|
57446
|
-
debugLog2("ssl", "Reading SSL certificate files", options3.verbose);
|
|
57447
|
-
const key = await fs5.promises.readFile(options3.https?.keyPath, "utf8");
|
|
57448
|
-
const cert = await fs5.promises.readFile(options3.https?.certPath, "utf8");
|
|
57449
|
-
debugLog2("ssl", "SSL configuration loaded successfully", options3.verbose);
|
|
57450
|
-
return { key, cert };
|
|
57451
|
-
} catch (error) {
|
|
57452
|
-
debugLog2("ssl", `Failed to read certificates: ${error}`, options3.verbose);
|
|
57453
|
-
return null;
|
|
57454
|
-
}
|
|
57455
|
-
} catch (err3) {
|
|
57456
|
-
debugLog2("ssl", `SSL configuration error: ${err3}`, options3.verbose);
|
|
57457
|
-
throw err3;
|
|
57458
|
-
}
|
|
57459
|
-
}
|
|
57460
57524
|
function isPortInUse(port, hostname, verbose) {
|
|
57461
57525
|
debugLog2("port", `Checking if port ${port} is in use on ${hostname}`, verbose);
|
|
57462
57526
|
return new Promise((resolve4) => {
|
|
@@ -57512,8 +57576,8 @@ async function testConnection(hostname, port, verbose) {
|
|
|
57512
57576
|
}
|
|
57513
57577
|
async function startServer(options3) {
|
|
57514
57578
|
debugLog2("server", `Starting server with options: ${JSON.stringify(options3)}`, options3.verbose);
|
|
57515
|
-
const fromUrl = new URL(options3.from
|
|
57516
|
-
const toUrl = new URL(options3.to
|
|
57579
|
+
const fromUrl = new URL((options3.from?.startsWith("http") ? options3.from : `http://${options3.from}`) || "localhost:5173");
|
|
57580
|
+
const toUrl = new URL((options3.to?.startsWith("http") ? options3.to : `http://${options3.to}`) || "stacks.localhost");
|
|
57517
57581
|
const fromPort = Number.parseInt(fromUrl.port) || (fromUrl.protocol.includes("https:") ? 443 : 80);
|
|
57518
57582
|
const hostsToCheck = [toUrl.hostname];
|
|
57519
57583
|
if (!toUrl.hostname.includes("localhost") && !toUrl.hostname.includes("127.0.0.1")) {
|
|
@@ -57597,7 +57661,7 @@ async function startServer(options3) {
|
|
|
57597
57661
|
debugLog2("server", `Setting up reverse proxy with SSL config for ${toUrl.hostname}`, options3.verbose);
|
|
57598
57662
|
await setupReverseProxy({
|
|
57599
57663
|
...options3,
|
|
57600
|
-
from: options3.from,
|
|
57664
|
+
from: options3.from || "localhost:5173",
|
|
57601
57665
|
to: toUrl.hostname,
|
|
57602
57666
|
fromPort,
|
|
57603
57667
|
sourceUrl: {
|
|
@@ -57752,51 +57816,77 @@ function startHttpRedirectServer(verbose) {
|
|
|
57752
57816
|
debugLog2("redirect", "HTTP redirect server started", verbose);
|
|
57753
57817
|
}
|
|
57754
57818
|
function startProxy(options3) {
|
|
57755
|
-
|
|
57819
|
+
const mergedOptions = {
|
|
57820
|
+
...config4,
|
|
57821
|
+
...options3
|
|
57822
|
+
};
|
|
57823
|
+
debugLog2("proxy", `Starting proxy with options: ${JSON.stringify(mergedOptions)}`, mergedOptions?.verbose);
|
|
57756
57824
|
const serverOptions = {
|
|
57757
|
-
from:
|
|
57758
|
-
to:
|
|
57759
|
-
https: httpsConfig(
|
|
57760
|
-
etcHostsCleanup:
|
|
57761
|
-
verbose:
|
|
57825
|
+
from: mergedOptions.from,
|
|
57826
|
+
to: mergedOptions.to,
|
|
57827
|
+
https: httpsConfig(mergedOptions),
|
|
57828
|
+
etcHostsCleanup: mergedOptions.etcHostsCleanup,
|
|
57829
|
+
verbose: mergedOptions.verbose
|
|
57762
57830
|
};
|
|
57763
57831
|
console.log("serverOptions", serverOptions);
|
|
57764
57832
|
startServer(serverOptions).catch((err3) => {
|
|
57765
|
-
debugLog2("proxy", `Failed to start proxy: ${err3}`,
|
|
57833
|
+
debugLog2("proxy", `Failed to start proxy: ${err3}`, mergedOptions.verbose);
|
|
57766
57834
|
log.error(`Failed to start proxy: ${err3.message}`);
|
|
57767
57835
|
cleanup({
|
|
57768
|
-
domains: [
|
|
57769
|
-
etcHostsCleanup:
|
|
57770
|
-
verbose:
|
|
57836
|
+
domains: [mergedOptions.to],
|
|
57837
|
+
etcHostsCleanup: mergedOptions.etcHostsCleanup,
|
|
57838
|
+
verbose: mergedOptions.verbose
|
|
57771
57839
|
});
|
|
57772
57840
|
});
|
|
57773
57841
|
}
|
|
57774
57842
|
async function startProxies(options3) {
|
|
57775
|
-
|
|
57776
|
-
|
|
57777
|
-
|
|
57778
|
-
|
|
57779
|
-
|
|
57843
|
+
debugLog2("proxies", "Starting proxy setup", options3?.verbose);
|
|
57844
|
+
const mergedOptions = {
|
|
57845
|
+
...config4,
|
|
57846
|
+
...options3
|
|
57847
|
+
};
|
|
57848
|
+
const primaryDomain = isMultiProxyConfig(mergedOptions) ? mergedOptions.proxies[0].to || "stacks.localhost" : mergedOptions.to || "stacks.localhost";
|
|
57849
|
+
if (mergedOptions.https) {
|
|
57850
|
+
const existingSSLConfig = await checkExistingCertificates(mergedOptions);
|
|
57851
|
+
if (existingSSLConfig) {
|
|
57852
|
+
debugLog2("ssl", `Using existing certificates for ${primaryDomain}`, mergedOptions.verbose);
|
|
57853
|
+
mergedOptions._cachedSSLConfig = existingSSLConfig;
|
|
57854
|
+
} else {
|
|
57855
|
+
debugLog2("ssl", `No valid certificates found for ${primaryDomain}, generating new ones`, mergedOptions.verbose);
|
|
57856
|
+
await generateCertificate2(mergedOptions);
|
|
57857
|
+
const sslConfig2 = await checkExistingCertificates(mergedOptions);
|
|
57858
|
+
if (!sslConfig2) {
|
|
57859
|
+
throw new Error(`Failed to load SSL certificates after generation for ${primaryDomain}. Please check file permissions and paths.`);
|
|
57860
|
+
}
|
|
57861
|
+
mergedOptions._cachedSSLConfig = sslConfig2;
|
|
57862
|
+
}
|
|
57780
57863
|
}
|
|
57781
|
-
const proxyOptions =
|
|
57864
|
+
const proxyOptions = isMultiProxyConfig(mergedOptions) ? mergedOptions.proxies.map((proxy) => ({
|
|
57782
57865
|
...proxy,
|
|
57783
|
-
https:
|
|
57784
|
-
etcHostsCleanup:
|
|
57785
|
-
verbose:
|
|
57786
|
-
_cachedSSLConfig:
|
|
57787
|
-
})) : [
|
|
57788
|
-
|
|
57789
|
-
|
|
57866
|
+
https: mergedOptions.https,
|
|
57867
|
+
etcHostsCleanup: mergedOptions.etcHostsCleanup,
|
|
57868
|
+
verbose: mergedOptions.verbose,
|
|
57869
|
+
_cachedSSLConfig: mergedOptions._cachedSSLConfig
|
|
57870
|
+
})) : [{
|
|
57871
|
+
from: mergedOptions.from || "localhost:5173",
|
|
57872
|
+
to: mergedOptions.to || "stacks.localhost",
|
|
57873
|
+
https: mergedOptions.https,
|
|
57874
|
+
etcHostsCleanup: mergedOptions.etcHostsCleanup,
|
|
57875
|
+
verbose: mergedOptions.verbose,
|
|
57876
|
+
_cachedSSLConfig: mergedOptions._cachedSSLConfig
|
|
57877
|
+
}];
|
|
57878
|
+
const domains = proxyOptions.map((opt) => opt.to || "stacks.localhost");
|
|
57879
|
+
const sslConfig = mergedOptions._cachedSSLConfig;
|
|
57790
57880
|
const cleanupHandler = () => cleanup({
|
|
57791
57881
|
domains,
|
|
57792
|
-
etcHostsCleanup:
|
|
57793
|
-
verbose:
|
|
57882
|
+
etcHostsCleanup: mergedOptions.etcHostsCleanup || false,
|
|
57883
|
+
verbose: mergedOptions.verbose || false
|
|
57794
57884
|
});
|
|
57795
57885
|
process9.on("SIGINT", cleanupHandler);
|
|
57796
57886
|
process9.on("SIGTERM", cleanupHandler);
|
|
57797
57887
|
process9.on("uncaughtException", (err3) => {
|
|
57798
57888
|
debugLog2("process", `Uncaught exception: ${err3}`, true);
|
|
57799
|
-
|
|
57889
|
+
console.error("Uncaught exception:", err3);
|
|
57800
57890
|
cleanupHandler();
|
|
57801
57891
|
});
|
|
57802
57892
|
for (const option of proxyOptions) {
|
|
@@ -57813,20 +57903,16 @@ async function startProxies(options3) {
|
|
|
57813
57903
|
});
|
|
57814
57904
|
} catch (err3) {
|
|
57815
57905
|
debugLog2("proxies", `Failed to start proxy for ${option.to}: ${err3}`, option.verbose);
|
|
57816
|
-
|
|
57906
|
+
console.error(`Failed to start proxy for ${option.to}:`, err3);
|
|
57817
57907
|
cleanupHandler();
|
|
57818
57908
|
}
|
|
57819
57909
|
}
|
|
57820
57910
|
}
|
|
57821
|
-
function isMultiProxyConfig2(options3) {
|
|
57822
|
-
return "proxies" in options3;
|
|
57823
|
-
}
|
|
57824
57911
|
|
|
57825
57912
|
// bin/cli.ts
|
|
57826
57913
|
var cli = new CAC("reverse-proxy");
|
|
57827
57914
|
cli.command("start", "Start the Reverse Proxy Server").option("--from <from>", "The URL to proxy from").option("--to <to>", "The URL to proxy to").option("--key-path <path>", "Absolute path to the SSL key").option("--cert-path <path>", "Absolute path to the SSL certificate").option("--ca-cert-path <path>", "Absolute path to the SSL CA certificate").option("--etc-hosts-cleanup", "Cleanup /etc/hosts on exit").option("--verbose", "Enable verbose logging").example("reverse-proxy start --from localhost:5173 --to my-project.localhost").example("reverse-proxy start --from localhost:3000 --to my-project.localhost/api").example("reverse-proxy start --from localhost:3000 --to localhost:3001").example("reverse-proxy start --from localhost:5173 --to my-project.test --key-path /absolute/path/to/key --cert-path /absolute/path/to/cert").action(async (options3) => {
|
|
57828
57915
|
if (!options3?.from || !options3.to) {
|
|
57829
|
-
console.log("in here", config4);
|
|
57830
57916
|
return startProxies(config4);
|
|
57831
57917
|
}
|
|
57832
57918
|
return startProxy({
|