unplugin-https-reverse-proxy 4.0.4 → 4.1.0-beta.3

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.
Files changed (53) hide show
  1. package/README.md +30 -6
  2. package/dist/{chunk-2P7SUCQ3.js → chunk-EY3HXBJ4.js} +0 -26
  3. package/dist/{chunk-5R33PUJP.js → chunk-HBXMM25C.js} +765 -229
  4. package/dist/chunk-RKHJN6KY.js +53 -0
  5. package/dist/chunk-WOMR3ZLM.js +17 -0
  6. package/dist/esbuild.cjs +870 -306
  7. package/dist/esbuild.js +4 -2
  8. package/dist/index.cjs +870 -306
  9. package/dist/index.js +4 -2
  10. package/dist/nuxt.cjs +842 -292
  11. package/dist/nuxt.js +6 -9
  12. package/dist/privilege-state.cjs +44 -0
  13. package/dist/privilege-state.d.cts +7 -0
  14. package/dist/privilege-state.d.ts +7 -0
  15. package/dist/privilege-state.js +10 -0
  16. package/dist/privileged-helper.cjs +668 -0
  17. package/dist/privileged-helper.d.cts +2 -0
  18. package/dist/privileged-helper.d.ts +2 -0
  19. package/dist/privileged-helper.js +641 -0
  20. package/dist/rollup.cjs +870 -306
  21. package/dist/rollup.js +4 -2
  22. package/dist/rspack.cjs +870 -306
  23. package/dist/rspack.js +4 -2
  24. package/dist/utils.cjs +0 -28
  25. package/dist/utils.d.cts +1 -3
  26. package/dist/utils.d.ts +1 -3
  27. package/dist/utils.js +1 -5
  28. package/dist/vite.cjs +870 -306
  29. package/dist/vite.js +4 -2
  30. package/dist/webpack.cjs +870 -306
  31. package/dist/webpack.js +4 -2
  32. package/package.json +1 -4
  33. package/src/caddy/caddyfile.ts +1 -0
  34. package/src/caddy/index.ts +184 -110
  35. package/src/caddy/privileged.ts +121 -0
  36. package/src/caddy/utils.ts +0 -43
  37. package/src/index.ts +49 -22
  38. package/src/nuxt.ts +1 -6
  39. package/src/privilege-state.ts +23 -0
  40. package/src/privileged/bootstrap.ts +174 -0
  41. package/src/privileged/client.ts +287 -0
  42. package/src/privileged/entry.ts +73 -0
  43. package/src/privileged/hosts-file.ts +142 -0
  44. package/src/privileged/launch.ts +235 -0
  45. package/src/privileged/ports.ts +45 -0
  46. package/src/privileged/protocol.ts +111 -0
  47. package/src/privileged/server.ts +465 -0
  48. package/src/privileged/session.ts +117 -0
  49. package/src/privileged/validation.ts +38 -0
  50. package/src/privileged/windows-elevation.ts +80 -0
  51. package/src/privileged-helper.ts +109 -0
  52. package/src/utils.ts +0 -28
  53. package/src/host/index.ts +0 -52
@@ -1,29 +1,36 @@
1
1
  import {
2
- hmrSseBridgeClientScript,
3
- setupHmrSseBridge
4
- } from "./chunk-C5A7XLKL.js";
5
- import {
6
- chmodRecursive,
7
2
  consola,
8
3
  generateQrcode,
9
4
  getIpv4List,
10
- isAdmin,
11
5
  once
12
- } from "./chunk-2P7SUCQ3.js";
6
+ } from "./chunk-EY3HXBJ4.js";
7
+ import {
8
+ hmrSseBridgeClientScript,
9
+ setupHmrSseBridge
10
+ } from "./chunk-C5A7XLKL.js";
11
+ import {
12
+ isPrivilegeDenied,
13
+ markPrivilegeDenied
14
+ } from "./chunk-WOMR3ZLM.js";
15
+ import {
16
+ decodeMessage,
17
+ serializeMessage,
18
+ splitLines
19
+ } from "./chunk-RKHJN6KY.js";
13
20
 
14
21
  // src/index.ts
15
- import process5 from "node:process";
22
+ import process8 from "node:process";
16
23
  import { Table } from "console-table-printer";
17
24
  import c from "picocolors";
18
25
  import { createUnplugin } from "unplugin";
19
26
 
20
27
  // src/caddy/index.ts
21
- import { spawn } from "node:child_process";
22
- import { chmodSync as chmodSync2, createWriteStream, existsSync as existsSync3, mkdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
23
- import { readFile as readFile2, unlink as unlink3, writeFile } from "node:fs/promises";
24
- import { platform } from "node:os";
25
- import { join as join3 } from "node:path";
26
- import process4 from "node:process";
28
+ import { execFile } from "node:child_process";
29
+ import { chmodSync, createWriteStream, existsSync as existsSync5, mkdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
30
+ import { readFile as readFile3, unlink as unlink3, writeFile as writeFile2 } from "node:fs/promises";
31
+ import { platform as platform3 } from "node:os";
32
+ import { join as join6 } from "node:path";
33
+ import process7 from "node:process";
27
34
 
28
35
  // node_modules/.pnpm/alien-signals@2.0.7/node_modules/alien-signals/esm/system.mjs
29
36
  var ReactiveFlags;
@@ -465,49 +472,6 @@ import { HttpProxyAgent } from "http-proxy-agent";
465
472
  import { HttpsProxyAgent } from "https-proxy-agent";
466
473
  import * as lockfile from "proper-lockfile";
467
474
 
468
- // src/host/index.ts
469
- import { exec } from "node:child_process";
470
- import { chmodSync } from "node:fs";
471
- import process2 from "node:process";
472
- import { promisify } from "node:util";
473
- import hostile from "hostile";
474
- var _setHost = promisify(hostile.set);
475
- var _removeHost = promisify(hostile.remove);
476
- function getPathOfSystemHostsPath() {
477
- return process2.platform === "win32" ? `${process2.env.windir || "C:\\WINDOWS"}\\system32\\drivers\\etc\\hosts` : "/etc/hosts";
478
- }
479
- async function syncHost() {
480
- return new Promise((resolve2, _reject) => {
481
- exec(
482
- process2.platform === "win32" ? "ipconfig /flushdns" : "sudo -E killall -HUP mDNSResponder",
483
- (error, _stdout, _stderr) => {
484
- if (error) {
485
- consola.error(`exec error: ${error}`);
486
- return resolve2(false);
487
- }
488
- return resolve2(true);
489
- }
490
- );
491
- });
492
- }
493
- async function addHost(ip2, host) {
494
- if (process2.platform !== "win32")
495
- chmodSync(getPathOfSystemHostsPath(), 511);
496
- await _setHost("127.0.0.1", "localhost");
497
- await _setHost(ip2, host);
498
- if (ip2 === "localhost")
499
- await _setHost("127.0.0.1", host);
500
- return await syncHost();
501
- }
502
- async function removeHost(ip2, host) {
503
- if (process2.platform !== "win32")
504
- chmodSync(getPathOfSystemHostsPath(), 511);
505
- await _removeHost(ip2, host);
506
- if (ip2 === "localhost")
507
- await _removeHost("127.0.0.1", host);
508
- return await syncHost();
509
- }
510
-
511
475
  // node_modules/.pnpm/@ark+util@0.46.0/node_modules/@ark/util/out/arrays.js
512
476
  var liftArray = (data) => Array.isArray(data) ? data : [data];
513
477
  var spliterate = (arr, predicate) => {
@@ -8831,7 +8795,7 @@ function isIterator(val) {
8831
8795
  function escapeRegex(str) {
8832
8796
  return str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
8833
8797
  }
8834
- function promisify2(fn) {
8798
+ function promisify(fn) {
8835
8799
  return function(...args2) {
8836
8800
  return new Promise((resolve2, reject2) => {
8837
8801
  fn(...args2, (err, result) => {
@@ -10167,8 +10131,8 @@ function requireResolve(file) {
10167
10131
  const require2 = createRequire(process.cwd() + "/");
10168
10132
  return require2.resolve(file);
10169
10133
  }
10170
- var statAsync = promisify2(stat);
10171
- var readFileAsync = promisify2(readFile$1);
10134
+ var statAsync = promisify(stat);
10135
+ var readFileAsync = promisify(readFile$1);
10172
10136
  function exists(filepath) {
10173
10137
  return __awaiter(this, void 0, void 0, function* () {
10174
10138
  try {
@@ -13375,6 +13339,7 @@ function validateTemplateContext(ctx) {
13375
13339
  var caddyTemplate = `{
13376
13340
  debug
13377
13341
  auto_https disable_redirects ignore_loaded_certs
13342
+ skip_install_trust
13378
13343
  }
13379
13344
 
13380
13345
  :7601 {
@@ -13461,7 +13426,7 @@ import { unlink as unlink2 } from "node:fs/promises";
13461
13426
  // src/caddy/constants.ts
13462
13427
  import os from "node:os";
13463
13428
  import { join as join2 } from "node:path";
13464
- import process3 from "node:process";
13429
+ import process2 from "node:process";
13465
13430
  import dotenvFlow from "dotenv-flow";
13466
13431
  dotenvFlow.config({
13467
13432
  silent: true
@@ -13471,8 +13436,8 @@ function resolvePath(path) {
13471
13436
  return join2(os.homedir() || "", path.slice(1));
13472
13437
  return path;
13473
13438
  }
13474
- var TEMP_DIR = resolvePath(process3.env.UHRP_CADDY_PATH || process3.env.TEMP || process3.env.TMPDIR || "/tmp");
13475
- var caddyPath = join2(TEMP_DIR, `caddy${process3.platform === "win32" ? ".exe" : ""}`);
13439
+ var TEMP_DIR = resolvePath(process2.env.UHRP_CADDY_PATH || process2.env.TEMP || process2.env.TMPDIR || "/tmp");
13440
+ var caddyPath = join2(TEMP_DIR, `caddy${process2.platform === "win32" ? ".exe" : ""}`);
13476
13441
  var caddyFilePath = join2(TEMP_DIR, "CADDYFILE");
13477
13442
  var caddyConfigPath = join2(TEMP_DIR, ".CADDYFILE.config.json");
13478
13443
  var caddyLockFilePath = join2(TEMP_DIR, "caddylock");
@@ -13651,8 +13616,542 @@ function isCaddyReloadCancellation(line) {
13651
13616
  }
13652
13617
  }
13653
13618
 
13619
+ // src/caddy/privileged.ts
13620
+ import { Buffer as Buffer2 } from "node:buffer";
13621
+ import { EventEmitter } from "node:events";
13622
+ import { dirname as dirname3, join as join5 } from "node:path";
13623
+ import process6 from "node:process";
13624
+ import { fileURLToPath } from "node:url";
13625
+
13626
+ // src/privileged/entry.ts
13627
+ import { existsSync as existsSync3 } from "node:fs";
13628
+ import { dirname as dirname2, join as join3 } from "node:path";
13629
+ import process3 from "node:process";
13630
+ function resolveHelperEntry(options) {
13631
+ const { moduleDir, nodeBin = process3.execPath, exists: exists2 = existsSync3 } = options;
13632
+ for (const name of ["privileged-helper.js", "privileged-helper.cjs", "privileged-helper.mjs"]) {
13633
+ const candidate = findUp(moduleDir, name, exists2);
13634
+ if (candidate)
13635
+ return { entry: nodeBin, args: [candidate] };
13636
+ }
13637
+ const source = findUp(moduleDir, "privileged-helper.ts", exists2);
13638
+ const tsxCli = findUp(moduleDir, "node_modules/tsx/dist/cli.mjs", exists2);
13639
+ if (source && tsxCli)
13640
+ return { entry: nodeBin, args: [tsxCli, source] };
13641
+ throw new Error(`privileged helper entry not found in ${moduleDir}. Build the package first.`);
13642
+ }
13643
+ function findUp(from, relative, exists2) {
13644
+ let current = from;
13645
+ while (true) {
13646
+ const candidate = join3(current, relative);
13647
+ if (exists2(candidate))
13648
+ return candidate;
13649
+ const parent = dirname2(current);
13650
+ if (parent === current)
13651
+ return void 0;
13652
+ current = parent;
13653
+ }
13654
+ }
13655
+
13656
+ // src/privileged/session.ts
13657
+ import { Buffer } from "node:buffer";
13658
+ import { existsSync as existsSync4 } from "node:fs";
13659
+ import { readFile as readFile2, writeFile } from "node:fs/promises";
13660
+ import { platform as platform2 } from "node:os";
13661
+ import { join as join4 } from "node:path";
13662
+
13663
+ // src/privileged/launch.ts
13664
+ import { spawn as spawn2, spawnSync } from "node:child_process";
13665
+ import { randomBytes } from "node:crypto";
13666
+ import { platform } from "node:os";
13667
+ import process5 from "node:process";
13668
+
13669
+ // src/privileged/client.ts
13670
+ import { connect } from "node:net";
13671
+ import process4 from "node:process";
13672
+ var FORWARDED_ENV_KEYS = [
13673
+ "HOME",
13674
+ "USER",
13675
+ "LOGNAME",
13676
+ "TMPDIR",
13677
+ "HTTP_PROXY",
13678
+ "HTTPS_PROXY",
13679
+ "http_proxy",
13680
+ "https_proxy",
13681
+ "NO_PROXY",
13682
+ "no_proxy"
13683
+ ];
13684
+ function collectForwardedEnv(source = process4.env) {
13685
+ const result = {};
13686
+ for (const key of FORWARDED_ENV_KEYS) {
13687
+ const value2 = source[key];
13688
+ if (typeof value2 === "string" && value2 !== "")
13689
+ result[key] = value2;
13690
+ }
13691
+ return result;
13692
+ }
13693
+ var HelperConnectionError = class extends Error {
13694
+ constructor(message) {
13695
+ super(message);
13696
+ this.name = "HelperConnectionError";
13697
+ }
13698
+ };
13699
+ function openSocket(socketPath) {
13700
+ return new Promise((resolve2, reject2) => {
13701
+ const socket = connect(socketPath);
13702
+ function onConnect() {
13703
+ socket.removeListener("error", onError);
13704
+ resolve2(socket);
13705
+ }
13706
+ function onError(error) {
13707
+ socket.removeListener("connect", onConnect);
13708
+ reject2(error);
13709
+ }
13710
+ socket.once("error", onError);
13711
+ socket.once("connect", onConnect);
13712
+ });
13713
+ }
13714
+ async function connectClient(options) {
13715
+ const {
13716
+ socketPath,
13717
+ token,
13718
+ timeoutMs = 12e4,
13719
+ retryIntervalMs = 100,
13720
+ callTimeoutMs = 3e4
13721
+ } = options;
13722
+ const deadline = Date.now() + timeoutMs;
13723
+ let lastError;
13724
+ while (Date.now() < deadline) {
13725
+ try {
13726
+ return await handshake(socketPath, token, callTimeoutMs);
13727
+ } catch (error) {
13728
+ lastError = error;
13729
+ const code = lastError.code;
13730
+ if (code === "EACCES" || lastError instanceof HelperConnectionError)
13731
+ throw lastError;
13732
+ await new Promise((resolve2) => setTimeout(resolve2, retryIntervalMs));
13733
+ }
13734
+ }
13735
+ throw new HelperConnectionError(
13736
+ `privileged helper is not reachable at ${socketPath}: ${(lastError == null ? void 0 : lastError.message) ?? "timed out"}`
13737
+ );
13738
+ }
13739
+ function handshake(socketPath, token, callTimeoutMs) {
13740
+ return new Promise((resolve2, reject2) => {
13741
+ void openSocket(socketPath).then((socket) => {
13742
+ let buffer = "";
13743
+ let settled = false;
13744
+ const fail = (error) => {
13745
+ if (settled)
13746
+ return;
13747
+ settled = true;
13748
+ socket.destroy();
13749
+ reject2(error);
13750
+ };
13751
+ const onData = (chunk) => {
13752
+ if (settled)
13753
+ return;
13754
+ const split2 = splitLines(buffer, chunk.toString("utf8"));
13755
+ buffer = split2.rest;
13756
+ const line = split2.lines[0];
13757
+ if (line === void 0)
13758
+ return;
13759
+ let hello;
13760
+ try {
13761
+ hello = JSON.parse(line);
13762
+ } catch (error) {
13763
+ return fail(new HelperConnectionError(`invalid handshake reply: ${error.message}`));
13764
+ }
13765
+ if (hello.type !== "handshake")
13766
+ return fail(new HelperConnectionError("helper did not answer the handshake"));
13767
+ if (!hello.ok)
13768
+ return fail(new HelperConnectionError(hello.reason ?? "helper rejected the handshake"));
13769
+ settled = true;
13770
+ socket.removeListener("data", onData);
13771
+ socket.removeListener("error", onError);
13772
+ const remaining = split2.lines.slice(1);
13773
+ resolve2(createClient(socket, [split2.rest, ...remaining].filter(Boolean).join("\n"), callTimeoutMs));
13774
+ };
13775
+ function onError(error) {
13776
+ fail(error);
13777
+ }
13778
+ socket.on("data", onData);
13779
+ socket.on("error", onError);
13780
+ const greeting = { type: "handshake", token };
13781
+ socket.write(serializeMessage(greeting));
13782
+ }, reject2);
13783
+ });
13784
+ }
13785
+ function createClient(socket, initialBuffer, callTimeoutMs) {
13786
+ let buffer = initialBuffer;
13787
+ let connected = true;
13788
+ let nextId = 1;
13789
+ const pending = /* @__PURE__ */ new Map();
13790
+ const listeners = /* @__PURE__ */ new Set();
13791
+ socket.on("data", (chunk) => {
13792
+ const split2 = splitLines(buffer, chunk.toString("utf8"));
13793
+ buffer = split2.rest;
13794
+ for (const line of split2.lines) {
13795
+ const decoded = decodeMessage(line);
13796
+ if (!decoded.ok)
13797
+ continue;
13798
+ const message = decoded.message;
13799
+ if (!("id" in message)) {
13800
+ for (const listener of listeners)
13801
+ listener(message);
13802
+ continue;
13803
+ }
13804
+ const entry = pending.get(message.id);
13805
+ if (!entry)
13806
+ continue;
13807
+ pending.delete(message.id);
13808
+ clearTimeout(entry.timer);
13809
+ if (message.ok)
13810
+ entry.resolve(message.result);
13811
+ else
13812
+ entry.reject(new Error(message.error.message));
13813
+ }
13814
+ });
13815
+ const disconnect = () => {
13816
+ if (!connected)
13817
+ return;
13818
+ connected = false;
13819
+ for (const [id, entry] of pending) {
13820
+ clearTimeout(entry.timer);
13821
+ pending.delete(id);
13822
+ entry.reject(new HelperConnectionError("privileged helper connection closed"));
13823
+ }
13824
+ };
13825
+ socket.on("close", disconnect);
13826
+ socket.on("error", disconnect);
13827
+ function call(method, params) {
13828
+ if (!connected)
13829
+ return Promise.reject(new HelperConnectionError("privileged helper is not connected"));
13830
+ const id = nextId++;
13831
+ const request = { id, method, params };
13832
+ return new Promise((resolve2, reject2) => {
13833
+ const timer = setTimeout(() => {
13834
+ pending.delete(id);
13835
+ reject2(new HelperConnectionError(`privileged helper did not answer "${method}" in time`));
13836
+ }, callTimeoutMs);
13837
+ pending.set(id, { resolve: resolve2, reject: reject2, timer });
13838
+ socket.write(serializeMessage(request));
13839
+ });
13840
+ }
13841
+ return {
13842
+ get connected() {
13843
+ return connected;
13844
+ },
13845
+ call,
13846
+ onEvent(listener) {
13847
+ listeners.add(listener);
13848
+ return () => {
13849
+ listeners.delete(listener);
13850
+ };
13851
+ },
13852
+ async close() {
13853
+ disconnect();
13854
+ socket.destroy();
13855
+ }
13856
+ };
13857
+ }
13858
+
13859
+ // src/privileged/windows-elevation.ts
13860
+ import { spawn } from "node:child_process";
13861
+ function quotePowerShell(value2) {
13862
+ return `'${value2.replace(/'/g, "''")}'`;
13863
+ }
13864
+ function buildElevationCommand(options) {
13865
+ const argumentList = options.args.map(quotePowerShell).join(",");
13866
+ const parts = [
13867
+ "Start-Process",
13868
+ "-FilePath",
13869
+ quotePowerShell(options.file)
13870
+ ];
13871
+ if (argumentList)
13872
+ parts.push("-ArgumentList", argumentList);
13873
+ if (options.cwd)
13874
+ parts.push("-WorkingDirectory", quotePowerShell(options.cwd));
13875
+ parts.push("-Verb", "RunAs");
13876
+ parts.push("-WindowStyle", "Hidden");
13877
+ return parts.join(" ");
13878
+ }
13879
+ function spawnElevatedOnWindows(options) {
13880
+ return new Promise((resolve2, reject2) => {
13881
+ const script = buildElevationCommand(options);
13882
+ const child = spawn(
13883
+ "powershell.exe",
13884
+ ["-NoProfile", "-NonInteractive", "-Command", script],
13885
+ { stdio: "ignore", windowsHide: true }
13886
+ );
13887
+ child.once("error", reject2);
13888
+ child.once("exit", (code) => {
13889
+ if (code === 0)
13890
+ return resolve2(child);
13891
+ reject2(new Error(
13892
+ `administrator permission was not granted (PowerShell exited with ${code}). Accept the UAC prompt to let the plugin edit the hosts file and bind ports 80/443.`
13893
+ ));
13894
+ });
13895
+ });
13896
+ }
13897
+
13898
+ // src/privileged/launch.ts
13899
+ function createHelperToken() {
13900
+ return randomBytes(24).toString("hex");
13901
+ }
13902
+ function describePasswordReason(target, https) {
13903
+ const port = https ? "443" : "80";
13904
+ return [
13905
+ `reverse proxy needs administrator permission for ${target}`,
13906
+ ` \xB7 bind port ${port}${https ? ` for https://${target}` : ""}`,
13907
+ ` \xB7 add ${target} to the hosts file`,
13908
+ "",
13909
+ "This is the only prompt; the rest of the dev server keeps running as you.",
13910
+ "Press Ctrl+C at the prompt to skip the proxy and keep the dev server."
13911
+ ];
13912
+ }
13913
+ function authenticateSudo(sudoCommand = "sudo", options = {}) {
13914
+ if (platform() === "win32")
13915
+ return { ok: true };
13916
+ if (spawnSync(sudoCommand, ["-n", "true"], { stdio: "ignore" }).status === 0)
13917
+ return { ok: true };
13918
+ if (options.target) {
13919
+ for (const line of describePasswordReason(options.target, options.https ?? false))
13920
+ process5.stderr.write(`${line}
13921
+ `);
13922
+ process5.stderr.write("\n");
13923
+ }
13924
+ if (spawnSync(sudoCommand, ["-v"], { stdio: "inherit" }).status === 0)
13925
+ return { ok: true };
13926
+ return {
13927
+ ok: false,
13928
+ denied: true,
13929
+ message: "administrator permission is required to edit the hosts file and bind ports 80/443"
13930
+ };
13931
+ }
13932
+ var PrivilegeDeniedError = class extends Error {
13933
+ constructor(message) {
13934
+ super(message);
13935
+ this.name = "PrivilegeDeniedError";
13936
+ }
13937
+ };
13938
+ async function startPrivilegedHelper(options) {
13939
+ var _a4, _b3;
13940
+ const {
13941
+ socketPath,
13942
+ token,
13943
+ helperEntry,
13944
+ helperArgs = [],
13945
+ sudoCommand = "sudo",
13946
+ skipAuth = false,
13947
+ direct = false,
13948
+ env: env2 = process5.env,
13949
+ log,
13950
+ connectTimeoutMs = 12e4
13951
+ } = options;
13952
+ if (!skipAuth && !direct) {
13953
+ const auth = authenticateSudo(sudoCommand, options.reason);
13954
+ if (!auth.ok) {
13955
+ const message = auth.message ?? "administrator permission is required";
13956
+ throw auth.denied ? new PrivilegeDeniedError(message) : new Error(message);
13957
+ }
13958
+ }
13959
+ const forwarded = collectForwardedEnv(env2);
13960
+ const forwardedArgs = Object.entries(forwarded).map(([key, value2]) => `${key}=${value2}`);
13961
+ const childArgv = [
13962
+ ...helperArgs,
13963
+ "--socket",
13964
+ socketPath,
13965
+ "--token",
13966
+ token,
13967
+ ...typeof process5.getuid === "function" ? ["--owner-uid", String(process5.getuid())] : [],
13968
+ ...typeof process5.getgid === "function" ? ["--owner-gid", String(process5.getgid())] : [],
13969
+ ...options.caddyStoragePath ? ["--caddy-storage", options.caddyStoragePath] : [],
13970
+ "--caddy",
13971
+ options.caddyBin,
13972
+ "--caddy-config",
13973
+ options.caddyConfigPath
13974
+ ];
13975
+ let child;
13976
+ if (!direct && platform() === "win32") {
13977
+ await spawnElevatedOnWindows({ file: helperEntry, args: childArgv, cwd: process5.cwd() });
13978
+ } else {
13979
+ const command = direct ? helperEntry : sudoCommand;
13980
+ const spawnArgs = direct ? childArgv : ["-n", "env", ...forwardedArgs, helperEntry, ...childArgv];
13981
+ child = spawn2(command, spawnArgs, {
13982
+ stdio: ["ignore", "pipe", "pipe"]
13983
+ });
13984
+ (_a4 = child.stdout) == null ? void 0 : _a4.on("data", (data) => log == null ? void 0 : log(data.toString().trimEnd()));
13985
+ (_b3 = child.stderr) == null ? void 0 : _b3.on("data", (data) => log == null ? void 0 : log(data.toString().trimEnd()));
13986
+ const exited = new Promise((resolve2) => child.once("exit", (code) => resolve2(code)));
13987
+ const earlyExit = await Promise.race([
13988
+ exited,
13989
+ new Promise((resolve2) => setTimeout(() => resolve2(void 0), 500))
13990
+ ]);
13991
+ if (earlyExit !== void 0 && earlyExit !== 0) {
13992
+ throw new Error(
13993
+ `privileged helper exited with code ${earlyExit}. Administrator permission was refused, or sudo is not available.`
13994
+ );
13995
+ }
13996
+ }
13997
+ try {
13998
+ const client = await connectClient({ socketPath, token, timeoutMs: connectTimeoutMs });
13999
+ return {
14000
+ client,
14001
+ async close() {
14002
+ await client.close().catch(() => {
14003
+ });
14004
+ child == null ? void 0 : child.unref();
14005
+ }
14006
+ };
14007
+ } catch (error) {
14008
+ try {
14009
+ child == null ? void 0 : child.kill();
14010
+ } catch {
14011
+ }
14012
+ throw error;
14013
+ }
14014
+ }
14015
+ async function connectExistingHelper(socketPath, token, timeoutMs = 1500) {
14016
+ try {
14017
+ return await connectClient({ socketPath, token, timeoutMs });
14018
+ } catch {
14019
+ return void 0;
14020
+ }
14021
+ }
14022
+
14023
+ // src/privileged/session.ts
14024
+ function tokenPath(runtimeDir) {
14025
+ return join4(runtimeDir, "helper.token");
14026
+ }
14027
+ function sessionSocketPath(runtimeDir) {
14028
+ if (platform2() === "win32")
14029
+ return `\\\\.\\pipe\\uhrp-${Buffer.from(runtimeDir).toString("hex").slice(0, 40)}`;
14030
+ return join4(runtimeDir, "helper.sock");
14031
+ }
14032
+ async function openHelperSession(scope2) {
14033
+ const socketPath = sessionSocketPath(scope2.runtimeDir);
14034
+ if (existsSync4(socketPath) || platform2() === "win32") {
14035
+ const token2 = await readToken(scope2.runtimeDir);
14036
+ if (token2) {
14037
+ const reused = await connectExistingHelper(socketPath, token2);
14038
+ if (reused) {
14039
+ return {
14040
+ client: reused,
14041
+ reused: true,
14042
+ close: async () => {
14043
+ await reused.close();
14044
+ }
14045
+ };
14046
+ }
14047
+ }
14048
+ }
14049
+ const token = createHelperToken();
14050
+ const started = await startPrivilegedHelper({
14051
+ socketPath,
14052
+ token,
14053
+ helperEntry: scope2.helperEntry,
14054
+ helperArgs: scope2.helperArgs,
14055
+ sudoCommand: scope2.sudoCommand,
14056
+ skipAuth: scope2.skipAuth,
14057
+ direct: scope2.direct,
14058
+ env: scope2.env,
14059
+ caddyStoragePath: scope2.caddyStoragePath,
14060
+ caddyBin: scope2.caddyBin,
14061
+ caddyConfigPath: scope2.caddyConfigPath,
14062
+ reason: scope2.reason,
14063
+ log: scope2.log
14064
+ });
14065
+ await writeToken(scope2.runtimeDir, token);
14066
+ return {
14067
+ client: started.client,
14068
+ reused: false,
14069
+ close: async () => {
14070
+ await started.close();
14071
+ }
14072
+ };
14073
+ }
14074
+ async function readToken(runtimeDir) {
14075
+ try {
14076
+ const content = await readFile2(tokenPath(runtimeDir), "utf8");
14077
+ const token = content.trim();
14078
+ return token === "" ? void 0 : token;
14079
+ } catch {
14080
+ return void 0;
14081
+ }
14082
+ }
14083
+ async function writeToken(runtimeDir, token) {
14084
+ try {
14085
+ await writeFile(tokenPath(runtimeDir), token, { mode: 384 });
14086
+ } catch {
14087
+ }
14088
+ }
14089
+
14090
+ // src/caddy/privileged.ts
14091
+ function resolvePrivilegedEnv() {
14092
+ const moduleDir = typeof __dirname === "string" ? __dirname : dirname3(fileURLToPath(import.meta.url));
14093
+ const resolved = resolveHelperEntry({ moduleDir });
14094
+ return { helperEntry: resolved.entry, helperArgs: resolved.args };
14095
+ }
14096
+ var HelperCaddyProcess = class extends EventEmitter {
14097
+ constructor(client) {
14098
+ super();
14099
+ this.client = client;
14100
+ this.stdout = new EventEmitter();
14101
+ this.stderr = new EventEmitter();
14102
+ this.finished = false;
14103
+ this.unsubscribe = client.onEvent((event) => this.handleEvent(event));
14104
+ }
14105
+ handleEvent(event) {
14106
+ if (event.type !== "event")
14107
+ return;
14108
+ if (event.kind === "caddy.stdout") {
14109
+ this.stdout.emit("data", Buffer2.from(event.data));
14110
+ return;
14111
+ }
14112
+ if (event.kind === "caddy.stderr") {
14113
+ this.stderr.emit("data", Buffer2.from(event.data));
14114
+ return;
14115
+ }
14116
+ if (event.kind === "caddy.exit") {
14117
+ this.finished = true;
14118
+ this.emit("exit", event.code, event.signal);
14119
+ }
14120
+ }
14121
+ /** Asks the helper to stop Caddy; the helper also stops it on disconnect. */
14122
+ kill() {
14123
+ this.unsubscribe();
14124
+ if (this.finished)
14125
+ return;
14126
+ this.finished = true;
14127
+ void this.client.call("caddy.stop").catch(() => {
14128
+ });
14129
+ }
14130
+ };
14131
+ function caddyStoragePath() {
14132
+ return process6.platform === "win32" ? join5(process6.env.AppData ?? "", "Caddy") : join5(process6.env.HOME ?? "", "Library/Application Support/Caddy");
14133
+ }
14134
+ function openPrivilegedSession(runtimeDir, options) {
14135
+ const env2 = resolvePrivilegedEnv();
14136
+ return openHelperSession({
14137
+ runtimeDir,
14138
+ helperEntry: env2.helperEntry,
14139
+ helperArgs: env2.helperArgs,
14140
+ direct: options.direct,
14141
+ // Caddy keeps its PKI under the user's home; the helper runs it as root, so
14142
+ // it must know which tree to hand back afterwards.
14143
+ caddyStoragePath: caddyStoragePath(),
14144
+ // The binary and Caddyfile are fixed here: the privileged helper must never
14145
+ // execute a path supplied over the socket.
14146
+ caddyBin: options.caddyBin,
14147
+ caddyConfigPath: options.caddyConfigPath,
14148
+ reason: options.reason,
14149
+ log: options.log
14150
+ });
14151
+ }
14152
+
13654
14153
  // src/caddy/tls-health.ts
13655
- import { checkServerIdentity, connect } from "node:tls";
14154
+ import { checkServerIdentity, connect as connect2 } from "node:tls";
13656
14155
  function assessTlsCertificate(certificate, hostname, now = Date.now(), verifyHostname = checkServerIdentity) {
13657
14156
  if (!certificate.valid_to)
13658
14157
  return { healthy: false, reason: "certificate_missing" };
@@ -13671,7 +14170,7 @@ function assessTlsCertificate(certificate, hostname, now = Date.now(), verifyHos
13671
14170
  }
13672
14171
  function probeLocalTls(hostname, options = {}) {
13673
14172
  const {
13674
- connect: openTlsConnection = connect,
14173
+ connect: openTlsConnection = connect2,
13675
14174
  port = 443,
13676
14175
  timeoutMs = 1e3
13677
14176
  } = options;
@@ -13733,40 +14232,8 @@ function formatTlsHealthFailure(hostname, result) {
13733
14232
  }
13734
14233
 
13735
14234
  // src/caddy/utils.ts
13736
- import { exec as exec2 } from "node:child_process";
13737
- import { createServer } from "node:net";
13738
14235
  import ora from "ora";
13739
14236
  var spinner;
13740
- function tryPort(port) {
13741
- return new Promise((resolve2, _reject) => {
13742
- try {
13743
- const server = createServer().listen(port);
13744
- server.on("listening", () => {
13745
- server.close();
13746
- resolve2(false);
13747
- });
13748
- server.on("error", (err) => {
13749
- if (err.code === "EADDRINUSE")
13750
- resolve2(true);
13751
- server.close();
13752
- });
13753
- } catch {
13754
- resolve2(true);
13755
- }
13756
- });
13757
- }
13758
- async function kill(port) {
13759
- return new Promise((resolve2, reject2) => {
13760
- exec2(`npx @maxbo/free-port ${port} -s`, (err, stdout, _stderr) => {
13761
- if (err) {
13762
- reject2(err);
13763
- } else {
13764
- consola.log(stdout);
13765
- resolve2();
13766
- }
13767
- });
13768
- });
13769
- }
13770
14237
  function getNumber(number2) {
13771
14238
  if (number2 <= 0)
13772
14239
  return "0%";
@@ -13805,26 +14272,26 @@ async function download() {
13805
14272
  if (await testCaddy())
13806
14273
  return caddyPath;
13807
14274
  return new Promise((resolve2, reject2) => {
13808
- if (!existsSync3(TEMP_DIR)) {
14275
+ if (!existsSync5(TEMP_DIR)) {
13809
14276
  mkdirSync(TEMP_DIR, { recursive: true });
13810
- chmodSync2(TEMP_DIR, 511);
14277
+ chmodSync(TEMP_DIR, 448);
13811
14278
  }
13812
14279
  const file = createWriteStream(caddyPath);
13813
- let _platform = platform().toString();
14280
+ let _platform = platform3().toString();
13814
14281
  _platform === "win32" && (_platform = "windows");
13815
- let _arch = process4.arch.toString();
14282
+ let _arch = process7.arch.toString();
13816
14283
  _arch === "x64" && (_arch = "amd64");
13817
14284
  const support = supportList.find((item) => item.platform === _platform && item.arch === _arch);
13818
14285
  if (!support)
13819
14286
  return reject2(new Error("not support"));
13820
14287
  const dowmloadLink = `https://caddyserver.com/api/download?os=${support.platform}&arch=${support.arch}&p=github.com%2Fcaddyserver%2Fforwardproxy`;
13821
- existsSync3(caddyPath) && unlinkSync(caddyPath);
13822
- const httpProxy = process4.env.HTTP_PROXY || process4.env.http_proxy;
13823
- const httpsProxy = process4.env.HTTPS_PROXY || process4.env.https_proxy;
14288
+ existsSync5(caddyPath) && unlinkSync(caddyPath);
14289
+ const httpProxy = process7.env.HTTP_PROXY || process7.env.http_proxy;
14290
+ const httpsProxy = process7.env.HTTPS_PROXY || process7.env.https_proxy;
13824
14291
  const httpAgent = httpProxy ? new HttpProxyAgent(httpProxy) : void 0;
13825
14292
  const httpsAgent = httpsProxy ? new HttpsProxyAgent(httpsProxy) : void 0;
13826
14293
  const chmodCaddyOnce = once(() => {
13827
- chmodSync2(caddyPath, 511);
14294
+ chmodSync(caddyPath, 493);
13828
14295
  });
13829
14296
  got.stream(dowmloadLink, {
13830
14297
  agent: {
@@ -13836,9 +14303,9 @@ async function download() {
13836
14303
  chmodCaddyOnce();
13837
14304
  }).pipe(file).on("finish", () => {
13838
14305
  logProgressOver();
13839
- if (process4.platform === "win32")
14306
+ if (process7.platform === "win32")
13840
14307
  return resolve2(caddyPath);
13841
- chmodSync2(caddyPath, 511);
14308
+ chmodSync(caddyPath, 493);
13842
14309
  resolve2(caddyPath);
13843
14310
  }).on("error", (err) => {
13844
14311
  reject2(err);
@@ -13846,19 +14313,17 @@ async function download() {
13846
14313
  });
13847
14314
  }
13848
14315
  function testCaddy() {
13849
- return new Promise((resolve2, reject2) => {
13850
- if (!existsSync3(caddyPath))
13851
- return resolve2(false);
13852
- chmodSync2(caddyPath, 511);
13853
- const child = process4.platform === "win32" ? spawn(caddyPath, []) : spawn("sudo", ["-E", caddyPath]);
13854
- child.on("close", () => {
14316
+ return new Promise((resolve2) => {
14317
+ if (!existsSync5(caddyPath))
13855
14318
  return resolve2(false);
13856
- });
13857
- child.on("error", (err) => {
13858
- return reject2(err);
13859
- });
13860
- child.stdout.on("data", (_data) => {
13861
- return resolve2(true);
14319
+ try {
14320
+ chmodSync(caddyPath, 493);
14321
+ } catch {
14322
+ }
14323
+ execFile(caddyPath, [], { timeout: 1e4 }, (error, stdout) => {
14324
+ if (error && !stdout)
14325
+ return resolve2(false);
14326
+ resolve2(stdout.length > 0);
13862
14327
  });
13863
14328
  });
13864
14329
  }
@@ -13880,39 +14345,63 @@ function splitHostPort(addr) {
13880
14345
  }
13881
14346
  return { host: addr.slice(0, lastColon), port: addr.slice(lastColon + 1) };
13882
14347
  }
14348
+ var defaultDependencies = {
14349
+ openSession: (runtimeDir, reason) => openPrivilegedSession(runtimeDir, {
14350
+ log: (message) => consola.debug(message),
14351
+ // Both paths are fixed here, before any socket traffic: the privileged
14352
+ // helper must never execute something named in a request.
14353
+ caddyBin: caddyPath,
14354
+ caddyConfigPath: caddyFilePath,
14355
+ reason
14356
+ })
14357
+ };
13883
14358
  var CaddyInstant = class {
13884
- constructor() {
14359
+ constructor(deps = {}) {
13885
14360
  this.inited = false;
13886
14361
  this.stoped = false;
13887
14362
  /** has locked when start */
13888
14363
  this.locked = false;
13889
14364
  this._stopEffects = [];
13890
- testCaddy().then(async () => {
13891
- this.inited = true;
13892
- });
14365
+ this.deps = { ...defaultDependencies, ...deps };
13893
14366
  this.locked = this.checkLock();
13894
14367
  }
13895
14368
  checkLock() {
13896
- if (!existsSync3(caddyLockFilePath))
14369
+ if (!existsSync5(caddyLockFilePath))
13897
14370
  writeFileSync2(caddyLockFilePath, "");
13898
- return lockfile.checkSync(caddyLockFilePath);
14371
+ try {
14372
+ return lockfile.checkSync(caddyLockFilePath);
14373
+ } catch {
14374
+ return false;
14375
+ }
14376
+ }
14377
+ /**
14378
+ * Connects to the privileged helper, starting it once if needed. It is
14379
+ * reused across instances so a second dev server does not ask for a
14380
+ * password again.
14381
+ */
14382
+ async session(reason) {
14383
+ if (this._session && !this._session.client.connected)
14384
+ this._session = void 0;
14385
+ if (!this._session)
14386
+ this._session = await this.deps.openSession(TEMP_DIR, reason);
14387
+ return this._session;
13899
14388
  }
13900
14389
  async getCaddyfile() {
13901
- if (!existsSync3(caddyFilePath)) {
14390
+ if (!existsSync5(caddyFilePath)) {
13902
14391
  this.caddyfile = "";
13903
14392
  return "";
13904
14393
  }
13905
- this.caddyfile = await readFile2(caddyFilePath, "utf-8");
14394
+ this.caddyfile = await readFile3(caddyFilePath, "utf-8");
13906
14395
  return this.caddyfile;
13907
14396
  }
13908
14397
  get caddyRoot() {
13909
- return join3(
13910
- process4.platform === "win32" ? `${process4.env.AppData}/Caddy` : `${process4.env.HOME}/Library/Application Support/Caddy`,
14398
+ return join6(
14399
+ process7.platform === "win32" ? `${process7.env.AppData}/Caddy` : `${process7.env.HOME}/Library/Application Support/Caddy`,
13911
14400
  "./pki/authorities/local"
13912
14401
  );
13913
14402
  }
13914
14403
  async writeCaddyfile() {
13915
- return await writeFile(caddyFilePath, this.caddyfile || "");
14404
+ return await writeFile2(caddyFilePath, this.caddyfile || "");
13916
14405
  }
13917
14406
  async deleteCaddyfile() {
13918
14407
  return await unlink3(caddyFilePath);
@@ -13921,6 +14410,33 @@ var CaddyInstant = class {
13921
14410
  await download();
13922
14411
  this.inited = true;
13923
14412
  }
14413
+ /**
14414
+ * Hands the Caddy storage directory back to the developer. Local CA data
14415
+ * created by an earlier root-owned run must stay readable for `tls internal`
14416
+ * to keep serving the same certificate the browser already trusts.
14417
+ */
14418
+ /**
14419
+ * Installs Caddy's local root CA so the browser stops warning about
14420
+ * `tls internal` certificates. Generating the CA and trusting it are separate
14421
+ * steps: a new CA appears whenever the previous one expires or the storage is
14422
+ * replaced, so this runs on every start instead of once.
14423
+ *
14424
+ * The helper owns both the binary path and the command, so nothing here can
14425
+ * be turned into an arbitrary root execution.
14426
+ */
14427
+ async trustLocalCa(session) {
14428
+ try {
14429
+ const result = await session.client.call("ca.trust");
14430
+ if (result.trusted)
14431
+ consola.debug(`Caddy local CA is trusted
14432
+ ${result.output}`);
14433
+ } catch (error) {
14434
+ consola.warn(
14435
+ `could not install the Caddy root certificate automatically: ${error.message}
14436
+ Run \`${caddyPath} trust\` manually if the browser warns about the certificate.`
14437
+ );
14438
+ }
14439
+ }
13924
14440
  async ensureTlsReady(targetHost) {
13925
14441
  const health = await waitForLocalTls(targetHost);
13926
14442
  if (!health.healthy)
@@ -13974,8 +14490,8 @@ var CaddyInstant = class {
13974
14490
  await this.init();
13975
14491
  const sourceHost = splitHostPort(source).host;
13976
14492
  const targetHost = splitHostPort(target).host;
13977
- if (!await addHost(sourceHost, targetHost))
13978
- throw new Error("update host failed");
14493
+ const session = await this.session({ target: targetHost, https });
14494
+ await session.client.call("hosts.add", { ip: sourceHost, host: targetHost });
13979
14495
  consola.success("update host success\n");
13980
14496
  const normalizeBase = (b) => {
13981
14497
  let out = b || "/";
@@ -14010,24 +14526,24 @@ var CaddyInstant = class {
14010
14526
  void this.updateCaddyfile();
14011
14527
  })
14012
14528
  );
14013
- if (!existsSync3(caddyLockFilePath))
14529
+ if (!existsSync5(caddyLockFilePath))
14014
14530
  writeFileSync2(caddyLockFilePath, "");
14015
14531
  if (!this.locked) {
14016
- if (await tryPort(443))
14017
- await kill(443);
14018
- if ((process4.platform === "win32" || !https) && await tryPort(80))
14019
- await kill(80);
14532
+ await session.client.call("port.free", { port: 443 });
14533
+ if (process7.platform === "win32" || !https)
14534
+ await session.client.call("port.free", { port: 80 });
14020
14535
  }
14021
14536
  return new Promise((resolve2, reject2) => {
14022
- var _a4, _b3;
14023
14537
  let startupCheckStarted = false;
14024
14538
  const resolveWhenReady = async () => {
14025
14539
  if (startupCheckStarted)
14026
14540
  return;
14027
14541
  startupCheckStarted = true;
14028
14542
  try {
14029
- if (https)
14543
+ if (https) {
14544
+ await this.trustLocalCa(session);
14030
14545
  await this.ensureTlsReady(targetHost);
14546
+ }
14031
14547
  resolve2();
14032
14548
  } catch (error) {
14033
14549
  if (!this.locked)
@@ -14036,96 +14552,87 @@ var CaddyInstant = class {
14036
14552
  }
14037
14553
  };
14038
14554
  const setupCleanup = () => {
14039
- process4.on("SIGINT", async () => {
14555
+ process7.on("SIGINT", async () => {
14040
14556
  if (this.stoped)
14041
14557
  return;
14042
- process4.stdin.resume();
14558
+ process7.stdin.resume();
14043
14559
  try {
14044
14560
  await this.baseCleanup(restore);
14045
14561
  } finally {
14046
14562
  this.stoped = true;
14047
- process4.nextTick(() => {
14048
- process4.exit();
14563
+ process7.nextTick(() => {
14564
+ process7.exit();
14049
14565
  });
14050
14566
  }
14051
14567
  });
14052
- const originalExit = process4.exit.bind(process4);
14053
- process4.exit = async (code) => {
14054
- const port = Number(splitHostPort(source).port);
14055
- if (!Number.isNaN(port) && await tryPort(port))
14056
- await kill(port);
14057
- const pwd = process4.cwd();
14058
- const viteCacheDir = `${pwd}/node_modules/.vite`;
14059
- if (existsSync3(viteCacheDir))
14060
- await chmodRecursive(viteCacheDir, 511).catch(() => {
14061
- });
14062
- const viteTempCacheDir = `${pwd}/node_modules/.vite-temp`;
14063
- if (existsSync3(viteTempCacheDir))
14064
- await chmodRecursive(viteTempCacheDir, 511).catch(() => {
14065
- });
14066
- const nuxtCacheDir = `${pwd}/.nuxt`;
14067
- if (existsSync3(nuxtCacheDir))
14068
- await chmodRecursive(nuxtCacheDir, 511).catch(() => {
14069
- });
14070
- const webpackCacheDir = `${pwd}/node_modules/.cache`;
14071
- if (existsSync3(webpackCacheDir))
14072
- await chmodRecursive(webpackCacheDir, 511).catch(() => {
14073
- });
14568
+ const originalExit = process7.exit.bind(process7);
14569
+ process7.exit = async (code) => {
14074
14570
  if (this.stoped)
14075
14571
  return originalExit(code);
14076
- process4.stdin.resume();
14572
+ process7.stdin.resume();
14077
14573
  try {
14078
14574
  await this.baseCleanup();
14079
14575
  } finally {
14080
14576
  this.stoped = true;
14081
- process4.nextTick(() => {
14577
+ process7.nextTick(() => {
14082
14578
  originalExit(code);
14083
14579
  });
14084
14580
  }
14085
14581
  };
14086
14582
  };
14087
14583
  if (!this.locked) {
14088
- this._caddyChild = process4.platform !== "win32" ? spawn("sudo", ["-E", caddyPath, "run", "--config", caddyFilePath, "--watch"]) : spawn(caddyPath, ["run", "--config", caddyFilePath, "--watch"]);
14089
14584
  lockfile.lockSync(caddyLockFilePath);
14090
- this._caddyChild.on("error", (err) => {
14091
- return reject2(err);
14092
- });
14093
- (_a4 = this._caddyChild.stderr) == null ? void 0 : _a4.on("data", async (data) => {
14094
- const lines = data.toString().split("\n").map((line) => line.trim());
14095
- for (const line of lines) {
14096
- showCaddyLog && line && console.info(line);
14097
- if (isCaddyReloadCancellation(line)) {
14098
- consola.info("Caddy restarted before TLS issuance completed; retrying.\n");
14099
- continue;
14100
- }
14101
- try {
14102
- if (line.includes("Error:") || line && JSON.parse(line).level === "error") {
14103
- if (line.includes("parsing caddyfile tokens")) {
14104
- consola.error("Caddyfile syntax error, please contact the author:\n", `${this.caddyfile}
14585
+ setupCleanup();
14586
+ void (async () => {
14587
+ try {
14588
+ const child = new HelperCaddyProcess(session.client);
14589
+ this._caddyChild = child;
14590
+ await session.client.call("caddy.start");
14591
+ child.on("exit", (code) => {
14592
+ if (code !== null && code !== 0)
14593
+ reject2(new Error(`Caddy exited with code ${code}`));
14594
+ });
14595
+ child.stderr.on("data", async (data) => {
14596
+ const lines = data.toString().split("\n").map((line) => line.trim());
14597
+ for (const line of lines) {
14598
+ showCaddyLog && line && console.info(line);
14599
+ if (isCaddyReloadCancellation(line)) {
14600
+ consola.info("Caddy restarted before TLS issuance completed; retrying.\n");
14601
+ continue;
14602
+ }
14603
+ try {
14604
+ if (line.includes("Error:") || line && JSON.parse(line).level === "error") {
14605
+ if (line.includes("parsing caddyfile tokens")) {
14606
+ consola.error("Caddyfile syntax error, please contact the author:\n", `${this.caddyfile}
14105
14607
 
14106
14608
  ${line}
14107
14609
  `);
14108
- await this.baseCleanup();
14109
- process4.exit();
14110
- } else {
14111
- consola.error(`${line}
14610
+ await this.baseCleanup();
14611
+ process7.exit();
14612
+ } else {
14613
+ consola.error(`${line}
14112
14614
  `);
14113
- return reject2(line);
14615
+ return reject2(line);
14616
+ }
14617
+ }
14618
+ } catch {
14114
14619
  }
14620
+ if (line.includes("config file changed"))
14621
+ consola.success("Detect added a new reverse proxy config, restarted.\n");
14622
+ if (line.includes("caddy proxying") || line.includes("serving initial"))
14623
+ void resolveWhenReady();
14115
14624
  }
14116
- } catch {
14117
- }
14118
- if (line.includes("config file changed"))
14119
- consola.success("Detect added a new reverse proxy config, restarted.\n");
14120
- if (line.includes("caddy proxying") || line.includes("serving initial"))
14625
+ });
14626
+ child.stdout.on("data", (data) => {
14627
+ consola.info(data.toString());
14121
14628
  void resolveWhenReady();
14629
+ });
14630
+ } catch (error) {
14631
+ if (!this.locked)
14632
+ await this.baseCleanup(restore);
14633
+ reject2(error);
14122
14634
  }
14123
- });
14124
- (_b3 = this._caddyChild.stdout) == null ? void 0 : _b3.on("data", (_data) => {
14125
- consola.info(_data.toString());
14126
- void resolveWhenReady();
14127
- });
14128
- setupCleanup();
14635
+ })();
14129
14636
  } else {
14130
14637
  consola.info("Caddy is running in another process.");
14131
14638
  void (async () => {
@@ -14142,17 +14649,25 @@ ${line}
14142
14649
  });
14143
14650
  }
14144
14651
  async baseCleanup(restore = true) {
14652
+ var _a4;
14145
14653
  this._stopEffects.forEach((fn) => fn());
14654
+ this._stopEffects.length = 0;
14146
14655
  try {
14147
- if (restore && this._source && this._target) {
14148
- if (await removeHost(splitHostPort(this._source).host, splitHostPort(this._target).host))
14149
- consola.success("Restore host success.\n");
14150
- else
14151
- consola.fail("Restore host failed.\n");
14656
+ if (restore && this._source && this._target && this._session) {
14657
+ const sourceHost = splitHostPort(this._source).host;
14658
+ const targetHost = splitHostPort(this._target).host;
14659
+ await this._session.client.call("hosts.remove", { ip: sourceHost, host: targetHost });
14660
+ if (sourceHost === "localhost")
14661
+ await this._session.client.call("hosts.remove", { ip: "127.0.0.1", host: targetHost });
14662
+ consola.success("Restore host success.\n");
14152
14663
  }
14153
14664
  } catch (e) {
14154
- consola.error(e);
14155
- consola.fail("Restore host failed.\n");
14665
+ if (((_a4 = this._session) == null ? void 0 : _a4.client.connected) === false) {
14666
+ consola.debug("hosts entries are restored by the privileged helper on disconnect");
14667
+ } else {
14668
+ consola.error(e);
14669
+ consola.fail("Restore host failed.\n");
14670
+ }
14156
14671
  }
14157
14672
  if (!this.locked && !this.stoped) {
14158
14673
  await this.stopCaddy();
@@ -14177,7 +14692,7 @@ ${line}
14177
14692
  var config;
14178
14693
  var caddy;
14179
14694
  var hmrSseBridgeActive = false;
14180
- var cwd = process5.cwd();
14695
+ var cwd = process8.cwd();
14181
14696
  function colorUrl(url2) {
14182
14697
  return c.green(url2.replace(/:(\d+)\//, (_, port) => `:${c.bold(port)}/`));
14183
14698
  }
@@ -14212,16 +14727,27 @@ async function printForwardProxy() {
14212
14727
  }
14213
14728
  var vitePrintUrls = once((options, source, target, base = "/", _printUrls) => {
14214
14729
  _printUrls == null ? void 0 : _printUrls();
14730
+ if (isPrivilegeDenied())
14731
+ return;
14215
14732
  if (caddy)
14216
14733
  return;
14217
- caddy = new CaddyInstant();
14218
- caddy.run(source, target, {
14734
+ const instance = new CaddyInstant();
14735
+ caddy = instance;
14736
+ instance.run(source, target, {
14219
14737
  base,
14220
14738
  ...options
14221
14739
  }).then(async () => {
14222
14740
  await printForwardProxy();
14223
14741
  consola.success(` ${c.green("\u279C")} ${c.bold("run caddy reverse proxy success")}: ${colorUrl(`${options.https ? "https" : "http"}://${target}${base}`)}`);
14224
14742
  }).catch((e) => {
14743
+ if (caddy === instance)
14744
+ caddy = void 0;
14745
+ if (e instanceof PrivilegeDeniedError) {
14746
+ markPrivilegeDenied();
14747
+ consola.warn("reverse proxy skipped: administrator permission was not granted.");
14748
+ consola.info("Restart the dev server to enable it again.");
14749
+ return;
14750
+ }
14225
14751
  throw e;
14226
14752
  });
14227
14753
  });
@@ -14242,10 +14768,6 @@ var unpluginFactory = (options) => ({
14242
14768
  } = options;
14243
14769
  if (!enable)
14244
14770
  return;
14245
- if (!isAdmin()) {
14246
- consola.warn("please run as administrator");
14247
- return;
14248
- }
14249
14771
  if (!target) {
14250
14772
  consola.fail("please provide target");
14251
14773
  return;
@@ -14281,7 +14803,7 @@ var unpluginFactory = (options) => ({
14281
14803
  },
14282
14804
  webpack(compiler) {
14283
14805
  var _a4, _b3, _c2;
14284
- if (process5.env.NODE_ENV !== "development")
14806
+ if (process8.env.NODE_ENV !== "development")
14285
14807
  return;
14286
14808
  const {
14287
14809
  enable = true,
@@ -14289,10 +14811,6 @@ var unpluginFactory = (options) => ({
14289
14811
  } = options;
14290
14812
  if (!enable)
14291
14813
  return;
14292
- if (!isAdmin()) {
14293
- consola.warn("please run as administrator");
14294
- return;
14295
- }
14296
14814
  if (!target) {
14297
14815
  consola.fail("please provide target");
14298
14816
  return;
@@ -14306,9 +14824,11 @@ var unpluginFactory = (options) => ({
14306
14824
  port: 8080,
14307
14825
  ...compiler.options.devServer,
14308
14826
  // @ts-expect-error vuecli
14309
- ...(_a4 = process5.VUE_CLI_SERVICE) == null ? void 0 : _a4.projectOptions.devServer
14827
+ ...(_a4 = process8.VUE_CLI_SERVICE) == null ? void 0 : _a4.projectOptions.devServer
14310
14828
  };
14311
14829
  const source = `${devServer.host}:${devServer.port}`;
14830
+ if (isPrivilegeDenied())
14831
+ return;
14312
14832
  if (caddy)
14313
14833
  return;
14314
14834
  let base = "/";
@@ -14323,15 +14843,16 @@ var unpluginFactory = (options) => ({
14323
14843
  const _close = (_c2 = compiler.close) == null ? void 0 : _c2.bind(compiler);
14324
14844
  if (_close) {
14325
14845
  compiler.close = async (callback) => {
14326
- process5.on("exit", () => {
14846
+ process8.on("exit", () => {
14327
14847
  _close && _close(callback);
14328
14848
  });
14329
14849
  };
14330
14850
  } else {
14331
14851
  options.https = false;
14332
14852
  }
14333
- caddy = new CaddyInstant();
14334
- caddy.run(source, target, {
14853
+ const instance = new CaddyInstant();
14854
+ caddy = instance;
14855
+ instance.run(source, target, {
14335
14856
  base,
14336
14857
  ...options
14337
14858
  }).then(() => {
@@ -14340,12 +14861,20 @@ var unpluginFactory = (options) => ({
14340
14861
  consola.success(` ${c.green("\u279C")} ${c.bold("run caddy reverse proxy success")}: ${colorUrl(`${options.https ? "https" : "http"}://${target}${base}`)}`);
14341
14862
  });
14342
14863
  }).catch((e) => {
14864
+ if (caddy === instance)
14865
+ caddy = void 0;
14866
+ if (e instanceof PrivilegeDeniedError) {
14867
+ markPrivilegeDenied();
14868
+ consola.warn("reverse proxy skipped: administrator permission was not granted.");
14869
+ consola.info("Restart the dev server to enable it again.");
14870
+ return;
14871
+ }
14343
14872
  throw e;
14344
14873
  });
14345
14874
  },
14346
14875
  async rspack(compiler) {
14347
14876
  var _a4, _b3, _c2, _d2;
14348
- if (process5.env.NODE_ENV !== "development")
14877
+ if (process8.env.NODE_ENV !== "development")
14349
14878
  return;
14350
14879
  const {
14351
14880
  enable = true,
@@ -14353,10 +14882,6 @@ var unpluginFactory = (options) => ({
14353
14882
  } = options;
14354
14883
  if (!enable)
14355
14884
  return;
14356
- if (!isAdmin()) {
14357
- consola.warn("please run as administrator");
14358
- return;
14359
- }
14360
14885
  if (!target) {
14361
14886
  consola.fail("please provide target");
14362
14887
  return;
@@ -14374,9 +14899,10 @@ var unpluginFactory = (options) => ({
14374
14899
  }))) == null ? void 0 : _b3.content) == null ? void 0 : _c2.server
14375
14900
  };
14376
14901
  const source = `${devServer.host}:${devServer.port}`;
14902
+ if (isPrivilegeDenied())
14903
+ return;
14377
14904
  if (caddy)
14378
14905
  return;
14379
- caddy = new CaddyInstant();
14380
14906
  let base = "/";
14381
14907
  const publicPath = (_d2 = compiler.options.output) == null ? void 0 : _d2.publicPath;
14382
14908
  if (typeof publicPath === "string" && publicPath) {
@@ -14386,13 +14912,23 @@ var unpluginFactory = (options) => ({
14386
14912
  base = `/${base}`;
14387
14913
  if (base !== "/" && !base.endsWith("/"))
14388
14914
  base = `${base}/`;
14389
- caddy.run(source, target, {
14915
+ const instance = new CaddyInstant();
14916
+ caddy = instance;
14917
+ instance.run(source, target, {
14390
14918
  base,
14391
14919
  ...options
14392
14920
  }).then(async () => {
14393
14921
  await printForwardProxy();
14394
14922
  consola.success(` ${c.green("\u279C")} ${c.bold("run caddy reverse proxy success")}: ${colorUrl(`${options.https ? "https" : "http"}://${target}${base}`)}`);
14395
14923
  }).catch((e) => {
14924
+ if (caddy === instance)
14925
+ caddy = void 0;
14926
+ if (e instanceof PrivilegeDeniedError) {
14927
+ markPrivilegeDenied();
14928
+ consola.warn("reverse proxy skipped: administrator permission was not granted.");
14929
+ consola.info("Restart the dev server to enable it again.");
14930
+ return;
14931
+ }
14396
14932
  throw e;
14397
14933
  });
14398
14934
  }