@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 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.4.1";
20464
+ var version = "0.5.1";
20465
20465
 
20466
20466
  // src/config.ts
20467
- import os2 from "os";
20468
- import path from "path";
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 os5 from "os";
20537
- import path4 from "path";
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 join2,
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 os3 from "os";
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 path2 from "path";
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 path22 from "path";
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(path23) {
48114
- return projectPath2(`database/${path23 || ""}`);
48116
+ function userDatabasePath2(path22) {
48117
+ return projectPath2(`database/${path22 || ""}`);
48115
48118
  }
48116
- function appPath2(path23) {
48117
- return projectPath2(`app/${path23 || ""}`);
48119
+ function appPath2(path22) {
48120
+ return projectPath2(`app/${path22 || ""}`);
48118
48121
  }
48119
- function commandsPath2(path23) {
48120
- return appPath2(`Commands/${path23 || ""}`);
48122
+ function commandsPath2(path22) {
48123
+ return appPath2(`Commands/${path22 || ""}`);
48121
48124
  }
48122
- function logsPath2(path23) {
48123
- return storagePath2(`logs/${path23 || ""}`);
48125
+ function logsPath2(path22) {
48126
+ return storagePath2(`logs/${path22 || ""}`);
48124
48127
  }
48125
48128
  function projectPath2(filePath = "", options2) {
48126
- let path23 = process52.cwd();
48127
- while (path23.includes("storage"))
48128
- path23 = resolve22(path23, "..");
48129
- const finalPath = resolve22(path23, filePath);
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(path23) {
48135
- return projectPath2(`storage/${path23 || ""}`);
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 = os3.release().split(".");
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(defaultConfig, loadedConfig);
56804
+ return deepMerge2(defaultConfig2, loadedConfig);
56802
56805
  } catch (error) {
56803
- return defaultConfig;
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 = path22.join(dir, file);
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.rootCAObject?.certificate || !options22.rootCAObject?.privateKey) {
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.rootCAObject.certificate);
56962
- const caKey = import_node_forge2.pki.privateKeyFromPem(options22.rootCAObject.privateKey);
56963
- debugLog("cert", "Generating 2048-bit RSA key pair for host certificate", options22?.verbose);
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 extractDomains(options3) {
57082
- if (isMultiProxyConfig(options3)) {
57086
+ function extractHostname(options3) {
57087
+ if (isMultiProxyOptions(options3)) {
57083
57088
  return options3.proxies.map((proxy) => {
57084
- const domain2 = proxy.to || "stacks.localhost";
57085
- return domain2.startsWith("http") ? new URL(domain2).hostname : domain2;
57089
+ const domain = proxy.to || "stacks.localhost";
57090
+ return domain.startsWith("http") ? new URL(domain).hostname : domain;
57086
57091
  });
57087
57092
  }
57088
- const domain = options3.to || "stacks.localhost";
57089
- return [domain.startsWith("http") ? new URL(domain).hostname : domain];
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 isMultiProxyConfig(options3) {
57095
- return "proxies" in options3;
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 generateBaseConfig(options3, verbose) {
57107
- const domains = extractDomains(options3);
57108
- const sslBase = path4.join(os5.homedir(), ".stacks", "ssl");
57109
- const httpsConfig = options3.https === true ? {
57110
- caCertPath: path4.join(sslBase, "rpx-ca.crt"),
57111
- certPath: path4.join(sslBase, "rpx.crt"),
57112
- keyPath: path4.join(sslBase, "rpx.key")
57113
- } : typeof config4.https === "object" ? {
57114
- ...options3.https,
57115
- ...config4.https
57116
- } : {};
57117
- debugLog2("ssl", `Extracted domains: ${domains.join(", ")}`, verbose);
57118
- debugLog2("ssl", `Using SSL base path: ${sslBase}`, verbose);
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
- domain: domains[0],
57131
- hostCertCN: domains[0],
57132
- caCertPath: httpsConfig?.caCertPath ?? path4.join(sslBase, "rpx-ca.crt"),
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 generateRootCAConfig(verbose = false) {
57151
- const sslBase = path4.join(os5.homedir(), ".stacks", "ssl");
57152
- return {
57153
- domain: "stacks.localhost",
57154
- hostCertCN: "stacks.localhost",
57155
- caCertPath: path4.join(sslBase, "rpx-root-ca.crt"),
57156
- certPath: path4.join(sslBase, "rpx-certificate.crt"),
57157
- keyPath: path4.join(sslBase, "rpx-certificate.key"),
57158
- altNameIPs: ["127.0.0.1", "::1"],
57159
- altNameURIs: [],
57160
- organizationName: "Stacks Local Development",
57161
- countryName: "US",
57162
- stateName: "California",
57163
- localityName: "Playa Vista",
57164
- commonName: "stacks.localhost",
57165
- validityDays: 3650,
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 httpsConfig(options3) {
57170
- return generateBaseConfig(options3, options3.verbose);
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
- const verbose2 = isMultiProxyConfig(options3) ? options3.verbose : options3.verbose;
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 = isMultiProxyConfig(options3) ? [options3.proxies[0].to, ...options3.proxies.map((proxy) => proxy.to)] : [options3.to];
57179
- const verbose = isMultiProxyConfig(options3) ? options3.verbose : options3.verbose;
57180
- debugLog2("ssl", `Generating certificate for domains: ${domains.join(", ")}`, verbose);
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 = generateBaseConfig(options3, verbose);
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
- rootCAObject: {
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 { spawn } from "child_process";
57215
- import fs3 from "fs";
57216
- import os7 from "os";
57217
- import path6 from "path";
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
- var hostsFilePath = process3.platform === "win32" ? path6.join(process3.env.windir || "C:\\Windows", "System32", "drivers", "etc", "hosts") : "/etc/hosts";
57220
- async function sudoWrite(operation, content) {
57221
- return new Promise((resolve4, reject) => {
57222
- if (process3.platform === "win32") {
57223
- reject(new Error("Administrator privileges required on Windows"));
57224
- return;
57225
- }
57226
- const tmpFile = path6.join(os7.tmpdir(), "hosts.tmp");
57227
- try {
57228
- if (operation === "append") {
57229
- const currentContent = fs3.readFileSync(hostsFilePath, "utf8");
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 fs3.promises.readFile(hostsFilePath, "utf-8");
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 fs3.promises.appendFile(hostsFilePath, hostEntries, { flag: "a" });
57390
+ await execSudo(`cp "${tmpFile}" "${hostsFilePath}"`);
57280
57391
  log.success(`Added new hosts: ${newEntries.join(", ")}`);
57281
- } catch (writeErr) {
57282
- if (writeErr.code === "EACCES") {
57283
- debugLog2("hosts", "Permission denied, attempting with sudo", verbose);
57284
- try {
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
- if (process3.platform === "win32") {
57293
- log.warn(`
57397
+ if (process3.platform === "win32") {
57398
+ log.warn(`
57294
57399
  On Windows:`);
57295
- log.warn("1. Run notepad as administrator");
57296
- log.warn("2. Open C:\\Windows\\System32\\drivers\\etc\\hosts");
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
- throw writeErr;
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 fs3.promises.readFile(hostsFilePath, "utf-8");
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 fs3.promises.writeFile(hostsFilePath, newContent);
57438
+ await execSudo(`cp "${tmpFile}" "${hostsFilePath}"`);
57334
57439
  log.success("Hosts removed successfully");
57335
- } catch (writeErr) {
57336
- if (writeErr.code === "EACCES") {
57337
- debugLog2("hosts", "Permission denied, attempting with sudo", verbose);
57338
- try {
57339
- await sudoWrite("write", newContent);
57340
- log.success("Hosts removed successfully with sudo");
57341
- } catch (sudoErr) {
57342
- log.error("Failed to modify hosts file automatically");
57343
- log.warn("Please remove these entries from your hosts file manually:");
57344
- hosts.forEach((host) => {
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
- log.warn("1. Run notepad as administrator");
57353
- log.warn("2. Open C:\\Windows\\System32\\drivers\\etc\\hosts");
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
- throw writeErr;
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 fs3.promises.readFile(hostsFilePath, "utf-8");
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.startsWith("http") ? options3.from : `http://${options3.from}`);
57516
- const toUrl = new URL(options3.to.startsWith("http") ? options3.to : `http://${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
- debugLog2("proxy", `Starting proxy with options: ${JSON.stringify(options3)}`, options3?.verbose);
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: options3?.from || "localhost:5173",
57758
- to: options3?.to || "stacks.localhost",
57759
- https: httpsConfig(options3),
57760
- etcHostsCleanup: options3?.etcHostsCleanup || false,
57761
- verbose: options3?.verbose || false
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}`, options3.verbose);
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: [options3.to],
57769
- etcHostsCleanup: options3.etcHostsCleanup,
57770
- verbose: options3.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
- if (!options3)
57776
- return;
57777
- debugLog2("proxies", "Starting proxies setup", isMultiProxyConfig2(options3) ? options3.verbose : options3.verbose);
57778
- if (options3.https) {
57779
- await generateCertificate2(options3);
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 = isMultiProxyConfig2(options3) ? options3.proxies.map((proxy) => ({
57864
+ const proxyOptions = isMultiProxyConfig(mergedOptions) ? mergedOptions.proxies.map((proxy) => ({
57782
57865
  ...proxy,
57783
- https: options3.https,
57784
- etcHostsCleanup: options3.etcHostsCleanup,
57785
- verbose: options3.verbose,
57786
- _cachedSSLConfig: options3._cachedSSLConfig
57787
- })) : [options3];
57788
- const domains = extractDomains(options3);
57789
- const sslConfig = options3.https ? getSSLConfig() : null;
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: isMultiProxyConfig2(options3) ? options3.etcHostsCleanup : options3.etcHostsCleanup || false,
57793
- verbose: isMultiProxyConfig2(options3) ? options3.verbose : options3.verbose || false
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
- log.error("Uncaught exception:", err3);
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
- log.error(`Failed to start proxy for ${option.to}:`, err3);
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({